blob: 383c78a95ab18ca634abf4eeeb1ccc156e4e4c4c [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:
Antoine Pitrou7d7aede2009-11-25 18:55:32 +0000654 bindata = indata.encode('ASCII', 'strict')
655 for arg in [bindata, bytearray(bindata), memoryview(bindata)]:
656 if connectionchatty:
657 if support.verbose:
658 sys.stdout.write(
659 " client: sending %s...\n" % (repr(indata)))
660 s.write(arg)
661 outdata = s.read()
662 if connectionchatty:
663 if support.verbose:
664 sys.stdout.write(" client: read %s\n" % repr(outdata))
665 outdata = str(outdata, 'ASCII', 'strict')
666 if outdata != indata.lower():
667 raise support.TestFailed(
668 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
669 % (repr(outdata[:min(len(outdata),20)]), len(outdata),
670 repr(indata[:min(len(indata),20)].lower()), len(indata)))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000671 s.write("over\n".encode("ASCII", "strict"))
Bill Janssen6e027db2007-11-15 22:23:56 +0000672 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000673 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000674 sys.stdout.write(" client: closing connection.\n")
675 s.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000676 finally:
677 server.stop()
678 server.join()
Thomas Woutersed03b412007-08-28 21:37:11 +0000679
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000680 def tryProtocolCombo (server_protocol,
681 client_protocol,
682 expectedToWork,
683 certsreqs=None):
Thomas Woutersed03b412007-08-28 21:37:11 +0000684
Benjamin Peterson2a691a82008-03-31 01:51:45 +0000685 if certsreqs is None:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000686 certsreqs = ssl.CERT_NONE
Thomas Woutersed03b412007-08-28 21:37:11 +0000687
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000688 if certsreqs == ssl.CERT_NONE:
689 certtype = "CERT_NONE"
690 elif certsreqs == ssl.CERT_OPTIONAL:
691 certtype = "CERT_OPTIONAL"
692 elif certsreqs == ssl.CERT_REQUIRED:
693 certtype = "CERT_REQUIRED"
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000694 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000695 formatstr = (expectedToWork and " %s->%s %s\n") or " {%s->%s} %s\n"
696 sys.stdout.write(formatstr %
697 (ssl.get_protocol_name(client_protocol),
698 ssl.get_protocol_name(server_protocol),
699 certtype))
700 try:
701 serverParamsTest(CERTFILE, server_protocol, certsreqs,
Bill Janssen6e027db2007-11-15 22:23:56 +0000702 CERTFILE, CERTFILE, client_protocol,
703 chatty=False, connectionchatty=False)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000704 except support.TestFailed:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000705 if expectedToWork:
706 raise
707 else:
708 if not expectedToWork:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000709 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000710 "Client protocol %s succeeded with server protocol %s!"
711 % (ssl.get_protocol_name(client_protocol),
712 ssl.get_protocol_name(server_protocol)))
713
714
Bill Janssen6e027db2007-11-15 22:23:56 +0000715 class ThreadedTests(unittest.TestCase):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000716
Trent Nelson6b240cd2008-04-10 20:12:06 +0000717 def testEcho (self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000718
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000719 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000720 sys.stdout.write("\n")
721 serverParamsTest(CERTFILE, ssl.PROTOCOL_TLSv1, ssl.CERT_NONE,
722 CERTFILE, CERTFILE, ssl.PROTOCOL_TLSv1,
723 chatty=True, connectionchatty=True)
724
725 def testReadCert(self):
726
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000727 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000728 sys.stdout.write("\n")
729 s2 = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000730 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000731 certreqs=ssl.CERT_NONE,
732 ssl_version=ssl.PROTOCOL_SSLv23,
733 cacerts=CERTFILE,
734 chatty=False)
735 flag = threading.Event()
736 server.start(flag)
737 # wait for it to start
738 flag.wait()
739 # try to connect
740 try:
741 try:
742 s = ssl.wrap_socket(socket.socket(),
743 certfile=CERTFILE,
744 ca_certs=CERTFILE,
745 cert_reqs=ssl.CERT_REQUIRED,
746 ssl_version=ssl.PROTOCOL_SSLv23)
Trent Nelson78520002008-04-10 20:54:35 +0000747 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000748 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000749 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000750 "Unexpected SSL error: " + str(x))
751 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000752 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000753 "Unexpected exception: " + str(x))
754 else:
755 if not s:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000756 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000757 "Can't SSL-handshake with test server")
758 cert = s.getpeercert()
759 if not cert:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000760 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000761 "Can't get peer certificate.")
762 cipher = s.cipher()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000763 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000764 sys.stdout.write(pprint.pformat(cert) + '\n')
765 sys.stdout.write("Connection cipher is " + str(cipher) + '.\n')
Bill Janssen6e027db2007-11-15 22:23:56 +0000766 if 'subject' not in cert:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000767 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000768 "No subject field in certificate: %s." %
769 pprint.pformat(cert))
770 if ((('organizationName', 'Python Software Foundation'),)
771 not in cert['subject']):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000772 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000773 "Missing or invalid 'organizationName' field in certificate subject; "
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000774 "should be 'Python Software Foundation'.")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000775 s.close()
776 finally:
777 server.stop()
778 server.join()
779
780 def testNULLcert(self):
781 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
782 "nullcert.pem"))
783 def testMalformedCert(self):
784 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
785 "badcert.pem"))
Bill Janssen58afe4c2008-09-08 16:45:19 +0000786 def testWrongCert(self):
787 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
788 "wrongcert.pem"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000789 def testMalformedKey(self):
790 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
791 "badkey.pem"))
792
Trent Nelson6b240cd2008-04-10 20:12:06 +0000793 def testRudeShutdown(self):
794
795 listener_ready = threading.Event()
796 listener_gone = threading.Event()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000797 port = support.find_unused_port()
Trent Nelson6b240cd2008-04-10 20:12:06 +0000798
799 # `listener` runs in a thread. It opens a socket listening on
800 # PORT, and sits in an accept() until the main thread connects.
801 # Then it rudely closes the socket, and sets Event `listener_gone`
802 # to let the main thread know the socket is gone.
803 def listener():
804 s = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000805 s.bind((HOST, port))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000806 s.listen(5)
807 listener_ready.set()
808 s.accept()
809 s = None # reclaim the socket object, which also closes it
810 listener_gone.set()
811
812 def connector():
813 listener_ready.wait()
814 s = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000815 s.connect((HOST, port))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000816 listener_gone.wait()
817 try:
818 ssl_sock = ssl.wrap_socket(s)
819 except IOError:
820 pass
821 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000822 raise support.TestFailed(
Trent Nelson6b240cd2008-04-10 20:12:06 +0000823 'connecting to closed SSL socket should have failed')
824
825 t = threading.Thread(target=listener)
826 t.start()
827 connector()
828 t.join()
829
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000830 def testProtocolSSL2(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000831 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000832 sys.stdout.write("\n")
833 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True)
834 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL)
835 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED)
836 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True)
837 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False)
838 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False)
839
840 def testProtocolSSL23(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000841 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000842 sys.stdout.write("\n")
843 try:
844 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv2, True)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000845 except support.TestFailed as x:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000846 # this fails on some older versions of OpenSSL (0.9.7l, for instance)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000847 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000848 sys.stdout.write(
849 " SSL2 client to SSL23 server test unexpectedly failed:\n %s\n"
850 % str(x))
851 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True)
852 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True)
853 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True)
854
855 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
856 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_OPTIONAL)
857 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
858
859 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
860 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_REQUIRED)
861 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
862
863 def testProtocolSSL3(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000864 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000865 sys.stdout.write("\n")
866 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True)
867 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
868 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
869 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False)
870 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, False)
871 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False)
872
873 def testProtocolTLS1(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000874 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000875 sys.stdout.write("\n")
876 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True)
877 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
878 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
879 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False)
880 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False)
881 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv23, False)
882
883 def testSTARTTLS (self):
884
Bill Janssen40a0f662008-08-12 16:56:25 +0000885 msgs = ("msg 1", "MSG 2", "STARTTLS", "MSG 3", "msg 4", "ENDTLS", "msg 5", "msg 6")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000886
Trent Nelson78520002008-04-10 20:54:35 +0000887 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000888 ssl_version=ssl.PROTOCOL_TLSv1,
889 starttls_server=True,
890 chatty=True,
891 connectionchatty=True)
892 flag = threading.Event()
893 server.start(flag)
894 # wait for it to start
895 flag.wait()
896 # try to connect
897 wrapped = False
898 try:
899 try:
900 s = socket.socket()
901 s.setblocking(1)
Trent Nelson78520002008-04-10 20:54:35 +0000902 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000903 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000904 raise support.TestFailed("Unexpected exception: " + str(x))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000905 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000906 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000907 sys.stdout.write("\n")
908 for indata in msgs:
Bill Janssen6e027db2007-11-15 22:23:56 +0000909 msg = indata.encode('ASCII', 'replace')
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000910 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000911 sys.stdout.write(
Bill Janssen6e027db2007-11-15 22:23:56 +0000912 " client: sending %s...\n" % repr(msg))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000913 if wrapped:
Bill Janssen6e027db2007-11-15 22:23:56 +0000914 conn.write(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000915 outdata = conn.read()
916 else:
Bill Janssen6e027db2007-11-15 22:23:56 +0000917 s.send(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000918 outdata = s.recv(1024)
919 if (indata == "STARTTLS" and
Bill Janssen6e027db2007-11-15 22:23:56 +0000920 str(outdata, 'ASCII', 'replace').strip().lower().startswith("ok")):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000921 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000922 msg = str(outdata, 'ASCII', 'replace')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000923 sys.stdout.write(
924 " client: read %s from server, starting TLS...\n"
Bill Janssen6e027db2007-11-15 22:23:56 +0000925 % repr(msg))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000926 conn = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000927 wrapped = True
Bill Janssen40a0f662008-08-12 16:56:25 +0000928 elif (indata == "ENDTLS" and
929 str(outdata, 'ASCII', 'replace').strip().lower().startswith("ok")):
930 if support.verbose:
931 msg = str(outdata, 'ASCII', 'replace')
932 sys.stdout.write(
933 " client: read %s from server, ending TLS...\n"
934 % repr(msg))
935 s = conn.unwrap()
936 wrapped = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000937 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000938 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000939 msg = str(outdata, 'ASCII', 'replace')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000940 sys.stdout.write(
Bill Janssen6e027db2007-11-15 22:23:56 +0000941 " client: read %s from server\n" % repr(msg))
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000942 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000943 sys.stdout.write(" client: closing connection.\n")
944 if wrapped:
Bill Janssen6e027db2007-11-15 22:23:56 +0000945 conn.write("over\n".encode("ASCII", "strict"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000946 else:
Bill Janssen40a0f662008-08-12 16:56:25 +0000947 s.send("over\n".encode("ASCII", "strict"))
Bill Janssen6e027db2007-11-15 22:23:56 +0000948 if wrapped:
949 conn.close()
950 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000951 s.close()
952 finally:
953 server.stop()
954 server.join()
955
Bill Janssen54cc54c2007-12-14 22:08:56 +0000956 def testSocketServer(self):
Bill Janssen6e027db2007-11-15 22:23:56 +0000957
Trent Nelson78520002008-04-10 20:54:35 +0000958 server = OurHTTPSServer(CERTFILE)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000959 flag = threading.Event()
960 server.start(flag)
961 # wait for it to start
962 flag.wait()
963 # try to connect
964 try:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000965 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000966 sys.stdout.write('\n')
967 d1 = open(CERTFILE, 'rb').read()
968 d2 = ''
969 # now fetch the same data from the HTTPS server
Trent Nelson78520002008-04-10 20:54:35 +0000970 url = 'https://%s:%d/%s' % (
971 HOST, server.port, os.path.split(CERTFILE)[1])
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000972 f = urllib.request.urlopen(url)
Barry Warsaw820c1202008-06-12 04:06:45 +0000973 dlen = f.info().get("content-length")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000974 if dlen and (int(dlen) > 0):
975 d2 = f.read(int(dlen))
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000976 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000977 sys.stdout.write(
978 " client: read %d bytes from remote server '%s'\n"
979 % (len(d2), server))
980 f.close()
981 except:
982 msg = ''.join(traceback.format_exception(*sys.exc_info()))
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000983 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000984 sys.stdout.write('\n' + msg)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000985 raise support.TestFailed(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000986 else:
987 if not (d1 == d2):
Bill Janssen6e027db2007-11-15 22:23:56 +0000988 print("d1 is", len(d1), repr(d1))
989 print("d2 is", len(d2), repr(d2))
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000990 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000991 "Couldn't fetch data from HTTPS server")
992 finally:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000993 if support.verbose:
Neal Norwitzf9ff5f02008-03-31 05:39:26 +0000994 sys.stdout.write('stopping server\n')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000995 server.stop()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000996 if support.verbose:
Neal Norwitzf9ff5f02008-03-31 05:39:26 +0000997 sys.stdout.write('joining thread\n')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000998 server.join()
999
Trent Nelson6b240cd2008-04-10 20:12:06 +00001000 def testAsyncoreServer(self):
1001
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001002 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001003 sys.stdout.write("\n")
1004
1005 indata="FOO\n"
Trent Nelson78520002008-04-10 20:54:35 +00001006 server = AsyncoreEchoServer(CERTFILE)
Trent Nelson6b240cd2008-04-10 20:12:06 +00001007 flag = threading.Event()
1008 server.start(flag)
1009 # wait for it to start
1010 flag.wait()
1011 # try to connect
1012 try:
1013 s = ssl.wrap_socket(socket.socket())
Trent Nelson78520002008-04-10 20:54:35 +00001014 s.connect((HOST, server.port))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001015 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001016 raise support.TestFailed("Unexpected SSL error: " + str(x))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001017 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001018 raise support.TestFailed("Unexpected exception: " + str(x))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001019 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001020 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001021 sys.stdout.write(
1022 " client: sending %s...\n" % (repr(indata)))
1023 s.sendall(indata.encode('ASCII', 'strict'))
1024 outdata = s.recv()
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001025 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001026 sys.stdout.write(" client: read %s\n" % repr(outdata))
1027 outdata = str(outdata, 'ASCII', 'strict')
1028 if outdata != indata.lower():
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001029 raise support.TestFailed(
Trent Nelson6b240cd2008-04-10 20:12:06 +00001030 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
1031 % (repr(outdata[:min(len(outdata),20)]), len(outdata),
1032 repr(indata[:min(len(indata),20)].lower()), len(indata)))
1033 s.write("over\n".encode("ASCII", "strict"))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001034 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001035 sys.stdout.write(" client: closing connection.\n")
1036 s.close()
1037 finally:
1038 server.stop()
1039 server.join()
1040
Bill Janssen58afe4c2008-09-08 16:45:19 +00001041 def testAllRecvAndSendMethods(self):
1042
1043 if support.verbose:
1044 sys.stdout.write("\n")
1045
1046 server = ThreadedEchoServer(CERTFILE,
1047 certreqs=ssl.CERT_NONE,
1048 ssl_version=ssl.PROTOCOL_TLSv1,
1049 cacerts=CERTFILE,
1050 chatty=True,
1051 connectionchatty=False)
1052 flag = threading.Event()
1053 server.start(flag)
1054 # wait for it to start
1055 flag.wait()
1056 # try to connect
1057 try:
1058 s = ssl.wrap_socket(socket.socket(),
1059 server_side=False,
1060 certfile=CERTFILE,
1061 ca_certs=CERTFILE,
1062 cert_reqs=ssl.CERT_NONE,
1063 ssl_version=ssl.PROTOCOL_TLSv1)
1064 s.connect((HOST, server.port))
1065 except ssl.SSLError as x:
1066 raise support.TestFailed("Unexpected SSL error: " + str(x))
1067 except Exception as x:
1068 raise support.TestFailed("Unexpected exception: " + str(x))
1069 else:
1070 # helper methods for standardising recv* method signatures
1071 def _recv_into():
1072 b = bytearray(b"\0"*100)
1073 count = s.recv_into(b)
1074 return b[:count]
1075
1076 def _recvfrom_into():
1077 b = bytearray(b"\0"*100)
1078 count, addr = s.recvfrom_into(b)
1079 return b[:count]
1080
1081 # (name, method, whether to expect success, *args)
1082 send_methods = [
1083 ('send', s.send, True, []),
1084 ('sendto', s.sendto, False, ["some.address"]),
1085 ('sendall', s.sendall, True, []),
1086 ]
1087 recv_methods = [
1088 ('recv', s.recv, True, []),
1089 ('recvfrom', s.recvfrom, False, ["some.address"]),
1090 ('recv_into', _recv_into, True, []),
1091 ('recvfrom_into', _recvfrom_into, False, []),
1092 ]
1093 data_prefix = "PREFIX_"
1094
1095 for meth_name, send_meth, expect_success, args in send_methods:
1096 indata = data_prefix + meth_name
1097 try:
1098 send_meth(indata.encode('ASCII', 'strict'), *args)
1099 outdata = s.read()
1100 outdata = str(outdata, 'ASCII', 'strict')
1101 if outdata != indata.lower():
1102 raise support.TestFailed(
1103 "While sending with <<{name:s}>> bad data "
1104 "<<{outdata:s}>> ({nout:d}) received; "
1105 "expected <<{indata:s}>> ({nin:d})\n".format(
1106 name=meth_name, outdata=repr(outdata[:20]),
1107 nout=len(outdata),
1108 indata=repr(indata[:20]), nin=len(indata)
1109 )
1110 )
1111 except ValueError as e:
1112 if expect_success:
1113 raise support.TestFailed(
1114 "Failed to send with method <<{name:s}>>; "
1115 "expected to succeed.\n".format(name=meth_name)
1116 )
1117 if not str(e).startswith(meth_name):
1118 raise support.TestFailed(
1119 "Method <<{name:s}>> failed with unexpected "
1120 "exception message: {exp:s}\n".format(
1121 name=meth_name, exp=e
1122 )
1123 )
1124
1125 for meth_name, recv_meth, expect_success, args in recv_methods:
1126 indata = data_prefix + meth_name
1127 try:
1128 s.send(indata.encode('ASCII', 'strict'))
1129 outdata = recv_meth(*args)
1130 outdata = str(outdata, 'ASCII', 'strict')
1131 if outdata != indata.lower():
1132 raise support.TestFailed(
1133 "While receiving with <<{name:s}>> bad data "
1134 "<<{outdata:s}>> ({nout:d}) received; "
1135 "expected <<{indata:s}>> ({nin:d})\n".format(
1136 name=meth_name, outdata=repr(outdata[:20]),
1137 nout=len(outdata),
1138 indata=repr(indata[:20]), nin=len(indata)
1139 )
1140 )
1141 except ValueError as e:
1142 if expect_success:
1143 raise support.TestFailed(
1144 "Failed to receive with method <<{name:s}>>; "
1145 "expected to succeed.\n".format(name=meth_name)
1146 )
1147 if not str(e).startswith(meth_name):
1148 raise support.TestFailed(
1149 "Method <<{name:s}>> failed with unexpected "
1150 "exception message: {exp:s}\n".format(
1151 name=meth_name, exp=e
1152 )
1153 )
1154 # consume data
1155 s.read()
1156
1157 s.write("over\n".encode("ASCII", "strict"))
1158 s.close()
1159 finally:
1160 server.stop()
1161 server.join()
1162
1163
Thomas Woutersed03b412007-08-28 21:37:11 +00001164def test_main(verbose=False):
1165 if skip_expected:
Benjamin Petersone549ead2009-03-28 21:42:05 +00001166 raise unittest.SkipTest("No SSL support")
Thomas Woutersed03b412007-08-28 21:37:11 +00001167
Trent Nelson78520002008-04-10 20:54:35 +00001168 global CERTFILE, SVN_PYTHON_ORG_ROOT_CERT
Thomas Woutersed03b412007-08-28 21:37:11 +00001169 CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir,
1170 "keycert.pem")
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001171 SVN_PYTHON_ORG_ROOT_CERT = os.path.join(
1172 os.path.dirname(__file__) or os.curdir,
1173 "https_svn_python_org_root.pem")
1174
1175 if (not os.path.exists(CERTFILE) or
1176 not os.path.exists(SVN_PYTHON_ORG_ROOT_CERT)):
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001177 raise support.TestFailed("Can't read certificate files!")
Bill Janssen6e027db2007-11-15 22:23:56 +00001178
Thomas Woutersed03b412007-08-28 21:37:11 +00001179 tests = [BasicTests]
1180
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001181 if support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00001182 tests.append(NetworkedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001183
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001184 if _have_threads:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001185 thread_info = support.threading_setup()
1186 if thread_info and support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00001187 tests.append(ThreadedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001188
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001189 support.run_unittest(*tests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001190
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001191 if _have_threads:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001192 support.threading_cleanup(*thread_info)
Thomas Woutersed03b412007-08-28 21:37:11 +00001193
1194if __name__ == "__main__":
1195 test_main()