0

I configure my Tornado server with:

ssl_options = { 
    "certfile": os.path.join("/tls.crt"),
    "keyfile": os.path.join("/tls.key")
}   
http = tornado.httpserver.HTTPServer(application, ssl_options=ssl_options)

tls.crt and tls.key are wildcarded for my domain, which I use successfully in another app in my stack behind HAPROXY, the latter terminating TLS.

The server on startup reports OpenSSL version:

OpenSSL 1.0.1k 8 Jan 2015

Browser

However, when fetch / from the browser (which eventually says "This web page is not available"), this appears in the Tornado STDOUT:

 [E 150228 15:05:52 ioloop:588] Exception in callback (<socket._socketobject object at 0x7ff342d37050>, <function null_wrapper at 0x7ff342d418c0>)
     Traceback (most recent call last):
       File "/usr/local/lib/python2.7/site-packages/tornado/ioloop.py", line 840, in start
         handler_func(fd_obj, events)
       File "/usr/local/lib/python2.7/site-packages/tornado/stack_context.py", line 275, in null_wrapper
         return fn(*args, **kwargs)
       File "/usr/local/lib/python2.7/site-packages/tornado/netutil.py", line 223, in accept_handler
         callback(connection, address)
       File "/usr/local/lib/python2.7/site-packages/tornado/tcpserver.py", line 225, in _handle_connection
         do_handshake_on_connect=False)
       File "/usr/local/lib/python2.7/site-packages/tornado/netutil.py", line 459, in ssl_wrap_socket
         context = ssl_options_to_context(ssl_options)
       File "/usr/local/lib/python2.7/site-packages/tornado/netutil.py", line 436, in ssl_options_to_context
         context.load_cert_chain(ssl_options['certfile'], ssl_options.get('keyfile', None))
     SSLError: [SSL] PEM lib (_ssl.c:2506)

cURL

Curling the endpoint shows:

* About to connect() to example.org port 443 (#0)
*   Trying 54.154.175.173... connected
* successfully set certificate verify locations:
*   CAfile: none
  CApath: /etc/ssl/certs
* SSLv3, TLS handshake, Client hello (1):
* Unknown SSL protocol error in connection to example.org:443 
* Closing connection #0
curl: (35) Unknown SSL protocol error in connection to example.org:443

openssl s_client

openssl s_client -connect example.org:443

Just hangs on:

CONNECTED(00000003)

I've cloned https://github.com/openssl/openssl.git and checked out the 1.0.1k tag, but can't find _ssl.c, so pointers here will be a good start.

I've also pointed CryptoNark at my domain, but just get empty output.

The host OS is AWS AMI ami-6330b7141. The Docker container for the app is python:2.7 version 31ff30c97af1.

UPDATE

The line in _ssl.c seems to be part of Python 3 backported stuff by @benjamin-peterson I'll try with latest Python 3.4.

opyate
  • 5,388
  • 1
  • 37
  • 64
  • You said "Error on Tornado server", but you never posted the error message. It sounds like the client is connecting to the front end, but then troubles begin. You should ensure the SSL terminator actually terminates the connection, or the proxy passes the response onto the backend, or the backend's response is returned to the client. – jww Feb 28 '15 at 19:50
  • You should also try `openssl s_client -connect example.org:443 -tls1 -servername example.org` in case its related to SSLv3 or SNI. – jww Feb 28 '15 at 19:53
  • Look for "Tornado STDOUT" in my question to see the error. Your second comment's suggestion hangs the same way for me. Thanks for looking. – opyate Mar 01 '15 at 16:09
  • My bad.... I'm not sure why I did not connect those dots. So it sounds like you *don't* have an HTTPS server listening on 443. Rather, it sounds like an HTTP server. The "bad protocol" is the SSL/TLS client trying to interpret the server's HTML as protocol data. You'll have to confirm it by looking at the server's reply. And I can't answer why that's the case because I'm not a web master or administrator (I just recognize the symptoms on occasion). – jww Mar 01 '15 at 23:23

1 Answers1

1

After looking at the error line in _ssl.c, the problem was in fact with the certificate (the error message PEM lib was probably indicative enough of that).

I set it via an environment variable, after doing this on the original certificate file:

awk 1 ORS='\\n' star.example.org.cert

Then in my Python app:

 with open('/tls.crt', 'w') as crt:
     crt.write(os.environ.get('SSL_CRT'));

Problem is, those newlines remained as \n, so I moved this step up to a Bash script:

if [ -n "$SSL_CRT" ]; then
    rm /tls.crt
    echo "SSL certificate provided!"
    echo -e "${SSL_CRT}" > /tls.crt
else
    echo "No SSL certificate provided"
fi
python app.py

It works now. A face-palm moment indeed.

opyate
  • 5,388
  • 1
  • 37
  • 64