blob: 77a5d6d7b6a5a8a52b9e9db64ba82adc9f109e38 [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
9import os
10import pprint
Jeremy Hylton1afc1692008-06-18 20:49:58 +000011import urllib.parse, urllib.request
Thomas Woutersed03b412007-08-28 21:37:11 +000012import traceback
Bill Janssen54cc54c2007-12-14 22:08:56 +000013import asyncore
Thomas Woutersed03b412007-08-28 21:37:11 +000014
Georg Brandl24420152008-05-26 16:32:26 +000015from http.server import HTTPServer, SimpleHTTPRequestHandler
Thomas Wouters1b7f8912007-09-19 03:06:30 +000016
Thomas Woutersed03b412007-08-28 21:37:11 +000017# Optionally test SSL support, if we have it in the tested platform
18skip_expected = False
19try:
20 import ssl
21except ImportError:
22 skip_expected = True
23
Benjamin Petersonee8712c2008-05-20 21:35:26 +000024HOST = support.HOST
Thomas Woutersed03b412007-08-28 21:37:11 +000025CERTFILE = None
Thomas Wouters1b7f8912007-09-19 03:06:30 +000026SVN_PYTHON_ORG_ROOT_CERT = None
Thomas Woutersed03b412007-08-28 21:37:11 +000027
Thomas Woutersed03b412007-08-28 21:37:11 +000028def handle_error(prefix):
29 exc_format = ' '.join(traceback.format_exception(*sys.exc_info()))
Benjamin Petersonee8712c2008-05-20 21:35:26 +000030 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000031 sys.stdout.write(prefix + exc_format)
Thomas Woutersed03b412007-08-28 21:37:11 +000032
33
34class BasicTests(unittest.TestCase):
35
Georg Brandlfceab5a2008-01-19 20:08:23 +000036 def testSSLconnect(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +000037 if not support.is_resource_enabled('network'):
Georg Brandlfceab5a2008-01-19 20:08:23 +000038 return
39 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
40 cert_reqs=ssl.CERT_NONE)
41 s.connect(("svn.python.org", 443))
42 c = s.getpeercert()
43 if c:
Benjamin Petersonee8712c2008-05-20 21:35:26 +000044 raise support.TestFailed("Peer cert %s shouldn't be here!")
Georg Brandlfceab5a2008-01-19 20:08:23 +000045 s.close()
46
47 # this should fail because we have no verification certs
48 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
49 cert_reqs=ssl.CERT_REQUIRED)
50 try:
51 s.connect(("svn.python.org", 443))
52 except ssl.SSLError:
53 pass
54 finally:
55 s.close()
56
Thomas Wouters1b7f8912007-09-19 03:06:30 +000057 def testCrucialConstants(self):
58 ssl.PROTOCOL_SSLv2
59 ssl.PROTOCOL_SSLv23
60 ssl.PROTOCOL_SSLv3
61 ssl.PROTOCOL_TLSv1
62 ssl.CERT_NONE
63 ssl.CERT_OPTIONAL
64 ssl.CERT_REQUIRED
Thomas Woutersed03b412007-08-28 21:37:11 +000065
Thomas Wouters1b7f8912007-09-19 03:06:30 +000066 def testRAND(self):
67 v = ssl.RAND_status()
Benjamin Petersonee8712c2008-05-20 21:35:26 +000068 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000069 sys.stdout.write("\n RAND_status is %d (%s)\n"
70 % (v, (v and "sufficient randomness") or
71 "insufficient randomness"))
Thomas Woutersed03b412007-08-28 21:37:11 +000072 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000073 ssl.RAND_egd(1)
74 except TypeError:
75 pass
Thomas Woutersed03b412007-08-28 21:37:11 +000076 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000077 print("didn't raise TypeError")
78 ssl.RAND_add("this is a random string", 75.0)
Thomas Woutersed03b412007-08-28 21:37:11 +000079
Thomas Wouters1b7f8912007-09-19 03:06:30 +000080 def testParseCert(self):
81 # note that this uses an 'unofficial' function in _ssl.c,
82 # provided solely for this test, to exercise the certificate
83 # parsing code
84 p = ssl._ssl._test_decode_cert(CERTFILE, False)
Benjamin Petersonee8712c2008-05-20 21:35:26 +000085 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000086 sys.stdout.write("\n" + pprint.pformat(p) + "\n")
Thomas Woutersed03b412007-08-28 21:37:11 +000087
Thomas Wouters1b7f8912007-09-19 03:06:30 +000088 def testDERtoPEM(self):
89
90 pem = open(SVN_PYTHON_ORG_ROOT_CERT, 'r').read()
91 d1 = ssl.PEM_cert_to_DER_cert(pem)
92 p2 = ssl.DER_cert_to_PEM_cert(d1)
93 d2 = ssl.PEM_cert_to_DER_cert(p2)
94 if (d1 != d2):
Benjamin Petersonee8712c2008-05-20 21:35:26 +000095 raise support.TestFailed("PEM-to-DER or DER-to-PEM translation failed")
Thomas Wouters1b7f8912007-09-19 03:06:30 +000096
Antoine Pitrou04f6a322010-04-05 21:40:07 +000097 def test_openssl_version(self):
98 n = ssl.OPENSSL_VERSION_NUMBER
99 t = ssl.OPENSSL_VERSION_INFO
100 s = ssl.OPENSSL_VERSION
101 self.assertIsInstance(n, int)
102 self.assertIsInstance(t, tuple)
103 self.assertIsInstance(s, str)
104 # Some sanity checks follow
105 # >= 0.9
106 self.assertGreaterEqual(n, 0x900000)
107 # < 2.0
108 self.assertLess(n, 0x20000000)
109 major, minor, fix, patch, status = t
110 self.assertGreaterEqual(major, 0)
111 self.assertLess(major, 2)
112 self.assertGreaterEqual(minor, 0)
113 self.assertLess(minor, 256)
114 self.assertGreaterEqual(fix, 0)
115 self.assertLess(fix, 256)
116 self.assertGreaterEqual(patch, 0)
117 self.assertLessEqual(patch, 26)
118 self.assertGreaterEqual(status, 0)
119 self.assertLessEqual(status, 15)
120 # Version string as returned by OpenSSL, the format might change
121 self.assertTrue(s.startswith("OpenSSL {:d}.{:d}.{:d}".format(major, minor, fix)),
122 (s, t))
123
Antoine Pitrou2d9cb9c2010-04-17 17:40:45 +0000124 def test_ciphers(self):
125 if not support.is_resource_enabled('network'):
126 return
127 remote = ("svn.python.org", 443)
128 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
129 cert_reqs=ssl.CERT_NONE, ciphers="ALL")
130 s.connect(remote)
131 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
132 cert_reqs=ssl.CERT_NONE, ciphers="DEFAULT")
133 s.connect(remote)
134 # Error checking occurs when connecting, because the SSL context
135 # isn't created before.
136 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
137 cert_reqs=ssl.CERT_NONE, ciphers="^$:,;?*'dorothyx")
138 with self.assertRaisesRegexp(ssl.SSLError, "No cipher can be selected"):
139 s.connect(remote)
140
Antoine Pitrou04f6a322010-04-05 21:40:07 +0000141
Bill Janssen6e027db2007-11-15 22:23:56 +0000142class NetworkedTests(unittest.TestCase):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000143
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000144 def testConnect(self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000145 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
146 cert_reqs=ssl.CERT_NONE)
147 s.connect(("svn.python.org", 443))
148 c = s.getpeercert()
149 if c:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000150 raise support.TestFailed("Peer cert %s shouldn't be here!")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000151 s.close()
152
153 # this should fail because we have no verification certs
154 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
155 cert_reqs=ssl.CERT_REQUIRED)
Thomas Woutersed03b412007-08-28 21:37:11 +0000156 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000157 s.connect(("svn.python.org", 443))
158 except ssl.SSLError:
159 pass
160 finally:
161 s.close()
162
163 # this should succeed because we specify the root cert
164 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
165 cert_reqs=ssl.CERT_REQUIRED,
166 ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
167 try:
168 s.connect(("svn.python.org", 443))
169 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000170 raise support.TestFailed("Unexpected exception %s" % x)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000171 finally:
172 s.close()
173
Bill Janssen6e027db2007-11-15 22:23:56 +0000174 def testNonBlockingHandshake(self):
175 s = socket.socket(socket.AF_INET)
176 s.connect(("svn.python.org", 443))
177 s.setblocking(False)
178 s = ssl.wrap_socket(s,
179 cert_reqs=ssl.CERT_NONE,
180 do_handshake_on_connect=False)
181 count = 0
182 while True:
183 try:
184 count += 1
185 s.do_handshake()
186 break
187 except ssl.SSLError as err:
188 if err.args[0] == ssl.SSL_ERROR_WANT_READ:
189 select.select([s], [], [])
190 elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE:
191 select.select([], [s], [])
192 else:
193 raise
194 s.close()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000195 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000196 sys.stdout.write("\nNeeded %d calls to do_handshake() to establish session.\n" % count)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000197
Bill Janssen54cc54c2007-12-14 22:08:56 +0000198 def testFetchServerCert(self):
199
200 pem = ssl.get_server_certificate(("svn.python.org", 443))
201 if not pem:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000202 raise support.TestFailed("No server certificate on svn.python.org:443!")
Bill Janssen54cc54c2007-12-14 22:08:56 +0000203
204 return
205
206 try:
207 pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=CERTFILE)
208 except ssl.SSLError as x:
209 #should fail
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000210 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000211 sys.stdout.write("%s\n" % x)
212 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000213 raise support.TestFailed("Got server certificate %s for svn.python.org!" % pem)
Bill Janssen54cc54c2007-12-14 22:08:56 +0000214
215 pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
216 if not pem:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000217 raise support.TestFailed("No server certificate on svn.python.org:443!")
218 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000219 sys.stdout.write("\nVerified certificate for svn.python.org:443 is\n%s\n" % pem)
220
Antoine Pitroufec12ff2010-04-21 19:46:23 +0000221 def test_algorithms(self):
222 # Issue #8484: all algorithms should be available when verifying a
223 # certificate.
224 # NOTE: https://sha256.tbs-internet.com is another possible test host
225 remote = ("sha2.hboeck.de", 443)
226 sha256_cert = os.path.join(os.path.dirname(__file__), "sha256.pem")
227 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
228 cert_reqs=ssl.CERT_REQUIRED,
229 ca_certs=sha256_cert,)
230 with support.transient_internet():
231 try:
232 s.connect(remote)
233 if support.verbose:
234 sys.stdout.write("\nCipher with %r is %r\n" %
235 (remote, s.cipher()))
236 sys.stdout.write("Certificate is:\n%s\n" %
237 pprint.pformat(s.getpeercert()))
238 finally:
239 s.close()
240
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000241
242try:
243 import threading
244except ImportError:
245 _have_threads = False
246else:
247
248 _have_threads = True
249
250 class ThreadedEchoServer(threading.Thread):
251
252 class ConnectionHandler(threading.Thread):
253
254 """A mildly complicated class, because we want it to work both
255 with and without the SSL wrapper around the socket connection, so
256 that we can test the STARTTLS functionality."""
257
Bill Janssen6e027db2007-11-15 22:23:56 +0000258 def __init__(self, server, connsock, addr):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000259 self.server = server
260 self.running = False
261 self.sock = connsock
Bill Janssen6e027db2007-11-15 22:23:56 +0000262 self.addr = addr
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000263 self.sock.setblocking(1)
264 self.sslconn = None
265 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000266 self.daemon = True
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000267
268 def wrap_conn (self):
269 try:
270 self.sslconn = ssl.wrap_socket(self.sock, server_side=True,
271 certfile=self.server.certificate,
272 ssl_version=self.server.protocol,
273 ca_certs=self.server.cacerts,
Antoine Pitrou2d9cb9c2010-04-17 17:40:45 +0000274 cert_reqs=self.server.certreqs,
275 ciphers=self.server.ciphers)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000276 except:
277 if self.server.chatty:
Bill Janssen6e027db2007-11-15 22:23:56 +0000278 handle_error("\n server: bad connection attempt from " + repr(self.addr) + ":\n")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000279 if not self.server.expect_bad_connects:
280 # here, we want to stop the server, because this shouldn't
281 # happen in the context of our test case
282 self.running = False
283 # normally, we'd just stop here, but for the test
284 # harness, we want to stop the server
285 self.server.stop()
Bill Janssen6e027db2007-11-15 22:23:56 +0000286 self.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000287 return False
288
289 else:
290 if self.server.certreqs == ssl.CERT_REQUIRED:
291 cert = self.sslconn.getpeercert()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000292 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000293 sys.stdout.write(" client cert is " + pprint.pformat(cert) + "\n")
294 cert_binary = self.sslconn.getpeercert(True)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000295 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000296 sys.stdout.write(" cert binary is " + str(len(cert_binary)) + " bytes\n")
297 cipher = self.sslconn.cipher()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000298 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000299 sys.stdout.write(" server: connection cipher is now " + str(cipher) + "\n")
300 return True
301
302 def read(self):
303 if self.sslconn:
304 return self.sslconn.read()
305 else:
306 return self.sock.recv(1024)
307
308 def write(self, bytes):
309 if self.sslconn:
310 return self.sslconn.write(bytes)
311 else:
312 return self.sock.send(bytes)
313
314 def close(self):
315 if self.sslconn:
316 self.sslconn.close()
317 else:
318 self.sock.close()
319
320 def run (self):
321 self.running = True
322 if not self.server.starttls_server:
323 if not self.wrap_conn():
324 return
325 while self.running:
326 try:
327 msg = self.read()
Bill Janssen6e027db2007-11-15 22:23:56 +0000328 amsg = (msg and str(msg, 'ASCII', 'strict')) or ''
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000329 if not msg:
330 # eof, so quit this handler
331 self.running = False
332 self.close()
Bill Janssen6e027db2007-11-15 22:23:56 +0000333 elif amsg.strip() == 'over':
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000334 if support.verbose and self.server.connectionchatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000335 sys.stdout.write(" server: client closed connection\n")
336 self.close()
337 return
Bill Janssen6e027db2007-11-15 22:23:56 +0000338 elif (self.server.starttls_server and
339 amsg.strip() == 'STARTTLS'):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000340 if support.verbose and self.server.connectionchatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000341 sys.stdout.write(" server: read STARTTLS from client, sending OK...\n")
Bill Janssen6e027db2007-11-15 22:23:56 +0000342 self.write("OK\n".encode("ASCII", "strict"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000343 if not self.wrap_conn():
344 return
Bill Janssen40a0f662008-08-12 16:56:25 +0000345 elif (self.server.starttls_server and self.sslconn
346 and amsg.strip() == 'ENDTLS'):
347 if support.verbose and self.server.connectionchatty:
348 sys.stdout.write(" server: read ENDTLS from client, sending OK...\n")
349 self.write("OK\n".encode("ASCII", "strict"))
350 self.sock = self.sslconn.unwrap()
351 self.sslconn = None
352 if support.verbose and self.server.connectionchatty:
353 sys.stdout.write(" server: connection is now unencrypted...\n")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000354 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000355 if (support.verbose and
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000356 self.server.connectionchatty):
357 ctype = (self.sslconn and "encrypted") or "unencrypted"
358 sys.stdout.write(" server: read %s (%s), sending back %s (%s)...\n"
359 % (repr(msg), ctype, repr(msg.lower()), ctype))
Bill Janssen6e027db2007-11-15 22:23:56 +0000360 self.write(amsg.lower().encode('ASCII', 'strict'))
361 except socket.error:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000362 if self.server.chatty:
363 handle_error("Test server failure:\n")
364 self.close()
365 self.running = False
366 # normally, we'd just stop here, but for the test
367 # harness, we want to stop the server
368 self.server.stop()
369 except:
370 handle_error('')
371
Trent Nelson78520002008-04-10 20:54:35 +0000372 def __init__(self, certificate, ssl_version=None,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000373 certreqs=None, cacerts=None, expect_bad_connects=False,
Antoine Pitrou2d9cb9c2010-04-17 17:40:45 +0000374 chatty=True, connectionchatty=False, starttls_server=False,
375 ciphers=None):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000376 if ssl_version is None:
377 ssl_version = ssl.PROTOCOL_TLSv1
378 if certreqs is None:
379 certreqs = ssl.CERT_NONE
380 self.certificate = certificate
381 self.protocol = ssl_version
382 self.certreqs = certreqs
383 self.cacerts = cacerts
Antoine Pitrou2d9cb9c2010-04-17 17:40:45 +0000384 self.ciphers = ciphers
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000385 self.expect_bad_connects = expect_bad_connects
386 self.chatty = chatty
387 self.connectionchatty = connectionchatty
388 self.starttls_server = starttls_server
389 self.sock = socket.socket()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000390 self.port = support.bind_port(self.sock)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000391 self.flag = None
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000392 self.active = False
393 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000394 self.daemon = True
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000395
396 def start (self, flag=None):
397 self.flag = flag
398 threading.Thread.start(self)
399
400 def run (self):
401 self.sock.settimeout(0.5)
402 self.sock.listen(5)
403 self.active = True
404 if self.flag:
405 # signal an event
406 self.flag.set()
407 while self.active:
408 try:
409 newconn, connaddr = self.sock.accept()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000410 if support.verbose and self.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000411 sys.stdout.write(' server: new connection from '
Bill Janssen6e027db2007-11-15 22:23:56 +0000412 + repr(connaddr) + '\n')
413 handler = self.ConnectionHandler(self, newconn, connaddr)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000414 handler.start()
415 except socket.timeout:
416 pass
417 except KeyboardInterrupt:
418 self.stop()
419 except:
420 if self.chatty:
421 handle_error("Test server failure:\n")
Bill Janssen6e027db2007-11-15 22:23:56 +0000422 self.sock.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000423
424 def stop (self):
425 self.active = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000426
Bill Janssen54cc54c2007-12-14 22:08:56 +0000427 class OurHTTPSServer(threading.Thread):
428
429 # This one's based on HTTPServer, which is based on SocketServer
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000430
431 class HTTPSServer(HTTPServer):
432
433 def __init__(self, server_address, RequestHandlerClass, certfile):
434
435 HTTPServer.__init__(self, server_address, RequestHandlerClass)
436 # we assume the certfile contains both private key and certificate
437 self.certfile = certfile
438 self.active = False
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000439 self.active_lock = threading.Lock()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000440 self.allow_reuse_address = True
441
Bill Janssen6e027db2007-11-15 22:23:56 +0000442 def __str__(self):
443 return ('<%s %s:%s>' %
444 (self.__class__.__name__,
445 self.server_name,
446 self.server_port))
447
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000448 def get_request (self):
449 # override this to wrap socket with SSL
450 sock, addr = self.socket.accept()
451 sslconn = ssl.wrap_socket(sock, server_side=True,
452 certfile=self.certfile)
453 return sslconn, addr
454
455 # The methods overridden below this are mainly so that we
456 # can run it in a thread and be able to stop it from another
457 # You probably wouldn't need them in other uses.
458
459 def server_activate(self):
460 # We want to run this in a thread for testing purposes,
461 # so we override this to set timeout, so that we get
462 # a chance to stop the server
463 self.socket.settimeout(0.5)
464 HTTPServer.server_activate(self)
465
466 def serve_forever(self):
467 # We want this to run in a thread, so we use a slightly
468 # modified version of "forever".
469 self.active = True
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000470 while 1:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000471 try:
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000472 # We need to lock while handling the request.
473 # Another thread can close the socket after self.active
474 # has been checked and before the request is handled.
475 # This causes an exception when using the closed socket.
476 with self.active_lock:
477 if not self.active:
478 break
479 self.handle_request()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000480 except socket.timeout:
481 pass
482 except KeyboardInterrupt:
483 self.server_close()
484 return
485 except:
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000486 sys.stdout.write(''.join(traceback.format_exception(*sys.exc_info())))
487 break
Neal Norwitzf9ff5f02008-03-31 05:39:26 +0000488 time.sleep(0.1)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000489
490 def server_close(self):
491 # Again, we want this to run in a thread, so we need to override
492 # close to clear the "active" flag, so that serve_forever() will
493 # terminate.
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000494 with self.active_lock:
495 HTTPServer.server_close(self)
496 self.active = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000497
498 class RootedHTTPRequestHandler(SimpleHTTPRequestHandler):
499
500 # need to override translate_path to get a known root,
501 # instead of using os.curdir, since the test could be
502 # run from anywhere
503
504 server_version = "TestHTTPS/1.0"
505
506 root = None
507
508 def translate_path(self, path):
509 """Translate a /-separated PATH to the local filename syntax.
510
511 Components that mean special things to the local file system
512 (e.g. drive or directory names) are ignored. (XXX They should
513 probably be diagnosed.)
514
515 """
516 # abandon query parameters
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000517 path = urllib.parse.urlparse(path)[2]
518 path = os.path.normpath(urllib.parse.unquote(path))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000519 words = path.split('/')
520 words = filter(None, words)
521 path = self.root
522 for word in words:
523 drive, word = os.path.splitdrive(word)
524 head, word = os.path.split(word)
525 if word in self.root: continue
526 path = os.path.join(path, word)
527 return path
528
529 def log_message(self, format, *args):
530
531 # we override this to suppress logging unless "verbose"
532
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000533 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000534 sys.stdout.write(" server (%s:%d %s):\n [%s] %s\n" %
535 (self.server.server_address,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000536 self.server.server_port,
537 self.request.cipher(),
538 self.log_date_time_string(),
539 format%args))
Thomas Woutersed03b412007-08-28 21:37:11 +0000540
541
Trent Nelson78520002008-04-10 20:54:35 +0000542 def __init__(self, certfile):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000543 self.flag = None
544 self.active = False
545 self.RootedHTTPRequestHandler.root = os.path.split(CERTFILE)[0]
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000546 self.port = support.find_unused_port()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000547 self.server = self.HTTPSServer(
Trent Nelson78520002008-04-10 20:54:35 +0000548 (HOST, self.port), self.RootedHTTPRequestHandler, certfile)
Thomas Woutersed03b412007-08-28 21:37:11 +0000549 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000550 self.daemon = True
Thomas Woutersed03b412007-08-28 21:37:11 +0000551
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000552 def __str__(self):
Bill Janssen6e027db2007-11-15 22:23:56 +0000553 return "<%s %s>" % (self.__class__.__name__, self.server)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000554
555 def start (self, flag=None):
556 self.flag = flag
557 threading.Thread.start(self)
558
Thomas Woutersed03b412007-08-28 21:37:11 +0000559 def run (self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000560 self.active = True
561 if self.flag:
562 self.flag.set()
563 self.server.serve_forever()
564 self.active = False
565
566 def stop (self):
567 self.active = False
568 self.server.server_close()
569
570
Bill Janssen54cc54c2007-12-14 22:08:56 +0000571 class AsyncoreEchoServer(threading.Thread):
572
573 # this one's based on asyncore.dispatcher
574
575 class EchoServer (asyncore.dispatcher):
576
577 class ConnectionHandler (asyncore.dispatcher_with_send):
578
579 def __init__(self, conn, certfile):
580 self.socket = ssl.wrap_socket(conn, server_side=True,
581 certfile=certfile,
582 do_handshake_on_connect=False)
583 asyncore.dispatcher_with_send.__init__(self, self.socket)
584 # now we have to do the handshake
585 # we'll just do it the easy way, and block the connection
586 # till it's finished. If we were doing it right, we'd
587 # do this in multiple calls to handle_read...
588 self.do_handshake(block=True)
589
590 def readable(self):
591 if isinstance(self.socket, ssl.SSLSocket):
592 while self.socket.pending() > 0:
593 self.handle_read_event()
594 return True
595
596 def handle_read(self):
597 data = self.recv(1024)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000598 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000599 sys.stdout.write(" server: read %s from client\n" % repr(data))
600 if not data:
601 self.close()
602 else:
603 self.send(str(data, 'ASCII', 'strict').lower().encode('ASCII', 'strict'))
604
605 def handle_close(self):
Bill Janssen2f5799b2008-06-29 00:08:12 +0000606 self.close()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000607 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000608 sys.stdout.write(" server: closed connection %s\n" % self.socket)
609
610 def handle_error(self):
611 raise
612
613 def __init__(self, port, certfile):
614 self.port = port
615 self.certfile = certfile
616 asyncore.dispatcher.__init__(self)
617 self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
618 self.bind(('', port))
619 self.listen(5)
620
621 def handle_accept(self):
622 sock_obj, addr = self.accept()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000623 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000624 sys.stdout.write(" server: new connection from %s:%s\n" %addr)
625 self.ConnectionHandler(sock_obj, self.certfile)
626
627 def handle_error(self):
628 raise
629
Trent Nelson78520002008-04-10 20:54:35 +0000630 def __init__(self, certfile):
Bill Janssen54cc54c2007-12-14 22:08:56 +0000631 self.flag = None
632 self.active = False
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000633 self.port = support.find_unused_port()
Trent Nelson78520002008-04-10 20:54:35 +0000634 self.server = self.EchoServer(self.port, certfile)
Bill Janssen54cc54c2007-12-14 22:08:56 +0000635 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000636 self.daemon = True
Bill Janssen54cc54c2007-12-14 22:08:56 +0000637
638 def __str__(self):
639 return "<%s %s>" % (self.__class__.__name__, self.server)
640
641 def start (self, flag=None):
642 self.flag = flag
643 threading.Thread.start(self)
644
645 def run (self):
646 self.active = True
647 if self.flag:
648 self.flag.set()
649 while self.active:
650 try:
651 asyncore.loop(1)
652 except:
653 pass
654
655 def stop (self):
656 self.active = False
657 self.server.close()
658
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000659 def badCertTest (certfile):
Trent Nelson78520002008-04-10 20:54:35 +0000660 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000661 certreqs=ssl.CERT_REQUIRED,
Bill Janssen6e027db2007-11-15 22:23:56 +0000662 cacerts=CERTFILE, chatty=False,
663 connectionchatty=False)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000664 flag = threading.Event()
665 server.start(flag)
666 # wait for it to start
667 flag.wait()
668 # try to connect
669 try:
Thomas Woutersed03b412007-08-28 21:37:11 +0000670 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000671 s = ssl.wrap_socket(socket.socket(),
672 certfile=certfile,
673 ssl_version=ssl.PROTOCOL_TLSv1)
Trent Nelson78520002008-04-10 20:54:35 +0000674 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000675 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000676 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000677 sys.stdout.write("\nSSLError is %s\n" % x)
Bill Janssenddc56692008-07-17 18:17:20 +0000678 except socket.error as x:
679 if support.verbose:
680 sys.stdout.write("\nsocket.error is %s\n" % x)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000681 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000682 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000683 "Use of invalid cert should have failed!")
684 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(),
Trent Nelson6b240cd2008-04-10 20:12:06 +0000709 server_side=False,
Bill Janssen6e027db2007-11-15 22:23:56 +0000710 certfile=client_certfile,
711 ca_certs=cacertsfile,
712 cert_reqs=certreqs,
Antoine Pitrou2d9cb9c2010-04-17 17:40:45 +0000713 ciphers=ciphers,
Bill Janssen6e027db2007-11-15 22:23:56 +0000714 ssl_version=client_protocol)
Trent Nelson78520002008-04-10 20:54:35 +0000715 s.connect((HOST, server.port))
Bill Janssen6e027db2007-11-15 22:23:56 +0000716 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000717 raise support.TestFailed("Unexpected SSL error: " + str(x))
Bill Janssen6e027db2007-11-15 22:23:56 +0000718 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000719 raise support.TestFailed("Unexpected exception: " + str(x))
Bill Janssen6e027db2007-11-15 22:23:56 +0000720 else:
Antoine Pitrou7d7aede2009-11-25 18:55:32 +0000721 bindata = indata.encode('ASCII', 'strict')
722 for arg in [bindata, bytearray(bindata), memoryview(bindata)]:
723 if connectionchatty:
724 if support.verbose:
725 sys.stdout.write(
726 " client: sending %s...\n" % (repr(indata)))
727 s.write(arg)
728 outdata = s.read()
729 if connectionchatty:
730 if support.verbose:
731 sys.stdout.write(" client: read %s\n" % repr(outdata))
732 outdata = str(outdata, 'ASCII', 'strict')
733 if outdata != indata.lower():
734 raise support.TestFailed(
735 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
736 % (repr(outdata[:min(len(outdata),20)]), len(outdata),
737 repr(indata[:min(len(indata),20)].lower()), len(indata)))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000738 s.write("over\n".encode("ASCII", "strict"))
Bill Janssen6e027db2007-11-15 22:23:56 +0000739 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000740 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000741 sys.stdout.write(" client: closing connection.\n")
742 s.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000743 finally:
744 server.stop()
745 server.join()
Thomas Woutersed03b412007-08-28 21:37:11 +0000746
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000747 def tryProtocolCombo (server_protocol,
748 client_protocol,
749 expectedToWork,
750 certsreqs=None):
Thomas Woutersed03b412007-08-28 21:37:11 +0000751
Benjamin Peterson2a691a82008-03-31 01:51:45 +0000752 if certsreqs is None:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000753 certsreqs = ssl.CERT_NONE
Thomas Woutersed03b412007-08-28 21:37:11 +0000754
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000755 if certsreqs == ssl.CERT_NONE:
756 certtype = "CERT_NONE"
757 elif certsreqs == ssl.CERT_OPTIONAL:
758 certtype = "CERT_OPTIONAL"
759 elif certsreqs == ssl.CERT_REQUIRED:
760 certtype = "CERT_REQUIRED"
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000761 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000762 formatstr = (expectedToWork and " %s->%s %s\n") or " {%s->%s} %s\n"
763 sys.stdout.write(formatstr %
764 (ssl.get_protocol_name(client_protocol),
765 ssl.get_protocol_name(server_protocol),
766 certtype))
767 try:
Antoine Pitrou2d9cb9c2010-04-17 17:40:45 +0000768 # NOTE: we must enable "ALL" ciphers, otherwise an SSLv23 client
769 # will send an SSLv3 hello (rather than SSLv2) starting from
770 # OpenSSL 1.0.0 (see issue #8322).
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000771 serverParamsTest(CERTFILE, server_protocol, certsreqs,
Bill Janssen6e027db2007-11-15 22:23:56 +0000772 CERTFILE, CERTFILE, client_protocol,
Antoine Pitrou2d9cb9c2010-04-17 17:40:45 +0000773 ciphers="ALL",
Bill Janssen6e027db2007-11-15 22:23:56 +0000774 chatty=False, connectionchatty=False)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000775 except support.TestFailed:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000776 if expectedToWork:
777 raise
778 else:
779 if not expectedToWork:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000780 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000781 "Client protocol %s succeeded with server protocol %s!"
782 % (ssl.get_protocol_name(client_protocol),
783 ssl.get_protocol_name(server_protocol)))
784
785
Bill Janssen6e027db2007-11-15 22:23:56 +0000786 class ThreadedTests(unittest.TestCase):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000787
Trent Nelson6b240cd2008-04-10 20:12:06 +0000788 def testEcho (self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000789
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000790 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000791 sys.stdout.write("\n")
792 serverParamsTest(CERTFILE, ssl.PROTOCOL_TLSv1, ssl.CERT_NONE,
793 CERTFILE, CERTFILE, ssl.PROTOCOL_TLSv1,
794 chatty=True, connectionchatty=True)
795
796 def testReadCert(self):
797
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000798 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000799 sys.stdout.write("\n")
800 s2 = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000801 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000802 certreqs=ssl.CERT_NONE,
803 ssl_version=ssl.PROTOCOL_SSLv23,
804 cacerts=CERTFILE,
805 chatty=False)
806 flag = threading.Event()
807 server.start(flag)
808 # wait for it to start
809 flag.wait()
810 # try to connect
811 try:
812 try:
813 s = ssl.wrap_socket(socket.socket(),
814 certfile=CERTFILE,
815 ca_certs=CERTFILE,
816 cert_reqs=ssl.CERT_REQUIRED,
817 ssl_version=ssl.PROTOCOL_SSLv23)
Trent Nelson78520002008-04-10 20:54:35 +0000818 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000819 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000820 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000821 "Unexpected SSL error: " + str(x))
822 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000823 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000824 "Unexpected exception: " + str(x))
825 else:
826 if not s:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000827 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000828 "Can't SSL-handshake with test server")
829 cert = s.getpeercert()
830 if not cert:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000831 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000832 "Can't get peer certificate.")
833 cipher = s.cipher()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000834 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000835 sys.stdout.write(pprint.pformat(cert) + '\n')
836 sys.stdout.write("Connection cipher is " + str(cipher) + '.\n')
Bill Janssen6e027db2007-11-15 22:23:56 +0000837 if 'subject' not in cert:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000838 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000839 "No subject field in certificate: %s." %
840 pprint.pformat(cert))
841 if ((('organizationName', 'Python Software Foundation'),)
842 not in cert['subject']):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000843 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000844 "Missing or invalid 'organizationName' field in certificate subject; "
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000845 "should be 'Python Software Foundation'.")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000846 s.close()
847 finally:
848 server.stop()
849 server.join()
850
851 def testNULLcert(self):
852 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
853 "nullcert.pem"))
854 def testMalformedCert(self):
855 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
856 "badcert.pem"))
Bill Janssen58afe4c2008-09-08 16:45:19 +0000857 def testWrongCert(self):
858 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
859 "wrongcert.pem"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000860 def testMalformedKey(self):
861 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
862 "badkey.pem"))
863
Trent Nelson6b240cd2008-04-10 20:12:06 +0000864 def testRudeShutdown(self):
865
866 listener_ready = threading.Event()
867 listener_gone = threading.Event()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000868 port = support.find_unused_port()
Trent Nelson6b240cd2008-04-10 20:12:06 +0000869
870 # `listener` runs in a thread. It opens a socket listening on
871 # PORT, and sits in an accept() until the main thread connects.
872 # Then it rudely closes the socket, and sets Event `listener_gone`
873 # to let the main thread know the socket is gone.
874 def listener():
875 s = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000876 s.bind((HOST, port))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000877 s.listen(5)
878 listener_ready.set()
879 s.accept()
880 s = None # reclaim the socket object, which also closes it
881 listener_gone.set()
882
883 def connector():
884 listener_ready.wait()
885 s = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000886 s.connect((HOST, port))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000887 listener_gone.wait()
888 try:
889 ssl_sock = ssl.wrap_socket(s)
890 except IOError:
891 pass
892 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000893 raise support.TestFailed(
Trent Nelson6b240cd2008-04-10 20:12:06 +0000894 'connecting to closed SSL socket should have failed')
895
896 t = threading.Thread(target=listener)
897 t.start()
898 connector()
899 t.join()
900
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000901 def testProtocolSSL2(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000902 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000903 sys.stdout.write("\n")
904 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True)
905 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL)
906 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED)
907 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True)
908 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False)
909 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False)
910
911 def testProtocolSSL23(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000912 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000913 sys.stdout.write("\n")
914 try:
915 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv2, True)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000916 except support.TestFailed as x:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000917 # this fails on some older versions of OpenSSL (0.9.7l, for instance)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000918 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000919 sys.stdout.write(
920 " SSL2 client to SSL23 server test unexpectedly failed:\n %s\n"
921 % str(x))
922 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True)
923 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True)
924 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True)
925
926 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
927 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_OPTIONAL)
928 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
929
930 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
931 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_REQUIRED)
932 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
933
934 def testProtocolSSL3(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000935 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000936 sys.stdout.write("\n")
937 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True)
938 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
939 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
940 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False)
941 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, False)
942 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False)
943
944 def testProtocolTLS1(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000945 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000946 sys.stdout.write("\n")
947 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True)
948 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
949 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
950 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False)
951 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False)
952 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv23, False)
953
954 def testSTARTTLS (self):
955
Bill Janssen40a0f662008-08-12 16:56:25 +0000956 msgs = ("msg 1", "MSG 2", "STARTTLS", "MSG 3", "msg 4", "ENDTLS", "msg 5", "msg 6")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000957
Trent Nelson78520002008-04-10 20:54:35 +0000958 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000959 ssl_version=ssl.PROTOCOL_TLSv1,
960 starttls_server=True,
961 chatty=True,
962 connectionchatty=True)
963 flag = threading.Event()
964 server.start(flag)
965 # wait for it to start
966 flag.wait()
967 # try to connect
968 wrapped = False
969 try:
970 try:
971 s = socket.socket()
972 s.setblocking(1)
Trent Nelson78520002008-04-10 20:54:35 +0000973 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000974 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000975 raise support.TestFailed("Unexpected exception: " + str(x))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000976 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000977 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000978 sys.stdout.write("\n")
979 for indata in msgs:
Bill Janssen6e027db2007-11-15 22:23:56 +0000980 msg = indata.encode('ASCII', 'replace')
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000981 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000982 sys.stdout.write(
Bill Janssen6e027db2007-11-15 22:23:56 +0000983 " client: sending %s...\n" % repr(msg))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000984 if wrapped:
Bill Janssen6e027db2007-11-15 22:23:56 +0000985 conn.write(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000986 outdata = conn.read()
987 else:
Bill Janssen6e027db2007-11-15 22:23:56 +0000988 s.send(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000989 outdata = s.recv(1024)
990 if (indata == "STARTTLS" and
Bill Janssen6e027db2007-11-15 22:23:56 +0000991 str(outdata, 'ASCII', 'replace').strip().lower().startswith("ok")):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000992 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000993 msg = str(outdata, 'ASCII', 'replace')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000994 sys.stdout.write(
995 " client: read %s from server, starting TLS...\n"
Bill Janssen6e027db2007-11-15 22:23:56 +0000996 % repr(msg))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000997 conn = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000998 wrapped = True
Bill Janssen40a0f662008-08-12 16:56:25 +0000999 elif (indata == "ENDTLS" and
1000 str(outdata, 'ASCII', 'replace').strip().lower().startswith("ok")):
1001 if support.verbose:
1002 msg = str(outdata, 'ASCII', 'replace')
1003 sys.stdout.write(
1004 " client: read %s from server, ending TLS...\n"
1005 % repr(msg))
1006 s = conn.unwrap()
1007 wrapped = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001008 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001009 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +00001010 msg = str(outdata, 'ASCII', 'replace')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001011 sys.stdout.write(
Bill Janssen6e027db2007-11-15 22:23:56 +00001012 " client: read %s from server\n" % repr(msg))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001013 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001014 sys.stdout.write(" client: closing connection.\n")
1015 if wrapped:
Bill Janssen6e027db2007-11-15 22:23:56 +00001016 conn.write("over\n".encode("ASCII", "strict"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001017 else:
Bill Janssen40a0f662008-08-12 16:56:25 +00001018 s.send("over\n".encode("ASCII", "strict"))
Bill Janssen6e027db2007-11-15 22:23:56 +00001019 if wrapped:
1020 conn.close()
1021 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001022 s.close()
1023 finally:
1024 server.stop()
1025 server.join()
1026
Bill Janssen54cc54c2007-12-14 22:08:56 +00001027 def testSocketServer(self):
Bill Janssen6e027db2007-11-15 22:23:56 +00001028
Trent Nelson78520002008-04-10 20:54:35 +00001029 server = OurHTTPSServer(CERTFILE)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001030 flag = threading.Event()
1031 server.start(flag)
1032 # wait for it to start
1033 flag.wait()
1034 # try to connect
1035 try:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001036 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001037 sys.stdout.write('\n')
1038 d1 = open(CERTFILE, 'rb').read()
1039 d2 = ''
1040 # now fetch the same data from the HTTPS server
Trent Nelson78520002008-04-10 20:54:35 +00001041 url = 'https://%s:%d/%s' % (
1042 HOST, server.port, os.path.split(CERTFILE)[1])
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001043 f = urllib.request.urlopen(url)
Barry Warsaw820c1202008-06-12 04:06:45 +00001044 dlen = f.info().get("content-length")
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001045 if dlen and (int(dlen) > 0):
1046 d2 = f.read(int(dlen))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001047 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001048 sys.stdout.write(
1049 " client: read %d bytes from remote server '%s'\n"
1050 % (len(d2), server))
1051 f.close()
1052 except:
1053 msg = ''.join(traceback.format_exception(*sys.exc_info()))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001054 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001055 sys.stdout.write('\n' + msg)
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001056 raise support.TestFailed(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001057 else:
1058 if not (d1 == d2):
Bill Janssen6e027db2007-11-15 22:23:56 +00001059 print("d1 is", len(d1), repr(d1))
1060 print("d2 is", len(d2), repr(d2))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001061 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001062 "Couldn't fetch data from HTTPS server")
1063 finally:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001064 if support.verbose:
Neal Norwitzf9ff5f02008-03-31 05:39:26 +00001065 sys.stdout.write('stopping server\n')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001066 server.stop()
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001067 if support.verbose:
Neal Norwitzf9ff5f02008-03-31 05:39:26 +00001068 sys.stdout.write('joining thread\n')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001069 server.join()
1070
Trent Nelson6b240cd2008-04-10 20:12:06 +00001071 def testAsyncoreServer(self):
1072
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001073 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001074 sys.stdout.write("\n")
1075
1076 indata="FOO\n"
Trent Nelson78520002008-04-10 20:54:35 +00001077 server = AsyncoreEchoServer(CERTFILE)
Trent Nelson6b240cd2008-04-10 20:12:06 +00001078 flag = threading.Event()
1079 server.start(flag)
1080 # wait for it to start
1081 flag.wait()
1082 # try to connect
1083 try:
1084 s = ssl.wrap_socket(socket.socket())
Trent Nelson78520002008-04-10 20:54:35 +00001085 s.connect((HOST, server.port))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001086 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001087 raise support.TestFailed("Unexpected SSL error: " + str(x))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001088 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001089 raise support.TestFailed("Unexpected exception: " + str(x))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001090 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001091 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001092 sys.stdout.write(
1093 " client: sending %s...\n" % (repr(indata)))
1094 s.sendall(indata.encode('ASCII', 'strict'))
1095 outdata = s.recv()
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001096 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001097 sys.stdout.write(" client: read %s\n" % repr(outdata))
1098 outdata = str(outdata, 'ASCII', 'strict')
1099 if outdata != indata.lower():
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001100 raise support.TestFailed(
Trent Nelson6b240cd2008-04-10 20:12:06 +00001101 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
1102 % (repr(outdata[:min(len(outdata),20)]), len(outdata),
1103 repr(indata[:min(len(indata),20)].lower()), len(indata)))
1104 s.write("over\n".encode("ASCII", "strict"))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001105 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001106 sys.stdout.write(" client: closing connection.\n")
1107 s.close()
1108 finally:
1109 server.stop()
1110 server.join()
1111
Bill Janssen58afe4c2008-09-08 16:45:19 +00001112 def testAllRecvAndSendMethods(self):
1113
1114 if support.verbose:
1115 sys.stdout.write("\n")
1116
1117 server = ThreadedEchoServer(CERTFILE,
1118 certreqs=ssl.CERT_NONE,
1119 ssl_version=ssl.PROTOCOL_TLSv1,
1120 cacerts=CERTFILE,
1121 chatty=True,
1122 connectionchatty=False)
1123 flag = threading.Event()
1124 server.start(flag)
1125 # wait for it to start
1126 flag.wait()
1127 # try to connect
1128 try:
1129 s = ssl.wrap_socket(socket.socket(),
1130 server_side=False,
1131 certfile=CERTFILE,
1132 ca_certs=CERTFILE,
1133 cert_reqs=ssl.CERT_NONE,
1134 ssl_version=ssl.PROTOCOL_TLSv1)
1135 s.connect((HOST, server.port))
1136 except ssl.SSLError as x:
Georg Brandl89fad142010-03-14 10:23:39 +00001137 self.fail("Unexpected SSL error: " + str(x))
Bill Janssen58afe4c2008-09-08 16:45:19 +00001138 except Exception as x:
Georg Brandl89fad142010-03-14 10:23:39 +00001139 self.fail("Unexpected exception: " + str(x))
Bill Janssen58afe4c2008-09-08 16:45:19 +00001140 else:
1141 # helper methods for standardising recv* method signatures
1142 def _recv_into():
1143 b = bytearray(b"\0"*100)
1144 count = s.recv_into(b)
1145 return b[:count]
1146
1147 def _recvfrom_into():
1148 b = bytearray(b"\0"*100)
1149 count, addr = s.recvfrom_into(b)
1150 return b[:count]
1151
1152 # (name, method, whether to expect success, *args)
1153 send_methods = [
1154 ('send', s.send, True, []),
1155 ('sendto', s.sendto, False, ["some.address"]),
1156 ('sendall', s.sendall, True, []),
1157 ]
1158 recv_methods = [
1159 ('recv', s.recv, True, []),
1160 ('recvfrom', s.recvfrom, False, ["some.address"]),
1161 ('recv_into', _recv_into, True, []),
1162 ('recvfrom_into', _recvfrom_into, False, []),
1163 ]
1164 data_prefix = "PREFIX_"
1165
1166 for meth_name, send_meth, expect_success, args in send_methods:
1167 indata = data_prefix + meth_name
1168 try:
1169 send_meth(indata.encode('ASCII', 'strict'), *args)
1170 outdata = s.read()
1171 outdata = str(outdata, 'ASCII', 'strict')
1172 if outdata != indata.lower():
Georg Brandl89fad142010-03-14 10:23:39 +00001173 self.fail(
Bill Janssen58afe4c2008-09-08 16:45:19 +00001174 "While sending with <<{name:s}>> bad data "
1175 "<<{outdata:s}>> ({nout:d}) received; "
1176 "expected <<{indata:s}>> ({nin:d})\n".format(
1177 name=meth_name, outdata=repr(outdata[:20]),
1178 nout=len(outdata),
1179 indata=repr(indata[:20]), nin=len(indata)
1180 )
1181 )
1182 except ValueError as e:
1183 if expect_success:
Georg Brandl89fad142010-03-14 10:23:39 +00001184 self.fail(
Bill Janssen58afe4c2008-09-08 16:45:19 +00001185 "Failed to send with method <<{name:s}>>; "
1186 "expected to succeed.\n".format(name=meth_name)
1187 )
1188 if not str(e).startswith(meth_name):
Georg Brandl89fad142010-03-14 10:23:39 +00001189 self.fail(
Bill Janssen58afe4c2008-09-08 16:45:19 +00001190 "Method <<{name:s}>> failed with unexpected "
1191 "exception message: {exp:s}\n".format(
1192 name=meth_name, exp=e
1193 )
1194 )
1195
1196 for meth_name, recv_meth, expect_success, args in recv_methods:
1197 indata = data_prefix + meth_name
1198 try:
1199 s.send(indata.encode('ASCII', 'strict'))
1200 outdata = recv_meth(*args)
1201 outdata = str(outdata, 'ASCII', 'strict')
1202 if outdata != indata.lower():
Georg Brandl89fad142010-03-14 10:23:39 +00001203 self.fail(
Bill Janssen58afe4c2008-09-08 16:45:19 +00001204 "While receiving with <<{name:s}>> bad data "
1205 "<<{outdata:s}>> ({nout:d}) received; "
1206 "expected <<{indata:s}>> ({nin:d})\n".format(
1207 name=meth_name, outdata=repr(outdata[:20]),
1208 nout=len(outdata),
1209 indata=repr(indata[:20]), nin=len(indata)
1210 )
1211 )
1212 except ValueError as e:
1213 if expect_success:
Georg Brandl89fad142010-03-14 10:23:39 +00001214 self.fail(
Bill Janssen58afe4c2008-09-08 16:45:19 +00001215 "Failed to receive with method <<{name:s}>>; "
1216 "expected to succeed.\n".format(name=meth_name)
1217 )
1218 if not str(e).startswith(meth_name):
Georg Brandl89fad142010-03-14 10:23:39 +00001219 self.fail(
Bill Janssen58afe4c2008-09-08 16:45:19 +00001220 "Method <<{name:s}>> failed with unexpected "
1221 "exception message: {exp:s}\n".format(
1222 name=meth_name, exp=e
1223 )
1224 )
1225 # consume data
1226 s.read()
1227
1228 s.write("over\n".encode("ASCII", "strict"))
1229 s.close()
1230 finally:
1231 server.stop()
1232 server.join()
1233
1234
Thomas Woutersed03b412007-08-28 21:37:11 +00001235def test_main(verbose=False):
1236 if skip_expected:
Benjamin Petersone549ead2009-03-28 21:42:05 +00001237 raise unittest.SkipTest("No SSL support")
Thomas Woutersed03b412007-08-28 21:37:11 +00001238
Trent Nelson78520002008-04-10 20:54:35 +00001239 global CERTFILE, SVN_PYTHON_ORG_ROOT_CERT
Thomas Woutersed03b412007-08-28 21:37:11 +00001240 CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir,
1241 "keycert.pem")
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001242 SVN_PYTHON_ORG_ROOT_CERT = os.path.join(
1243 os.path.dirname(__file__) or os.curdir,
1244 "https_svn_python_org_root.pem")
1245
1246 if (not os.path.exists(CERTFILE) or
1247 not os.path.exists(SVN_PYTHON_ORG_ROOT_CERT)):
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001248 raise support.TestFailed("Can't read certificate files!")
Bill Janssen6e027db2007-11-15 22:23:56 +00001249
Thomas Woutersed03b412007-08-28 21:37:11 +00001250 tests = [BasicTests]
1251
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001252 if support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00001253 tests.append(NetworkedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001254
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001255 if _have_threads:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001256 thread_info = support.threading_setup()
1257 if thread_info and support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00001258 tests.append(ThreadedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001259
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001260 support.run_unittest(*tests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001261
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001262 if _have_threads:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001263 support.threading_cleanup(*thread_info)
Thomas Woutersed03b412007-08-28 21:37:11 +00001264
1265if __name__ == "__main__":
1266 test_main()