blob: 33419fe5416b2b30d42d1ecb430d66a89d8eb74b [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
Thomas Wouters1b7f8912007-09-19 03:06:30 +000013import urllib, urlparse
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
443 path = urlparse.urlparse(path)[2]
444 path = os.path.normpath(urllib.unquote(path))
445 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):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000532 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000533 sys.stdout.write(" server: closed connection %s\n" % self.socket)
534
535 def handle_error(self):
536 raise
537
538 def __init__(self, port, certfile):
539 self.port = port
540 self.certfile = certfile
541 asyncore.dispatcher.__init__(self)
542 self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
543 self.bind(('', port))
544 self.listen(5)
545
546 def handle_accept(self):
547 sock_obj, addr = self.accept()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000548 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000549 sys.stdout.write(" server: new connection from %s:%s\n" %addr)
550 self.ConnectionHandler(sock_obj, self.certfile)
551
552 def handle_error(self):
553 raise
554
Trent Nelson78520002008-04-10 20:54:35 +0000555 def __init__(self, certfile):
Bill Janssen54cc54c2007-12-14 22:08:56 +0000556 self.flag = None
557 self.active = False
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000558 self.port = support.find_unused_port()
Trent Nelson78520002008-04-10 20:54:35 +0000559 self.server = self.EchoServer(self.port, certfile)
Bill Janssen54cc54c2007-12-14 22:08:56 +0000560 threading.Thread.__init__(self)
Benjamin Peterson502d89e2008-06-11 22:55:41 +0000561 self.set_daemon(True)
Bill Janssen54cc54c2007-12-14 22:08:56 +0000562
563 def __str__(self):
564 return "<%s %s>" % (self.__class__.__name__, self.server)
565
566 def start (self, flag=None):
567 self.flag = flag
568 threading.Thread.start(self)
569
570 def run (self):
571 self.active = True
572 if self.flag:
573 self.flag.set()
574 while self.active:
575 try:
576 asyncore.loop(1)
577 except:
578 pass
579
580 def stop (self):
581 self.active = False
582 self.server.close()
583
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000584 def badCertTest (certfile):
Trent Nelson78520002008-04-10 20:54:35 +0000585 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000586 certreqs=ssl.CERT_REQUIRED,
Bill Janssen6e027db2007-11-15 22:23:56 +0000587 cacerts=CERTFILE, chatty=False,
588 connectionchatty=False)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000589 flag = threading.Event()
590 server.start(flag)
591 # wait for it to start
592 flag.wait()
593 # try to connect
594 try:
Thomas Woutersed03b412007-08-28 21:37:11 +0000595 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000596 s = ssl.wrap_socket(socket.socket(),
597 certfile=certfile,
598 ssl_version=ssl.PROTOCOL_TLSv1)
Trent Nelson78520002008-04-10 20:54:35 +0000599 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000600 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000601 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000602 sys.stdout.write("\nSSLError is %s\n" % x)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000603 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000604 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000605 "Use of invalid cert should have failed!")
606 finally:
607 server.stop()
608 server.join()
Thomas Woutersed03b412007-08-28 21:37:11 +0000609
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000610 def serverParamsTest (certfile, protocol, certreqs, cacertsfile,
Bill Janssen6e027db2007-11-15 22:23:56 +0000611 client_certfile, client_protocol=None,
612 indata="FOO\n",
613 chatty=False, connectionchatty=False):
Thomas Woutersed03b412007-08-28 21:37:11 +0000614
Trent Nelson78520002008-04-10 20:54:35 +0000615 server = ThreadedEchoServer(certfile,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000616 certreqs=certreqs,
617 ssl_version=protocol,
618 cacerts=cacertsfile,
619 chatty=chatty,
Bill Janssen6e027db2007-11-15 22:23:56 +0000620 connectionchatty=False)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000621 flag = threading.Event()
622 server.start(flag)
623 # wait for it to start
624 flag.wait()
625 # try to connect
626 if client_protocol is None:
627 client_protocol = protocol
628 try:
Bill Janssen6e027db2007-11-15 22:23:56 +0000629 s = ssl.wrap_socket(socket.socket(),
Trent Nelson6b240cd2008-04-10 20:12:06 +0000630 server_side=False,
Bill Janssen6e027db2007-11-15 22:23:56 +0000631 certfile=client_certfile,
632 ca_certs=cacertsfile,
633 cert_reqs=certreqs,
634 ssl_version=client_protocol)
Trent Nelson78520002008-04-10 20:54:35 +0000635 s.connect((HOST, server.port))
Bill Janssen6e027db2007-11-15 22:23:56 +0000636 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000637 raise support.TestFailed("Unexpected SSL error: " + str(x))
Bill Janssen6e027db2007-11-15 22:23:56 +0000638 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000639 raise support.TestFailed("Unexpected exception: " + str(x))
Bill Janssen6e027db2007-11-15 22:23:56 +0000640 else:
641 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000642 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000643 sys.stdout.write(
644 " client: sending %s...\n" % (repr(indata)))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000645 s.write(indata.encode('ASCII', 'strict'))
Bill Janssen6e027db2007-11-15 22:23:56 +0000646 outdata = s.read()
647 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000648 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000649 sys.stdout.write(" client: read %s\n" % repr(outdata))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000650 outdata = str(outdata, 'ASCII', 'strict')
Bill Janssen6e027db2007-11-15 22:23:56 +0000651 if outdata != indata.lower():
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000652 raise support.TestFailed(
Bill Janssen6e027db2007-11-15 22:23:56 +0000653 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
Trent Nelson6b240cd2008-04-10 20:12:06 +0000654 % (repr(outdata[:min(len(outdata),20)]), len(outdata),
655 repr(indata[:min(len(indata),20)].lower()), len(indata)))
656 s.write("over\n".encode("ASCII", "strict"))
Bill Janssen6e027db2007-11-15 22:23:56 +0000657 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000658 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000659 sys.stdout.write(" client: closing connection.\n")
660 s.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000661 finally:
662 server.stop()
663 server.join()
Thomas Woutersed03b412007-08-28 21:37:11 +0000664
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000665 def tryProtocolCombo (server_protocol,
666 client_protocol,
667 expectedToWork,
668 certsreqs=None):
Thomas Woutersed03b412007-08-28 21:37:11 +0000669
Benjamin Peterson2a691a82008-03-31 01:51:45 +0000670 if certsreqs is None:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000671 certsreqs = ssl.CERT_NONE
Thomas Woutersed03b412007-08-28 21:37:11 +0000672
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000673 if certsreqs == ssl.CERT_NONE:
674 certtype = "CERT_NONE"
675 elif certsreqs == ssl.CERT_OPTIONAL:
676 certtype = "CERT_OPTIONAL"
677 elif certsreqs == ssl.CERT_REQUIRED:
678 certtype = "CERT_REQUIRED"
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000679 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000680 formatstr = (expectedToWork and " %s->%s %s\n") or " {%s->%s} %s\n"
681 sys.stdout.write(formatstr %
682 (ssl.get_protocol_name(client_protocol),
683 ssl.get_protocol_name(server_protocol),
684 certtype))
685 try:
686 serverParamsTest(CERTFILE, server_protocol, certsreqs,
Bill Janssen6e027db2007-11-15 22:23:56 +0000687 CERTFILE, CERTFILE, client_protocol,
688 chatty=False, connectionchatty=False)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000689 except support.TestFailed:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000690 if expectedToWork:
691 raise
692 else:
693 if not expectedToWork:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000694 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000695 "Client protocol %s succeeded with server protocol %s!"
696 % (ssl.get_protocol_name(client_protocol),
697 ssl.get_protocol_name(server_protocol)))
698
699
Bill Janssen6e027db2007-11-15 22:23:56 +0000700 class ThreadedTests(unittest.TestCase):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000701
Trent Nelson6b240cd2008-04-10 20:12:06 +0000702 def testEcho (self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000703
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000704 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000705 sys.stdout.write("\n")
706 serverParamsTest(CERTFILE, ssl.PROTOCOL_TLSv1, ssl.CERT_NONE,
707 CERTFILE, CERTFILE, ssl.PROTOCOL_TLSv1,
708 chatty=True, connectionchatty=True)
709
710 def testReadCert(self):
711
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000712 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000713 sys.stdout.write("\n")
714 s2 = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000715 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000716 certreqs=ssl.CERT_NONE,
717 ssl_version=ssl.PROTOCOL_SSLv23,
718 cacerts=CERTFILE,
719 chatty=False)
720 flag = threading.Event()
721 server.start(flag)
722 # wait for it to start
723 flag.wait()
724 # try to connect
725 try:
726 try:
727 s = ssl.wrap_socket(socket.socket(),
728 certfile=CERTFILE,
729 ca_certs=CERTFILE,
730 cert_reqs=ssl.CERT_REQUIRED,
731 ssl_version=ssl.PROTOCOL_SSLv23)
Trent Nelson78520002008-04-10 20:54:35 +0000732 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000733 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000734 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000735 "Unexpected SSL error: " + str(x))
736 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000737 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000738 "Unexpected exception: " + str(x))
739 else:
740 if not s:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000741 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000742 "Can't SSL-handshake with test server")
743 cert = s.getpeercert()
744 if not cert:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000745 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000746 "Can't get peer certificate.")
747 cipher = s.cipher()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000748 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000749 sys.stdout.write(pprint.pformat(cert) + '\n')
750 sys.stdout.write("Connection cipher is " + str(cipher) + '.\n')
Bill Janssen6e027db2007-11-15 22:23:56 +0000751 if 'subject' not in cert:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000752 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000753 "No subject field in certificate: %s." %
754 pprint.pformat(cert))
755 if ((('organizationName', 'Python Software Foundation'),)
756 not in cert['subject']):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000757 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000758 "Missing or invalid 'organizationName' field in certificate subject; "
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000759 "should be 'Python Software Foundation'.")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000760 s.close()
761 finally:
762 server.stop()
763 server.join()
764
765 def testNULLcert(self):
766 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
767 "nullcert.pem"))
768 def testMalformedCert(self):
769 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
770 "badcert.pem"))
771 def testMalformedKey(self):
772 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
773 "badkey.pem"))
774
Trent Nelson6b240cd2008-04-10 20:12:06 +0000775 def testRudeShutdown(self):
776
777 listener_ready = threading.Event()
778 listener_gone = threading.Event()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000779 port = support.find_unused_port()
Trent Nelson6b240cd2008-04-10 20:12:06 +0000780
781 # `listener` runs in a thread. It opens a socket listening on
782 # PORT, and sits in an accept() until the main thread connects.
783 # Then it rudely closes the socket, and sets Event `listener_gone`
784 # to let the main thread know the socket is gone.
785 def listener():
786 s = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000787 s.bind((HOST, port))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000788 s.listen(5)
789 listener_ready.set()
790 s.accept()
791 s = None # reclaim the socket object, which also closes it
792 listener_gone.set()
793
794 def connector():
795 listener_ready.wait()
796 s = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000797 s.connect((HOST, port))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000798 listener_gone.wait()
799 try:
800 ssl_sock = ssl.wrap_socket(s)
801 except IOError:
802 pass
803 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000804 raise support.TestFailed(
Trent Nelson6b240cd2008-04-10 20:12:06 +0000805 'connecting to closed SSL socket should have failed')
806
807 t = threading.Thread(target=listener)
808 t.start()
809 connector()
810 t.join()
811
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000812 def testProtocolSSL2(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000813 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000814 sys.stdout.write("\n")
815 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True)
816 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL)
817 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED)
818 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True)
819 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False)
820 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False)
821
822 def testProtocolSSL23(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000823 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000824 sys.stdout.write("\n")
825 try:
826 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv2, True)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000827 except support.TestFailed as x:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000828 # this fails on some older versions of OpenSSL (0.9.7l, for instance)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000829 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000830 sys.stdout.write(
831 " SSL2 client to SSL23 server test unexpectedly failed:\n %s\n"
832 % str(x))
833 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True)
834 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True)
835 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True)
836
837 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
838 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_OPTIONAL)
839 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
840
841 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
842 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_REQUIRED)
843 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
844
845 def testProtocolSSL3(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000846 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000847 sys.stdout.write("\n")
848 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True)
849 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
850 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
851 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False)
852 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, False)
853 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False)
854
855 def testProtocolTLS1(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000856 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000857 sys.stdout.write("\n")
858 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True)
859 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
860 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
861 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False)
862 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False)
863 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv23, False)
864
865 def testSTARTTLS (self):
866
867 msgs = ("msg 1", "MSG 2", "STARTTLS", "MSG 3", "msg 4")
868
Trent Nelson78520002008-04-10 20:54:35 +0000869 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000870 ssl_version=ssl.PROTOCOL_TLSv1,
871 starttls_server=True,
872 chatty=True,
873 connectionchatty=True)
874 flag = threading.Event()
875 server.start(flag)
876 # wait for it to start
877 flag.wait()
878 # try to connect
879 wrapped = False
880 try:
881 try:
882 s = socket.socket()
883 s.setblocking(1)
Trent Nelson78520002008-04-10 20:54:35 +0000884 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000885 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000886 raise support.TestFailed("Unexpected exception: " + str(x))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000887 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000888 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000889 sys.stdout.write("\n")
890 for indata in msgs:
Bill Janssen6e027db2007-11-15 22:23:56 +0000891 msg = indata.encode('ASCII', 'replace')
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000892 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000893 sys.stdout.write(
Bill Janssen6e027db2007-11-15 22:23:56 +0000894 " client: sending %s...\n" % repr(msg))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000895 if wrapped:
Bill Janssen6e027db2007-11-15 22:23:56 +0000896 conn.write(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000897 outdata = conn.read()
898 else:
Bill Janssen6e027db2007-11-15 22:23:56 +0000899 s.send(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000900 outdata = s.recv(1024)
901 if (indata == "STARTTLS" and
Bill Janssen6e027db2007-11-15 22:23:56 +0000902 str(outdata, 'ASCII', 'replace').strip().lower().startswith("ok")):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000903 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000904 msg = str(outdata, 'ASCII', 'replace')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000905 sys.stdout.write(
906 " client: read %s from server, starting TLS...\n"
Bill Janssen6e027db2007-11-15 22:23:56 +0000907 % repr(msg))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000908 conn = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1)
909
910 wrapped = True
911 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000912 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000913 msg = str(outdata, 'ASCII', 'replace')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000914 sys.stdout.write(
Bill Janssen6e027db2007-11-15 22:23:56 +0000915 " client: read %s from server\n" % repr(msg))
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000916 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000917 sys.stdout.write(" client: closing connection.\n")
918 if wrapped:
Bill Janssen6e027db2007-11-15 22:23:56 +0000919 conn.write("over\n".encode("ASCII", "strict"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000920 else:
921 s.send("over\n")
Bill Janssen6e027db2007-11-15 22:23:56 +0000922 if wrapped:
923 conn.close()
924 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000925 s.close()
926 finally:
927 server.stop()
928 server.join()
929
Bill Janssen54cc54c2007-12-14 22:08:56 +0000930 def testSocketServer(self):
Bill Janssen6e027db2007-11-15 22:23:56 +0000931
Trent Nelson78520002008-04-10 20:54:35 +0000932 server = OurHTTPSServer(CERTFILE)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000933 flag = threading.Event()
934 server.start(flag)
935 # wait for it to start
936 flag.wait()
937 # try to connect
938 try:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000939 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000940 sys.stdout.write('\n')
941 d1 = open(CERTFILE, 'rb').read()
942 d2 = ''
943 # now fetch the same data from the HTTPS server
Trent Nelson78520002008-04-10 20:54:35 +0000944 url = 'https://%s:%d/%s' % (
945 HOST, server.port, os.path.split(CERTFILE)[1])
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000946 f = urllib.urlopen(url)
947 dlen = f.info().getheader("content-length")
948 if dlen and (int(dlen) > 0):
949 d2 = f.read(int(dlen))
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000950 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000951 sys.stdout.write(
952 " client: read %d bytes from remote server '%s'\n"
953 % (len(d2), server))
954 f.close()
955 except:
956 msg = ''.join(traceback.format_exception(*sys.exc_info()))
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000957 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000958 sys.stdout.write('\n' + msg)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000959 raise support.TestFailed(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000960 else:
961 if not (d1 == d2):
Bill Janssen6e027db2007-11-15 22:23:56 +0000962 print("d1 is", len(d1), repr(d1))
963 print("d2 is", len(d2), repr(d2))
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000964 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000965 "Couldn't fetch data from HTTPS server")
966 finally:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000967 if support.verbose:
Neal Norwitzf9ff5f02008-03-31 05:39:26 +0000968 sys.stdout.write('stopping server\n')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000969 server.stop()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000970 if support.verbose:
Neal Norwitzf9ff5f02008-03-31 05:39:26 +0000971 sys.stdout.write('joining thread\n')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000972 server.join()
973
Trent Nelson6b240cd2008-04-10 20:12:06 +0000974 def testAsyncoreServer(self):
975
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000976 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +0000977 sys.stdout.write("\n")
978
979 indata="FOO\n"
Trent Nelson78520002008-04-10 20:54:35 +0000980 server = AsyncoreEchoServer(CERTFILE)
Trent Nelson6b240cd2008-04-10 20:12:06 +0000981 flag = threading.Event()
982 server.start(flag)
983 # wait for it to start
984 flag.wait()
985 # try to connect
986 try:
987 s = ssl.wrap_socket(socket.socket())
Trent Nelson78520002008-04-10 20:54:35 +0000988 s.connect((HOST, server.port))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000989 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000990 raise support.TestFailed("Unexpected SSL error: " + str(x))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000991 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000992 raise support.TestFailed("Unexpected exception: " + str(x))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000993 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000994 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +0000995 sys.stdout.write(
996 " client: sending %s...\n" % (repr(indata)))
997 s.sendall(indata.encode('ASCII', 'strict'))
998 outdata = s.recv()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000999 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001000 sys.stdout.write(" client: read %s\n" % repr(outdata))
1001 outdata = str(outdata, 'ASCII', 'strict')
1002 if outdata != indata.lower():
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001003 raise support.TestFailed(
Trent Nelson6b240cd2008-04-10 20:12:06 +00001004 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
1005 % (repr(outdata[:min(len(outdata),20)]), len(outdata),
1006 repr(indata[:min(len(indata),20)].lower()), len(indata)))
1007 s.write("over\n".encode("ASCII", "strict"))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001008 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001009 sys.stdout.write(" client: closing connection.\n")
1010 s.close()
1011 finally:
1012 server.stop()
1013 server.join()
1014
Thomas Woutersed03b412007-08-28 21:37:11 +00001015def test_main(verbose=False):
1016 if skip_expected:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001017 raise support.TestSkipped("No SSL support")
Thomas Woutersed03b412007-08-28 21:37:11 +00001018
Trent Nelson78520002008-04-10 20:54:35 +00001019 global CERTFILE, SVN_PYTHON_ORG_ROOT_CERT
Thomas Woutersed03b412007-08-28 21:37:11 +00001020 CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir,
1021 "keycert.pem")
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001022 SVN_PYTHON_ORG_ROOT_CERT = os.path.join(
1023 os.path.dirname(__file__) or os.curdir,
1024 "https_svn_python_org_root.pem")
1025
1026 if (not os.path.exists(CERTFILE) or
1027 not os.path.exists(SVN_PYTHON_ORG_ROOT_CERT)):
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001028 raise support.TestFailed("Can't read certificate files!")
Bill Janssen6e027db2007-11-15 22:23:56 +00001029
Thomas Woutersed03b412007-08-28 21:37:11 +00001030 tests = [BasicTests]
1031
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001032 if support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00001033 tests.append(NetworkedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001034
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001035 if _have_threads:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001036 thread_info = support.threading_setup()
1037 if thread_info and support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00001038 tests.append(ThreadedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001039
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001040 support.run_unittest(*tests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001041
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001042 if _have_threads:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001043 support.threading_cleanup(*thread_info)
Thomas Woutersed03b412007-08-28 21:37:11 +00001044
1045if __name__ == "__main__":
1046 test_main()