[Twisted-Python] Serving WSGIResource via SSL endpoint

Hi Twistedeers! I have a twisted plugin that I created to replace the Django dev server for our devs. It sets up a separate twisted service for serving media, so we don't need any urls.py tomfoolery in dev. It also sets up an experimental REST api server which we hope to make javascript requests to in the near future. The core of the code looks like this: resource = WSGIResource(reactor, reactor.getThreadPool(), WSGIHandler()) endpoint = 'tcp:port=8000' server = strports.service(endpoint, server.Site(resource)) server.setServiceParent(application) This has worked great for a while. However, we have some views that we require https on, and so this dev server doesn't allow us to get to those views at all. I generated a .key file and a .crt file with openssl, and then cat'd them together to make a pem, and then changed the endpoint to be... endpoint = 'ssl:port=8000:privateKey=/path/to/key.pem' Now when I open my browser and type https://localhost:8000, chrome just hangs. I don't really know how to diagnose this, because I don't really know anything about SSL (it's all just magic security goodness to me). I don't necessarily need a direct answer (though it will certainly make me look good to all the other devs), but maybe some pointers in the right direction would help. -Piper

On Aug 14, 2014, at 3:54 PM, Piper Masden <piper.masden@gmail.com> wrote:
Hi Twistedeers!
I have a twisted plugin that I created to replace the Django dev server for our devs.
Cool!
It sets up a separate twisted service for serving media, so we don't need any urls.py tomfoolery in dev. It also sets up an experimental REST api server which we hope to make javascript requests to in the near future.
Glad to hear you're using Twisted for this.
The core of the code looks like this:
resource = WSGIResource(reactor, reactor.getThreadPool(), WSGIHandler()) endpoint = 'tcp:port=8000' server = strports.service(endpoint, server.Site(resource)) server.setServiceParent(application)
This has worked great for a while. However, we have some views that we require https on, and so this dev server doesn't allow us to get to those views at all. I generated a .key file and a .crt file with openssl, and then cat'd them together to make a pem, and then changed the endpoint to be...
endpoint = 'ssl:port=8000:privateKey=/path/to/key.pem'
Now when I open my browser and type https://localhost:8000, chrome just hangs. I don't really know how to diagnose this, because I don't really know anything about SSL (it's all just magic security goodness to me). I don't necessarily need a direct answer (though it will certainly make me look good to all the other devs), but maybe some pointers in the right direction would help.
This isn't really enough information to diagnose a problem, but here are some things you could try: openssl s_client -connect localhost:8000 curl -vvvv https://localhost:8000/ These should output some stuff about your TLS connection, and will perhaps emit an error message which looks obvious to you. If not, seeing some of that output might be useful to help diagnose it. Also, trying other web browsers is always helpful. You might also try replacing your SSL string endpoint description with a TXSNI endpoint plugin: <https://github.com/glyph/txsni>. This is just a little easier to get right because of how it reads certificates (for example you don't need to get your private key, chain cert, and main cert in the right order, as long as they're all in the appropriate file. -glyph

