Re: PyOpenSSL empty socket property
Glyph <[email protected]> Sun, 8 Sep 2019 20:32:19 -0700
| Newsgroups | gmane.comp.python.twisted |
|---|---|
| Message-ID | <[email protected]> |
--===============5705995186937567742== Content-Type: multipart/alternative; boundary="Apple-Mail=_85FD3470-399C-4483-BD25-5D47DBFC9434" --Apple-Mail=_85FD3470-399C-4483-BD25-5D47DBFC9434 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=us-ascii 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 <[email protected]> = wrote: >=20 > Perhaps this line from OpenSSL.SSL.Connection is a clue. >=20 > "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> >=20 > On Wed, Sep 4, 2019 at 1:38 AM Arn Vollebregt = <[email protected] <mailto:[email protected]>> = wrote: > Hi, >=20 > 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? >=20 > ---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 - > ------ >=20 > ---testTwisted.py--- > ### Generate server key material ### > # openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout = serverPrivateKey.pem -out serverCertificate.pem -subj = "/C=3D''/O=3D''/OU=3D''/CN=3Dserver" > ### Generate client key material ### > # openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout = clientPrivateKey.pem -out clientCertificate.pem -subj = "/C=3D''/O=3D''/OU=3D''/CN=3Dclient" > 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 >=20 > def verifyCallback(conn, cert, errno, depth, result): > print('\'verifyCallback\' called for result ' + str(result)) > print('\tconn._socket: ' + str(conn._socket)) > return True >=20 > def sniCallback(conn): > print('\'sniCallback\' called.') > print('\tconn._socket: ' + str(conn._socket)) >=20 > class MainResource(resource.Resource): > isLeaf =3D True >=20 > def render_GET(self, request): > request.responseHeaders.addRawHeader("Content-Type", = "text/html; charset=3Dutf-8") > return b"<html><body>Hello World</body></html>" >=20 > if __name__ =3D=3D '__main__': > myContextFactory =3D ssl.DefaultOpenSSLContextFactory( > 'serverPrivateKey.pem', > 'serverCertificate.pem' > ) > ctx =3D myContextFactory.getContext() > # = https://www.pyopenssl.org/en/stable/api/ssl.html#OpenSSL.SSL.Context.set_v= erify = <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_tlsex= t_servername_callback = <https://pyopenssl.org/en/stable/api/ssl.html#OpenSSL.SSL.Context.set_tlse= xt_servername_callback> > ctx.set_tlsext_servername_callback(sniCallback) >=20 > site =3D server.Site(MainResource()) > reactor.listenSSL(443, site, myContextFactory) > reactor.run() > ------ >=20 > ---testPyOpenSSL.py--- > ### Generate server key material ### > # openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout = serverPrivateKey.pem -out serverCertificate.pem -subj = "/C=3D''/O=3D''/OU=3D''/CN=3Dserver" > ### Generate client key material ### > # openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout = clientPrivateKey.pem -out clientCertificate.pem -subj = "/C=3D''/O=3D''/OU=3D''/CN=3Dclient" > 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 >=20 > def verifyCallback(conn, cert, errno, depth, result): > print('\'verifyCallback\' called for result ' + str(result)) > print('\tconn._socket: ' + str(conn._socket)) > return True >=20 > def sniCallback(conn): > print('\'sniCallback\' called.') > print('\tconn._socket: ' + str(conn._socket)) > print(type(conn)) >=20 > class SecureHTTPServer(HTTPServer): > def __init__(self, server_address, HandlerClass): > BaseServer.__init__(self, server_address, HandlerClass) > ctx =3D 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_v= erify = <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_tlsex= t_servername_callback = <https://pyopenssl.org/en/stable/api/ssl.html#OpenSSL.SSL.Context.set_tlse= xt_servername_callback> > ctx.set_tlsext_servername_callback(sniCallback) > self.socket =3D SSL.Connection(ctx, = socket.socket(self.address_family,self.socket_type)) > self.server_bind() > self.server_activate() > =20 > def shutdown_request(self,request): > request.shutdown() >=20 > class SecureHTTPRequestHandler(SimpleHTTPRequestHandler): > def setup(self): > self.connection =3D self.request > self.rfile =3D socket._fileobject(self.request, "rb", = self.rbufsize) > self.wfile =3D socket._fileobject(self.request, "wb", = self.wbufsize) > =20 > def do_GET(self): > self.send_response(200) > SimpleHTTPRequestHandler.end_headers(self) > self.wfile.write('<html><body>Hello World</body></html>') >=20 > if __name__ =3D=3D '__main__': > ip,port =3D ('0.0.0.0', 443) > httpd =3D SecureHTTPServer((ip, port), SecureHTTPRequestHandler) > httpd.serve_forever() > ------ >=20 > (Please note that even though these examples are for Python2 (due to = other quirks) I am aiming to implement this in Python3.) >=20 > Regards, >=20 > Arn > _______________________________________________ > Twisted-Python mailing list > [email protected] = <mailto:[email protected]> > https://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python = <https://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python> > _______________________________________________ > Twisted-Python mailing list > [email protected] > https://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python --Apple-Mail=_85FD3470-399C-4483-BD25-5D47DBFC9434 Content-Transfer-Encoding: quoted-printable Content-Type: text/html; charset=us-ascii <html><head><meta http-equiv=3D"Content-Type" content=3D"text/html; = charset=3Dus-ascii"></head><body style=3D"word-wrap: break-word; = -webkit-nbsp-mode: space; line-break: after-white-space;" = class=3D"">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!<div class=3D""><br class=3D""></div><div class=3D"">What are you = trying to do with `getpeername()`? Hopefully there's a similar = Twisted API that you could work with.<br class=3D""><div class=3D""><br = class=3D""></div><div class=3D"">-glyph<br class=3D""><div><br = class=3D""><blockquote type=3D"cite" class=3D""><div class=3D"">On Sep = 5, 2019, at 11:07 PM, Sean DiZazzo <<a = href=3D"mailto:[email protected]" = class=3D"">[email protected]</a>> wrote:</div><br = class=3D"Apple-interchange-newline"><div class=3D""><div dir=3D"ltr" = class=3D""><div dir=3D"ltr" class=3D"">Perhaps this line from = OpenSSL.SSL.Connection is a clue.<div class=3D""><br class=3D""></div><div= class=3D"">"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."<div class=3D""><a = href=3D"https://www.pyopenssl.org/en/stable/api/ssl.html#OpenSSL.SSL.Conne= ction" = class=3D"">https://www.pyopenssl.org/en/stable/api/ssl.html#OpenSSL.SSL.Co= nnection</a><span = style=3D"color:rgb(64,64,64);font-family:Lato,proxima-nova,"Helvetica= = Neue",Arial,sans-serif;font-size:16px;background-color:rgb(252,252,25= 2)" class=3D""><br class=3D""></span></div></div><input = name=3D"virtru-metadata" type=3D"hidden" = value=3D"{"email-policy":{"state":"closed",&= quot;expirationUnit":"days","disableCopyPaste":fa= lse,"disablePrint":false,"disableForwarding":false,&qu= ot;enableNoauth":false,"persistentProtection":false,"e= xpandedWatermarking":false,"expires":false,"isManaged&= quot;:false},"attachments":{},"compose-id":"1&quo= t;,"compose-window":{"secure":false}}" = class=3D""></div><br class=3D""><div class=3D"gmail_quote" style=3D""><div= dir=3D"ltr" class=3D"gmail_attr">On Wed, Sep 4, 2019 at 1:38 AM Arn = Vollebregt <<a href=3D"mailto:[email protected]" = class=3D"">[email protected]</a>> wrote:<br = class=3D""></div><blockquote class=3D"gmail_quote" style=3D"margin:0px = 0px 0px 0.8ex;border-left:1px solid = rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr" class=3D""><div = class=3D"">Hi,</div><div class=3D""><br class=3D""></div><div class=3D"">I= noticed that PyOpenSSL SNI callbacks (set with <i = class=3D"">ctx.set_tlsext_servername_callback</i>) receive a <i = class=3D"">OpenSSL.SSL.Connection</i> object within Twisted that have an = empty <i class=3D"">_socket</i> property, while this property <u = class=3D"">is</u> actually set when using <i class=3D"">PyOpenSSL</i> = directly. For my use-case this is a problem as I want to call <i = class=3D"">conn._socket.getpeername()</i> 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?</div><div class=3D""><br class=3D""></div><div = class=3D"">---console---</div><div class=3D"">user:~$ sudo python = testTwisted.py &</div><div class=3D"">[3] 32842</div><div = class=3D"">user:~$ curl -s --insecure --key clientPrivateKey.pem --cert = clientCertificate.pem <a href=3D"https://127.0.0.1/" target=3D"_blank" = class=3D"">https://127.0.0.1</a> > /dev/null<br = class=3D"">'sniCallback' called.<br class=3D""> = conn._socket: None<br class=3D"">'verifyCallback' called for = result 0<br class=3D""> conn._socket: None<br = class=3D"">'verifyCallback' called for result 1<br class=3D""> = conn._socket: None</div><div class=3D"">user:~$ = sudo python testPyOpenSSL.py &<br class=3D"">[1] 33270</div><div = class=3D"">user:~$ curl -s --insecure --key clientPrivateKey.pem --cert = clientCertificate.pem <a href=3D"https://127.0.0.1/" target=3D"_blank" = class=3D"">https://127.0.0.1</a> > /dev/null<br = class=3D"">'sniCallback' called.<br class=3D""> = conn._socket: <socket._socketobject object at = 0x7f34c5bd3130><br class=3D""><class = 'OpenSSL.SSL.Connection'><br class=3D"">'verifyCallback' called for = result 0<br class=3D""> conn._socket: = <socket._socketobject object at 0x7f34c5bd3130><br = class=3D"">'verifyCallback' called for result 1<br class=3D""> = conn._socket: <socket._socketobject object at = 0x7f34c5bd3130><br class=3D"">127.0.0.1 - - [29/Aug/2019 11:45:47] = "GET / HTTP/1.1" 200 -</div><div class=3D"">------<br = class=3D""></div><div class=3D""><br class=3D""></div><div = class=3D"">---testTwisted.py---</div><div class=3D"">### Generate server = key material ###<br class=3D""># openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout=20 serverPrivateKey.pem -out serverCertificate.pem -subj=20 "/C=3D''/O=3D''/OU=3D''/CN=3Dserver"<br class=3D"">### Generate client = key material ###<br class=3D""># openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout=20 clientPrivateKey.pem -out clientCertificate.pem -subj=20 "/C=3D''/O=3D''/OU=3D''/CN=3Dclient"<br class=3D"">from __future__ = import print_function<br class=3D"">#<a = href=3D"https://twistedmatrix.com/documents/12.0.0/core/howto/ssl.html" = target=3D"_blank" = class=3D"">https://twistedmatrix.com/documents/12.0.0/core/howto/ssl.html<= /a><br class=3D"">from OpenSSL import SSL<br class=3D"">from = twisted.internet import ssl, reactor<br class=3D"">from twisted.web = import server, resource<br class=3D"">from twisted.internet.protocol = import Factory, Protocol<br class=3D""><br class=3D"">def = verifyCallback(conn, cert, errno, depth, result):<br class=3D""> = print('\'verifyCallback\' called for result ' + str(result))<br = class=3D""> print('\tconn._socket: ' + = str(conn._socket))<br class=3D""> return True<br = class=3D""><br class=3D"">def sniCallback(conn):<br class=3D""> = print('\'sniCallback\' called.')<br class=3D""> = print('\tconn._socket: ' + str(conn._socket))<br class=3D""><br = class=3D"">class MainResource(resource.Resource):<br class=3D""> = isLeaf =3D True<br class=3D""><br class=3D""> def = render_GET(self, request):<br class=3D""> = request.responseHeaders.addRawHeader("Content-Type", "text/html; = charset=3Dutf-8")<br class=3D""> return = b"<html><body>Hello World</body></html>"<br = class=3D""><br class=3D"">if __name__ =3D=3D '__main__':<br = class=3D""> myContextFactory =3D = ssl.DefaultOpenSSLContextFactory(<br class=3D""> = 'serverPrivateKey.pem',<br class=3D""> = 'serverCertificate.pem'<br class=3D""> )<br class=3D""> = ctx =3D myContextFactory.getContext()<br class=3D""> = # <a = href=3D"https://www.pyopenssl.org/en/stable/api/ssl.html#OpenSSL.SSL.Conte= xt.set_verify" target=3D"_blank" = class=3D"">https://www.pyopenssl.org/en/stable/api/ssl.html#OpenSSL.SSL.Co= ntext.set_verify</a><br class=3D""> = ctx.set_verify(SSL.VERIFY_PEER, verifyCallback)<br class=3D""> = # <a = href=3D"https://pyopenssl.org/en/stable/api/ssl.html#OpenSSL.SSL.Context.s= et_tlsext_servername_callback" target=3D"_blank" = class=3D"">https://pyopenssl.org/en/stable/api/ssl.html#OpenSSL.SSL.Contex= t.set_tlsext_servername_callback</a><br class=3D""> = ctx.set_tlsext_servername_callback(sniCallback)<br class=3D""><br = class=3D""> site =3D server.Site(MainResource())<br = class=3D""> reactor.listenSSL(443, site, = myContextFactory)<br class=3D""> reactor.run()</div><div = class=3D"">------</div><div class=3D""><br class=3D""></div><div = class=3D"">---testPyOpenSSL.py---</div><div class=3D"">### Generate = server key material ###<br class=3D""># openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout=20 serverPrivateKey.pem -out serverCertificate.pem -subj=20 "/C=3D''/O=3D''/OU=3D''/CN=3Dserver"<br class=3D"">### Generate client = key material ###<br class=3D""># openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout=20 clientPrivateKey.pem -out clientCertificate.pem -subj=20 "/C=3D''/O=3D''/OU=3D''/CN=3Dclient"<br class=3D"">from __future__ = import print_function<br class=3D"">import socket, sys, os<br = class=3D"">from SocketServer import BaseServer<br class=3D"">from = BaseHTTPServer import HTTPServer<br class=3D"">from SimpleHTTPServer = import SimpleHTTPRequestHandler<br class=3D"">from OpenSSL import SSL<br = class=3D""><br class=3D"">def verifyCallback(conn, cert, errno, depth, = result):<br class=3D""> print('\'verifyCallback\' called = for result ' + str(result))<br class=3D""> = print('\tconn._socket: ' + str(conn._socket))<br class=3D""> = return True<br class=3D""><br class=3D"">def = sniCallback(conn):<br class=3D""> print('\'sniCallback\' = called.')<br class=3D""> print('\tconn._socket: ' + = str(conn._socket))<br class=3D""> print(type(conn))<br = class=3D""><br class=3D"">class SecureHTTPServer(HTTPServer):<br = class=3D""> def __init__(self, server_address, = HandlerClass):<br class=3D""> = BaseServer.__init__(self, server_address, HandlerClass)<br = class=3D""> ctx =3D = SSL.Context(SSL.TLSv1_2_METHOD)<br class=3D""> = ctx.use_privatekey_file('serverPrivateKey.pem')<br = class=3D""> = ctx.use_certificate_file('serverCertificate.pem')<br class=3D""> = # <a = href=3D"https://www.pyopenssl.org/en/stable/api/ssl.html#OpenSSL.SSL.Conte= xt.set_verify" target=3D"_blank" = class=3D"">https://www.pyopenssl.org/en/stable/api/ssl.html#OpenSSL.SSL.Co= ntext.set_verify</a><br class=3D""> = ctx.set_verify(SSL.VERIFY_PEER, verifyCallback)<br class=3D""> = # <a = href=3D"https://pyopenssl.org/en/stable/api/ssl.html#OpenSSL.SSL.Context.s= et_tlsext_servername_callback" target=3D"_blank" = class=3D"">https://pyopenssl.org/en/stable/api/ssl.html#OpenSSL.SSL.Contex= t.set_tlsext_servername_callback</a><br class=3D""> = ctx.set_tlsext_servername_callback(sniCallback)<br = class=3D""> self.socket =3D = SSL.Connection(ctx, = socket.socket(self.address_family,self.socket_type))<br class=3D""> = self.server_bind()<br class=3D""> = self.server_activate()<br class=3D""> <br = class=3D""> def shutdown_request(self,request):<br = class=3D""> request.shutdown()<br = class=3D""><br class=3D"">class = SecureHTTPRequestHandler(SimpleHTTPRequestHandler):<br class=3D""> = def setup(self):<br class=3D""> = self.connection =3D self.request<br class=3D""> = self.rfile =3D socket._fileobject(self.request, "rb", = self.rbufsize)<br class=3D""> self.wfile =3D = socket._fileobject(self.request, "wb", self.wbufsize)<br class=3D""> = <br class=3D""> def do_GET(self):<br = class=3D""> self.send_response(200)<br = class=3D""> = SimpleHTTPRequestHandler.end_headers(self)<br class=3D""> = self.wfile.write('<html><body>Hello = World</body></html>')<br class=3D""><br class=3D"">if = __name__ =3D=3D '__main__':<br class=3D""> ip,port =3D = ('0.0.0.0', 443)<br class=3D""> httpd =3D = SecureHTTPServer((ip, port), SecureHTTPRequestHandler)<br = class=3D""> httpd.serve_forever()</div><div = class=3D"">------</div><div class=3D""><br class=3D""></div><div = class=3D"">(Please note that even though these examples are for Python2 = (due to other quirks) I am aiming to implement this in Python3.)<br = class=3D""></div><div class=3D""><br class=3D""></div><div = class=3D"">Regards,</div><div class=3D""><br class=3D""></div><div = class=3D"">Arn</div></div> _______________________________________________<br class=3D""> Twisted-Python mailing list<br class=3D""> <a href=3D"mailto:[email protected]" target=3D"_blank" = class=3D"">[email protected]</a><br class=3D""> <a = href=3D"https://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python"= rel=3D"noreferrer" target=3D"_blank" = class=3D"">https://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-pyth= on</a><br class=3D""> </blockquote></div></div> _______________________________________________<br = class=3D"">Twisted-Python mailing list<br class=3D""><a = href=3D"mailto:[email protected]" = class=3D"">[email protected]</a><br = class=3D"">https://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-pyth= on<br class=3D""></div></blockquote></div><br = class=3D""></div></div></body></html>= --Apple-Mail=_85FD3470-399C-4483-BD25-5D47DBFC9434-- --===============5705995186937567742== Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: base64 Content-Disposition: inline X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18KVHdpc3RlZC1Q eXRob24gbWFpbGluZyBsaXN0ClR3aXN0ZWQtUHl0aG9uQHR3aXN0ZWRtYXRyaXguY29tCmh0dHBz Oi8vdHdpc3RlZG1hdHJpeC5jb20vY2dpLWJpbi9tYWlsbWFuL2xpc3RpbmZvL3R3aXN0ZWQtcHl0 aG9uCg== --===============5705995186937567742==--