💾 Archived View for drewdevault.com › 2020 › 09 › 21 › Gemini-TOFU.gmi captured on 2022-06-03 at 23:06:19. Gemini links have been rewritten to link to archived content
⬅️ Previous capture (2021-11-30)
-=-=-=-=-=-=-
I will have more to say about Gemini in the future, but for now, I wanted to write up some details about one thing in particular: the trust-on-first-use algorithm I implemented for my client, gmni. I think you should implement this algorithm, too!
First of all, it's important to note that the Gemini specification explicitly mentions TOFU and the role of self-signed certificates: they are the norm in Geminiland, and if your client does not support them then you're going to be unable to browse many sites. However, the exact details are left up to the implementation.
First, on startup, it finds the known_hosts file. For my client, this is `~/.local/share/gmni/known_hosts` (the exact path is adjusted as necessary per the XDG basedirs specification). Each line of this file represents a known host, and each host has four fields separated by spaces, in this order:
If a known_hosts entry is encountered with a hashing algorithm you don't understand, it is disregarded.
Then, when processing a request and deciding whether or not to trust its certificate, take the following steps:
1. Compute the certificate's fingerprint. Use the entire certificate (in OpenSSL terms, `X509_digest` will do this), not just the public key.†
2. Look up the known_hosts record for this hostname. If one is found, and the fingerprint does not match, the trust state is UNTRUSTED, GOTO 4. If found, and the fingerprint matches, the trust state is TRUSTED, GOTO 6.
3. The trust state is UNKNOWN. GOTO 4.
4. Display information about the certficate and its trust state to the user, and prompt them to choose an action, from the following options:
5. Complete the requested action:
6. Allow the request to proceed.
† Rationale: this fingerprint matches the output of `openssl x509 -sha512 -fingerprint`.
If the trust state is UNKNOWN, instead of requring user input to proceed, the implementation MAY proceed with the request IF the UI displays that a new certificate was trusted and provides a means to review the certificate and revoke that trust.
Note that being signed by a certificate authority in the system trust store is not considered meaningful to this algorithm. Such a cert is TOFU'd all the same.
That's it! If you have feedback on this approach, please send me an email.
My implementation doesn't *entirely* match this behavior, but it's close and I'll finish it up before 1.0. If you want to read the code, here it is:
You should use a self-signed certificate, and you should not use a certificate signed by one of the mainstream certificate authorities. We don't need to carry along the legacy CA cabal into our brave new Gemini future.
You should also set the certificate expiration into the far future, hundreds of years from now, and move certificates from server to server to keep the trust state intact. Think how SSH host keys work.
Finally, if you're writing a Gemini server, you should not burden your users with certificate maintenance at all. Generate a self-signed certificate for each host you intend to service on startup. Certificate maintenance is annoying and error prone, and because we use TOFU, we don't have to make the user do it.
See also:
TOFU Recommendations on makeworld.qq
\ \_____ ###[==_____> /_/
“TOFU recommendations for Gemini” was published on September 21, 2020.
View “TOFU recommendations for Gemini” on the WWW
The content for this site is CC-BY-SA. The code for this site is MIT.