1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
---
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
|