💾 Archived View for gemini.circumlunar.space › ~solderpunk › gemlog › tls-musings.gmi captured on 2020-09-24 at 00:45:46. Gemini links have been rewritten to link to archived content
-=-=-=-=-=-=-
This post, or something like it, has been brewing for a very long time but I've not gotten around to writing it up just now. That it's happening *now* and not yet further in the future is prompted by a combination of things:
Links for the above (text/gemini *does* force a slightly awkward exposition at times...):
and his post "Transient TLS client certificates - Part 2"
80h's post "The joy of tls libs in rust"
Second Hacker News thread (specifically for the Castor client)
What follows is a bunch of loosely collected/organised thoughts on the subject of TLS in Gemini:
It might be fair to say that the decision to make TLS mandatory in Gemini is the least popular design decision I've made. I'm still convinced it was the right decision to make, compared to the alternatives of having the protocol be plaintext like Gopher (part of what motivated me to start Gemini was watching the recent growth of gopherspace and reading about what was driving people away from the web and reasoning that there must be a lot *more* people feeling the same urge but who, in a post-Snowden world, were totally unwilling to go back to plaintext) or basing it on some alternative security system (like
the Noise Protocol Framework).
It's not that I think TLS is beautiful and perfect. It's not that I don't see the problem with huge, massively complicated libraries with spotty security records like OpenSSL, or with the commercial Certificate Authority system. I get it. I still think it's a smart choice for at least two big reasons:
Gemini is not just simple, it's built from parts that we might think of as
commercial off-the-shelf parts.
Not literally commercial in this case, but I wanted to capture the connotations of COTS. Everybody who works in internet development recognises URLs and MIME types (already defined in excruciating detail for us by RFCs somebody else wrote), they recognise the client-server request-response architecture of the thing. They probably know TLS too - probably not as well as they'd like or arguably should, but it's a thing they've heard of before, worked with before, and probably already trust (perhaps begrudgingly, but nevertheless) it to secure their banking.
All of this makes it comparatively easy for interested people to wrap their head around Gemini, pick up their favourite programming language and the pre-existing libraries for it, and put together a client, or a server, or both. People have been doing this, a lot! At
right now I count 9 severs and 14 clients, for 23 in total (and I wouldn't be surprised if that number's changed already tomorrow). At the same time
the official known servers list
has 31 servers on it, making for 32 in total once we add the one hosting the list. That's an implementation to server ratio of 0.72. That's crazy! How many internet protocols have such a high value of that figure? How many internet protocols have reached that high a value less than a year after they were created?
I think this has happened for Gemini due to radical familiarity. People can read the spec and think "okay, I get this, I can build something, let's go!". Replacing TLS with *anything* else would break that. It might very well result in a protocol which is easier to code from scratch, which has better privacy, and which has other real benefits that I don't at all mean to deride. But it would be a protocol that many more people would see as a bit of a black box and would *use* rather than implement.
Gemini is a small project, with no financial budget and a very limited time/energy budget. The number of people who have carefully read every line of code in any client or server implementation is likely not to exceed 1 in a lot of cases. And yet, by using TLS for our security, we guarantee that a very large number of very smart and knowledgeable people will get paid good money full time to effectively think about Gemini security and to write and test libraries for us, even if they've never heard of Gemini. Even if they *have* heard of Gemini and for some reason viciously hate it, we still benefit from all of their work, and always will. TLS is going to be scrutinised and maintained and improved for the foreseeable future on other people's time and money. This is currently not true for any alternative. It would almost be crazy for a small volunteer project *not* to take advantage of this kind of guaranteed pre-existing industry support.
I think a lot of negative feelings toward TLS are actually negative feelings toward OpenSSL combined with the impression that OpenSSL is the only serious option. There's this idea that doing TLS necessarily means depending on this huge, sprawling, poorly-understood, -documented, -tested code base and that's a recipe for disaster, and very different to e.g. relying on your OS to provide TCP/IP and DNS and a filesystem and all the other things that people who proudly write tiny Gopher clients ignore when they tell themselves they wrote their client from scratch and understand perfectly how it works.
This is not quite true, though, although when I started Gemini I wrongly believed it was pretty close to the truth. The only alternatives I knew of were
and
A quick aside on minimum TLS version: The current spec says Gemini has to use TLS 1.2 or greater. I would have loved, absolutely *loved*, to spec 1.3 or greater. The TLS 1.3 specification drastically reduces the range of supported cryptographic primitives and complexity in general, and gets rid of a lot of the tedious but important configuration that people associate with TLS. It introduces other features, too, which will be beneficial for Gemini. For example, being able to restart previously negotiated sessions to reduce the handshake overhead, which to some extent could ameliorate the fact that Gemini's lack of support for reusing connections means we're setting up and tearing down TLS connections over and over again (although, without any way for one request to trigger followups for images, stylesheets, javascript, fonts, etc. I don't think this is really that big a problem). So why haven't I? Because, at the time, TLS 1.3 was not supported in LibreSSL, and there was an existing server implementation (the first ever, in fact!) using LibreSSL which couldn't do more than 1.2, and because in general I didn't want to discourage the use of non-OpenSSL libraries. I have very high hopes for the LibreSSL project and very high faith in the OpenBSD folks behind it.
Oh, and you know what, I've just checked now and a new LibreSSL was released earlier this month and the release notes mention "Completed initial TLS 1.3 implementation with a completely new state machine and record layer. TLS 1.3 is now enabled by default for the client side, with the server side to be enabled in a future release". So maybe I'll be able to change the spec sooner than I thought!
Anyway, it turns out there is more variety in the TLS ecosystem than I previously thought. I'm especially interested in
which, among other things, aims to "be small, both in RAM and code footprint. For instance, a minimal server implementation may fit in about 20 kilobytes of compiled code and 25 kilobytes of RAM". This thing runs on tiny ARM microprocessors, including
the popular hobbyist platform ESP8266.
This was a surprising and exciting discovery for me. I think the existence of a library like this is at odds with a lot of people's intuitive understanding of TLS.
In short, I think that the trend toward simplification in the TLS spec itself represented by 1.3 and the appearance of new TLS libraries which are explicitly aiming to be smaller and simpler than OpenSSL mean that many objections to using TLS will get weaker and weaker over time. I hope so, anyway.
My off-the-cuff objection to people objecting "I can't write TLS myself!" has always been "That's okay, I guarantee your language of choice has bindings to at least OpenSSL. Use that!". Having now tried to do this myself, I have to concede that it's not exactly as simple as all that, and it seems like many other people have had the same experience.
It's true that a great many programming languages make it easy to call out to OpenSSL. However, very often the interface they expose is quite limited and has very clearly been designed for the express purpose of letting web developers with minimal understanding of TLS implement Perfectly Normal Everyday Stuff quickly and easily with little to no risk of shooting themselves in the foot as a result of some small error. I completely understand why an interface like this is a good thing to have, but it's extremely frustrating not being able to "go off-road". For example, the `ssl` module in the Python standard library does not permit a server to accept a connection with a self-signed client certificate, which is problematic for Gemini's notion of transient client certificates as a kind of alternative cookie which allows a client to voluntarily enter into a kind of "session" with a server, secure in the knowledge that it can permanently terminate that session whenever it likes. Implementing the TOFU security model also seems to be problematic in a lot of libraries.
For the record, yes, I realise that this frustration with libraries not making it easy to do what we want is because what we want to do is quite unusual from the perspective of mainstream TLS usage, and the fact that what we want to do is unusual from the perspective of mainstream TLS usage undermines, to some extent, the earlier argument that by using TLS we get to "freeride" on the mainstream industry implementing and testing our security code. But it's a very mild kind of undermining which doesn't take much away from the strength of the argument.
This is, as I said, frustrating, and does mean that mandatory TLS raises the difficulty of implementation more than I thought it would. But I don't see that there's much that can be done about it.
It's become pretty clear, both from my own efforts to add extensive client certificate support to AV-98 and from questions that people having been asking on the mailing list or on Mastodon, that the current Gemini spec is way too vague with regard to several aspects of our use of TLS.
For example, there's no mention anywhere of
which is essential to correct functioning of virtual hosting. It seems some existing clients might not be sending the server hostname as part of the TLS handshake and that some servers might not function correctly without it. This will need to be addressed.
To be honest, almost *all* of the fine details of how I imagined client side certificates would be used have proven to be not more than vaguely implicit in the descriptions of the different status codes, and this will need to be addressed, too. Everything from the high level workflows of how clients can "sign up for an account" at servers, to finer details of how the Issuer and Subject fields of self-signed certificates should be used by convention, will need to be hashed out.
I'm starting to think that the bulk of the work to be done after the spec freeze expires will be TLS-related.