0

I'm trying to generate the same SHA1 fingerprint for a X509 certificate using pycryptodome that I get from the openssl command:

openssl x509 -noout -fingerprint -sha1 -inform pem -in certificate.crt

My certificate is in PEM format on disk

However, the code snippet below gives me a different value.

from Crypto.PublicKey import RSA
import hashlib

contents = open("/home/ubuntu/certificate.crt", "r").read().encode()
certificate = RSA.import_key(contents)
bytes = certificate.export_key("DER")
hashlib.sha1(bytes).hexdigest()

Anyone any idea what I'm doing wrong?

MvdD
  • 22,082
  • 8
  • 65
  • 93

2 Answers2

1

The code uses only PyCryptodome to print the fingerprint of an X.509 certificate:

from Crypto.Hash import SHA1
from Crypto.IO import PEM

filename = "cert.pem"

pem_data = open(filename, "r").read()
der = PEM.decode(pem_data)

h = SHA1.new()
h.update(der[0])
fingerprint = h.hexdigest()

print(fingerprint)

Documentation:

Crypto.IO.PEM.decode(pem_data, passphrase=None)

Crypto.Hash.SHA1()

The following example implements basic error checking for the certificate and prepends the hex string to 40 characters so that it is a valid kid:

"""
This code reads an X.509 certificate and prints the SHA-1 fingerprint in hex
"""

import sys
import re
from Crypto.Hash import SHA1
from Crypto.IO import PEM

def get_fingerprint(fname):
    """
    Read an X.509 certificate and return the SHA-1 fingerprint in hex
    """

    with open(fname, "r", encoding="utf-8") as f:
        pem_data = f.read()

    r = re.compile(r"\s*-----BEGIN (.*)-----\s+")
    m = r.match(pem_data)
    marker = m.group(1)

    if marker != "CERTIFICATE":
        print("Error: Expected X.509 Certificate")
        sys.exit(1)

    der = PEM.decode(pem_data)

    h = SHA1.new()
    h.update(der[0])
    fingerprint = h.hexdigest()

    # insert leading zero bytes to make the string 40 digits
    while len(fingerprint) < 40:
        fingerprint = '0' + fingerprint

    return fingerprint

if __name__ == '__main__':
    filename = "cert1.pem"

    print(get_fingerprint(filename))
John Hanley
  • 74,467
  • 6
  • 95
  • 159
0

Still don't know how to do it using Pycryptodome, but I found there's no need for it at all. The following code fragment generates the same fingerprint as openssl does

pem = open("/home/ubuntu/certificate.crt", "r").read().encode()
pem = pem.removeprefix("-----BEGIN CERTIFICATE-----\n")
pem = pem.removesuffix("-----END CERTIFICATE-----\n")
public_bytes = base64.b64decode(pem)
sha1digest = hashlib.sha1(public_bytes).hexdigest()
fingerprint = ":".join(sha1digest[i : i + 2] for i in range(0, len(sha1digest), 2))
MvdD
  • 22,082
  • 8
  • 65
  • 93