--- 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 authentication and clean up and fix packet loss handling (EFCP), fix congestion avoidance, and then leave the big missing part - 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 as part of the application. The library could of course add some configuration/command line options to each linked application (e.g. --certificate ), but that is also 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 without. 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 -> /etc/ouroboros/apache.crt and when /usr/bin/apache starts, it would get that certificate loaded). That would kind of have worked, but it left another problem: 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 from 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, and before the process is running? That seems like a catch-22. First mapping the program, instantiating the program, then configure a new mapping, starting another process would be an error-prone mess riddled with race conditions. The answer was simple: don't map the process, map the service name. O7s already has the primitives to map programs and processes to service names. And this method is actually not that far off the current Internet approach. X509 certficates are usually tied to Domain Names. One part of the puzzle solved using this indirection, and I can still use standard X509 certificates, nice. 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. Translated to the current Internet: DNS could return the public key together with the IP address. So, instead of first 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: get the public key of the peer from the naming system and use it to encrypt 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 retrieved from it 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, but from my initial survey, rust don't seem like a good fit due to the lack of shared memory/robust mutex support. Golang inherits mutexes from C pthreads, but I'm not that fond of switching to golang over C (and it might not work that transparently with other OS like BSD or OS X if I rely on the pthreads and shared memory). 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