--- date: 2024-11-10 title: "The other end of the authentication rabbit hole" linkTitle: "Authentication" author: Dimitri Staessens --- ''' I know the pieces fit 'Cause I watched them tumble down -- Tool, Schism (2001) ''' Mariah Carey signals it almost Christmas, so it sounds like as good a time for a blog post. Been a long time since my last one. My plan for this year for Ouroboros was to clean up the flow allocator code, then add implement authentication and clean up and fix packet loss handling (EFCP) and congestion avoidance, and then leave the elephant - the naming system - for later. As they say, plans never survive contact with the enemy. At least I got the clean-up of the flow allocator code done. So how did the authentication implementation go, you ask? Or maybe not, but I'm going to tell you anyway. Despite not having an implementation, the journey has been quite interesting. The idea was quite simple, actually. I've been been told ad nauseam not to "reinvent the wheel", so my approach to authentication was going to be as boring as one could expect: establish a flow between the client and server, and then do some well-known public key cryptography magic to authenticate. It's how SSL does it, nothing wrong with that, is there? After an initial check, I validated I could easily use OpenSSL and X509 certificates. This authentication implementation was going to be a walk in the park. But here I am, at least 5 months later, and I don't have this implemented. There was one thing I absolutely wanted to avoid: having to configure the certificates for each application. The library could of course add some configuration/command line options to each linked application (e.g. --certificate), but even that is not to my liking: I know this is roughly how it is with OpenSSL certificates today, but it's a drag, and the O7s code was very emphatically hinting that it could be done. But how? One way was to map programs to certificates in the IRM configuration, and when an application starts, the IRMd will pass it the certificate. As an example, the configuration has an entry /usr/bin/apache -> apache.crt and when /usr/bin/apache starts, it would get that certificate loaded). Meh, that would kind of have worked, but it left another problem open: what if I wanted the same application to start twice, but with different certificates? In other words, I'd need to map the certificate to a process, not to a program. That kept my mind busy for a while, as there seemingly was no obvious solution to this. I say seemingly, because the solution is as obvious as it is simple. But it's far off the current state of affairs. So, how could I get a process to load a certificate at runtime, but configure it in a central location before the process is running? That seems like aa catch 22. Mapping the program, instantiating the program, then set a new mapping, starting another process, that would be an error-prone mess riddled with race conditions. The answer is simple don't map the process, map the service name. O7s already has the primitives to map programs and processes to names. And this method is actually not that far off the current Internet. X509 certficates are usually tied to Domain Names. One part of the puzzle solved, and I can still use standard X509 certificates. So, why don't I have this yet? Glad you asked. Mapping certificates to names and as such indirectly tying them to processes allows for a significantly different approach for authentication. Why would we trust the peer with sending us his certificate? We can get it from the name system, before establishing any communications with the peer. So, instead of allocating a flow, and then authenticating and deriving symmetric keys for end-to-end in-flight encryption - as is done with TLS - we can do something a lot more secure: encrypt absolutely everything - including the initial (flow allocation) handshake. But this has another impact on my implementation plan: I need the naming system, as the public certificate needs to be there for this to work. The naming system is a component that has not been written yet. It is a distributed application/database and it needs IPC with the IRMd. And so this has opened another debate in my head: should I start over with the implementation? O7s started in 2016 with the intention to be a RINA implentation, but as we went on we changed it quite a bit. Some core parts are a thorn in my eye, most notably the synchronous RPC implementation. I don't want to build the new component (name system) using that approach, and ripping it out of the current implementation is going to be messy. Starting over would allow using a more "modern" language than C. I've been looking at rust and golang, but from my initial survey, they don't seem like a good fit due to the lack of shared memory/robust mutex support. If C is the only viable language for this thing, ripping the guts out of the current implementation might be the best option after all. I've not reached a conclusion yet. Anyway, as always: Stay Curious. And have a nice end of year. Dimitri