merge with the code from func
[certmaster.git] / certmaster / SSLCommon.py
1 # This program is free software; you can redistribute it and/or modify
2 # it under the terms of the GNU General Public License as published by
3 # the Free Software Foundation; either version 2 of the License, or
4 # (at your option) any later version.
5 #
6 # This program is distributed in the hope that it will be useful,
7 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 # GNU Library General Public License for more details.
10 #
11 # You should have received a copy of the GNU General Public License
12 # along with this program; if not, write to the Free Software
13 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
14 #
15 # Copyright 2005 Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
16
17 import os, sys
18 from OpenSSL import SSL
19 import SSLConnection
20 import httplib
21 import socket
22 import SocketServer
23
24 def our_verify(connection, x509, errNum, errDepth, preverifyOK):
25 # print "Verify: errNum = %s, errDepth = %s, preverifyOK = %s" % (errNum, errDepth, preverifyOK)
26
27 # preverifyOK should tell us whether or not the client's certificate
28 # correctly authenticates against the CA chain
29 return preverifyOK
30
31
32 def CreateSSLContext(pkey, cert, ca_cert):
33 for f in pkey, cert, ca_cert:
34 if f and not os.access(f, os.R_OK):
35 print "%s does not exist or is not readable." % f
36 os._exit(1)
37
38 ctx = SSL.Context(SSL.SSLv3_METHOD) # SSLv3 only
39 ctx.use_certificate_file(cert)
40 ctx.use_privatekey_file(pkey)
41 ctx.load_client_ca(ca_cert)
42 ctx.load_verify_locations(ca_cert)
43 verify = SSL.VERIFY_PEER | SSL.VERIFY_FAIL_IF_NO_PEER_CERT
44 ctx.set_verify(verify, our_verify)
45 ctx.set_verify_depth(10)
46 ctx.set_options(SSL.OP_NO_SSLv2 | SSL.OP_NO_TLSv1)
47 return ctx
48
49
50
51 class BaseServer(SocketServer.TCPServer):
52 allow_reuse_address = 1
53
54 def __init__(self, server_addr, req_handler):
55 self._quit = False
56 self.allow_reuse_address = 1
57 SocketServer.TCPServer.__init__(self, server_addr, req_handler)
58
59 def stop(self):
60 self._quit = True
61
62 def serve_forever(self):
63 while not self._quit:
64 self.handle_request()
65 self.server_close()
66
67
68 class BaseSSLServer(BaseServer):
69 """ SSL-enabled variant """
70
71 def __init__(self, server_address, req_handler, pkey, cert, ca_cert, timeout=None):
72 self._timeout = timeout
73 self.ssl_ctx = CreateSSLContext(pkey, cert, ca_cert)
74
75 BaseServer.__init__(self, server_address, req_handler)
76
77 sock = socket.socket(self.address_family, self.socket_type)
78 con = SSL.Connection(self.ssl_ctx, sock)
79 self.socket = SSLConnection.SSLConnection(con)
80 if sys.version_info[:3] >= (2, 3, 0):
81 self.socket.settimeout(self._timeout)
82 self.server_bind()
83 self.server_activate()
84
85 host, port = self.socket.getsockname()[:2]
86 self.server_name = socket.getfqdn(host)
87 self.server_port = port
88
89
90 class HTTPSConnection(httplib.HTTPConnection):
91 "This class allows communication via SSL."
92
93 response_class = httplib.HTTPResponse
94
95 def __init__(self, host, port=None, ssl_context=None, strict=None, timeout=None):
96 httplib.HTTPConnection.__init__(self, host, port, strict)
97 self.ssl_ctx = ssl_context
98 self._timeout = timeout
99
100 def connect(self):
101 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
102 con = SSL.Connection(self.ssl_ctx, sock)
103 self.sock = SSLConnection.SSLConnection(con)
104 if sys.version_info[:3] >= (2, 3, 0):
105 self.sock.settimeout(self._timeout)
106 self.sock.connect((self.host, self.port))
107
108
109 class HTTPS(httplib.HTTP):
110 """Compatibility with 1.5 httplib interface
111
112 Python 1.5.2 did not have an HTTPS class, but it defined an
113 interface for sending http requests that is also useful for
114 https.
115 """
116
117 _connection_class = HTTPSConnection
118
119 def __init__(self, host='', port=None, ssl_context=None, strict=None, timeout=None):
120 self._setup(self._connection_class(host, port, ssl_context, strict, timeout))
121