blob: 5e659c24ea1ba1e7275046c0039eb9855b09d75d [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])
Antoine Pitrou05830aa2010-04-27 13:15:18 +0000682 except socket.error as x:
683 if test_support.verbose:
684 sys.stdout.write("\nsocket.error is %s\n" % x[1])
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000685 else:
Antoine Pitrou18c913e2010-04-27 10:59:39 +0000686 self.fail("Use of invalid cert should have failed!")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000687 finally:
688 server.stop()
689 server.join()
Thomas Woutersed03b412007-08-28 21:37:11 +0000690
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000691 def serverParamsTest (certfile, protocol, certreqs, cacertsfile,
Bill Janssen6e027db2007-11-15 22:23:56 +0000692 client_certfile, client_protocol=None,
693 indata="FOO\n",
Antoine Pitrou2d9cb9c2010-04-17 17:40:45 +0000694 ciphers=None, chatty=False, connectionchatty=False):
Thomas Woutersed03b412007-08-28 21:37:11 +0000695
Trent Nelson78520002008-04-10 20:54:35 +0000696 server = ThreadedEchoServer(certfile,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000697 certreqs=certreqs,
698 ssl_version=protocol,
699 cacerts=cacertsfile,
Antoine Pitrou2d9cb9c2010-04-17 17:40:45 +0000700 ciphers=ciphers,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000701 chatty=chatty,
Bill Janssen6e027db2007-11-15 22:23:56 +0000702 connectionchatty=False)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000703 flag = threading.Event()
704 server.start(flag)
705 # wait for it to start
706 flag.wait()
707 # try to connect
708 if client_protocol is None:
709 client_protocol = protocol
710 try:
Bill Janssen6e027db2007-11-15 22:23:56 +0000711 s = ssl.wrap_socket(socket.socket(),
712 certfile=client_certfile,
713 ca_certs=cacertsfile,
Antoine Pitrou2d9cb9c2010-04-17 17:40:45 +0000714 ciphers=ciphers,
Antoine Pitrou18c913e2010-04-27 10:59:39 +0000715 cert_reqs=certreqs,
Bill Janssen6e027db2007-11-15 22:23:56 +0000716 ssl_version=client_protocol)
Trent Nelson78520002008-04-10 20:54:35 +0000717 s.connect((HOST, server.port))
Antoine Pitrou7d7aede2009-11-25 18:55:32 +0000718 bindata = indata.encode('ASCII', 'strict')
719 for arg in [bindata, bytearray(bindata), memoryview(bindata)]:
720 if connectionchatty:
721 if support.verbose:
722 sys.stdout.write(
723 " client: sending %s...\n" % (repr(indata)))
724 s.write(arg)
725 outdata = s.read()
726 if connectionchatty:
727 if support.verbose:
728 sys.stdout.write(" client: read %s\n" % repr(outdata))
729 outdata = str(outdata, 'ASCII', 'strict')
730 if outdata != indata.lower():
Antoine Pitrou18c913e2010-04-27 10:59:39 +0000731 self.fail(
Antoine Pitrou7d7aede2009-11-25 18:55:32 +0000732 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
733 % (repr(outdata[:min(len(outdata),20)]), len(outdata),
734 repr(indata[:min(len(indata),20)].lower()), len(indata)))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000735 s.write("over\n".encode("ASCII", "strict"))
Bill Janssen6e027db2007-11-15 22:23:56 +0000736 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000737 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000738 sys.stdout.write(" client: closing connection.\n")
739 s.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000740 finally:
741 server.stop()
742 server.join()
Thomas Woutersed03b412007-08-28 21:37:11 +0000743
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000744 def tryProtocolCombo (server_protocol,
745 client_protocol,
746 expectedToWork,
747 certsreqs=None):
Thomas Woutersed03b412007-08-28 21:37:11 +0000748
Benjamin Peterson2a691a82008-03-31 01:51:45 +0000749 if certsreqs is None:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000750 certsreqs = ssl.CERT_NONE
Thomas Woutersed03b412007-08-28 21:37:11 +0000751
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000752 if certsreqs == ssl.CERT_NONE:
753 certtype = "CERT_NONE"
754 elif certsreqs == ssl.CERT_OPTIONAL:
755 certtype = "CERT_OPTIONAL"
756 elif certsreqs == ssl.CERT_REQUIRED:
757 certtype = "CERT_REQUIRED"
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000758 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000759 formatstr = (expectedToWork and " %s->%s %s\n") or " {%s->%s} %s\n"
760 sys.stdout.write(formatstr %
761 (ssl.get_protocol_name(client_protocol),
762 ssl.get_protocol_name(server_protocol),
763 certtype))
764 try:
Antoine Pitrou2d9cb9c2010-04-17 17:40:45 +0000765 # NOTE: we must enable "ALL" ciphers, otherwise an SSLv23 client
766 # will send an SSLv3 hello (rather than SSLv2) starting from
767 # OpenSSL 1.0.0 (see issue #8322).
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000768 serverParamsTest(CERTFILE, server_protocol, certsreqs,
Bill Janssen6e027db2007-11-15 22:23:56 +0000769 CERTFILE, CERTFILE, client_protocol,
Antoine Pitrou2d9cb9c2010-04-17 17:40:45 +0000770 ciphers="ALL",
Bill Janssen6e027db2007-11-15 22:23:56 +0000771 chatty=False, connectionchatty=False)
Antoine Pitrou18c913e2010-04-27 10:59:39 +0000772 # Protocol mismatch can result in either an SSLError, or a
773 # "Connection reset by peer" error.
774 except ssl.SSLError:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000775 if expectedToWork:
776 raise
Antoine Pitrou18c913e2010-04-27 10:59:39 +0000777 except socket.error as e:
778 if expectedToWork or e.errno != errno.ECONNRESET:
779 raise
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000780 else:
781 if not expectedToWork:
Antoine Pitrou18c913e2010-04-27 10:59:39 +0000782 self.fail(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000783 "Client protocol %s succeeded with server protocol %s!"
784 % (ssl.get_protocol_name(client_protocol),
785 ssl.get_protocol_name(server_protocol)))
786
787
Bill Janssen6e027db2007-11-15 22:23:56 +0000788 class ThreadedTests(unittest.TestCase):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000789
Trent Nelson6b240cd2008-04-10 20:12:06 +0000790 def testEcho (self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000791
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000792 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000793 sys.stdout.write("\n")
794 serverParamsTest(CERTFILE, ssl.PROTOCOL_TLSv1, ssl.CERT_NONE,
795 CERTFILE, CERTFILE, ssl.PROTOCOL_TLSv1,
796 chatty=True, connectionchatty=True)
797
798 def testReadCert(self):
799
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000800 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000801 sys.stdout.write("\n")
802 s2 = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000803 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000804 certreqs=ssl.CERT_NONE,
805 ssl_version=ssl.PROTOCOL_SSLv23,
806 cacerts=CERTFILE,
807 chatty=False)
808 flag = threading.Event()
809 server.start(flag)
810 # wait for it to start
811 flag.wait()
812 # try to connect
813 try:
Antoine Pitrou18c913e2010-04-27 10:59:39 +0000814 s = ssl.wrap_socket(socket.socket(),
815 certfile=CERTFILE,
816 ca_certs=CERTFILE,
817 cert_reqs=ssl.CERT_REQUIRED,
818 ssl_version=ssl.PROTOCOL_SSLv23)
819 s.connect((HOST, server.port))
820 cert = s.getpeercert()
821 self.assertTrue(cert, "Can't get peer certificate.")
822 cipher = s.cipher()
823 if support.verbose:
824 sys.stdout.write(pprint.pformat(cert) + '\n')
825 sys.stdout.write("Connection cipher is " + str(cipher) + '.\n')
826 if 'subject' not in cert:
827 self.fail("No subject field in certificate: %s." %
828 pprint.pformat(cert))
829 if ((('organizationName', 'Python Software Foundation'),)
830 not in cert['subject']):
831 self.fail(
832 "Missing or invalid 'organizationName' field in certificate subject; "
833 "should be 'Python Software Foundation'.")
834 s.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000835 finally:
836 server.stop()
837 server.join()
838
839 def testNULLcert(self):
840 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
841 "nullcert.pem"))
842 def testMalformedCert(self):
843 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
844 "badcert.pem"))
Bill Janssen58afe4c2008-09-08 16:45:19 +0000845 def testWrongCert(self):
846 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
847 "wrongcert.pem"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000848 def testMalformedKey(self):
849 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
850 "badkey.pem"))
851
Trent Nelson6b240cd2008-04-10 20:12:06 +0000852 def testRudeShutdown(self):
853
854 listener_ready = threading.Event()
855 listener_gone = threading.Event()
Antoine Pitrou773b5db2010-04-27 08:53:36 +0000856 s = socket.socket()
857 port = support.bind_port(s, HOST)
Trent Nelson6b240cd2008-04-10 20:12:06 +0000858
Antoine Pitrou773b5db2010-04-27 08:53:36 +0000859 # `listener` runs in a thread. It sits in an accept() until
860 # the main thread connects. Then it rudely closes the socket,
861 # and sets Event `listener_gone` to let the main thread know
862 # the socket is gone.
Trent Nelson6b240cd2008-04-10 20:12:06 +0000863 def listener():
Trent Nelson6b240cd2008-04-10 20:12:06 +0000864 s.listen(5)
865 listener_ready.set()
866 s.accept()
Antoine Pitrou773b5db2010-04-27 08:53:36 +0000867 s.close()
Trent Nelson6b240cd2008-04-10 20:12:06 +0000868 listener_gone.set()
869
870 def connector():
871 listener_ready.wait()
Antoine Pitrou773b5db2010-04-27 08:53:36 +0000872 c = socket.socket()
873 c.connect((HOST, port))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000874 listener_gone.wait()
875 try:
Antoine Pitrou773b5db2010-04-27 08:53:36 +0000876 ssl_sock = ssl.wrap_socket(c)
Trent Nelson6b240cd2008-04-10 20:12:06 +0000877 except IOError:
878 pass
879 else:
Antoine Pitrou18c913e2010-04-27 10:59:39 +0000880 self.fail('connecting to closed SSL socket should have failed')
Trent Nelson6b240cd2008-04-10 20:12:06 +0000881
882 t = threading.Thread(target=listener)
883 t.start()
Antoine Pitrou773b5db2010-04-27 08:53:36 +0000884 try:
885 connector()
886 finally:
887 t.join()
Trent Nelson6b240cd2008-04-10 20:12:06 +0000888
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000889 def testProtocolSSL2(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_SSLv2, ssl.PROTOCOL_SSLv2, True)
893 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL)
894 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED)
895 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True)
896 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False)
897 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False)
898
899 def testProtocolSSL23(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000900 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000901 sys.stdout.write("\n")
902 try:
903 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv2, True)
Antoine Pitrou18c913e2010-04-27 10:59:39 +0000904 except (ssl.SSLError, socket.error) as x:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000905 # this fails on some older versions of OpenSSL (0.9.7l, for instance)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000906 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000907 sys.stdout.write(
908 " SSL2 client to SSL23 server test unexpectedly failed:\n %s\n"
909 % str(x))
910 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True)
911 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True)
912 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True)
913
914 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
915 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_OPTIONAL)
916 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
917
918 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
919 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_REQUIRED)
920 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
921
922 def testProtocolSSL3(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000923 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000924 sys.stdout.write("\n")
925 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True)
926 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
927 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
928 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False)
929 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, False)
930 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False)
931
932 def testProtocolTLS1(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000933 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000934 sys.stdout.write("\n")
935 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True)
936 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
937 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
938 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False)
939 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False)
940 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv23, False)
941
942 def testSTARTTLS (self):
943
Bill Janssen40a0f662008-08-12 16:56:25 +0000944 msgs = ("msg 1", "MSG 2", "STARTTLS", "MSG 3", "msg 4", "ENDTLS", "msg 5", "msg 6")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000945
Trent Nelson78520002008-04-10 20:54:35 +0000946 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000947 ssl_version=ssl.PROTOCOL_TLSv1,
948 starttls_server=True,
949 chatty=True,
950 connectionchatty=True)
951 flag = threading.Event()
952 server.start(flag)
953 # wait for it to start
954 flag.wait()
955 # try to connect
956 wrapped = False
957 try:
Antoine Pitrou18c913e2010-04-27 10:59:39 +0000958 s = socket.socket()
959 s.setblocking(1)
960 s.connect((HOST, server.port))
961 if support.verbose:
962 sys.stdout.write("\n")
963 for indata in msgs:
964 msg = indata.encode('ASCII', 'replace')
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000965 if support.verbose:
Antoine Pitrou18c913e2010-04-27 10:59:39 +0000966 sys.stdout.write(
967 " client: sending %s...\n" % repr(msg))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000968 if wrapped:
Antoine Pitrou18c913e2010-04-27 10:59:39 +0000969 conn.write(msg)
970 outdata = conn.read()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000971 else:
Antoine Pitrou18c913e2010-04-27 10:59:39 +0000972 s.send(msg)
973 outdata = s.recv(1024)
974 if (indata == "STARTTLS" and
975 str(outdata, 'ASCII', 'replace').strip().lower().startswith("ok")):
976 if support.verbose:
977 msg = str(outdata, 'ASCII', 'replace')
978 sys.stdout.write(
979 " client: read %s from server, starting TLS...\n"
980 % repr(msg))
981 conn = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1)
982 wrapped = True
983 elif (indata == "ENDTLS" and
984 str(outdata, 'ASCII', 'replace').strip().lower().startswith("ok")):
985 if support.verbose:
986 msg = str(outdata, 'ASCII', 'replace')
987 sys.stdout.write(
988 " client: read %s from server, ending TLS...\n"
989 % repr(msg))
990 s = conn.unwrap()
991 wrapped = False
992 else:
993 if support.verbose:
994 msg = str(outdata, 'ASCII', 'replace')
995 sys.stdout.write(
996 " client: read %s from server\n" % repr(msg))
997 if support.verbose:
998 sys.stdout.write(" client: closing connection.\n")
999 if wrapped:
1000 conn.write("over\n".encode("ASCII", "strict"))
1001 else:
1002 s.send("over\n".encode("ASCII", "strict"))
Bill Janssen6e027db2007-11-15 22:23:56 +00001003 if wrapped:
1004 conn.close()
1005 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001006 s.close()
1007 finally:
1008 server.stop()
1009 server.join()
1010
Bill Janssen54cc54c2007-12-14 22:08:56 +00001011 def testSocketServer(self):
Bill Janssen6e027db2007-11-15 22:23:56 +00001012
Trent Nelson78520002008-04-10 20:54:35 +00001013 server = OurHTTPSServer(CERTFILE)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001014 flag = threading.Event()
1015 server.start(flag)
1016 # wait for it to start
1017 flag.wait()
1018 # try to connect
1019 try:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001020 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001021 sys.stdout.write('\n')
1022 d1 = open(CERTFILE, 'rb').read()
1023 d2 = ''
1024 # now fetch the same data from the HTTPS server
Trent Nelson78520002008-04-10 20:54:35 +00001025 url = 'https://%s:%d/%s' % (
1026 HOST, server.port, os.path.split(CERTFILE)[1])
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001027 f = urllib.request.urlopen(url)
Barry Warsaw820c1202008-06-12 04:06:45 +00001028 dlen = f.info().get("content-length")
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001029 if dlen and (int(dlen) > 0):
1030 d2 = f.read(int(dlen))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001031 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001032 sys.stdout.write(
1033 " client: read %d bytes from remote server '%s'\n"
1034 % (len(d2), server))
1035 f.close()
Antoine Pitrou18c913e2010-04-27 10:59:39 +00001036 self.assertEqual(d1, d2)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001037 finally:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001038 if support.verbose:
Neal Norwitzf9ff5f02008-03-31 05:39:26 +00001039 sys.stdout.write('stopping server\n')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001040 server.stop()
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001041 if support.verbose:
Neal Norwitzf9ff5f02008-03-31 05:39:26 +00001042 sys.stdout.write('joining thread\n')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001043 server.join()
1044
Trent Nelson6b240cd2008-04-10 20:12:06 +00001045 def testAsyncoreServer(self):
1046
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001047 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001048 sys.stdout.write("\n")
1049
1050 indata="FOO\n"
Trent Nelson78520002008-04-10 20:54:35 +00001051 server = AsyncoreEchoServer(CERTFILE)
Trent Nelson6b240cd2008-04-10 20:12:06 +00001052 flag = threading.Event()
1053 server.start(flag)
1054 # wait for it to start
1055 flag.wait()
1056 # try to connect
1057 try:
1058 s = ssl.wrap_socket(socket.socket())
Antoine Pitrou18c913e2010-04-27 10:59:39 +00001059 s.connect(('127.0.0.1', server.port))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001060 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001061 sys.stdout.write(
1062 " client: sending %s...\n" % (repr(indata)))
Antoine Pitrou18c913e2010-04-27 10:59:39 +00001063 s.write(indata.encode('ASCII', 'strict'))
1064 outdata = s.read()
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001065 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001066 sys.stdout.write(" client: read %s\n" % repr(outdata))
1067 outdata = str(outdata, 'ASCII', 'strict')
1068 if outdata != indata.lower():
Antoine Pitrou18c913e2010-04-27 10:59:39 +00001069 self.fail(
Trent Nelson6b240cd2008-04-10 20:12:06 +00001070 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
Antoine Pitrou18c913e2010-04-27 10:59:39 +00001071 % (outdata[:min(len(outdata),20)], len(outdata),
1072 indata[:min(len(indata),20)].lower(), len(indata)))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001073 s.write("over\n".encode("ASCII", "strict"))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001074 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001075 sys.stdout.write(" client: closing connection.\n")
1076 s.close()
1077 finally:
1078 server.stop()
1079 server.join()
1080
Bill Janssen58afe4c2008-09-08 16:45:19 +00001081 def testAllRecvAndSendMethods(self):
1082
1083 if support.verbose:
1084 sys.stdout.write("\n")
1085
1086 server = ThreadedEchoServer(CERTFILE,
1087 certreqs=ssl.CERT_NONE,
1088 ssl_version=ssl.PROTOCOL_TLSv1,
1089 cacerts=CERTFILE,
1090 chatty=True,
1091 connectionchatty=False)
1092 flag = threading.Event()
1093 server.start(flag)
1094 # wait for it to start
1095 flag.wait()
1096 # try to connect
Antoine Pitrou18c913e2010-04-27 10:59:39 +00001097 s = ssl.wrap_socket(socket.socket(),
1098 server_side=False,
1099 certfile=CERTFILE,
1100 ca_certs=CERTFILE,
1101 cert_reqs=ssl.CERT_NONE,
1102 ssl_version=ssl.PROTOCOL_TLSv1)
1103 s.connect((HOST, server.port))
Bill Janssen58afe4c2008-09-08 16:45:19 +00001104 try:
Bill Janssen58afe4c2008-09-08 16:45:19 +00001105 # helper methods for standardising recv* method signatures
1106 def _recv_into():
1107 b = bytearray(b"\0"*100)
1108 count = s.recv_into(b)
1109 return b[:count]
1110
1111 def _recvfrom_into():
1112 b = bytearray(b"\0"*100)
1113 count, addr = s.recvfrom_into(b)
1114 return b[:count]
1115
1116 # (name, method, whether to expect success, *args)
1117 send_methods = [
1118 ('send', s.send, True, []),
1119 ('sendto', s.sendto, False, ["some.address"]),
1120 ('sendall', s.sendall, True, []),
1121 ]
1122 recv_methods = [
1123 ('recv', s.recv, True, []),
1124 ('recvfrom', s.recvfrom, False, ["some.address"]),
1125 ('recv_into', _recv_into, True, []),
1126 ('recvfrom_into', _recvfrom_into, False, []),
1127 ]
1128 data_prefix = "PREFIX_"
1129
1130 for meth_name, send_meth, expect_success, args in send_methods:
1131 indata = data_prefix + meth_name
1132 try:
1133 send_meth(indata.encode('ASCII', 'strict'), *args)
1134 outdata = s.read()
1135 outdata = str(outdata, 'ASCII', 'strict')
1136 if outdata != indata.lower():
Georg Brandl89fad142010-03-14 10:23:39 +00001137 self.fail(
Bill Janssen58afe4c2008-09-08 16:45:19 +00001138 "While sending with <<{name:s}>> bad data "
1139 "<<{outdata:s}>> ({nout:d}) received; "
1140 "expected <<{indata:s}>> ({nin:d})\n".format(
1141 name=meth_name, outdata=repr(outdata[:20]),
1142 nout=len(outdata),
1143 indata=repr(indata[:20]), nin=len(indata)
1144 )
1145 )
1146 except ValueError as e:
1147 if expect_success:
Georg Brandl89fad142010-03-14 10:23:39 +00001148 self.fail(
Bill Janssen58afe4c2008-09-08 16:45:19 +00001149 "Failed to send with method <<{name:s}>>; "
1150 "expected to succeed.\n".format(name=meth_name)
1151 )
1152 if not str(e).startswith(meth_name):
Georg Brandl89fad142010-03-14 10:23:39 +00001153 self.fail(
Bill Janssen58afe4c2008-09-08 16:45:19 +00001154 "Method <<{name:s}>> failed with unexpected "
1155 "exception message: {exp:s}\n".format(
1156 name=meth_name, exp=e
1157 )
1158 )
1159
1160 for meth_name, recv_meth, expect_success, args in recv_methods:
1161 indata = data_prefix + meth_name
1162 try:
1163 s.send(indata.encode('ASCII', 'strict'))
1164 outdata = recv_meth(*args)
1165 outdata = str(outdata, 'ASCII', 'strict')
1166 if outdata != indata.lower():
Georg Brandl89fad142010-03-14 10:23:39 +00001167 self.fail(
Bill Janssen58afe4c2008-09-08 16:45:19 +00001168 "While receiving with <<{name:s}>> bad data "
1169 "<<{outdata:s}>> ({nout:d}) received; "
1170 "expected <<{indata:s}>> ({nin:d})\n".format(
1171 name=meth_name, outdata=repr(outdata[:20]),
1172 nout=len(outdata),
1173 indata=repr(indata[:20]), nin=len(indata)
1174 )
1175 )
1176 except ValueError as e:
1177 if expect_success:
Georg Brandl89fad142010-03-14 10:23:39 +00001178 self.fail(
Bill Janssen58afe4c2008-09-08 16:45:19 +00001179 "Failed to receive with method <<{name:s}>>; "
1180 "expected to succeed.\n".format(name=meth_name)
1181 )
1182 if not str(e).startswith(meth_name):
Georg Brandl89fad142010-03-14 10:23:39 +00001183 self.fail(
Bill Janssen58afe4c2008-09-08 16:45:19 +00001184 "Method <<{name:s}>> failed with unexpected "
1185 "exception message: {exp:s}\n".format(
1186 name=meth_name, exp=e
1187 )
1188 )
1189 # consume data
1190 s.read()
1191
1192 s.write("over\n".encode("ASCII", "strict"))
1193 s.close()
1194 finally:
1195 server.stop()
1196 server.join()
1197
Antoine Pitroud3f8ab82010-04-24 21:26:44 +00001198 def test_handshake_timeout(self):
1199 # Issue #5103: SSL handshake must respect the socket timeout
1200 server = socket.socket(socket.AF_INET)
1201 host = "127.0.0.1"
1202 port = support.bind_port(server)
1203 started = threading.Event()
1204 finish = False
1205
1206 def serve():
1207 server.listen(5)
1208 started.set()
1209 conns = []
1210 while not finish:
1211 r, w, e = select.select([server], [], [], 0.1)
1212 if server in r:
1213 # Let the socket hang around rather than having
1214 # it closed by garbage collection.
1215 conns.append(server.accept()[0])
1216
1217 t = threading.Thread(target=serve)
1218 t.start()
1219 started.wait()
1220
1221 try:
Antoine Pitrou40f08742010-04-24 22:04:40 +00001222 try:
1223 c = socket.socket(socket.AF_INET)
1224 c.settimeout(0.2)
1225 c.connect((host, port))
1226 # Will attempt handshake and time out
1227 self.assertRaisesRegexp(ssl.SSLError, "timed out",
1228 ssl.wrap_socket, c)
1229 finally:
1230 c.close()
Antoine Pitroud3f8ab82010-04-24 21:26:44 +00001231 try:
1232 c = socket.socket(socket.AF_INET)
1233 c = ssl.wrap_socket(c)
1234 c.settimeout(0.2)
1235 # Will attempt handshake and time out
1236 self.assertRaisesRegexp(ssl.SSLError, "timed out",
1237 c.connect, (host, port))
1238 finally:
1239 c.close()
1240 finally:
1241 finish = True
1242 t.join()
1243 server.close()
1244
Bill Janssen58afe4c2008-09-08 16:45:19 +00001245
Thomas Woutersed03b412007-08-28 21:37:11 +00001246def test_main(verbose=False):
1247 if skip_expected:
Benjamin Petersone549ead2009-03-28 21:42:05 +00001248 raise unittest.SkipTest("No SSL support")
Thomas Woutersed03b412007-08-28 21:37:11 +00001249
Trent Nelson78520002008-04-10 20:54:35 +00001250 global CERTFILE, SVN_PYTHON_ORG_ROOT_CERT
Thomas Woutersed03b412007-08-28 21:37:11 +00001251 CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir,
1252 "keycert.pem")
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001253 SVN_PYTHON_ORG_ROOT_CERT = os.path.join(
1254 os.path.dirname(__file__) or os.curdir,
1255 "https_svn_python_org_root.pem")
1256
1257 if (not os.path.exists(CERTFILE) or
1258 not os.path.exists(SVN_PYTHON_ORG_ROOT_CERT)):
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001259 raise support.TestFailed("Can't read certificate files!")
Bill Janssen6e027db2007-11-15 22:23:56 +00001260
Thomas Woutersed03b412007-08-28 21:37:11 +00001261 tests = [BasicTests]
1262
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001263 if support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00001264 tests.append(NetworkedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001265
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001266 if _have_threads:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001267 thread_info = support.threading_setup()
1268 if thread_info and support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00001269 tests.append(ThreadedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001270
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001271 support.run_unittest(*tests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001272
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001273 if _have_threads:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001274 support.threading_cleanup(*thread_info)
Thomas Woutersed03b412007-08-28 21:37:11 +00001275
1276if __name__ == "__main__":
1277 test_main()