Search code examples
pythonsslrequestopensslcertificate

Find a json/dict of the client certificate from a HTTPS request


I'm having a client certificate - server certificate for a Flask endpoint i'm building. Currently the HTTPS requests can go though, and I can print the details of the client certificate on the server side like this:

@app.route('/predict', methods=['POST'])
def predict():
    res = "hi"
    status = False

    if request.url.startswith('https://'):
        client_cert = request.headers["CLIENT_CERT"]
        res = client_cert["subject"]
        print(client_cert)

It prints out the info of the client cert that comes from a request:

"{'subject': ((('countryName', 'DE'),), (('stateOrProvinceName', 'BW'),), (('localityName', 'Walldorf'),), (('organizationName', 'MYCOMPANY'),), (('organizationalUnitName', 'MYDEPARTMENT'),), (('commonName', '*.domainname.com'),)), 'issuer': ((('countryName', 'DE'),), (('stateOrProvinceName', 'BW'),), (('localityName', 'Walldorf'),), (('organizationName', 'MYCOMPANY'),), (('organizationalUnitName', 'MYDEPARTMENT'),), (('commonName', 'SAMPLE CA'),)), 'version': 1, 'serialNumber': '01', 'notBefore': 'Aug 12 07:21:25 2021 GMT', 'notAfter': 'Aug 12 07:21:25 2022 GMT'}"

I am looking to retrieve the commonName entry in the above string to do further verification, as I only want to allow commonName that is in a particular format that I expect.

As you can see, retrieving the client cert from the headers of the request gives the certificate in the form of a string. Because this is not a string of proper json, I cannot use json.loads to parse the string into a dictionary. is there any good way to parse this string so that I can get the commonName value, or is there any other good way to access the client certificate of a request?

Thanks!


Solution

  • The format of the response appears to be well-defined. In which case, this will achieve the OP's objective. There's undoubtedly a RE that will do the trick but this is simple and effective:-

    def getCommonNames(s):
        rv = []
        offset = 0
        try:
            while True:
                i = s.index('commonName', offset)
                offset = i + 14
                j = s.index("'", offset)
                rv.append(s[offset:j])
        except Exception:
            pass
        return rv
    
    
    S = "{'subject': ((('countryName', 'DE'),), (('stateOrProvinceName', 'BW'),), (('localityName', 'Walldorf'),), (('organizationName', 'MYCOMPANY'),), (('organizationalUnitName', 'MYDEPARTMENT'),), (('commonName', '*.domainname.com'),)), 'issuer': ((('countryName', 'DE'),), (('stateOrProvinceName', 'BW'),), (('localityName', 'Walldorf'),), (('organizationName', 'MYCOMPANY'),), (('organizationalUnitName', 'MYDEPARTMENT'),), (('commonName', 'SAMPLE CA'),)), 'version': 1, 'serialNumber': '01', 'notBefore': 'Aug 12 07:21:25 2021 GMT', 'notAfter': 'Aug 12 07:21:25 2022 GMT'}"
    print(getCommonNames(S))