1 # Copyright 2014 Google Inc. All Rights Reserved.
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
15 """Extends BaseHTTPRequestHandler with SSL certificate generation."""
23 class SslHandshakeHandler:
24 """Handles Server Name Indication (SNI) using dummy certs."""
27 """Sets up connection providing the certificate to the client."""
28 # One of: One of SSLv2_METHOD, SSLv3_METHOD, SSLv23_METHOD, or TLSv1_METHOD
29 context = certutils.get_ssl_context()
30 def handle_servername(connection):
31 """A SNI callback that happens during do_handshake()."""
33 host = connection.get_servername()
36 self.server.http_archive_fetch.http_archive.get_certificate(host))
37 new_context = certutils.get_ssl_context()
38 cert = certutils.load_cert(cert_str)
39 new_context.use_certificate(cert)
40 new_context.use_privatekey_file(self.server.ca_cert_path)
41 connection.set_context(new_context)
43 # else: fail with 'no shared cipher'
45 # Do not leak any exceptions or else openssl crashes.
46 logging.error('Exception in SNI handler', e)
48 context.set_tlsext_servername_callback(handle_servername)
49 self.connection = certutils.get_ssl_connection(context, self.connection)
50 self.connection.set_accept_state()
52 self.connection.do_handshake()
53 except certutils.Error, v:
54 host = self.connection.get_servername()
56 logging.error('Dropping request without SNI')
58 raise certutils.Error('SSL handshake error %s: %s' % (host, str(v)))
60 # Re-wrap the read/write streams with our new connection.
61 self.rfile = socket._fileobject(self.connection, 'rb', self.rbufsize,
63 self.wfile = socket._fileobject(self.connection, 'wb', self.wbufsize,
67 self.connection.shutdown()
68 self.connection.close()
71 def wrap_handler(handler_class):
72 """Wraps a BaseHTTPHandler wtih SSL MITM certificates."""
73 if certutils.openssl_import_error:
74 raise certutils.openssl_import_error
76 class WrappedHandler(SslHandshakeHandler, handler_class):
79 handler_class.setup(self)
80 SslHandshakeHandler.setup(self)
83 handler_class.finish(self)
84 SslHandshakeHandler.finish(self)