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."""
24 def _SetUpUsingDummyCert(handler
):
25 """Sets up connection providing the certificate to the client.
27 This method handles Server Name Indication (SNI) using dummy certs.
30 handler: an instance of BaseHTTPServer.BaseHTTPRequestHandler that is used
31 by some instance of BaseHTTPServer.HTTPServer.
33 # One of: One of SSLv2_METHOD, SSLv3_METHOD, SSLv23_METHOD, or TLSv1_METHOD
34 context
= certutils
.get_ssl_context()
35 def handle_servername(connection
):
36 """A SNI callback that happens during do_handshake()."""
38 host
= connection
.get_servername()
41 handler
.server
.get_certificate(host
))
42 new_context
= certutils
.get_ssl_context()
43 cert
= certutils
.load_cert(cert_str
)
44 new_context
.use_certificate(cert
)
45 new_context
.use_privatekey_file(handler
.server
.ca_cert_path
)
46 connection
.set_context(new_context
)
48 # else: fail with 'no shared cipher'
50 # Do not leak any exceptions or else openssl crashes.
51 logging
.error('Exception in SNI handler: %s', e
)
53 context
.set_tlsext_servername_callback(handle_servername
)
54 handler
.connection
= certutils
.get_ssl_connection(context
, handler
.connection
)
55 handler
.connection
.set_accept_state()
57 handler
.connection
.do_handshake()
58 except certutils
.Error
, v
:
59 host
= handler
.connection
.get_servername()
61 logging
.error('Dropping request without SNI')
63 raise certutils
.Error('SSL handshake error %s: %s' % (host
, str(v
)))
65 # Re-wrap the read/write streams with our new connection.
66 handler
.rfile
= socket
._fileobject
(handler
.connection
, 'rb', handler
.rbufsize
,
68 handler
.wfile
= socket
._fileobject
(handler
.connection
, 'wb', handler
.wbufsize
,
72 def wrap_handler(handler_class
):
73 """Wraps a BaseHTTPHandler with SSL MITM certificates."""
74 if certutils
.openssl_import_error
:
75 # pylint: disable=raising-bad-type
76 raise certutils
.openssl_import_error
78 class WrappedHandler(handler_class
):
81 handler_class
.setup(self
)
82 _SetUpUsingDummyCert(self
)
85 handler_class
.finish(self
)
86 self
.connection
.shutdown()
87 self
.connection
.close()