blob: 1ad6f0297fdfa295e1fe4c3b3ba9683bc43e5ad2 [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 Peterson4171da52008-08-18 21:11:09 +0000204 self.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
Bill Janssen40a0f662008-08-12 16:56:25 +0000282 elif (self.server.starttls_server and self.sslconn
283 and amsg.strip() == 'ENDTLS'):
284 if support.verbose and self.server.connectionchatty:
285 sys.stdout.write(" server: read ENDTLS from client, sending OK...\n")
286 self.write("OK\n".encode("ASCII", "strict"))
287 self.sock = self.sslconn.unwrap()
288 self.sslconn = None
289 if support.verbose and self.server.connectionchatty:
290 sys.stdout.write(" server: connection is now unencrypted...\n")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000291 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000292 if (support.verbose and
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000293 self.server.connectionchatty):
294 ctype = (self.sslconn and "encrypted") or "unencrypted"
295 sys.stdout.write(" server: read %s (%s), sending back %s (%s)...\n"
296 % (repr(msg), ctype, repr(msg.lower()), ctype))
Bill Janssen6e027db2007-11-15 22:23:56 +0000297 self.write(amsg.lower().encode('ASCII', 'strict'))
298 except socket.error:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000299 if self.server.chatty:
300 handle_error("Test server failure:\n")
301 self.close()
302 self.running = False
303 # normally, we'd just stop here, but for the test
304 # harness, we want to stop the server
305 self.server.stop()
306 except:
307 handle_error('')
308
Trent Nelson78520002008-04-10 20:54:35 +0000309 def __init__(self, certificate, ssl_version=None,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000310 certreqs=None, cacerts=None, expect_bad_connects=False,
311 chatty=True, connectionchatty=False, starttls_server=False):
312 if ssl_version is None:
313 ssl_version = ssl.PROTOCOL_TLSv1
314 if certreqs is None:
315 certreqs = ssl.CERT_NONE
316 self.certificate = certificate
317 self.protocol = ssl_version
318 self.certreqs = certreqs
319 self.cacerts = cacerts
320 self.expect_bad_connects = expect_bad_connects
321 self.chatty = chatty
322 self.connectionchatty = connectionchatty
323 self.starttls_server = starttls_server
324 self.sock = socket.socket()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000325 self.port = support.bind_port(self.sock)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000326 self.flag = None
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000327 self.active = False
328 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000329 self.daemon = True
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000330
331 def start (self, flag=None):
332 self.flag = flag
333 threading.Thread.start(self)
334
335 def run (self):
336 self.sock.settimeout(0.5)
337 self.sock.listen(5)
338 self.active = True
339 if self.flag:
340 # signal an event
341 self.flag.set()
342 while self.active:
343 try:
344 newconn, connaddr = self.sock.accept()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000345 if support.verbose and self.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000346 sys.stdout.write(' server: new connection from '
Bill Janssen6e027db2007-11-15 22:23:56 +0000347 + repr(connaddr) + '\n')
348 handler = self.ConnectionHandler(self, newconn, connaddr)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000349 handler.start()
350 except socket.timeout:
351 pass
352 except KeyboardInterrupt:
353 self.stop()
354 except:
355 if self.chatty:
356 handle_error("Test server failure:\n")
Bill Janssen6e027db2007-11-15 22:23:56 +0000357 self.sock.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000358
359 def stop (self):
360 self.active = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000361
Bill Janssen54cc54c2007-12-14 22:08:56 +0000362 class OurHTTPSServer(threading.Thread):
363
364 # This one's based on HTTPServer, which is based on SocketServer
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000365
366 class HTTPSServer(HTTPServer):
367
368 def __init__(self, server_address, RequestHandlerClass, certfile):
369
370 HTTPServer.__init__(self, server_address, RequestHandlerClass)
371 # we assume the certfile contains both private key and certificate
372 self.certfile = certfile
373 self.active = False
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000374 self.active_lock = threading.Lock()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000375 self.allow_reuse_address = True
376
Bill Janssen6e027db2007-11-15 22:23:56 +0000377 def __str__(self):
378 return ('<%s %s:%s>' %
379 (self.__class__.__name__,
380 self.server_name,
381 self.server_port))
382
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000383 def get_request (self):
384 # override this to wrap socket with SSL
385 sock, addr = self.socket.accept()
386 sslconn = ssl.wrap_socket(sock, server_side=True,
387 certfile=self.certfile)
388 return sslconn, addr
389
390 # The methods overridden below this are mainly so that we
391 # can run it in a thread and be able to stop it from another
392 # You probably wouldn't need them in other uses.
393
394 def server_activate(self):
395 # We want to run this in a thread for testing purposes,
396 # so we override this to set timeout, so that we get
397 # a chance to stop the server
398 self.socket.settimeout(0.5)
399 HTTPServer.server_activate(self)
400
401 def serve_forever(self):
402 # We want this to run in a thread, so we use a slightly
403 # modified version of "forever".
404 self.active = True
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000405 while 1:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000406 try:
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000407 # We need to lock while handling the request.
408 # Another thread can close the socket after self.active
409 # has been checked and before the request is handled.
410 # This causes an exception when using the closed socket.
411 with self.active_lock:
412 if not self.active:
413 break
414 self.handle_request()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000415 except socket.timeout:
416 pass
417 except KeyboardInterrupt:
418 self.server_close()
419 return
420 except:
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000421 sys.stdout.write(''.join(traceback.format_exception(*sys.exc_info())))
422 break
Neal Norwitzf9ff5f02008-03-31 05:39:26 +0000423 time.sleep(0.1)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000424
425 def server_close(self):
426 # Again, we want this to run in a thread, so we need to override
427 # close to clear the "active" flag, so that serve_forever() will
428 # terminate.
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000429 with self.active_lock:
430 HTTPServer.server_close(self)
431 self.active = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000432
433 class RootedHTTPRequestHandler(SimpleHTTPRequestHandler):
434
435 # need to override translate_path to get a known root,
436 # instead of using os.curdir, since the test could be
437 # run from anywhere
438
439 server_version = "TestHTTPS/1.0"
440
441 root = None
442
443 def translate_path(self, path):
444 """Translate a /-separated PATH to the local filename syntax.
445
446 Components that mean special things to the local file system
447 (e.g. drive or directory names) are ignored. (XXX They should
448 probably be diagnosed.)
449
450 """
451 # abandon query parameters
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000452 path = urllib.parse.urlparse(path)[2]
453 path = os.path.normpath(urllib.parse.unquote(path))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000454 words = path.split('/')
455 words = filter(None, words)
456 path = self.root
457 for word in words:
458 drive, word = os.path.splitdrive(word)
459 head, word = os.path.split(word)
460 if word in self.root: continue
461 path = os.path.join(path, word)
462 return path
463
464 def log_message(self, format, *args):
465
466 # we override this to suppress logging unless "verbose"
467
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000468 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000469 sys.stdout.write(" server (%s:%d %s):\n [%s] %s\n" %
470 (self.server.server_address,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000471 self.server.server_port,
472 self.request.cipher(),
473 self.log_date_time_string(),
474 format%args))
Thomas Woutersed03b412007-08-28 21:37:11 +0000475
476
Trent Nelson78520002008-04-10 20:54:35 +0000477 def __init__(self, certfile):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000478 self.flag = None
479 self.active = False
480 self.RootedHTTPRequestHandler.root = os.path.split(CERTFILE)[0]
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000481 self.port = support.find_unused_port()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000482 self.server = self.HTTPSServer(
Trent Nelson78520002008-04-10 20:54:35 +0000483 (HOST, self.port), self.RootedHTTPRequestHandler, certfile)
Thomas Woutersed03b412007-08-28 21:37:11 +0000484 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000485 self.daemon = True
Thomas Woutersed03b412007-08-28 21:37:11 +0000486
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000487 def __str__(self):
Bill Janssen6e027db2007-11-15 22:23:56 +0000488 return "<%s %s>" % (self.__class__.__name__, self.server)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000489
490 def start (self, flag=None):
491 self.flag = flag
492 threading.Thread.start(self)
493
Thomas Woutersed03b412007-08-28 21:37:11 +0000494 def run (self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000495 self.active = True
496 if self.flag:
497 self.flag.set()
498 self.server.serve_forever()
499 self.active = False
500
501 def stop (self):
502 self.active = False
503 self.server.server_close()
504
505
Bill Janssen54cc54c2007-12-14 22:08:56 +0000506 class AsyncoreEchoServer(threading.Thread):
507
508 # this one's based on asyncore.dispatcher
509
510 class EchoServer (asyncore.dispatcher):
511
512 class ConnectionHandler (asyncore.dispatcher_with_send):
513
514 def __init__(self, conn, certfile):
515 self.socket = ssl.wrap_socket(conn, server_side=True,
516 certfile=certfile,
517 do_handshake_on_connect=False)
518 asyncore.dispatcher_with_send.__init__(self, self.socket)
519 # now we have to do the handshake
520 # we'll just do it the easy way, and block the connection
521 # till it's finished. If we were doing it right, we'd
522 # do this in multiple calls to handle_read...
523 self.do_handshake(block=True)
524
525 def readable(self):
526 if isinstance(self.socket, ssl.SSLSocket):
527 while self.socket.pending() > 0:
528 self.handle_read_event()
529 return True
530
531 def handle_read(self):
532 data = self.recv(1024)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000533 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000534 sys.stdout.write(" server: read %s from client\n" % repr(data))
535 if not data:
536 self.close()
537 else:
538 self.send(str(data, 'ASCII', 'strict').lower().encode('ASCII', 'strict'))
539
540 def handle_close(self):
Bill Janssen2f5799b2008-06-29 00:08:12 +0000541 self.close()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000542 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000543 sys.stdout.write(" server: closed connection %s\n" % self.socket)
544
545 def handle_error(self):
546 raise
547
548 def __init__(self, port, certfile):
549 self.port = port
550 self.certfile = certfile
551 asyncore.dispatcher.__init__(self)
552 self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
553 self.bind(('', port))
554 self.listen(5)
555
556 def handle_accept(self):
557 sock_obj, addr = self.accept()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000558 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000559 sys.stdout.write(" server: new connection from %s:%s\n" %addr)
560 self.ConnectionHandler(sock_obj, self.certfile)
561
562 def handle_error(self):
563 raise
564
Trent Nelson78520002008-04-10 20:54:35 +0000565 def __init__(self, certfile):
Bill Janssen54cc54c2007-12-14 22:08:56 +0000566 self.flag = None
567 self.active = False
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000568 self.port = support.find_unused_port()
Trent Nelson78520002008-04-10 20:54:35 +0000569 self.server = self.EchoServer(self.port, certfile)
Bill Janssen54cc54c2007-12-14 22:08:56 +0000570 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000571 self.daemon = True
Bill Janssen54cc54c2007-12-14 22:08:56 +0000572
573 def __str__(self):
574 return "<%s %s>" % (self.__class__.__name__, self.server)
575
576 def start (self, flag=None):
577 self.flag = flag
578 threading.Thread.start(self)
579
580 def run (self):
581 self.active = True
582 if self.flag:
583 self.flag.set()
584 while self.active:
585 try:
586 asyncore.loop(1)
587 except:
588 pass
589
590 def stop (self):
591 self.active = False
592 self.server.close()
593
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000594 def badCertTest (certfile):
Trent Nelson78520002008-04-10 20:54:35 +0000595 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000596 certreqs=ssl.CERT_REQUIRED,
Bill Janssen6e027db2007-11-15 22:23:56 +0000597 cacerts=CERTFILE, chatty=False,
598 connectionchatty=False)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000599 flag = threading.Event()
600 server.start(flag)
601 # wait for it to start
602 flag.wait()
603 # try to connect
604 try:
Thomas Woutersed03b412007-08-28 21:37:11 +0000605 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000606 s = ssl.wrap_socket(socket.socket(),
607 certfile=certfile,
608 ssl_version=ssl.PROTOCOL_TLSv1)
Trent Nelson78520002008-04-10 20:54:35 +0000609 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000610 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000611 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000612 sys.stdout.write("\nSSLError is %s\n" % x)
Bill Janssenddc56692008-07-17 18:17:20 +0000613 except socket.error as x:
614 if support.verbose:
615 sys.stdout.write("\nsocket.error is %s\n" % x)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000616 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000617 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000618 "Use of invalid cert should have failed!")
619 finally:
620 server.stop()
621 server.join()
Thomas Woutersed03b412007-08-28 21:37:11 +0000622
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000623 def serverParamsTest (certfile, protocol, certreqs, cacertsfile,
Bill Janssen6e027db2007-11-15 22:23:56 +0000624 client_certfile, client_protocol=None,
625 indata="FOO\n",
626 chatty=False, connectionchatty=False):
Thomas Woutersed03b412007-08-28 21:37:11 +0000627
Trent Nelson78520002008-04-10 20:54:35 +0000628 server = ThreadedEchoServer(certfile,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000629 certreqs=certreqs,
630 ssl_version=protocol,
631 cacerts=cacertsfile,
632 chatty=chatty,
Bill Janssen6e027db2007-11-15 22:23:56 +0000633 connectionchatty=False)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000634 flag = threading.Event()
635 server.start(flag)
636 # wait for it to start
637 flag.wait()
638 # try to connect
639 if client_protocol is None:
640 client_protocol = protocol
641 try:
Bill Janssen6e027db2007-11-15 22:23:56 +0000642 s = ssl.wrap_socket(socket.socket(),
Trent Nelson6b240cd2008-04-10 20:12:06 +0000643 server_side=False,
Bill Janssen6e027db2007-11-15 22:23:56 +0000644 certfile=client_certfile,
645 ca_certs=cacertsfile,
646 cert_reqs=certreqs,
647 ssl_version=client_protocol)
Trent Nelson78520002008-04-10 20:54:35 +0000648 s.connect((HOST, server.port))
Bill Janssen6e027db2007-11-15 22:23:56 +0000649 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000650 raise support.TestFailed("Unexpected SSL error: " + str(x))
Bill Janssen6e027db2007-11-15 22:23:56 +0000651 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000652 raise support.TestFailed("Unexpected exception: " + str(x))
Bill Janssen6e027db2007-11-15 22:23:56 +0000653 else:
654 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000655 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000656 sys.stdout.write(
657 " client: sending %s...\n" % (repr(indata)))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000658 s.write(indata.encode('ASCII', 'strict'))
Bill Janssen6e027db2007-11-15 22:23:56 +0000659 outdata = s.read()
660 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000661 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000662 sys.stdout.write(" client: read %s\n" % repr(outdata))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000663 outdata = str(outdata, 'ASCII', 'strict')
Bill Janssen6e027db2007-11-15 22:23:56 +0000664 if outdata != indata.lower():
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000665 raise support.TestFailed(
Bill Janssen6e027db2007-11-15 22:23:56 +0000666 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
Trent Nelson6b240cd2008-04-10 20:12:06 +0000667 % (repr(outdata[:min(len(outdata),20)]), len(outdata),
668 repr(indata[:min(len(indata),20)].lower()), len(indata)))
669 s.write("over\n".encode("ASCII", "strict"))
Bill Janssen6e027db2007-11-15 22:23:56 +0000670 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000671 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000672 sys.stdout.write(" client: closing connection.\n")
673 s.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000674 finally:
675 server.stop()
676 server.join()
Thomas Woutersed03b412007-08-28 21:37:11 +0000677
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000678 def tryProtocolCombo (server_protocol,
679 client_protocol,
680 expectedToWork,
681 certsreqs=None):
Thomas Woutersed03b412007-08-28 21:37:11 +0000682
Benjamin Peterson2a691a82008-03-31 01:51:45 +0000683 if certsreqs is None:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000684 certsreqs = ssl.CERT_NONE
Thomas Woutersed03b412007-08-28 21:37:11 +0000685
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000686 if certsreqs == ssl.CERT_NONE:
687 certtype = "CERT_NONE"
688 elif certsreqs == ssl.CERT_OPTIONAL:
689 certtype = "CERT_OPTIONAL"
690 elif certsreqs == ssl.CERT_REQUIRED:
691 certtype = "CERT_REQUIRED"
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000692 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000693 formatstr = (expectedToWork and " %s->%s %s\n") or " {%s->%s} %s\n"
694 sys.stdout.write(formatstr %
695 (ssl.get_protocol_name(client_protocol),
696 ssl.get_protocol_name(server_protocol),
697 certtype))
698 try:
699 serverParamsTest(CERTFILE, server_protocol, certsreqs,
Bill Janssen6e027db2007-11-15 22:23:56 +0000700 CERTFILE, CERTFILE, client_protocol,
701 chatty=False, connectionchatty=False)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000702 except support.TestFailed:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000703 if expectedToWork:
704 raise
705 else:
706 if not expectedToWork:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000707 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000708 "Client protocol %s succeeded with server protocol %s!"
709 % (ssl.get_protocol_name(client_protocol),
710 ssl.get_protocol_name(server_protocol)))
711
712
Bill Janssen6e027db2007-11-15 22:23:56 +0000713 class ThreadedTests(unittest.TestCase):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000714
Trent Nelson6b240cd2008-04-10 20:12:06 +0000715 def testEcho (self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000716
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000717 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000718 sys.stdout.write("\n")
719 serverParamsTest(CERTFILE, ssl.PROTOCOL_TLSv1, ssl.CERT_NONE,
720 CERTFILE, CERTFILE, ssl.PROTOCOL_TLSv1,
721 chatty=True, connectionchatty=True)
722
723 def testReadCert(self):
724
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000725 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000726 sys.stdout.write("\n")
727 s2 = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000728 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000729 certreqs=ssl.CERT_NONE,
730 ssl_version=ssl.PROTOCOL_SSLv23,
731 cacerts=CERTFILE,
732 chatty=False)
733 flag = threading.Event()
734 server.start(flag)
735 # wait for it to start
736 flag.wait()
737 # try to connect
738 try:
739 try:
740 s = ssl.wrap_socket(socket.socket(),
741 certfile=CERTFILE,
742 ca_certs=CERTFILE,
743 cert_reqs=ssl.CERT_REQUIRED,
744 ssl_version=ssl.PROTOCOL_SSLv23)
Trent Nelson78520002008-04-10 20:54:35 +0000745 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000746 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000747 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000748 "Unexpected SSL error: " + str(x))
749 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000750 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000751 "Unexpected exception: " + str(x))
752 else:
753 if not s:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000754 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000755 "Can't SSL-handshake with test server")
756 cert = s.getpeercert()
757 if not cert:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000758 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000759 "Can't get peer certificate.")
760 cipher = s.cipher()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000761 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000762 sys.stdout.write(pprint.pformat(cert) + '\n')
763 sys.stdout.write("Connection cipher is " + str(cipher) + '.\n')
Bill Janssen6e027db2007-11-15 22:23:56 +0000764 if 'subject' not in cert:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000765 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000766 "No subject field in certificate: %s." %
767 pprint.pformat(cert))
768 if ((('organizationName', 'Python Software Foundation'),)
769 not in cert['subject']):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000770 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000771 "Missing or invalid 'organizationName' field in certificate subject; "
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000772 "should be 'Python Software Foundation'.")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000773 s.close()
774 finally:
775 server.stop()
776 server.join()
777
778 def testNULLcert(self):
779 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
780 "nullcert.pem"))
781 def testMalformedCert(self):
782 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
783 "badcert.pem"))
784 def testMalformedKey(self):
785 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
786 "badkey.pem"))
787
Trent Nelson6b240cd2008-04-10 20:12:06 +0000788 def testRudeShutdown(self):
789
790 listener_ready = threading.Event()
791 listener_gone = threading.Event()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000792 port = support.find_unused_port()
Trent Nelson6b240cd2008-04-10 20:12:06 +0000793
794 # `listener` runs in a thread. It opens a socket listening on
795 # PORT, and sits in an accept() until the main thread connects.
796 # Then it rudely closes the socket, and sets Event `listener_gone`
797 # to let the main thread know the socket is gone.
798 def listener():
799 s = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000800 s.bind((HOST, port))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000801 s.listen(5)
802 listener_ready.set()
803 s.accept()
804 s = None # reclaim the socket object, which also closes it
805 listener_gone.set()
806
807 def connector():
808 listener_ready.wait()
809 s = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000810 s.connect((HOST, port))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000811 listener_gone.wait()
812 try:
813 ssl_sock = ssl.wrap_socket(s)
814 except IOError:
815 pass
816 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000817 raise support.TestFailed(
Trent Nelson6b240cd2008-04-10 20:12:06 +0000818 'connecting to closed SSL socket should have failed')
819
820 t = threading.Thread(target=listener)
821 t.start()
822 connector()
823 t.join()
824
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000825 def testProtocolSSL2(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000826 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000827 sys.stdout.write("\n")
828 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True)
829 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL)
830 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED)
831 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True)
832 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False)
833 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False)
834
835 def testProtocolSSL23(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000836 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000837 sys.stdout.write("\n")
838 try:
839 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv2, True)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000840 except support.TestFailed as x:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000841 # this fails on some older versions of OpenSSL (0.9.7l, for instance)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000842 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000843 sys.stdout.write(
844 " SSL2 client to SSL23 server test unexpectedly failed:\n %s\n"
845 % str(x))
846 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True)
847 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True)
848 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True)
849
850 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
851 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_OPTIONAL)
852 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
853
854 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
855 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_REQUIRED)
856 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
857
858 def testProtocolSSL3(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000859 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000860 sys.stdout.write("\n")
861 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True)
862 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
863 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
864 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False)
865 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, False)
866 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False)
867
868 def testProtocolTLS1(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000869 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000870 sys.stdout.write("\n")
871 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True)
872 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
873 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
874 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False)
875 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False)
876 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv23, False)
877
878 def testSTARTTLS (self):
879
Bill Janssen40a0f662008-08-12 16:56:25 +0000880 msgs = ("msg 1", "MSG 2", "STARTTLS", "MSG 3", "msg 4", "ENDTLS", "msg 5", "msg 6")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000881
Trent Nelson78520002008-04-10 20:54:35 +0000882 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000883 ssl_version=ssl.PROTOCOL_TLSv1,
884 starttls_server=True,
885 chatty=True,
886 connectionchatty=True)
887 flag = threading.Event()
888 server.start(flag)
889 # wait for it to start
890 flag.wait()
891 # try to connect
892 wrapped = False
893 try:
894 try:
895 s = socket.socket()
896 s.setblocking(1)
Trent Nelson78520002008-04-10 20:54:35 +0000897 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000898 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000899 raise support.TestFailed("Unexpected exception: " + str(x))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000900 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000901 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000902 sys.stdout.write("\n")
903 for indata in msgs:
Bill Janssen6e027db2007-11-15 22:23:56 +0000904 msg = indata.encode('ASCII', 'replace')
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000905 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000906 sys.stdout.write(
Bill Janssen6e027db2007-11-15 22:23:56 +0000907 " client: sending %s...\n" % repr(msg))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000908 if wrapped:
Bill Janssen6e027db2007-11-15 22:23:56 +0000909 conn.write(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000910 outdata = conn.read()
911 else:
Bill Janssen6e027db2007-11-15 22:23:56 +0000912 s.send(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000913 outdata = s.recv(1024)
914 if (indata == "STARTTLS" and
Bill Janssen6e027db2007-11-15 22:23:56 +0000915 str(outdata, 'ASCII', 'replace').strip().lower().startswith("ok")):
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(
919 " client: read %s from server, starting TLS...\n"
Bill Janssen6e027db2007-11-15 22:23:56 +0000920 % repr(msg))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000921 conn = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000922 wrapped = True
Bill Janssen40a0f662008-08-12 16:56:25 +0000923 elif (indata == "ENDTLS" and
924 str(outdata, 'ASCII', 'replace').strip().lower().startswith("ok")):
925 if support.verbose:
926 msg = str(outdata, 'ASCII', 'replace')
927 sys.stdout.write(
928 " client: read %s from server, ending TLS...\n"
929 % repr(msg))
930 s = conn.unwrap()
931 wrapped = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000932 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000933 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000934 msg = str(outdata, 'ASCII', 'replace')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000935 sys.stdout.write(
Bill Janssen6e027db2007-11-15 22:23:56 +0000936 " client: read %s from server\n" % repr(msg))
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000937 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000938 sys.stdout.write(" client: closing connection.\n")
939 if wrapped:
Bill Janssen6e027db2007-11-15 22:23:56 +0000940 conn.write("over\n".encode("ASCII", "strict"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000941 else:
Bill Janssen40a0f662008-08-12 16:56:25 +0000942 s.send("over\n".encode("ASCII", "strict"))
Bill Janssen6e027db2007-11-15 22:23:56 +0000943 if wrapped:
944 conn.close()
945 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000946 s.close()
947 finally:
948 server.stop()
949 server.join()
950
Bill Janssen54cc54c2007-12-14 22:08:56 +0000951 def testSocketServer(self):
Bill Janssen6e027db2007-11-15 22:23:56 +0000952
Trent Nelson78520002008-04-10 20:54:35 +0000953 server = OurHTTPSServer(CERTFILE)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000954 flag = threading.Event()
955 server.start(flag)
956 # wait for it to start
957 flag.wait()
958 # try to connect
959 try:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000960 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000961 sys.stdout.write('\n')
962 d1 = open(CERTFILE, 'rb').read()
963 d2 = ''
964 # now fetch the same data from the HTTPS server
Trent Nelson78520002008-04-10 20:54:35 +0000965 url = 'https://%s:%d/%s' % (
966 HOST, server.port, os.path.split(CERTFILE)[1])
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000967 f = urllib.request.urlopen(url)
Barry Warsaw820c1202008-06-12 04:06:45 +0000968 dlen = f.info().get("content-length")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000969 if dlen and (int(dlen) > 0):
970 d2 = f.read(int(dlen))
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000971 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000972 sys.stdout.write(
973 " client: read %d bytes from remote server '%s'\n"
974 % (len(d2), server))
975 f.close()
976 except:
977 msg = ''.join(traceback.format_exception(*sys.exc_info()))
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000978 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000979 sys.stdout.write('\n' + msg)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000980 raise support.TestFailed(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000981 else:
982 if not (d1 == d2):
Bill Janssen6e027db2007-11-15 22:23:56 +0000983 print("d1 is", len(d1), repr(d1))
984 print("d2 is", len(d2), repr(d2))
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000985 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000986 "Couldn't fetch data from HTTPS server")
987 finally:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000988 if support.verbose:
Neal Norwitzf9ff5f02008-03-31 05:39:26 +0000989 sys.stdout.write('stopping server\n')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000990 server.stop()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000991 if support.verbose:
Neal Norwitzf9ff5f02008-03-31 05:39:26 +0000992 sys.stdout.write('joining thread\n')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000993 server.join()
994
Trent Nelson6b240cd2008-04-10 20:12:06 +0000995 def testAsyncoreServer(self):
996
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000997 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +0000998 sys.stdout.write("\n")
999
1000 indata="FOO\n"
Trent Nelson78520002008-04-10 20:54:35 +00001001 server = AsyncoreEchoServer(CERTFILE)
Trent Nelson6b240cd2008-04-10 20:12:06 +00001002 flag = threading.Event()
1003 server.start(flag)
1004 # wait for it to start
1005 flag.wait()
1006 # try to connect
1007 try:
1008 s = ssl.wrap_socket(socket.socket())
Trent Nelson78520002008-04-10 20:54:35 +00001009 s.connect((HOST, server.port))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001010 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001011 raise support.TestFailed("Unexpected SSL error: " + str(x))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001012 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001013 raise support.TestFailed("Unexpected exception: " + str(x))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001014 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001015 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001016 sys.stdout.write(
1017 " client: sending %s...\n" % (repr(indata)))
1018 s.sendall(indata.encode('ASCII', 'strict'))
1019 outdata = s.recv()
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001020 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001021 sys.stdout.write(" client: read %s\n" % repr(outdata))
1022 outdata = str(outdata, 'ASCII', 'strict')
1023 if outdata != indata.lower():
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001024 raise support.TestFailed(
Trent Nelson6b240cd2008-04-10 20:12:06 +00001025 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
1026 % (repr(outdata[:min(len(outdata),20)]), len(outdata),
1027 repr(indata[:min(len(indata),20)].lower()), len(indata)))
1028 s.write("over\n".encode("ASCII", "strict"))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001029 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001030 sys.stdout.write(" client: closing connection.\n")
1031 s.close()
1032 finally:
1033 server.stop()
1034 server.join()
1035
Thomas Woutersed03b412007-08-28 21:37:11 +00001036def test_main(verbose=False):
1037 if skip_expected:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001038 raise support.TestSkipped("No SSL support")
Thomas Woutersed03b412007-08-28 21:37:11 +00001039
Trent Nelson78520002008-04-10 20:54:35 +00001040 global CERTFILE, SVN_PYTHON_ORG_ROOT_CERT
Thomas Woutersed03b412007-08-28 21:37:11 +00001041 CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir,
1042 "keycert.pem")
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001043 SVN_PYTHON_ORG_ROOT_CERT = os.path.join(
1044 os.path.dirname(__file__) or os.curdir,
1045 "https_svn_python_org_root.pem")
1046
1047 if (not os.path.exists(CERTFILE) or
1048 not os.path.exists(SVN_PYTHON_ORG_ROOT_CERT)):
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001049 raise support.TestFailed("Can't read certificate files!")
Bill Janssen6e027db2007-11-15 22:23:56 +00001050
Thomas Woutersed03b412007-08-28 21:37:11 +00001051 tests = [BasicTests]
1052
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001053 if support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00001054 tests.append(NetworkedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001055
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001056 if _have_threads:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001057 thread_info = support.threading_setup()
1058 if thread_info and support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00001059 tests.append(ThreadedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001060
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001061 support.run_unittest(*tests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001062
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001063 if _have_threads:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001064 support.threading_cleanup(*thread_info)
Thomas Woutersed03b412007-08-28 21:37:11 +00001065
1066if __name__ == "__main__":
1067 test_main()