[Twisted-Python] PyOpenSSL empty socket property

Glyph glyph at twistedmatrix.com
Sun Sep 8 21:32:19 MDT 2019


Indeed, in Twisted, the SSL.Connection is constructed with a memory BIO. And in fact there may not be a socket in the loop at all!

What are you trying to do with `getpeername()`?  Hopefully there's a similar Twisted API that you could work with.

-glyph

> On Sep 5, 2019, at 11:07 PM, Sean DiZazzo <sean.dizazzo at gmail.com> wrote:
> 
> Perhaps this line from OpenSSL.SSL.Connection is a clue.
> 
> "socket may be None; in this case, the Connection is created with a memory BIO: see the bio_read(), bio_write(), and bio_shutdown() methods."
> https://www.pyopenssl.org/en/stable/api/ssl.html#OpenSSL.SSL.Connection <https://www.pyopenssl.org/en/stable/api/ssl.html#OpenSSL.SSL.Connection>
> 
> On Wed, Sep 4, 2019 at 1:38 AM Arn Vollebregt <kpn.arn.vollebregt at gmail.com <mailto:kpn.arn.vollebregt at gmail.com>> wrote:
> Hi,
> 
> I noticed that PyOpenSSL SNI callbacks (set with ctx.set_tlsext_servername_callback) receive a OpenSSL.SSL.Connection object within Twisted that have an empty _socket property, while this property is actually set when using PyOpenSSL directly. For my use-case this is a problem as I want to call conn._socket.getpeername() to determine the peer's IP address. So I am wondering: why is this behaviour different? And how do I get the peer IP address?
> 
> ---console---
> user:~$ sudo python testTwisted.py &
> [3] 32842
> user:~$ curl -s --insecure --key clientPrivateKey.pem --cert clientCertificate.pem https://127.0.0.1 <https://127.0.0.1/> > /dev/null
> 'sniCallback' called.
>         conn._socket: None
> 'verifyCallback' called for result 0
>         conn._socket: None
> 'verifyCallback' called for result 1
>         conn._socket: None
> user:~$ sudo python testPyOpenSSL.py &
> [1] 33270
> user:~$ curl -s --insecure --key clientPrivateKey.pem --cert clientCertificate.pem https://127.0.0.1 <https://127.0.0.1/> > /dev/null
> 'sniCallback' called.
>         conn._socket: <socket._socketobject object at 0x7f34c5bd3130>
> <class 'OpenSSL.SSL.Connection'>
> 'verifyCallback' called for result 0
>         conn._socket: <socket._socketobject object at 0x7f34c5bd3130>
> 'verifyCallback' called for result 1
>         conn._socket: <socket._socketobject object at 0x7f34c5bd3130>
> 127.0.0.1 - - [29/Aug/2019 11:45:47] "GET / HTTP/1.1" 200 -
> ------
> 
> ---testTwisted.py---
> ### Generate server key material ###
> # openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout serverPrivateKey.pem -out serverCertificate.pem -subj "/C=''/O=''/OU=''/CN=server"
> ### Generate client key material ###
> # openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout clientPrivateKey.pem -out clientCertificate.pem -subj "/C=''/O=''/OU=''/CN=client"
> from __future__ import print_function
> #https://twistedmatrix.com/documents/12.0.0/core/howto/ssl.html <https://twistedmatrix.com/documents/12.0.0/core/howto/ssl.html>
> from OpenSSL import SSL
> from twisted.internet import ssl, reactor
> from twisted.web import server, resource
> from twisted.internet.protocol import Factory, Protocol
> 
> def verifyCallback(conn, cert, errno, depth, result):
>     print('\'verifyCallback\' called for result ' + str(result))
>     print('\tconn._socket: ' + str(conn._socket))
>     return True
> 
> def sniCallback(conn):
>     print('\'sniCallback\' called.')
>     print('\tconn._socket: ' + str(conn._socket))
> 
> class MainResource(resource.Resource):
>     isLeaf = True
> 
>     def render_GET(self, request):
>         request.responseHeaders.addRawHeader("Content-Type", "text/html; charset=utf-8")
>         return b"<html><body>Hello World</body></html>"
> 
> if __name__ == '__main__':
>     myContextFactory = ssl.DefaultOpenSSLContextFactory(
>         'serverPrivateKey.pem',
>         'serverCertificate.pem'
>     )
>     ctx = myContextFactory.getContext()
>     # https://www.pyopenssl.org/en/stable/api/ssl.html#OpenSSL.SSL.Context.set_verify <https://www.pyopenssl.org/en/stable/api/ssl.html#OpenSSL.SSL.Context.set_verify>
>     ctx.set_verify(SSL.VERIFY_PEER, verifyCallback)
>     # https://pyopenssl.org/en/stable/api/ssl.html#OpenSSL.SSL.Context.set_tlsext_servername_callback <https://pyopenssl.org/en/stable/api/ssl.html#OpenSSL.SSL.Context.set_tlsext_servername_callback>
>     ctx.set_tlsext_servername_callback(sniCallback)
> 
>     site = server.Site(MainResource())
>     reactor.listenSSL(443, site, myContextFactory)
>     reactor.run()
> ------
> 
> ---testPyOpenSSL.py---
> ### Generate server key material ###
> # openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout serverPrivateKey.pem -out serverCertificate.pem -subj "/C=''/O=''/OU=''/CN=server"
> ### Generate client key material ###
> # openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout clientPrivateKey.pem -out clientCertificate.pem -subj "/C=''/O=''/OU=''/CN=client"
> from __future__ import print_function
> import socket, sys, os
> from SocketServer import BaseServer
> from BaseHTTPServer import HTTPServer
> from SimpleHTTPServer import SimpleHTTPRequestHandler
> from OpenSSL import SSL
> 
> def verifyCallback(conn, cert, errno, depth, result):
>     print('\'verifyCallback\' called for result ' + str(result))
>     print('\tconn._socket: ' + str(conn._socket))
>     return True
> 
> def sniCallback(conn):
>     print('\'sniCallback\' called.')
>     print('\tconn._socket: ' + str(conn._socket))
>     print(type(conn))
> 
> class SecureHTTPServer(HTTPServer):
>     def __init__(self, server_address, HandlerClass):
>         BaseServer.__init__(self, server_address, HandlerClass)
>         ctx = SSL.Context(SSL.TLSv1_2_METHOD)
>         ctx.use_privatekey_file('serverPrivateKey.pem')
>         ctx.use_certificate_file('serverCertificate.pem')
>         # https://www.pyopenssl.org/en/stable/api/ssl.html#OpenSSL.SSL.Context.set_verify <https://www.pyopenssl.org/en/stable/api/ssl.html#OpenSSL.SSL.Context.set_verify>
>         ctx.set_verify(SSL.VERIFY_PEER, verifyCallback)
>         # https://pyopenssl.org/en/stable/api/ssl.html#OpenSSL.SSL.Context.set_tlsext_servername_callback <https://pyopenssl.org/en/stable/api/ssl.html#OpenSSL.SSL.Context.set_tlsext_servername_callback>
>         ctx.set_tlsext_servername_callback(sniCallback)
>         self.socket = SSL.Connection(ctx, socket.socket(self.address_family,self.socket_type))
>         self.server_bind()
>         self.server_activate()
>     
>     def shutdown_request(self,request):
>         request.shutdown()
> 
> class SecureHTTPRequestHandler(SimpleHTTPRequestHandler):
>     def setup(self):
>         self.connection = self.request
>         self.rfile = socket._fileobject(self.request, "rb", self.rbufsize)
>         self.wfile = socket._fileobject(self.request, "wb", self.wbufsize)
>     
>     def do_GET(self):
>         self.send_response(200)
>         SimpleHTTPRequestHandler.end_headers(self)
>         self.wfile.write('<html><body>Hello World</body></html>')
> 
> if __name__ == '__main__':
>     ip,port = ('0.0.0.0', 443)
>     httpd = SecureHTTPServer((ip, port), SecureHTTPRequestHandler)
>     httpd.serve_forever()
> ------
> 
> (Please note that even though these examples are for Python2 (due to other quirks) I am aiming to implement this in Python3.)
> 
> Regards,
> 
> Arn
> _______________________________________________
> Twisted-Python mailing list
> Twisted-Python at twistedmatrix.com <mailto:Twisted-Python at twistedmatrix.com>
> https://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python <https://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python>
> _______________________________________________
> Twisted-Python mailing list
> Twisted-Python at twistedmatrix.com
> https://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python

-------------- next part --------------
An HTML attachment was scrubbed...
URL: </pipermail/twisted-python/attachments/20190908/fb1b5723/attachment-0002.html>


More information about the Twisted-Python mailing list