~ubuntu-branches/ubuntu/karmic/kaa-base/karmic

« back to all changes in this revision

Viewing changes to src/net/tls.py

  • Committer: Bazaar Package Importer
  • Author(s): A Mennucc1
  • Date: 2008-03-25 14:12:15 UTC
  • mfrom: (2.1.1 lenny)
  • Revision ID: james.westby@ubuntu.com-20080325141215-unddr7llk7aghxma
Tags: 0.4.0-1
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 $
 
6
#
 
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.
 
10
#
 
11
# -----------------------------------------------------------------------------
 
12
# Copyright (C) 2008 Dirk Meyer
 
13
#
 
14
# First Edition: Dirk Meyer <dischi@freevo.org>
 
15
# Maintainer:    Dirk Meyer <dischi@freevo.org>
 
16
#
 
17
# Please see the file AUTHORS for a complete list of authors.
 
18
#
 
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.
 
22
#
 
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.
 
27
#
 
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
 
31
# 02110-1301 USA
 
32
#
 
33
# -----------------------------------------------------------------------------
 
34
 
 
35
# python imports
 
36
import sys
 
37
import logging
 
38
 
 
39
# import tlslite API to the namespace of this module
 
40
from tlslite.api import *
 
41
 
 
42
# import tlslite.api to overwrite TLSConnection
 
43
import tlslite.api
 
44
 
 
45
# kaa imports
 
46
import kaa
 
47
 
 
48
# get logging object
 
49
log = logging.getLogger('tls')
 
50
 
 
51
 
 
52
class TLSConnection(tlslite.api.TLSConnection):
 
53
    """
 
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
 
56
    kaa.notifier support.
 
57
    """
 
58
    @kaa.coroutine()
 
59
    def _iterate_handshake(self, handshake):
 
60
        """
 
61
        Iterate through the TLS handshake for asynchronous calls using
 
62
        kaa.notifier IOMonitor and InProgressCallback.
 
63
        """
 
64
        try:
 
65
            while True:
 
66
                n = handshake.next()
 
67
                cb = kaa.InProgressCallback()
 
68
                disp = kaa.notifier.IOMonitor(cb)
 
69
                if n == 0:
 
70
                    disp.register(self.sock.fileno(), kaa.notifier.IO_READ)
 
71
                if n == 1:
 
72
                    disp.register(self.sock.fileno(), kaa.notifier.IO_WRITE)
 
73
                yield cb
 
74
                disp.unregister()
 
75
        except StopIteration:
 
76
            pass
 
77
 
 
78
    def handshakeClientCert(self, certChain=None, privateKey=None, session=None,
 
79
                            settings=None, checker=None):
 
80
        """
 
81
        Perform a certificate-based handshake in the role of client.
 
82
        """
 
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)
 
87
 
 
88
    def handshakeServer(self, sharedKeyDB=None, verifierDB=None, certChain=None,
 
89
                        privateKey=None, reqCert=None, sessionCache=None,
 
90
                        settings=None, checker=None):
 
91
        """
 
92
        Start a server handshake operation on the TLS connection.
 
93
        """
 
94
        handshake = tlslite.api.TLSConnection.handshakeServerAsync(
 
95
            self, sharedKeyDB, verifierDB, certChain, privateKey, reqCert,
 
96
            sessionCache, settings, checker)
 
97
        return self._iterate_handshake(handshake)
 
98
 
 
99
    def fileno(self):
 
100
        """
 
101
        Return socket descriptor. This makes this class feel like a normal
 
102
        socket to the IOMonitor.
 
103
        """
 
104
        return self.sock.fileno()
 
105
 
 
106
    def close(self):
 
107
        """
 
108
        Close the socket.
 
109
        """
 
110
        if not self.closed:
 
111
            # force socket close or this will block
 
112
            # on kaa shutdown.
 
113
            self.sock.close()
 
114
        return tlslite.api.TLSConnection.close(self)
 
115
 
 
116
 
 
117
class TLSSocket(kaa.Socket):
 
118
    """
 
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.
 
122
    """
 
123
    def __init__(self):
 
124
        kaa.Socket.__init__(self)
 
125
        self.signals['tls'] = kaa.Signal()
 
126
        self._handshake = False
 
127
 
 
128
    def _accept(self):
 
129
        """
 
130
        Accept a new connection and return a new Socket object.
 
131
        """
 
132
        sock, addr = self._socket.accept()
 
133
        client_socket = TLSSocket()
 
134
        client_socket.wrap(sock, addr)
 
135
        self.signals['new-client'].emit(client_socket)
 
136
 
 
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.
 
144
        return
 
145
 
 
146
    def wrap(self, sock, addr = None):
 
147
        """
 
148
        Wraps an existing low-level socket object.  addr specifies the address
 
149
        corresponding to the socket.
 
150
        """
 
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)
 
156
 
 
157
    def write(self, data):
 
158
        """
 
159
        Write data to the socket. The data will be delayed while the socket
 
160
        is doing the TLS handshake.
 
161
        """
 
162
        if self._handshake:
 
163
            # do not send data while doing a handshake
 
164
            return self._write_buffer.append(data)
 
165
        return super(TLSSocket, self).write(data)
 
166
 
 
167
    def _handle_read(self):
 
168
        """
 
169
        Callback for new data on the socket.
 
170
        """
 
171
        try:
 
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)
 
178
 
 
179
    @kaa.coroutine()
 
180
    def starttls_client(self, session=None, key=None, **kwargs):
 
181
        """
 
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.
 
187
        """
 
188
        try:
 
189
            if key:
 
190
                kwargs['privateKey'] = key.key
 
191
                kwargs['certChain'] = key.chain
 
192
            self._handshake = True
 
193
            if session is None:
 
194
                session = Session()
 
195
            c = TLSConnection(self._socket)
 
196
            self._rmon.unregister()
 
197
            yield c.handshakeClientCert(session=session, **kwargs)
 
198
            self._socket = c
 
199
            self.signals['tls'].emit()
 
200
            self._rmon.register(self._socket.fileno(), kaa.IO_READ)
 
201
            self._handshake = False
 
202
        except:
 
203
            self._handshake = False
 
204
            type, value, tb = sys.exc_info()
 
205
            raise type, value, tb
 
206
 
 
207
    @kaa.coroutine()
 
208
    def starttls_server(self, key, **kwargs):
 
209
        """
 
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.
 
215
        """
 
216
        try:
 
217
            self._handshake = True
 
218
            c = TLSConnection(self._socket)
 
219
            self._rmon.unregister()
 
220
            yield c.handshakeServer(privateKey=key.key, certChain=key.chain, **kwargs)
 
221
            self._socket = c
 
222
            self.signals['tls'].emit()
 
223
            self._rmon.register(self._socket.fileno(), kaa.IO_READ)
 
224
            self._handshake = False
 
225
        except:
 
226
            self._handshake = False
 
227
            type, value, tb = sys.exc_info()
 
228
            raise type, value, tb
 
229
 
 
230
 
 
231
class TLSKey(object):
 
232
    """
 
233
    Class to hold the public (and private) key together with the certification chain.
 
234
    This class can be used with TLSSocket as key.
 
235
    """
 
236
    def __init__(self, filename, private, *certs):
 
237
        self.key = parsePEMKey(open(filename).read(), private=private)
 
238
        chain = []
 
239
        for cert in (filename, ) + certs:
 
240
            x509 = X509()
 
241
            x509.parse(open(cert).read())
 
242
            chain.append(x509)
 
243
        self.chain = X509CertChain(chain)