Index: net/tools/testserver/testserver.py |
diff --git a/net/tools/testserver/testserver.py b/net/tools/testserver/testserver.py |
index 28405ffc17e871cabafb5d47ddf1c23c34af7745..f694bf718cbe969f71b15b22fb0bfa2e905ed0ca 100755 |
--- a/net/tools/testserver/testserver.py |
+++ b/net/tools/testserver/testserver.py |
@@ -19,15 +19,17 @@ import BaseHTTPServer |
import cgi |
import errno |
import httplib |
+import minica |
import optparse |
import os |
import random |
import re |
import select |
-import SocketServer |
import socket |
-import sys |
+import SocketServer |
import struct |
+import sys |
+import threading |
import time |
import urllib |
import urlparse |
@@ -105,25 +107,35 @@ class StoppableHTTPServer(BaseHTTPServer.HTTPServer): |
class HTTPServer(ClientRestrictingServerMixIn, StoppableHTTPServer): |
- """This is a specialization of StoppableHTTPerver that adds client |
+ """This is a specialization of StoppableHTTPServer that adds client |
verification.""" |
pass |
+class OCSPServer(ClientRestrictingServerMixIn, BaseHTTPServer.HTTPServer): |
+ """This is a specialization of HTTPServer that serves an |
+ OCSP response""" |
+ |
+ def serve_forever_on_thread(self): |
+ self.thread = threading.Thread(target = self.serve_forever, |
+ name = "OCSPServerThread") |
Ryan Sleevi
2012/03/09 22:07:53
Could you explain why the threading is necessary h
agl
2012/03/13 22:24:29
For the OCSP tests we need testserver to listen fo
|
+ self.thread.start() |
+ |
+ def stop_serving(self): |
+ self.shutdown() |
+ self.thread.join() |
class HTTPSServer(tlslite.api.TLSSocketServerMixIn, |
ClientRestrictingServerMixIn, |
StoppableHTTPServer): |
- """This is a specialization of StoppableHTTPerver that add https support and |
+ """This is a specialization of StoppableHTTPServer that add https support and |
client verification.""" |
- def __init__(self, server_address, request_hander_class, cert_path, |
+ def __init__(self, server_address, request_hander_class, pem_cert_and_key, |
ssl_client_auth, ssl_client_cas, ssl_bulk_ciphers, |
record_resume_info): |
- s = open(cert_path).read() |
- self.cert_chain = tlslite.api.X509CertChain().parseChain(s) |
- s = open(cert_path).read() |
- self.private_key = tlslite.api.parsePEMKey(s, private=True) |
+ self.cert_chain = tlslite.api.X509CertChain().parseChain(pem_cert_and_key) |
+ self.private_key = tlslite.api.parsePEMKey(pem_cert_and_key, private=True) |
self.ssl_client_auth = ssl_client_auth |
self.ssl_client_cas = [] |
for ca_file in ssl_client_cas: |
@@ -1876,6 +1888,21 @@ def MakeDataDir(): |
return my_data_dir |
+class OCSPHandler(BasePageHandler): |
+ def __init__(self, request, client_address, socket_server): |
+ handlers = [self.OCSPResponse] |
+ self.ocsp_response = socket_server.ocsp_response |
+ BasePageHandler.__init__(self, request, client_address, socket_server, |
+ handlers, handlers, handlers, |
+ handlers, handlers) |
Ryan Sleevi
2012/03/09 22:07:53
Seems inappropriate to pass handlers for the conne
agl
2012/03/13 22:24:29
Done.
|
+ |
+ def OCSPResponse(self): |
+ self.send_response(200) |
+ self.send_header('Content-Type', 'application/ocsp-response') |
+ self.send_header('Content-Length', str(len(self.ocsp_response))) |
+ self.end_headers() |
+ |
+ self.wfile.write(self.ocsp_response) |
class TCPEchoHandler(SocketServer.BaseRequestHandler): |
"""The RequestHandler class for TCP echo server. |
@@ -1956,19 +1983,53 @@ def main(options, args): |
server_data = {} |
server_data['host'] = host |
+ ocsp_server = None |
+ |
if options.server_type == SERVER_HTTP: |
if options.cert: |
- # let's make sure the cert file exists. |
- if not os.path.isfile(options.cert): |
- print 'specified server cert file not found: ' + options.cert + \ |
- ' exiting...' |
- return |
+ pem_cert_and_key = None |
+ if options.cert.startswith('__'): |
Ryan Sleevi
2012/03/09 22:07:53
As I mentioned in the C++ code, I strongly feel we
agl
2012/03/13 22:24:29
Done.
|
+ ocsp_server = OCSPServer((host, 0), OCSPHandler) |
+ print 'OCSP server on port ' + str(ocsp_server.server_port) |
+ |
+ ocsp_der = None |
+ ocsp_revoked = False |
+ ocsp_invalid = False |
+ |
+ if options.cert == '__ocsp_ok__': |
+ pass |
+ elif options.cert == '__ocsp_revoked__': |
+ ocsp_revoked = True |
+ elif options.cert == '__ocsp_invalid__': |
+ ocsp_invalid = True |
+ else: |
+ print 'unknown special certificate type: ' + options.cert |
+ return |
+ |
+ (pem_cert_and_key, ocsp_der) = \ |
+ minica.GenerateCertKeyAndOCSP( |
+ subject = "127.0.0.1", |
+ ocsp_url = "http://127.0.0.1:%d/ocsp" % ocsp_server.server_port, |
+ ocsp_revoked = ocsp_revoked) |
+ |
+ if ocsp_invalid: |
+ ocsp_der = '3' |
+ |
+ ocsp_server.ocsp_response = ocsp_der |
+ else: |
+ # options.cert is a filename. Let's make sure the cert file exists. |
+ if not os.path.isfile(options.cert): |
+ print 'specified server cert file not found: ' + options.cert + \ |
+ ' exiting...' |
+ return |
+ pem_cert_and_key = file(options.cert, 'r').read() |
+ |
for ca_cert in options.ssl_client_ca: |
if not os.path.isfile(ca_cert): |
print 'specified trusted client CA file not found: ' + ca_cert + \ |
' exiting...' |
return |
- server = HTTPSServer((host, port), TestPageHandler, options.cert, |
+ server = HTTPSServer((host, port), TestPageHandler, pem_cert_and_key, |
options.ssl_client_auth, options.ssl_client_ca, |
options.ssl_bulk_cipher, options.record_resume) |
print 'HTTPS server started on %s:%d...' % (host, server.server_port) |
@@ -2048,10 +2109,15 @@ def main(options, args): |
startup_pipe.write(server_data_json) |
startup_pipe.close() |
+ if ocsp_server is not None: |
+ ocsp_server.serve_forever_on_thread() |
+ |
try: |
server.serve_forever() |
except KeyboardInterrupt: |
print 'shutting down server' |
+ if ocsp_server is not None: |
+ ocsp_server.stop_serving() |
server.stop = True |
if __name__ == '__main__': |