blob: 0be5652f88c7e18590de3b8e0021ea4633bed36d [file] [log] [blame]
Thomas Woutersed03b412007-08-28 21:37:11 +00001# Test the support for SSL and sockets
2
3import sys
4import unittest
Benjamin Petersonee8712c2008-05-20 21:35:26 +00005from test import support
Thomas Woutersed03b412007-08-28 21:37:11 +00006import socket
Bill Janssen6e027db2007-11-15 22:23:56 +00007import select
Thomas Woutersed03b412007-08-28 21:37:11 +00008import errno
Thomas Woutersed03b412007-08-28 21:37:11 +00009import subprocess
10import time
11import os
12import pprint
Jeremy Hylton1afc1692008-06-18 20:49:58 +000013import urllib.parse, urllib.request
Thomas Woutersed03b412007-08-28 21:37:11 +000014import shutil
15import traceback
Bill Janssen54cc54c2007-12-14 22:08:56 +000016import asyncore
Thomas Woutersed03b412007-08-28 21:37:11 +000017
Georg Brandl24420152008-05-26 16:32:26 +000018from http.server import HTTPServer, SimpleHTTPRequestHandler
Thomas Wouters1b7f8912007-09-19 03:06:30 +000019
Thomas Woutersed03b412007-08-28 21:37:11 +000020# Optionally test SSL support, if we have it in the tested platform
21skip_expected = False
22try:
23 import ssl
24except ImportError:
25 skip_expected = True
26
Benjamin Petersonee8712c2008-05-20 21:35:26 +000027HOST = support.HOST
Thomas Woutersed03b412007-08-28 21:37:11 +000028CERTFILE = None
Thomas Wouters1b7f8912007-09-19 03:06:30 +000029SVN_PYTHON_ORG_ROOT_CERT = None
Thomas Woutersed03b412007-08-28 21:37:11 +000030
Thomas Woutersed03b412007-08-28 21:37:11 +000031def handle_error(prefix):
32 exc_format = ' '.join(traceback.format_exception(*sys.exc_info()))
Benjamin Petersonee8712c2008-05-20 21:35:26 +000033 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000034 sys.stdout.write(prefix + exc_format)
Thomas Woutersed03b412007-08-28 21:37:11 +000035
36
37class BasicTests(unittest.TestCase):
38
Georg Brandlfceab5a2008-01-19 20:08:23 +000039 def testSSLconnect(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +000040 if not support.is_resource_enabled('network'):
Georg Brandlfceab5a2008-01-19 20:08:23 +000041 return
42 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
43 cert_reqs=ssl.CERT_NONE)
44 s.connect(("svn.python.org", 443))
45 c = s.getpeercert()
46 if c:
Benjamin Petersonee8712c2008-05-20 21:35:26 +000047 raise support.TestFailed("Peer cert %s shouldn't be here!")
Georg Brandlfceab5a2008-01-19 20:08:23 +000048 s.close()
49
50 # this should fail because we have no verification certs
51 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
52 cert_reqs=ssl.CERT_REQUIRED)
53 try:
54 s.connect(("svn.python.org", 443))
55 except ssl.SSLError:
56 pass
57 finally:
58 s.close()
59
Thomas Wouters1b7f8912007-09-19 03:06:30 +000060 def testCrucialConstants(self):
61 ssl.PROTOCOL_SSLv2
62 ssl.PROTOCOL_SSLv23
63 ssl.PROTOCOL_SSLv3
64 ssl.PROTOCOL_TLSv1
65 ssl.CERT_NONE
66 ssl.CERT_OPTIONAL
67 ssl.CERT_REQUIRED
Thomas Woutersed03b412007-08-28 21:37:11 +000068
Thomas Wouters1b7f8912007-09-19 03:06:30 +000069 def testRAND(self):
70 v = ssl.RAND_status()
Benjamin Petersonee8712c2008-05-20 21:35:26 +000071 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000072 sys.stdout.write("\n RAND_status is %d (%s)\n"
73 % (v, (v and "sufficient randomness") or
74 "insufficient randomness"))
Thomas Woutersed03b412007-08-28 21:37:11 +000075 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000076 ssl.RAND_egd(1)
77 except TypeError:
78 pass
Thomas Woutersed03b412007-08-28 21:37:11 +000079 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000080 print("didn't raise TypeError")
81 ssl.RAND_add("this is a random string", 75.0)
Thomas Woutersed03b412007-08-28 21:37:11 +000082
Thomas Wouters1b7f8912007-09-19 03:06:30 +000083 def testParseCert(self):
84 # note that this uses an 'unofficial' function in _ssl.c,
85 # provided solely for this test, to exercise the certificate
86 # parsing code
87 p = ssl._ssl._test_decode_cert(CERTFILE, False)
Benjamin Petersonee8712c2008-05-20 21:35:26 +000088 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000089 sys.stdout.write("\n" + pprint.pformat(p) + "\n")
Thomas Woutersed03b412007-08-28 21:37:11 +000090
Thomas Wouters1b7f8912007-09-19 03:06:30 +000091 def testDERtoPEM(self):
92
93 pem = open(SVN_PYTHON_ORG_ROOT_CERT, 'r').read()
94 d1 = ssl.PEM_cert_to_DER_cert(pem)
95 p2 = ssl.DER_cert_to_PEM_cert(d1)
96 d2 = ssl.PEM_cert_to_DER_cert(p2)
97 if (d1 != d2):
Benjamin Petersonee8712c2008-05-20 21:35:26 +000098 raise support.TestFailed("PEM-to-DER or DER-to-PEM translation failed")
Thomas Wouters1b7f8912007-09-19 03:06:30 +000099
Bill Janssen6e027db2007-11-15 22:23:56 +0000100class NetworkedTests(unittest.TestCase):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000101
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000102 def testConnect(self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000103 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
104 cert_reqs=ssl.CERT_NONE)
105 s.connect(("svn.python.org", 443))
106 c = s.getpeercert()
107 if c:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000108 raise support.TestFailed("Peer cert %s shouldn't be here!")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000109 s.close()
110
111 # this should fail because we have no verification certs
112 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
113 cert_reqs=ssl.CERT_REQUIRED)
Thomas Woutersed03b412007-08-28 21:37:11 +0000114 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000115 s.connect(("svn.python.org", 443))
116 except ssl.SSLError:
117 pass
118 finally:
119 s.close()
120
121 # this should succeed because we specify the root cert
122 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
123 cert_reqs=ssl.CERT_REQUIRED,
124 ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
125 try:
126 s.connect(("svn.python.org", 443))
127 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000128 raise support.TestFailed("Unexpected exception %s" % x)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000129 finally:
130 s.close()
131
Bill Janssen6e027db2007-11-15 22:23:56 +0000132 def testNonBlockingHandshake(self):
133 s = socket.socket(socket.AF_INET)
134 s.connect(("svn.python.org", 443))
135 s.setblocking(False)
136 s = ssl.wrap_socket(s,
137 cert_reqs=ssl.CERT_NONE,
138 do_handshake_on_connect=False)
139 count = 0
140 while True:
141 try:
142 count += 1
143 s.do_handshake()
144 break
145 except ssl.SSLError as err:
146 if err.args[0] == ssl.SSL_ERROR_WANT_READ:
147 select.select([s], [], [])
148 elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE:
149 select.select([], [s], [])
150 else:
151 raise
152 s.close()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000153 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000154 sys.stdout.write("\nNeeded %d calls to do_handshake() to establish session.\n" % count)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000155
Bill Janssen54cc54c2007-12-14 22:08:56 +0000156 def testFetchServerCert(self):
157
158 pem = ssl.get_server_certificate(("svn.python.org", 443))
159 if not pem:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000160 raise support.TestFailed("No server certificate on svn.python.org:443!")
Bill Janssen54cc54c2007-12-14 22:08:56 +0000161
162 return
163
164 try:
165 pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=CERTFILE)
166 except ssl.SSLError as x:
167 #should fail
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000168 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000169 sys.stdout.write("%s\n" % x)
170 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000171 raise support.TestFailed("Got server certificate %s for svn.python.org!" % pem)
Bill Janssen54cc54c2007-12-14 22:08:56 +0000172
173 pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
174 if not pem:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000175 raise support.TestFailed("No server certificate on svn.python.org:443!")
176 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000177 sys.stdout.write("\nVerified certificate for svn.python.org:443 is\n%s\n" % pem)
178
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000179
180try:
181 import threading
182except ImportError:
183 _have_threads = False
184else:
185
186 _have_threads = True
187
188 class ThreadedEchoServer(threading.Thread):
189
190 class ConnectionHandler(threading.Thread):
191
192 """A mildly complicated class, because we want it to work both
193 with and without the SSL wrapper around the socket connection, so
194 that we can test the STARTTLS functionality."""
195
Bill Janssen6e027db2007-11-15 22:23:56 +0000196 def __init__(self, server, connsock, addr):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000197 self.server = server
198 self.running = False
199 self.sock = connsock
Bill Janssen6e027db2007-11-15 22:23:56 +0000200 self.addr = addr
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000201 self.sock.setblocking(1)
202 self.sslconn = None
203 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000204 self.daemon = True
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000205
206 def wrap_conn (self):
207 try:
208 self.sslconn = ssl.wrap_socket(self.sock, server_side=True,
209 certfile=self.server.certificate,
210 ssl_version=self.server.protocol,
211 ca_certs=self.server.cacerts,
212 cert_reqs=self.server.certreqs)
213 except:
214 if self.server.chatty:
Bill Janssen6e027db2007-11-15 22:23:56 +0000215 handle_error("\n server: bad connection attempt from " + repr(self.addr) + ":\n")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000216 if not self.server.expect_bad_connects:
217 # here, we want to stop the server, because this shouldn't
218 # happen in the context of our test case
219 self.running = False
220 # normally, we'd just stop here, but for the test
221 # harness, we want to stop the server
222 self.server.stop()
Bill Janssen6e027db2007-11-15 22:23:56 +0000223 self.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000224 return False
225
226 else:
227 if self.server.certreqs == ssl.CERT_REQUIRED:
228 cert = self.sslconn.getpeercert()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000229 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000230 sys.stdout.write(" client cert is " + pprint.pformat(cert) + "\n")
231 cert_binary = self.sslconn.getpeercert(True)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000232 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000233 sys.stdout.write(" cert binary is " + str(len(cert_binary)) + " bytes\n")
234 cipher = self.sslconn.cipher()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000235 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000236 sys.stdout.write(" server: connection cipher is now " + str(cipher) + "\n")
237 return True
238
239 def read(self):
240 if self.sslconn:
241 return self.sslconn.read()
242 else:
243 return self.sock.recv(1024)
244
245 def write(self, bytes):
246 if self.sslconn:
247 return self.sslconn.write(bytes)
248 else:
249 return self.sock.send(bytes)
250
251 def close(self):
252 if self.sslconn:
253 self.sslconn.close()
254 else:
255 self.sock.close()
256
257 def run (self):
258 self.running = True
259 if not self.server.starttls_server:
260 if not self.wrap_conn():
261 return
262 while self.running:
263 try:
264 msg = self.read()
Bill Janssen6e027db2007-11-15 22:23:56 +0000265 amsg = (msg and str(msg, 'ASCII', 'strict')) or ''
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000266 if not msg:
267 # eof, so quit this handler
268 self.running = False
269 self.close()
Bill Janssen6e027db2007-11-15 22:23:56 +0000270 elif amsg.strip() == 'over':
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000271 if support.verbose and self.server.connectionchatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000272 sys.stdout.write(" server: client closed connection\n")
273 self.close()
274 return
Bill Janssen6e027db2007-11-15 22:23:56 +0000275 elif (self.server.starttls_server and
276 amsg.strip() == 'STARTTLS'):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000277 if support.verbose and self.server.connectionchatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000278 sys.stdout.write(" server: read STARTTLS from client, sending OK...\n")
Bill Janssen6e027db2007-11-15 22:23:56 +0000279 self.write("OK\n".encode("ASCII", "strict"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000280 if not self.wrap_conn():
281 return
Bill Janssen40a0f662008-08-12 16:56:25 +0000282 elif (self.server.starttls_server and self.sslconn
283 and amsg.strip() == 'ENDTLS'):
284 if support.verbose and self.server.connectionchatty:
285 sys.stdout.write(" server: read ENDTLS from client, sending OK...\n")
286 self.write("OK\n".encode("ASCII", "strict"))
287 self.sock = self.sslconn.unwrap()
288 self.sslconn = None
289 if support.verbose and self.server.connectionchatty:
290 sys.stdout.write(" server: connection is now unencrypted...\n")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000291 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000292 if (support.verbose and
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000293 self.server.connectionchatty):
294 ctype = (self.sslconn and "encrypted") or "unencrypted"
295 sys.stdout.write(" server: read %s (%s), sending back %s (%s)...\n"
296 % (repr(msg), ctype, repr(msg.lower()), ctype))
Bill Janssen6e027db2007-11-15 22:23:56 +0000297 self.write(amsg.lower().encode('ASCII', 'strict'))
298 except socket.error:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000299 if self.server.chatty:
300 handle_error("Test server failure:\n")
301 self.close()
302 self.running = False
303 # normally, we'd just stop here, but for the test
304 # harness, we want to stop the server
305 self.server.stop()
306 except:
307 handle_error('')
308
Trent Nelson78520002008-04-10 20:54:35 +0000309 def __init__(self, certificate, ssl_version=None,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000310 certreqs=None, cacerts=None, expect_bad_connects=False,
311 chatty=True, connectionchatty=False, starttls_server=False):
312 if ssl_version is None:
313 ssl_version = ssl.PROTOCOL_TLSv1
314 if certreqs is None:
315 certreqs = ssl.CERT_NONE
316 self.certificate = certificate
317 self.protocol = ssl_version
318 self.certreqs = certreqs
319 self.cacerts = cacerts
320 self.expect_bad_connects = expect_bad_connects
321 self.chatty = chatty
322 self.connectionchatty = connectionchatty
323 self.starttls_server = starttls_server
324 self.sock = socket.socket()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000325 self.port = support.bind_port(self.sock)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000326 self.flag = None
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000327 self.active = False
328 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000329 self.daemon = True
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000330
331 def start (self, flag=None):
332 self.flag = flag
333 threading.Thread.start(self)
334
335 def run (self):
336 self.sock.settimeout(0.5)
337 self.sock.listen(5)
338 self.active = True
339 if self.flag:
340 # signal an event
341 self.flag.set()
342 while self.active:
343 try:
344 newconn, connaddr = self.sock.accept()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000345 if support.verbose and self.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000346 sys.stdout.write(' server: new connection from '
Bill Janssen6e027db2007-11-15 22:23:56 +0000347 + repr(connaddr) + '\n')
348 handler = self.ConnectionHandler(self, newconn, connaddr)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000349 handler.start()
350 except socket.timeout:
351 pass
352 except KeyboardInterrupt:
353 self.stop()
354 except:
355 if self.chatty:
356 handle_error("Test server failure:\n")
Bill Janssen6e027db2007-11-15 22:23:56 +0000357 self.sock.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000358
359 def stop (self):
360 self.active = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000361
Bill Janssen54cc54c2007-12-14 22:08:56 +0000362 class OurHTTPSServer(threading.Thread):
363
364 # This one's based on HTTPServer, which is based on SocketServer
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000365
366 class HTTPSServer(HTTPServer):
367
368 def __init__(self, server_address, RequestHandlerClass, certfile):
369
370 HTTPServer.__init__(self, server_address, RequestHandlerClass)
371 # we assume the certfile contains both private key and certificate
372 self.certfile = certfile
373 self.active = False
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000374 self.active_lock = threading.Lock()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000375 self.allow_reuse_address = True
376
Bill Janssen6e027db2007-11-15 22:23:56 +0000377 def __str__(self):
378 return ('<%s %s:%s>' %
379 (self.__class__.__name__,
380 self.server_name,
381 self.server_port))
382
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000383 def get_request (self):
384 # override this to wrap socket with SSL
385 sock, addr = self.socket.accept()
386 sslconn = ssl.wrap_socket(sock, server_side=True,
387 certfile=self.certfile)
388 return sslconn, addr
389
390 # The methods overridden below this are mainly so that we
391 # can run it in a thread and be able to stop it from another
392 # You probably wouldn't need them in other uses.
393
394 def server_activate(self):
395 # We want to run this in a thread for testing purposes,
396 # so we override this to set timeout, so that we get
397 # a chance to stop the server
398 self.socket.settimeout(0.5)
399 HTTPServer.server_activate(self)
400
401 def serve_forever(self):
402 # We want this to run in a thread, so we use a slightly
403 # modified version of "forever".
404 self.active = True
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000405 while 1:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000406 try:
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000407 # We need to lock while handling the request.
408 # Another thread can close the socket after self.active
409 # has been checked and before the request is handled.
410 # This causes an exception when using the closed socket.
411 with self.active_lock:
412 if not self.active:
413 break
414 self.handle_request()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000415 except socket.timeout:
416 pass
417 except KeyboardInterrupt:
418 self.server_close()
419 return
420 except:
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000421 sys.stdout.write(''.join(traceback.format_exception(*sys.exc_info())))
422 break
Neal Norwitzf9ff5f02008-03-31 05:39:26 +0000423 time.sleep(0.1)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000424
425 def server_close(self):
426 # Again, we want this to run in a thread, so we need to override
427 # close to clear the "active" flag, so that serve_forever() will
428 # terminate.
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000429 with self.active_lock:
430 HTTPServer.server_close(self)
431 self.active = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000432
433 class RootedHTTPRequestHandler(SimpleHTTPRequestHandler):
434
435 # need to override translate_path to get a known root,
436 # instead of using os.curdir, since the test could be
437 # run from anywhere
438
439 server_version = "TestHTTPS/1.0"
440
441 root = None
442
443 def translate_path(self, path):
444 """Translate a /-separated PATH to the local filename syntax.
445
446 Components that mean special things to the local file system
447 (e.g. drive or directory names) are ignored. (XXX They should
448 probably be diagnosed.)
449
450 """
451 # abandon query parameters
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000452 path = urllib.parse.urlparse(path)[2]
453 path = os.path.normpath(urllib.parse.unquote(path))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000454 words = path.split('/')
455 words = filter(None, words)
456 path = self.root
457 for word in words:
458 drive, word = os.path.splitdrive(word)
459 head, word = os.path.split(word)
460 if word in self.root: continue
461 path = os.path.join(path, word)
462 return path
463
464 def log_message(self, format, *args):
465
466 # we override this to suppress logging unless "verbose"
467
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000468 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000469 sys.stdout.write(" server (%s:%d %s):\n [%s] %s\n" %
470 (self.server.server_address,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000471 self.server.server_port,
472 self.request.cipher(),
473 self.log_date_time_string(),
474 format%args))
Thomas Woutersed03b412007-08-28 21:37:11 +0000475
476
Trent Nelson78520002008-04-10 20:54:35 +0000477 def __init__(self, certfile):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000478 self.flag = None
479 self.active = False
480 self.RootedHTTPRequestHandler.root = os.path.split(CERTFILE)[0]
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000481 self.port = support.find_unused_port()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000482 self.server = self.HTTPSServer(
Trent Nelson78520002008-04-10 20:54:35 +0000483 (HOST, self.port), self.RootedHTTPRequestHandler, certfile)
Thomas Woutersed03b412007-08-28 21:37:11 +0000484 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000485 self.daemon = True
Thomas Woutersed03b412007-08-28 21:37:11 +0000486
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000487 def __str__(self):
Bill Janssen6e027db2007-11-15 22:23:56 +0000488 return "<%s %s>" % (self.__class__.__name__, self.server)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000489
490 def start (self, flag=None):
491 self.flag = flag
492 threading.Thread.start(self)
493
Thomas Woutersed03b412007-08-28 21:37:11 +0000494 def run (self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000495 self.active = True
496 if self.flag:
497 self.flag.set()
498 self.server.serve_forever()
499 self.active = False
500
501 def stop (self):
502 self.active = False
503 self.server.server_close()
504
505
Bill Janssen54cc54c2007-12-14 22:08:56 +0000506 class AsyncoreEchoServer(threading.Thread):
507
508 # this one's based on asyncore.dispatcher
509
510 class EchoServer (asyncore.dispatcher):
511
512 class ConnectionHandler (asyncore.dispatcher_with_send):
513
514 def __init__(self, conn, certfile):
515 self.socket = ssl.wrap_socket(conn, server_side=True,
516 certfile=certfile,
517 do_handshake_on_connect=False)
518 asyncore.dispatcher_with_send.__init__(self, self.socket)
519 # now we have to do the handshake
520 # we'll just do it the easy way, and block the connection
521 # till it's finished. If we were doing it right, we'd
522 # do this in multiple calls to handle_read...
523 self.do_handshake(block=True)
524
525 def readable(self):
526 if isinstance(self.socket, ssl.SSLSocket):
527 while self.socket.pending() > 0:
528 self.handle_read_event()
529 return True
530
531 def handle_read(self):
532 data = self.recv(1024)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000533 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000534 sys.stdout.write(" server: read %s from client\n" % repr(data))
535 if not data:
536 self.close()
537 else:
538 self.send(str(data, 'ASCII', 'strict').lower().encode('ASCII', 'strict'))
539
540 def handle_close(self):
Bill Janssen2f5799b2008-06-29 00:08:12 +0000541 self.close()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000542 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000543 sys.stdout.write(" server: closed connection %s\n" % self.socket)
544
545 def handle_error(self):
546 raise
547
548 def __init__(self, port, certfile):
549 self.port = port
550 self.certfile = certfile
551 asyncore.dispatcher.__init__(self)
552 self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
553 self.bind(('', port))
554 self.listen(5)
555
556 def handle_accept(self):
557 sock_obj, addr = self.accept()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000558 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000559 sys.stdout.write(" server: new connection from %s:%s\n" %addr)
560 self.ConnectionHandler(sock_obj, self.certfile)
561
562 def handle_error(self):
563 raise
564
Trent Nelson78520002008-04-10 20:54:35 +0000565 def __init__(self, certfile):
Bill Janssen54cc54c2007-12-14 22:08:56 +0000566 self.flag = None
567 self.active = False
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000568 self.port = support.find_unused_port()
Trent Nelson78520002008-04-10 20:54:35 +0000569 self.server = self.EchoServer(self.port, certfile)
Bill Janssen54cc54c2007-12-14 22:08:56 +0000570 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000571 self.daemon = True
Bill Janssen54cc54c2007-12-14 22:08:56 +0000572
573 def __str__(self):
574 return "<%s %s>" % (self.__class__.__name__, self.server)
575
576 def start (self, flag=None):
577 self.flag = flag
578 threading.Thread.start(self)
579
580 def run (self):
581 self.active = True
582 if self.flag:
583 self.flag.set()
584 while self.active:
585 try:
586 asyncore.loop(1)
587 except:
588 pass
589
590 def stop (self):
591 self.active = False
592 self.server.close()
593
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000594 def badCertTest (certfile):
Trent Nelson78520002008-04-10 20:54:35 +0000595 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000596 certreqs=ssl.CERT_REQUIRED,
Bill Janssen6e027db2007-11-15 22:23:56 +0000597 cacerts=CERTFILE, chatty=False,
598 connectionchatty=False)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000599 flag = threading.Event()
600 server.start(flag)
601 # wait for it to start
602 flag.wait()
603 # try to connect
604 try:
Thomas Woutersed03b412007-08-28 21:37:11 +0000605 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000606 s = ssl.wrap_socket(socket.socket(),
607 certfile=certfile,
608 ssl_version=ssl.PROTOCOL_TLSv1)
Trent Nelson78520002008-04-10 20:54:35 +0000609 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000610 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000611 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000612 sys.stdout.write("\nSSLError is %s\n" % x)
Bill Janssenddc56692008-07-17 18:17:20 +0000613 except socket.error as x:
614 if support.verbose:
615 sys.stdout.write("\nsocket.error is %s\n" % x)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000616 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000617 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000618 "Use of invalid cert should have failed!")
619 finally:
620 server.stop()
621 server.join()
Thomas Woutersed03b412007-08-28 21:37:11 +0000622
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000623 def serverParamsTest (certfile, protocol, certreqs, cacertsfile,
Bill Janssen6e027db2007-11-15 22:23:56 +0000624 client_certfile, client_protocol=None,
625 indata="FOO\n",
626 chatty=False, connectionchatty=False):
Thomas Woutersed03b412007-08-28 21:37:11 +0000627
Trent Nelson78520002008-04-10 20:54:35 +0000628 server = ThreadedEchoServer(certfile,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000629 certreqs=certreqs,
630 ssl_version=protocol,
631 cacerts=cacertsfile,
632 chatty=chatty,
Bill Janssen6e027db2007-11-15 22:23:56 +0000633 connectionchatty=False)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000634 flag = threading.Event()
635 server.start(flag)
636 # wait for it to start
637 flag.wait()
638 # try to connect
639 if client_protocol is None:
640 client_protocol = protocol
641 try:
Bill Janssen6e027db2007-11-15 22:23:56 +0000642 s = ssl.wrap_socket(socket.socket(),
Trent Nelson6b240cd2008-04-10 20:12:06 +0000643 server_side=False,
Bill Janssen6e027db2007-11-15 22:23:56 +0000644 certfile=client_certfile,
645 ca_certs=cacertsfile,
646 cert_reqs=certreqs,
647 ssl_version=client_protocol)
Trent Nelson78520002008-04-10 20:54:35 +0000648 s.connect((HOST, server.port))
Bill Janssen6e027db2007-11-15 22:23:56 +0000649 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000650 raise support.TestFailed("Unexpected SSL error: " + str(x))
Bill Janssen6e027db2007-11-15 22:23:56 +0000651 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000652 raise support.TestFailed("Unexpected exception: " + str(x))
Bill Janssen6e027db2007-11-15 22:23:56 +0000653 else:
654 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000655 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000656 sys.stdout.write(
657 " client: sending %s...\n" % (repr(indata)))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000658 s.write(indata.encode('ASCII', 'strict'))
Bill Janssen6e027db2007-11-15 22:23:56 +0000659 outdata = s.read()
660 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000661 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000662 sys.stdout.write(" client: read %s\n" % repr(outdata))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000663 outdata = str(outdata, 'ASCII', 'strict')
Bill Janssen6e027db2007-11-15 22:23:56 +0000664 if outdata != indata.lower():
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000665 raise support.TestFailed(
Bill Janssen6e027db2007-11-15 22:23:56 +0000666 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
Trent Nelson6b240cd2008-04-10 20:12:06 +0000667 % (repr(outdata[:min(len(outdata),20)]), len(outdata),
668 repr(indata[:min(len(indata),20)].lower()), len(indata)))
669 s.write("over\n".encode("ASCII", "strict"))
Bill Janssen6e027db2007-11-15 22:23:56 +0000670 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000671 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000672 sys.stdout.write(" client: closing connection.\n")
673 s.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000674 finally:
675 server.stop()
676 server.join()
Thomas Woutersed03b412007-08-28 21:37:11 +0000677
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000678 def tryProtocolCombo (server_protocol,
679 client_protocol,
680 expectedToWork,
681 certsreqs=None):
Thomas Woutersed03b412007-08-28 21:37:11 +0000682
Benjamin Peterson2a691a82008-03-31 01:51:45 +0000683 if certsreqs is None:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000684 certsreqs = ssl.CERT_NONE
Thomas Woutersed03b412007-08-28 21:37:11 +0000685
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000686 if certsreqs == ssl.CERT_NONE:
687 certtype = "CERT_NONE"
688 elif certsreqs == ssl.CERT_OPTIONAL:
689 certtype = "CERT_OPTIONAL"
690 elif certsreqs == ssl.CERT_REQUIRED:
691 certtype = "CERT_REQUIRED"
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000692 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000693 formatstr = (expectedToWork and " %s->%s %s\n") or " {%s->%s} %s\n"
694 sys.stdout.write(formatstr %
695 (ssl.get_protocol_name(client_protocol),
696 ssl.get_protocol_name(server_protocol),
697 certtype))
698 try:
699 serverParamsTest(CERTFILE, server_protocol, certsreqs,
Bill Janssen6e027db2007-11-15 22:23:56 +0000700 CERTFILE, CERTFILE, client_protocol,
701 chatty=False, connectionchatty=False)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000702 except support.TestFailed:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000703 if expectedToWork:
704 raise
705 else:
706 if not expectedToWork:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000707 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000708 "Client protocol %s succeeded with server protocol %s!"
709 % (ssl.get_protocol_name(client_protocol),
710 ssl.get_protocol_name(server_protocol)))
711
712
Bill Janssen6e027db2007-11-15 22:23:56 +0000713 class ThreadedTests(unittest.TestCase):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000714
Trent Nelson6b240cd2008-04-10 20:12:06 +0000715 def testEcho (self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000716
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000717 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000718 sys.stdout.write("\n")
719 serverParamsTest(CERTFILE, ssl.PROTOCOL_TLSv1, ssl.CERT_NONE,
720 CERTFILE, CERTFILE, ssl.PROTOCOL_TLSv1,
721 chatty=True, connectionchatty=True)
722
723 def testReadCert(self):
724
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000725 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000726 sys.stdout.write("\n")
727 s2 = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000728 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000729 certreqs=ssl.CERT_NONE,
730 ssl_version=ssl.PROTOCOL_SSLv23,
731 cacerts=CERTFILE,
732 chatty=False)
733 flag = threading.Event()
734 server.start(flag)
735 # wait for it to start
736 flag.wait()
737 # try to connect
738 try:
739 try:
740 s = ssl.wrap_socket(socket.socket(),
741 certfile=CERTFILE,
742 ca_certs=CERTFILE,
743 cert_reqs=ssl.CERT_REQUIRED,
744 ssl_version=ssl.PROTOCOL_SSLv23)
Trent Nelson78520002008-04-10 20:54:35 +0000745 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000746 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000747 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000748 "Unexpected SSL error: " + str(x))
749 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000750 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000751 "Unexpected exception: " + str(x))
752 else:
753 if not s:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000754 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000755 "Can't SSL-handshake with test server")
756 cert = s.getpeercert()
757 if not cert:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000758 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000759 "Can't get peer certificate.")
760 cipher = s.cipher()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000761 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000762 sys.stdout.write(pprint.pformat(cert) + '\n')
763 sys.stdout.write("Connection cipher is " + str(cipher) + '.\n')
Bill Janssen6e027db2007-11-15 22:23:56 +0000764 if 'subject' not in cert:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000765 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000766 "No subject field in certificate: %s." %
767 pprint.pformat(cert))
768 if ((('organizationName', 'Python Software Foundation'),)
769 not in cert['subject']):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000770 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000771 "Missing or invalid 'organizationName' field in certificate subject; "
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000772 "should be 'Python Software Foundation'.")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000773 s.close()
774 finally:
775 server.stop()
776 server.join()
777
778 def testNULLcert(self):
779 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
780 "nullcert.pem"))
781 def testMalformedCert(self):
782 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
783 "badcert.pem"))
Bill Janssen58afe4c2008-09-08 16:45:19 +0000784 def testWrongCert(self):
785 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
786 "wrongcert.pem"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000787 def testMalformedKey(self):
788 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
789 "badkey.pem"))
790
Trent Nelson6b240cd2008-04-10 20:12:06 +0000791 def testRudeShutdown(self):
792
793 listener_ready = threading.Event()
794 listener_gone = threading.Event()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000795 port = support.find_unused_port()
Trent Nelson6b240cd2008-04-10 20:12:06 +0000796
797 # `listener` runs in a thread. It opens a socket listening on
798 # PORT, and sits in an accept() until the main thread connects.
799 # Then it rudely closes the socket, and sets Event `listener_gone`
800 # to let the main thread know the socket is gone.
801 def listener():
802 s = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000803 s.bind((HOST, port))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000804 s.listen(5)
805 listener_ready.set()
806 s.accept()
807 s = None # reclaim the socket object, which also closes it
808 listener_gone.set()
809
810 def connector():
811 listener_ready.wait()
812 s = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000813 s.connect((HOST, port))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000814 listener_gone.wait()
815 try:
816 ssl_sock = ssl.wrap_socket(s)
817 except IOError:
818 pass
819 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000820 raise support.TestFailed(
Trent Nelson6b240cd2008-04-10 20:12:06 +0000821 'connecting to closed SSL socket should have failed')
822
823 t = threading.Thread(target=listener)
824 t.start()
825 connector()
826 t.join()
827
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000828 def testProtocolSSL2(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000829 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000830 sys.stdout.write("\n")
831 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True)
832 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL)
833 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED)
834 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True)
835 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False)
836 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False)
837
838 def testProtocolSSL23(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000839 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000840 sys.stdout.write("\n")
841 try:
842 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv2, True)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000843 except support.TestFailed as x:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000844 # this fails on some older versions of OpenSSL (0.9.7l, for instance)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000845 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000846 sys.stdout.write(
847 " SSL2 client to SSL23 server test unexpectedly failed:\n %s\n"
848 % str(x))
849 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True)
850 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True)
851 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True)
852
853 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
854 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_OPTIONAL)
855 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
856
857 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
858 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_REQUIRED)
859 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
860
861 def testProtocolSSL3(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000862 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000863 sys.stdout.write("\n")
864 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True)
865 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
866 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
867 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False)
868 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, False)
869 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False)
870
871 def testProtocolTLS1(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000872 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000873 sys.stdout.write("\n")
874 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True)
875 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
876 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
877 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False)
878 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False)
879 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv23, False)
880
881 def testSTARTTLS (self):
882
Bill Janssen40a0f662008-08-12 16:56:25 +0000883 msgs = ("msg 1", "MSG 2", "STARTTLS", "MSG 3", "msg 4", "ENDTLS", "msg 5", "msg 6")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000884
Trent Nelson78520002008-04-10 20:54:35 +0000885 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000886 ssl_version=ssl.PROTOCOL_TLSv1,
887 starttls_server=True,
888 chatty=True,
889 connectionchatty=True)
890 flag = threading.Event()
891 server.start(flag)
892 # wait for it to start
893 flag.wait()
894 # try to connect
895 wrapped = False
896 try:
897 try:
898 s = socket.socket()
899 s.setblocking(1)
Trent Nelson78520002008-04-10 20:54:35 +0000900 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000901 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000902 raise support.TestFailed("Unexpected exception: " + str(x))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000903 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000904 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000905 sys.stdout.write("\n")
906 for indata in msgs:
Bill Janssen6e027db2007-11-15 22:23:56 +0000907 msg = indata.encode('ASCII', 'replace')
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000908 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000909 sys.stdout.write(
Bill Janssen6e027db2007-11-15 22:23:56 +0000910 " client: sending %s...\n" % repr(msg))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000911 if wrapped:
Bill Janssen6e027db2007-11-15 22:23:56 +0000912 conn.write(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000913 outdata = conn.read()
914 else:
Bill Janssen6e027db2007-11-15 22:23:56 +0000915 s.send(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000916 outdata = s.recv(1024)
917 if (indata == "STARTTLS" and
Bill Janssen6e027db2007-11-15 22:23:56 +0000918 str(outdata, 'ASCII', 'replace').strip().lower().startswith("ok")):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000919 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000920 msg = str(outdata, 'ASCII', 'replace')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000921 sys.stdout.write(
922 " client: read %s from server, starting TLS...\n"
Bill Janssen6e027db2007-11-15 22:23:56 +0000923 % repr(msg))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000924 conn = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000925 wrapped = True
Bill Janssen40a0f662008-08-12 16:56:25 +0000926 elif (indata == "ENDTLS" and
927 str(outdata, 'ASCII', 'replace').strip().lower().startswith("ok")):
928 if support.verbose:
929 msg = str(outdata, 'ASCII', 'replace')
930 sys.stdout.write(
931 " client: read %s from server, ending TLS...\n"
932 % repr(msg))
933 s = conn.unwrap()
934 wrapped = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000935 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000936 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000937 msg = str(outdata, 'ASCII', 'replace')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000938 sys.stdout.write(
Bill Janssen6e027db2007-11-15 22:23:56 +0000939 " client: read %s from server\n" % repr(msg))
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000940 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000941 sys.stdout.write(" client: closing connection.\n")
942 if wrapped:
Bill Janssen6e027db2007-11-15 22:23:56 +0000943 conn.write("over\n".encode("ASCII", "strict"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000944 else:
Bill Janssen40a0f662008-08-12 16:56:25 +0000945 s.send("over\n".encode("ASCII", "strict"))
Bill Janssen6e027db2007-11-15 22:23:56 +0000946 if wrapped:
947 conn.close()
948 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000949 s.close()
950 finally:
951 server.stop()
952 server.join()
953
Bill Janssen54cc54c2007-12-14 22:08:56 +0000954 def testSocketServer(self):
Bill Janssen6e027db2007-11-15 22:23:56 +0000955
Trent Nelson78520002008-04-10 20:54:35 +0000956 server = OurHTTPSServer(CERTFILE)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000957 flag = threading.Event()
958 server.start(flag)
959 # wait for it to start
960 flag.wait()
961 # try to connect
962 try:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000963 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000964 sys.stdout.write('\n')
965 d1 = open(CERTFILE, 'rb').read()
966 d2 = ''
967 # now fetch the same data from the HTTPS server
Trent Nelson78520002008-04-10 20:54:35 +0000968 url = 'https://%s:%d/%s' % (
969 HOST, server.port, os.path.split(CERTFILE)[1])
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000970 f = urllib.request.urlopen(url)
Barry Warsaw820c1202008-06-12 04:06:45 +0000971 dlen = f.info().get("content-length")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000972 if dlen and (int(dlen) > 0):
973 d2 = f.read(int(dlen))
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000974 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000975 sys.stdout.write(
976 " client: read %d bytes from remote server '%s'\n"
977 % (len(d2), server))
978 f.close()
979 except:
980 msg = ''.join(traceback.format_exception(*sys.exc_info()))
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000981 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000982 sys.stdout.write('\n' + msg)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000983 raise support.TestFailed(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000984 else:
985 if not (d1 == d2):
Bill Janssen6e027db2007-11-15 22:23:56 +0000986 print("d1 is", len(d1), repr(d1))
987 print("d2 is", len(d2), repr(d2))
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000988 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000989 "Couldn't fetch data from HTTPS server")
990 finally:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000991 if support.verbose:
Neal Norwitzf9ff5f02008-03-31 05:39:26 +0000992 sys.stdout.write('stopping server\n')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000993 server.stop()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000994 if support.verbose:
Neal Norwitzf9ff5f02008-03-31 05:39:26 +0000995 sys.stdout.write('joining thread\n')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000996 server.join()
997
Trent Nelson6b240cd2008-04-10 20:12:06 +0000998 def testAsyncoreServer(self):
999
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001000 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001001 sys.stdout.write("\n")
1002
1003 indata="FOO\n"
Trent Nelson78520002008-04-10 20:54:35 +00001004 server = AsyncoreEchoServer(CERTFILE)
Trent Nelson6b240cd2008-04-10 20:12:06 +00001005 flag = threading.Event()
1006 server.start(flag)
1007 # wait for it to start
1008 flag.wait()
1009 # try to connect
1010 try:
1011 s = ssl.wrap_socket(socket.socket())
Trent Nelson78520002008-04-10 20:54:35 +00001012 s.connect((HOST, server.port))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001013 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001014 raise support.TestFailed("Unexpected SSL error: " + str(x))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001015 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001016 raise support.TestFailed("Unexpected exception: " + str(x))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001017 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001018 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001019 sys.stdout.write(
1020 " client: sending %s...\n" % (repr(indata)))
1021 s.sendall(indata.encode('ASCII', 'strict'))
1022 outdata = s.recv()
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001023 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001024 sys.stdout.write(" client: read %s\n" % repr(outdata))
1025 outdata = str(outdata, 'ASCII', 'strict')
1026 if outdata != indata.lower():
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001027 raise support.TestFailed(
Trent Nelson6b240cd2008-04-10 20:12:06 +00001028 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
1029 % (repr(outdata[:min(len(outdata),20)]), len(outdata),
1030 repr(indata[:min(len(indata),20)].lower()), len(indata)))
1031 s.write("over\n".encode("ASCII", "strict"))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001032 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001033 sys.stdout.write(" client: closing connection.\n")
1034 s.close()
1035 finally:
1036 server.stop()
1037 server.join()
1038
Bill Janssen58afe4c2008-09-08 16:45:19 +00001039 def testAllRecvAndSendMethods(self):
1040
1041 if support.verbose:
1042 sys.stdout.write("\n")
1043
1044 server = ThreadedEchoServer(CERTFILE,
1045 certreqs=ssl.CERT_NONE,
1046 ssl_version=ssl.PROTOCOL_TLSv1,
1047 cacerts=CERTFILE,
1048 chatty=True,
1049 connectionchatty=False)
1050 flag = threading.Event()
1051 server.start(flag)
1052 # wait for it to start
1053 flag.wait()
1054 # try to connect
1055 try:
1056 s = ssl.wrap_socket(socket.socket(),
1057 server_side=False,
1058 certfile=CERTFILE,
1059 ca_certs=CERTFILE,
1060 cert_reqs=ssl.CERT_NONE,
1061 ssl_version=ssl.PROTOCOL_TLSv1)
1062 s.connect((HOST, server.port))
1063 except ssl.SSLError as x:
1064 raise support.TestFailed("Unexpected SSL error: " + str(x))
1065 except Exception as x:
1066 raise support.TestFailed("Unexpected exception: " + str(x))
1067 else:
1068 # helper methods for standardising recv* method signatures
1069 def _recv_into():
1070 b = bytearray(b"\0"*100)
1071 count = s.recv_into(b)
1072 return b[:count]
1073
1074 def _recvfrom_into():
1075 b = bytearray(b"\0"*100)
1076 count, addr = s.recvfrom_into(b)
1077 return b[:count]
1078
1079 # (name, method, whether to expect success, *args)
1080 send_methods = [
1081 ('send', s.send, True, []),
1082 ('sendto', s.sendto, False, ["some.address"]),
1083 ('sendall', s.sendall, True, []),
1084 ]
1085 recv_methods = [
1086 ('recv', s.recv, True, []),
1087 ('recvfrom', s.recvfrom, False, ["some.address"]),
1088 ('recv_into', _recv_into, True, []),
1089 ('recvfrom_into', _recvfrom_into, False, []),
1090 ]
1091 data_prefix = "PREFIX_"
1092
1093 for meth_name, send_meth, expect_success, args in send_methods:
1094 indata = data_prefix + meth_name
1095 try:
1096 send_meth(indata.encode('ASCII', 'strict'), *args)
1097 outdata = s.read()
1098 outdata = str(outdata, 'ASCII', 'strict')
1099 if outdata != indata.lower():
1100 raise support.TestFailed(
1101 "While sending with <<{name:s}>> bad data "
1102 "<<{outdata:s}>> ({nout:d}) received; "
1103 "expected <<{indata:s}>> ({nin:d})\n".format(
1104 name=meth_name, outdata=repr(outdata[:20]),
1105 nout=len(outdata),
1106 indata=repr(indata[:20]), nin=len(indata)
1107 )
1108 )
1109 except ValueError as e:
1110 if expect_success:
1111 raise support.TestFailed(
1112 "Failed to send with method <<{name:s}>>; "
1113 "expected to succeed.\n".format(name=meth_name)
1114 )
1115 if not str(e).startswith(meth_name):
1116 raise support.TestFailed(
1117 "Method <<{name:s}>> failed with unexpected "
1118 "exception message: {exp:s}\n".format(
1119 name=meth_name, exp=e
1120 )
1121 )
1122
1123 for meth_name, recv_meth, expect_success, args in recv_methods:
1124 indata = data_prefix + meth_name
1125 try:
1126 s.send(indata.encode('ASCII', 'strict'))
1127 outdata = recv_meth(*args)
1128 outdata = str(outdata, 'ASCII', 'strict')
1129 if outdata != indata.lower():
1130 raise support.TestFailed(
1131 "While receiving with <<{name:s}>> bad data "
1132 "<<{outdata:s}>> ({nout:d}) received; "
1133 "expected <<{indata:s}>> ({nin:d})\n".format(
1134 name=meth_name, outdata=repr(outdata[:20]),
1135 nout=len(outdata),
1136 indata=repr(indata[:20]), nin=len(indata)
1137 )
1138 )
1139 except ValueError as e:
1140 if expect_success:
1141 raise support.TestFailed(
1142 "Failed to receive with method <<{name:s}>>; "
1143 "expected to succeed.\n".format(name=meth_name)
1144 )
1145 if not str(e).startswith(meth_name):
1146 raise support.TestFailed(
1147 "Method <<{name:s}>> failed with unexpected "
1148 "exception message: {exp:s}\n".format(
1149 name=meth_name, exp=e
1150 )
1151 )
1152 # consume data
1153 s.read()
1154
1155 s.write("over\n".encode("ASCII", "strict"))
1156 s.close()
1157 finally:
1158 server.stop()
1159 server.join()
1160
1161
Thomas Woutersed03b412007-08-28 21:37:11 +00001162def test_main(verbose=False):
1163 if skip_expected:
Benjamin Petersone549ead2009-03-28 21:42:05 +00001164 raise unittest.SkipTest("No SSL support")
Thomas Woutersed03b412007-08-28 21:37:11 +00001165
Trent Nelson78520002008-04-10 20:54:35 +00001166 global CERTFILE, SVN_PYTHON_ORG_ROOT_CERT
Thomas Woutersed03b412007-08-28 21:37:11 +00001167 CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir,
1168 "keycert.pem")
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001169 SVN_PYTHON_ORG_ROOT_CERT = os.path.join(
1170 os.path.dirname(__file__) or os.curdir,
1171 "https_svn_python_org_root.pem")
1172
1173 if (not os.path.exists(CERTFILE) or
1174 not os.path.exists(SVN_PYTHON_ORG_ROOT_CERT)):
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001175 raise support.TestFailed("Can't read certificate files!")
Bill Janssen6e027db2007-11-15 22:23:56 +00001176
Thomas Woutersed03b412007-08-28 21:37:11 +00001177 tests = [BasicTests]
1178
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001179 if support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00001180 tests.append(NetworkedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001181
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001182 if _have_threads:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001183 thread_info = support.threading_setup()
1184 if thread_info and support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00001185 tests.append(ThreadedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001186
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001187 support.run_unittest(*tests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001188
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001189 if _have_threads:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001190 support.threading_cleanup(*thread_info)
Thomas Woutersed03b412007-08-28 21:37:11 +00001191
1192if __name__ == "__main__":
1193 test_main()