blob: 1804fcd655a87f8cd8e4bfe5ae474c077de18624 [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
124
Bill Janssen6e027db2007-11-15 22:23:56 +0000125class NetworkedTests(unittest.TestCase):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000126
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000127 def testConnect(self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000128 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
129 cert_reqs=ssl.CERT_NONE)
130 s.connect(("svn.python.org", 443))
131 c = s.getpeercert()
132 if c:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000133 raise support.TestFailed("Peer cert %s shouldn't be here!")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000134 s.close()
135
136 # this should fail because we have no verification certs
137 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
138 cert_reqs=ssl.CERT_REQUIRED)
Thomas Woutersed03b412007-08-28 21:37:11 +0000139 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000140 s.connect(("svn.python.org", 443))
141 except ssl.SSLError:
142 pass
143 finally:
144 s.close()
145
146 # this should succeed because we specify the root cert
147 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
148 cert_reqs=ssl.CERT_REQUIRED,
149 ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
150 try:
151 s.connect(("svn.python.org", 443))
152 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000153 raise support.TestFailed("Unexpected exception %s" % x)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000154 finally:
155 s.close()
156
Bill Janssen6e027db2007-11-15 22:23:56 +0000157 def testNonBlockingHandshake(self):
158 s = socket.socket(socket.AF_INET)
159 s.connect(("svn.python.org", 443))
160 s.setblocking(False)
161 s = ssl.wrap_socket(s,
162 cert_reqs=ssl.CERT_NONE,
163 do_handshake_on_connect=False)
164 count = 0
165 while True:
166 try:
167 count += 1
168 s.do_handshake()
169 break
170 except ssl.SSLError as err:
171 if err.args[0] == ssl.SSL_ERROR_WANT_READ:
172 select.select([s], [], [])
173 elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE:
174 select.select([], [s], [])
175 else:
176 raise
177 s.close()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000178 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000179 sys.stdout.write("\nNeeded %d calls to do_handshake() to establish session.\n" % count)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000180
Bill Janssen54cc54c2007-12-14 22:08:56 +0000181 def testFetchServerCert(self):
182
183 pem = ssl.get_server_certificate(("svn.python.org", 443))
184 if not pem:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000185 raise support.TestFailed("No server certificate on svn.python.org:443!")
Bill Janssen54cc54c2007-12-14 22:08:56 +0000186
187 return
188
189 try:
190 pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=CERTFILE)
191 except ssl.SSLError as x:
192 #should fail
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000193 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000194 sys.stdout.write("%s\n" % x)
195 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000196 raise support.TestFailed("Got server certificate %s for svn.python.org!" % pem)
Bill Janssen54cc54c2007-12-14 22:08:56 +0000197
198 pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
199 if not pem:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000200 raise support.TestFailed("No server certificate on svn.python.org:443!")
201 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000202 sys.stdout.write("\nVerified certificate for svn.python.org:443 is\n%s\n" % pem)
203
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000204
205try:
206 import threading
207except ImportError:
208 _have_threads = False
209else:
210
211 _have_threads = True
212
213 class ThreadedEchoServer(threading.Thread):
214
215 class ConnectionHandler(threading.Thread):
216
217 """A mildly complicated class, because we want it to work both
218 with and without the SSL wrapper around the socket connection, so
219 that we can test the STARTTLS functionality."""
220
Bill Janssen6e027db2007-11-15 22:23:56 +0000221 def __init__(self, server, connsock, addr):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000222 self.server = server
223 self.running = False
224 self.sock = connsock
Bill Janssen6e027db2007-11-15 22:23:56 +0000225 self.addr = addr
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000226 self.sock.setblocking(1)
227 self.sslconn = None
228 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000229 self.daemon = True
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000230
231 def wrap_conn (self):
232 try:
233 self.sslconn = ssl.wrap_socket(self.sock, server_side=True,
234 certfile=self.server.certificate,
235 ssl_version=self.server.protocol,
236 ca_certs=self.server.cacerts,
237 cert_reqs=self.server.certreqs)
238 except:
239 if self.server.chatty:
Bill Janssen6e027db2007-11-15 22:23:56 +0000240 handle_error("\n server: bad connection attempt from " + repr(self.addr) + ":\n")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000241 if not self.server.expect_bad_connects:
242 # here, we want to stop the server, because this shouldn't
243 # happen in the context of our test case
244 self.running = False
245 # normally, we'd just stop here, but for the test
246 # harness, we want to stop the server
247 self.server.stop()
Bill Janssen6e027db2007-11-15 22:23:56 +0000248 self.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000249 return False
250
251 else:
252 if self.server.certreqs == ssl.CERT_REQUIRED:
253 cert = self.sslconn.getpeercert()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000254 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000255 sys.stdout.write(" client cert is " + pprint.pformat(cert) + "\n")
256 cert_binary = self.sslconn.getpeercert(True)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000257 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000258 sys.stdout.write(" cert binary is " + str(len(cert_binary)) + " bytes\n")
259 cipher = self.sslconn.cipher()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000260 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000261 sys.stdout.write(" server: connection cipher is now " + str(cipher) + "\n")
262 return True
263
264 def read(self):
265 if self.sslconn:
266 return self.sslconn.read()
267 else:
268 return self.sock.recv(1024)
269
270 def write(self, bytes):
271 if self.sslconn:
272 return self.sslconn.write(bytes)
273 else:
274 return self.sock.send(bytes)
275
276 def close(self):
277 if self.sslconn:
278 self.sslconn.close()
279 else:
280 self.sock.close()
281
282 def run (self):
283 self.running = True
284 if not self.server.starttls_server:
285 if not self.wrap_conn():
286 return
287 while self.running:
288 try:
289 msg = self.read()
Bill Janssen6e027db2007-11-15 22:23:56 +0000290 amsg = (msg and str(msg, 'ASCII', 'strict')) or ''
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000291 if not msg:
292 # eof, so quit this handler
293 self.running = False
294 self.close()
Bill Janssen6e027db2007-11-15 22:23:56 +0000295 elif amsg.strip() == 'over':
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000296 if support.verbose and self.server.connectionchatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000297 sys.stdout.write(" server: client closed connection\n")
298 self.close()
299 return
Bill Janssen6e027db2007-11-15 22:23:56 +0000300 elif (self.server.starttls_server and
301 amsg.strip() == 'STARTTLS'):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000302 if support.verbose and self.server.connectionchatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000303 sys.stdout.write(" server: read STARTTLS from client, sending OK...\n")
Bill Janssen6e027db2007-11-15 22:23:56 +0000304 self.write("OK\n".encode("ASCII", "strict"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000305 if not self.wrap_conn():
306 return
Bill Janssen40a0f662008-08-12 16:56:25 +0000307 elif (self.server.starttls_server and self.sslconn
308 and amsg.strip() == 'ENDTLS'):
309 if support.verbose and self.server.connectionchatty:
310 sys.stdout.write(" server: read ENDTLS from client, sending OK...\n")
311 self.write("OK\n".encode("ASCII", "strict"))
312 self.sock = self.sslconn.unwrap()
313 self.sslconn = None
314 if support.verbose and self.server.connectionchatty:
315 sys.stdout.write(" server: connection is now unencrypted...\n")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000316 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000317 if (support.verbose and
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000318 self.server.connectionchatty):
319 ctype = (self.sslconn and "encrypted") or "unencrypted"
320 sys.stdout.write(" server: read %s (%s), sending back %s (%s)...\n"
321 % (repr(msg), ctype, repr(msg.lower()), ctype))
Bill Janssen6e027db2007-11-15 22:23:56 +0000322 self.write(amsg.lower().encode('ASCII', 'strict'))
323 except socket.error:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000324 if self.server.chatty:
325 handle_error("Test server failure:\n")
326 self.close()
327 self.running = False
328 # normally, we'd just stop here, but for the test
329 # harness, we want to stop the server
330 self.server.stop()
331 except:
332 handle_error('')
333
Trent Nelson78520002008-04-10 20:54:35 +0000334 def __init__(self, certificate, ssl_version=None,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000335 certreqs=None, cacerts=None, expect_bad_connects=False,
336 chatty=True, connectionchatty=False, starttls_server=False):
337 if ssl_version is None:
338 ssl_version = ssl.PROTOCOL_TLSv1
339 if certreqs is None:
340 certreqs = ssl.CERT_NONE
341 self.certificate = certificate
342 self.protocol = ssl_version
343 self.certreqs = certreqs
344 self.cacerts = cacerts
345 self.expect_bad_connects = expect_bad_connects
346 self.chatty = chatty
347 self.connectionchatty = connectionchatty
348 self.starttls_server = starttls_server
349 self.sock = socket.socket()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000350 self.port = support.bind_port(self.sock)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000351 self.flag = None
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000352 self.active = False
353 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000354 self.daemon = True
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000355
356 def start (self, flag=None):
357 self.flag = flag
358 threading.Thread.start(self)
359
360 def run (self):
361 self.sock.settimeout(0.5)
362 self.sock.listen(5)
363 self.active = True
364 if self.flag:
365 # signal an event
366 self.flag.set()
367 while self.active:
368 try:
369 newconn, connaddr = self.sock.accept()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000370 if support.verbose and self.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000371 sys.stdout.write(' server: new connection from '
Bill Janssen6e027db2007-11-15 22:23:56 +0000372 + repr(connaddr) + '\n')
373 handler = self.ConnectionHandler(self, newconn, connaddr)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000374 handler.start()
375 except socket.timeout:
376 pass
377 except KeyboardInterrupt:
378 self.stop()
379 except:
380 if self.chatty:
381 handle_error("Test server failure:\n")
Bill Janssen6e027db2007-11-15 22:23:56 +0000382 self.sock.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000383
384 def stop (self):
385 self.active = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000386
Bill Janssen54cc54c2007-12-14 22:08:56 +0000387 class OurHTTPSServer(threading.Thread):
388
389 # This one's based on HTTPServer, which is based on SocketServer
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000390
391 class HTTPSServer(HTTPServer):
392
393 def __init__(self, server_address, RequestHandlerClass, certfile):
394
395 HTTPServer.__init__(self, server_address, RequestHandlerClass)
396 # we assume the certfile contains both private key and certificate
397 self.certfile = certfile
398 self.active = False
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000399 self.active_lock = threading.Lock()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000400 self.allow_reuse_address = True
401
Bill Janssen6e027db2007-11-15 22:23:56 +0000402 def __str__(self):
403 return ('<%s %s:%s>' %
404 (self.__class__.__name__,
405 self.server_name,
406 self.server_port))
407
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000408 def get_request (self):
409 # override this to wrap socket with SSL
410 sock, addr = self.socket.accept()
411 sslconn = ssl.wrap_socket(sock, server_side=True,
412 certfile=self.certfile)
413 return sslconn, addr
414
415 # The methods overridden below this are mainly so that we
416 # can run it in a thread and be able to stop it from another
417 # You probably wouldn't need them in other uses.
418
419 def server_activate(self):
420 # We want to run this in a thread for testing purposes,
421 # so we override this to set timeout, so that we get
422 # a chance to stop the server
423 self.socket.settimeout(0.5)
424 HTTPServer.server_activate(self)
425
426 def serve_forever(self):
427 # We want this to run in a thread, so we use a slightly
428 # modified version of "forever".
429 self.active = True
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000430 while 1:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000431 try:
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000432 # We need to lock while handling the request.
433 # Another thread can close the socket after self.active
434 # has been checked and before the request is handled.
435 # This causes an exception when using the closed socket.
436 with self.active_lock:
437 if not self.active:
438 break
439 self.handle_request()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000440 except socket.timeout:
441 pass
442 except KeyboardInterrupt:
443 self.server_close()
444 return
445 except:
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000446 sys.stdout.write(''.join(traceback.format_exception(*sys.exc_info())))
447 break
Neal Norwitzf9ff5f02008-03-31 05:39:26 +0000448 time.sleep(0.1)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000449
450 def server_close(self):
451 # Again, we want this to run in a thread, so we need to override
452 # close to clear the "active" flag, so that serve_forever() will
453 # terminate.
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000454 with self.active_lock:
455 HTTPServer.server_close(self)
456 self.active = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000457
458 class RootedHTTPRequestHandler(SimpleHTTPRequestHandler):
459
460 # need to override translate_path to get a known root,
461 # instead of using os.curdir, since the test could be
462 # run from anywhere
463
464 server_version = "TestHTTPS/1.0"
465
466 root = None
467
468 def translate_path(self, path):
469 """Translate a /-separated PATH to the local filename syntax.
470
471 Components that mean special things to the local file system
472 (e.g. drive or directory names) are ignored. (XXX They should
473 probably be diagnosed.)
474
475 """
476 # abandon query parameters
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000477 path = urllib.parse.urlparse(path)[2]
478 path = os.path.normpath(urllib.parse.unquote(path))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000479 words = path.split('/')
480 words = filter(None, words)
481 path = self.root
482 for word in words:
483 drive, word = os.path.splitdrive(word)
484 head, word = os.path.split(word)
485 if word in self.root: continue
486 path = os.path.join(path, word)
487 return path
488
489 def log_message(self, format, *args):
490
491 # we override this to suppress logging unless "verbose"
492
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000493 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000494 sys.stdout.write(" server (%s:%d %s):\n [%s] %s\n" %
495 (self.server.server_address,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000496 self.server.server_port,
497 self.request.cipher(),
498 self.log_date_time_string(),
499 format%args))
Thomas Woutersed03b412007-08-28 21:37:11 +0000500
501
Trent Nelson78520002008-04-10 20:54:35 +0000502 def __init__(self, certfile):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000503 self.flag = None
504 self.active = False
505 self.RootedHTTPRequestHandler.root = os.path.split(CERTFILE)[0]
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000506 self.port = support.find_unused_port()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000507 self.server = self.HTTPSServer(
Trent Nelson78520002008-04-10 20:54:35 +0000508 (HOST, self.port), self.RootedHTTPRequestHandler, certfile)
Thomas Woutersed03b412007-08-28 21:37:11 +0000509 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000510 self.daemon = True
Thomas Woutersed03b412007-08-28 21:37:11 +0000511
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000512 def __str__(self):
Bill Janssen6e027db2007-11-15 22:23:56 +0000513 return "<%s %s>" % (self.__class__.__name__, self.server)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000514
515 def start (self, flag=None):
516 self.flag = flag
517 threading.Thread.start(self)
518
Thomas Woutersed03b412007-08-28 21:37:11 +0000519 def run (self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000520 self.active = True
521 if self.flag:
522 self.flag.set()
523 self.server.serve_forever()
524 self.active = False
525
526 def stop (self):
527 self.active = False
528 self.server.server_close()
529
530
Bill Janssen54cc54c2007-12-14 22:08:56 +0000531 class AsyncoreEchoServer(threading.Thread):
532
533 # this one's based on asyncore.dispatcher
534
535 class EchoServer (asyncore.dispatcher):
536
537 class ConnectionHandler (asyncore.dispatcher_with_send):
538
539 def __init__(self, conn, certfile):
540 self.socket = ssl.wrap_socket(conn, server_side=True,
541 certfile=certfile,
542 do_handshake_on_connect=False)
543 asyncore.dispatcher_with_send.__init__(self, self.socket)
544 # now we have to do the handshake
545 # we'll just do it the easy way, and block the connection
546 # till it's finished. If we were doing it right, we'd
547 # do this in multiple calls to handle_read...
548 self.do_handshake(block=True)
549
550 def readable(self):
551 if isinstance(self.socket, ssl.SSLSocket):
552 while self.socket.pending() > 0:
553 self.handle_read_event()
554 return True
555
556 def handle_read(self):
557 data = self.recv(1024)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000558 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000559 sys.stdout.write(" server: read %s from client\n" % repr(data))
560 if not data:
561 self.close()
562 else:
563 self.send(str(data, 'ASCII', 'strict').lower().encode('ASCII', 'strict'))
564
565 def handle_close(self):
Bill Janssen2f5799b2008-06-29 00:08:12 +0000566 self.close()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000567 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000568 sys.stdout.write(" server: closed connection %s\n" % self.socket)
569
570 def handle_error(self):
571 raise
572
573 def __init__(self, port, certfile):
574 self.port = port
575 self.certfile = certfile
576 asyncore.dispatcher.__init__(self)
577 self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
578 self.bind(('', port))
579 self.listen(5)
580
581 def handle_accept(self):
582 sock_obj, addr = self.accept()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000583 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000584 sys.stdout.write(" server: new connection from %s:%s\n" %addr)
585 self.ConnectionHandler(sock_obj, self.certfile)
586
587 def handle_error(self):
588 raise
589
Trent Nelson78520002008-04-10 20:54:35 +0000590 def __init__(self, certfile):
Bill Janssen54cc54c2007-12-14 22:08:56 +0000591 self.flag = None
592 self.active = False
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000593 self.port = support.find_unused_port()
Trent Nelson78520002008-04-10 20:54:35 +0000594 self.server = self.EchoServer(self.port, certfile)
Bill Janssen54cc54c2007-12-14 22:08:56 +0000595 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000596 self.daemon = True
Bill Janssen54cc54c2007-12-14 22:08:56 +0000597
598 def __str__(self):
599 return "<%s %s>" % (self.__class__.__name__, self.server)
600
601 def start (self, flag=None):
602 self.flag = flag
603 threading.Thread.start(self)
604
605 def run (self):
606 self.active = True
607 if self.flag:
608 self.flag.set()
609 while self.active:
610 try:
611 asyncore.loop(1)
612 except:
613 pass
614
615 def stop (self):
616 self.active = False
617 self.server.close()
618
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000619 def badCertTest (certfile):
Trent Nelson78520002008-04-10 20:54:35 +0000620 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000621 certreqs=ssl.CERT_REQUIRED,
Bill Janssen6e027db2007-11-15 22:23:56 +0000622 cacerts=CERTFILE, chatty=False,
623 connectionchatty=False)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000624 flag = threading.Event()
625 server.start(flag)
626 # wait for it to start
627 flag.wait()
628 # try to connect
629 try:
Thomas Woutersed03b412007-08-28 21:37:11 +0000630 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000631 s = ssl.wrap_socket(socket.socket(),
632 certfile=certfile,
633 ssl_version=ssl.PROTOCOL_TLSv1)
Trent Nelson78520002008-04-10 20:54:35 +0000634 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000635 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000636 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000637 sys.stdout.write("\nSSLError is %s\n" % x)
Bill Janssenddc56692008-07-17 18:17:20 +0000638 except socket.error as x:
639 if support.verbose:
640 sys.stdout.write("\nsocket.error is %s\n" % x)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000641 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000642 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000643 "Use of invalid cert should have failed!")
644 finally:
645 server.stop()
646 server.join()
Thomas Woutersed03b412007-08-28 21:37:11 +0000647
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000648 def serverParamsTest (certfile, protocol, certreqs, cacertsfile,
Bill Janssen6e027db2007-11-15 22:23:56 +0000649 client_certfile, client_protocol=None,
650 indata="FOO\n",
651 chatty=False, connectionchatty=False):
Thomas Woutersed03b412007-08-28 21:37:11 +0000652
Trent Nelson78520002008-04-10 20:54:35 +0000653 server = ThreadedEchoServer(certfile,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000654 certreqs=certreqs,
655 ssl_version=protocol,
656 cacerts=cacertsfile,
657 chatty=chatty,
Bill Janssen6e027db2007-11-15 22:23:56 +0000658 connectionchatty=False)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000659 flag = threading.Event()
660 server.start(flag)
661 # wait for it to start
662 flag.wait()
663 # try to connect
664 if client_protocol is None:
665 client_protocol = protocol
666 try:
Bill Janssen6e027db2007-11-15 22:23:56 +0000667 s = ssl.wrap_socket(socket.socket(),
Trent Nelson6b240cd2008-04-10 20:12:06 +0000668 server_side=False,
Bill Janssen6e027db2007-11-15 22:23:56 +0000669 certfile=client_certfile,
670 ca_certs=cacertsfile,
671 cert_reqs=certreqs,
672 ssl_version=client_protocol)
Trent Nelson78520002008-04-10 20:54:35 +0000673 s.connect((HOST, server.port))
Bill Janssen6e027db2007-11-15 22:23:56 +0000674 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000675 raise support.TestFailed("Unexpected SSL error: " + str(x))
Bill Janssen6e027db2007-11-15 22:23:56 +0000676 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000677 raise support.TestFailed("Unexpected exception: " + str(x))
Bill Janssen6e027db2007-11-15 22:23:56 +0000678 else:
Antoine Pitrou7d7aede2009-11-25 18:55:32 +0000679 bindata = indata.encode('ASCII', 'strict')
680 for arg in [bindata, bytearray(bindata), memoryview(bindata)]:
681 if connectionchatty:
682 if support.verbose:
683 sys.stdout.write(
684 " client: sending %s...\n" % (repr(indata)))
685 s.write(arg)
686 outdata = s.read()
687 if connectionchatty:
688 if support.verbose:
689 sys.stdout.write(" client: read %s\n" % repr(outdata))
690 outdata = str(outdata, 'ASCII', 'strict')
691 if outdata != indata.lower():
692 raise support.TestFailed(
693 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
694 % (repr(outdata[:min(len(outdata),20)]), len(outdata),
695 repr(indata[:min(len(indata),20)].lower()), len(indata)))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000696 s.write("over\n".encode("ASCII", "strict"))
Bill Janssen6e027db2007-11-15 22:23:56 +0000697 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000698 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000699 sys.stdout.write(" client: closing connection.\n")
700 s.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000701 finally:
702 server.stop()
703 server.join()
Thomas Woutersed03b412007-08-28 21:37:11 +0000704
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000705 def tryProtocolCombo (server_protocol,
706 client_protocol,
707 expectedToWork,
708 certsreqs=None):
Thomas Woutersed03b412007-08-28 21:37:11 +0000709
Benjamin Peterson2a691a82008-03-31 01:51:45 +0000710 if certsreqs is None:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000711 certsreqs = ssl.CERT_NONE
Thomas Woutersed03b412007-08-28 21:37:11 +0000712
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000713 if certsreqs == ssl.CERT_NONE:
714 certtype = "CERT_NONE"
715 elif certsreqs == ssl.CERT_OPTIONAL:
716 certtype = "CERT_OPTIONAL"
717 elif certsreqs == ssl.CERT_REQUIRED:
718 certtype = "CERT_REQUIRED"
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000719 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000720 formatstr = (expectedToWork and " %s->%s %s\n") or " {%s->%s} %s\n"
721 sys.stdout.write(formatstr %
722 (ssl.get_protocol_name(client_protocol),
723 ssl.get_protocol_name(server_protocol),
724 certtype))
725 try:
726 serverParamsTest(CERTFILE, server_protocol, certsreqs,
Bill Janssen6e027db2007-11-15 22:23:56 +0000727 CERTFILE, CERTFILE, client_protocol,
728 chatty=False, connectionchatty=False)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000729 except support.TestFailed:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000730 if expectedToWork:
731 raise
732 else:
733 if not expectedToWork:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000734 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000735 "Client protocol %s succeeded with server protocol %s!"
736 % (ssl.get_protocol_name(client_protocol),
737 ssl.get_protocol_name(server_protocol)))
738
739
Bill Janssen6e027db2007-11-15 22:23:56 +0000740 class ThreadedTests(unittest.TestCase):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000741
Trent Nelson6b240cd2008-04-10 20:12:06 +0000742 def testEcho (self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000743
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000744 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000745 sys.stdout.write("\n")
746 serverParamsTest(CERTFILE, ssl.PROTOCOL_TLSv1, ssl.CERT_NONE,
747 CERTFILE, CERTFILE, ssl.PROTOCOL_TLSv1,
748 chatty=True, connectionchatty=True)
749
750 def testReadCert(self):
751
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000752 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000753 sys.stdout.write("\n")
754 s2 = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000755 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000756 certreqs=ssl.CERT_NONE,
757 ssl_version=ssl.PROTOCOL_SSLv23,
758 cacerts=CERTFILE,
759 chatty=False)
760 flag = threading.Event()
761 server.start(flag)
762 # wait for it to start
763 flag.wait()
764 # try to connect
765 try:
766 try:
767 s = ssl.wrap_socket(socket.socket(),
768 certfile=CERTFILE,
769 ca_certs=CERTFILE,
770 cert_reqs=ssl.CERT_REQUIRED,
771 ssl_version=ssl.PROTOCOL_SSLv23)
Trent Nelson78520002008-04-10 20:54:35 +0000772 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000773 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000774 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000775 "Unexpected SSL error: " + str(x))
776 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000777 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000778 "Unexpected exception: " + str(x))
779 else:
780 if not s:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000781 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000782 "Can't SSL-handshake with test server")
783 cert = s.getpeercert()
784 if not cert:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000785 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000786 "Can't get peer certificate.")
787 cipher = s.cipher()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000788 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000789 sys.stdout.write(pprint.pformat(cert) + '\n')
790 sys.stdout.write("Connection cipher is " + str(cipher) + '.\n')
Bill Janssen6e027db2007-11-15 22:23:56 +0000791 if 'subject' not in cert:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000792 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000793 "No subject field in certificate: %s." %
794 pprint.pformat(cert))
795 if ((('organizationName', 'Python Software Foundation'),)
796 not in cert['subject']):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000797 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000798 "Missing or invalid 'organizationName' field in certificate subject; "
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000799 "should be 'Python Software Foundation'.")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000800 s.close()
801 finally:
802 server.stop()
803 server.join()
804
805 def testNULLcert(self):
806 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
807 "nullcert.pem"))
808 def testMalformedCert(self):
809 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
810 "badcert.pem"))
Bill Janssen58afe4c2008-09-08 16:45:19 +0000811 def testWrongCert(self):
812 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
813 "wrongcert.pem"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000814 def testMalformedKey(self):
815 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
816 "badkey.pem"))
817
Trent Nelson6b240cd2008-04-10 20:12:06 +0000818 def testRudeShutdown(self):
819
820 listener_ready = threading.Event()
821 listener_gone = threading.Event()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000822 port = support.find_unused_port()
Trent Nelson6b240cd2008-04-10 20:12:06 +0000823
824 # `listener` runs in a thread. It opens a socket listening on
825 # PORT, and sits in an accept() until the main thread connects.
826 # Then it rudely closes the socket, and sets Event `listener_gone`
827 # to let the main thread know the socket is gone.
828 def listener():
829 s = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000830 s.bind((HOST, port))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000831 s.listen(5)
832 listener_ready.set()
833 s.accept()
834 s = None # reclaim the socket object, which also closes it
835 listener_gone.set()
836
837 def connector():
838 listener_ready.wait()
839 s = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000840 s.connect((HOST, port))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000841 listener_gone.wait()
842 try:
843 ssl_sock = ssl.wrap_socket(s)
844 except IOError:
845 pass
846 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000847 raise support.TestFailed(
Trent Nelson6b240cd2008-04-10 20:12:06 +0000848 'connecting to closed SSL socket should have failed')
849
850 t = threading.Thread(target=listener)
851 t.start()
852 connector()
853 t.join()
854
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000855 def testProtocolSSL2(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000856 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000857 sys.stdout.write("\n")
858 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True)
859 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL)
860 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED)
861 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True)
862 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False)
863 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False)
864
865 def testProtocolSSL23(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000866 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000867 sys.stdout.write("\n")
868 try:
869 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv2, True)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000870 except support.TestFailed as x:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000871 # this fails on some older versions of OpenSSL (0.9.7l, for instance)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000872 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000873 sys.stdout.write(
874 " SSL2 client to SSL23 server test unexpectedly failed:\n %s\n"
875 % str(x))
876 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True)
877 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True)
878 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True)
879
880 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
881 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_OPTIONAL)
882 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
883
884 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
885 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_REQUIRED)
886 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
887
888 def testProtocolSSL3(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000889 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000890 sys.stdout.write("\n")
891 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True)
892 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
893 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
894 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False)
895 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, False)
896 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False)
897
898 def testProtocolTLS1(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000899 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000900 sys.stdout.write("\n")
901 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True)
902 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
903 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
904 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False)
905 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False)
906 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv23, False)
907
908 def testSTARTTLS (self):
909
Bill Janssen40a0f662008-08-12 16:56:25 +0000910 msgs = ("msg 1", "MSG 2", "STARTTLS", "MSG 3", "msg 4", "ENDTLS", "msg 5", "msg 6")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000911
Trent Nelson78520002008-04-10 20:54:35 +0000912 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000913 ssl_version=ssl.PROTOCOL_TLSv1,
914 starttls_server=True,
915 chatty=True,
916 connectionchatty=True)
917 flag = threading.Event()
918 server.start(flag)
919 # wait for it to start
920 flag.wait()
921 # try to connect
922 wrapped = False
923 try:
924 try:
925 s = socket.socket()
926 s.setblocking(1)
Trent Nelson78520002008-04-10 20:54:35 +0000927 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000928 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000929 raise support.TestFailed("Unexpected exception: " + str(x))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000930 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000931 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000932 sys.stdout.write("\n")
933 for indata in msgs:
Bill Janssen6e027db2007-11-15 22:23:56 +0000934 msg = indata.encode('ASCII', 'replace')
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000935 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000936 sys.stdout.write(
Bill Janssen6e027db2007-11-15 22:23:56 +0000937 " client: sending %s...\n" % repr(msg))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000938 if wrapped:
Bill Janssen6e027db2007-11-15 22:23:56 +0000939 conn.write(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000940 outdata = conn.read()
941 else:
Bill Janssen6e027db2007-11-15 22:23:56 +0000942 s.send(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000943 outdata = s.recv(1024)
944 if (indata == "STARTTLS" and
Bill Janssen6e027db2007-11-15 22:23:56 +0000945 str(outdata, 'ASCII', 'replace').strip().lower().startswith("ok")):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000946 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000947 msg = str(outdata, 'ASCII', 'replace')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000948 sys.stdout.write(
949 " client: read %s from server, starting TLS...\n"
Bill Janssen6e027db2007-11-15 22:23:56 +0000950 % repr(msg))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000951 conn = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000952 wrapped = True
Bill Janssen40a0f662008-08-12 16:56:25 +0000953 elif (indata == "ENDTLS" and
954 str(outdata, 'ASCII', 'replace').strip().lower().startswith("ok")):
955 if support.verbose:
956 msg = str(outdata, 'ASCII', 'replace')
957 sys.stdout.write(
958 " client: read %s from server, ending TLS...\n"
959 % repr(msg))
960 s = conn.unwrap()
961 wrapped = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000962 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000963 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000964 msg = str(outdata, 'ASCII', 'replace')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000965 sys.stdout.write(
Bill Janssen6e027db2007-11-15 22:23:56 +0000966 " client: read %s from server\n" % repr(msg))
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000967 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000968 sys.stdout.write(" client: closing connection.\n")
969 if wrapped:
Bill Janssen6e027db2007-11-15 22:23:56 +0000970 conn.write("over\n".encode("ASCII", "strict"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000971 else:
Bill Janssen40a0f662008-08-12 16:56:25 +0000972 s.send("over\n".encode("ASCII", "strict"))
Bill Janssen6e027db2007-11-15 22:23:56 +0000973 if wrapped:
974 conn.close()
975 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000976 s.close()
977 finally:
978 server.stop()
979 server.join()
980
Bill Janssen54cc54c2007-12-14 22:08:56 +0000981 def testSocketServer(self):
Bill Janssen6e027db2007-11-15 22:23:56 +0000982
Trent Nelson78520002008-04-10 20:54:35 +0000983 server = OurHTTPSServer(CERTFILE)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000984 flag = threading.Event()
985 server.start(flag)
986 # wait for it to start
987 flag.wait()
988 # try to connect
989 try:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000990 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000991 sys.stdout.write('\n')
992 d1 = open(CERTFILE, 'rb').read()
993 d2 = ''
994 # now fetch the same data from the HTTPS server
Trent Nelson78520002008-04-10 20:54:35 +0000995 url = 'https://%s:%d/%s' % (
996 HOST, server.port, os.path.split(CERTFILE)[1])
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000997 f = urllib.request.urlopen(url)
Barry Warsaw820c1202008-06-12 04:06:45 +0000998 dlen = f.info().get("content-length")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000999 if dlen and (int(dlen) > 0):
1000 d2 = f.read(int(dlen))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001001 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001002 sys.stdout.write(
1003 " client: read %d bytes from remote server '%s'\n"
1004 % (len(d2), server))
1005 f.close()
1006 except:
1007 msg = ''.join(traceback.format_exception(*sys.exc_info()))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001008 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001009 sys.stdout.write('\n' + msg)
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001010 raise support.TestFailed(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001011 else:
1012 if not (d1 == d2):
Bill Janssen6e027db2007-11-15 22:23:56 +00001013 print("d1 is", len(d1), repr(d1))
1014 print("d2 is", len(d2), repr(d2))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001015 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001016 "Couldn't fetch data from HTTPS server")
1017 finally:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001018 if support.verbose:
Neal Norwitzf9ff5f02008-03-31 05:39:26 +00001019 sys.stdout.write('stopping server\n')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001020 server.stop()
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001021 if support.verbose:
Neal Norwitzf9ff5f02008-03-31 05:39:26 +00001022 sys.stdout.write('joining thread\n')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001023 server.join()
1024
Trent Nelson6b240cd2008-04-10 20:12:06 +00001025 def testAsyncoreServer(self):
1026
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001027 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001028 sys.stdout.write("\n")
1029
1030 indata="FOO\n"
Trent Nelson78520002008-04-10 20:54:35 +00001031 server = AsyncoreEchoServer(CERTFILE)
Trent Nelson6b240cd2008-04-10 20:12:06 +00001032 flag = threading.Event()
1033 server.start(flag)
1034 # wait for it to start
1035 flag.wait()
1036 # try to connect
1037 try:
1038 s = ssl.wrap_socket(socket.socket())
Trent Nelson78520002008-04-10 20:54:35 +00001039 s.connect((HOST, server.port))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001040 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001041 raise support.TestFailed("Unexpected SSL error: " + str(x))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001042 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001043 raise support.TestFailed("Unexpected exception: " + str(x))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001044 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001045 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001046 sys.stdout.write(
1047 " client: sending %s...\n" % (repr(indata)))
1048 s.sendall(indata.encode('ASCII', 'strict'))
1049 outdata = s.recv()
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001050 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001051 sys.stdout.write(" client: read %s\n" % repr(outdata))
1052 outdata = str(outdata, 'ASCII', 'strict')
1053 if outdata != indata.lower():
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001054 raise support.TestFailed(
Trent Nelson6b240cd2008-04-10 20:12:06 +00001055 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
1056 % (repr(outdata[:min(len(outdata),20)]), len(outdata),
1057 repr(indata[:min(len(indata),20)].lower()), len(indata)))
1058 s.write("over\n".encode("ASCII", "strict"))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001059 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001060 sys.stdout.write(" client: closing connection.\n")
1061 s.close()
1062 finally:
1063 server.stop()
1064 server.join()
1065
Bill Janssen58afe4c2008-09-08 16:45:19 +00001066 def testAllRecvAndSendMethods(self):
1067
1068 if support.verbose:
1069 sys.stdout.write("\n")
1070
1071 server = ThreadedEchoServer(CERTFILE,
1072 certreqs=ssl.CERT_NONE,
1073 ssl_version=ssl.PROTOCOL_TLSv1,
1074 cacerts=CERTFILE,
1075 chatty=True,
1076 connectionchatty=False)
1077 flag = threading.Event()
1078 server.start(flag)
1079 # wait for it to start
1080 flag.wait()
1081 # try to connect
1082 try:
1083 s = ssl.wrap_socket(socket.socket(),
1084 server_side=False,
1085 certfile=CERTFILE,
1086 ca_certs=CERTFILE,
1087 cert_reqs=ssl.CERT_NONE,
1088 ssl_version=ssl.PROTOCOL_TLSv1)
1089 s.connect((HOST, server.port))
1090 except ssl.SSLError as x:
Georg Brandl89fad142010-03-14 10:23:39 +00001091 self.fail("Unexpected SSL error: " + str(x))
Bill Janssen58afe4c2008-09-08 16:45:19 +00001092 except Exception as x:
Georg Brandl89fad142010-03-14 10:23:39 +00001093 self.fail("Unexpected exception: " + str(x))
Bill Janssen58afe4c2008-09-08 16:45:19 +00001094 else:
1095 # helper methods for standardising recv* method signatures
1096 def _recv_into():
1097 b = bytearray(b"\0"*100)
1098 count = s.recv_into(b)
1099 return b[:count]
1100
1101 def _recvfrom_into():
1102 b = bytearray(b"\0"*100)
1103 count, addr = s.recvfrom_into(b)
1104 return b[:count]
1105
1106 # (name, method, whether to expect success, *args)
1107 send_methods = [
1108 ('send', s.send, True, []),
1109 ('sendto', s.sendto, False, ["some.address"]),
1110 ('sendall', s.sendall, True, []),
1111 ]
1112 recv_methods = [
1113 ('recv', s.recv, True, []),
1114 ('recvfrom', s.recvfrom, False, ["some.address"]),
1115 ('recv_into', _recv_into, True, []),
1116 ('recvfrom_into', _recvfrom_into, False, []),
1117 ]
1118 data_prefix = "PREFIX_"
1119
1120 for meth_name, send_meth, expect_success, args in send_methods:
1121 indata = data_prefix + meth_name
1122 try:
1123 send_meth(indata.encode('ASCII', 'strict'), *args)
1124 outdata = s.read()
1125 outdata = str(outdata, 'ASCII', 'strict')
1126 if outdata != indata.lower():
Georg Brandl89fad142010-03-14 10:23:39 +00001127 self.fail(
Bill Janssen58afe4c2008-09-08 16:45:19 +00001128 "While sending with <<{name:s}>> bad data "
1129 "<<{outdata:s}>> ({nout:d}) received; "
1130 "expected <<{indata:s}>> ({nin:d})\n".format(
1131 name=meth_name, outdata=repr(outdata[:20]),
1132 nout=len(outdata),
1133 indata=repr(indata[:20]), nin=len(indata)
1134 )
1135 )
1136 except ValueError as e:
1137 if expect_success:
Georg Brandl89fad142010-03-14 10:23:39 +00001138 self.fail(
Bill Janssen58afe4c2008-09-08 16:45:19 +00001139 "Failed to send with method <<{name:s}>>; "
1140 "expected to succeed.\n".format(name=meth_name)
1141 )
1142 if not str(e).startswith(meth_name):
Georg Brandl89fad142010-03-14 10:23:39 +00001143 self.fail(
Bill Janssen58afe4c2008-09-08 16:45:19 +00001144 "Method <<{name:s}>> failed with unexpected "
1145 "exception message: {exp:s}\n".format(
1146 name=meth_name, exp=e
1147 )
1148 )
1149
1150 for meth_name, recv_meth, expect_success, args in recv_methods:
1151 indata = data_prefix + meth_name
1152 try:
1153 s.send(indata.encode('ASCII', 'strict'))
1154 outdata = recv_meth(*args)
1155 outdata = str(outdata, 'ASCII', 'strict')
1156 if outdata != indata.lower():
Georg Brandl89fad142010-03-14 10:23:39 +00001157 self.fail(
Bill Janssen58afe4c2008-09-08 16:45:19 +00001158 "While receiving with <<{name:s}>> bad data "
1159 "<<{outdata:s}>> ({nout:d}) received; "
1160 "expected <<{indata:s}>> ({nin:d})\n".format(
1161 name=meth_name, outdata=repr(outdata[:20]),
1162 nout=len(outdata),
1163 indata=repr(indata[:20]), nin=len(indata)
1164 )
1165 )
1166 except ValueError as e:
1167 if expect_success:
Georg Brandl89fad142010-03-14 10:23:39 +00001168 self.fail(
Bill Janssen58afe4c2008-09-08 16:45:19 +00001169 "Failed to receive with method <<{name:s}>>; "
1170 "expected to succeed.\n".format(name=meth_name)
1171 )
1172 if not str(e).startswith(meth_name):
Georg Brandl89fad142010-03-14 10:23:39 +00001173 self.fail(
Bill Janssen58afe4c2008-09-08 16:45:19 +00001174 "Method <<{name:s}>> failed with unexpected "
1175 "exception message: {exp:s}\n".format(
1176 name=meth_name, exp=e
1177 )
1178 )
1179 # consume data
1180 s.read()
1181
1182 s.write("over\n".encode("ASCII", "strict"))
1183 s.close()
1184 finally:
1185 server.stop()
1186 server.join()
1187
1188
Thomas Woutersed03b412007-08-28 21:37:11 +00001189def test_main(verbose=False):
1190 if skip_expected:
Benjamin Petersone549ead2009-03-28 21:42:05 +00001191 raise unittest.SkipTest("No SSL support")
Thomas Woutersed03b412007-08-28 21:37:11 +00001192
Trent Nelson78520002008-04-10 20:54:35 +00001193 global CERTFILE, SVN_PYTHON_ORG_ROOT_CERT
Thomas Woutersed03b412007-08-28 21:37:11 +00001194 CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir,
1195 "keycert.pem")
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001196 SVN_PYTHON_ORG_ROOT_CERT = os.path.join(
1197 os.path.dirname(__file__) or os.curdir,
1198 "https_svn_python_org_root.pem")
1199
1200 if (not os.path.exists(CERTFILE) or
1201 not os.path.exists(SVN_PYTHON_ORG_ROOT_CERT)):
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001202 raise support.TestFailed("Can't read certificate files!")
Bill Janssen6e027db2007-11-15 22:23:56 +00001203
Thomas Woutersed03b412007-08-28 21:37:11 +00001204 tests = [BasicTests]
1205
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001206 if support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00001207 tests.append(NetworkedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001208
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001209 if _have_threads:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001210 thread_info = support.threading_setup()
1211 if thread_info and support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00001212 tests.append(ThreadedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001213
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001214 support.run_unittest(*tests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001215
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001216 if _have_threads:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001217 support.threading_cleanup(*thread_info)
Thomas Woutersed03b412007-08-28 21:37:11 +00001218
1219if __name__ == "__main__":
1220 test_main()