source: TI12-security/branches/Dependencies/m2crypto/contrib/dispatcher.py @ 2172

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/branches/Dependencies/m2crypto/contrib/dispatcher.py@2237
Revision 2172, 5.0 KB checked in by pjkersha, 13 years ago (diff)
Line 
1#!/usr/local/bin/python -O
2"""
3   Implements a [hopefully] non-blocking SSL dispatcher on top of
4   M2Crypto package.
5   
6   Written by Ilya Etingof <ilya@glas.net>, 05/2001
7"""
8import asyncore, socket
9
10# M2Crypto
11from M2Crypto import SSL
12
13class _nb_connection (SSL.Connection):
14    """Functional equivalent of SSL.Connection class. Facilitates
15       possibly delayed socket.connect() and socket.accept()
16       termination.
17    """
18    def __init__ (self, ctx, sock):
19        SSL.Connection.__init__ (self, ctx, sock)
20       
21    def connect(self, addr):
22        self._setup_ssl(addr)
23        return self._check_ssl_return(SSL.m2.ssl_connect(self.ssl))
24
25    def accept(self, addr):
26        self._setup_ssl(addr)
27        self.accept_ssl()
28               
29class dispatcher(asyncore.dispatcher_with_send):
30    """A non-blocking SSL dispatcher that mimics the
31       asyncode.dispatcher API.
32    """
33    def __init__ (self, cert, key, sock=None, serving=None):
34        asyncore.dispatcher_with_send.__init__ (self)
35       
36        self.__serving = serving
37
38        # XXX
39        if sock:
40            if self.__serving:
41                self.set_socket(sock)
42        else:
43            self.create_socket (socket.AF_INET, socket.SOCK_STREAM)
44           
45        self.ctx = SSL.Context('sslv23')
46        self.ctx.set_verify(SSL.verify_none, 10)
47        self.ctx.load_cert(cert, key)
48        self.ctx.set_info_callback()
49
50        self.ssl = _nb_connection(self.ctx, self.socket)
51       
52        self.__output = ''
53        self.__want_write = 1
54
55    #
56    # The following are asyncore overloaded methods
57    #
58   
59    def handle_connect (self):
60        """Initiate SSL connection negotiation
61        """
62        if self.__serving:
63            self.ssl.accept (self.addr)
64
65            self.peer = self.ssl.get_peer_cert()
66       
67            self.handle_ssl_accept()
68
69        else:
70            self.ssl.connect (self.addr)
71
72            self.handle_ssl_connect()
73
74    def handle_read(self):
75        """Read user and/or SSL protocol data from SSL connection
76        """
77        ret = self.ssl._read_nbio()
78
79        if ret:
80            self.handle_ssl_read(ret)
81        else:
82            # Assume write is wanted
83            self.__want_write = 1
84
85    def handle_write(self):
86        """Write pending user and/or SSL protocol data down to SSL
87           connection
88        """
89        self.__want_write = 0
90
91        ret = self.ssl._write_nbio(self.__output)
92       
93        if ret < 0:
94            try:
95                err = SSL.m2.ssl_get_error(self.ssl.ssl, ret)
96
97            except SSL.SSLError:
98                return
99           
100            if err == SSL.m2.ssl_error_want_write:
101                self.__want_write = 1
102        else:
103            self.__output = self.__output[ret:]
104
105    def writable (self):
106        """Indicate that write is desired if here're some
107           user and/or SSL protocol data.
108        """
109        if self.__output or self.__want_write:
110            return 1
111
112        return self.ssl_writable()
113
114    def handle_close (self):
115        """Shutdown SSL connection.
116        """
117        self.ssl = None
118       
119        self.ctx = None
120        self.close ()
121
122        self.handle_ssl_close()
123
124    def handle_error (self, *info):
125        """A trap for asyncore errors
126        """
127        self.handle_ssl_error(info)
128
129    #
130    # The following are ssl.dispatcher API
131    #
132   
133    def ssl_connect(self, server):
134        """Initiate SSL connection
135        """
136        self.connect(server)
137   
138    def ssl_write(self, data):
139        """Write data to SSL connection
140        """
141        self.__output = self.__output + data
142
143    def ssl_close(self):
144        """Close SSL connection
145        """
146        self.handle_close()
147       
148    def handle_ssl_connect(self):
149        """Invoked on SSL connection establishment (whilst
150           in client mode)
151        """
152        print 'Unhandled handle_ssl_connect()'
153
154    def handle_ssl_accept(self):
155        """Invoked on SSL connection establishment (whilst
156           in server mode)
157        """
158        print 'Unhandled handle_ssl_accept()'
159       
160    def handle_ssl_read(self, data):
161        """Invoked on new data arrival to SSL connection
162        """
163        print 'Unhandled handle_ssl_read event'
164
165    def handle_ssl_close(self):
166        """Invoked on SSL connection termination
167        """
168        pass
169
170    def ssl_writable(self):
171        """Invoked prior to every select() call
172        """
173        return 0
174   
175if __name__=='__main__':
176    """Give it a test run
177    """
178    class client(dispatcher):
179        """SSL client class
180        """
181        def __init__ (self, cert, key):
182            dispatcher.__init__(self, cert, key)
183           
184        def handle_ssl_read(self, data):
185            print data           
186            self.ssl_write('test write')
187
188    ssl = client('test.cert', 'test.key')
189    ssl.ssl_connect(('localhost', 7777))
190   
191    asyncore.loop()
Note: See TracBrowser for help on using the repository browser.