Added setting of ciphersuite with only high and better SSLv3 certs. This should...
[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, passwd_callback=None):
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 if passwd_callback:
40 ctx.set_passwd_cb = passwd_callback
41
42 ctx.set_cipher_list('ALL:!aNULL:!ADH:!eNULL:!LOW:!MEDIUM:!EXP:RC4+RSA:+HIGH')
43 ctx.use_certificate_file(cert)
44 ctx.use_privatekey_file(pkey)
45 ctx.load_client_ca(ca_cert)
46 ctx.load_verify_locations(ca_cert)
47 verify = SSL.VERIFY_PEER | SSL.VERIFY_FAIL_IF_NO_PEER_CERT
48 ctx.set_verify(verify, our_verify)
49 ctx.set_verify_depth(10)
50 ctx.set_options(SSL.OP_NO_SSLv2 | SSL.OP_NO_TLSv1)
51 return ctx
52
53
54
55 class BaseServer(SocketServer.TCPServer):
56 allow_reuse_address = 1
57
58 def __init__(self, server_addr, req_handler):
59 self._quit = False
60 self.allow_reuse_address = 1
61 SocketServer.TCPServer.__init__(self, server_addr, req_handler)
62
63 def stop(self):
64 self._quit = True
65
66 def serve_forever(self):
67 while not self._quit:
68 self.handle_request()
69 self.server_close()
70
71
72 class BaseSSLServer(BaseServer):
73 """ SSL-enabled variant """
74
75 def __init__(self, server_address, req_handler, pkey, cert, ca_cert, timeout=None):
76 self._timeout = timeout
77 self.ssl_ctx = CreateSSLContext(pkey, cert, ca_cert)
78
79 BaseServer.__init__(self, server_address, req_handler)
80
81 sock = socket.socket(self.address_family, self.socket_type)
82 con = SSL.Connection(self.ssl_ctx, sock)
83 self.socket = SSLConnection.SSLConnection(con)
84 if sys.version_info[:3] >= (2, 3, 0):
85 self.socket.settimeout(self._timeout)
86 self.server_bind()
87 self.server_activate()
88
89 host, port = self.socket.getsockname()[:2]
90 self.server_name = socket.getfqdn(host)
91 self.server_port = port
92
93
94 class HTTPSConnection(httplib.HTTPConnection):
95 "This class allows communication via SSL."
96
97 response_class = httplib.HTTPResponse
98
99 def __init__(self, host, port=None, ssl_context=None, strict=None, timeout=None):
100 httplib.HTTPConnection.__init__(self, host, port, strict)
101 self.ssl_ctx = ssl_context
102 self._timeout = timeout
103
104 def connect(self):
105 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
106 con = SSL.Connection(self.ssl_ctx, sock)
107 self.sock = SSLConnection.SSLConnection(con)
108 if sys.version_info[:3] >= (2, 3, 0):
109 self.sock.settimeout(self._timeout)
110 self.sock.connect((self.host, self.port))
111
112
113 class HTTPS(httplib.HTTP):
114 """Compatibility with 1.5 httplib interface
115
116 Python 1.5.2 did not have an HTTPS class, but it defined an
117 interface for sending http requests that is also useful for
118 https.
119 """
120
121 _connection_class = HTTPSConnection
122
123 def __init__(self, host='', port=None, ssl_context=None, strict=None, timeout=None):
124 self._setup(self._connection_class(host, port, ssl_context, strict, timeout))