3

I'm trying to use Python to test a web server. I have nearly no experience with Python, but encouraged to use it because its easy to learn and simple to do things with (someone else's opinion, not mine at the moment). The script I am using is:

s1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s2 = ssl.wrap_socket(s1,
                     ca_certs="./pki/signing-dss-cert.pem",
                     cert_reqs=ssl.CERT_REQUIRED,
                     ssl_version=ssl.PROTOCOL_TLSv1,
                     server_hostname="localhost")

s2.connect( ("localhost", 8443) )

s2.send("GET / ")
time.sleep(1)
s2.send("HTTP/1.1")

The error is:

Traceback (most recent call last):
  File "./fetch.sh", line 10, in <module>
    server_hostname="localhost")
TypeError: wrap_socket() got an unexpected keyword argument 'server_hostname'

I've also tried using servername, name, hostname and sni with no joy.

The Python docs don't mention SNI (TLS/SSL wrapper for socket objects and SSL wiki page). But I know the patch for SNI and server_hostname was incorporated 4 years ago in 2010 (Add a *server_hostname* argument to SSLContext.wrap_socket, changeset 65593:846c0e1342d0).

The equivalent OpenSSL call I need access to is SSL_set_tlsext_host_name.

How do I specify the SNI hostname? (Eventually, I'll need to set it to an arbitrary name because I am testing a proxy).

3
  • Try to merge my code with yours and try to use the servername instead of "localhost" when you create the connection. Commented Mar 13, 2014 at 18:54
  • Which version of Python are you using? Commented Mar 13, 2014 at 22:38
  • sys.version_info(major=2, minor=7, micro=3, releaselevel='final', serial=0). Debian 7.3 (x64), fully patched. Commented Mar 13, 2014 at 22:47

2 Answers 2

2

The patch you're mentioning is for Python 3.2, and you're using Python 2.7. Issue 5639 also seems to indicate there is no plan to back-port SNI support for Python 2.7.

You could wrap the socket with pyOpenSSL instead (its Connection class has a set_tlsext_host_name since version 0.13. (I'm not sure which version comes with Debian 7.3, you might want to set up a virtualenv and upgrade to a newer version locally, if needed.)

There is an SNI example is the pyOpenSSL repository.

If you want your usage of wrap_socket to be more compatible with the trick were you replace the value of sock in an httplib connection, you could have a look at how urllib3 does this with pyOpenSSL. Essentially, it creates an OpenSSL.SSL.Connection from an existing socket, but since that connection isn't compatible with a socket, it wraps it into a class that implements the required method.

(By the way, in Python 2.7, urllib, urllib2 and httpconnection don't do any certificate verification at all, unless you implement it yourself by wrapping their sockets.)

EDIT:

Here is a version of your code that should work with Python 3.2. Unfortunately, the server_name parameter isn't in the plain ssl.wrap_socket, only in SSLContext.wrap_socket, but you can use SSLSocket directly.

import socket
import ssl

CA_BUNDLE_FILE="/etc/ssl/certs/ca-certificates.crt"


HOST = "sni.velox.ch"
s1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s2 = ssl.SSLSocket(sock=s1, ca_certs=CA_BUNDLE_FILE,
                     cert_reqs=ssl.CERT_REQUIRED,
                     ssl_version=ssl.PROTOCOL_TLSv1,
                     server_hostname=HOST)

s2.connect((HOST, 443))

s2.send(bytes("GET / HTTP/1.1\n", "UTF-8"))
# This might need to be modified when using another port
s2.send(bytes("Host: %s\n" % (HOST,), "UTF-8"))
s2.send(bytes("\n", "UTF-8"))

# Certainly not the best way to read the response, but it works.
while True:
    x = s2.read()
    if not x:
        break
    print(x)
Sign up to request clarification or add additional context in comments.

4 Comments

Thanks Bruno. "If you want your usage of wrap_socket to be more compatible..." - I just want it to work. I wasted about 4 hours on it today because it was supposed to be easier and faster. I think I'm going back to C/C++. C/C++ development is faster for me than trying to unravel everything you said above. And I'm befuddled the latest Debian is using an old, unpatched library. There's a reason I use the latest distros, and its not because I enjoy cutting edge bugs.
I wouldn't judge Python on this. If you're new to Python and don't have any 2.x legacy code, you could try a Python 3.2+ interpreter. It should be callable using python3.2 provided you've installed the package for it.
Thanks again Bruno. This worked once I downloaded, built and installed Python 3.4.
Strange you had to get Python 3.4 and build it yourself. I got that to work on a Debian system simply by installing the python3 package (and using python3.2). (Just in case you weren't aware of it, on Debian/Ubuntu, Python versions can be installed together (except micro-level number) via normal packages. By default python is still the most recent 2.x interpreter, but you can call the python3.x interpreter explicitly.)
0

My env is:requests==2.7.0, python-2.7.5-34.el7.x86_64, gevent==1.0.2

Change python version to python-2.7.5-18.el7_1.1.x86_64, problem is solved.

on CentOS:

sudo rpm -Uvh --oldpackage python-devel-2.7.5-18.el7_1.1.x86_64.rpm  python-libs-2.7.5-18.el7_1.1.x86_64.rpm  python-2.7.5-18.el7_1.1.x86_64.rpm

pakages can search on google.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.