blob: 8f8212a8b3323966b3072ea8aabfbda3497031e3 [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
26CERTFILE = None
Bill Janssen296a59d2007-09-16 22:06:00 +000027SVN_PYTHON_ORG_ROOT_CERT = None
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +000028
Bill Janssen98d19da2007-09-10 21:51:02 +000029TESTPORT = 10025
Neal Norwitz3e533c22007-08-27 01:03:18 +000030
31def handle_error(prefix):
32 exc_format = ' '.join(traceback.format_exception(*sys.exc_info()))
Bill Janssen98d19da2007-09-10 21:51:02 +000033 if test_support.verbose:
34 sys.stdout.write(prefix + exc_format)
Neal Norwitz3e533c22007-08-27 01:03:18 +000035
36
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +000037class BasicTests(unittest.TestCase):
38
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +000039 def testSSLconnect(self):
Christian Heimes6c29be52008-01-19 16:39:27 +000040 if not test_support.is_resource_enabled('network'):
41 return
Bill Janssen296a59d2007-09-16 22:06:00 +000042 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:
47 raise test_support.TestFailed("Peer cert %s shouldn't be here!")
48 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:
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +000058 s.close()
59
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +000060
Bill Janssen98d19da2007-09-10 21:51:02 +000061 def testCrucialConstants(self):
62 ssl.PROTOCOL_SSLv2
63 ssl.PROTOCOL_SSLv23
64 ssl.PROTOCOL_SSLv3
65 ssl.PROTOCOL_TLSv1
66 ssl.CERT_NONE
67 ssl.CERT_OPTIONAL
68 ssl.CERT_REQUIRED
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +000069
Bill Janssen98d19da2007-09-10 21:51:02 +000070 def testRAND(self):
71 v = ssl.RAND_status()
72 if test_support.verbose:
73 sys.stdout.write("\n RAND_status is %d (%s)\n"
74 % (v, (v and "sufficient randomness") or
75 "insufficient randomness"))
Guido van Rossume4729332007-08-26 19:35:09 +000076 try:
Bill Janssen98d19da2007-09-10 21:51:02 +000077 ssl.RAND_egd(1)
78 except TypeError:
79 pass
Guido van Rossume4729332007-08-26 19:35:09 +000080 else:
Bill Janssen98d19da2007-09-10 21:51:02 +000081 print "didn't raise TypeError"
82 ssl.RAND_add("this is a random string", 75.0)
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +000083
Bill Janssen98d19da2007-09-10 21:51:02 +000084 def testParseCert(self):
85 # note that this uses an 'unofficial' function in _ssl.c,
86 # provided solely for this test, to exercise the certificate
87 # parsing code
88 p = ssl._ssl._test_decode_cert(CERTFILE, False)
89 if test_support.verbose:
90 sys.stdout.write("\n" + pprint.pformat(p) + "\n")
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +000091
Bill Janssen296a59d2007-09-16 22:06:00 +000092 def testDERtoPEM(self):
93
94 pem = open(SVN_PYTHON_ORG_ROOT_CERT, 'r').read()
95 d1 = ssl.PEM_cert_to_DER_cert(pem)
96 p2 = ssl.DER_cert_to_PEM_cert(d1)
97 d2 = ssl.PEM_cert_to_DER_cert(p2)
98 if (d1 != d2):
99 raise test_support.TestFailed("PEM-to-DER or DER-to-PEM translation failed")
100
101
102class NetworkTests(unittest.TestCase):
103
104 def testConnect(self):
Bill Janssen296a59d2007-09-16 22:06:00 +0000105 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
106 cert_reqs=ssl.CERT_NONE)
107 s.connect(("svn.python.org", 443))
108 c = s.getpeercert()
109 if c:
110 raise test_support.TestFailed("Peer cert %s shouldn't be here!")
111 s.close()
112
113 # this should fail because we have no verification certs
114 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
115 cert_reqs=ssl.CERT_REQUIRED)
116 try:
117 s.connect(("svn.python.org", 443))
118 except ssl.SSLError:
119 pass
120 finally:
121 s.close()
122
123 # this should succeed because we specify the root cert
124 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
125 cert_reqs=ssl.CERT_REQUIRED,
126 ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
127 try:
128 s.connect(("svn.python.org", 443))
129 except ssl.SSLError, x:
130 raise test_support.TestFailed("Unexpected exception %s" % x)
131 finally:
132 s.close()
133
134 def testFetchServerCert(self):
135
136 pem = ssl.get_server_certificate(("svn.python.org", 443))
137 if not pem:
138 raise test_support.TestFailed("No server certificate on svn.python.org:443!")
139
140 try:
141 pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=CERTFILE)
142 except ssl.SSLError:
143 #should fail
144 pass
145 else:
146 raise test_support.TestFailed("Got server certificate %s for svn.python.org!" % pem)
147
148 pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
149 if not pem:
150 raise test_support.TestFailed("No server certificate on svn.python.org:443!")
151 if test_support.verbose:
152 sys.stdout.write("\nVerified certificate for svn.python.org:443 is\n%s\n" % pem)
153
154
Bill Janssen98d19da2007-09-10 21:51:02 +0000155try:
156 import threading
157except ImportError:
158 _have_threads = False
159else:
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000160
Bill Janssen98d19da2007-09-10 21:51:02 +0000161 _have_threads = True
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000162
Bill Janssen98d19da2007-09-10 21:51:02 +0000163 class ThreadedEchoServer(threading.Thread):
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000164
Bill Janssen98d19da2007-09-10 21:51:02 +0000165 class ConnectionHandler(threading.Thread):
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000166
Bill Janssen98d19da2007-09-10 21:51:02 +0000167 """A mildly complicated class, because we want it to work both
168 with and without the SSL wrapper around the socket connection, so
169 that we can test the STARTTLS functionality."""
170
171 def __init__(self, server, connsock):
172 self.server = server
173 self.running = False
174 self.sock = connsock
175 self.sock.setblocking(1)
176 self.sslconn = None
177 threading.Thread.__init__(self)
178 self.setDaemon(True)
179
180 def wrap_conn (self):
181 try:
182 self.sslconn = ssl.wrap_socket(self.sock, server_side=True,
183 certfile=self.server.certificate,
184 ssl_version=self.server.protocol,
185 ca_certs=self.server.cacerts,
186 cert_reqs=self.server.certreqs)
187 except:
188 if self.server.chatty:
189 handle_error("\n server: bad connection attempt from " +
190 str(self.sock.getpeername()) + ":\n")
191 if not self.server.expect_bad_connects:
192 # here, we want to stop the server, because this shouldn't
193 # happen in the context of our test case
194 self.running = False
195 # normally, we'd just stop here, but for the test
196 # harness, we want to stop the server
197 self.server.stop()
198 return False
199
200 else:
201 if self.server.certreqs == ssl.CERT_REQUIRED:
202 cert = self.sslconn.getpeercert()
203 if test_support.verbose and self.server.chatty:
204 sys.stdout.write(" client cert is " + pprint.pformat(cert) + "\n")
205 cert_binary = self.sslconn.getpeercert(True)
206 if test_support.verbose and self.server.chatty:
207 sys.stdout.write(" cert binary is " + str(len(cert_binary)) + " bytes\n")
208 cipher = self.sslconn.cipher()
209 if test_support.verbose and self.server.chatty:
210 sys.stdout.write(" server: connection cipher is now " + str(cipher) + "\n")
211 return True
212
213 def read(self):
214 if self.sslconn:
215 return self.sslconn.read()
216 else:
217 return self.sock.recv(1024)
218
219 def write(self, bytes):
220 if self.sslconn:
221 return self.sslconn.write(bytes)
222 else:
223 return self.sock.send(bytes)
224
225 def close(self):
226 if self.sslconn:
227 self.sslconn.close()
228 else:
229 self.sock.close()
230
231 def run (self):
232 self.running = True
233 if not self.server.starttls_server:
234 if not self.wrap_conn():
235 return
236 while self.running:
237 try:
238 msg = self.read()
239 if not msg:
240 # eof, so quit this handler
241 self.running = False
242 self.close()
243 elif msg.strip() == 'over':
244 if test_support.verbose and self.server.connectionchatty:
245 sys.stdout.write(" server: client closed connection\n")
246 self.close()
247 return
248 elif self.server.starttls_server and msg.strip() == 'STARTTLS':
249 if test_support.verbose and self.server.connectionchatty:
250 sys.stdout.write(" server: read STARTTLS from client, sending OK...\n")
251 self.write("OK\n")
252 if not self.wrap_conn():
253 return
254 else:
255 if (test_support.verbose and
256 self.server.connectionchatty):
257 ctype = (self.sslconn and "encrypted") or "unencrypted"
258 sys.stdout.write(" server: read %s (%s), sending back %s (%s)...\n"
259 % (repr(msg), ctype, repr(msg.lower()), ctype))
260 self.write(msg.lower())
261 except ssl.SSLError:
262 if self.server.chatty:
263 handle_error("Test server failure:\n")
264 self.close()
265 self.running = False
266 # normally, we'd just stop here, but for the test
267 # harness, we want to stop the server
268 self.server.stop()
269 except:
270 handle_error('')
271
272 def __init__(self, port, certificate, ssl_version=None,
273 certreqs=None, cacerts=None, expect_bad_connects=False,
274 chatty=True, connectionchatty=False, starttls_server=False):
275 if ssl_version is None:
276 ssl_version = ssl.PROTOCOL_TLSv1
277 if certreqs is None:
278 certreqs = ssl.CERT_NONE
279 self.certificate = certificate
280 self.protocol = ssl_version
281 self.certreqs = certreqs
282 self.cacerts = cacerts
283 self.expect_bad_connects = expect_bad_connects
284 self.chatty = chatty
285 self.connectionchatty = connectionchatty
286 self.starttls_server = starttls_server
287 self.sock = socket.socket()
288 self.flag = None
289 if hasattr(socket, 'SO_REUSEADDR'):
290 self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
291 if hasattr(socket, 'SO_REUSEPORT'):
292 self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
293 self.sock.bind(('127.0.0.1', port))
294 self.active = False
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000295 threading.Thread.__init__(self)
Bill Janssen98d19da2007-09-10 21:51:02 +0000296 self.setDaemon(False)
297
298 def start (self, flag=None):
299 self.flag = flag
300 threading.Thread.start(self)
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000301
302 def run (self):
Bill Janssen98d19da2007-09-10 21:51:02 +0000303 self.sock.settimeout(0.5)
304 self.sock.listen(5)
305 self.active = True
306 if self.flag:
307 # signal an event
308 self.flag.set()
309 while self.active:
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000310 try:
Bill Janssen98d19da2007-09-10 21:51:02 +0000311 newconn, connaddr = self.sock.accept()
312 if test_support.verbose and self.chatty:
313 sys.stdout.write(' server: new connection from '
314 + str(connaddr) + '\n')
315 handler = self.ConnectionHandler(self, newconn)
316 handler.start()
317 except socket.timeout:
318 pass
319 except KeyboardInterrupt:
320 self.stop()
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000321 except:
Bill Janssen98d19da2007-09-10 21:51:02 +0000322 if self.chatty:
323 handle_error("Test server failure:\n")
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000324
Bill Janssen98d19da2007-09-10 21:51:02 +0000325 def stop (self):
326 self.active = False
327 self.sock.close()
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000328
Bill Janssen296a59d2007-09-16 22:06:00 +0000329
330 class AsyncoreHTTPSServer(threading.Thread):
331
332 class HTTPSServer(HTTPServer):
333
334 def __init__(self, server_address, RequestHandlerClass, certfile):
335
336 HTTPServer.__init__(self, server_address, RequestHandlerClass)
337 # we assume the certfile contains both private key and certificate
338 self.certfile = certfile
339 self.active = False
Neal Norwitz0098c9d2008-03-09 19:03:42 +0000340 self.active_lock = threading.Lock()
Bill Janssen296a59d2007-09-16 22:06:00 +0000341 self.allow_reuse_address = True
342
343 def get_request (self):
344 # override this to wrap socket with SSL
345 sock, addr = self.socket.accept()
346 sslconn = ssl.wrap_socket(sock, server_side=True,
347 certfile=self.certfile)
348 return sslconn, addr
349
350 # The methods overridden below this are mainly so that we
351 # can run it in a thread and be able to stop it from another
352 # You probably wouldn't need them in other uses.
353
354 def server_activate(self):
355 # We want to run this in a thread for testing purposes,
356 # so we override this to set timeout, so that we get
357 # a chance to stop the server
358 self.socket.settimeout(0.5)
359 HTTPServer.server_activate(self)
360
361 def serve_forever(self):
362 # We want this to run in a thread, so we use a slightly
363 # modified version of "forever".
364 self.active = True
Neal Norwitz0098c9d2008-03-09 19:03:42 +0000365 while 1:
Bill Janssen296a59d2007-09-16 22:06:00 +0000366 try:
Neal Norwitz0098c9d2008-03-09 19:03:42 +0000367 # We need to lock while handling the request.
368 # Another thread can close the socket after self.active
369 # has been checked and before the request is handled.
370 # This causes an exception when using the closed socket.
371 with self.active_lock:
372 if not self.active:
373 break
374 self.handle_request()
Bill Janssen296a59d2007-09-16 22:06:00 +0000375 except socket.timeout:
376 pass
377 except KeyboardInterrupt:
378 self.server_close()
379 return
380 except:
Neal Norwitz0098c9d2008-03-09 19:03:42 +0000381 sys.stdout.write(''.join(traceback.format_exception(*sys.exc_info())))
382 break
Neal Norwitzd0a91af2008-04-02 05:54:27 +0000383 time.sleep(0.1)
Bill Janssen296a59d2007-09-16 22:06:00 +0000384
385 def server_close(self):
386 # Again, we want this to run in a thread, so we need to override
387 # close to clear the "active" flag, so that serve_forever() will
388 # terminate.
Neal Norwitz0098c9d2008-03-09 19:03:42 +0000389 with self.active_lock:
390 HTTPServer.server_close(self)
391 self.active = False
Bill Janssen296a59d2007-09-16 22:06:00 +0000392
393 class RootedHTTPRequestHandler(SimpleHTTPRequestHandler):
394
395 # need to override translate_path to get a known root,
396 # instead of using os.curdir, since the test could be
397 # run from anywhere
398
399 server_version = "TestHTTPS/1.0"
400
401 root = None
402
403 def translate_path(self, path):
404 """Translate a /-separated PATH to the local filename syntax.
405
406 Components that mean special things to the local file system
407 (e.g. drive or directory names) are ignored. (XXX They should
408 probably be diagnosed.)
409
410 """
411 # abandon query parameters
412 path = urlparse.urlparse(path)[2]
413 path = os.path.normpath(urllib.unquote(path))
414 words = path.split('/')
415 words = filter(None, words)
416 path = self.root
417 for word in words:
418 drive, word = os.path.splitdrive(word)
419 head, word = os.path.split(word)
420 if word in self.root: continue
421 path = os.path.join(path, word)
422 return path
423
424 def log_message(self, format, *args):
425
426 # we override this to suppress logging unless "verbose"
427
428 if test_support.verbose:
429 sys.stdout.write(" server (%s, %d, %s):\n [%s] %s\n" %
430 (self.server.server_name,
431 self.server.server_port,
432 self.request.cipher(),
433 self.log_date_time_string(),
434 format%args))
435
436
437 def __init__(self, port, certfile):
438 self.flag = None
439 self.active = False
440 self.RootedHTTPRequestHandler.root = os.path.split(CERTFILE)[0]
441 self.server = self.HTTPSServer(
442 ('', port), self.RootedHTTPRequestHandler, certfile)
443 threading.Thread.__init__(self)
444 self.setDaemon(True)
445
446 def __str__(self):
447 return '<%s %s:%d>' % (self.__class__.__name__,
448 self.server.server_name,
449 self.server.server_port)
450
451 def start (self, flag=None):
452 self.flag = flag
453 threading.Thread.start(self)
454
455 def run (self):
456 self.active = True
457 if self.flag:
458 self.flag.set()
459 self.server.serve_forever()
460 self.active = False
461
462 def stop (self):
463 self.active = False
464 self.server.server_close()
465
466
Bill Janssen98d19da2007-09-10 21:51:02 +0000467 def badCertTest (certfile):
468 server = ThreadedEchoServer(TESTPORT, CERTFILE,
469 certreqs=ssl.CERT_REQUIRED,
470 cacerts=CERTFILE, chatty=False)
471 flag = threading.Event()
472 server.start(flag)
473 # wait for it to start
474 flag.wait()
475 # try to connect
476 try:
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000477 try:
Bill Janssen98d19da2007-09-10 21:51:02 +0000478 s = ssl.wrap_socket(socket.socket(),
479 certfile=certfile,
480 ssl_version=ssl.PROTOCOL_TLSv1)
481 s.connect(('127.0.0.1', TESTPORT))
482 except ssl.SSLError, x:
Neal Norwitz9eb9b102007-08-27 01:15:33 +0000483 if test_support.verbose:
Bill Janssen98d19da2007-09-10 21:51:02 +0000484 sys.stdout.write("\nSSLError is %s\n" % x[1])
485 else:
486 raise test_support.TestFailed(
487 "Use of invalid cert should have failed!")
488 finally:
489 server.stop()
490 server.join()
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000491
Bill Janssen98d19da2007-09-10 21:51:02 +0000492 def serverParamsTest (certfile, protocol, certreqs, cacertsfile,
493 client_certfile, client_protocol=None, indata="FOO\n",
494 chatty=True, connectionchatty=False):
495
496 server = ThreadedEchoServer(TESTPORT, certfile,
497 certreqs=certreqs,
498 ssl_version=protocol,
499 cacerts=cacertsfile,
500 chatty=chatty,
501 connectionchatty=connectionchatty)
502 flag = threading.Event()
503 server.start(flag)
504 # wait for it to start
505 flag.wait()
506 # try to connect
507 if client_protocol is None:
508 client_protocol = protocol
509 try:
510 try:
511 s = ssl.wrap_socket(socket.socket(),
512 certfile=client_certfile,
513 ca_certs=cacertsfile,
514 cert_reqs=certreqs,
515 ssl_version=client_protocol)
516 s.connect(('127.0.0.1', TESTPORT))
517 except ssl.SSLError, x:
518 raise test_support.TestFailed("Unexpected SSL error: " + str(x))
519 except Exception, x:
520 raise test_support.TestFailed("Unexpected exception: " + str(x))
521 else:
522 if connectionchatty:
523 if test_support.verbose:
524 sys.stdout.write(
525 " client: sending %s...\n" % (repr(indata)))
526 s.write(indata)
527 outdata = s.read()
528 if connectionchatty:
529 if test_support.verbose:
530 sys.stdout.write(" client: read %s\n" % repr(outdata))
531 if outdata != indata.lower():
532 raise test_support.TestFailed(
533 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
534 % (outdata[:min(len(outdata),20)], len(outdata),
535 indata[:min(len(indata),20)].lower(), len(indata)))
536 s.write("over\n")
537 if connectionchatty:
538 if test_support.verbose:
539 sys.stdout.write(" client: closing connection.\n")
Bill Janssen98d19da2007-09-10 21:51:02 +0000540 s.close()
541 finally:
542 server.stop()
543 server.join()
544
545 def tryProtocolCombo (server_protocol,
546 client_protocol,
547 expectedToWork,
Bill Janssene3f1d7d2007-09-11 01:09:19 +0000548 certsreqs=None):
549
Benjamin Peterson5b63acd2008-03-29 15:24:25 +0000550 if certsreqs is None:
Bill Janssene3f1d7d2007-09-11 01:09:19 +0000551 certsreqs = ssl.CERT_NONE
Bill Janssen98d19da2007-09-10 21:51:02 +0000552
553 if certsreqs == ssl.CERT_NONE:
554 certtype = "CERT_NONE"
555 elif certsreqs == ssl.CERT_OPTIONAL:
556 certtype = "CERT_OPTIONAL"
557 elif certsreqs == ssl.CERT_REQUIRED:
558 certtype = "CERT_REQUIRED"
559 if test_support.verbose:
560 formatstr = (expectedToWork and " %s->%s %s\n") or " {%s->%s} %s\n"
561 sys.stdout.write(formatstr %
562 (ssl.get_protocol_name(client_protocol),
563 ssl.get_protocol_name(server_protocol),
564 certtype))
565 try:
566 serverParamsTest(CERTFILE, server_protocol, certsreqs,
567 CERTFILE, CERTFILE, client_protocol, chatty=False)
568 except test_support.TestFailed:
569 if expectedToWork:
570 raise
571 else:
572 if not expectedToWork:
573 raise test_support.TestFailed(
574 "Client protocol %s succeeded with server protocol %s!"
575 % (ssl.get_protocol_name(client_protocol),
576 ssl.get_protocol_name(server_protocol)))
577
578
579 class ConnectedTests(unittest.TestCase):
580
581 def testRudeShutdown(self):
582
583 listener_ready = threading.Event()
584 listener_gone = threading.Event()
585
586 # `listener` runs in a thread. It opens a socket listening on
587 # PORT, and sits in an accept() until the main thread connects.
588 # Then it rudely closes the socket, and sets Event `listener_gone`
589 # to let the main thread know the socket is gone.
590 def listener():
591 s = socket.socket()
Bill Janssen119c7a62007-09-10 23:41:24 +0000592 if hasattr(socket, 'SO_REUSEADDR'):
593 s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
Bill Janssen98d19da2007-09-10 21:51:02 +0000594 if hasattr(socket, 'SO_REUSEPORT'):
595 s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
Bill Janssen296a59d2007-09-16 22:06:00 +0000596 s.bind(('127.0.0.1', TESTPORT))
Bill Janssen98d19da2007-09-10 21:51:02 +0000597 s.listen(5)
598 listener_ready.set()
599 s.accept()
600 s = None # reclaim the socket object, which also closes it
601 listener_gone.set()
602
603 def connector():
604 listener_ready.wait()
605 s = socket.socket()
Bill Janssen119c7a62007-09-10 23:41:24 +0000606 s.connect(('127.0.0.1', TESTPORT))
Bill Janssen98d19da2007-09-10 21:51:02 +0000607 listener_gone.wait()
608 try:
609 ssl_sock = ssl.wrap_socket(s)
610 except socket.sslerror:
611 pass
612 else:
613 raise test_support.TestFailed(
614 'connecting to closed SSL socket should have failed')
615
616 t = threading.Thread(target=listener)
617 t.start()
618 connector()
619 t.join()
620
621 def testEcho (self):
622
623 if test_support.verbose:
624 sys.stdout.write("\n")
625 serverParamsTest(CERTFILE, ssl.PROTOCOL_TLSv1, ssl.CERT_NONE,
626 CERTFILE, CERTFILE, ssl.PROTOCOL_TLSv1,
627 chatty=True, connectionchatty=True)
628
629 def testReadCert(self):
630
631 if test_support.verbose:
632 sys.stdout.write("\n")
633 s2 = socket.socket()
634 server = ThreadedEchoServer(TESTPORT, CERTFILE,
635 certreqs=ssl.CERT_NONE,
636 ssl_version=ssl.PROTOCOL_SSLv23,
637 cacerts=CERTFILE,
638 chatty=False)
639 flag = threading.Event()
640 server.start(flag)
641 # wait for it to start
642 flag.wait()
643 # try to connect
644 try:
645 try:
646 s = ssl.wrap_socket(socket.socket(),
647 certfile=CERTFILE,
648 ca_certs=CERTFILE,
649 cert_reqs=ssl.CERT_REQUIRED,
650 ssl_version=ssl.PROTOCOL_SSLv23)
651 s.connect(('127.0.0.1', TESTPORT))
652 except ssl.SSLError, x:
653 raise test_support.TestFailed(
654 "Unexpected SSL error: " + str(x))
655 except Exception, x:
656 raise test_support.TestFailed(
657 "Unexpected exception: " + str(x))
658 else:
659 if not s:
660 raise test_support.TestFailed(
661 "Can't SSL-handshake with test server")
662 cert = s.getpeercert()
663 if not cert:
664 raise test_support.TestFailed(
665 "Can't get peer certificate.")
666 cipher = s.cipher()
667 if test_support.verbose:
668 sys.stdout.write(pprint.pformat(cert) + '\n')
669 sys.stdout.write("Connection cipher is " + str(cipher) + '.\n')
670 if not cert.has_key('subject'):
671 raise test_support.TestFailed(
672 "No subject field in certificate: %s." %
673 pprint.pformat(cert))
674 if ((('organizationName', 'Python Software Foundation'),)
675 not in cert['subject']):
676 raise test_support.TestFailed(
677 "Missing or invalid 'organizationName' field in certificate subject; "
Neal Norwitz0098c9d2008-03-09 19:03:42 +0000678 "should be 'Python Software Foundation'.")
Bill Janssen98d19da2007-09-10 21:51:02 +0000679 s.close()
680 finally:
681 server.stop()
682 server.join()
683
684 def testNULLcert(self):
685 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
686 "nullcert.pem"))
687 def testMalformedCert(self):
688 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
689 "badcert.pem"))
690 def testMalformedKey(self):
691 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
692 "badkey.pem"))
693
694 def testProtocolSSL2(self):
695 if test_support.verbose:
696 sys.stdout.write("\n")
697 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True)
698 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL)
699 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED)
700 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True)
701 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False)
702 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False)
703
704 def testProtocolSSL23(self):
705 if test_support.verbose:
706 sys.stdout.write("\n")
707 try:
708 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv2, True)
709 except test_support.TestFailed, x:
710 # this fails on some older versions of OpenSSL (0.9.7l, for instance)
711 if test_support.verbose:
712 sys.stdout.write(
713 " SSL2 client to SSL23 server test unexpectedly failed:\n %s\n"
714 % str(x))
715 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True)
716 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True)
717 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True)
718
719 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
720 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_OPTIONAL)
721 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
722
723 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
724 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_REQUIRED)
725 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
726
727 def testProtocolSSL3(self):
728 if test_support.verbose:
729 sys.stdout.write("\n")
730 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True)
731 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
732 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
733 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False)
734 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, False)
735 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False)
736
737 def testProtocolTLS1(self):
738 if test_support.verbose:
739 sys.stdout.write("\n")
740 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True)
741 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
742 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
743 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False)
744 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False)
745 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv23, False)
746
747 def testSTARTTLS (self):
748
749 msgs = ("msg 1", "MSG 2", "STARTTLS", "MSG 3", "msg 4")
750
751 server = ThreadedEchoServer(TESTPORT, CERTFILE,
752 ssl_version=ssl.PROTOCOL_TLSv1,
753 starttls_server=True,
754 chatty=True,
755 connectionchatty=True)
756 flag = threading.Event()
757 server.start(flag)
758 # wait for it to start
759 flag.wait()
760 # try to connect
761 wrapped = False
762 try:
763 try:
764 s = socket.socket()
765 s.setblocking(1)
766 s.connect(('127.0.0.1', TESTPORT))
767 except Exception, x:
768 raise test_support.TestFailed("Unexpected exception: " + str(x))
769 else:
770 if test_support.verbose:
771 sys.stdout.write("\n")
772 for indata in msgs:
773 if test_support.verbose:
Bill Janssen296a59d2007-09-16 22:06:00 +0000774 sys.stdout.write(
775 " client: sending %s...\n" % repr(indata))
Bill Janssen98d19da2007-09-10 21:51:02 +0000776 if wrapped:
777 conn.write(indata)
778 outdata = conn.read()
779 else:
780 s.send(indata)
781 outdata = s.recv(1024)
Bill Janssen296a59d2007-09-16 22:06:00 +0000782 if (indata == "STARTTLS" and
783 outdata.strip().lower().startswith("ok")):
Bill Janssen98d19da2007-09-10 21:51:02 +0000784 if test_support.verbose:
Bill Janssen296a59d2007-09-16 22:06:00 +0000785 sys.stdout.write(
786 " client: read %s from server, starting TLS...\n"
787 % repr(outdata))
Bill Janssen98d19da2007-09-10 21:51:02 +0000788 conn = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1)
789
790 wrapped = True
791 else:
792 if test_support.verbose:
Bill Janssen296a59d2007-09-16 22:06:00 +0000793 sys.stdout.write(
794 " client: read %s from server\n" % repr(outdata))
Bill Janssen98d19da2007-09-10 21:51:02 +0000795 if test_support.verbose:
796 sys.stdout.write(" client: closing connection.\n")
797 if wrapped:
798 conn.write("over\n")
Bill Janssen98d19da2007-09-10 21:51:02 +0000799 else:
800 s.send("over\n")
801 s.close()
802 finally:
803 server.stop()
804 server.join()
805
Bill Janssen296a59d2007-09-16 22:06:00 +0000806 def testAsyncore(self):
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000807
Bill Janssen296a59d2007-09-16 22:06:00 +0000808 server = AsyncoreHTTPSServer(TESTPORT, CERTFILE)
809 flag = threading.Event()
810 server.start(flag)
811 # wait for it to start
812 flag.wait()
813 # try to connect
814 try:
815 if test_support.verbose:
816 sys.stdout.write('\n')
Bill Janssenbf10c472007-09-16 23:16:46 +0000817 d1 = open(CERTFILE, 'rb').read()
Bill Janssen296a59d2007-09-16 22:06:00 +0000818 d2 = ''
819 # now fetch the same data from the HTTPS server
820 url = 'https://127.0.0.1:%d/%s' % (
821 TESTPORT, os.path.split(CERTFILE)[1])
822 f = urllib.urlopen(url)
823 dlen = f.info().getheader("content-length")
824 if dlen and (int(dlen) > 0):
825 d2 = f.read(int(dlen))
826 if test_support.verbose:
827 sys.stdout.write(
828 " client: read %d bytes from remote server '%s'\n"
829 % (len(d2), server))
830 f.close()
831 except:
832 msg = ''.join(traceback.format_exception(*sys.exc_info()))
833 if test_support.verbose:
834 sys.stdout.write('\n' + msg)
835 raise test_support.TestFailed(msg)
836 else:
837 if not (d1 == d2):
838 raise test_support.TestFailed(
839 "Couldn't fetch data from HTTPS server")
840 finally:
841 server.stop()
842 server.join()
Neal Norwitz7fc8e292007-08-26 18:50:39 +0000843
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000844
Bill Janssen119c7a62007-09-10 23:41:24 +0000845def findtestsocket(start, end):
846 def testbind(i):
847 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
848 try:
849 s.bind(("127.0.0.1", i))
850 except:
851 return 0
852 else:
853 return 1
854 finally:
855 s.close()
856
857 for i in range(start, end):
858 if testbind(i) and testbind(i+1):
859 return i
860 return 0
861
862
Neal Norwitz9eb9b102007-08-27 01:15:33 +0000863def test_main(verbose=False):
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000864 if skip_expected:
Bill Janssenffe576d2007-09-05 00:46:27 +0000865 raise test_support.TestSkipped("No SSL support")
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000866
Bill Janssen296a59d2007-09-16 22:06:00 +0000867 global CERTFILE, TESTPORT, SVN_PYTHON_ORG_ROOT_CERT
Guido van Rossumba8c5652007-08-27 17:19:42 +0000868 CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir,
Bill Janssen296a59d2007-09-16 22:06:00 +0000869 "keycert.pem")
870 SVN_PYTHON_ORG_ROOT_CERT = os.path.join(
871 os.path.dirname(__file__) or os.curdir,
872 "https_svn_python_org_root.pem")
873
874 if (not os.path.exists(CERTFILE) or
875 not os.path.exists(SVN_PYTHON_ORG_ROOT_CERT)):
Bill Janssen98d19da2007-09-10 21:51:02 +0000876 raise test_support.TestFailed("Can't read certificate files!")
Bill Janssen119c7a62007-09-10 23:41:24 +0000877 TESTPORT = findtestsocket(10025, 12000)
878 if not TESTPORT:
879 raise test_support.TestFailed("Can't find open port to test servers on!")
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000880
881 tests = [BasicTests]
882
Bill Janssen296a59d2007-09-16 22:06:00 +0000883 if test_support.is_resource_enabled('network'):
884 tests.append(NetworkTests)
885
Bill Janssen98d19da2007-09-10 21:51:02 +0000886 if _have_threads:
887 thread_info = test_support.threading_setup()
Bill Janssen296a59d2007-09-16 22:06:00 +0000888 if thread_info and test_support.is_resource_enabled('network'):
Bill Janssen98d19da2007-09-10 21:51:02 +0000889 tests.append(ConnectedTests)
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000890
Bill Janssen98d19da2007-09-10 21:51:02 +0000891 test_support.run_unittest(*tests)
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000892
Bill Janssen98d19da2007-09-10 21:51:02 +0000893 if _have_threads:
894 test_support.threading_cleanup(*thread_info)
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000895
896if __name__ == "__main__":
897 test_main()