blob: eb4d00ca5f3d26101c3a52435769ce15eaba8ac4 [file] [log] [blame]
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +00001# Test the support for SSL and sockets
2
3import sys
4import unittest
5from test import test_support
6import socket
7import errno
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +00008import subprocess
9import time
10import os
11import pprint
Bill Janssen296a59d2007-09-16 22:06:00 +000012import urllib, urlparse
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +000013import shutil
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +000014import traceback
15
Bill Janssen296a59d2007-09-16 22:06:00 +000016from BaseHTTPServer import HTTPServer
17from SimpleHTTPServer import SimpleHTTPRequestHandler
18
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +000019# Optionally test SSL support, if we have it in the tested platform
20skip_expected = False
21try:
22 import ssl
23except ImportError:
24 skip_expected = True
25
Trent Nelsone41b0062008-04-08 23:47:30 +000026HOST = test_support.HOST
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +000027CERTFILE = None
Bill Janssen296a59d2007-09-16 22:06:00 +000028SVN_PYTHON_ORG_ROOT_CERT = None
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +000029
Neal Norwitz3e533c22007-08-27 01:03:18 +000030def handle_error(prefix):
31 exc_format = ' '.join(traceback.format_exception(*sys.exc_info()))
Bill Janssen98d19da2007-09-10 21:51:02 +000032 if test_support.verbose:
33 sys.stdout.write(prefix + exc_format)
Neal Norwitz3e533c22007-08-27 01:03:18 +000034
35
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +000036class BasicTests(unittest.TestCase):
37
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +000038 def testSSLconnect(self):
Christian Heimes6c29be52008-01-19 16:39:27 +000039 if not test_support.is_resource_enabled('network'):
40 return
Bill Janssen296a59d2007-09-16 22:06:00 +000041 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
42 cert_reqs=ssl.CERT_NONE)
43 s.connect(("svn.python.org", 443))
44 c = s.getpeercert()
45 if c:
46 raise test_support.TestFailed("Peer cert %s shouldn't be here!")
47 s.close()
48
49 # this should fail because we have no verification certs
50 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
51 cert_reqs=ssl.CERT_REQUIRED)
52 try:
53 s.connect(("svn.python.org", 443))
54 except ssl.SSLError:
55 pass
56 finally:
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +000057 s.close()
58
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +000059
Bill Janssen98d19da2007-09-10 21:51:02 +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
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +000068
Bill Janssen98d19da2007-09-10 21:51:02 +000069 def testRAND(self):
70 v = ssl.RAND_status()
71 if test_support.verbose:
72 sys.stdout.write("\n RAND_status is %d (%s)\n"
73 % (v, (v and "sufficient randomness") or
74 "insufficient randomness"))
Guido van Rossume4729332007-08-26 19:35:09 +000075 try:
Bill Janssen98d19da2007-09-10 21:51:02 +000076 ssl.RAND_egd(1)
77 except TypeError:
78 pass
Guido van Rossume4729332007-08-26 19:35:09 +000079 else:
Bill Janssen98d19da2007-09-10 21:51:02 +000080 print "didn't raise TypeError"
81 ssl.RAND_add("this is a random string", 75.0)
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +000082
Bill Janssen98d19da2007-09-10 21:51:02 +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)
88 if test_support.verbose:
89 sys.stdout.write("\n" + pprint.pformat(p) + "\n")
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +000090
Bill Janssen296a59d2007-09-16 22:06:00 +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):
98 raise test_support.TestFailed("PEM-to-DER or DER-to-PEM translation failed")
99
100
101class NetworkTests(unittest.TestCase):
102
103 def testConnect(self):
Bill Janssen296a59d2007-09-16 22:06:00 +0000104 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
105 cert_reqs=ssl.CERT_NONE)
106 s.connect(("svn.python.org", 443))
107 c = s.getpeercert()
108 if c:
109 raise test_support.TestFailed("Peer cert %s shouldn't be here!")
110 s.close()
111
112 # this should fail because we have no verification certs
113 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
114 cert_reqs=ssl.CERT_REQUIRED)
115 try:
116 s.connect(("svn.python.org", 443))
117 except ssl.SSLError:
118 pass
119 finally:
120 s.close()
121
122 # this should succeed because we specify the root cert
123 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
124 cert_reqs=ssl.CERT_REQUIRED,
125 ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
126 try:
127 s.connect(("svn.python.org", 443))
128 except ssl.SSLError, x:
129 raise test_support.TestFailed("Unexpected exception %s" % x)
130 finally:
131 s.close()
132
133 def testFetchServerCert(self):
134
135 pem = ssl.get_server_certificate(("svn.python.org", 443))
136 if not pem:
137 raise test_support.TestFailed("No server certificate on svn.python.org:443!")
138
139 try:
140 pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=CERTFILE)
141 except ssl.SSLError:
142 #should fail
143 pass
144 else:
145 raise test_support.TestFailed("Got server certificate %s for svn.python.org!" % pem)
146
147 pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
148 if not pem:
149 raise test_support.TestFailed("No server certificate on svn.python.org:443!")
150 if test_support.verbose:
151 sys.stdout.write("\nVerified certificate for svn.python.org:443 is\n%s\n" % pem)
152
153
Bill Janssen98d19da2007-09-10 21:51:02 +0000154try:
155 import threading
156except ImportError:
157 _have_threads = False
158else:
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000159
Bill Janssen98d19da2007-09-10 21:51:02 +0000160 _have_threads = True
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000161
Bill Janssen98d19da2007-09-10 21:51:02 +0000162 class ThreadedEchoServer(threading.Thread):
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000163
Bill Janssen98d19da2007-09-10 21:51:02 +0000164 class ConnectionHandler(threading.Thread):
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000165
Bill Janssen98d19da2007-09-10 21:51:02 +0000166 """A mildly complicated class, because we want it to work both
167 with and without the SSL wrapper around the socket connection, so
168 that we can test the STARTTLS functionality."""
169
170 def __init__(self, server, connsock):
171 self.server = server
172 self.running = False
173 self.sock = connsock
174 self.sock.setblocking(1)
175 self.sslconn = None
176 threading.Thread.__init__(self)
177 self.setDaemon(True)
178
179 def wrap_conn (self):
180 try:
181 self.sslconn = ssl.wrap_socket(self.sock, server_side=True,
182 certfile=self.server.certificate,
183 ssl_version=self.server.protocol,
184 ca_certs=self.server.cacerts,
185 cert_reqs=self.server.certreqs)
186 except:
187 if self.server.chatty:
188 handle_error("\n server: bad connection attempt from " +
189 str(self.sock.getpeername()) + ":\n")
190 if not self.server.expect_bad_connects:
191 # here, we want to stop the server, because this shouldn't
192 # happen in the context of our test case
193 self.running = False
194 # normally, we'd just stop here, but for the test
195 # harness, we want to stop the server
196 self.server.stop()
197 return False
198
199 else:
200 if self.server.certreqs == ssl.CERT_REQUIRED:
201 cert = self.sslconn.getpeercert()
202 if test_support.verbose and self.server.chatty:
203 sys.stdout.write(" client cert is " + pprint.pformat(cert) + "\n")
204 cert_binary = self.sslconn.getpeercert(True)
205 if test_support.verbose and self.server.chatty:
206 sys.stdout.write(" cert binary is " + str(len(cert_binary)) + " bytes\n")
207 cipher = self.sslconn.cipher()
208 if test_support.verbose and self.server.chatty:
209 sys.stdout.write(" server: connection cipher is now " + str(cipher) + "\n")
210 return True
211
212 def read(self):
213 if self.sslconn:
214 return self.sslconn.read()
215 else:
216 return self.sock.recv(1024)
217
218 def write(self, bytes):
219 if self.sslconn:
220 return self.sslconn.write(bytes)
221 else:
222 return self.sock.send(bytes)
223
224 def close(self):
225 if self.sslconn:
226 self.sslconn.close()
227 else:
228 self.sock.close()
229
230 def run (self):
231 self.running = True
232 if not self.server.starttls_server:
233 if not self.wrap_conn():
234 return
235 while self.running:
236 try:
237 msg = self.read()
238 if not msg:
239 # eof, so quit this handler
240 self.running = False
241 self.close()
242 elif msg.strip() == 'over':
243 if test_support.verbose and self.server.connectionchatty:
244 sys.stdout.write(" server: client closed connection\n")
245 self.close()
246 return
247 elif self.server.starttls_server and msg.strip() == 'STARTTLS':
248 if test_support.verbose and self.server.connectionchatty:
249 sys.stdout.write(" server: read STARTTLS from client, sending OK...\n")
250 self.write("OK\n")
251 if not self.wrap_conn():
252 return
253 else:
254 if (test_support.verbose and
255 self.server.connectionchatty):
256 ctype = (self.sslconn and "encrypted") or "unencrypted"
257 sys.stdout.write(" server: read %s (%s), sending back %s (%s)...\n"
258 % (repr(msg), ctype, repr(msg.lower()), ctype))
259 self.write(msg.lower())
260 except ssl.SSLError:
261 if self.server.chatty:
262 handle_error("Test server failure:\n")
263 self.close()
264 self.running = False
265 # normally, we'd just stop here, but for the test
266 # harness, we want to stop the server
267 self.server.stop()
268 except:
269 handle_error('')
270
Trent Nelsone41b0062008-04-08 23:47:30 +0000271 def __init__(self, certificate, ssl_version=None,
Bill Janssen98d19da2007-09-10 21:51:02 +0000272 certreqs=None, cacerts=None, expect_bad_connects=False,
273 chatty=True, connectionchatty=False, starttls_server=False):
274 if ssl_version is None:
275 ssl_version = ssl.PROTOCOL_TLSv1
276 if certreqs is None:
277 certreqs = ssl.CERT_NONE
278 self.certificate = certificate
279 self.protocol = ssl_version
280 self.certreqs = certreqs
281 self.cacerts = cacerts
282 self.expect_bad_connects = expect_bad_connects
283 self.chatty = chatty
284 self.connectionchatty = connectionchatty
285 self.starttls_server = starttls_server
286 self.sock = socket.socket()
Trent Nelsone41b0062008-04-08 23:47:30 +0000287 self.port = test_support.bind_port(self.sock)
Bill Janssen98d19da2007-09-10 21:51:02 +0000288 self.flag = None
Bill Janssen98d19da2007-09-10 21:51:02 +0000289 self.active = False
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000290 threading.Thread.__init__(self)
Bill Janssen98d19da2007-09-10 21:51:02 +0000291 self.setDaemon(False)
292
293 def start (self, flag=None):
294 self.flag = flag
295 threading.Thread.start(self)
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000296
297 def run (self):
Bill Janssen98d19da2007-09-10 21:51:02 +0000298 self.sock.settimeout(0.5)
299 self.sock.listen(5)
300 self.active = True
301 if self.flag:
302 # signal an event
303 self.flag.set()
304 while self.active:
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000305 try:
Bill Janssen98d19da2007-09-10 21:51:02 +0000306 newconn, connaddr = self.sock.accept()
307 if test_support.verbose and self.chatty:
308 sys.stdout.write(' server: new connection from '
309 + str(connaddr) + '\n')
310 handler = self.ConnectionHandler(self, newconn)
311 handler.start()
312 except socket.timeout:
313 pass
314 except KeyboardInterrupt:
315 self.stop()
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000316 except:
Bill Janssen98d19da2007-09-10 21:51:02 +0000317 if self.chatty:
318 handle_error("Test server failure:\n")
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000319
Bill Janssen98d19da2007-09-10 21:51:02 +0000320 def stop (self):
321 self.active = False
322 self.sock.close()
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000323
Bill Janssen296a59d2007-09-16 22:06:00 +0000324
325 class AsyncoreHTTPSServer(threading.Thread):
326
327 class HTTPSServer(HTTPServer):
328
329 def __init__(self, server_address, RequestHandlerClass, certfile):
330
331 HTTPServer.__init__(self, server_address, RequestHandlerClass)
332 # we assume the certfile contains both private key and certificate
333 self.certfile = certfile
334 self.active = False
Neal Norwitz0098c9d2008-03-09 19:03:42 +0000335 self.active_lock = threading.Lock()
Bill Janssen296a59d2007-09-16 22:06:00 +0000336 self.allow_reuse_address = True
337
338 def get_request (self):
339 # override this to wrap socket with SSL
340 sock, addr = self.socket.accept()
341 sslconn = ssl.wrap_socket(sock, server_side=True,
342 certfile=self.certfile)
343 return sslconn, addr
344
345 # The methods overridden below this are mainly so that we
346 # can run it in a thread and be able to stop it from another
347 # You probably wouldn't need them in other uses.
348
349 def server_activate(self):
350 # We want to run this in a thread for testing purposes,
351 # so we override this to set timeout, so that we get
352 # a chance to stop the server
353 self.socket.settimeout(0.5)
354 HTTPServer.server_activate(self)
355
356 def serve_forever(self):
357 # We want this to run in a thread, so we use a slightly
358 # modified version of "forever".
359 self.active = True
Neal Norwitz0098c9d2008-03-09 19:03:42 +0000360 while 1:
Bill Janssen296a59d2007-09-16 22:06:00 +0000361 try:
Neal Norwitz0098c9d2008-03-09 19:03:42 +0000362 # We need to lock while handling the request.
363 # Another thread can close the socket after self.active
364 # has been checked and before the request is handled.
365 # This causes an exception when using the closed socket.
366 with self.active_lock:
367 if not self.active:
368 break
369 self.handle_request()
Bill Janssen296a59d2007-09-16 22:06:00 +0000370 except socket.timeout:
371 pass
372 except KeyboardInterrupt:
373 self.server_close()
374 return
375 except:
Neal Norwitz0098c9d2008-03-09 19:03:42 +0000376 sys.stdout.write(''.join(traceback.format_exception(*sys.exc_info())))
377 break
Neal Norwitzd0a91af2008-04-02 05:54:27 +0000378 time.sleep(0.1)
Bill Janssen296a59d2007-09-16 22:06:00 +0000379
380 def server_close(self):
381 # Again, we want this to run in a thread, so we need to override
382 # close to clear the "active" flag, so that serve_forever() will
383 # terminate.
Neal Norwitz0098c9d2008-03-09 19:03:42 +0000384 with self.active_lock:
385 HTTPServer.server_close(self)
386 self.active = False
Bill Janssen296a59d2007-09-16 22:06:00 +0000387
388 class RootedHTTPRequestHandler(SimpleHTTPRequestHandler):
389
390 # need to override translate_path to get a known root,
391 # instead of using os.curdir, since the test could be
392 # run from anywhere
393
394 server_version = "TestHTTPS/1.0"
395
396 root = None
397
398 def translate_path(self, path):
399 """Translate a /-separated PATH to the local filename syntax.
400
401 Components that mean special things to the local file system
402 (e.g. drive or directory names) are ignored. (XXX They should
403 probably be diagnosed.)
404
405 """
406 # abandon query parameters
407 path = urlparse.urlparse(path)[2]
408 path = os.path.normpath(urllib.unquote(path))
409 words = path.split('/')
410 words = filter(None, words)
411 path = self.root
412 for word in words:
413 drive, word = os.path.splitdrive(word)
414 head, word = os.path.split(word)
415 if word in self.root: continue
416 path = os.path.join(path, word)
417 return path
418
419 def log_message(self, format, *args):
420
421 # we override this to suppress logging unless "verbose"
422
423 if test_support.verbose:
424 sys.stdout.write(" server (%s, %d, %s):\n [%s] %s\n" %
425 (self.server.server_name,
426 self.server.server_port,
427 self.request.cipher(),
428 self.log_date_time_string(),
429 format%args))
430
431
Trent Nelsone41b0062008-04-08 23:47:30 +0000432 def __init__(self, certfile):
Bill Janssen296a59d2007-09-16 22:06:00 +0000433 self.flag = None
434 self.active = False
435 self.RootedHTTPRequestHandler.root = os.path.split(CERTFILE)[0]
Trent Nelsone41b0062008-04-08 23:47:30 +0000436 self.port = test_support.find_unused_port()
Bill Janssen296a59d2007-09-16 22:06:00 +0000437 self.server = self.HTTPSServer(
Trent Nelsone41b0062008-04-08 23:47:30 +0000438 (HOST, self.port), self.RootedHTTPRequestHandler, certfile)
Bill Janssen296a59d2007-09-16 22:06:00 +0000439 threading.Thread.__init__(self)
440 self.setDaemon(True)
441
442 def __str__(self):
443 return '<%s %s:%d>' % (self.__class__.__name__,
444 self.server.server_name,
445 self.server.server_port)
446
447 def start (self, flag=None):
448 self.flag = flag
449 threading.Thread.start(self)
450
451 def run (self):
452 self.active = True
453 if self.flag:
454 self.flag.set()
455 self.server.serve_forever()
456 self.active = False
457
458 def stop (self):
459 self.active = False
460 self.server.server_close()
461
462
Bill Janssen98d19da2007-09-10 21:51:02 +0000463 def badCertTest (certfile):
Trent Nelsone41b0062008-04-08 23:47:30 +0000464 server = ThreadedEchoServer(CERTFILE,
Bill Janssen98d19da2007-09-10 21:51:02 +0000465 certreqs=ssl.CERT_REQUIRED,
466 cacerts=CERTFILE, chatty=False)
467 flag = threading.Event()
468 server.start(flag)
469 # wait for it to start
470 flag.wait()
471 # try to connect
472 try:
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000473 try:
Bill Janssen98d19da2007-09-10 21:51:02 +0000474 s = ssl.wrap_socket(socket.socket(),
475 certfile=certfile,
476 ssl_version=ssl.PROTOCOL_TLSv1)
Trent Nelsone41b0062008-04-08 23:47:30 +0000477 s.connect((HOST, server.port))
Bill Janssen98d19da2007-09-10 21:51:02 +0000478 except ssl.SSLError, x:
Neal Norwitz9eb9b102007-08-27 01:15:33 +0000479 if test_support.verbose:
Bill Janssen98d19da2007-09-10 21:51:02 +0000480 sys.stdout.write("\nSSLError is %s\n" % x[1])
481 else:
482 raise test_support.TestFailed(
483 "Use of invalid cert should have failed!")
484 finally:
485 server.stop()
486 server.join()
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000487
Bill Janssen98d19da2007-09-10 21:51:02 +0000488 def serverParamsTest (certfile, protocol, certreqs, cacertsfile,
489 client_certfile, client_protocol=None, indata="FOO\n",
490 chatty=True, connectionchatty=False):
491
Trent Nelsone41b0062008-04-08 23:47:30 +0000492 server = ThreadedEchoServer(certfile,
Bill Janssen98d19da2007-09-10 21:51:02 +0000493 certreqs=certreqs,
494 ssl_version=protocol,
495 cacerts=cacertsfile,
496 chatty=chatty,
497 connectionchatty=connectionchatty)
498 flag = threading.Event()
499 server.start(flag)
500 # wait for it to start
501 flag.wait()
502 # try to connect
503 if client_protocol is None:
504 client_protocol = protocol
505 try:
506 try:
507 s = ssl.wrap_socket(socket.socket(),
508 certfile=client_certfile,
509 ca_certs=cacertsfile,
510 cert_reqs=certreqs,
511 ssl_version=client_protocol)
Trent Nelsone41b0062008-04-08 23:47:30 +0000512 s.connect((HOST, server.port))
Bill Janssen98d19da2007-09-10 21:51:02 +0000513 except ssl.SSLError, x:
514 raise test_support.TestFailed("Unexpected SSL error: " + str(x))
515 except Exception, x:
516 raise test_support.TestFailed("Unexpected exception: " + str(x))
517 else:
518 if connectionchatty:
519 if test_support.verbose:
520 sys.stdout.write(
521 " client: sending %s...\n" % (repr(indata)))
522 s.write(indata)
523 outdata = s.read()
524 if connectionchatty:
525 if test_support.verbose:
526 sys.stdout.write(" client: read %s\n" % repr(outdata))
527 if outdata != indata.lower():
528 raise test_support.TestFailed(
529 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
530 % (outdata[:min(len(outdata),20)], len(outdata),
531 indata[:min(len(indata),20)].lower(), len(indata)))
532 s.write("over\n")
533 if connectionchatty:
534 if test_support.verbose:
535 sys.stdout.write(" client: closing connection.\n")
Bill Janssen98d19da2007-09-10 21:51:02 +0000536 s.close()
537 finally:
538 server.stop()
539 server.join()
540
541 def tryProtocolCombo (server_protocol,
542 client_protocol,
543 expectedToWork,
Bill Janssene3f1d7d2007-09-11 01:09:19 +0000544 certsreqs=None):
545
Benjamin Peterson5b63acd2008-03-29 15:24:25 +0000546 if certsreqs is None:
Bill Janssene3f1d7d2007-09-11 01:09:19 +0000547 certsreqs = ssl.CERT_NONE
Bill Janssen98d19da2007-09-10 21:51:02 +0000548
549 if certsreqs == ssl.CERT_NONE:
550 certtype = "CERT_NONE"
551 elif certsreqs == ssl.CERT_OPTIONAL:
552 certtype = "CERT_OPTIONAL"
553 elif certsreqs == ssl.CERT_REQUIRED:
554 certtype = "CERT_REQUIRED"
555 if test_support.verbose:
556 formatstr = (expectedToWork and " %s->%s %s\n") or " {%s->%s} %s\n"
557 sys.stdout.write(formatstr %
558 (ssl.get_protocol_name(client_protocol),
559 ssl.get_protocol_name(server_protocol),
560 certtype))
561 try:
562 serverParamsTest(CERTFILE, server_protocol, certsreqs,
563 CERTFILE, CERTFILE, client_protocol, chatty=False)
564 except test_support.TestFailed:
565 if expectedToWork:
566 raise
567 else:
568 if not expectedToWork:
569 raise test_support.TestFailed(
570 "Client protocol %s succeeded with server protocol %s!"
571 % (ssl.get_protocol_name(client_protocol),
572 ssl.get_protocol_name(server_protocol)))
573
574
575 class ConnectedTests(unittest.TestCase):
576
577 def testRudeShutdown(self):
578
579 listener_ready = threading.Event()
580 listener_gone = threading.Event()
Trent Nelsone41b0062008-04-08 23:47:30 +0000581 port = test_support.find_unused_port()
Bill Janssen98d19da2007-09-10 21:51:02 +0000582
583 # `listener` runs in a thread. It opens a socket listening on
584 # PORT, and sits in an accept() until the main thread connects.
585 # Then it rudely closes the socket, and sets Event `listener_gone`
586 # to let the main thread know the socket is gone.
587 def listener():
588 s = socket.socket()
Trent Nelsone41b0062008-04-08 23:47:30 +0000589 s.bind((HOST, port))
Bill Janssen98d19da2007-09-10 21:51:02 +0000590 s.listen(5)
591 listener_ready.set()
592 s.accept()
593 s = None # reclaim the socket object, which also closes it
594 listener_gone.set()
595
596 def connector():
597 listener_ready.wait()
598 s = socket.socket()
Trent Nelsone41b0062008-04-08 23:47:30 +0000599 s.connect((HOST, port))
Bill Janssen98d19da2007-09-10 21:51:02 +0000600 listener_gone.wait()
601 try:
602 ssl_sock = ssl.wrap_socket(s)
603 except socket.sslerror:
604 pass
605 else:
606 raise test_support.TestFailed(
607 'connecting to closed SSL socket should have failed')
608
609 t = threading.Thread(target=listener)
610 t.start()
611 connector()
612 t.join()
613
614 def testEcho (self):
615
616 if test_support.verbose:
617 sys.stdout.write("\n")
618 serverParamsTest(CERTFILE, ssl.PROTOCOL_TLSv1, ssl.CERT_NONE,
619 CERTFILE, CERTFILE, ssl.PROTOCOL_TLSv1,
620 chatty=True, connectionchatty=True)
621
622 def testReadCert(self):
623
624 if test_support.verbose:
625 sys.stdout.write("\n")
626 s2 = socket.socket()
Trent Nelsone41b0062008-04-08 23:47:30 +0000627 server = ThreadedEchoServer(CERTFILE,
Bill Janssen98d19da2007-09-10 21:51:02 +0000628 certreqs=ssl.CERT_NONE,
629 ssl_version=ssl.PROTOCOL_SSLv23,
630 cacerts=CERTFILE,
631 chatty=False)
632 flag = threading.Event()
633 server.start(flag)
634 # wait for it to start
635 flag.wait()
636 # try to connect
637 try:
638 try:
639 s = ssl.wrap_socket(socket.socket(),
640 certfile=CERTFILE,
641 ca_certs=CERTFILE,
642 cert_reqs=ssl.CERT_REQUIRED,
643 ssl_version=ssl.PROTOCOL_SSLv23)
Trent Nelsone41b0062008-04-08 23:47:30 +0000644 s.connect((HOST, server.port))
Bill Janssen98d19da2007-09-10 21:51:02 +0000645 except ssl.SSLError, x:
646 raise test_support.TestFailed(
647 "Unexpected SSL error: " + str(x))
648 except Exception, x:
649 raise test_support.TestFailed(
650 "Unexpected exception: " + str(x))
651 else:
652 if not s:
653 raise test_support.TestFailed(
654 "Can't SSL-handshake with test server")
655 cert = s.getpeercert()
656 if not cert:
657 raise test_support.TestFailed(
658 "Can't get peer certificate.")
659 cipher = s.cipher()
660 if test_support.verbose:
661 sys.stdout.write(pprint.pformat(cert) + '\n')
662 sys.stdout.write("Connection cipher is " + str(cipher) + '.\n')
663 if not cert.has_key('subject'):
664 raise test_support.TestFailed(
665 "No subject field in certificate: %s." %
666 pprint.pformat(cert))
667 if ((('organizationName', 'Python Software Foundation'),)
668 not in cert['subject']):
669 raise test_support.TestFailed(
670 "Missing or invalid 'organizationName' field in certificate subject; "
Neal Norwitz0098c9d2008-03-09 19:03:42 +0000671 "should be 'Python Software Foundation'.")
Bill Janssen98d19da2007-09-10 21:51:02 +0000672 s.close()
673 finally:
674 server.stop()
675 server.join()
676
677 def testNULLcert(self):
678 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
679 "nullcert.pem"))
680 def testMalformedCert(self):
681 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
682 "badcert.pem"))
683 def testMalformedKey(self):
684 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
685 "badkey.pem"))
686
687 def testProtocolSSL2(self):
688 if test_support.verbose:
689 sys.stdout.write("\n")
690 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True)
691 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL)
692 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED)
693 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True)
694 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False)
695 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False)
696
697 def testProtocolSSL23(self):
698 if test_support.verbose:
699 sys.stdout.write("\n")
700 try:
701 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv2, True)
702 except test_support.TestFailed, x:
703 # this fails on some older versions of OpenSSL (0.9.7l, for instance)
704 if test_support.verbose:
705 sys.stdout.write(
706 " SSL2 client to SSL23 server test unexpectedly failed:\n %s\n"
707 % str(x))
708 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True)
709 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True)
710 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True)
711
712 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
713 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_OPTIONAL)
714 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
715
716 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
717 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_REQUIRED)
718 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
719
720 def testProtocolSSL3(self):
721 if test_support.verbose:
722 sys.stdout.write("\n")
723 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True)
724 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
725 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
726 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False)
727 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, False)
728 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False)
729
730 def testProtocolTLS1(self):
731 if test_support.verbose:
732 sys.stdout.write("\n")
733 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True)
734 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
735 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
736 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False)
737 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False)
738 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv23, False)
739
740 def testSTARTTLS (self):
741
742 msgs = ("msg 1", "MSG 2", "STARTTLS", "MSG 3", "msg 4")
743
Trent Nelsone41b0062008-04-08 23:47:30 +0000744 server = ThreadedEchoServer(CERTFILE,
Bill Janssen98d19da2007-09-10 21:51:02 +0000745 ssl_version=ssl.PROTOCOL_TLSv1,
746 starttls_server=True,
747 chatty=True,
748 connectionchatty=True)
749 flag = threading.Event()
750 server.start(flag)
751 # wait for it to start
752 flag.wait()
753 # try to connect
754 wrapped = False
755 try:
756 try:
757 s = socket.socket()
758 s.setblocking(1)
Trent Nelsone41b0062008-04-08 23:47:30 +0000759 s.connect((HOST, server.port))
Bill Janssen98d19da2007-09-10 21:51:02 +0000760 except Exception, x:
761 raise test_support.TestFailed("Unexpected exception: " + str(x))
762 else:
763 if test_support.verbose:
764 sys.stdout.write("\n")
765 for indata in msgs:
766 if test_support.verbose:
Bill Janssen296a59d2007-09-16 22:06:00 +0000767 sys.stdout.write(
768 " client: sending %s...\n" % repr(indata))
Bill Janssen98d19da2007-09-10 21:51:02 +0000769 if wrapped:
770 conn.write(indata)
771 outdata = conn.read()
772 else:
773 s.send(indata)
774 outdata = s.recv(1024)
Bill Janssen296a59d2007-09-16 22:06:00 +0000775 if (indata == "STARTTLS" and
776 outdata.strip().lower().startswith("ok")):
Bill Janssen98d19da2007-09-10 21:51:02 +0000777 if test_support.verbose:
Bill Janssen296a59d2007-09-16 22:06:00 +0000778 sys.stdout.write(
779 " client: read %s from server, starting TLS...\n"
780 % repr(outdata))
Bill Janssen98d19da2007-09-10 21:51:02 +0000781 conn = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1)
782
783 wrapped = True
784 else:
785 if test_support.verbose:
Bill Janssen296a59d2007-09-16 22:06:00 +0000786 sys.stdout.write(
787 " client: read %s from server\n" % repr(outdata))
Bill Janssen98d19da2007-09-10 21:51:02 +0000788 if test_support.verbose:
789 sys.stdout.write(" client: closing connection.\n")
790 if wrapped:
791 conn.write("over\n")
Bill Janssen98d19da2007-09-10 21:51:02 +0000792 else:
793 s.send("over\n")
794 s.close()
795 finally:
796 server.stop()
797 server.join()
798
Bill Janssen296a59d2007-09-16 22:06:00 +0000799 def testAsyncore(self):
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000800
Trent Nelsone41b0062008-04-08 23:47:30 +0000801 server = AsyncoreHTTPSServer(CERTFILE)
Bill Janssen296a59d2007-09-16 22:06:00 +0000802 flag = threading.Event()
803 server.start(flag)
804 # wait for it to start
805 flag.wait()
806 # try to connect
807 try:
808 if test_support.verbose:
809 sys.stdout.write('\n')
Bill Janssenbf10c472007-09-16 23:16:46 +0000810 d1 = open(CERTFILE, 'rb').read()
Bill Janssen296a59d2007-09-16 22:06:00 +0000811 d2 = ''
812 # now fetch the same data from the HTTPS server
Trent Nelsone41b0062008-04-08 23:47:30 +0000813 url = 'https://%s:%d/%s' % (
814 HOST, server.port, os.path.split(CERTFILE)[1])
Bill Janssen296a59d2007-09-16 22:06:00 +0000815 f = urllib.urlopen(url)
816 dlen = f.info().getheader("content-length")
817 if dlen and (int(dlen) > 0):
818 d2 = f.read(int(dlen))
819 if test_support.verbose:
820 sys.stdout.write(
821 " client: read %d bytes from remote server '%s'\n"
822 % (len(d2), server))
823 f.close()
824 except:
825 msg = ''.join(traceback.format_exception(*sys.exc_info()))
826 if test_support.verbose:
827 sys.stdout.write('\n' + msg)
828 raise test_support.TestFailed(msg)
829 else:
830 if not (d1 == d2):
831 raise test_support.TestFailed(
832 "Couldn't fetch data from HTTPS server")
833 finally:
834 server.stop()
835 server.join()
Neal Norwitz7fc8e292007-08-26 18:50:39 +0000836
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000837
Neal Norwitz9eb9b102007-08-27 01:15:33 +0000838def test_main(verbose=False):
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000839 if skip_expected:
Bill Janssenffe576d2007-09-05 00:46:27 +0000840 raise test_support.TestSkipped("No SSL support")
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000841
Trent Nelsone41b0062008-04-08 23:47:30 +0000842 global CERTFILE, SVN_PYTHON_ORG_ROOT_CERT
Guido van Rossumba8c5652007-08-27 17:19:42 +0000843 CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir,
Bill Janssen296a59d2007-09-16 22:06:00 +0000844 "keycert.pem")
845 SVN_PYTHON_ORG_ROOT_CERT = os.path.join(
846 os.path.dirname(__file__) or os.curdir,
847 "https_svn_python_org_root.pem")
848
849 if (not os.path.exists(CERTFILE) or
850 not os.path.exists(SVN_PYTHON_ORG_ROOT_CERT)):
Bill Janssen98d19da2007-09-10 21:51:02 +0000851 raise test_support.TestFailed("Can't read certificate files!")
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000852
853 tests = [BasicTests]
854
Bill Janssen296a59d2007-09-16 22:06:00 +0000855 if test_support.is_resource_enabled('network'):
856 tests.append(NetworkTests)
857
Bill Janssen98d19da2007-09-10 21:51:02 +0000858 if _have_threads:
859 thread_info = test_support.threading_setup()
Bill Janssen296a59d2007-09-16 22:06:00 +0000860 if thread_info and test_support.is_resource_enabled('network'):
Bill Janssen98d19da2007-09-10 21:51:02 +0000861 tests.append(ConnectedTests)
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000862
Bill Janssen98d19da2007-09-10 21:51:02 +0000863 test_support.run_unittest(*tests)
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000864
Bill Janssen98d19da2007-09-10 21:51:02 +0000865 if _have_threads:
866 test_support.threading_cleanup(*thread_info)
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000867
868if __name__ == "__main__":
869 test_main()