On Fri, Aug 15, 2014 at 2:15 AM, Glyph <glyph@twistedmatrix.com> wrote:
On Aug 14, 2014, at 3:54 PM, Piper Masden <piper.masden@gmail.com> wrote:
The core of the code looks like this:
resource = WSGIResource(reactor, reactor.getThreadPool(), WSGIHandler()) endpoint = 'tcp:port=8000' server = strports.service(endpoint, server.Site(resource)) server.setServiceParent(application)
This has worked great for a while. However, we have some views that we require https on, and so this dev server doesn't allow us to get to those views at all. I generated a .key file and a .crt file with openssl, and then cat'd them together to make a pem, and then changed the endpoint to be...
endpoint = 'ssl:port=8000:privateKey=/path/to/key.pem'
Now when I open my browser and type https://localhost:8000, chrome just hangs. I don't really know how to diagnose this, because I don't really know anything about SSL (it's all just magic security goodness to me). I don't necessarily need a direct answer (though it will certainly make me look good to all the other devs), but maybe some pointers in the right direction would help.
This isn't really enough information to diagnose a problem, but here are some things you could try:
openssl s_client -connect localhost:8000 curl -vvvv https://localhost:8000/
These should output some stuff about your TLS connection, and will perhaps emit an error message which looks obvious to you. If not, seeing some of that output might be useful to help diagnose it. Also, trying other web browsers is always helpful.
I tried Firefox and Safari right after I Chrome. I did have it slightly working once, where I could get it connect, and if I hit the "Stop" button, the browser would draw the served data. I thought that might have been because the media server wasn't serving media via https, and the browser was confused. When I tried to enable that, it stopped working altogether (Chrome just says "Establishing secure connection" until it times out). Here's my code now (I added Tobias' suggestion to not use the pem file): resource = WSGIResource(reactor, reactor.getThreadPool(), WSGIHandler()) endpoint = 'ssl:port=8000:privateKey=server.key:certKey=server.crt' server = strports.service(endpoint, server.Site(resource)) When I use the openssl command you gave me, I get this: > openssl s_client -connect localhost:8000 CONNECTED(00000003) ^C (I had to Ctrl-C it, because it just stuck there) When I do the curl command, I get this: > curl -vvvv https://localhost:8000/ * Adding handle: conn: 0x7fd0f9813600 * Adding handle: send: 0 * Adding handle: recv: 0 * Curl_addHandleToPipeline: length: 1 * - Conn 0 (0x7fd0f9813600) send_pipe: 1, recv_pipe: 0 * About to connect() to localhost port 8000 (#0) * Trying ::1... * Trying 127.0.0.1... * Connected to localhost (127.0.0.1) port 8000 (#0) ^C (I have to Ctrl-C it too) Maybe I generated my certs wrong or something? I just did openssl req -nodes -new -x509 -keyout server.key -out server.crt ...which I basically took from a OpenSSL HOWTO because I have no idea what I'm doing.
You might also try replacing your SSL string endpoint description with a TXSNI endpoint plugin: <https://github.com/glyph/txsni>. This is just a little easier to get right because of how it reads certificates (for example you don't need to get your private key, chain cert, and main cert in the right order, as long as they're all in the appropriate file.
If I can't get this to work, I may bug you about txsni. I think this is a case me just not knowing anything about OpenSSL (and the internets having wildly varying levels of explanations) and probably doing something not very smart. If I can learn something about OpenSSL while I facepalm, I'd rather do that. -Piper

Maybe I generated my certs wrong or something? I just did
Did you set the "Common Name" (CN) correctly? FWIW, you might have look at this recipe https://github.com/crossbario/crossbar/wiki/Secure%20WebSocket%20and%20HTTPS... Ignore the other stuff / the site in general .. I am pointing there since I know for sure this works with Twisted and all browsers. If above doesn't help: can you post your complete code (exactly as you run it)? I'll give it a shot .. /Tobias

On 04:32 pm, piper.masden@gmail.com wrote:
On Fri, Aug 15, 2014 at 2:15 AM, Glyph <glyph@twistedmatrix.com> wrote:
When I use the openssl command you gave me, I get this:
openssl s_client -connect localhost:8000 CONNECTED(00000003) ^C
(I had to Ctrl-C it, because it just stuck there)
You might find it instructive to run these commands against a known working TLS server so you can draw some conclusions about the results when you use them against yours. For example, this would show you that the TLS handshake is never actually completing. Are you sure you've actually set up TLS on this port? An http://sscce.org/ would help the list diagnose the problem. Jean-Paul

generated a .key file and a .crt file with openssl, and then cat'd them together to make a pem, and then changed the endpoint to be... endpoint = 'ssl:port=8000:privateKey=/path/to/key.pem'
you could try to not concat key and cert, but leave them separate: endpoint = 'ssl:port=8000:privateKey=/path/to/key.pem;certKey=/path/to/cert.pem' /Tobias
participants (4)
-
exarkun@twistedmatrix.com
-
Glyph
-
Piper Masden
-
Tobias Oberstein