Skip to content

Instantly share code, notes, and snippets.

@leonletto
Forked from nebulak/ca-setup.md
Created November 11, 2022 20:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save leonletto/cf747cc51c4cfdcd6998800af37d5d4f to your computer and use it in GitHub Desktop.
Save leonletto/cf747cc51c4cfdcd6998800af37d5d4f to your computer and use it in GitHub Desktop.
python mutual tls for client certificate validation
# sources:
# https://kb.op5.com/pages/viewpage.action?pageId=19073746#sthash.9gTMRKM1.dpbs
# https://stackoverflow.com/a/26093147
# https://jamielinux.com/docs/openssl-certificate-authority/sign-server-and-client-certificates.html
# additional ressource: https://gist.github.com/Soarez/9688998
# TODO: renew certificates and ca, add capability for authentication to client cert
# TODO ressources: https://gist.github.com/richieforeman/3166387

HKP_PATH=""
CLIENT_PATH=""

# Create CA-key and CA-cert
openssl genrsa -out FlexCA.key 2048
openssl req -x509 -new -nodes -key FlexCA.key -sha256 -days 1024 -out FlexCA.pem -subj "/C=US/ST=Denial/L=Springfield/O=Dis/CN=example.com"

# Create client key & cert signing request
openssl genrsa -out FlexClient.key 2048
openssl req -new -key FlexClient.key -out FlexClient.csr -subj "/C=US/ST=Denial/L=Springfield/O=Dis/CN=example.com"

# Generate Client certificate
openssl x509 -req -in FlexClient.csr -CA FlexCA.pem -CAkey FlexCA.key -CAcreateserial -out FlexClient.pem -days 1024 -sha256

# //TODO: restart hkp-server
# //TODO: for readme: how to create ca & client-certs:
# // ---> https://jamielinux.com/docs/openssl-certificate-authority/sign-server-and-client-certificates.html
# source: https://www.ajg.id.au/2018/01/01/mutual-tls-with-python-flask-and-werkzeug/
from flask import Flask, render_template, request
import werkzeug.serving
import ssl
import OpenSSL
class PeerCertWSGIRequestHandler( werkzeug.serving.WSGIRequestHandler ):
"""
We subclass this class so that we can gain access to the connection
property. self.connection is the underlying client socket. When a TLS
connection is established, the underlying socket is an instance of
SSLSocket, which in turn exposes the getpeercert() method.
The output from that method is what we want to make available elsewhere
in the application.
"""
def make_environ(self):
"""
The superclass method develops the environ hash that eventually
forms part of the Flask request object.
We allow the superclass method to run first, then we insert the
peer certificate into the hash. That exposes it to us later in
the request variable that Flask provides
"""
environ = super(PeerCertWSGIRequestHandler, self).make_environ()
x509_binary = self.connection.getpeercert(True)
x509 = OpenSSL.crypto.load_certificate( OpenSSL.crypto.FILETYPE_ASN1, x509_binary )
environ['peercert'] = x509
return environ
app = Flask(__name__)
# to establish an SSL socket we need the private key and certificate that
# we want to serve to users.
#
# app_key_password here is None, because the key isn't password protected,
# but if yours is protected here's where you place it.
app_key = './app.key'
app_key_password = None
app_cert = './app.crt'
# in order to verify client certificates we need the certificate of the
# CA that issued the client's certificate. In this example I have a
# single certificate, but this could also be a bundle file.
ca_cert = './ca.crt'
# create_default_context establishes a new SSLContext object that
# aligns with the purpose we provide as an argument. Here we provide
# Purpose.CLIENT_AUTH, so the SSLContext is set up to handle validation
# of client certificates.
ssl_context = ssl.create_default_context( purpose=ssl.Purpose.CLIENT_AUTH,
cafile=ca_cert )
# load in the certificate and private key for our server to provide to clients.
# force the client to provide a certificate.
ssl_context.load_cert_chain( certfile=app_cert, keyfile=app_key, password=app_key_password )
ssl_context.verify_mode = ssl.CERT_REQUIRED
# now we get into the regular Flask details, except we're passing in the peer certificate
# as a variable to the template.
@app.route('/')
def hello_world():
return render_template('helloworld.html', client_cert=request.environ['peercert'])
# start our webserver!
if __name__ == "__main__":
app.run( ssl_context=ssl_context, request_handler=PeerCertWSGIRequestHandler )
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment