Doing SSL client authentication in python
Question:
OK, I am trying to use client certificates to authenticate a python client to an Nginx server. Here is what I tried so far:
Created a local CA
openssl genrsa -des3 -out ca.key 4096
openssl req -new -x509 -days 365 -key ca.key -out ca.crt
Created server key and certificate
openssl genrsa -des3 -out server.key 1024
openssl rsa -in server.key -out server.key
openssl req -new -key server.key -out server.csr
openssl x509 -req -days 365 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt
Used similar procedure to create a client key and certificate
openssl genrsa -des3 -out client.key 1024
openssl rsa -in client.key -out client.key
openssl req -new -key client.key -out client.csr
openssl x509 -req -days 365 -in client.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out client.crt
Add these lines to my nginx config
server {
listen 443;
ssl on;
server_name dev.lightcloud.com;
keepalive_timeout 70;
access_log /usr/local/var/log/nginx/lightcloud.access.log;
error_log /usr/local/var/log/nginx/lightcloud.error.log;
ssl_certificate /Users/wombat/Lightcloud-Web/ssl/server.crt;
ssl_certificate_key /Users/wombat/Lightcloud-Web/ssl/server.key;
ssl_client_certificate /Users/wombat/Lightcloud-Web/ssl/ca.crt;
ssl_verify_client on;
location / {
uwsgi_pass unix:///tmp/uwsgi.socket;
include uwsgi_params;
}
}
created a PEM client file
cat client.crt client.key ca.crt > client.pem
created a test python script
import ssl
import http.client
context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
context.load_verify_locations("ca.crt")
context.load_cert_chain("client.pem")
conn = http.client.HTTPSConnection("localhost", context=context)
conn.set_debuglevel(3)
conn.putrequest('GET', '/')
conn.endheaders()
response = conn.getresponse()
print(response.read())
And now I get 400 The SSL certificate error from the server. What am I doing wrong?
Answers:
It seems that my problem was that I did not create the CA properly and wasn’t signing keys the right way. A CA cert needs to be signed and if you pretend to be top level CA you self-sign your CA cert.
openssl req -new -newkey rsa:2048 -keyout ca.key -out ca.pem
openssl ca -create_serial -out cacert.pem -days 365 -keyfile ca.key -selfsign -infiles ca.pem
Then you use ca command to sign requests
openssl genrsa -des3 -out server.key 1024
openssl req -new -key server.key -out server.csr
openssl ca -out server.pem -infiles server.csr
OK, I am trying to use client certificates to authenticate a python client to an Nginx server. Here is what I tried so far:
Created a local CA
openssl genrsa -des3 -out ca.key 4096 openssl req -new -x509 -days 365 -key ca.key -out ca.crt
Created server key and certificate
openssl genrsa -des3 -out server.key 1024 openssl rsa -in server.key -out server.key openssl req -new -key server.key -out server.csr openssl x509 -req -days 365 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt
Used similar procedure to create a client key and certificate
openssl genrsa -des3 -out client.key 1024 openssl rsa -in client.key -out client.key openssl req -new -key client.key -out client.csr openssl x509 -req -days 365 -in client.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out client.crt
Add these lines to my nginx config
server { listen 443; ssl on; server_name dev.lightcloud.com; keepalive_timeout 70; access_log /usr/local/var/log/nginx/lightcloud.access.log; error_log /usr/local/var/log/nginx/lightcloud.error.log; ssl_certificate /Users/wombat/Lightcloud-Web/ssl/server.crt; ssl_certificate_key /Users/wombat/Lightcloud-Web/ssl/server.key; ssl_client_certificate /Users/wombat/Lightcloud-Web/ssl/ca.crt; ssl_verify_client on; location / { uwsgi_pass unix:///tmp/uwsgi.socket; include uwsgi_params; } }
created a PEM client file
cat client.crt client.key ca.crt > client.pem
created a test python script
import ssl import http.client context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) context.load_verify_locations("ca.crt") context.load_cert_chain("client.pem") conn = http.client.HTTPSConnection("localhost", context=context) conn.set_debuglevel(3) conn.putrequest('GET', '/') conn.endheaders() response = conn.getresponse() print(response.read())
And now I get 400 The SSL certificate error from the server. What am I doing wrong?
It seems that my problem was that I did not create the CA properly and wasn’t signing keys the right way. A CA cert needs to be signed and if you pretend to be top level CA you self-sign your CA cert.
openssl req -new -newkey rsa:2048 -keyout ca.key -out ca.pem openssl ca -create_serial -out cacert.pem -days 365 -keyfile ca.key -selfsign -infiles ca.pem
Then you use ca command to sign requests
openssl genrsa -des3 -out server.key 1024 openssl req -new -key server.key -out server.csr openssl ca -out server.pem -infiles server.csr