PyOpenSSL empty socket property
Arn Vollebregt <[email protected]> Wed, 4 Sep 2019 10:37:39 +0200
| Newsgroups | gmane.comp.python.twisted |
|---|---|
| Message-ID | <CAObs90D9WZvU0qnrQeGOPHsSqp7izmzJZ59uqwWEYpR9tnfp8w@mail.gmail.com> |
--===============6229979268907749522==
Content-Type: multipart/alternative; boundary="000000000000c34f960591b61e15"
--000000000000c34f960591b61e15
Content-Type: text/plain; charset="UTF-8"
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 > /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 > /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
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
ctx.set_verify(SSL.VERIFY_PEER, verifyCallback)
#
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
ctx.set_verify(SSL.VERIFY_PEER, verifyCallback)
#
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
--000000000000c34f960591b61e15
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div>Hi,</div><div><br></div><div>I noticed that PyOpenSSL=
SNI callbacks (set with <i>ctx.set_tlsext_servername_callback</i>) receive=
a <i>OpenSSL.SSL.Connection</i> object within Twisted that have an empty <=
i>_socket</i> property, while this property <u>is</u> actually set when usi=
ng <i>PyOpenSSL</i> directly. For my use-case this is a problem as I want t=
o call <i>conn._socket.getpeername()</i> to determine the peer's IP add=
ress. So I am wondering: why is this behaviour different? And how do I get =
the peer IP address?</div><div><br></div><div>---console---</div><div>user:=
~$ sudo python testTwisted.py &</div><div>[3] 32842</div><div>user:~$ c=
url -s --insecure --key clientPrivateKey.pem --cert clientCertificate.pem <=
a href=3D"https://127.0.0.1" target=3D"_blank">https://127.0.0.1</a> > /=
dev/null<br>'sniCallback' called.<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 co=
nn._socket: None<br>'verifyCallback' called for result 0<br>=C2=A0 =
=C2=A0 =C2=A0 =C2=A0 conn._socket: None<br>'verifyCallback' called =
for result 1<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 conn._socket: None</div><div>us=
er:~$ sudo python testPyOpenSSL.py &<br>[1] 33270</div><div>user:~$ cur=
l -s --insecure --key clientPrivateKey.pem --cert clientCertificate.pem <a =
href=3D"https://127.0.0.1" target=3D"_blank">https://127.0.0.1</a> > /de=
v/null<br>'sniCallback' called.<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 conn=
._socket: <socket._socketobject object at 0x7f34c5bd3130><br><clas=
s 'OpenSSL.SSL.Connection'><br>'verifyCallback' called f=
or result 0<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 conn._socket: <socket._socket=
object object at 0x7f34c5bd3130><br>'verifyCallback' called for =
result 1<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 conn._socket: <socket._socketobj=
ect object at 0x7f34c5bd3130><br>127.0.0.1 - - [29/Aug/2019 11:45:47] &q=
uot;GET / HTTP/1.1" 200 -</div><div>------<br></div><div><br></div><di=
v>---testTwisted.py---</div><div>### Generate server key material ###<br>#
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>#=
## Generate client key material ###<br>#
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>f=
rom __future__ import print_function<br>#<a href=3D"https://twistedmatrix.c=
om/documents/12.0.0/core/howto/ssl.html" target=3D"_blank">https://twistedm=
atrix.com/documents/12.0.0/core/howto/ssl.html</a><br>from OpenSSL import S=
SL<br>from twisted.internet import ssl, reactor<br>from twisted.web import =
server, resource<br>from twisted.internet.protocol import Factory, Protocol=
<br><br>def verifyCallback(conn, cert, errno, depth, result):<br>=C2=A0 =C2=
=A0 print('\'verifyCallback\' called for result ' + str(res=
ult))<br>=C2=A0 =C2=A0 print('\tconn._socket: ' + str(conn._socket)=
)<br>=C2=A0 =C2=A0 return True<br><br>def sniCallback(conn):<br>=C2=A0 =C2=
=A0 print('\'sniCallback\' called.')<br>=C2=A0 =C2=A0 print=
('\tconn._socket: ' + str(conn._socket))<br><br>class MainResource(=
resource.Resource):<br>=C2=A0 =C2=A0 isLeaf =3D True<br><br>=C2=A0 =C2=A0 d=
ef render_GET(self, request):<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 request.respon=
seHeaders.addRawHeader("Content-Type", "text/html; charset=
=3Dutf-8")<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 return b"<html>&l=
t;body>Hello World</body></html>"<br><br>if __name__ =
=3D=3D '__main__':<br>=C2=A0 =C2=A0 myContextFactory =3D ssl.Defaul=
tOpenSSLContextFactory(<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 'serverPrivateKe=
y.pem',<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 'serverCertificate.pem'<=
br>=C2=A0 =C2=A0 )<br>=C2=A0 =C2=A0 ctx =3D myContextFactory.getContext()<b=
r>=C2=A0 =C2=A0 # <a href=3D"https://www.pyopenssl.org/en/stable/api/ssl.ht=
ml#OpenSSL.SSL.Context.set_verify" target=3D"_blank">https://www.pyopenssl.=
org/en/stable/api/ssl.html#OpenSSL.SSL.Context.set_verify</a><br>=C2=A0 =C2=
=A0 ctx.set_verify(SSL.VERIFY_PEER, verifyCallback)<br>=C2=A0 =C2=A0 # <a h=
ref=3D"https://pyopenssl.org/en/stable/api/ssl.html#OpenSSL.SSL.Context.set=
_tlsext_servername_callback" target=3D"_blank">https://pyopenssl.org/en/sta=
ble/api/ssl.html#OpenSSL.SSL.Context.set_tlsext_servername_callback</a><br>=
=C2=A0 =C2=A0 ctx.set_tlsext_servername_callback(sniCallback)<br><br>=C2=A0=
=C2=A0 site =3D server.Site(MainResource())<br>=C2=A0 =C2=A0 reactor.liste=
nSSL(443, site, myContextFactory)<br>=C2=A0 =C2=A0 reactor.run()</div><div>=
------</div><div><br></div><div>---testPyOpenSSL.py---</div><div>### Genera=
te server key material ###<br>#
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>#=
## Generate client key material ###<br>#
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>f=
rom __future__ import print_function<br>import socket, sys, os<br>from Sock=
etServer import BaseServer<br>from BaseHTTPServer import HTTPServer<br>from=
SimpleHTTPServer import SimpleHTTPRequestHandler<br>from OpenSSL import SS=
L<br><br>def verifyCallback(conn, cert, errno, depth, result):<br>=C2=A0 =
=C2=A0 print('\'verifyCallback\' called for result ' + str(=
result))<br>=C2=A0 =C2=A0 print('\tconn._socket: ' + str(conn._sock=
et))<br>=C2=A0 =C2=A0 return True<br><br>def sniCallback(conn):<br>=C2=A0 =
=C2=A0 print('\'sniCallback\' called.')<br>=C2=A0 =C2=A0 pr=
int('\tconn._socket: ' + str(conn._socket))<br>=C2=A0 =C2=A0 print(=
type(conn))<br><br>class SecureHTTPServer(HTTPServer):<br>=C2=A0 =C2=A0 def=
__init__(self, server_address, HandlerClass):<br>=C2=A0 =C2=A0 =C2=A0 =C2=
=A0 BaseServer.__init__(self, server_address, HandlerClass)<br>=C2=A0 =C2=
=A0 =C2=A0 =C2=A0 ctx =3D SSL.Context(SSL.TLSv1_2_METHOD)<br>=C2=A0 =C2=A0 =
=C2=A0 =C2=A0 ctx.use_privatekey_file('serverPrivateKey.pem')<br>=
=C2=A0 =C2=A0 =C2=A0 =C2=A0 ctx.use_certificate_file('serverCertificate=
.pem')<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 # <a href=3D"https://www.pyopenss=
l.org/en/stable/api/ssl.html#OpenSSL.SSL.Context.set_verify" target=3D"_bla=
nk">https://www.pyopenssl.org/en/stable/api/ssl.html#OpenSSL.SSL.Context.se=
t_verify</a><br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 ctx.set_verify(SSL.VERIFY_PEER,=
verifyCallback)<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 # <a href=3D"https://pyopen=
ssl.org/en/stable/api/ssl.html#OpenSSL.SSL.Context.set_tlsext_servername_ca=
llback" target=3D"_blank">https://pyopenssl.org/en/stable/api/ssl.html#Open=
SSL.SSL.Context.set_tlsext_servername_callback</a><br>=C2=A0 =C2=A0 =C2=A0 =
=C2=A0 ctx.set_tlsext_servername_callback(sniCallback)<br>=C2=A0 =C2=A0 =C2=
=A0 =C2=A0 self.socket =3D SSL.Connection(ctx, socket.socket(self.address_f=
amily,self.socket_type))<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 self.server_bind()<=
br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 self.server_activate()<br>=C2=A0 =C2=A0 <br>=
=C2=A0 =C2=A0 def shutdown_request(self,request):<br>=C2=A0 =C2=A0 =C2=A0 =
=C2=A0 request.shutdown()<br><br>class SecureHTTPRequestHandler(SimpleHTTPR=
equestHandler):<br>=C2=A0 =C2=A0 def setup(self):<br>=C2=A0 =C2=A0 =C2=A0 =
=C2=A0 self.connection =3D self.request<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 self=
.rfile =3D socket._fileobject(self.request, "rb", self.rbufsize)<=
br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 self.wfile =3D socket._fileobject(self.reque=
st, "wb", self.wbufsize)<br>=C2=A0 =C2=A0 <br>=C2=A0 =C2=A0 def d=
o_GET(self):<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 self.send_response(200)<br>=C2=
=A0 =C2=A0 =C2=A0 =C2=A0 SimpleHTTPRequestHandler.end_headers(self)<br>=C2=
=A0 =C2=A0 =C2=A0 =C2=A0 self.wfile.write('<html><body>Hell=
o World</body></html>')<br><br>if __name__ =3D=3D '__ma=
in__':<br>=C2=A0 =C2=A0 ip,port =3D ('0.0.0.0', 443)<br>=C2=A0 =
=C2=A0 httpd =3D SecureHTTPServer((ip, port), SecureHTTPRequestHandler)<br>=
=C2=A0 =C2=A0 httpd.serve_forever()</div><div>------</div><div><br></div><d=
iv>(Please note that even though these examples are for Python2 (due to oth=
er quirks) I am aiming to implement this in Python3.)<br></div><div><br></d=
iv><div>Regards,</div><div><br></div><div>Arn</div></div>
--000000000000c34f960591b61e15--
--===============6229979268907749522==
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: base64
Content-Disposition: inline
X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18KVHdpc3RlZC1Q
eXRob24gbWFpbGluZyBsaXN0ClR3aXN0ZWQtUHl0aG9uQHR3aXN0ZWRtYXRyaXguY29tCmh0dHBz
Oi8vdHdpc3RlZG1hdHJpeC5jb20vY2dpLWJpbi9tYWlsbWFuL2xpc3RpbmZvL3R3aXN0ZWQtcHl0
aG9uCg==
--===============6229979268907749522==--