Merge lp:~andrea.corbellini/beeseek/ssl-sockets into lp:beeseek/1.0

Proposed by Andrea Corbellini
Status: Merged
Approved by: Andrea Corbellini
Approved revision: 238
Merged at revision: not available
Proposed branch: lp:~andrea.corbellini/beeseek/ssl-sockets
Merge into: lp:beeseek/1.0
Diff against target: None lines
To merge this branch: bzr merge lp:~andrea.corbellini/beeseek/ssl-sockets
Reviewer Review Type Date Requested Status
Andrea Corbellini Approve
Review via email: mp+3968@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Andrea Corbellini (andrea.corbellini) wrote :

This branch enables sockets to receive and send data using SSL encryption.
It requires pyopenssl.

Revision history for this message
Andrea Corbellini (andrea.corbellini) wrote :

Approved after discussion with team members.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'beeseek/network/lowlevel.py'
--- beeseek/network/lowlevel.py 2009-02-17 17:06:44 +0000
+++ beeseek/network/lowlevel.py 2009-02-25 17:00:00 +0000
@@ -18,12 +18,20 @@
18from select import select18from select import select
19from beeseek.interfaces import Interface, implements19from beeseek.interfaces import Interface, implements
2020
21try:
22 from cStringIO import StringIO
23except ImportError:
24 from StringIO import StringIO
25
26
21__all__ = ('SocketError', 'IProtocol', 'BaseProtocol', 'ISocket',27__all__ = ('SocketError', 'IProtocol', 'BaseProtocol', 'ISocket',
22 'BaseSocket', 'IPSocket', 'IPv6Socket', 'UNIXSocket',28 'BaseSocket', 'IPSocket', 'IPv6Socket', 'UNIXSocket',
23 'has_ipv6', 'has_unix')29 'has_ipv6', 'has_unix', 'has_ssl', 'SSLContext')
2430
2531
26SocketError = _socket.error32SocketError = _socket.error
33SSL_CLIENT = 0
34SSL_SERVER = 1
2735
28class IProtocol(Interface):36class IProtocol(Interface):
29 """Base interface for all network connectors.37 """Base interface for all network connectors.
@@ -142,6 +150,9 @@
142150
143 # Other socket methods151 # Other socket methods
144152
153 def fileno(self):
154 """Return the fileno."""
155
145 def waitinput(self, timeout=None):156 def waitinput(self, timeout=None):
146 """Wait for incoming data.157 """Wait for incoming data.
147158
@@ -150,6 +161,16 @@
150 :return: True if there is incoming data; else False.161 :return: True if there is incoming data; else False.
151 """162 """
152163
164 def enable_ssl(self, context=None, state=None):
165 """Read and write data using an SSL connection.
166
167 :param context: The SSLContext to use.
168 :param state: The connection state.
169 """
170
171 def disable_ssl(self):
172 """Read and write data using a standard connection."""
173
153 # Close methods174 # Close methods
154175
155 def close(self):176 def close(self):
@@ -181,7 +202,8 @@
181 high-level network objects.202 high-level network objects.
182 """203 """
183204
184 __slots__ = 'closed', '_sock', '_fileno', '_rfile', '_wfile'205 __slots__ = ('closed', '_sock', '_fileno', '_rfile', '_wfile',
206 '_rbuf', '_ssl')
185 implements(IProtocol, isbase=True)207 implements(IProtocol, isbase=True)
186208
187209
@@ -190,6 +212,7 @@
190 self._fileno = fileno = self._sock.fileno()212 self._fileno = fileno = self._sock.fileno()
191 self._rfile = os.fdopen(fileno, 'r', 0)213 self._rfile = os.fdopen(fileno, 'r', 0)
192 self._wfile = os.fdopen(fileno, 'w', bufsize)214 self._wfile = os.fdopen(fileno, 'w', bufsize)
215 self._ssl = None
193 self.closed = False216 self.closed = False
194217
195 # Connect/bind methods218 # Connect/bind methods
@@ -212,32 +235,111 @@
212235
213 def raw_recv(self, size=-1):236 def raw_recv(self, size=-1):
214 if size < 0:237 if size < 0:
215 size = 5120238 size = 8192
216 try:239 if not self._ssl:
217 data = os.read(self._fileno, size)240 try:
218 except IOError:241 data = os.read(self._fileno, size)
219 self.closed = True242 except IOError:
220 return ''243 self.closed = True
244 return ''
245 else:
246 rbuf = self._rbuf
247 rbuf.seek(0, 0)
248 data = rbuf.read(size)
249 self._rbuf = StringIO(rbuf.read())
250 if data:
251 return data
252 data = self._ssl.recv(size)
221 if not data:253 if not data:
222 self.closed = True254 self.closed = True
223 return data255 return data
224256
225 def raw_read(self, size=-1):257 def raw_read(self, size=-1):
226 try:258 if not self._ssl:
227 data = self._rfile.read(size)259 try:
228 except IOError:260 data = self._rfile.read(size)
229 self.closed = True261 except IOError:
230 return ''262 self.closed = True
263 return ''
264 else:
265 ssl = self._ssl
266 rbuf = self._rbuf
267 if size < 0:
268 self._rbuf = StringIO()
269 while True:
270 data = ssl.recv(8192)
271 if not data:
272 break
273 rbuf.write(data)
274 else:
275 rbuf.seek(0, 2)
276 buflen = rbuf.tell()
277 if buflen >= size:
278 rbuf.seek(0, 0)
279 data = rbuf.read(size)
280 self._rbuf = StringIO(rbuf.read())
281 return data
282 else:
283 self._rbuf = StringIO()
284 size -= buflen
285 while size:
286 data = ssl.recv(size)
287 if not data:
288 break
289 rbuf.write(data)
290 size -= len(data)
291 data = rbuf.getvalue()
231 if not data:292 if not data:
232 self.closed = True293 self.closed = True
233 return data294 return data
234295
235 def raw_readline(self, size=-1):296 def raw_readline(self, size=-1):
236 try:297 if not self._ssl:
237 data = self._rfile.readline(size)298 try:
238 except IOError:299 data = self._rfile.readline(size)
239 self.closed = True300 except IOError:
240 return ''301 self.closed = True
302 return ''
303 else:
304 ssl = self._ssl
305 rbuf = self._rbuf
306 rbuf.seek(0, 0)
307 if size < 0:
308 data = rbuf.readline()
309 if data.endswith('\n'):
310 self._rbuf = StringIO()
311 return data
312 while True:
313 data = ssl.recv(8192)
314 if not data:
315 self._rbuf = StringIO()
316 break
317 newline = data.find('\n') + 1
318 if newline > 0:
319 rbuf.write(data[:newline])
320 self._rbuf = StringIO(data[newline:])
321 break
322 rbuf.write(data)
323 data = rbuf.read()
324 else:
325 data = rbuf.readline(size)
326 size -= len(data)
327 if not size or data.endswith('\n'):
328 self._rbuf = StringIO(rbuf.read())
329 return data
330 self._rbuf = StringIO()
331 while size:
332 data = ssl.recv(size)
333 if not data:
334 break
335 newline = data.find('\n') + 1
336 if newline > 0:
337 rbuf.write(data[:newline])
338 self._rbuf.write(data[newline:])
339 break
340 size -= len(data)
341 rbuf.write(data)
342 data = rbuf.getvalue()
241 if not data:343 if not data:
242 self.closed = True344 self.closed = True
243 return data345 return data
@@ -245,16 +347,22 @@
245 # Send methods347 # Send methods
246348
247 def raw_write(self, data):349 def raw_write(self, data):
248 try:350 if not self._ssl:
249 self._wfile.write(data)351 try:
250 except IOError:352 self._wfile.write(data)
251 self.closed = True353 except IOError:
354 self.closed = True
355 else:
356 self._ssl.sendall(data)
252357
253 def raw_writelines(self, data):358 def raw_writelines(self, data):
254 try:359 if not self._ssl:
255 self._wfile.writelines(data)360 try:
256 except IOError:361 self._wfile.writelines(data)
257 self.closed = True362 except IOError:
363 self.closed = True
364 else:
365 self._ssl.sendall(''.join(data))
258366
259 def flush(self):367 def flush(self):
260 try:368 try:
@@ -268,12 +376,29 @@
268 return self._fileno376 return self._fileno
269377
270 def waitinput(self, timeout=None):378 def waitinput(self, timeout=None):
271 return bool(select((self._rfile,), (), (), timeout))379 return bool(select((self._rfile,), (), (), timeout)[0])
380
381 def enable_ssl(self, context=None, state=SSL_CLIENT):
382 if not context:
383 context = SSLContext()
384 self._ssl = ssl = SSL.Connection(context, self._sock)
385 if state == SSL_CLIENT:
386 ssl.set_connect_state()
387 elif state == SSL_SERVER:
388 ssl.set_accept_state()
389 self._rbuf = StringIO()
390
391 def disable_ssl(self):
392 self._ssl.shutdown()
393 self._ssl = None
394 del self._rbuf
272395
273 # Close methods396 # Close methods
274397
275 def close(self):398 def close(self):
276 self.flush()399 self.flush()
400 if self._ssl:
401 self.disable_ssl()
277 try:402 try:
278 self._sock.shutdown(_socket.SHUT_RDWR)403 self._sock.shutdown(_socket.SHUT_RDWR)
279 except SocketError:404 except SocketError:
@@ -384,3 +509,20 @@
384 family = _socket.AF_UNIX509 family = _socket.AF_UNIX
385else:510else:
386 has_unix = False511 has_unix = False
512
513
514try:
515 from OpenSSL import SSL
516 from OpenSSL.SSL import ZeroReturnError
517except ImportError:
518 has_ssl = False
519else:
520 has_ssl = True
521 class SSLContext(object):
522
523 def __new__(cls, pemfile=None, certfile=None):
524 context = SSL.Context(SSL.SSLv23_METHOD)
525 if pemfile:
526 context.use_privatekey_file(pemfile)
527 context.use_certificate_file(certfile)
528 return context

Subscribers

People subscribed via source and target branches