Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / webpagereplay / sslproxy.py
1 # Copyright 2014 Google Inc. All Rights Reserved.
2 #
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
6 #
7 #      http://www.apache.org/licenses/LICENSE-2.0
8 #
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.
14
15 """Extends BaseHTTPRequestHandler with SSL certificate generation."""
16
17 import logging
18 import socket
19
20 import certutils
21
22
23 class SslHandshakeHandler:
24   """Handles Server Name Indication (SNI) using dummy certs."""
25
26   def setup(self):
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()."""
32       try:
33         host = connection.get_servername()
34         if host:
35           cert_str = (
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)
42           return new_context
43         # else: fail with 'no shared cipher'
44       except Exception, e:
45         # Do not leak any exceptions or else openssl crashes.
46         logging.error('Exception in SNI handler', e)
47
48     context.set_tlsext_servername_callback(handle_servername)
49     self.connection = certutils.get_ssl_connection(context, self.connection)
50     self.connection.set_accept_state()
51     try:
52       self.connection.do_handshake()
53     except certutils.Error, v:
54       host = self.connection.get_servername()
55       if not host:
56         logging.error('Dropping request without SNI')
57         return ''
58       raise certutils.Error('SSL handshake error %s: %s' % (host, str(v)))
59
60     # Re-wrap the read/write streams with our new connection.
61     self.rfile = socket._fileobject(self.connection, 'rb', self.rbufsize,
62                                     close=False)
63     self.wfile = socket._fileobject(self.connection, 'wb', self.wbufsize,
64                                     close=False)
65
66   def finish(self):
67     self.connection.shutdown()
68     self.connection.close()
69
70
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
75
76   class WrappedHandler(SslHandshakeHandler, handler_class):
77
78     def setup(self):
79       handler_class.setup(self)
80       SslHandshakeHandler.setup(self)
81
82     def finish(self):
83       handler_class.finish(self)
84       SslHandshakeHandler.finish(self)
85   return WrappedHandler