blob: 9e36e8067a8ca6335e9ea290af4cf9dd180383d7 [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)
Bill Janssenddc56692008-07-17 18:17:20 +0000604 except socket.error as x:
605 if support.verbose:
606 sys.stdout.write("\nsocket.error is %s\n" % x)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000607 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000608 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000609 "Use of invalid cert should have failed!")
610 finally:
611 server.stop()
612 server.join()
Thomas Woutersed03b412007-08-28 21:37:11 +0000613
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000614 def serverParamsTest (certfile, protocol, certreqs, cacertsfile,
Bill Janssen6e027db2007-11-15 22:23:56 +0000615 client_certfile, client_protocol=None,
616 indata="FOO\n",
617 chatty=False, connectionchatty=False):
Thomas Woutersed03b412007-08-28 21:37:11 +0000618
Trent Nelson78520002008-04-10 20:54:35 +0000619 server = ThreadedEchoServer(certfile,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000620 certreqs=certreqs,
621 ssl_version=protocol,
622 cacerts=cacertsfile,
623 chatty=chatty,
Bill Janssen6e027db2007-11-15 22:23:56 +0000624 connectionchatty=False)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000625 flag = threading.Event()
626 server.start(flag)
627 # wait for it to start
628 flag.wait()
629 # try to connect
630 if client_protocol is None:
631 client_protocol = protocol
632 try:
Bill Janssen6e027db2007-11-15 22:23:56 +0000633 s = ssl.wrap_socket(socket.socket(),
Trent Nelson6b240cd2008-04-10 20:12:06 +0000634 server_side=False,
Bill Janssen6e027db2007-11-15 22:23:56 +0000635 certfile=client_certfile,
636 ca_certs=cacertsfile,
637 cert_reqs=certreqs,
638 ssl_version=client_protocol)
Trent Nelson78520002008-04-10 20:54:35 +0000639 s.connect((HOST, server.port))
Bill Janssen6e027db2007-11-15 22:23:56 +0000640 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000641 raise support.TestFailed("Unexpected SSL error: " + str(x))
Bill Janssen6e027db2007-11-15 22:23:56 +0000642 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000643 raise support.TestFailed("Unexpected exception: " + str(x))
Bill Janssen6e027db2007-11-15 22:23:56 +0000644 else:
645 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000646 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000647 sys.stdout.write(
648 " client: sending %s...\n" % (repr(indata)))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000649 s.write(indata.encode('ASCII', 'strict'))
Bill Janssen6e027db2007-11-15 22:23:56 +0000650 outdata = s.read()
651 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000652 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000653 sys.stdout.write(" client: read %s\n" % repr(outdata))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000654 outdata = str(outdata, 'ASCII', 'strict')
Bill Janssen6e027db2007-11-15 22:23:56 +0000655 if outdata != indata.lower():
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000656 raise support.TestFailed(
Bill Janssen6e027db2007-11-15 22:23:56 +0000657 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
Trent Nelson6b240cd2008-04-10 20:12:06 +0000658 % (repr(outdata[:min(len(outdata),20)]), len(outdata),
659 repr(indata[:min(len(indata),20)].lower()), len(indata)))
660 s.write("over\n".encode("ASCII", "strict"))
Bill Janssen6e027db2007-11-15 22:23:56 +0000661 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000662 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000663 sys.stdout.write(" client: closing connection.\n")
664 s.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000665 finally:
666 server.stop()
667 server.join()
Thomas Woutersed03b412007-08-28 21:37:11 +0000668
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000669 def tryProtocolCombo (server_protocol,
670 client_protocol,
671 expectedToWork,
672 certsreqs=None):
Thomas Woutersed03b412007-08-28 21:37:11 +0000673
Benjamin Peterson2a691a82008-03-31 01:51:45 +0000674 if certsreqs is None:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000675 certsreqs = ssl.CERT_NONE
Thomas Woutersed03b412007-08-28 21:37:11 +0000676
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000677 if certsreqs == ssl.CERT_NONE:
678 certtype = "CERT_NONE"
679 elif certsreqs == ssl.CERT_OPTIONAL:
680 certtype = "CERT_OPTIONAL"
681 elif certsreqs == ssl.CERT_REQUIRED:
682 certtype = "CERT_REQUIRED"
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000683 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000684 formatstr = (expectedToWork and " %s->%s %s\n") or " {%s->%s} %s\n"
685 sys.stdout.write(formatstr %
686 (ssl.get_protocol_name(client_protocol),
687 ssl.get_protocol_name(server_protocol),
688 certtype))
689 try:
690 serverParamsTest(CERTFILE, server_protocol, certsreqs,
Bill Janssen6e027db2007-11-15 22:23:56 +0000691 CERTFILE, CERTFILE, client_protocol,
692 chatty=False, connectionchatty=False)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000693 except support.TestFailed:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000694 if expectedToWork:
695 raise
696 else:
697 if not expectedToWork:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000698 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000699 "Client protocol %s succeeded with server protocol %s!"
700 % (ssl.get_protocol_name(client_protocol),
701 ssl.get_protocol_name(server_protocol)))
702
703
Bill Janssen6e027db2007-11-15 22:23:56 +0000704 class ThreadedTests(unittest.TestCase):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000705
Trent Nelson6b240cd2008-04-10 20:12:06 +0000706 def testEcho (self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000707
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000708 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000709 sys.stdout.write("\n")
710 serverParamsTest(CERTFILE, ssl.PROTOCOL_TLSv1, ssl.CERT_NONE,
711 CERTFILE, CERTFILE, ssl.PROTOCOL_TLSv1,
712 chatty=True, connectionchatty=True)
713
714 def testReadCert(self):
715
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000716 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000717 sys.stdout.write("\n")
718 s2 = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000719 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000720 certreqs=ssl.CERT_NONE,
721 ssl_version=ssl.PROTOCOL_SSLv23,
722 cacerts=CERTFILE,
723 chatty=False)
724 flag = threading.Event()
725 server.start(flag)
726 # wait for it to start
727 flag.wait()
728 # try to connect
729 try:
730 try:
731 s = ssl.wrap_socket(socket.socket(),
732 certfile=CERTFILE,
733 ca_certs=CERTFILE,
734 cert_reqs=ssl.CERT_REQUIRED,
735 ssl_version=ssl.PROTOCOL_SSLv23)
Trent Nelson78520002008-04-10 20:54:35 +0000736 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000737 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000738 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000739 "Unexpected SSL error: " + str(x))
740 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000741 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000742 "Unexpected exception: " + str(x))
743 else:
744 if not s:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000745 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000746 "Can't SSL-handshake with test server")
747 cert = s.getpeercert()
748 if not cert:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000749 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000750 "Can't get peer certificate.")
751 cipher = s.cipher()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000752 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000753 sys.stdout.write(pprint.pformat(cert) + '\n')
754 sys.stdout.write("Connection cipher is " + str(cipher) + '.\n')
Bill Janssen6e027db2007-11-15 22:23:56 +0000755 if 'subject' not in cert:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000756 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000757 "No subject field in certificate: %s." %
758 pprint.pformat(cert))
759 if ((('organizationName', 'Python Software Foundation'),)
760 not in cert['subject']):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000761 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000762 "Missing or invalid 'organizationName' field in certificate subject; "
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000763 "should be 'Python Software Foundation'.")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000764 s.close()
765 finally:
766 server.stop()
767 server.join()
768
769 def testNULLcert(self):
770 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
771 "nullcert.pem"))
772 def testMalformedCert(self):
773 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
774 "badcert.pem"))
775 def testMalformedKey(self):
776 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
777 "badkey.pem"))
778
Trent Nelson6b240cd2008-04-10 20:12:06 +0000779 def testRudeShutdown(self):
780
781 listener_ready = threading.Event()
782 listener_gone = threading.Event()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000783 port = support.find_unused_port()
Trent Nelson6b240cd2008-04-10 20:12:06 +0000784
785 # `listener` runs in a thread. It opens a socket listening on
786 # PORT, and sits in an accept() until the main thread connects.
787 # Then it rudely closes the socket, and sets Event `listener_gone`
788 # to let the main thread know the socket is gone.
789 def listener():
790 s = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000791 s.bind((HOST, port))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000792 s.listen(5)
793 listener_ready.set()
794 s.accept()
795 s = None # reclaim the socket object, which also closes it
796 listener_gone.set()
797
798 def connector():
799 listener_ready.wait()
800 s = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000801 s.connect((HOST, port))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000802 listener_gone.wait()
803 try:
804 ssl_sock = ssl.wrap_socket(s)
805 except IOError:
806 pass
807 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000808 raise support.TestFailed(
Trent Nelson6b240cd2008-04-10 20:12:06 +0000809 'connecting to closed SSL socket should have failed')
810
811 t = threading.Thread(target=listener)
812 t.start()
813 connector()
814 t.join()
815
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000816 def testProtocolSSL2(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000817 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000818 sys.stdout.write("\n")
819 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True)
820 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL)
821 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED)
822 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True)
823 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False)
824 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False)
825
826 def testProtocolSSL23(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000827 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000828 sys.stdout.write("\n")
829 try:
830 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv2, True)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000831 except support.TestFailed as x:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000832 # this fails on some older versions of OpenSSL (0.9.7l, for instance)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000833 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000834 sys.stdout.write(
835 " SSL2 client to SSL23 server test unexpectedly failed:\n %s\n"
836 % str(x))
837 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True)
838 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True)
839 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True)
840
841 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
842 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_OPTIONAL)
843 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
844
845 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
846 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_REQUIRED)
847 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
848
849 def testProtocolSSL3(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000850 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000851 sys.stdout.write("\n")
852 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True)
853 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
854 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
855 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False)
856 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, False)
857 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False)
858
859 def testProtocolTLS1(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000860 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000861 sys.stdout.write("\n")
862 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True)
863 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
864 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
865 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False)
866 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False)
867 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv23, False)
868
869 def testSTARTTLS (self):
870
871 msgs = ("msg 1", "MSG 2", "STARTTLS", "MSG 3", "msg 4")
872
Trent Nelson78520002008-04-10 20:54:35 +0000873 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000874 ssl_version=ssl.PROTOCOL_TLSv1,
875 starttls_server=True,
876 chatty=True,
877 connectionchatty=True)
878 flag = threading.Event()
879 server.start(flag)
880 # wait for it to start
881 flag.wait()
882 # try to connect
883 wrapped = False
884 try:
885 try:
886 s = socket.socket()
887 s.setblocking(1)
Trent Nelson78520002008-04-10 20:54:35 +0000888 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000889 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000890 raise support.TestFailed("Unexpected exception: " + str(x))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000891 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000892 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000893 sys.stdout.write("\n")
894 for indata in msgs:
Bill Janssen6e027db2007-11-15 22:23:56 +0000895 msg = indata.encode('ASCII', 'replace')
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000896 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000897 sys.stdout.write(
Bill Janssen6e027db2007-11-15 22:23:56 +0000898 " client: sending %s...\n" % repr(msg))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000899 if wrapped:
Bill Janssen6e027db2007-11-15 22:23:56 +0000900 conn.write(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000901 outdata = conn.read()
902 else:
Bill Janssen6e027db2007-11-15 22:23:56 +0000903 s.send(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000904 outdata = s.recv(1024)
905 if (indata == "STARTTLS" and
Bill Janssen6e027db2007-11-15 22:23:56 +0000906 str(outdata, 'ASCII', 'replace').strip().lower().startswith("ok")):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000907 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000908 msg = str(outdata, 'ASCII', 'replace')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000909 sys.stdout.write(
910 " client: read %s from server, starting TLS...\n"
Bill Janssen6e027db2007-11-15 22:23:56 +0000911 % repr(msg))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000912 conn = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1)
913
914 wrapped = True
915 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000916 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000917 msg = str(outdata, 'ASCII', 'replace')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000918 sys.stdout.write(
Bill Janssen6e027db2007-11-15 22:23:56 +0000919 " client: read %s from server\n" % repr(msg))
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000920 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000921 sys.stdout.write(" client: closing connection.\n")
922 if wrapped:
Bill Janssen6e027db2007-11-15 22:23:56 +0000923 conn.write("over\n".encode("ASCII", "strict"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000924 else:
925 s.send("over\n")
Bill Janssen6e027db2007-11-15 22:23:56 +0000926 if wrapped:
927 conn.close()
928 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000929 s.close()
930 finally:
931 server.stop()
932 server.join()
933
Bill Janssen54cc54c2007-12-14 22:08:56 +0000934 def testSocketServer(self):
Bill Janssen6e027db2007-11-15 22:23:56 +0000935
Trent Nelson78520002008-04-10 20:54:35 +0000936 server = OurHTTPSServer(CERTFILE)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000937 flag = threading.Event()
938 server.start(flag)
939 # wait for it to start
940 flag.wait()
941 # try to connect
942 try:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000943 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000944 sys.stdout.write('\n')
945 d1 = open(CERTFILE, 'rb').read()
946 d2 = ''
947 # now fetch the same data from the HTTPS server
Trent Nelson78520002008-04-10 20:54:35 +0000948 url = 'https://%s:%d/%s' % (
949 HOST, server.port, os.path.split(CERTFILE)[1])
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000950 f = urllib.request.urlopen(url)
Barry Warsaw820c1202008-06-12 04:06:45 +0000951 dlen = f.info().get("content-length")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000952 if dlen and (int(dlen) > 0):
953 d2 = f.read(int(dlen))
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000954 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000955 sys.stdout.write(
956 " client: read %d bytes from remote server '%s'\n"
957 % (len(d2), server))
958 f.close()
959 except:
960 msg = ''.join(traceback.format_exception(*sys.exc_info()))
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000961 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000962 sys.stdout.write('\n' + msg)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000963 raise support.TestFailed(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000964 else:
965 if not (d1 == d2):
Bill Janssen6e027db2007-11-15 22:23:56 +0000966 print("d1 is", len(d1), repr(d1))
967 print("d2 is", len(d2), repr(d2))
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000968 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000969 "Couldn't fetch data from HTTPS server")
970 finally:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000971 if support.verbose:
Neal Norwitzf9ff5f02008-03-31 05:39:26 +0000972 sys.stdout.write('stopping server\n')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000973 server.stop()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000974 if support.verbose:
Neal Norwitzf9ff5f02008-03-31 05:39:26 +0000975 sys.stdout.write('joining thread\n')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000976 server.join()
977
Trent Nelson6b240cd2008-04-10 20:12:06 +0000978 def testAsyncoreServer(self):
979
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000980 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +0000981 sys.stdout.write("\n")
982
983 indata="FOO\n"
Trent Nelson78520002008-04-10 20:54:35 +0000984 server = AsyncoreEchoServer(CERTFILE)
Trent Nelson6b240cd2008-04-10 20:12:06 +0000985 flag = threading.Event()
986 server.start(flag)
987 # wait for it to start
988 flag.wait()
989 # try to connect
990 try:
991 s = ssl.wrap_socket(socket.socket())
Trent Nelson78520002008-04-10 20:54:35 +0000992 s.connect((HOST, server.port))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000993 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000994 raise support.TestFailed("Unexpected SSL error: " + str(x))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000995 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000996 raise support.TestFailed("Unexpected exception: " + str(x))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000997 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000998 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +0000999 sys.stdout.write(
1000 " client: sending %s...\n" % (repr(indata)))
1001 s.sendall(indata.encode('ASCII', 'strict'))
1002 outdata = s.recv()
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001003 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001004 sys.stdout.write(" client: read %s\n" % repr(outdata))
1005 outdata = str(outdata, 'ASCII', 'strict')
1006 if outdata != indata.lower():
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001007 raise support.TestFailed(
Trent Nelson6b240cd2008-04-10 20:12:06 +00001008 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
1009 % (repr(outdata[:min(len(outdata),20)]), len(outdata),
1010 repr(indata[:min(len(indata),20)].lower()), len(indata)))
1011 s.write("over\n".encode("ASCII", "strict"))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001012 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001013 sys.stdout.write(" client: closing connection.\n")
1014 s.close()
1015 finally:
1016 server.stop()
1017 server.join()
1018
Thomas Woutersed03b412007-08-28 21:37:11 +00001019def test_main(verbose=False):
1020 if skip_expected:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001021 raise support.TestSkipped("No SSL support")
Thomas Woutersed03b412007-08-28 21:37:11 +00001022
Trent Nelson78520002008-04-10 20:54:35 +00001023 global CERTFILE, SVN_PYTHON_ORG_ROOT_CERT
Thomas Woutersed03b412007-08-28 21:37:11 +00001024 CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir,
1025 "keycert.pem")
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001026 SVN_PYTHON_ORG_ROOT_CERT = os.path.join(
1027 os.path.dirname(__file__) or os.curdir,
1028 "https_svn_python_org_root.pem")
1029
1030 if (not os.path.exists(CERTFILE) or
1031 not os.path.exists(SVN_PYTHON_ORG_ROOT_CERT)):
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001032 raise support.TestFailed("Can't read certificate files!")
Bill Janssen6e027db2007-11-15 22:23:56 +00001033
Thomas Woutersed03b412007-08-28 21:37:11 +00001034 tests = [BasicTests]
1035
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001036 if support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00001037 tests.append(NetworkedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001038
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001039 if _have_threads:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001040 thread_info = support.threading_setup()
1041 if thread_info and support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00001042 tests.append(ThreadedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001043
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001044 support.run_unittest(*tests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001045
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001046 if _have_threads:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001047 support.threading_cleanup(*thread_info)
Thomas Woutersed03b412007-08-28 21:37:11 +00001048
1049if __name__ == "__main__":
1050 test_main()