blob: 8d6d742be4c4c01c9689bfb972d78abe22efa250 [file] [log] [blame]
Thomas Woutersed03b412007-08-28 21:37:11 +00001# Test the support for SSL and sockets
2
3import sys
4import unittest
Benjamin Petersonee8712c2008-05-20 21:35:26 +00005from test import support
Thomas Woutersed03b412007-08-28 21:37:11 +00006import socket
Bill Janssen6e027db2007-11-15 22:23:56 +00007import select
Thomas Woutersed03b412007-08-28 21:37:11 +00008import time
9import os
10import pprint
Jeremy Hylton1afc1692008-06-18 20:49:58 +000011import urllib.parse, urllib.request
Thomas Woutersed03b412007-08-28 21:37:11 +000012import traceback
Bill Janssen54cc54c2007-12-14 22:08:56 +000013import asyncore
Thomas Woutersed03b412007-08-28 21:37:11 +000014
Georg Brandl24420152008-05-26 16:32:26 +000015from http.server import HTTPServer, SimpleHTTPRequestHandler
Thomas Wouters1b7f8912007-09-19 03:06:30 +000016
Thomas Woutersed03b412007-08-28 21:37:11 +000017# Optionally test SSL support, if we have it in the tested platform
18skip_expected = False
19try:
20 import ssl
21except ImportError:
22 skip_expected = True
23
Benjamin Petersonee8712c2008-05-20 21:35:26 +000024HOST = support.HOST
Thomas Woutersed03b412007-08-28 21:37:11 +000025CERTFILE = None
Thomas Wouters1b7f8912007-09-19 03:06:30 +000026SVN_PYTHON_ORG_ROOT_CERT = None
Thomas Woutersed03b412007-08-28 21:37:11 +000027
Thomas Woutersed03b412007-08-28 21:37:11 +000028def handle_error(prefix):
29 exc_format = ' '.join(traceback.format_exception(*sys.exc_info()))
Benjamin Petersonee8712c2008-05-20 21:35:26 +000030 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000031 sys.stdout.write(prefix + exc_format)
Thomas Woutersed03b412007-08-28 21:37:11 +000032
33
34class BasicTests(unittest.TestCase):
35
Georg Brandlfceab5a2008-01-19 20:08:23 +000036 def testSSLconnect(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +000037 if not support.is_resource_enabled('network'):
Georg Brandlfceab5a2008-01-19 20:08:23 +000038 return
39 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
40 cert_reqs=ssl.CERT_NONE)
41 s.connect(("svn.python.org", 443))
42 c = s.getpeercert()
43 if c:
Benjamin Petersonee8712c2008-05-20 21:35:26 +000044 raise support.TestFailed("Peer cert %s shouldn't be here!")
Georg Brandlfceab5a2008-01-19 20:08:23 +000045 s.close()
46
47 # this should fail because we have no verification certs
48 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
49 cert_reqs=ssl.CERT_REQUIRED)
50 try:
51 s.connect(("svn.python.org", 443))
52 except ssl.SSLError:
53 pass
54 finally:
55 s.close()
56
Thomas Wouters1b7f8912007-09-19 03:06:30 +000057 def testCrucialConstants(self):
58 ssl.PROTOCOL_SSLv2
59 ssl.PROTOCOL_SSLv23
60 ssl.PROTOCOL_SSLv3
61 ssl.PROTOCOL_TLSv1
62 ssl.CERT_NONE
63 ssl.CERT_OPTIONAL
64 ssl.CERT_REQUIRED
Thomas Woutersed03b412007-08-28 21:37:11 +000065
Thomas Wouters1b7f8912007-09-19 03:06:30 +000066 def testRAND(self):
67 v = ssl.RAND_status()
Benjamin Petersonee8712c2008-05-20 21:35:26 +000068 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000069 sys.stdout.write("\n RAND_status is %d (%s)\n"
70 % (v, (v and "sufficient randomness") or
71 "insufficient randomness"))
Thomas Woutersed03b412007-08-28 21:37:11 +000072 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000073 ssl.RAND_egd(1)
74 except TypeError:
75 pass
Thomas Woutersed03b412007-08-28 21:37:11 +000076 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000077 print("didn't raise TypeError")
78 ssl.RAND_add("this is a random string", 75.0)
Thomas Woutersed03b412007-08-28 21:37:11 +000079
Thomas Wouters1b7f8912007-09-19 03:06:30 +000080 def testParseCert(self):
81 # note that this uses an 'unofficial' function in _ssl.c,
82 # provided solely for this test, to exercise the certificate
83 # parsing code
84 p = ssl._ssl._test_decode_cert(CERTFILE, False)
Benjamin Petersonee8712c2008-05-20 21:35:26 +000085 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000086 sys.stdout.write("\n" + pprint.pformat(p) + "\n")
Thomas Woutersed03b412007-08-28 21:37:11 +000087
Thomas Wouters1b7f8912007-09-19 03:06:30 +000088 def testDERtoPEM(self):
89
90 pem = open(SVN_PYTHON_ORG_ROOT_CERT, 'r').read()
91 d1 = ssl.PEM_cert_to_DER_cert(pem)
92 p2 = ssl.DER_cert_to_PEM_cert(d1)
93 d2 = ssl.PEM_cert_to_DER_cert(p2)
94 if (d1 != d2):
Benjamin Petersonee8712c2008-05-20 21:35:26 +000095 raise support.TestFailed("PEM-to-DER or DER-to-PEM translation failed")
Thomas Wouters1b7f8912007-09-19 03:06:30 +000096
Bill Janssen6e027db2007-11-15 22:23:56 +000097class NetworkedTests(unittest.TestCase):
Thomas Wouters1b7f8912007-09-19 03:06:30 +000098
Thomas Wouters1b7f8912007-09-19 03:06:30 +000099 def testConnect(self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000100 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
101 cert_reqs=ssl.CERT_NONE)
102 s.connect(("svn.python.org", 443))
103 c = s.getpeercert()
104 if c:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000105 raise support.TestFailed("Peer cert %s shouldn't be here!")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000106 s.close()
107
108 # this should fail because we have no verification certs
109 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
110 cert_reqs=ssl.CERT_REQUIRED)
Thomas Woutersed03b412007-08-28 21:37:11 +0000111 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000112 s.connect(("svn.python.org", 443))
113 except ssl.SSLError:
114 pass
115 finally:
116 s.close()
117
118 # this should succeed because we specify the root cert
119 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
120 cert_reqs=ssl.CERT_REQUIRED,
121 ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
122 try:
123 s.connect(("svn.python.org", 443))
124 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000125 raise support.TestFailed("Unexpected exception %s" % x)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000126 finally:
127 s.close()
128
Bill Janssen6e027db2007-11-15 22:23:56 +0000129 def testNonBlockingHandshake(self):
130 s = socket.socket(socket.AF_INET)
131 s.connect(("svn.python.org", 443))
132 s.setblocking(False)
133 s = ssl.wrap_socket(s,
134 cert_reqs=ssl.CERT_NONE,
135 do_handshake_on_connect=False)
136 count = 0
137 while True:
138 try:
139 count += 1
140 s.do_handshake()
141 break
142 except ssl.SSLError as err:
143 if err.args[0] == ssl.SSL_ERROR_WANT_READ:
144 select.select([s], [], [])
145 elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE:
146 select.select([], [s], [])
147 else:
148 raise
149 s.close()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000150 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000151 sys.stdout.write("\nNeeded %d calls to do_handshake() to establish session.\n" % count)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000152
Bill Janssen54cc54c2007-12-14 22:08:56 +0000153 def testFetchServerCert(self):
154
155 pem = ssl.get_server_certificate(("svn.python.org", 443))
156 if not pem:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000157 raise support.TestFailed("No server certificate on svn.python.org:443!")
Bill Janssen54cc54c2007-12-14 22:08:56 +0000158
159 return
160
161 try:
162 pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=CERTFILE)
163 except ssl.SSLError as x:
164 #should fail
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000165 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000166 sys.stdout.write("%s\n" % x)
167 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000168 raise support.TestFailed("Got server certificate %s for svn.python.org!" % pem)
Bill Janssen54cc54c2007-12-14 22:08:56 +0000169
170 pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
171 if not pem:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000172 raise support.TestFailed("No server certificate on svn.python.org:443!")
173 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000174 sys.stdout.write("\nVerified certificate for svn.python.org:443 is\n%s\n" % pem)
175
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000176
177try:
178 import threading
179except ImportError:
180 _have_threads = False
181else:
182
183 _have_threads = True
184
185 class ThreadedEchoServer(threading.Thread):
186
187 class ConnectionHandler(threading.Thread):
188
189 """A mildly complicated class, because we want it to work both
190 with and without the SSL wrapper around the socket connection, so
191 that we can test the STARTTLS functionality."""
192
Bill Janssen6e027db2007-11-15 22:23:56 +0000193 def __init__(self, server, connsock, addr):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000194 self.server = server
195 self.running = False
196 self.sock = connsock
Bill Janssen6e027db2007-11-15 22:23:56 +0000197 self.addr = addr
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000198 self.sock.setblocking(1)
199 self.sslconn = None
200 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000201 self.daemon = True
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000202
203 def wrap_conn (self):
204 try:
205 self.sslconn = ssl.wrap_socket(self.sock, server_side=True,
206 certfile=self.server.certificate,
207 ssl_version=self.server.protocol,
208 ca_certs=self.server.cacerts,
209 cert_reqs=self.server.certreqs)
210 except:
211 if self.server.chatty:
Bill Janssen6e027db2007-11-15 22:23:56 +0000212 handle_error("\n server: bad connection attempt from " + repr(self.addr) + ":\n")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000213 if not self.server.expect_bad_connects:
214 # here, we want to stop the server, because this shouldn't
215 # happen in the context of our test case
216 self.running = False
217 # normally, we'd just stop here, but for the test
218 # harness, we want to stop the server
219 self.server.stop()
Bill Janssen6e027db2007-11-15 22:23:56 +0000220 self.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000221 return False
222
223 else:
224 if self.server.certreqs == ssl.CERT_REQUIRED:
225 cert = self.sslconn.getpeercert()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000226 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000227 sys.stdout.write(" client cert is " + pprint.pformat(cert) + "\n")
228 cert_binary = self.sslconn.getpeercert(True)
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(" cert binary is " + str(len(cert_binary)) + " bytes\n")
231 cipher = self.sslconn.cipher()
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(" server: connection cipher is now " + str(cipher) + "\n")
234 return True
235
236 def read(self):
237 if self.sslconn:
238 return self.sslconn.read()
239 else:
240 return self.sock.recv(1024)
241
242 def write(self, bytes):
243 if self.sslconn:
244 return self.sslconn.write(bytes)
245 else:
246 return self.sock.send(bytes)
247
248 def close(self):
249 if self.sslconn:
250 self.sslconn.close()
251 else:
252 self.sock.close()
253
254 def run (self):
255 self.running = True
256 if not self.server.starttls_server:
257 if not self.wrap_conn():
258 return
259 while self.running:
260 try:
261 msg = self.read()
Bill Janssen6e027db2007-11-15 22:23:56 +0000262 amsg = (msg and str(msg, 'ASCII', 'strict')) or ''
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000263 if not msg:
264 # eof, so quit this handler
265 self.running = False
266 self.close()
Bill Janssen6e027db2007-11-15 22:23:56 +0000267 elif amsg.strip() == 'over':
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000268 if support.verbose and self.server.connectionchatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000269 sys.stdout.write(" server: client closed connection\n")
270 self.close()
271 return
Bill Janssen6e027db2007-11-15 22:23:56 +0000272 elif (self.server.starttls_server and
273 amsg.strip() == 'STARTTLS'):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000274 if support.verbose and self.server.connectionchatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000275 sys.stdout.write(" server: read STARTTLS from client, sending OK...\n")
Bill Janssen6e027db2007-11-15 22:23:56 +0000276 self.write("OK\n".encode("ASCII", "strict"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000277 if not self.wrap_conn():
278 return
Bill Janssen40a0f662008-08-12 16:56:25 +0000279 elif (self.server.starttls_server and self.sslconn
280 and amsg.strip() == 'ENDTLS'):
281 if support.verbose and self.server.connectionchatty:
282 sys.stdout.write(" server: read ENDTLS from client, sending OK...\n")
283 self.write("OK\n".encode("ASCII", "strict"))
284 self.sock = self.sslconn.unwrap()
285 self.sslconn = None
286 if support.verbose and self.server.connectionchatty:
287 sys.stdout.write(" server: connection is now unencrypted...\n")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000288 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000289 if (support.verbose and
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000290 self.server.connectionchatty):
291 ctype = (self.sslconn and "encrypted") or "unencrypted"
292 sys.stdout.write(" server: read %s (%s), sending back %s (%s)...\n"
293 % (repr(msg), ctype, repr(msg.lower()), ctype))
Bill Janssen6e027db2007-11-15 22:23:56 +0000294 self.write(amsg.lower().encode('ASCII', 'strict'))
295 except socket.error:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000296 if self.server.chatty:
297 handle_error("Test server failure:\n")
298 self.close()
299 self.running = False
300 # normally, we'd just stop here, but for the test
301 # harness, we want to stop the server
302 self.server.stop()
303 except:
304 handle_error('')
305
Trent Nelson78520002008-04-10 20:54:35 +0000306 def __init__(self, certificate, ssl_version=None,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000307 certreqs=None, cacerts=None, expect_bad_connects=False,
308 chatty=True, connectionchatty=False, starttls_server=False):
309 if ssl_version is None:
310 ssl_version = ssl.PROTOCOL_TLSv1
311 if certreqs is None:
312 certreqs = ssl.CERT_NONE
313 self.certificate = certificate
314 self.protocol = ssl_version
315 self.certreqs = certreqs
316 self.cacerts = cacerts
317 self.expect_bad_connects = expect_bad_connects
318 self.chatty = chatty
319 self.connectionchatty = connectionchatty
320 self.starttls_server = starttls_server
321 self.sock = socket.socket()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000322 self.port = support.bind_port(self.sock)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000323 self.flag = None
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000324 self.active = False
325 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000326 self.daemon = True
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000327
328 def start (self, flag=None):
329 self.flag = flag
330 threading.Thread.start(self)
331
332 def run (self):
333 self.sock.settimeout(0.5)
334 self.sock.listen(5)
335 self.active = True
336 if self.flag:
337 # signal an event
338 self.flag.set()
339 while self.active:
340 try:
341 newconn, connaddr = self.sock.accept()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000342 if support.verbose and self.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000343 sys.stdout.write(' server: new connection from '
Bill Janssen6e027db2007-11-15 22:23:56 +0000344 + repr(connaddr) + '\n')
345 handler = self.ConnectionHandler(self, newconn, connaddr)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000346 handler.start()
347 except socket.timeout:
348 pass
349 except KeyboardInterrupt:
350 self.stop()
351 except:
352 if self.chatty:
353 handle_error("Test server failure:\n")
Bill Janssen6e027db2007-11-15 22:23:56 +0000354 self.sock.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000355
356 def stop (self):
357 self.active = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000358
Bill Janssen54cc54c2007-12-14 22:08:56 +0000359 class OurHTTPSServer(threading.Thread):
360
361 # This one's based on HTTPServer, which is based on SocketServer
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000362
363 class HTTPSServer(HTTPServer):
364
365 def __init__(self, server_address, RequestHandlerClass, certfile):
366
367 HTTPServer.__init__(self, server_address, RequestHandlerClass)
368 # we assume the certfile contains both private key and certificate
369 self.certfile = certfile
370 self.active = False
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000371 self.active_lock = threading.Lock()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000372 self.allow_reuse_address = True
373
Bill Janssen6e027db2007-11-15 22:23:56 +0000374 def __str__(self):
375 return ('<%s %s:%s>' %
376 (self.__class__.__name__,
377 self.server_name,
378 self.server_port))
379
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000380 def get_request (self):
381 # override this to wrap socket with SSL
382 sock, addr = self.socket.accept()
383 sslconn = ssl.wrap_socket(sock, server_side=True,
384 certfile=self.certfile)
385 return sslconn, addr
386
387 # The methods overridden below this are mainly so that we
388 # can run it in a thread and be able to stop it from another
389 # You probably wouldn't need them in other uses.
390
391 def server_activate(self):
392 # We want to run this in a thread for testing purposes,
393 # so we override this to set timeout, so that we get
394 # a chance to stop the server
395 self.socket.settimeout(0.5)
396 HTTPServer.server_activate(self)
397
398 def serve_forever(self):
399 # We want this to run in a thread, so we use a slightly
400 # modified version of "forever".
401 self.active = True
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000402 while 1:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000403 try:
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000404 # We need to lock while handling the request.
405 # Another thread can close the socket after self.active
406 # has been checked and before the request is handled.
407 # This causes an exception when using the closed socket.
408 with self.active_lock:
409 if not self.active:
410 break
411 self.handle_request()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000412 except socket.timeout:
413 pass
414 except KeyboardInterrupt:
415 self.server_close()
416 return
417 except:
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000418 sys.stdout.write(''.join(traceback.format_exception(*sys.exc_info())))
419 break
Neal Norwitzf9ff5f02008-03-31 05:39:26 +0000420 time.sleep(0.1)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000421
422 def server_close(self):
423 # Again, we want this to run in a thread, so we need to override
424 # close to clear the "active" flag, so that serve_forever() will
425 # terminate.
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000426 with self.active_lock:
427 HTTPServer.server_close(self)
428 self.active = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000429
430 class RootedHTTPRequestHandler(SimpleHTTPRequestHandler):
431
432 # need to override translate_path to get a known root,
433 # instead of using os.curdir, since the test could be
434 # run from anywhere
435
436 server_version = "TestHTTPS/1.0"
437
438 root = None
439
440 def translate_path(self, path):
441 """Translate a /-separated PATH to the local filename syntax.
442
443 Components that mean special things to the local file system
444 (e.g. drive or directory names) are ignored. (XXX They should
445 probably be diagnosed.)
446
447 """
448 # abandon query parameters
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000449 path = urllib.parse.urlparse(path)[2]
450 path = os.path.normpath(urllib.parse.unquote(path))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000451 words = path.split('/')
452 words = filter(None, words)
453 path = self.root
454 for word in words:
455 drive, word = os.path.splitdrive(word)
456 head, word = os.path.split(word)
457 if word in self.root: continue
458 path = os.path.join(path, word)
459 return path
460
461 def log_message(self, format, *args):
462
463 # we override this to suppress logging unless "verbose"
464
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000465 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000466 sys.stdout.write(" server (%s:%d %s):\n [%s] %s\n" %
467 (self.server.server_address,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000468 self.server.server_port,
469 self.request.cipher(),
470 self.log_date_time_string(),
471 format%args))
Thomas Woutersed03b412007-08-28 21:37:11 +0000472
473
Trent Nelson78520002008-04-10 20:54:35 +0000474 def __init__(self, certfile):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000475 self.flag = None
476 self.active = False
477 self.RootedHTTPRequestHandler.root = os.path.split(CERTFILE)[0]
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000478 self.port = support.find_unused_port()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000479 self.server = self.HTTPSServer(
Trent Nelson78520002008-04-10 20:54:35 +0000480 (HOST, self.port), self.RootedHTTPRequestHandler, certfile)
Thomas Woutersed03b412007-08-28 21:37:11 +0000481 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000482 self.daemon = True
Thomas Woutersed03b412007-08-28 21:37:11 +0000483
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000484 def __str__(self):
Bill Janssen6e027db2007-11-15 22:23:56 +0000485 return "<%s %s>" % (self.__class__.__name__, self.server)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000486
487 def start (self, flag=None):
488 self.flag = flag
489 threading.Thread.start(self)
490
Thomas Woutersed03b412007-08-28 21:37:11 +0000491 def run (self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000492 self.active = True
493 if self.flag:
494 self.flag.set()
495 self.server.serve_forever()
496 self.active = False
497
498 def stop (self):
499 self.active = False
500 self.server.server_close()
501
502
Bill Janssen54cc54c2007-12-14 22:08:56 +0000503 class AsyncoreEchoServer(threading.Thread):
504
505 # this one's based on asyncore.dispatcher
506
507 class EchoServer (asyncore.dispatcher):
508
509 class ConnectionHandler (asyncore.dispatcher_with_send):
510
511 def __init__(self, conn, certfile):
512 self.socket = ssl.wrap_socket(conn, server_side=True,
513 certfile=certfile,
514 do_handshake_on_connect=False)
515 asyncore.dispatcher_with_send.__init__(self, self.socket)
516 # now we have to do the handshake
517 # we'll just do it the easy way, and block the connection
518 # till it's finished. If we were doing it right, we'd
519 # do this in multiple calls to handle_read...
520 self.do_handshake(block=True)
521
522 def readable(self):
523 if isinstance(self.socket, ssl.SSLSocket):
524 while self.socket.pending() > 0:
525 self.handle_read_event()
526 return True
527
528 def handle_read(self):
529 data = self.recv(1024)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000530 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000531 sys.stdout.write(" server: read %s from client\n" % repr(data))
532 if not data:
533 self.close()
534 else:
535 self.send(str(data, 'ASCII', 'strict').lower().encode('ASCII', 'strict'))
536
537 def handle_close(self):
Bill Janssen2f5799b2008-06-29 00:08:12 +0000538 self.close()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000539 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000540 sys.stdout.write(" server: closed connection %s\n" % self.socket)
541
542 def handle_error(self):
543 raise
544
545 def __init__(self, port, certfile):
546 self.port = port
547 self.certfile = certfile
548 asyncore.dispatcher.__init__(self)
549 self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
550 self.bind(('', port))
551 self.listen(5)
552
553 def handle_accept(self):
554 sock_obj, addr = self.accept()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000555 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000556 sys.stdout.write(" server: new connection from %s:%s\n" %addr)
557 self.ConnectionHandler(sock_obj, self.certfile)
558
559 def handle_error(self):
560 raise
561
Trent Nelson78520002008-04-10 20:54:35 +0000562 def __init__(self, certfile):
Bill Janssen54cc54c2007-12-14 22:08:56 +0000563 self.flag = None
564 self.active = False
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000565 self.port = support.find_unused_port()
Trent Nelson78520002008-04-10 20:54:35 +0000566 self.server = self.EchoServer(self.port, certfile)
Bill Janssen54cc54c2007-12-14 22:08:56 +0000567 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000568 self.daemon = True
Bill Janssen54cc54c2007-12-14 22:08:56 +0000569
570 def __str__(self):
571 return "<%s %s>" % (self.__class__.__name__, self.server)
572
573 def start (self, flag=None):
574 self.flag = flag
575 threading.Thread.start(self)
576
577 def run (self):
578 self.active = True
579 if self.flag:
580 self.flag.set()
581 while self.active:
582 try:
583 asyncore.loop(1)
584 except:
585 pass
586
587 def stop (self):
588 self.active = False
589 self.server.close()
590
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000591 def badCertTest (certfile):
Trent Nelson78520002008-04-10 20:54:35 +0000592 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000593 certreqs=ssl.CERT_REQUIRED,
Bill Janssen6e027db2007-11-15 22:23:56 +0000594 cacerts=CERTFILE, chatty=False,
595 connectionchatty=False)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000596 flag = threading.Event()
597 server.start(flag)
598 # wait for it to start
599 flag.wait()
600 # try to connect
601 try:
Thomas Woutersed03b412007-08-28 21:37:11 +0000602 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000603 s = ssl.wrap_socket(socket.socket(),
604 certfile=certfile,
605 ssl_version=ssl.PROTOCOL_TLSv1)
Trent Nelson78520002008-04-10 20:54:35 +0000606 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000607 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000608 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000609 sys.stdout.write("\nSSLError is %s\n" % x)
Bill Janssenddc56692008-07-17 18:17:20 +0000610 except socket.error as x:
611 if support.verbose:
612 sys.stdout.write("\nsocket.error is %s\n" % x)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000613 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000614 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000615 "Use of invalid cert should have failed!")
616 finally:
617 server.stop()
618 server.join()
Thomas Woutersed03b412007-08-28 21:37:11 +0000619
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000620 def serverParamsTest (certfile, protocol, certreqs, cacertsfile,
Bill Janssen6e027db2007-11-15 22:23:56 +0000621 client_certfile, client_protocol=None,
622 indata="FOO\n",
623 chatty=False, connectionchatty=False):
Thomas Woutersed03b412007-08-28 21:37:11 +0000624
Trent Nelson78520002008-04-10 20:54:35 +0000625 server = ThreadedEchoServer(certfile,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000626 certreqs=certreqs,
627 ssl_version=protocol,
628 cacerts=cacertsfile,
629 chatty=chatty,
Bill Janssen6e027db2007-11-15 22:23:56 +0000630 connectionchatty=False)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000631 flag = threading.Event()
632 server.start(flag)
633 # wait for it to start
634 flag.wait()
635 # try to connect
636 if client_protocol is None:
637 client_protocol = protocol
638 try:
Bill Janssen6e027db2007-11-15 22:23:56 +0000639 s = ssl.wrap_socket(socket.socket(),
Trent Nelson6b240cd2008-04-10 20:12:06 +0000640 server_side=False,
Bill Janssen6e027db2007-11-15 22:23:56 +0000641 certfile=client_certfile,
642 ca_certs=cacertsfile,
643 cert_reqs=certreqs,
644 ssl_version=client_protocol)
Trent Nelson78520002008-04-10 20:54:35 +0000645 s.connect((HOST, server.port))
Bill Janssen6e027db2007-11-15 22:23:56 +0000646 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000647 raise support.TestFailed("Unexpected SSL error: " + str(x))
Bill Janssen6e027db2007-11-15 22:23:56 +0000648 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000649 raise support.TestFailed("Unexpected exception: " + str(x))
Bill Janssen6e027db2007-11-15 22:23:56 +0000650 else:
Antoine Pitrou7d7aede2009-11-25 18:55:32 +0000651 bindata = indata.encode('ASCII', 'strict')
652 for arg in [bindata, bytearray(bindata), memoryview(bindata)]:
653 if connectionchatty:
654 if support.verbose:
655 sys.stdout.write(
656 " client: sending %s...\n" % (repr(indata)))
657 s.write(arg)
658 outdata = s.read()
659 if connectionchatty:
660 if support.verbose:
661 sys.stdout.write(" client: read %s\n" % repr(outdata))
662 outdata = str(outdata, 'ASCII', 'strict')
663 if outdata != indata.lower():
664 raise support.TestFailed(
665 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
666 % (repr(outdata[:min(len(outdata),20)]), len(outdata),
667 repr(indata[:min(len(indata),20)].lower()), len(indata)))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000668 s.write("over\n".encode("ASCII", "strict"))
Bill Janssen6e027db2007-11-15 22:23:56 +0000669 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000670 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000671 sys.stdout.write(" client: closing connection.\n")
672 s.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000673 finally:
674 server.stop()
675 server.join()
Thomas Woutersed03b412007-08-28 21:37:11 +0000676
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000677 def tryProtocolCombo (server_protocol,
678 client_protocol,
679 expectedToWork,
680 certsreqs=None):
Thomas Woutersed03b412007-08-28 21:37:11 +0000681
Benjamin Peterson2a691a82008-03-31 01:51:45 +0000682 if certsreqs is None:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000683 certsreqs = ssl.CERT_NONE
Thomas Woutersed03b412007-08-28 21:37:11 +0000684
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000685 if certsreqs == ssl.CERT_NONE:
686 certtype = "CERT_NONE"
687 elif certsreqs == ssl.CERT_OPTIONAL:
688 certtype = "CERT_OPTIONAL"
689 elif certsreqs == ssl.CERT_REQUIRED:
690 certtype = "CERT_REQUIRED"
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000691 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000692 formatstr = (expectedToWork and " %s->%s %s\n") or " {%s->%s} %s\n"
693 sys.stdout.write(formatstr %
694 (ssl.get_protocol_name(client_protocol),
695 ssl.get_protocol_name(server_protocol),
696 certtype))
697 try:
698 serverParamsTest(CERTFILE, server_protocol, certsreqs,
Bill Janssen6e027db2007-11-15 22:23:56 +0000699 CERTFILE, CERTFILE, client_protocol,
700 chatty=False, connectionchatty=False)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000701 except support.TestFailed:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000702 if expectedToWork:
703 raise
704 else:
705 if not expectedToWork:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000706 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000707 "Client protocol %s succeeded with server protocol %s!"
708 % (ssl.get_protocol_name(client_protocol),
709 ssl.get_protocol_name(server_protocol)))
710
711
Bill Janssen6e027db2007-11-15 22:23:56 +0000712 class ThreadedTests(unittest.TestCase):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000713
Trent Nelson6b240cd2008-04-10 20:12:06 +0000714 def testEcho (self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000715
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000716 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000717 sys.stdout.write("\n")
718 serverParamsTest(CERTFILE, ssl.PROTOCOL_TLSv1, ssl.CERT_NONE,
719 CERTFILE, CERTFILE, ssl.PROTOCOL_TLSv1,
720 chatty=True, connectionchatty=True)
721
722 def testReadCert(self):
723
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000724 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000725 sys.stdout.write("\n")
726 s2 = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000727 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000728 certreqs=ssl.CERT_NONE,
729 ssl_version=ssl.PROTOCOL_SSLv23,
730 cacerts=CERTFILE,
731 chatty=False)
732 flag = threading.Event()
733 server.start(flag)
734 # wait for it to start
735 flag.wait()
736 # try to connect
737 try:
738 try:
739 s = ssl.wrap_socket(socket.socket(),
740 certfile=CERTFILE,
741 ca_certs=CERTFILE,
742 cert_reqs=ssl.CERT_REQUIRED,
743 ssl_version=ssl.PROTOCOL_SSLv23)
Trent Nelson78520002008-04-10 20:54:35 +0000744 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000745 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000746 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000747 "Unexpected SSL error: " + str(x))
748 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000749 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000750 "Unexpected exception: " + str(x))
751 else:
752 if not s:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000753 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000754 "Can't SSL-handshake with test server")
755 cert = s.getpeercert()
756 if not cert:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000757 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000758 "Can't get peer certificate.")
759 cipher = s.cipher()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000760 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000761 sys.stdout.write(pprint.pformat(cert) + '\n')
762 sys.stdout.write("Connection cipher is " + str(cipher) + '.\n')
Bill Janssen6e027db2007-11-15 22:23:56 +0000763 if 'subject' not in cert:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000764 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000765 "No subject field in certificate: %s." %
766 pprint.pformat(cert))
767 if ((('organizationName', 'Python Software Foundation'),)
768 not in cert['subject']):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000769 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000770 "Missing or invalid 'organizationName' field in certificate subject; "
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000771 "should be 'Python Software Foundation'.")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000772 s.close()
773 finally:
774 server.stop()
775 server.join()
776
777 def testNULLcert(self):
778 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
779 "nullcert.pem"))
780 def testMalformedCert(self):
781 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
782 "badcert.pem"))
Bill Janssen58afe4c2008-09-08 16:45:19 +0000783 def testWrongCert(self):
784 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
785 "wrongcert.pem"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000786 def testMalformedKey(self):
787 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
788 "badkey.pem"))
789
Trent Nelson6b240cd2008-04-10 20:12:06 +0000790 def testRudeShutdown(self):
791
792 listener_ready = threading.Event()
793 listener_gone = threading.Event()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000794 port = support.find_unused_port()
Trent Nelson6b240cd2008-04-10 20:12:06 +0000795
796 # `listener` runs in a thread. It opens a socket listening on
797 # PORT, and sits in an accept() until the main thread connects.
798 # Then it rudely closes the socket, and sets Event `listener_gone`
799 # to let the main thread know the socket is gone.
800 def listener():
801 s = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000802 s.bind((HOST, port))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000803 s.listen(5)
804 listener_ready.set()
805 s.accept()
806 s = None # reclaim the socket object, which also closes it
807 listener_gone.set()
808
809 def connector():
810 listener_ready.wait()
811 s = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000812 s.connect((HOST, port))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000813 listener_gone.wait()
814 try:
815 ssl_sock = ssl.wrap_socket(s)
816 except IOError:
817 pass
818 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000819 raise support.TestFailed(
Trent Nelson6b240cd2008-04-10 20:12:06 +0000820 'connecting to closed SSL socket should have failed')
821
822 t = threading.Thread(target=listener)
823 t.start()
824 connector()
825 t.join()
826
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000827 def testProtocolSSL2(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000828 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000829 sys.stdout.write("\n")
830 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True)
831 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL)
832 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED)
833 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True)
834 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False)
835 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False)
836
837 def testProtocolSSL23(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000838 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000839 sys.stdout.write("\n")
840 try:
841 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv2, True)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000842 except support.TestFailed as x:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000843 # this fails on some older versions of OpenSSL (0.9.7l, for instance)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000844 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000845 sys.stdout.write(
846 " SSL2 client to SSL23 server test unexpectedly failed:\n %s\n"
847 % str(x))
848 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True)
849 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True)
850 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True)
851
852 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
853 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_OPTIONAL)
854 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
855
856 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
857 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_REQUIRED)
858 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
859
860 def testProtocolSSL3(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000861 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000862 sys.stdout.write("\n")
863 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True)
864 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
865 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
866 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False)
867 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, False)
868 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False)
869
870 def testProtocolTLS1(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000871 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000872 sys.stdout.write("\n")
873 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True)
874 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
875 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
876 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False)
877 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False)
878 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv23, False)
879
880 def testSTARTTLS (self):
881
Bill Janssen40a0f662008-08-12 16:56:25 +0000882 msgs = ("msg 1", "MSG 2", "STARTTLS", "MSG 3", "msg 4", "ENDTLS", "msg 5", "msg 6")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000883
Trent Nelson78520002008-04-10 20:54:35 +0000884 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000885 ssl_version=ssl.PROTOCOL_TLSv1,
886 starttls_server=True,
887 chatty=True,
888 connectionchatty=True)
889 flag = threading.Event()
890 server.start(flag)
891 # wait for it to start
892 flag.wait()
893 # try to connect
894 wrapped = False
895 try:
896 try:
897 s = socket.socket()
898 s.setblocking(1)
Trent Nelson78520002008-04-10 20:54:35 +0000899 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000900 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000901 raise support.TestFailed("Unexpected exception: " + str(x))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000902 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000903 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000904 sys.stdout.write("\n")
905 for indata in msgs:
Bill Janssen6e027db2007-11-15 22:23:56 +0000906 msg = indata.encode('ASCII', 'replace')
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000907 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000908 sys.stdout.write(
Bill Janssen6e027db2007-11-15 22:23:56 +0000909 " client: sending %s...\n" % repr(msg))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000910 if wrapped:
Bill Janssen6e027db2007-11-15 22:23:56 +0000911 conn.write(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000912 outdata = conn.read()
913 else:
Bill Janssen6e027db2007-11-15 22:23:56 +0000914 s.send(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000915 outdata = s.recv(1024)
916 if (indata == "STARTTLS" and
Bill Janssen6e027db2007-11-15 22:23:56 +0000917 str(outdata, 'ASCII', 'replace').strip().lower().startswith("ok")):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000918 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000919 msg = str(outdata, 'ASCII', 'replace')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000920 sys.stdout.write(
921 " client: read %s from server, starting TLS...\n"
Bill Janssen6e027db2007-11-15 22:23:56 +0000922 % repr(msg))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000923 conn = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000924 wrapped = True
Bill Janssen40a0f662008-08-12 16:56:25 +0000925 elif (indata == "ENDTLS" and
926 str(outdata, 'ASCII', 'replace').strip().lower().startswith("ok")):
927 if support.verbose:
928 msg = str(outdata, 'ASCII', 'replace')
929 sys.stdout.write(
930 " client: read %s from server, ending TLS...\n"
931 % repr(msg))
932 s = conn.unwrap()
933 wrapped = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000934 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000935 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000936 msg = str(outdata, 'ASCII', 'replace')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000937 sys.stdout.write(
Bill Janssen6e027db2007-11-15 22:23:56 +0000938 " client: read %s from server\n" % repr(msg))
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000939 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000940 sys.stdout.write(" client: closing connection.\n")
941 if wrapped:
Bill Janssen6e027db2007-11-15 22:23:56 +0000942 conn.write("over\n".encode("ASCII", "strict"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000943 else:
Bill Janssen40a0f662008-08-12 16:56:25 +0000944 s.send("over\n".encode("ASCII", "strict"))
Bill Janssen6e027db2007-11-15 22:23:56 +0000945 if wrapped:
946 conn.close()
947 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000948 s.close()
949 finally:
950 server.stop()
951 server.join()
952
Bill Janssen54cc54c2007-12-14 22:08:56 +0000953 def testSocketServer(self):
Bill Janssen6e027db2007-11-15 22:23:56 +0000954
Trent Nelson78520002008-04-10 20:54:35 +0000955 server = OurHTTPSServer(CERTFILE)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000956 flag = threading.Event()
957 server.start(flag)
958 # wait for it to start
959 flag.wait()
960 # try to connect
961 try:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000962 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000963 sys.stdout.write('\n')
964 d1 = open(CERTFILE, 'rb').read()
965 d2 = ''
966 # now fetch the same data from the HTTPS server
Trent Nelson78520002008-04-10 20:54:35 +0000967 url = 'https://%s:%d/%s' % (
968 HOST, server.port, os.path.split(CERTFILE)[1])
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000969 f = urllib.request.urlopen(url)
Barry Warsaw820c1202008-06-12 04:06:45 +0000970 dlen = f.info().get("content-length")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000971 if dlen and (int(dlen) > 0):
972 d2 = f.read(int(dlen))
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000973 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000974 sys.stdout.write(
975 " client: read %d bytes from remote server '%s'\n"
976 % (len(d2), server))
977 f.close()
978 except:
979 msg = ''.join(traceback.format_exception(*sys.exc_info()))
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000980 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000981 sys.stdout.write('\n' + msg)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000982 raise support.TestFailed(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000983 else:
984 if not (d1 == d2):
Bill Janssen6e027db2007-11-15 22:23:56 +0000985 print("d1 is", len(d1), repr(d1))
986 print("d2 is", len(d2), repr(d2))
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000987 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000988 "Couldn't fetch data from HTTPS server")
989 finally:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000990 if support.verbose:
Neal Norwitzf9ff5f02008-03-31 05:39:26 +0000991 sys.stdout.write('stopping server\n')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000992 server.stop()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000993 if support.verbose:
Neal Norwitzf9ff5f02008-03-31 05:39:26 +0000994 sys.stdout.write('joining thread\n')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000995 server.join()
996
Trent Nelson6b240cd2008-04-10 20:12:06 +0000997 def testAsyncoreServer(self):
998
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000999 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001000 sys.stdout.write("\n")
1001
1002 indata="FOO\n"
Trent Nelson78520002008-04-10 20:54:35 +00001003 server = AsyncoreEchoServer(CERTFILE)
Trent Nelson6b240cd2008-04-10 20:12:06 +00001004 flag = threading.Event()
1005 server.start(flag)
1006 # wait for it to start
1007 flag.wait()
1008 # try to connect
1009 try:
1010 s = ssl.wrap_socket(socket.socket())
Trent Nelson78520002008-04-10 20:54:35 +00001011 s.connect((HOST, server.port))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001012 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001013 raise support.TestFailed("Unexpected SSL error: " + str(x))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001014 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001015 raise support.TestFailed("Unexpected exception: " + str(x))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001016 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001017 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001018 sys.stdout.write(
1019 " client: sending %s...\n" % (repr(indata)))
1020 s.sendall(indata.encode('ASCII', 'strict'))
1021 outdata = s.recv()
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001022 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001023 sys.stdout.write(" client: read %s\n" % repr(outdata))
1024 outdata = str(outdata, 'ASCII', 'strict')
1025 if outdata != indata.lower():
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001026 raise support.TestFailed(
Trent Nelson6b240cd2008-04-10 20:12:06 +00001027 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
1028 % (repr(outdata[:min(len(outdata),20)]), len(outdata),
1029 repr(indata[:min(len(indata),20)].lower()), len(indata)))
1030 s.write("over\n".encode("ASCII", "strict"))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001031 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001032 sys.stdout.write(" client: closing connection.\n")
1033 s.close()
1034 finally:
1035 server.stop()
1036 server.join()
1037
Bill Janssen58afe4c2008-09-08 16:45:19 +00001038 def testAllRecvAndSendMethods(self):
1039
1040 if support.verbose:
1041 sys.stdout.write("\n")
1042
1043 server = ThreadedEchoServer(CERTFILE,
1044 certreqs=ssl.CERT_NONE,
1045 ssl_version=ssl.PROTOCOL_TLSv1,
1046 cacerts=CERTFILE,
1047 chatty=True,
1048 connectionchatty=False)
1049 flag = threading.Event()
1050 server.start(flag)
1051 # wait for it to start
1052 flag.wait()
1053 # try to connect
1054 try:
1055 s = ssl.wrap_socket(socket.socket(),
1056 server_side=False,
1057 certfile=CERTFILE,
1058 ca_certs=CERTFILE,
1059 cert_reqs=ssl.CERT_NONE,
1060 ssl_version=ssl.PROTOCOL_TLSv1)
1061 s.connect((HOST, server.port))
1062 except ssl.SSLError as x:
Georg Brandl89fad142010-03-14 10:23:39 +00001063 self.fail("Unexpected SSL error: " + str(x))
Bill Janssen58afe4c2008-09-08 16:45:19 +00001064 except Exception as x:
Georg Brandl89fad142010-03-14 10:23:39 +00001065 self.fail("Unexpected exception: " + str(x))
Bill Janssen58afe4c2008-09-08 16:45:19 +00001066 else:
1067 # helper methods for standardising recv* method signatures
1068 def _recv_into():
1069 b = bytearray(b"\0"*100)
1070 count = s.recv_into(b)
1071 return b[:count]
1072
1073 def _recvfrom_into():
1074 b = bytearray(b"\0"*100)
1075 count, addr = s.recvfrom_into(b)
1076 return b[:count]
1077
1078 # (name, method, whether to expect success, *args)
1079 send_methods = [
1080 ('send', s.send, True, []),
1081 ('sendto', s.sendto, False, ["some.address"]),
1082 ('sendall', s.sendall, True, []),
1083 ]
1084 recv_methods = [
1085 ('recv', s.recv, True, []),
1086 ('recvfrom', s.recvfrom, False, ["some.address"]),
1087 ('recv_into', _recv_into, True, []),
1088 ('recvfrom_into', _recvfrom_into, False, []),
1089 ]
1090 data_prefix = "PREFIX_"
1091
1092 for meth_name, send_meth, expect_success, args in send_methods:
1093 indata = data_prefix + meth_name
1094 try:
1095 send_meth(indata.encode('ASCII', 'strict'), *args)
1096 outdata = s.read()
1097 outdata = str(outdata, 'ASCII', 'strict')
1098 if outdata != indata.lower():
Georg Brandl89fad142010-03-14 10:23:39 +00001099 self.fail(
Bill Janssen58afe4c2008-09-08 16:45:19 +00001100 "While sending with <<{name:s}>> bad data "
1101 "<<{outdata:s}>> ({nout:d}) received; "
1102 "expected <<{indata:s}>> ({nin:d})\n".format(
1103 name=meth_name, outdata=repr(outdata[:20]),
1104 nout=len(outdata),
1105 indata=repr(indata[:20]), nin=len(indata)
1106 )
1107 )
1108 except ValueError as e:
1109 if expect_success:
Georg Brandl89fad142010-03-14 10:23:39 +00001110 self.fail(
Bill Janssen58afe4c2008-09-08 16:45:19 +00001111 "Failed to send with method <<{name:s}>>; "
1112 "expected to succeed.\n".format(name=meth_name)
1113 )
1114 if not str(e).startswith(meth_name):
Georg Brandl89fad142010-03-14 10:23:39 +00001115 self.fail(
Bill Janssen58afe4c2008-09-08 16:45:19 +00001116 "Method <<{name:s}>> failed with unexpected "
1117 "exception message: {exp:s}\n".format(
1118 name=meth_name, exp=e
1119 )
1120 )
1121
1122 for meth_name, recv_meth, expect_success, args in recv_methods:
1123 indata = data_prefix + meth_name
1124 try:
1125 s.send(indata.encode('ASCII', 'strict'))
1126 outdata = recv_meth(*args)
1127 outdata = str(outdata, 'ASCII', 'strict')
1128 if outdata != indata.lower():
Georg Brandl89fad142010-03-14 10:23:39 +00001129 self.fail(
Bill Janssen58afe4c2008-09-08 16:45:19 +00001130 "While receiving with <<{name:s}>> bad data "
1131 "<<{outdata:s}>> ({nout:d}) received; "
1132 "expected <<{indata:s}>> ({nin:d})\n".format(
1133 name=meth_name, outdata=repr(outdata[:20]),
1134 nout=len(outdata),
1135 indata=repr(indata[:20]), nin=len(indata)
1136 )
1137 )
1138 except ValueError as e:
1139 if expect_success:
Georg Brandl89fad142010-03-14 10:23:39 +00001140 self.fail(
Bill Janssen58afe4c2008-09-08 16:45:19 +00001141 "Failed to receive with method <<{name:s}>>; "
1142 "expected to succeed.\n".format(name=meth_name)
1143 )
1144 if not str(e).startswith(meth_name):
Georg Brandl89fad142010-03-14 10:23:39 +00001145 self.fail(
Bill Janssen58afe4c2008-09-08 16:45:19 +00001146 "Method <<{name:s}>> failed with unexpected "
1147 "exception message: {exp:s}\n".format(
1148 name=meth_name, exp=e
1149 )
1150 )
1151 # consume data
1152 s.read()
1153
1154 s.write("over\n".encode("ASCII", "strict"))
1155 s.close()
1156 finally:
1157 server.stop()
1158 server.join()
1159
1160
Thomas Woutersed03b412007-08-28 21:37:11 +00001161def test_main(verbose=False):
1162 if skip_expected:
Benjamin Petersone549ead2009-03-28 21:42:05 +00001163 raise unittest.SkipTest("No SSL support")
Thomas Woutersed03b412007-08-28 21:37:11 +00001164
Trent Nelson78520002008-04-10 20:54:35 +00001165 global CERTFILE, SVN_PYTHON_ORG_ROOT_CERT
Thomas Woutersed03b412007-08-28 21:37:11 +00001166 CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir,
1167 "keycert.pem")
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001168 SVN_PYTHON_ORG_ROOT_CERT = os.path.join(
1169 os.path.dirname(__file__) or os.curdir,
1170 "https_svn_python_org_root.pem")
1171
1172 if (not os.path.exists(CERTFILE) or
1173 not os.path.exists(SVN_PYTHON_ORG_ROOT_CERT)):
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001174 raise support.TestFailed("Can't read certificate files!")
Bill Janssen6e027db2007-11-15 22:23:56 +00001175
Thomas Woutersed03b412007-08-28 21:37:11 +00001176 tests = [BasicTests]
1177
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001178 if support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00001179 tests.append(NetworkedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001180
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001181 if _have_threads:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001182 thread_info = support.threading_setup()
1183 if thread_info and support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00001184 tests.append(ThreadedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001185
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001186 support.run_unittest(*tests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001187
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001188 if _have_threads:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001189 support.threading_cleanup(*thread_info)
Thomas Woutersed03b412007-08-28 21:37:11 +00001190
1191if __name__ == "__main__":
1192 test_main()