1
# -* -coding: iso-8859-1 -*-
2
# -----------------------------------------------------------------------------
3
# tls.py - TLS support for kaa.notifier based on tlslite
4
# -----------------------------------------------------------------------------
5
# $Id: tls.py 3200 2008-03-19 15:11:32Z dmeyer $
7
# This module wraps TLS for client and server based on tlslite. See
8
# http://trevp.net/tlslite/docs/public/tlslite.TLSConnection.TLSConnection-class.html
9
# for more information about optional paramater.
11
# -----------------------------------------------------------------------------
12
# Copyright (C) 2008 Dirk Meyer
14
# First Edition: Dirk Meyer <dischi@freevo.org>
15
# Maintainer: Dirk Meyer <dischi@freevo.org>
17
# Please see the file AUTHORS for a complete list of authors.
19
# This library is free software; you can redistribute it and/or modify
20
# it under the terms of the GNU Lesser General Public License version
21
# 2.1 as published by the Free Software Foundation.
23
# This library is distributed in the hope that it will be useful, but
24
# WITHOUT ANY WARRANTY; without even the implied warranty of
25
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
26
# Lesser General Public License for more details.
28
# You should have received a copy of the GNU Lesser General Public
29
# License along with this library; if not, write to the Free Software
30
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
33
# -----------------------------------------------------------------------------
39
# import tlslite API to the namespace of this module
40
from tlslite.api import *
42
# import tlslite.api to overwrite TLSConnection
49
log = logging.getLogger('tls')
52
class TLSConnection(tlslite.api.TLSConnection):
54
This class wraps a socket and provides TLS handshaking and data transfer.
55
It enhances the tlslite version of the class with the same name with
59
def _iterate_handshake(self, handshake):
61
Iterate through the TLS handshake for asynchronous calls using
62
kaa.notifier IOMonitor and InProgressCallback.
67
cb = kaa.InProgressCallback()
68
disp = kaa.notifier.IOMonitor(cb)
70
disp.register(self.sock.fileno(), kaa.notifier.IO_READ)
72
disp.register(self.sock.fileno(), kaa.notifier.IO_WRITE)
78
def handshakeClientCert(self, certChain=None, privateKey=None, session=None,
79
settings=None, checker=None):
81
Perform a certificate-based handshake in the role of client.
83
handshake = tlslite.api.TLSConnection.handshakeClientCert(
84
self, certChain=certChain, privateKey=privateKey, session=session,
85
settings=settings, checker=checker, async=True)
86
return self._iterate_handshake(handshake)
88
def handshakeServer(self, sharedKeyDB=None, verifierDB=None, certChain=None,
89
privateKey=None, reqCert=None, sessionCache=None,
90
settings=None, checker=None):
92
Start a server handshake operation on the TLS connection.
94
handshake = tlslite.api.TLSConnection.handshakeServerAsync(
95
self, sharedKeyDB, verifierDB, certChain, privateKey, reqCert,
96
sessionCache, settings, checker)
97
return self._iterate_handshake(handshake)
101
Return socket descriptor. This makes this class feel like a normal
102
socket to the IOMonitor.
104
return self.sock.fileno()
111
# force socket close or this will block
114
return tlslite.api.TLSConnection.close(self)
117
class TLSSocket(kaa.Socket):
119
Special version of kaa.Socket with TLS support. On creation the
120
connection is NOT encrypted, starttls_client and starttls_server
121
must be called to encrypt the connection.
124
kaa.Socket.__init__(self)
125
self.signals['tls'] = kaa.Signal()
126
self._handshake = False
130
Accept a new connection and return a new Socket object.
132
sock, addr = self._socket.accept()
133
client_socket = TLSSocket()
134
client_socket.wrap(sock, addr)
135
self.signals['new-client'].emit(client_socket)
137
def _update_read_monitor(self, signal = None, change = None):
138
# FIXME: This function is broken in TLSSocket for two reasons:
139
# 1. auto-reconnect while doing a tls handshake is wrong
140
# This could be fixed using self._handshake
141
# 2. Passing self._socket to register does not work,
142
# self._socket.fileno() is needed. Always using fileno()
143
# does not work for some strange reason.
146
def wrap(self, sock, addr = None):
148
Wraps an existing low-level socket object. addr specifies the address
149
corresponding to the socket.
151
super(TLSSocket, self).wrap(sock, addr)
152
# since _update_read_monitor is deactivated we need to always register
153
# the rmon to the notifier.
154
if not self._rmon.active():
155
self._rmon.register(self._socket.fileno(), kaa.IO_READ)
157
def write(self, data):
159
Write data to the socket. The data will be delayed while the socket
160
is doing the TLS handshake.
163
# do not send data while doing a handshake
164
return self._write_buffer.append(data)
165
return super(TLSSocket, self).write(data)
167
def _handle_read(self):
169
Callback for new data on the socket.
172
return super(TLSSocket, self)._handle_read()
173
except TLSAbruptCloseError, e:
174
log.error('TLSAbruptCloseError')
175
self._read_signal.emit(None)
176
self._readline_signal.emit(None)
177
return self.close(immediate=True, expected=False)
180
def starttls_client(self, session=None, key=None, **kwargs):
182
Start a certificate-based handshake in the role of a TLS client.
183
Note: this function DOES NOT check the server key based on the
184
key chain. Provide a checker callback to be called for verification.
185
http://trevp.net/tlslite/docs/public/tlslite.Checker.Checker-class.html
186
Every callable object can be used as checker.
190
kwargs['privateKey'] = key.key
191
kwargs['certChain'] = key.chain
192
self._handshake = True
195
c = TLSConnection(self._socket)
196
self._rmon.unregister()
197
yield c.handshakeClientCert(session=session, **kwargs)
199
self.signals['tls'].emit()
200
self._rmon.register(self._socket.fileno(), kaa.IO_READ)
201
self._handshake = False
203
self._handshake = False
204
type, value, tb = sys.exc_info()
205
raise type, value, tb
208
def starttls_server(self, key, **kwargs):
210
Start a certificate-based handshake in the role of a TLS server.
211
Note: this function DOES NOT check the client key if requested,
212
provide a checker callback to be called for verification.
213
http://trevp.net/tlslite/docs/public/tlslite.Checker.Checker-class.html
214
Every callable object can be used as checker.
217
self._handshake = True
218
c = TLSConnection(self._socket)
219
self._rmon.unregister()
220
yield c.handshakeServer(privateKey=key.key, certChain=key.chain, **kwargs)
222
self.signals['tls'].emit()
223
self._rmon.register(self._socket.fileno(), kaa.IO_READ)
224
self._handshake = False
226
self._handshake = False
227
type, value, tb = sys.exc_info()
228
raise type, value, tb
231
class TLSKey(object):
233
Class to hold the public (and private) key together with the certification chain.
234
This class can be used with TLSSocket as key.
236
def __init__(self, filename, private, *certs):
237
self.key = parsePEMKey(open(filename).read(), private=private)
239
for cert in (filename, ) + certs:
241
x509.parse(open(cert).read())
243
self.chain = X509CertChain(chain)