blob: a5af557513c252b540a45be8e11d91be04e309ab [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 time
Antoine Pitroucfcd8ad2010-04-23 23:31:47 +00009import gc
Thomas Woutersed03b412007-08-28 21:37:11 +000010import os
Antoine Pitroucfcd8ad2010-04-23 23:31:47 +000011import errno
Thomas Woutersed03b412007-08-28 21:37:11 +000012import pprint
Jeremy Hylton1afc1692008-06-18 20:49:58 +000013import urllib.parse, urllib.request
Thomas Woutersed03b412007-08-28 21:37:11 +000014import traceback
Bill Janssen54cc54c2007-12-14 22:08:56 +000015import asyncore
Antoine Pitrou9d543662010-04-23 23:10:32 +000016import weakref
Thomas Woutersed03b412007-08-28 21:37:11 +000017
Georg Brandl24420152008-05-26 16:32:26 +000018from http.server import HTTPServer, SimpleHTTPRequestHandler
Thomas Wouters1b7f8912007-09-19 03:06:30 +000019
Thomas Woutersed03b412007-08-28 21:37:11 +000020# Optionally test SSL support, if we have it in the tested platform
21skip_expected = False
22try:
23 import ssl
24except ImportError:
25 skip_expected = True
26
Benjamin Petersonee8712c2008-05-20 21:35:26 +000027HOST = support.HOST
Thomas Woutersed03b412007-08-28 21:37:11 +000028CERTFILE = None
Thomas Wouters1b7f8912007-09-19 03:06:30 +000029SVN_PYTHON_ORG_ROOT_CERT = None
Thomas Woutersed03b412007-08-28 21:37:11 +000030
Thomas Woutersed03b412007-08-28 21:37:11 +000031def handle_error(prefix):
32 exc_format = ' '.join(traceback.format_exception(*sys.exc_info()))
Benjamin Petersonee8712c2008-05-20 21:35:26 +000033 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000034 sys.stdout.write(prefix + exc_format)
Thomas Woutersed03b412007-08-28 21:37:11 +000035
36
37class BasicTests(unittest.TestCase):
38
Georg Brandlfceab5a2008-01-19 20:08:23 +000039 def testSSLconnect(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +000040 if not support.is_resource_enabled('network'):
Georg Brandlfceab5a2008-01-19 20:08:23 +000041 return
42 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
43 cert_reqs=ssl.CERT_NONE)
44 s.connect(("svn.python.org", 443))
45 c = s.getpeercert()
46 if c:
Antoine Pitrou18c913e2010-04-27 10:59:39 +000047 self.fail("Peer cert %s shouldn't be here!")
Georg Brandlfceab5a2008-01-19 20:08:23 +000048 s.close()
49
50 # this should fail because we have no verification certs
51 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
52 cert_reqs=ssl.CERT_REQUIRED)
53 try:
54 s.connect(("svn.python.org", 443))
55 except ssl.SSLError:
56 pass
57 finally:
58 s.close()
59
Thomas Wouters1b7f8912007-09-19 03:06:30 +000060 def testCrucialConstants(self):
61 ssl.PROTOCOL_SSLv2
62 ssl.PROTOCOL_SSLv23
63 ssl.PROTOCOL_SSLv3
64 ssl.PROTOCOL_TLSv1
65 ssl.CERT_NONE
66 ssl.CERT_OPTIONAL
67 ssl.CERT_REQUIRED
Thomas Woutersed03b412007-08-28 21:37:11 +000068
Thomas Wouters1b7f8912007-09-19 03:06:30 +000069 def testRAND(self):
70 v = ssl.RAND_status()
Benjamin Petersonee8712c2008-05-20 21:35:26 +000071 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000072 sys.stdout.write("\n RAND_status is %d (%s)\n"
73 % (v, (v and "sufficient randomness") or
74 "insufficient randomness"))
Thomas Woutersed03b412007-08-28 21:37:11 +000075 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000076 ssl.RAND_egd(1)
77 except TypeError:
78 pass
Thomas Woutersed03b412007-08-28 21:37:11 +000079 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000080 print("didn't raise TypeError")
81 ssl.RAND_add("this is a random string", 75.0)
Thomas Woutersed03b412007-08-28 21:37:11 +000082
Thomas Wouters1b7f8912007-09-19 03:06:30 +000083 def testParseCert(self):
84 # note that this uses an 'unofficial' function in _ssl.c,
85 # provided solely for this test, to exercise the certificate
86 # parsing code
87 p = ssl._ssl._test_decode_cert(CERTFILE, False)
Benjamin Petersonee8712c2008-05-20 21:35:26 +000088 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000089 sys.stdout.write("\n" + pprint.pformat(p) + "\n")
Thomas Woutersed03b412007-08-28 21:37:11 +000090
Thomas Wouters1b7f8912007-09-19 03:06:30 +000091 def testDERtoPEM(self):
92
93 pem = open(SVN_PYTHON_ORG_ROOT_CERT, 'r').read()
94 d1 = ssl.PEM_cert_to_DER_cert(pem)
95 p2 = ssl.DER_cert_to_PEM_cert(d1)
96 d2 = ssl.PEM_cert_to_DER_cert(p2)
Antoine Pitrou18c913e2010-04-27 10:59:39 +000097 self.assertEqual(d1, d2)
Thomas Wouters1b7f8912007-09-19 03:06:30 +000098
Antoine Pitrou04f6a322010-04-05 21:40:07 +000099 def test_openssl_version(self):
100 n = ssl.OPENSSL_VERSION_NUMBER
101 t = ssl.OPENSSL_VERSION_INFO
102 s = ssl.OPENSSL_VERSION
103 self.assertIsInstance(n, int)
104 self.assertIsInstance(t, tuple)
105 self.assertIsInstance(s, str)
106 # Some sanity checks follow
107 # >= 0.9
108 self.assertGreaterEqual(n, 0x900000)
109 # < 2.0
110 self.assertLess(n, 0x20000000)
111 major, minor, fix, patch, status = t
112 self.assertGreaterEqual(major, 0)
113 self.assertLess(major, 2)
114 self.assertGreaterEqual(minor, 0)
115 self.assertLess(minor, 256)
116 self.assertGreaterEqual(fix, 0)
117 self.assertLess(fix, 256)
118 self.assertGreaterEqual(patch, 0)
119 self.assertLessEqual(patch, 26)
120 self.assertGreaterEqual(status, 0)
121 self.assertLessEqual(status, 15)
122 # Version string as returned by OpenSSL, the format might change
123 self.assertTrue(s.startswith("OpenSSL {:d}.{:d}.{:d}".format(major, minor, fix)),
124 (s, t))
125
Antoine Pitrou2d9cb9c2010-04-17 17:40:45 +0000126 def test_ciphers(self):
127 if not support.is_resource_enabled('network'):
128 return
129 remote = ("svn.python.org", 443)
130 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
131 cert_reqs=ssl.CERT_NONE, ciphers="ALL")
132 s.connect(remote)
133 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
134 cert_reqs=ssl.CERT_NONE, ciphers="DEFAULT")
135 s.connect(remote)
136 # Error checking occurs when connecting, because the SSL context
137 # isn't created before.
138 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
139 cert_reqs=ssl.CERT_NONE, ciphers="^$:,;?*'dorothyx")
140 with self.assertRaisesRegexp(ssl.SSLError, "No cipher can be selected"):
141 s.connect(remote)
142
Antoine Pitrou9d543662010-04-23 23:10:32 +0000143 @support.cpython_only
144 def test_refcycle(self):
145 # Issue #7943: an SSL object doesn't create reference cycles with
146 # itself.
147 s = socket.socket(socket.AF_INET)
148 ss = ssl.wrap_socket(s)
149 wr = weakref.ref(ss)
150 del ss
151 self.assertEqual(wr(), None)
152
Antoine Pitrou40f08742010-04-24 22:04:40 +0000153 def test_timeout(self):
154 # Issue #8524: when creating an SSL socket, the timeout of the
155 # original socket should be retained.
156 for timeout in (None, 0.0, 5.0):
157 s = socket.socket(socket.AF_INET)
158 s.settimeout(timeout)
159 ss = ssl.wrap_socket(s)
160 self.assertEqual(timeout, ss.gettimeout())
161
Antoine Pitrou04f6a322010-04-05 21:40:07 +0000162
Bill Janssen6e027db2007-11-15 22:23:56 +0000163class NetworkedTests(unittest.TestCase):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000164
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000165 def testConnect(self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000166 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
167 cert_reqs=ssl.CERT_NONE)
168 s.connect(("svn.python.org", 443))
169 c = s.getpeercert()
170 if c:
Antoine Pitrou18c913e2010-04-27 10:59:39 +0000171 self.fail("Peer cert %s shouldn't be here!")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000172 s.close()
173
174 # this should fail because we have no verification certs
175 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
176 cert_reqs=ssl.CERT_REQUIRED)
Thomas Woutersed03b412007-08-28 21:37:11 +0000177 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000178 s.connect(("svn.python.org", 443))
179 except ssl.SSLError:
180 pass
181 finally:
182 s.close()
183
184 # this should succeed because we specify the root cert
185 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
186 cert_reqs=ssl.CERT_REQUIRED,
187 ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
188 try:
189 s.connect(("svn.python.org", 443))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000190 finally:
191 s.close()
192
Antoine Pitroue3220242010-04-24 11:13:53 +0000193 @unittest.skipIf(os.name == "nt", "Can't use a socket as a file under Windows")
194 def test_makefile_close(self):
195 # Issue #5238: creating a file-like object with makefile() shouldn't
196 # delay closing the underlying "real socket" (here tested with its
197 # file descriptor, hence skipping the test under Windows).
198 ss = ssl.wrap_socket(socket.socket(socket.AF_INET))
199 ss.connect(("svn.python.org", 443))
200 fd = ss.fileno()
201 f = ss.makefile()
202 f.close()
203 # The fd is still open
204 os.read(fd, 0)
205 # Closing the SSL socket should close the fd too
206 ss.close()
207 gc.collect()
208 with self.assertRaises(OSError) as e:
209 os.read(fd, 0)
210 self.assertEqual(e.exception.errno, errno.EBADF)
211
Bill Janssen6e027db2007-11-15 22:23:56 +0000212 def testNonBlockingHandshake(self):
213 s = socket.socket(socket.AF_INET)
214 s.connect(("svn.python.org", 443))
215 s.setblocking(False)
216 s = ssl.wrap_socket(s,
217 cert_reqs=ssl.CERT_NONE,
218 do_handshake_on_connect=False)
219 count = 0
220 while True:
221 try:
222 count += 1
223 s.do_handshake()
224 break
225 except ssl.SSLError as err:
226 if err.args[0] == ssl.SSL_ERROR_WANT_READ:
227 select.select([s], [], [])
228 elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE:
229 select.select([], [s], [])
230 else:
231 raise
232 s.close()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000233 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000234 sys.stdout.write("\nNeeded %d calls to do_handshake() to establish session.\n" % count)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000235
Bill Janssen54cc54c2007-12-14 22:08:56 +0000236 def testFetchServerCert(self):
237
238 pem = ssl.get_server_certificate(("svn.python.org", 443))
239 if not pem:
Antoine Pitrou18c913e2010-04-27 10:59:39 +0000240 self.fail("No server certificate on svn.python.org:443!")
Bill Janssen54cc54c2007-12-14 22:08:56 +0000241
242 return
243
244 try:
245 pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=CERTFILE)
246 except ssl.SSLError as x:
247 #should fail
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000248 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000249 sys.stdout.write("%s\n" % x)
250 else:
Antoine Pitrou18c913e2010-04-27 10:59:39 +0000251 self.fail("Got server certificate %s for svn.python.org!" % pem)
Bill Janssen54cc54c2007-12-14 22:08:56 +0000252
253 pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
254 if not pem:
Antoine Pitrou18c913e2010-04-27 10:59:39 +0000255 self.fail("No server certificate on svn.python.org:443!")
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000256 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000257 sys.stdout.write("\nVerified certificate for svn.python.org:443 is\n%s\n" % pem)
258
Antoine Pitroufec12ff2010-04-21 19:46:23 +0000259 def test_algorithms(self):
260 # Issue #8484: all algorithms should be available when verifying a
261 # certificate.
Antoine Pitrou29619b22010-04-22 18:43:31 +0000262 # SHA256 was added in OpenSSL 0.9.8
263 if ssl.OPENSSL_VERSION_INFO < (0, 9, 8, 0, 15):
264 self.skipTest("SHA256 not available on %r" % ssl.OPENSSL_VERSION)
Antoine Pitroufec12ff2010-04-21 19:46:23 +0000265 # NOTE: https://sha256.tbs-internet.com is another possible test host
266 remote = ("sha2.hboeck.de", 443)
267 sha256_cert = os.path.join(os.path.dirname(__file__), "sha256.pem")
268 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
269 cert_reqs=ssl.CERT_REQUIRED,
270 ca_certs=sha256_cert,)
271 with support.transient_internet():
272 try:
273 s.connect(remote)
274 if support.verbose:
275 sys.stdout.write("\nCipher with %r is %r\n" %
276 (remote, s.cipher()))
277 sys.stdout.write("Certificate is:\n%s\n" %
278 pprint.pformat(s.getpeercert()))
279 finally:
280 s.close()
281
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000282
283try:
284 import threading
285except ImportError:
286 _have_threads = False
287else:
288
289 _have_threads = True
290
291 class ThreadedEchoServer(threading.Thread):
292
293 class ConnectionHandler(threading.Thread):
294
295 """A mildly complicated class, because we want it to work both
296 with and without the SSL wrapper around the socket connection, so
297 that we can test the STARTTLS functionality."""
298
Bill Janssen6e027db2007-11-15 22:23:56 +0000299 def __init__(self, server, connsock, addr):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000300 self.server = server
301 self.running = False
302 self.sock = connsock
Bill Janssen6e027db2007-11-15 22:23:56 +0000303 self.addr = addr
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000304 self.sock.setblocking(1)
305 self.sslconn = None
306 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000307 self.daemon = True
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000308
309 def wrap_conn (self):
310 try:
311 self.sslconn = ssl.wrap_socket(self.sock, server_side=True,
312 certfile=self.server.certificate,
313 ssl_version=self.server.protocol,
314 ca_certs=self.server.cacerts,
Antoine Pitrou2d9cb9c2010-04-17 17:40:45 +0000315 cert_reqs=self.server.certreqs,
316 ciphers=self.server.ciphers)
Antoine Pitrou18c913e2010-04-27 10:59:39 +0000317 except ssl.SSLError:
318 # XXX Various errors can have happened here, for example
319 # a mismatching protocol version, an invalid certificate,
320 # or a low-level bug. This should be made more discriminating.
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000321 if self.server.chatty:
Bill Janssen6e027db2007-11-15 22:23:56 +0000322 handle_error("\n server: bad connection attempt from " + repr(self.addr) + ":\n")
Antoine Pitrou18c913e2010-04-27 10:59:39 +0000323 self.running = False
324 self.server.stop()
Bill Janssen6e027db2007-11-15 22:23:56 +0000325 self.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000326 return False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000327 else:
328 if self.server.certreqs == ssl.CERT_REQUIRED:
329 cert = self.sslconn.getpeercert()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000330 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000331 sys.stdout.write(" client cert is " + pprint.pformat(cert) + "\n")
332 cert_binary = self.sslconn.getpeercert(True)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000333 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000334 sys.stdout.write(" cert binary is " + str(len(cert_binary)) + " bytes\n")
335 cipher = self.sslconn.cipher()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000336 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000337 sys.stdout.write(" server: connection cipher is now " + str(cipher) + "\n")
338 return True
339
340 def read(self):
341 if self.sslconn:
342 return self.sslconn.read()
343 else:
344 return self.sock.recv(1024)
345
346 def write(self, bytes):
347 if self.sslconn:
348 return self.sslconn.write(bytes)
349 else:
350 return self.sock.send(bytes)
351
352 def close(self):
353 if self.sslconn:
354 self.sslconn.close()
355 else:
356 self.sock.close()
357
358 def run (self):
359 self.running = True
360 if not self.server.starttls_server:
361 if not self.wrap_conn():
362 return
363 while self.running:
364 try:
365 msg = self.read()
Bill Janssen6e027db2007-11-15 22:23:56 +0000366 amsg = (msg and str(msg, 'ASCII', 'strict')) or ''
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000367 if not msg:
368 # eof, so quit this handler
369 self.running = False
370 self.close()
Bill Janssen6e027db2007-11-15 22:23:56 +0000371 elif amsg.strip() == 'over':
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000372 if support.verbose and self.server.connectionchatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000373 sys.stdout.write(" server: client closed connection\n")
374 self.close()
375 return
Bill Janssen6e027db2007-11-15 22:23:56 +0000376 elif (self.server.starttls_server and
377 amsg.strip() == 'STARTTLS'):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000378 if support.verbose and self.server.connectionchatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000379 sys.stdout.write(" server: read STARTTLS from client, sending OK...\n")
Bill Janssen6e027db2007-11-15 22:23:56 +0000380 self.write("OK\n".encode("ASCII", "strict"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000381 if not self.wrap_conn():
382 return
Bill Janssen40a0f662008-08-12 16:56:25 +0000383 elif (self.server.starttls_server and self.sslconn
384 and amsg.strip() == 'ENDTLS'):
385 if support.verbose and self.server.connectionchatty:
386 sys.stdout.write(" server: read ENDTLS from client, sending OK...\n")
387 self.write("OK\n".encode("ASCII", "strict"))
388 self.sock = self.sslconn.unwrap()
389 self.sslconn = None
390 if support.verbose and self.server.connectionchatty:
391 sys.stdout.write(" server: connection is now unencrypted...\n")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000392 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000393 if (support.verbose and
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000394 self.server.connectionchatty):
395 ctype = (self.sslconn and "encrypted") or "unencrypted"
396 sys.stdout.write(" server: read %s (%s), sending back %s (%s)...\n"
397 % (repr(msg), ctype, repr(msg.lower()), ctype))
Bill Janssen6e027db2007-11-15 22:23:56 +0000398 self.write(amsg.lower().encode('ASCII', 'strict'))
399 except socket.error:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000400 if self.server.chatty:
401 handle_error("Test server failure:\n")
402 self.close()
403 self.running = False
404 # normally, we'd just stop here, but for the test
405 # harness, we want to stop the server
406 self.server.stop()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000407
Trent Nelson78520002008-04-10 20:54:35 +0000408 def __init__(self, certificate, ssl_version=None,
Antoine Pitrou18c913e2010-04-27 10:59:39 +0000409 certreqs=None, cacerts=None,
Antoine Pitrou2d9cb9c2010-04-17 17:40:45 +0000410 chatty=True, connectionchatty=False, starttls_server=False,
411 ciphers=None):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000412 if ssl_version is None:
413 ssl_version = ssl.PROTOCOL_TLSv1
414 if certreqs is None:
415 certreqs = ssl.CERT_NONE
416 self.certificate = certificate
417 self.protocol = ssl_version
418 self.certreqs = certreqs
419 self.cacerts = cacerts
Antoine Pitrou2d9cb9c2010-04-17 17:40:45 +0000420 self.ciphers = ciphers
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000421 self.chatty = chatty
422 self.connectionchatty = connectionchatty
423 self.starttls_server = starttls_server
424 self.sock = socket.socket()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000425 self.port = support.bind_port(self.sock)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000426 self.flag = None
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000427 self.active = False
428 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000429 self.daemon = True
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000430
431 def start (self, flag=None):
432 self.flag = flag
433 threading.Thread.start(self)
434
435 def run (self):
Antoine Pitrouaf7c6022010-04-27 09:56:02 +0000436 self.sock.settimeout(0.05)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000437 self.sock.listen(5)
438 self.active = True
439 if self.flag:
440 # signal an event
441 self.flag.set()
442 while self.active:
443 try:
444 newconn, connaddr = self.sock.accept()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000445 if support.verbose and self.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000446 sys.stdout.write(' server: new connection from '
Bill Janssen6e027db2007-11-15 22:23:56 +0000447 + repr(connaddr) + '\n')
448 handler = self.ConnectionHandler(self, newconn, connaddr)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000449 handler.start()
450 except socket.timeout:
451 pass
452 except KeyboardInterrupt:
453 self.stop()
Bill Janssen6e027db2007-11-15 22:23:56 +0000454 self.sock.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000455
456 def stop (self):
457 self.active = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000458
Bill Janssen54cc54c2007-12-14 22:08:56 +0000459 class OurHTTPSServer(threading.Thread):
460
461 # This one's based on HTTPServer, which is based on SocketServer
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000462
463 class HTTPSServer(HTTPServer):
464
465 def __init__(self, server_address, RequestHandlerClass, certfile):
466
467 HTTPServer.__init__(self, server_address, RequestHandlerClass)
468 # we assume the certfile contains both private key and certificate
469 self.certfile = certfile
470 self.active = False
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000471 self.active_lock = threading.Lock()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000472 self.allow_reuse_address = True
473
Bill Janssen6e027db2007-11-15 22:23:56 +0000474 def __str__(self):
475 return ('<%s %s:%s>' %
476 (self.__class__.__name__,
477 self.server_name,
478 self.server_port))
479
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000480 def get_request (self):
481 # override this to wrap socket with SSL
482 sock, addr = self.socket.accept()
483 sslconn = ssl.wrap_socket(sock, server_side=True,
484 certfile=self.certfile)
485 return sslconn, addr
486
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000487 class RootedHTTPRequestHandler(SimpleHTTPRequestHandler):
488
489 # need to override translate_path to get a known root,
490 # instead of using os.curdir, since the test could be
491 # run from anywhere
492
493 server_version = "TestHTTPS/1.0"
494
495 root = None
496
497 def translate_path(self, path):
498 """Translate a /-separated PATH to the local filename syntax.
499
500 Components that mean special things to the local file system
501 (e.g. drive or directory names) are ignored. (XXX They should
502 probably be diagnosed.)
503
504 """
505 # abandon query parameters
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000506 path = urllib.parse.urlparse(path)[2]
507 path = os.path.normpath(urllib.parse.unquote(path))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000508 words = path.split('/')
509 words = filter(None, words)
510 path = self.root
511 for word in words:
512 drive, word = os.path.splitdrive(word)
513 head, word = os.path.split(word)
514 if word in self.root: continue
515 path = os.path.join(path, word)
516 return path
517
518 def log_message(self, format, *args):
519
520 # we override this to suppress logging unless "verbose"
521
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000522 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000523 sys.stdout.write(" server (%s:%d %s):\n [%s] %s\n" %
524 (self.server.server_address,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000525 self.server.server_port,
526 self.request.cipher(),
527 self.log_date_time_string(),
528 format%args))
Thomas Woutersed03b412007-08-28 21:37:11 +0000529
530
Trent Nelson78520002008-04-10 20:54:35 +0000531 def __init__(self, certfile):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000532 self.flag = None
533 self.active = False
534 self.RootedHTTPRequestHandler.root = os.path.split(CERTFILE)[0]
535 self.server = self.HTTPSServer(
Antoine Pitrou773b5db2010-04-27 08:53:36 +0000536 (HOST, 0), self.RootedHTTPRequestHandler, certfile)
537 self.port = self.server.server_port
Thomas Woutersed03b412007-08-28 21:37:11 +0000538 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000539 self.daemon = True
Thomas Woutersed03b412007-08-28 21:37:11 +0000540
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000541 def __str__(self):
Bill Janssen6e027db2007-11-15 22:23:56 +0000542 return "<%s %s>" % (self.__class__.__name__, self.server)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000543
544 def start (self, flag=None):
545 self.flag = flag
546 threading.Thread.start(self)
547
Thomas Woutersed03b412007-08-28 21:37:11 +0000548 def run (self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000549 self.active = True
550 if self.flag:
551 self.flag.set()
Antoine Pitrouaf7c6022010-04-27 09:56:02 +0000552 self.server.serve_forever(0.05)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000553 self.active = False
554
555 def stop (self):
556 self.active = False
Antoine Pitrouaf7c6022010-04-27 09:56:02 +0000557 self.server.shutdown()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000558
559
Bill Janssen54cc54c2007-12-14 22:08:56 +0000560 class AsyncoreEchoServer(threading.Thread):
561
562 # this one's based on asyncore.dispatcher
563
564 class EchoServer (asyncore.dispatcher):
565
566 class ConnectionHandler (asyncore.dispatcher_with_send):
567
568 def __init__(self, conn, certfile):
569 self.socket = ssl.wrap_socket(conn, server_side=True,
570 certfile=certfile,
571 do_handshake_on_connect=False)
572 asyncore.dispatcher_with_send.__init__(self, self.socket)
Antoine Pitroud3f8ab82010-04-24 21:26:44 +0000573 self._ssl_accepting = True
574 self._do_ssl_handshake()
Bill Janssen54cc54c2007-12-14 22:08:56 +0000575
576 def readable(self):
577 if isinstance(self.socket, ssl.SSLSocket):
578 while self.socket.pending() > 0:
579 self.handle_read_event()
580 return True
581
Antoine Pitroud3f8ab82010-04-24 21:26:44 +0000582 def _do_ssl_handshake(self):
583 try:
584 self.socket.do_handshake()
585 except ssl.SSLError as err:
586 if err.args[0] in (ssl.SSL_ERROR_WANT_READ,
587 ssl.SSL_ERROR_WANT_WRITE):
588 return
589 elif err.args[0] == ssl.SSL_ERROR_EOF:
590 return self.handle_close()
591 raise
592 except socket.error as err:
593 if err.args[0] == errno.ECONNABORTED:
594 return self.handle_close()
Bill Janssen54cc54c2007-12-14 22:08:56 +0000595 else:
Antoine Pitroud3f8ab82010-04-24 21:26:44 +0000596 self._ssl_accepting = False
597
598 def handle_read(self):
599 if self._ssl_accepting:
600 self._do_ssl_handshake()
601 else:
602 data = self.recv(1024)
603 if support.verbose:
604 sys.stdout.write(" server: read %s from client\n" % repr(data))
605 if not data:
606 self.close()
607 else:
608 self.send(str(data, 'ASCII', 'strict').lower().encode('ASCII', 'strict'))
Bill Janssen54cc54c2007-12-14 22:08:56 +0000609
610 def handle_close(self):
Bill Janssen2f5799b2008-06-29 00:08:12 +0000611 self.close()
Antoine Pitrou18c913e2010-04-27 10:59:39 +0000612 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000613 sys.stdout.write(" server: closed connection %s\n" % self.socket)
614
615 def handle_error(self):
616 raise
617
Antoine Pitrou773b5db2010-04-27 08:53:36 +0000618 def __init__(self, certfile):
Bill Janssen54cc54c2007-12-14 22:08:56 +0000619 self.certfile = certfile
Antoine Pitrou773b5db2010-04-27 08:53:36 +0000620 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
621 self.port = support.bind_port(sock, '')
622 asyncore.dispatcher.__init__(self, sock)
Bill Janssen54cc54c2007-12-14 22:08:56 +0000623 self.listen(5)
624
625 def handle_accept(self):
626 sock_obj, addr = self.accept()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000627 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000628 sys.stdout.write(" server: new connection from %s:%s\n" %addr)
629 self.ConnectionHandler(sock_obj, self.certfile)
630
631 def handle_error(self):
632 raise
633
Trent Nelson78520002008-04-10 20:54:35 +0000634 def __init__(self, certfile):
Bill Janssen54cc54c2007-12-14 22:08:56 +0000635 self.flag = None
636 self.active = False
Antoine Pitrou773b5db2010-04-27 08:53:36 +0000637 self.server = self.EchoServer(certfile)
638 self.port = self.server.port
Bill Janssen54cc54c2007-12-14 22:08:56 +0000639 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000640 self.daemon = True
Bill Janssen54cc54c2007-12-14 22:08:56 +0000641
642 def __str__(self):
643 return "<%s %s>" % (self.__class__.__name__, self.server)
644
645 def start (self, flag=None):
646 self.flag = flag
647 threading.Thread.start(self)
648
649 def run (self):
650 self.active = True
651 if self.flag:
652 self.flag.set()
653 while self.active:
654 try:
655 asyncore.loop(1)
656 except:
657 pass
658
659 def stop (self):
660 self.active = False
661 self.server.close()
662
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000663 def badCertTest (certfile):
Trent Nelson78520002008-04-10 20:54:35 +0000664 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000665 certreqs=ssl.CERT_REQUIRED,
Bill Janssen6e027db2007-11-15 22:23:56 +0000666 cacerts=CERTFILE, chatty=False,
667 connectionchatty=False)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000668 flag = threading.Event()
669 server.start(flag)
670 # wait for it to start
671 flag.wait()
672 # try to connect
673 try:
Thomas Woutersed03b412007-08-28 21:37:11 +0000674 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000675 s = ssl.wrap_socket(socket.socket(),
676 certfile=certfile,
677 ssl_version=ssl.PROTOCOL_TLSv1)
Trent Nelson78520002008-04-10 20:54:35 +0000678 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000679 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000680 if support.verbose:
Antoine Pitrou18c913e2010-04-27 10:59:39 +0000681 sys.stdout.write("\nSSLError is %s\n" % x.args[1])
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000682 else:
Antoine Pitrou18c913e2010-04-27 10:59:39 +0000683 self.fail("Use of invalid cert should have failed!")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000684 finally:
685 server.stop()
686 server.join()
Thomas Woutersed03b412007-08-28 21:37:11 +0000687
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000688 def serverParamsTest (certfile, protocol, certreqs, cacertsfile,
Bill Janssen6e027db2007-11-15 22:23:56 +0000689 client_certfile, client_protocol=None,
690 indata="FOO\n",
Antoine Pitrou2d9cb9c2010-04-17 17:40:45 +0000691 ciphers=None, chatty=False, connectionchatty=False):
Thomas Woutersed03b412007-08-28 21:37:11 +0000692
Trent Nelson78520002008-04-10 20:54:35 +0000693 server = ThreadedEchoServer(certfile,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000694 certreqs=certreqs,
695 ssl_version=protocol,
696 cacerts=cacertsfile,
Antoine Pitrou2d9cb9c2010-04-17 17:40:45 +0000697 ciphers=ciphers,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000698 chatty=chatty,
Bill Janssen6e027db2007-11-15 22:23:56 +0000699 connectionchatty=False)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000700 flag = threading.Event()
701 server.start(flag)
702 # wait for it to start
703 flag.wait()
704 # try to connect
705 if client_protocol is None:
706 client_protocol = protocol
707 try:
Bill Janssen6e027db2007-11-15 22:23:56 +0000708 s = ssl.wrap_socket(socket.socket(),
709 certfile=client_certfile,
710 ca_certs=cacertsfile,
Antoine Pitrou2d9cb9c2010-04-17 17:40:45 +0000711 ciphers=ciphers,
Antoine Pitrou18c913e2010-04-27 10:59:39 +0000712 cert_reqs=certreqs,
Bill Janssen6e027db2007-11-15 22:23:56 +0000713 ssl_version=client_protocol)
Trent Nelson78520002008-04-10 20:54:35 +0000714 s.connect((HOST, server.port))
Antoine Pitrou7d7aede2009-11-25 18:55:32 +0000715 bindata = indata.encode('ASCII', 'strict')
716 for arg in [bindata, bytearray(bindata), memoryview(bindata)]:
717 if connectionchatty:
718 if support.verbose:
719 sys.stdout.write(
720 " client: sending %s...\n" % (repr(indata)))
721 s.write(arg)
722 outdata = s.read()
723 if connectionchatty:
724 if support.verbose:
725 sys.stdout.write(" client: read %s\n" % repr(outdata))
726 outdata = str(outdata, 'ASCII', 'strict')
727 if outdata != indata.lower():
Antoine Pitrou18c913e2010-04-27 10:59:39 +0000728 self.fail(
Antoine Pitrou7d7aede2009-11-25 18:55:32 +0000729 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
730 % (repr(outdata[:min(len(outdata),20)]), len(outdata),
731 repr(indata[:min(len(indata),20)].lower()), len(indata)))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000732 s.write("over\n".encode("ASCII", "strict"))
Bill Janssen6e027db2007-11-15 22:23:56 +0000733 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000734 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000735 sys.stdout.write(" client: closing connection.\n")
736 s.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000737 finally:
738 server.stop()
739 server.join()
Thomas Woutersed03b412007-08-28 21:37:11 +0000740
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000741 def tryProtocolCombo (server_protocol,
742 client_protocol,
743 expectedToWork,
744 certsreqs=None):
Thomas Woutersed03b412007-08-28 21:37:11 +0000745
Benjamin Peterson2a691a82008-03-31 01:51:45 +0000746 if certsreqs is None:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000747 certsreqs = ssl.CERT_NONE
Thomas Woutersed03b412007-08-28 21:37:11 +0000748
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000749 if certsreqs == ssl.CERT_NONE:
750 certtype = "CERT_NONE"
751 elif certsreqs == ssl.CERT_OPTIONAL:
752 certtype = "CERT_OPTIONAL"
753 elif certsreqs == ssl.CERT_REQUIRED:
754 certtype = "CERT_REQUIRED"
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000755 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000756 formatstr = (expectedToWork and " %s->%s %s\n") or " {%s->%s} %s\n"
757 sys.stdout.write(formatstr %
758 (ssl.get_protocol_name(client_protocol),
759 ssl.get_protocol_name(server_protocol),
760 certtype))
761 try:
Antoine Pitrou2d9cb9c2010-04-17 17:40:45 +0000762 # NOTE: we must enable "ALL" ciphers, otherwise an SSLv23 client
763 # will send an SSLv3 hello (rather than SSLv2) starting from
764 # OpenSSL 1.0.0 (see issue #8322).
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000765 serverParamsTest(CERTFILE, server_protocol, certsreqs,
Bill Janssen6e027db2007-11-15 22:23:56 +0000766 CERTFILE, CERTFILE, client_protocol,
Antoine Pitrou2d9cb9c2010-04-17 17:40:45 +0000767 ciphers="ALL",
Bill Janssen6e027db2007-11-15 22:23:56 +0000768 chatty=False, connectionchatty=False)
Antoine Pitrou18c913e2010-04-27 10:59:39 +0000769 # Protocol mismatch can result in either an SSLError, or a
770 # "Connection reset by peer" error.
771 except ssl.SSLError:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000772 if expectedToWork:
773 raise
Antoine Pitrou18c913e2010-04-27 10:59:39 +0000774 except socket.error as e:
775 if expectedToWork or e.errno != errno.ECONNRESET:
776 raise
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000777 else:
778 if not expectedToWork:
Antoine Pitrou18c913e2010-04-27 10:59:39 +0000779 self.fail(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000780 "Client protocol %s succeeded with server protocol %s!"
781 % (ssl.get_protocol_name(client_protocol),
782 ssl.get_protocol_name(server_protocol)))
783
784
Bill Janssen6e027db2007-11-15 22:23:56 +0000785 class ThreadedTests(unittest.TestCase):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000786
Trent Nelson6b240cd2008-04-10 20:12:06 +0000787 def testEcho (self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000788
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000789 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000790 sys.stdout.write("\n")
791 serverParamsTest(CERTFILE, ssl.PROTOCOL_TLSv1, ssl.CERT_NONE,
792 CERTFILE, CERTFILE, ssl.PROTOCOL_TLSv1,
793 chatty=True, connectionchatty=True)
794
795 def testReadCert(self):
796
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000797 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000798 sys.stdout.write("\n")
799 s2 = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000800 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000801 certreqs=ssl.CERT_NONE,
802 ssl_version=ssl.PROTOCOL_SSLv23,
803 cacerts=CERTFILE,
804 chatty=False)
805 flag = threading.Event()
806 server.start(flag)
807 # wait for it to start
808 flag.wait()
809 # try to connect
810 try:
Antoine Pitrou18c913e2010-04-27 10:59:39 +0000811 s = ssl.wrap_socket(socket.socket(),
812 certfile=CERTFILE,
813 ca_certs=CERTFILE,
814 cert_reqs=ssl.CERT_REQUIRED,
815 ssl_version=ssl.PROTOCOL_SSLv23)
816 s.connect((HOST, server.port))
817 cert = s.getpeercert()
818 self.assertTrue(cert, "Can't get peer certificate.")
819 cipher = s.cipher()
820 if support.verbose:
821 sys.stdout.write(pprint.pformat(cert) + '\n')
822 sys.stdout.write("Connection cipher is " + str(cipher) + '.\n')
823 if 'subject' not in cert:
824 self.fail("No subject field in certificate: %s." %
825 pprint.pformat(cert))
826 if ((('organizationName', 'Python Software Foundation'),)
827 not in cert['subject']):
828 self.fail(
829 "Missing or invalid 'organizationName' field in certificate subject; "
830 "should be 'Python Software Foundation'.")
831 s.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000832 finally:
833 server.stop()
834 server.join()
835
836 def testNULLcert(self):
837 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
838 "nullcert.pem"))
839 def testMalformedCert(self):
840 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
841 "badcert.pem"))
Bill Janssen58afe4c2008-09-08 16:45:19 +0000842 def testWrongCert(self):
843 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
844 "wrongcert.pem"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000845 def testMalformedKey(self):
846 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
847 "badkey.pem"))
848
Trent Nelson6b240cd2008-04-10 20:12:06 +0000849 def testRudeShutdown(self):
850
851 listener_ready = threading.Event()
852 listener_gone = threading.Event()
Antoine Pitrou773b5db2010-04-27 08:53:36 +0000853 s = socket.socket()
854 port = support.bind_port(s, HOST)
Trent Nelson6b240cd2008-04-10 20:12:06 +0000855
Antoine Pitrou773b5db2010-04-27 08:53:36 +0000856 # `listener` runs in a thread. It sits in an accept() until
857 # the main thread connects. Then it rudely closes the socket,
858 # and sets Event `listener_gone` to let the main thread know
859 # the socket is gone.
Trent Nelson6b240cd2008-04-10 20:12:06 +0000860 def listener():
Trent Nelson6b240cd2008-04-10 20:12:06 +0000861 s.listen(5)
862 listener_ready.set()
863 s.accept()
Antoine Pitrou773b5db2010-04-27 08:53:36 +0000864 s.close()
Trent Nelson6b240cd2008-04-10 20:12:06 +0000865 listener_gone.set()
866
867 def connector():
868 listener_ready.wait()
Antoine Pitrou773b5db2010-04-27 08:53:36 +0000869 c = socket.socket()
870 c.connect((HOST, port))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000871 listener_gone.wait()
872 try:
Antoine Pitrou773b5db2010-04-27 08:53:36 +0000873 ssl_sock = ssl.wrap_socket(c)
Trent Nelson6b240cd2008-04-10 20:12:06 +0000874 except IOError:
875 pass
876 else:
Antoine Pitrou18c913e2010-04-27 10:59:39 +0000877 self.fail('connecting to closed SSL socket should have failed')
Trent Nelson6b240cd2008-04-10 20:12:06 +0000878
879 t = threading.Thread(target=listener)
880 t.start()
Antoine Pitrou773b5db2010-04-27 08:53:36 +0000881 try:
882 connector()
883 finally:
884 t.join()
Trent Nelson6b240cd2008-04-10 20:12:06 +0000885
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000886 def testProtocolSSL2(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_SSLv2, ssl.PROTOCOL_SSLv2, True)
890 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL)
891 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED)
892 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True)
893 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False)
894 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False)
895
896 def testProtocolSSL23(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000897 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000898 sys.stdout.write("\n")
899 try:
900 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv2, True)
Antoine Pitrou18c913e2010-04-27 10:59:39 +0000901 except (ssl.SSLError, socket.error) as x:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000902 # this fails on some older versions of OpenSSL (0.9.7l, for instance)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000903 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000904 sys.stdout.write(
905 " SSL2 client to SSL23 server test unexpectedly failed:\n %s\n"
906 % str(x))
907 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True)
908 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True)
909 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True)
910
911 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
912 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_OPTIONAL)
913 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
914
915 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
916 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_REQUIRED)
917 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
918
919 def testProtocolSSL3(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000920 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000921 sys.stdout.write("\n")
922 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True)
923 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
924 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
925 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False)
926 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, False)
927 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False)
928
929 def testProtocolTLS1(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000930 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000931 sys.stdout.write("\n")
932 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True)
933 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
934 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
935 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False)
936 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False)
937 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv23, False)
938
939 def testSTARTTLS (self):
940
Bill Janssen40a0f662008-08-12 16:56:25 +0000941 msgs = ("msg 1", "MSG 2", "STARTTLS", "MSG 3", "msg 4", "ENDTLS", "msg 5", "msg 6")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000942
Trent Nelson78520002008-04-10 20:54:35 +0000943 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000944 ssl_version=ssl.PROTOCOL_TLSv1,
945 starttls_server=True,
946 chatty=True,
947 connectionchatty=True)
948 flag = threading.Event()
949 server.start(flag)
950 # wait for it to start
951 flag.wait()
952 # try to connect
953 wrapped = False
954 try:
Antoine Pitrou18c913e2010-04-27 10:59:39 +0000955 s = socket.socket()
956 s.setblocking(1)
957 s.connect((HOST, server.port))
958 if support.verbose:
959 sys.stdout.write("\n")
960 for indata in msgs:
961 msg = indata.encode('ASCII', 'replace')
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000962 if support.verbose:
Antoine Pitrou18c913e2010-04-27 10:59:39 +0000963 sys.stdout.write(
964 " client: sending %s...\n" % repr(msg))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000965 if wrapped:
Antoine Pitrou18c913e2010-04-27 10:59:39 +0000966 conn.write(msg)
967 outdata = conn.read()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000968 else:
Antoine Pitrou18c913e2010-04-27 10:59:39 +0000969 s.send(msg)
970 outdata = s.recv(1024)
971 if (indata == "STARTTLS" and
972 str(outdata, 'ASCII', 'replace').strip().lower().startswith("ok")):
973 if support.verbose:
974 msg = str(outdata, 'ASCII', 'replace')
975 sys.stdout.write(
976 " client: read %s from server, starting TLS...\n"
977 % repr(msg))
978 conn = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1)
979 wrapped = True
980 elif (indata == "ENDTLS" and
981 str(outdata, 'ASCII', 'replace').strip().lower().startswith("ok")):
982 if support.verbose:
983 msg = str(outdata, 'ASCII', 'replace')
984 sys.stdout.write(
985 " client: read %s from server, ending TLS...\n"
986 % repr(msg))
987 s = conn.unwrap()
988 wrapped = False
989 else:
990 if support.verbose:
991 msg = str(outdata, 'ASCII', 'replace')
992 sys.stdout.write(
993 " client: read %s from server\n" % repr(msg))
994 if support.verbose:
995 sys.stdout.write(" client: closing connection.\n")
996 if wrapped:
997 conn.write("over\n".encode("ASCII", "strict"))
998 else:
999 s.send("over\n".encode("ASCII", "strict"))
Bill Janssen6e027db2007-11-15 22:23:56 +00001000 if wrapped:
1001 conn.close()
1002 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001003 s.close()
1004 finally:
1005 server.stop()
1006 server.join()
1007
Bill Janssen54cc54c2007-12-14 22:08:56 +00001008 def testSocketServer(self):
Bill Janssen6e027db2007-11-15 22:23:56 +00001009
Trent Nelson78520002008-04-10 20:54:35 +00001010 server = OurHTTPSServer(CERTFILE)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001011 flag = threading.Event()
1012 server.start(flag)
1013 # wait for it to start
1014 flag.wait()
1015 # try to connect
1016 try:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001017 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001018 sys.stdout.write('\n')
1019 d1 = open(CERTFILE, 'rb').read()
1020 d2 = ''
1021 # now fetch the same data from the HTTPS server
Trent Nelson78520002008-04-10 20:54:35 +00001022 url = 'https://%s:%d/%s' % (
1023 HOST, server.port, os.path.split(CERTFILE)[1])
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001024 f = urllib.request.urlopen(url)
Barry Warsaw820c1202008-06-12 04:06:45 +00001025 dlen = f.info().get("content-length")
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001026 if dlen and (int(dlen) > 0):
1027 d2 = f.read(int(dlen))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001028 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001029 sys.stdout.write(
1030 " client: read %d bytes from remote server '%s'\n"
1031 % (len(d2), server))
1032 f.close()
Antoine Pitrou18c913e2010-04-27 10:59:39 +00001033 self.assertEqual(d1, d2)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001034 finally:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001035 if support.verbose:
Neal Norwitzf9ff5f02008-03-31 05:39:26 +00001036 sys.stdout.write('stopping server\n')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001037 server.stop()
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001038 if support.verbose:
Neal Norwitzf9ff5f02008-03-31 05:39:26 +00001039 sys.stdout.write('joining thread\n')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001040 server.join()
1041
Trent Nelson6b240cd2008-04-10 20:12:06 +00001042 def testAsyncoreServer(self):
1043
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001044 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001045 sys.stdout.write("\n")
1046
1047 indata="FOO\n"
Trent Nelson78520002008-04-10 20:54:35 +00001048 server = AsyncoreEchoServer(CERTFILE)
Trent Nelson6b240cd2008-04-10 20:12:06 +00001049 flag = threading.Event()
1050 server.start(flag)
1051 # wait for it to start
1052 flag.wait()
1053 # try to connect
1054 try:
1055 s = ssl.wrap_socket(socket.socket())
Antoine Pitrou18c913e2010-04-27 10:59:39 +00001056 s.connect(('127.0.0.1', server.port))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001057 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001058 sys.stdout.write(
1059 " client: sending %s...\n" % (repr(indata)))
Antoine Pitrou18c913e2010-04-27 10:59:39 +00001060 s.write(indata.encode('ASCII', 'strict'))
1061 outdata = s.read()
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001062 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001063 sys.stdout.write(" client: read %s\n" % repr(outdata))
1064 outdata = str(outdata, 'ASCII', 'strict')
1065 if outdata != indata.lower():
Antoine Pitrou18c913e2010-04-27 10:59:39 +00001066 self.fail(
Trent Nelson6b240cd2008-04-10 20:12:06 +00001067 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
Antoine Pitrou18c913e2010-04-27 10:59:39 +00001068 % (outdata[:min(len(outdata),20)], len(outdata),
1069 indata[:min(len(indata),20)].lower(), len(indata)))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001070 s.write("over\n".encode("ASCII", "strict"))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001071 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001072 sys.stdout.write(" client: closing connection.\n")
1073 s.close()
1074 finally:
1075 server.stop()
1076 server.join()
1077
Bill Janssen58afe4c2008-09-08 16:45:19 +00001078 def testAllRecvAndSendMethods(self):
1079
1080 if support.verbose:
1081 sys.stdout.write("\n")
1082
1083 server = ThreadedEchoServer(CERTFILE,
1084 certreqs=ssl.CERT_NONE,
1085 ssl_version=ssl.PROTOCOL_TLSv1,
1086 cacerts=CERTFILE,
1087 chatty=True,
1088 connectionchatty=False)
1089 flag = threading.Event()
1090 server.start(flag)
1091 # wait for it to start
1092 flag.wait()
1093 # try to connect
Antoine Pitrou18c913e2010-04-27 10:59:39 +00001094 s = ssl.wrap_socket(socket.socket(),
1095 server_side=False,
1096 certfile=CERTFILE,
1097 ca_certs=CERTFILE,
1098 cert_reqs=ssl.CERT_NONE,
1099 ssl_version=ssl.PROTOCOL_TLSv1)
1100 s.connect((HOST, server.port))
Bill Janssen58afe4c2008-09-08 16:45:19 +00001101 try:
Bill Janssen58afe4c2008-09-08 16:45:19 +00001102 # helper methods for standardising recv* method signatures
1103 def _recv_into():
1104 b = bytearray(b"\0"*100)
1105 count = s.recv_into(b)
1106 return b[:count]
1107
1108 def _recvfrom_into():
1109 b = bytearray(b"\0"*100)
1110 count, addr = s.recvfrom_into(b)
1111 return b[:count]
1112
1113 # (name, method, whether to expect success, *args)
1114 send_methods = [
1115 ('send', s.send, True, []),
1116 ('sendto', s.sendto, False, ["some.address"]),
1117 ('sendall', s.sendall, True, []),
1118 ]
1119 recv_methods = [
1120 ('recv', s.recv, True, []),
1121 ('recvfrom', s.recvfrom, False, ["some.address"]),
1122 ('recv_into', _recv_into, True, []),
1123 ('recvfrom_into', _recvfrom_into, False, []),
1124 ]
1125 data_prefix = "PREFIX_"
1126
1127 for meth_name, send_meth, expect_success, args in send_methods:
1128 indata = data_prefix + meth_name
1129 try:
1130 send_meth(indata.encode('ASCII', 'strict'), *args)
1131 outdata = s.read()
1132 outdata = str(outdata, 'ASCII', 'strict')
1133 if outdata != indata.lower():
Georg Brandl89fad142010-03-14 10:23:39 +00001134 self.fail(
Bill Janssen58afe4c2008-09-08 16:45:19 +00001135 "While sending with <<{name:s}>> bad data "
1136 "<<{outdata:s}>> ({nout:d}) received; "
1137 "expected <<{indata:s}>> ({nin:d})\n".format(
1138 name=meth_name, outdata=repr(outdata[:20]),
1139 nout=len(outdata),
1140 indata=repr(indata[:20]), nin=len(indata)
1141 )
1142 )
1143 except ValueError as e:
1144 if expect_success:
Georg Brandl89fad142010-03-14 10:23:39 +00001145 self.fail(
Bill Janssen58afe4c2008-09-08 16:45:19 +00001146 "Failed to send with method <<{name:s}>>; "
1147 "expected to succeed.\n".format(name=meth_name)
1148 )
1149 if not str(e).startswith(meth_name):
Georg Brandl89fad142010-03-14 10:23:39 +00001150 self.fail(
Bill Janssen58afe4c2008-09-08 16:45:19 +00001151 "Method <<{name:s}>> failed with unexpected "
1152 "exception message: {exp:s}\n".format(
1153 name=meth_name, exp=e
1154 )
1155 )
1156
1157 for meth_name, recv_meth, expect_success, args in recv_methods:
1158 indata = data_prefix + meth_name
1159 try:
1160 s.send(indata.encode('ASCII', 'strict'))
1161 outdata = recv_meth(*args)
1162 outdata = str(outdata, 'ASCII', 'strict')
1163 if outdata != indata.lower():
Georg Brandl89fad142010-03-14 10:23:39 +00001164 self.fail(
Bill Janssen58afe4c2008-09-08 16:45:19 +00001165 "While receiving with <<{name:s}>> bad data "
1166 "<<{outdata:s}>> ({nout:d}) received; "
1167 "expected <<{indata:s}>> ({nin:d})\n".format(
1168 name=meth_name, outdata=repr(outdata[:20]),
1169 nout=len(outdata),
1170 indata=repr(indata[:20]), nin=len(indata)
1171 )
1172 )
1173 except ValueError as e:
1174 if expect_success:
Georg Brandl89fad142010-03-14 10:23:39 +00001175 self.fail(
Bill Janssen58afe4c2008-09-08 16:45:19 +00001176 "Failed to receive with method <<{name:s}>>; "
1177 "expected to succeed.\n".format(name=meth_name)
1178 )
1179 if not str(e).startswith(meth_name):
Georg Brandl89fad142010-03-14 10:23:39 +00001180 self.fail(
Bill Janssen58afe4c2008-09-08 16:45:19 +00001181 "Method <<{name:s}>> failed with unexpected "
1182 "exception message: {exp:s}\n".format(
1183 name=meth_name, exp=e
1184 )
1185 )
1186 # consume data
1187 s.read()
1188
1189 s.write("over\n".encode("ASCII", "strict"))
1190 s.close()
1191 finally:
1192 server.stop()
1193 server.join()
1194
Antoine Pitroud3f8ab82010-04-24 21:26:44 +00001195 def test_handshake_timeout(self):
1196 # Issue #5103: SSL handshake must respect the socket timeout
1197 server = socket.socket(socket.AF_INET)
1198 host = "127.0.0.1"
1199 port = support.bind_port(server)
1200 started = threading.Event()
1201 finish = False
1202
1203 def serve():
1204 server.listen(5)
1205 started.set()
1206 conns = []
1207 while not finish:
1208 r, w, e = select.select([server], [], [], 0.1)
1209 if server in r:
1210 # Let the socket hang around rather than having
1211 # it closed by garbage collection.
1212 conns.append(server.accept()[0])
1213
1214 t = threading.Thread(target=serve)
1215 t.start()
1216 started.wait()
1217
1218 try:
Antoine Pitrou40f08742010-04-24 22:04:40 +00001219 try:
1220 c = socket.socket(socket.AF_INET)
1221 c.settimeout(0.2)
1222 c.connect((host, port))
1223 # Will attempt handshake and time out
1224 self.assertRaisesRegexp(ssl.SSLError, "timed out",
1225 ssl.wrap_socket, c)
1226 finally:
1227 c.close()
Antoine Pitroud3f8ab82010-04-24 21:26:44 +00001228 try:
1229 c = socket.socket(socket.AF_INET)
1230 c = ssl.wrap_socket(c)
1231 c.settimeout(0.2)
1232 # Will attempt handshake and time out
1233 self.assertRaisesRegexp(ssl.SSLError, "timed out",
1234 c.connect, (host, port))
1235 finally:
1236 c.close()
1237 finally:
1238 finish = True
1239 t.join()
1240 server.close()
1241
Bill Janssen58afe4c2008-09-08 16:45:19 +00001242
Thomas Woutersed03b412007-08-28 21:37:11 +00001243def test_main(verbose=False):
1244 if skip_expected:
Benjamin Petersone549ead2009-03-28 21:42:05 +00001245 raise unittest.SkipTest("No SSL support")
Thomas Woutersed03b412007-08-28 21:37:11 +00001246
Trent Nelson78520002008-04-10 20:54:35 +00001247 global CERTFILE, SVN_PYTHON_ORG_ROOT_CERT
Thomas Woutersed03b412007-08-28 21:37:11 +00001248 CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir,
1249 "keycert.pem")
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001250 SVN_PYTHON_ORG_ROOT_CERT = os.path.join(
1251 os.path.dirname(__file__) or os.curdir,
1252 "https_svn_python_org_root.pem")
1253
1254 if (not os.path.exists(CERTFILE) or
1255 not os.path.exists(SVN_PYTHON_ORG_ROOT_CERT)):
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001256 raise support.TestFailed("Can't read certificate files!")
Bill Janssen6e027db2007-11-15 22:23:56 +00001257
Thomas Woutersed03b412007-08-28 21:37:11 +00001258 tests = [BasicTests]
1259
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001260 if support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00001261 tests.append(NetworkedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001262
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001263 if _have_threads:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001264 thread_info = support.threading_setup()
1265 if thread_info and support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00001266 tests.append(ThreadedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001267
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001268 support.run_unittest(*tests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001269
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001270 if _have_threads:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001271 support.threading_cleanup(*thread_info)
Thomas Woutersed03b412007-08-28 21:37:11 +00001272
1273if __name__ == "__main__":
1274 test_main()