Software can extract fingerprints from SSL certificates, and use the fingerprints to authorize or verify the other end of the connection. This may be done either by servers--such as a SMTP server that allows relay for certificates that have particular fingerprints--or by clients, such as Trust On First Use (TOFU) used by gemini clients to associate a certificate with a server.
Fingerprints do not scale unless the process is largely automated; it is more common to trust certificates signed by a particular Certificate Authority (CA)—minus any present on a Certificate Revocation List—so that the software or, worse, humans need not fiddle with things every time a certificate changes. Of course certificate authorities are not without problems--can you always trust all of the CA in a typical browser?
The fingerprint is generally specific to an application or library so may not be portable unless pains are taken to derive the fingerprint the same way. Here is the amfora author on the topic:
The way to store cert data is not standardized, but my recommendation is a SHA-256 hash of the entire *binary* cert, or preferably, a SHA-256 hash of the binary "Subject Public Key Info" (SPKI) section of the cert.
...
As for why just hashing the SPKI is preferably, it's because that is the part of the certificate that stores the public key type, and the public key itself. If that part of the cert has not changed, then it doesn't matter if other parts of the cert have, like the signature algorithm or the serial number, because you know the same person is making the connection, because they still have control of that keypair.
gemini://makeworld.space/gemlog/2020-07-03-tofu-rec.gmi
https://github.com/makeworld-the-better-one/amfora
This perhaps bears some scrutiny. The code can be found in client/tofu.go, here extracted into a standalone script, certid.go, and replicated into the Perl script certid.pl for some OpenSSL flavor.
$ go build certid.go $ ./certid thrig.pem old 35B73040D25807B6AB78AF29CB286044F79EC36569227E665A8615112BAB9028 new 8E45637224E2FD37B21EA39CBC94FFB135AB25D1445CFAA6A7359BA5E2BE2398 $ ./certid.pl thrig.pem 35:B7:30:40:D2:58:07:B6:AB:78:AF:29:CB:28:60:44:F7:9E:C3:65:69:22:7E:66:5A:86:15:11:2B:AB:90:28 8E45637224E2FD37B21EA39CBC94FFB135AB25D1445CFAA6A7359BA5E2BE2398 $ grep thrig ~/.cache/amfora/tofu.toml "thrig/me" = "8E45637224E2FD37B21EA39CBC94FFB135AB25D1445CFAA6A7359BA5E2BE2398" "thrig/me/expiry" = 2296-10-03T19:35:58Z
This shows that the X509_get_fingerprint call in the Net::SSLeay module digests the same data as the origCertID code from amfora. More interesting may be to generate new certificates that do not change the fingerprint for the new certId code in amfora. This requires a private key, which I am not sharing here.
$ cat recert #!/bin/sh openssl req -x509 -new -sha256 -days 99 -nodes -key thrig.key \ -out "$1".cert -subj "/CN=thrig.me" -addext \ "subjectAltName=DNS:thrig.me,IP:104.207.156.138,IP:2001:19f0:8001:143b:5400:4ff:fe1a:8ed6" $ ./recert foo $ ./certid foo.cert old 7316EC6EDF37A539299AD6D468CB23CE276031E6EEF35BC6085290F81909D73F new 8E45637224E2FD37B21EA39CBC94FFB135AB25D1445CFAA6A7359BA5E2BE2398 $ openssl x509 -noout -dates < thrig.pem notBefore=Dec 20 19:35:58 2022 GMT notAfter=Oct 3 19:35:58 2296 GMT $ openssl x509 -noout -dates < foo.cert notBefore=Apr 12 21:08:46 2023 GMT notAfter=Jul 20 21:08:46 2023 GMT
This shows that a new certificate with a different expiration date will be verified as the same certificate by amfora. A gemini client that verifies the entire certificate will see a new fingerprint. Therefore, gemini clients probably should use the amfora form and only checksum the subject public key information section.