blob: da30c4433d5ea636f134d13347509423966a2e88 [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])
Antoine Pitrou537bed62010-04-27 13:16:06 +0000646 except socket.error as x:
647 if test_support.verbose:
648 sys.stdout.write("\nsocket.error is %s\n" % x[1])
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000649 else:
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000650 self.fail("Use of invalid cert should have failed!")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000651 finally:
652 server.stop()
653 server.join()
Thomas Woutersed03b412007-08-28 21:37:11 +0000654
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000655 def serverParamsTest (certfile, protocol, certreqs, cacertsfile,
Bill Janssen6e027db2007-11-15 22:23:56 +0000656 client_certfile, client_protocol=None,
657 indata="FOO\n",
658 chatty=False, connectionchatty=False):
Thomas Woutersed03b412007-08-28 21:37:11 +0000659
Trent Nelson78520002008-04-10 20:54:35 +0000660 server = ThreadedEchoServer(certfile,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000661 certreqs=certreqs,
662 ssl_version=protocol,
663 cacerts=cacertsfile,
664 chatty=chatty,
Bill Janssen6e027db2007-11-15 22:23:56 +0000665 connectionchatty=False)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000666 flag = threading.Event()
667 server.start(flag)
668 # wait for it to start
669 flag.wait()
670 # try to connect
671 if client_protocol is None:
672 client_protocol = protocol
673 try:
Bill Janssen6e027db2007-11-15 22:23:56 +0000674 s = ssl.wrap_socket(socket.socket(),
675 certfile=client_certfile,
676 ca_certs=cacertsfile,
677 cert_reqs=certreqs,
678 ssl_version=client_protocol)
Trent Nelson78520002008-04-10 20:54:35 +0000679 s.connect((HOST, server.port))
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000680 arg = indata.encode('ASCII', 'strict')
Bill Janssen6e027db2007-11-15 22:23:56 +0000681 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000682 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000683 sys.stdout.write(
684 " client: sending %s...\n" % (repr(indata)))
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000685 s.write(arg)
Bill Janssen6e027db2007-11-15 22:23:56 +0000686 outdata = s.read()
687 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000688 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000689 sys.stdout.write(" client: read %s\n" % repr(outdata))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000690 outdata = str(outdata, 'ASCII', 'strict')
Bill Janssen6e027db2007-11-15 22:23:56 +0000691 if outdata != indata.lower():
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000692 self.fail(
Bill Janssen6e027db2007-11-15 22:23:56 +0000693 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
Trent Nelson6b240cd2008-04-10 20:12:06 +0000694 % (repr(outdata[:min(len(outdata),20)]), len(outdata),
695 repr(indata[:min(len(indata),20)].lower()), len(indata)))
696 s.write("over\n".encode("ASCII", "strict"))
Bill Janssen6e027db2007-11-15 22:23:56 +0000697 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000698 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000699 sys.stdout.write(" client: closing connection.\n")
700 s.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000701 finally:
702 server.stop()
703 server.join()
Thomas Woutersed03b412007-08-28 21:37:11 +0000704
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000705 def tryProtocolCombo (server_protocol,
706 client_protocol,
707 expectedToWork,
708 certsreqs=None):
Thomas Woutersed03b412007-08-28 21:37:11 +0000709
Benjamin Peterson2a691a82008-03-31 01:51:45 +0000710 if certsreqs is None:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000711 certsreqs = ssl.CERT_NONE
Thomas Woutersed03b412007-08-28 21:37:11 +0000712
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000713 if certsreqs == ssl.CERT_NONE:
714 certtype = "CERT_NONE"
715 elif certsreqs == ssl.CERT_OPTIONAL:
716 certtype = "CERT_OPTIONAL"
717 elif certsreqs == ssl.CERT_REQUIRED:
718 certtype = "CERT_REQUIRED"
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000719 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000720 formatstr = (expectedToWork and " %s->%s %s\n") or " {%s->%s} %s\n"
721 sys.stdout.write(formatstr %
722 (ssl.get_protocol_name(client_protocol),
723 ssl.get_protocol_name(server_protocol),
724 certtype))
725 try:
726 serverParamsTest(CERTFILE, server_protocol, certsreqs,
Bill Janssen6e027db2007-11-15 22:23:56 +0000727 CERTFILE, CERTFILE, client_protocol,
728 chatty=False, connectionchatty=False)
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000729 # Protocol mismatch can result in either an SSLError, or a
730 # "Connection reset by peer" error.
731 except ssl.SSLError:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000732 if expectedToWork:
733 raise
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000734 except socket.error as e:
735 if expectedToWork or e.errno != errno.ECONNRESET:
736 raise
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000737 else:
738 if not expectedToWork:
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000739 self.fail(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000740 "Client protocol %s succeeded with server protocol %s!"
741 % (ssl.get_protocol_name(client_protocol),
742 ssl.get_protocol_name(server_protocol)))
743
744
Bill Janssen6e027db2007-11-15 22:23:56 +0000745 class ThreadedTests(unittest.TestCase):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000746
Trent Nelson6b240cd2008-04-10 20:12:06 +0000747 def testEcho (self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000748
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000749 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000750 sys.stdout.write("\n")
751 serverParamsTest(CERTFILE, ssl.PROTOCOL_TLSv1, ssl.CERT_NONE,
752 CERTFILE, CERTFILE, ssl.PROTOCOL_TLSv1,
753 chatty=True, connectionchatty=True)
754
755 def testReadCert(self):
756
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000757 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000758 sys.stdout.write("\n")
759 s2 = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000760 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000761 certreqs=ssl.CERT_NONE,
762 ssl_version=ssl.PROTOCOL_SSLv23,
763 cacerts=CERTFILE,
764 chatty=False)
765 flag = threading.Event()
766 server.start(flag)
767 # wait for it to start
768 flag.wait()
769 # try to connect
770 try:
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000771 s = ssl.wrap_socket(socket.socket(),
772 certfile=CERTFILE,
773 ca_certs=CERTFILE,
774 cert_reqs=ssl.CERT_REQUIRED,
775 ssl_version=ssl.PROTOCOL_SSLv23)
776 s.connect((HOST, server.port))
777 cert = s.getpeercert()
778 self.assertTrue(cert, "Can't get peer certificate.")
779 cipher = s.cipher()
780 if support.verbose:
781 sys.stdout.write(pprint.pformat(cert) + '\n')
782 sys.stdout.write("Connection cipher is " + str(cipher) + '.\n')
783 if 'subject' not in cert:
784 self.fail("No subject field in certificate: %s." %
785 pprint.pformat(cert))
786 if ((('organizationName', 'Python Software Foundation'),)
787 not in cert['subject']):
788 self.fail(
789 "Missing or invalid 'organizationName' field in certificate subject; "
790 "should be 'Python Software Foundation'.")
791 s.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000792 finally:
793 server.stop()
794 server.join()
795
796 def testNULLcert(self):
797 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
798 "nullcert.pem"))
799 def testMalformedCert(self):
800 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
801 "badcert.pem"))
Bill Janssen58afe4c2008-09-08 16:45:19 +0000802 def testWrongCert(self):
803 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
804 "wrongcert.pem"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000805 def testMalformedKey(self):
806 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
807 "badkey.pem"))
808
Trent Nelson6b240cd2008-04-10 20:12:06 +0000809 def testRudeShutdown(self):
810
811 listener_ready = threading.Event()
812 listener_gone = threading.Event()
Antoine Pitrou0fb2e542010-04-27 08:58:38 +0000813 s = socket.socket()
814 port = support.bind_port(s, HOST)
Trent Nelson6b240cd2008-04-10 20:12:06 +0000815
Antoine Pitrou0fb2e542010-04-27 08:58:38 +0000816 # `listener` runs in a thread. It sits in an accept() until
817 # the main thread connects. Then it rudely closes the socket,
818 # and sets Event `listener_gone` to let the main thread know
819 # the socket is gone.
Trent Nelson6b240cd2008-04-10 20:12:06 +0000820 def listener():
Trent Nelson6b240cd2008-04-10 20:12:06 +0000821 s.listen(5)
822 listener_ready.set()
823 s.accept()
Antoine Pitrou0fb2e542010-04-27 08:58:38 +0000824 s.close()
Trent Nelson6b240cd2008-04-10 20:12:06 +0000825 listener_gone.set()
826
827 def connector():
828 listener_ready.wait()
Antoine Pitrou0fb2e542010-04-27 08:58:38 +0000829 c = socket.socket()
830 c.connect((HOST, port))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000831 listener_gone.wait()
832 try:
Antoine Pitrou0fb2e542010-04-27 08:58:38 +0000833 ssl_sock = ssl.wrap_socket(c)
Trent Nelson6b240cd2008-04-10 20:12:06 +0000834 except IOError:
835 pass
836 else:
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000837 self.fail('connecting to closed SSL socket should have failed')
Trent Nelson6b240cd2008-04-10 20:12:06 +0000838
839 t = threading.Thread(target=listener)
840 t.start()
Antoine Pitrou0fb2e542010-04-27 08:58:38 +0000841 try:
842 connector()
843 finally:
844 t.join()
Trent Nelson6b240cd2008-04-10 20:12:06 +0000845
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000846 def testProtocolSSL2(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000847 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000848 sys.stdout.write("\n")
849 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True)
850 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL)
851 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED)
852 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True)
853 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False)
854 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False)
855
856 def testProtocolSSL23(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000857 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000858 sys.stdout.write("\n")
859 try:
860 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv2, True)
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000861 except (ssl.SSLError, socket.error) as x:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000862 # this fails on some older versions of OpenSSL (0.9.7l, for instance)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000863 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000864 sys.stdout.write(
865 " SSL2 client to SSL23 server test unexpectedly failed:\n %s\n"
866 % str(x))
867 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True)
868 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True)
869 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True)
870
871 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
872 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_OPTIONAL)
873 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
874
875 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
876 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_REQUIRED)
877 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
878
879 def testProtocolSSL3(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000880 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000881 sys.stdout.write("\n")
882 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True)
883 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
884 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
885 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False)
886 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, False)
887 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False)
888
889 def testProtocolTLS1(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000890 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000891 sys.stdout.write("\n")
892 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True)
893 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
894 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
895 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False)
896 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False)
897 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv23, False)
898
899 def testSTARTTLS (self):
900
Bill Janssen40a0f662008-08-12 16:56:25 +0000901 msgs = ("msg 1", "MSG 2", "STARTTLS", "MSG 3", "msg 4", "ENDTLS", "msg 5", "msg 6")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000902
Trent Nelson78520002008-04-10 20:54:35 +0000903 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000904 ssl_version=ssl.PROTOCOL_TLSv1,
905 starttls_server=True,
906 chatty=True,
907 connectionchatty=True)
908 flag = threading.Event()
909 server.start(flag)
910 # wait for it to start
911 flag.wait()
912 # try to connect
913 wrapped = False
914 try:
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000915 s = socket.socket()
916 s.setblocking(1)
917 s.connect((HOST, server.port))
918 if support.verbose:
919 sys.stdout.write("\n")
920 for indata in msgs:
921 msg = indata.encode('ASCII', 'replace')
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000922 if support.verbose:
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000923 sys.stdout.write(
924 " client: sending %s...\n" % repr(msg))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000925 if wrapped:
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000926 conn.write(msg)
927 outdata = conn.read()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000928 else:
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000929 s.send(msg)
930 outdata = s.recv(1024)
931 if (indata == "STARTTLS" and
932 str(outdata, 'ASCII', 'replace').strip().lower().startswith("ok")):
933 if support.verbose:
934 msg = str(outdata, 'ASCII', 'replace')
935 sys.stdout.write(
936 " client: read %s from server, starting TLS...\n"
937 % repr(msg))
938 conn = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1)
939 wrapped = True
940 elif (indata == "ENDTLS" and
941 str(outdata, 'ASCII', 'replace').strip().lower().startswith("ok")):
942 if support.verbose:
943 msg = str(outdata, 'ASCII', 'replace')
944 sys.stdout.write(
945 " client: read %s from server, ending TLS...\n"
946 % repr(msg))
947 s = conn.unwrap()
948 wrapped = False
949 else:
950 if support.verbose:
951 msg = str(outdata, 'ASCII', 'replace')
952 sys.stdout.write(
953 " client: read %s from server\n" % repr(msg))
954 if support.verbose:
955 sys.stdout.write(" client: closing connection.\n")
956 if wrapped:
957 conn.write("over\n".encode("ASCII", "strict"))
958 else:
959 s.send("over\n".encode("ASCII", "strict"))
Bill Janssen6e027db2007-11-15 22:23:56 +0000960 if wrapped:
961 conn.close()
962 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000963 s.close()
964 finally:
965 server.stop()
966 server.join()
967
Bill Janssen54cc54c2007-12-14 22:08:56 +0000968 def testSocketServer(self):
Bill Janssen6e027db2007-11-15 22:23:56 +0000969
Trent Nelson78520002008-04-10 20:54:35 +0000970 server = OurHTTPSServer(CERTFILE)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000971 flag = threading.Event()
972 server.start(flag)
973 # wait for it to start
974 flag.wait()
975 # try to connect
976 try:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000977 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000978 sys.stdout.write('\n')
979 d1 = open(CERTFILE, 'rb').read()
980 d2 = ''
981 # now fetch the same data from the HTTPS server
Trent Nelson78520002008-04-10 20:54:35 +0000982 url = 'https://%s:%d/%s' % (
983 HOST, server.port, os.path.split(CERTFILE)[1])
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000984 f = urllib.request.urlopen(url)
Barry Warsaw820c1202008-06-12 04:06:45 +0000985 dlen = f.info().get("content-length")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000986 if dlen and (int(dlen) > 0):
987 d2 = f.read(int(dlen))
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000988 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000989 sys.stdout.write(
990 " client: read %d bytes from remote server '%s'\n"
991 % (len(d2), server))
992 f.close()
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000993 self.assertEqual(d1, d2)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000994 finally:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000995 if support.verbose:
Neal Norwitzf9ff5f02008-03-31 05:39:26 +0000996 sys.stdout.write('stopping server\n')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000997 server.stop()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000998 if support.verbose:
Neal Norwitzf9ff5f02008-03-31 05:39:26 +0000999 sys.stdout.write('joining thread\n')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001000 server.join()
1001
Trent Nelson6b240cd2008-04-10 20:12:06 +00001002 def testAsyncoreServer(self):
1003
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001004 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001005 sys.stdout.write("\n")
1006
1007 indata="FOO\n"
Trent Nelson78520002008-04-10 20:54:35 +00001008 server = AsyncoreEchoServer(CERTFILE)
Trent Nelson6b240cd2008-04-10 20:12:06 +00001009 flag = threading.Event()
1010 server.start(flag)
1011 # wait for it to start
1012 flag.wait()
1013 # try to connect
1014 try:
1015 s = ssl.wrap_socket(socket.socket())
Antoine Pitrou66ffb262010-04-27 11:05:15 +00001016 s.connect(('127.0.0.1', server.port))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001017 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001018 sys.stdout.write(
1019 " client: sending %s...\n" % (repr(indata)))
Antoine Pitrou66ffb262010-04-27 11:05:15 +00001020 s.write(indata.encode('ASCII', 'strict'))
1021 outdata = s.read()
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001022 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001023 sys.stdout.write(" client: read %s\n" % repr(outdata))
1024 outdata = str(outdata, 'ASCII', 'strict')
1025 if outdata != indata.lower():
Antoine Pitrou66ffb262010-04-27 11:05:15 +00001026 self.fail(
Trent Nelson6b240cd2008-04-10 20:12:06 +00001027 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
Antoine Pitrou66ffb262010-04-27 11:05:15 +00001028 % (outdata[:min(len(outdata),20)], len(outdata),
1029 indata[:min(len(indata),20)].lower(), len(indata)))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001030 s.write("over\n".encode("ASCII", "strict"))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001031 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001032 sys.stdout.write(" client: closing connection.\n")
1033 s.close()
1034 finally:
1035 server.stop()
1036 server.join()
1037
Bill Janssen58afe4c2008-09-08 16:45:19 +00001038 def testAllRecvAndSendMethods(self):
1039
1040 if support.verbose:
1041 sys.stdout.write("\n")
1042
1043 server = ThreadedEchoServer(CERTFILE,
1044 certreqs=ssl.CERT_NONE,
1045 ssl_version=ssl.PROTOCOL_TLSv1,
1046 cacerts=CERTFILE,
1047 chatty=True,
1048 connectionchatty=False)
1049 flag = threading.Event()
1050 server.start(flag)
1051 # wait for it to start
1052 flag.wait()
1053 # try to connect
Antoine Pitrou66ffb262010-04-27 11:05:15 +00001054 s = ssl.wrap_socket(socket.socket(),
1055 server_side=False,
1056 certfile=CERTFILE,
1057 ca_certs=CERTFILE,
1058 cert_reqs=ssl.CERT_NONE,
1059 ssl_version=ssl.PROTOCOL_TLSv1)
1060 s.connect((HOST, server.port))
Bill Janssen58afe4c2008-09-08 16:45:19 +00001061 try:
Bill Janssen58afe4c2008-09-08 16:45:19 +00001062 # helper methods for standardising recv* method signatures
1063 def _recv_into():
1064 b = bytearray(b"\0"*100)
1065 count = s.recv_into(b)
1066 return b[:count]
1067
1068 def _recvfrom_into():
1069 b = bytearray(b"\0"*100)
1070 count, addr = s.recvfrom_into(b)
1071 return b[:count]
1072
1073 # (name, method, whether to expect success, *args)
1074 send_methods = [
1075 ('send', s.send, True, []),
1076 ('sendto', s.sendto, False, ["some.address"]),
1077 ('sendall', s.sendall, True, []),
1078 ]
1079 recv_methods = [
1080 ('recv', s.recv, True, []),
1081 ('recvfrom', s.recvfrom, False, ["some.address"]),
1082 ('recv_into', _recv_into, True, []),
1083 ('recvfrom_into', _recvfrom_into, False, []),
1084 ]
1085 data_prefix = "PREFIX_"
1086
1087 for meth_name, send_meth, expect_success, args in send_methods:
1088 indata = data_prefix + meth_name
1089 try:
1090 send_meth(indata.encode('ASCII', 'strict'), *args)
1091 outdata = s.read()
1092 outdata = str(outdata, 'ASCII', 'strict')
1093 if outdata != indata.lower():
1094 raise support.TestFailed(
1095 "While sending with <<{name:s}>> bad data "
1096 "<<{outdata:s}>> ({nout:d}) received; "
1097 "expected <<{indata:s}>> ({nin:d})\n".format(
1098 name=meth_name, outdata=repr(outdata[:20]),
1099 nout=len(outdata),
1100 indata=repr(indata[:20]), nin=len(indata)
1101 )
1102 )
1103 except ValueError as e:
1104 if expect_success:
1105 raise support.TestFailed(
1106 "Failed to send with method <<{name:s}>>; "
1107 "expected to succeed.\n".format(name=meth_name)
1108 )
1109 if not str(e).startswith(meth_name):
1110 raise support.TestFailed(
1111 "Method <<{name:s}>> failed with unexpected "
1112 "exception message: {exp:s}\n".format(
1113 name=meth_name, exp=e
1114 )
1115 )
1116
1117 for meth_name, recv_meth, expect_success, args in recv_methods:
1118 indata = data_prefix + meth_name
1119 try:
1120 s.send(indata.encode('ASCII', 'strict'))
1121 outdata = recv_meth(*args)
1122 outdata = str(outdata, 'ASCII', 'strict')
1123 if outdata != indata.lower():
1124 raise support.TestFailed(
1125 "While receiving with <<{name:s}>> bad data "
1126 "<<{outdata:s}>> ({nout:d}) received; "
1127 "expected <<{indata:s}>> ({nin:d})\n".format(
1128 name=meth_name, outdata=repr(outdata[:20]),
1129 nout=len(outdata),
1130 indata=repr(indata[:20]), nin=len(indata)
1131 )
1132 )
1133 except ValueError as e:
1134 if expect_success:
1135 raise support.TestFailed(
1136 "Failed to receive with method <<{name:s}>>; "
1137 "expected to succeed.\n".format(name=meth_name)
1138 )
1139 if not str(e).startswith(meth_name):
1140 raise support.TestFailed(
1141 "Method <<{name:s}>> failed with unexpected "
1142 "exception message: {exp:s}\n".format(
1143 name=meth_name, exp=e
1144 )
1145 )
1146 # consume data
1147 s.read()
1148
1149 s.write("over\n".encode("ASCII", "strict"))
1150 s.close()
1151 finally:
1152 server.stop()
1153 server.join()
1154
Antoine Pitrouec146182010-04-24 21:30:20 +00001155 def test_handshake_timeout(self):
1156 # Issue #5103: SSL handshake must respect the socket timeout
1157 server = socket.socket(socket.AF_INET)
1158 host = "127.0.0.1"
1159 port = support.bind_port(server)
1160 started = threading.Event()
1161 finish = False
1162
1163 def serve():
1164 server.listen(5)
1165 started.set()
1166 conns = []
1167 while not finish:
1168 r, w, e = select.select([server], [], [], 0.1)
1169 if server in r:
1170 # Let the socket hang around rather than having
1171 # it closed by garbage collection.
1172 conns.append(server.accept()[0])
1173
1174 t = threading.Thread(target=serve)
1175 t.start()
1176 started.wait()
1177
1178 try:
Antoine Pitrouc2203f92010-04-24 22:07:51 +00001179 try:
1180 c = socket.socket(socket.AF_INET)
1181 c.settimeout(0.2)
1182 c.connect((host, port))
1183 # Will attempt handshake and time out
1184 self.assertRaisesRegexp(ssl.SSLError, "timed out",
1185 ssl.wrap_socket, c)
1186 finally:
1187 c.close()
Antoine Pitrouec146182010-04-24 21:30:20 +00001188 try:
1189 c = socket.socket(socket.AF_INET)
1190 c = ssl.wrap_socket(c)
1191 c.settimeout(0.2)
1192 # Will attempt handshake and time out
1193 self.assertRaisesRegexp(ssl.SSLError, "timed out",
1194 c.connect, (host, port))
1195 finally:
1196 c.close()
1197 finally:
1198 finish = True
1199 t.join()
1200 server.close()
1201
Bill Janssen58afe4c2008-09-08 16:45:19 +00001202
Thomas Woutersed03b412007-08-28 21:37:11 +00001203def test_main(verbose=False):
1204 if skip_expected:
Benjamin Petersone549ead2009-03-28 21:42:05 +00001205 raise unittest.SkipTest("No SSL support")
Thomas Woutersed03b412007-08-28 21:37:11 +00001206
Trent Nelson78520002008-04-10 20:54:35 +00001207 global CERTFILE, SVN_PYTHON_ORG_ROOT_CERT
Thomas Woutersed03b412007-08-28 21:37:11 +00001208 CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir,
1209 "keycert.pem")
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001210 SVN_PYTHON_ORG_ROOT_CERT = os.path.join(
1211 os.path.dirname(__file__) or os.curdir,
1212 "https_svn_python_org_root.pem")
1213
1214 if (not os.path.exists(CERTFILE) or
1215 not os.path.exists(SVN_PYTHON_ORG_ROOT_CERT)):
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001216 raise support.TestFailed("Can't read certificate files!")
Bill Janssen6e027db2007-11-15 22:23:56 +00001217
Thomas Woutersed03b412007-08-28 21:37:11 +00001218 tests = [BasicTests]
1219
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001220 if support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00001221 tests.append(NetworkedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001222
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001223 if _have_threads:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001224 thread_info = support.threading_setup()
1225 if thread_info and support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00001226 tests.append(ThreadedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001227
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001228 support.run_unittest(*tests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001229
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001230 if _have_threads:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001231 support.threading_cleanup(*thread_info)
Thomas Woutersed03b412007-08-28 21:37:11 +00001232
1233if __name__ == "__main__":
1234 test_main()