blob: 52c392c58c0b6bcde0af6c54299fe3c88a035219 [file] [log] [blame]
Thomas Woutersed03b412007-08-28 21:37:11 +00001# Test the support for SSL and sockets
2
3import sys
4import unittest
Benjamin Petersonee8712c2008-05-20 21:35:26 +00005from test import support
Thomas Woutersed03b412007-08-28 21:37:11 +00006import socket
Bill Janssen6e027db2007-11-15 22:23:56 +00007import select
Thomas Woutersed03b412007-08-28 21:37:11 +00008import errno
Thomas Woutersed03b412007-08-28 21:37:11 +00009import subprocess
10import time
11import os
12import pprint
Jeremy Hylton1afc1692008-06-18 20:49:58 +000013import urllib.parse, urllib.request
Thomas Woutersed03b412007-08-28 21:37:11 +000014import shutil
15import traceback
Bill Janssen54cc54c2007-12-14 22:08:56 +000016import asyncore
Thomas Woutersed03b412007-08-28 21:37:11 +000017
Georg Brandl24420152008-05-26 16:32:26 +000018from http.server import HTTPServer, SimpleHTTPRequestHandler
Thomas Wouters1b7f8912007-09-19 03:06:30 +000019
Thomas Woutersed03b412007-08-28 21:37:11 +000020# Optionally test SSL support, if we have it in the tested platform
21skip_expected = False
22try:
23 import ssl
24except ImportError:
25 skip_expected = True
26
Benjamin Petersonee8712c2008-05-20 21:35:26 +000027HOST = support.HOST
Thomas Woutersed03b412007-08-28 21:37:11 +000028CERTFILE = None
Thomas Wouters1b7f8912007-09-19 03:06:30 +000029SVN_PYTHON_ORG_ROOT_CERT = None
Thomas Woutersed03b412007-08-28 21:37:11 +000030
Thomas Woutersed03b412007-08-28 21:37:11 +000031def handle_error(prefix):
32 exc_format = ' '.join(traceback.format_exception(*sys.exc_info()))
Benjamin Petersonee8712c2008-05-20 21:35:26 +000033 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000034 sys.stdout.write(prefix + exc_format)
Thomas Woutersed03b412007-08-28 21:37:11 +000035
36
37class BasicTests(unittest.TestCase):
38
Georg Brandlfceab5a2008-01-19 20:08:23 +000039 def testSSLconnect(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +000040 if not support.is_resource_enabled('network'):
Georg Brandlfceab5a2008-01-19 20:08:23 +000041 return
42 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
43 cert_reqs=ssl.CERT_NONE)
44 s.connect(("svn.python.org", 443))
45 c = s.getpeercert()
46 if c:
Benjamin Petersonee8712c2008-05-20 21:35:26 +000047 raise support.TestFailed("Peer cert %s shouldn't be here!")
Georg Brandlfceab5a2008-01-19 20:08:23 +000048 s.close()
49
50 # this should fail because we have no verification certs
51 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
52 cert_reqs=ssl.CERT_REQUIRED)
53 try:
54 s.connect(("svn.python.org", 443))
55 except ssl.SSLError:
56 pass
57 finally:
58 s.close()
59
Thomas Wouters1b7f8912007-09-19 03:06:30 +000060 def testCrucialConstants(self):
61 ssl.PROTOCOL_SSLv2
62 ssl.PROTOCOL_SSLv23
63 ssl.PROTOCOL_SSLv3
64 ssl.PROTOCOL_TLSv1
65 ssl.CERT_NONE
66 ssl.CERT_OPTIONAL
67 ssl.CERT_REQUIRED
Thomas Woutersed03b412007-08-28 21:37:11 +000068
Thomas Wouters1b7f8912007-09-19 03:06:30 +000069 def testRAND(self):
70 v = ssl.RAND_status()
Benjamin Petersonee8712c2008-05-20 21:35:26 +000071 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000072 sys.stdout.write("\n RAND_status is %d (%s)\n"
73 % (v, (v and "sufficient randomness") or
74 "insufficient randomness"))
Thomas Woutersed03b412007-08-28 21:37:11 +000075 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000076 ssl.RAND_egd(1)
77 except TypeError:
78 pass
Thomas Woutersed03b412007-08-28 21:37:11 +000079 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000080 print("didn't raise TypeError")
81 ssl.RAND_add("this is a random string", 75.0)
Thomas Woutersed03b412007-08-28 21:37:11 +000082
Thomas Wouters1b7f8912007-09-19 03:06:30 +000083 def testParseCert(self):
84 # note that this uses an 'unofficial' function in _ssl.c,
85 # provided solely for this test, to exercise the certificate
86 # parsing code
87 p = ssl._ssl._test_decode_cert(CERTFILE, False)
Benjamin Petersonee8712c2008-05-20 21:35:26 +000088 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000089 sys.stdout.write("\n" + pprint.pformat(p) + "\n")
Thomas Woutersed03b412007-08-28 21:37:11 +000090
Thomas Wouters1b7f8912007-09-19 03:06:30 +000091 def testDERtoPEM(self):
92
93 pem = open(SVN_PYTHON_ORG_ROOT_CERT, 'r').read()
94 d1 = ssl.PEM_cert_to_DER_cert(pem)
95 p2 = ssl.DER_cert_to_PEM_cert(d1)
96 d2 = ssl.PEM_cert_to_DER_cert(p2)
97 if (d1 != d2):
Benjamin Petersonee8712c2008-05-20 21:35:26 +000098 raise support.TestFailed("PEM-to-DER or DER-to-PEM translation failed")
Thomas Wouters1b7f8912007-09-19 03:06:30 +000099
Bill Janssen6e027db2007-11-15 22:23:56 +0000100class NetworkedTests(unittest.TestCase):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000101
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000102 def testConnect(self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000103 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
104 cert_reqs=ssl.CERT_NONE)
105 s.connect(("svn.python.org", 443))
106 c = s.getpeercert()
107 if c:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000108 raise support.TestFailed("Peer cert %s shouldn't be here!")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000109 s.close()
110
111 # this should fail because we have no verification certs
112 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
113 cert_reqs=ssl.CERT_REQUIRED)
Thomas Woutersed03b412007-08-28 21:37:11 +0000114 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000115 s.connect(("svn.python.org", 443))
116 except ssl.SSLError:
117 pass
118 finally:
119 s.close()
120
121 # this should succeed because we specify the root cert
122 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
123 cert_reqs=ssl.CERT_REQUIRED,
124 ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
125 try:
126 s.connect(("svn.python.org", 443))
127 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000128 raise support.TestFailed("Unexpected exception %s" % x)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000129 finally:
130 s.close()
131
Bill Janssen6e027db2007-11-15 22:23:56 +0000132 def testNonBlockingHandshake(self):
133 s = socket.socket(socket.AF_INET)
134 s.connect(("svn.python.org", 443))
135 s.setblocking(False)
136 s = ssl.wrap_socket(s,
137 cert_reqs=ssl.CERT_NONE,
138 do_handshake_on_connect=False)
139 count = 0
140 while True:
141 try:
142 count += 1
143 s.do_handshake()
144 break
145 except ssl.SSLError as err:
146 if err.args[0] == ssl.SSL_ERROR_WANT_READ:
147 select.select([s], [], [])
148 elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE:
149 select.select([], [s], [])
150 else:
151 raise
152 s.close()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000153 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000154 sys.stdout.write("\nNeeded %d calls to do_handshake() to establish session.\n" % count)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000155
Bill Janssen54cc54c2007-12-14 22:08:56 +0000156 def testFetchServerCert(self):
157
158 pem = ssl.get_server_certificate(("svn.python.org", 443))
159 if not pem:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000160 raise support.TestFailed("No server certificate on svn.python.org:443!")
Bill Janssen54cc54c2007-12-14 22:08:56 +0000161
162 return
163
164 try:
165 pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=CERTFILE)
166 except ssl.SSLError as x:
167 #should fail
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000168 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000169 sys.stdout.write("%s\n" % x)
170 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000171 raise support.TestFailed("Got server certificate %s for svn.python.org!" % pem)
Bill Janssen54cc54c2007-12-14 22:08:56 +0000172
173 pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
174 if not pem:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000175 raise support.TestFailed("No server certificate on svn.python.org:443!")
176 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000177 sys.stdout.write("\nVerified certificate for svn.python.org:443 is\n%s\n" % pem)
178
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000179
180try:
181 import threading
182except ImportError:
183 _have_threads = False
184else:
185
186 _have_threads = True
187
188 class ThreadedEchoServer(threading.Thread):
189
190 class ConnectionHandler(threading.Thread):
191
192 """A mildly complicated class, because we want it to work both
193 with and without the SSL wrapper around the socket connection, so
194 that we can test the STARTTLS functionality."""
195
Bill Janssen6e027db2007-11-15 22:23:56 +0000196 def __init__(self, server, connsock, addr):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000197 self.server = server
198 self.running = False
199 self.sock = connsock
Bill Janssen6e027db2007-11-15 22:23:56 +0000200 self.addr = addr
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000201 self.sock.setblocking(1)
202 self.sslconn = None
203 threading.Thread.__init__(self)
Benjamin Peterson502d89e2008-06-11 22:55:41 +0000204 self.set_daemon(True)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000205
206 def wrap_conn (self):
207 try:
208 self.sslconn = ssl.wrap_socket(self.sock, server_side=True,
209 certfile=self.server.certificate,
210 ssl_version=self.server.protocol,
211 ca_certs=self.server.cacerts,
212 cert_reqs=self.server.certreqs)
213 except:
214 if self.server.chatty:
Bill Janssen6e027db2007-11-15 22:23:56 +0000215 handle_error("\n server: bad connection attempt from " + repr(self.addr) + ":\n")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000216 if not self.server.expect_bad_connects:
217 # here, we want to stop the server, because this shouldn't
218 # happen in the context of our test case
219 self.running = False
220 # normally, we'd just stop here, but for the test
221 # harness, we want to stop the server
222 self.server.stop()
Bill Janssen6e027db2007-11-15 22:23:56 +0000223 self.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000224 return False
225
226 else:
227 if self.server.certreqs == ssl.CERT_REQUIRED:
228 cert = self.sslconn.getpeercert()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000229 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000230 sys.stdout.write(" client cert is " + pprint.pformat(cert) + "\n")
231 cert_binary = self.sslconn.getpeercert(True)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000232 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000233 sys.stdout.write(" cert binary is " + str(len(cert_binary)) + " bytes\n")
234 cipher = self.sslconn.cipher()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000235 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000236 sys.stdout.write(" server: connection cipher is now " + str(cipher) + "\n")
237 return True
238
239 def read(self):
240 if self.sslconn:
241 return self.sslconn.read()
242 else:
243 return self.sock.recv(1024)
244
245 def write(self, bytes):
246 if self.sslconn:
247 return self.sslconn.write(bytes)
248 else:
249 return self.sock.send(bytes)
250
251 def close(self):
252 if self.sslconn:
253 self.sslconn.close()
254 else:
255 self.sock.close()
256
257 def run (self):
258 self.running = True
259 if not self.server.starttls_server:
260 if not self.wrap_conn():
261 return
262 while self.running:
263 try:
264 msg = self.read()
Bill Janssen6e027db2007-11-15 22:23:56 +0000265 amsg = (msg and str(msg, 'ASCII', 'strict')) or ''
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000266 if not msg:
267 # eof, so quit this handler
268 self.running = False
269 self.close()
Bill Janssen6e027db2007-11-15 22:23:56 +0000270 elif amsg.strip() == 'over':
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000271 if support.verbose and self.server.connectionchatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000272 sys.stdout.write(" server: client closed connection\n")
273 self.close()
274 return
Bill Janssen6e027db2007-11-15 22:23:56 +0000275 elif (self.server.starttls_server and
276 amsg.strip() == 'STARTTLS'):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000277 if support.verbose and self.server.connectionchatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000278 sys.stdout.write(" server: read STARTTLS from client, sending OK...\n")
Bill Janssen6e027db2007-11-15 22:23:56 +0000279 self.write("OK\n".encode("ASCII", "strict"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000280 if not self.wrap_conn():
281 return
282 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000283 if (support.verbose and
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000284 self.server.connectionchatty):
285 ctype = (self.sslconn and "encrypted") or "unencrypted"
286 sys.stdout.write(" server: read %s (%s), sending back %s (%s)...\n"
287 % (repr(msg), ctype, repr(msg.lower()), ctype))
Bill Janssen6e027db2007-11-15 22:23:56 +0000288 self.write(amsg.lower().encode('ASCII', 'strict'))
289 except socket.error:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000290 if self.server.chatty:
291 handle_error("Test server failure:\n")
292 self.close()
293 self.running = False
294 # normally, we'd just stop here, but for the test
295 # harness, we want to stop the server
296 self.server.stop()
297 except:
298 handle_error('')
299
Trent Nelson78520002008-04-10 20:54:35 +0000300 def __init__(self, certificate, ssl_version=None,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000301 certreqs=None, cacerts=None, expect_bad_connects=False,
302 chatty=True, connectionchatty=False, starttls_server=False):
303 if ssl_version is None:
304 ssl_version = ssl.PROTOCOL_TLSv1
305 if certreqs is None:
306 certreqs = ssl.CERT_NONE
307 self.certificate = certificate
308 self.protocol = ssl_version
309 self.certreqs = certreqs
310 self.cacerts = cacerts
311 self.expect_bad_connects = expect_bad_connects
312 self.chatty = chatty
313 self.connectionchatty = connectionchatty
314 self.starttls_server = starttls_server
315 self.sock = socket.socket()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000316 self.port = support.bind_port(self.sock)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000317 self.flag = None
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000318 self.active = False
319 threading.Thread.__init__(self)
Benjamin Peterson502d89e2008-06-11 22:55:41 +0000320 self.set_daemon(False)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000321
322 def start (self, flag=None):
323 self.flag = flag
324 threading.Thread.start(self)
325
326 def run (self):
327 self.sock.settimeout(0.5)
328 self.sock.listen(5)
329 self.active = True
330 if self.flag:
331 # signal an event
332 self.flag.set()
333 while self.active:
334 try:
335 newconn, connaddr = self.sock.accept()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000336 if support.verbose and self.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000337 sys.stdout.write(' server: new connection from '
Bill Janssen6e027db2007-11-15 22:23:56 +0000338 + repr(connaddr) + '\n')
339 handler = self.ConnectionHandler(self, newconn, connaddr)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000340 handler.start()
341 except socket.timeout:
342 pass
343 except KeyboardInterrupt:
344 self.stop()
345 except:
346 if self.chatty:
347 handle_error("Test server failure:\n")
Bill Janssen6e027db2007-11-15 22:23:56 +0000348 self.sock.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000349
350 def stop (self):
351 self.active = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000352
Bill Janssen54cc54c2007-12-14 22:08:56 +0000353 class OurHTTPSServer(threading.Thread):
354
355 # This one's based on HTTPServer, which is based on SocketServer
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000356
357 class HTTPSServer(HTTPServer):
358
359 def __init__(self, server_address, RequestHandlerClass, certfile):
360
361 HTTPServer.__init__(self, server_address, RequestHandlerClass)
362 # we assume the certfile contains both private key and certificate
363 self.certfile = certfile
364 self.active = False
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000365 self.active_lock = threading.Lock()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000366 self.allow_reuse_address = True
367
Bill Janssen6e027db2007-11-15 22:23:56 +0000368 def __str__(self):
369 return ('<%s %s:%s>' %
370 (self.__class__.__name__,
371 self.server_name,
372 self.server_port))
373
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000374 def get_request (self):
375 # override this to wrap socket with SSL
376 sock, addr = self.socket.accept()
377 sslconn = ssl.wrap_socket(sock, server_side=True,
378 certfile=self.certfile)
379 return sslconn, addr
380
381 # The methods overridden below this are mainly so that we
382 # can run it in a thread and be able to stop it from another
383 # You probably wouldn't need them in other uses.
384
385 def server_activate(self):
386 # We want to run this in a thread for testing purposes,
387 # so we override this to set timeout, so that we get
388 # a chance to stop the server
389 self.socket.settimeout(0.5)
390 HTTPServer.server_activate(self)
391
392 def serve_forever(self):
393 # We want this to run in a thread, so we use a slightly
394 # modified version of "forever".
395 self.active = True
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000396 while 1:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000397 try:
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000398 # We need to lock while handling the request.
399 # Another thread can close the socket after self.active
400 # has been checked and before the request is handled.
401 # This causes an exception when using the closed socket.
402 with self.active_lock:
403 if not self.active:
404 break
405 self.handle_request()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000406 except socket.timeout:
407 pass
408 except KeyboardInterrupt:
409 self.server_close()
410 return
411 except:
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000412 sys.stdout.write(''.join(traceback.format_exception(*sys.exc_info())))
413 break
Neal Norwitzf9ff5f02008-03-31 05:39:26 +0000414 time.sleep(0.1)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000415
416 def server_close(self):
417 # Again, we want this to run in a thread, so we need to override
418 # close to clear the "active" flag, so that serve_forever() will
419 # terminate.
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000420 with self.active_lock:
421 HTTPServer.server_close(self)
422 self.active = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000423
424 class RootedHTTPRequestHandler(SimpleHTTPRequestHandler):
425
426 # need to override translate_path to get a known root,
427 # instead of using os.curdir, since the test could be
428 # run from anywhere
429
430 server_version = "TestHTTPS/1.0"
431
432 root = None
433
434 def translate_path(self, path):
435 """Translate a /-separated PATH to the local filename syntax.
436
437 Components that mean special things to the local file system
438 (e.g. drive or directory names) are ignored. (XXX They should
439 probably be diagnosed.)
440
441 """
442 # abandon query parameters
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000443 path = urllib.parse.urlparse(path)[2]
444 path = os.path.normpath(urllib.parse.unquote(path))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000445 words = path.split('/')
446 words = filter(None, words)
447 path = self.root
448 for word in words:
449 drive, word = os.path.splitdrive(word)
450 head, word = os.path.split(word)
451 if word in self.root: continue
452 path = os.path.join(path, word)
453 return path
454
455 def log_message(self, format, *args):
456
457 # we override this to suppress logging unless "verbose"
458
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000459 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000460 sys.stdout.write(" server (%s:%d %s):\n [%s] %s\n" %
461 (self.server.server_address,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000462 self.server.server_port,
463 self.request.cipher(),
464 self.log_date_time_string(),
465 format%args))
Thomas Woutersed03b412007-08-28 21:37:11 +0000466
467
Trent Nelson78520002008-04-10 20:54:35 +0000468 def __init__(self, certfile):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000469 self.flag = None
470 self.active = False
471 self.RootedHTTPRequestHandler.root = os.path.split(CERTFILE)[0]
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000472 self.port = support.find_unused_port()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000473 self.server = self.HTTPSServer(
Trent Nelson78520002008-04-10 20:54:35 +0000474 (HOST, self.port), self.RootedHTTPRequestHandler, certfile)
Thomas Woutersed03b412007-08-28 21:37:11 +0000475 threading.Thread.__init__(self)
Benjamin Peterson502d89e2008-06-11 22:55:41 +0000476 self.set_daemon(True)
Thomas Woutersed03b412007-08-28 21:37:11 +0000477
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000478 def __str__(self):
Bill Janssen6e027db2007-11-15 22:23:56 +0000479 return "<%s %s>" % (self.__class__.__name__, self.server)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000480
481 def start (self, flag=None):
482 self.flag = flag
483 threading.Thread.start(self)
484
Thomas Woutersed03b412007-08-28 21:37:11 +0000485 def run (self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000486 self.active = True
487 if self.flag:
488 self.flag.set()
489 self.server.serve_forever()
490 self.active = False
491
492 def stop (self):
493 self.active = False
494 self.server.server_close()
495
496
Bill Janssen54cc54c2007-12-14 22:08:56 +0000497 class AsyncoreEchoServer(threading.Thread):
498
499 # this one's based on asyncore.dispatcher
500
501 class EchoServer (asyncore.dispatcher):
502
503 class ConnectionHandler (asyncore.dispatcher_with_send):
504
505 def __init__(self, conn, certfile):
506 self.socket = ssl.wrap_socket(conn, server_side=True,
507 certfile=certfile,
508 do_handshake_on_connect=False)
509 asyncore.dispatcher_with_send.__init__(self, self.socket)
510 # now we have to do the handshake
511 # we'll just do it the easy way, and block the connection
512 # till it's finished. If we were doing it right, we'd
513 # do this in multiple calls to handle_read...
514 self.do_handshake(block=True)
515
516 def readable(self):
517 if isinstance(self.socket, ssl.SSLSocket):
518 while self.socket.pending() > 0:
519 self.handle_read_event()
520 return True
521
522 def handle_read(self):
523 data = self.recv(1024)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000524 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000525 sys.stdout.write(" server: read %s from client\n" % repr(data))
526 if not data:
527 self.close()
528 else:
529 self.send(str(data, 'ASCII', 'strict').lower().encode('ASCII', 'strict'))
530
531 def handle_close(self):
Bill Janssen2f5799b2008-06-29 00:08:12 +0000532 self.close()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000533 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000534 sys.stdout.write(" server: closed connection %s\n" % self.socket)
535
536 def handle_error(self):
537 raise
538
539 def __init__(self, port, certfile):
540 self.port = port
541 self.certfile = certfile
542 asyncore.dispatcher.__init__(self)
543 self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
544 self.bind(('', port))
545 self.listen(5)
546
547 def handle_accept(self):
548 sock_obj, addr = self.accept()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000549 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000550 sys.stdout.write(" server: new connection from %s:%s\n" %addr)
551 self.ConnectionHandler(sock_obj, self.certfile)
552
553 def handle_error(self):
554 raise
555
Trent Nelson78520002008-04-10 20:54:35 +0000556 def __init__(self, certfile):
Bill Janssen54cc54c2007-12-14 22:08:56 +0000557 self.flag = None
558 self.active = False
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000559 self.port = support.find_unused_port()
Trent Nelson78520002008-04-10 20:54:35 +0000560 self.server = self.EchoServer(self.port, certfile)
Bill Janssen54cc54c2007-12-14 22:08:56 +0000561 threading.Thread.__init__(self)
Benjamin Peterson502d89e2008-06-11 22:55:41 +0000562 self.set_daemon(True)
Bill Janssen54cc54c2007-12-14 22:08:56 +0000563
564 def __str__(self):
565 return "<%s %s>" % (self.__class__.__name__, self.server)
566
567 def start (self, flag=None):
568 self.flag = flag
569 threading.Thread.start(self)
570
571 def run (self):
572 self.active = True
573 if self.flag:
574 self.flag.set()
575 while self.active:
576 try:
577 asyncore.loop(1)
578 except:
579 pass
580
581 def stop (self):
582 self.active = False
583 self.server.close()
584
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000585 def badCertTest (certfile):
Trent Nelson78520002008-04-10 20:54:35 +0000586 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000587 certreqs=ssl.CERT_REQUIRED,
Bill Janssen6e027db2007-11-15 22:23:56 +0000588 cacerts=CERTFILE, chatty=False,
589 connectionchatty=False)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000590 flag = threading.Event()
591 server.start(flag)
592 # wait for it to start
593 flag.wait()
594 # try to connect
595 try:
Thomas Woutersed03b412007-08-28 21:37:11 +0000596 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000597 s = ssl.wrap_socket(socket.socket(),
598 certfile=certfile,
599 ssl_version=ssl.PROTOCOL_TLSv1)
Trent Nelson78520002008-04-10 20:54:35 +0000600 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000601 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000602 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000603 sys.stdout.write("\nSSLError is %s\n" % x)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000604 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000605 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000606 "Use of invalid cert should have failed!")
607 finally:
608 server.stop()
609 server.join()
Thomas Woutersed03b412007-08-28 21:37:11 +0000610
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000611 def serverParamsTest (certfile, protocol, certreqs, cacertsfile,
Bill Janssen6e027db2007-11-15 22:23:56 +0000612 client_certfile, client_protocol=None,
613 indata="FOO\n",
614 chatty=False, connectionchatty=False):
Thomas Woutersed03b412007-08-28 21:37:11 +0000615
Trent Nelson78520002008-04-10 20:54:35 +0000616 server = ThreadedEchoServer(certfile,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000617 certreqs=certreqs,
618 ssl_version=protocol,
619 cacerts=cacertsfile,
620 chatty=chatty,
Bill Janssen6e027db2007-11-15 22:23:56 +0000621 connectionchatty=False)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000622 flag = threading.Event()
623 server.start(flag)
624 # wait for it to start
625 flag.wait()
626 # try to connect
627 if client_protocol is None:
628 client_protocol = protocol
629 try:
Bill Janssen6e027db2007-11-15 22:23:56 +0000630 s = ssl.wrap_socket(socket.socket(),
Trent Nelson6b240cd2008-04-10 20:12:06 +0000631 server_side=False,
Bill Janssen6e027db2007-11-15 22:23:56 +0000632 certfile=client_certfile,
633 ca_certs=cacertsfile,
634 cert_reqs=certreqs,
635 ssl_version=client_protocol)
Trent Nelson78520002008-04-10 20:54:35 +0000636 s.connect((HOST, server.port))
Bill Janssen6e027db2007-11-15 22:23:56 +0000637 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000638 raise support.TestFailed("Unexpected SSL error: " + str(x))
Bill Janssen6e027db2007-11-15 22:23:56 +0000639 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000640 raise support.TestFailed("Unexpected exception: " + str(x))
Bill Janssen6e027db2007-11-15 22:23:56 +0000641 else:
642 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000643 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000644 sys.stdout.write(
645 " client: sending %s...\n" % (repr(indata)))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000646 s.write(indata.encode('ASCII', 'strict'))
Bill Janssen6e027db2007-11-15 22:23:56 +0000647 outdata = s.read()
648 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000649 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000650 sys.stdout.write(" client: read %s\n" % repr(outdata))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000651 outdata = str(outdata, 'ASCII', 'strict')
Bill Janssen6e027db2007-11-15 22:23:56 +0000652 if outdata != indata.lower():
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000653 raise support.TestFailed(
Bill Janssen6e027db2007-11-15 22:23:56 +0000654 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
Trent Nelson6b240cd2008-04-10 20:12:06 +0000655 % (repr(outdata[:min(len(outdata),20)]), len(outdata),
656 repr(indata[:min(len(indata),20)].lower()), len(indata)))
657 s.write("over\n".encode("ASCII", "strict"))
Bill Janssen6e027db2007-11-15 22:23:56 +0000658 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000659 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000660 sys.stdout.write(" client: closing connection.\n")
661 s.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000662 finally:
663 server.stop()
664 server.join()
Thomas Woutersed03b412007-08-28 21:37:11 +0000665
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000666 def tryProtocolCombo (server_protocol,
667 client_protocol,
668 expectedToWork,
669 certsreqs=None):
Thomas Woutersed03b412007-08-28 21:37:11 +0000670
Benjamin Peterson2a691a82008-03-31 01:51:45 +0000671 if certsreqs is None:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000672 certsreqs = ssl.CERT_NONE
Thomas Woutersed03b412007-08-28 21:37:11 +0000673
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000674 if certsreqs == ssl.CERT_NONE:
675 certtype = "CERT_NONE"
676 elif certsreqs == ssl.CERT_OPTIONAL:
677 certtype = "CERT_OPTIONAL"
678 elif certsreqs == ssl.CERT_REQUIRED:
679 certtype = "CERT_REQUIRED"
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000680 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000681 formatstr = (expectedToWork and " %s->%s %s\n") or " {%s->%s} %s\n"
682 sys.stdout.write(formatstr %
683 (ssl.get_protocol_name(client_protocol),
684 ssl.get_protocol_name(server_protocol),
685 certtype))
686 try:
687 serverParamsTest(CERTFILE, server_protocol, certsreqs,
Bill Janssen6e027db2007-11-15 22:23:56 +0000688 CERTFILE, CERTFILE, client_protocol,
689 chatty=False, connectionchatty=False)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000690 except support.TestFailed:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000691 if expectedToWork:
692 raise
693 else:
694 if not expectedToWork:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000695 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000696 "Client protocol %s succeeded with server protocol %s!"
697 % (ssl.get_protocol_name(client_protocol),
698 ssl.get_protocol_name(server_protocol)))
699
700
Bill Janssen6e027db2007-11-15 22:23:56 +0000701 class ThreadedTests(unittest.TestCase):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000702
Trent Nelson6b240cd2008-04-10 20:12:06 +0000703 def testEcho (self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000704
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000705 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000706 sys.stdout.write("\n")
707 serverParamsTest(CERTFILE, ssl.PROTOCOL_TLSv1, ssl.CERT_NONE,
708 CERTFILE, CERTFILE, ssl.PROTOCOL_TLSv1,
709 chatty=True, connectionchatty=True)
710
711 def testReadCert(self):
712
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000713 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000714 sys.stdout.write("\n")
715 s2 = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000716 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000717 certreqs=ssl.CERT_NONE,
718 ssl_version=ssl.PROTOCOL_SSLv23,
719 cacerts=CERTFILE,
720 chatty=False)
721 flag = threading.Event()
722 server.start(flag)
723 # wait for it to start
724 flag.wait()
725 # try to connect
726 try:
727 try:
728 s = ssl.wrap_socket(socket.socket(),
729 certfile=CERTFILE,
730 ca_certs=CERTFILE,
731 cert_reqs=ssl.CERT_REQUIRED,
732 ssl_version=ssl.PROTOCOL_SSLv23)
Trent Nelson78520002008-04-10 20:54:35 +0000733 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000734 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000735 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000736 "Unexpected SSL error: " + str(x))
737 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000738 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000739 "Unexpected exception: " + str(x))
740 else:
741 if not s:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000742 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000743 "Can't SSL-handshake with test server")
744 cert = s.getpeercert()
745 if not cert:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000746 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000747 "Can't get peer certificate.")
748 cipher = s.cipher()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000749 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000750 sys.stdout.write(pprint.pformat(cert) + '\n')
751 sys.stdout.write("Connection cipher is " + str(cipher) + '.\n')
Bill Janssen6e027db2007-11-15 22:23:56 +0000752 if 'subject' not in cert:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000753 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000754 "No subject field in certificate: %s." %
755 pprint.pformat(cert))
756 if ((('organizationName', 'Python Software Foundation'),)
757 not in cert['subject']):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000758 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000759 "Missing or invalid 'organizationName' field in certificate subject; "
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000760 "should be 'Python Software Foundation'.")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000761 s.close()
762 finally:
763 server.stop()
764 server.join()
765
766 def testNULLcert(self):
767 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
768 "nullcert.pem"))
769 def testMalformedCert(self):
770 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
771 "badcert.pem"))
772 def testMalformedKey(self):
773 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
774 "badkey.pem"))
775
Trent Nelson6b240cd2008-04-10 20:12:06 +0000776 def testRudeShutdown(self):
777
778 listener_ready = threading.Event()
779 listener_gone = threading.Event()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000780 port = support.find_unused_port()
Trent Nelson6b240cd2008-04-10 20:12:06 +0000781
782 # `listener` runs in a thread. It opens a socket listening on
783 # PORT, and sits in an accept() until the main thread connects.
784 # Then it rudely closes the socket, and sets Event `listener_gone`
785 # to let the main thread know the socket is gone.
786 def listener():
787 s = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000788 s.bind((HOST, port))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000789 s.listen(5)
790 listener_ready.set()
791 s.accept()
792 s = None # reclaim the socket object, which also closes it
793 listener_gone.set()
794
795 def connector():
796 listener_ready.wait()
797 s = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000798 s.connect((HOST, port))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000799 listener_gone.wait()
800 try:
801 ssl_sock = ssl.wrap_socket(s)
802 except IOError:
803 pass
804 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000805 raise support.TestFailed(
Trent Nelson6b240cd2008-04-10 20:12:06 +0000806 'connecting to closed SSL socket should have failed')
807
808 t = threading.Thread(target=listener)
809 t.start()
810 connector()
811 t.join()
812
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000813 def testProtocolSSL2(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000814 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000815 sys.stdout.write("\n")
816 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True)
817 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL)
818 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED)
819 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True)
820 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False)
821 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False)
822
823 def testProtocolSSL23(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000824 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000825 sys.stdout.write("\n")
826 try:
827 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv2, True)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000828 except support.TestFailed as x:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000829 # this fails on some older versions of OpenSSL (0.9.7l, for instance)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000830 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000831 sys.stdout.write(
832 " SSL2 client to SSL23 server test unexpectedly failed:\n %s\n"
833 % str(x))
834 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True)
835 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True)
836 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True)
837
838 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
839 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_OPTIONAL)
840 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
841
842 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
843 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_REQUIRED)
844 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
845
846 def testProtocolSSL3(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000847 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000848 sys.stdout.write("\n")
849 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True)
850 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
851 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
852 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False)
853 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, False)
854 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False)
855
856 def testProtocolTLS1(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000857 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000858 sys.stdout.write("\n")
859 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True)
860 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
861 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
862 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False)
863 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False)
864 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv23, False)
865
866 def testSTARTTLS (self):
867
868 msgs = ("msg 1", "MSG 2", "STARTTLS", "MSG 3", "msg 4")
869
Trent Nelson78520002008-04-10 20:54:35 +0000870 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000871 ssl_version=ssl.PROTOCOL_TLSv1,
872 starttls_server=True,
873 chatty=True,
874 connectionchatty=True)
875 flag = threading.Event()
876 server.start(flag)
877 # wait for it to start
878 flag.wait()
879 # try to connect
880 wrapped = False
881 try:
882 try:
883 s = socket.socket()
884 s.setblocking(1)
Trent Nelson78520002008-04-10 20:54:35 +0000885 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000886 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000887 raise support.TestFailed("Unexpected exception: " + str(x))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000888 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000889 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000890 sys.stdout.write("\n")
891 for indata in msgs:
Bill Janssen6e027db2007-11-15 22:23:56 +0000892 msg = indata.encode('ASCII', 'replace')
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000893 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000894 sys.stdout.write(
Bill Janssen6e027db2007-11-15 22:23:56 +0000895 " client: sending %s...\n" % repr(msg))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000896 if wrapped:
Bill Janssen6e027db2007-11-15 22:23:56 +0000897 conn.write(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000898 outdata = conn.read()
899 else:
Bill Janssen6e027db2007-11-15 22:23:56 +0000900 s.send(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000901 outdata = s.recv(1024)
902 if (indata == "STARTTLS" and
Bill Janssen6e027db2007-11-15 22:23:56 +0000903 str(outdata, 'ASCII', 'replace').strip().lower().startswith("ok")):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000904 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000905 msg = str(outdata, 'ASCII', 'replace')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000906 sys.stdout.write(
907 " client: read %s from server, starting TLS...\n"
Bill Janssen6e027db2007-11-15 22:23:56 +0000908 % repr(msg))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000909 conn = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1)
910
911 wrapped = True
912 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000913 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000914 msg = str(outdata, 'ASCII', 'replace')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000915 sys.stdout.write(
Bill Janssen6e027db2007-11-15 22:23:56 +0000916 " client: read %s from server\n" % repr(msg))
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000917 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000918 sys.stdout.write(" client: closing connection.\n")
919 if wrapped:
Bill Janssen6e027db2007-11-15 22:23:56 +0000920 conn.write("over\n".encode("ASCII", "strict"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000921 else:
922 s.send("over\n")
Bill Janssen6e027db2007-11-15 22:23:56 +0000923 if wrapped:
924 conn.close()
925 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000926 s.close()
927 finally:
928 server.stop()
929 server.join()
930
Bill Janssen54cc54c2007-12-14 22:08:56 +0000931 def testSocketServer(self):
Bill Janssen6e027db2007-11-15 22:23:56 +0000932
Trent Nelson78520002008-04-10 20:54:35 +0000933 server = OurHTTPSServer(CERTFILE)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000934 flag = threading.Event()
935 server.start(flag)
936 # wait for it to start
937 flag.wait()
938 # try to connect
939 try:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000940 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000941 sys.stdout.write('\n')
942 d1 = open(CERTFILE, 'rb').read()
943 d2 = ''
944 # now fetch the same data from the HTTPS server
Trent Nelson78520002008-04-10 20:54:35 +0000945 url = 'https://%s:%d/%s' % (
946 HOST, server.port, os.path.split(CERTFILE)[1])
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000947 f = urllib.request.urlopen(url)
Barry Warsaw820c1202008-06-12 04:06:45 +0000948 dlen = f.info().get("content-length")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000949 if dlen and (int(dlen) > 0):
950 d2 = f.read(int(dlen))
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000951 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000952 sys.stdout.write(
953 " client: read %d bytes from remote server '%s'\n"
954 % (len(d2), server))
955 f.close()
956 except:
957 msg = ''.join(traceback.format_exception(*sys.exc_info()))
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000958 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000959 sys.stdout.write('\n' + msg)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000960 raise support.TestFailed(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000961 else:
962 if not (d1 == d2):
Bill Janssen6e027db2007-11-15 22:23:56 +0000963 print("d1 is", len(d1), repr(d1))
964 print("d2 is", len(d2), repr(d2))
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000965 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000966 "Couldn't fetch data from HTTPS server")
967 finally:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000968 if support.verbose:
Neal Norwitzf9ff5f02008-03-31 05:39:26 +0000969 sys.stdout.write('stopping server\n')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000970 server.stop()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000971 if support.verbose:
Neal Norwitzf9ff5f02008-03-31 05:39:26 +0000972 sys.stdout.write('joining thread\n')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000973 server.join()
974
Trent Nelson6b240cd2008-04-10 20:12:06 +0000975 def testAsyncoreServer(self):
976
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000977 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +0000978 sys.stdout.write("\n")
979
980 indata="FOO\n"
Trent Nelson78520002008-04-10 20:54:35 +0000981 server = AsyncoreEchoServer(CERTFILE)
Trent Nelson6b240cd2008-04-10 20:12:06 +0000982 flag = threading.Event()
983 server.start(flag)
984 # wait for it to start
985 flag.wait()
986 # try to connect
987 try:
988 s = ssl.wrap_socket(socket.socket())
Trent Nelson78520002008-04-10 20:54:35 +0000989 s.connect((HOST, server.port))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000990 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000991 raise support.TestFailed("Unexpected SSL error: " + str(x))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000992 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000993 raise support.TestFailed("Unexpected exception: " + str(x))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000994 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000995 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +0000996 sys.stdout.write(
997 " client: sending %s...\n" % (repr(indata)))
998 s.sendall(indata.encode('ASCII', 'strict'))
999 outdata = s.recv()
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001000 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001001 sys.stdout.write(" client: read %s\n" % repr(outdata))
1002 outdata = str(outdata, 'ASCII', 'strict')
1003 if outdata != indata.lower():
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001004 raise support.TestFailed(
Trent Nelson6b240cd2008-04-10 20:12:06 +00001005 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
1006 % (repr(outdata[:min(len(outdata),20)]), len(outdata),
1007 repr(indata[:min(len(indata),20)].lower()), len(indata)))
1008 s.write("over\n".encode("ASCII", "strict"))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001009 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001010 sys.stdout.write(" client: closing connection.\n")
1011 s.close()
1012 finally:
1013 server.stop()
1014 server.join()
1015
Thomas Woutersed03b412007-08-28 21:37:11 +00001016def test_main(verbose=False):
1017 if skip_expected:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001018 raise support.TestSkipped("No SSL support")
Thomas Woutersed03b412007-08-28 21:37:11 +00001019
Trent Nelson78520002008-04-10 20:54:35 +00001020 global CERTFILE, SVN_PYTHON_ORG_ROOT_CERT
Thomas Woutersed03b412007-08-28 21:37:11 +00001021 CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir,
1022 "keycert.pem")
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001023 SVN_PYTHON_ORG_ROOT_CERT = os.path.join(
1024 os.path.dirname(__file__) or os.curdir,
1025 "https_svn_python_org_root.pem")
1026
1027 if (not os.path.exists(CERTFILE) or
1028 not os.path.exists(SVN_PYTHON_ORG_ROOT_CERT)):
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001029 raise support.TestFailed("Can't read certificate files!")
Bill Janssen6e027db2007-11-15 22:23:56 +00001030
Thomas Woutersed03b412007-08-28 21:37:11 +00001031 tests = [BasicTests]
1032
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001033 if support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00001034 tests.append(NetworkedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001035
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001036 if _have_threads:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001037 thread_info = support.threading_setup()
1038 if thread_info and support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00001039 tests.append(ThreadedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001040
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001041 support.run_unittest(*tests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001042
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001043 if _have_threads:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001044 support.threading_cleanup(*thread_info)
Thomas Woutersed03b412007-08-28 21:37:11 +00001045
1046if __name__ == "__main__":
1047 test_main()