Skip to content

Commit 76421db

Browse files
committed
Add ARCHITECTURE.md
1 parent 7109d86 commit 76421db

2 files changed

Lines changed: 240 additions & 12 deletions

File tree

ARCHITECTURE.md

Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
This document describes the high-level architecture of `credentialsd`. If you
2+
want to familiarize yourself with the code base, you are just in the right
3+
place!
4+
5+
# High-level Overview
6+
7+
There are three APIs defined in [doc/api.md](/doc/api.md). This repository contains
8+
two services that implement the three APIs defined by the specification:
9+
10+
- `credentialsd`: Implements the Gateway API and Flow Control API
11+
- `credentialsd-ui`: Implements the UI Control API.
12+
13+
These two services communicate with each other over D-Bus IPC.
14+
15+
The **Gateway** is the entrypoint for clients to interact with. The Flow
16+
Controler and UI Controller work together to guide the user through the
17+
process of selecting an appropriate credential based on the request received by
18+
the Gateway.
19+
20+
The **UI Control API** is used to launch a UI for the user to respond to
21+
authenticator requests for user interaction. The **Flow Controller** mediates
22+
authenticator requests for user interaction. The UI Controller and Flow
23+
Controller pass user interaction request and action messages back and forth
24+
until the authenticator releases the credential. Then, the Flow Controller
25+
sends the credential to the Gateway, which relays the credential to the client.
26+
27+
Here is a diagram of the intended usage and interactions between the APIs.
28+
29+
```mermaid
30+
sequenceDiagram
31+
participant C as Client
32+
participant G as Gateway
33+
participant U as UI Controller
34+
participant F as Flow Controller
35+
participant A as Authenticator
36+
37+
C ->> +G: Initiate request
38+
G ->> U: Launch UI
39+
U ->> F: Subscribe to events
40+
loop
41+
F ->> +A: Send control messages
42+
A ->> F: Request user interaction
43+
F ->> U: Request user interaction
44+
U ->> F: Respond with user interaction
45+
end
46+
A ->> -F: Release credential
47+
F ->> G: Respond with credential
48+
G ->> -C: Respond with credential
49+
```
50+
51+
The division into multiple services and APIs has two purposes:
52+
53+
- least privilege: if there is a vulnerability in the UI process, it shouldn't
54+
have access to interact with the credential service memory directly. Also,
55+
hosting separate D-Bus services allows us to set different access control
56+
policies on the bus, restricting communication on the Flow Control and UI
57+
Control APIs to the `credentialsd` and `credentialsd-ui` services.
58+
59+
- flexibility: UIs are very specific to their desktop environment, so it would
60+
be impossible to satisfy the style and requirements for all the various Linux
61+
desktop environments out there. This separation allows desktop environments to
62+
create their own UIs targeted for their users.
63+
64+
# Code Map
65+
66+
## credentialsd
67+
68+
A Rust binary project for the service hosting the Gateway and Flow Control APIs.
69+
Interacts with authenticators and clients/user agents.
70+
71+
`credentialsd` does not start the UI directly; it sends a request to start the
72+
UI via D-Bus. It relies on D-Bus service activation or some other external
73+
method to start the process that hosts the UI Control API.
74+
75+
Credential requests on the Gateway are handled one at a time; if a new request
76+
comes in, it is immediately rejected, and the client is expected to retry if
77+
necessary. Currently, clients cannot cancel their own requests; the user has to
78+
do that via the UI.
79+
80+
### `credentialsd/src/credential_service/`
81+
82+
`CredentialService` is the main component that interacts with authenticators. It
83+
also holds request context to return back to the Gateway for request completion
84+
or when the Flow Controller notifies it that the request is cancelled.
85+
86+
Various authenticator transports are handled in sub-modules, for now USB and
87+
hybrid transports are supported. Each handler starts a `Stream` of events that
88+
represents requests from the authenticator for user interaction. If a response
89+
is required from the user, the event should contain a channel for the credential
90+
service to send the response after it receives user input.
91+
92+
The credential service mostly just forwards events over to the UI service, minus
93+
any details that are not necessary for the UI to know (like the response
94+
channels mentioned above, which cannot be serialized over D-Bus anyway).
95+
96+
Actual interaction I/O is performed in the [libwebauthn][libwebauthn] library.
97+
98+
[libwebauthn]: https://github.com/linux-credentials/libwebauthn
99+
100+
### `credentialsd/src/dbus/`
101+
102+
D-Bus clients and services.
103+
104+
The Gateway and Flow Controller services are defined here, as well as a client
105+
for the UI Controller.
106+
107+
The `model` module contains some methods to convert from D-Bus types to internal
108+
credential service types. (These types don't need to be made known to the UI, so
109+
they do not live in `credentialsd-common`).
110+
111+
### `credentialsd/src/webauthn.rs`
112+
113+
Types and functions to deal with WebAuthn data.
114+
115+
Re-exports many types from `libwebauthn`.
116+
117+
### `credentialsd/tests`
118+
119+
The `tests/` directory contains a setup for integration tests, allowing
120+
`credentialsd` to connect to a test D-Bus instance. There is currently only a
121+
few tests there; this should be expanded in the future.
122+
123+
## `credentialsd-common/`
124+
125+
Rust types shared between `credentialsd` and `credentials-ui`.
126+
127+
Most of the types live in `src/model.rs`, and some are duplciated in
128+
`src/server.rs`. The duplicates in the `server` module have tweaks that make it
129+
easier to serialize over D-Bus, but more difficult to work with in Rust. So
130+
conversion methods are provided between the two modules.
131+
132+
## `credentialsd-ui/`
133+
134+
A reference implementation for the UI Control API.
135+
136+
This is a GTK4 implementation of a UI Controller. We don't intend this to fully
137+
polish the UI, but it is provided as a reference for other desktop environment
138+
developers to understand how to work with the API.
139+
140+
## `doc/`
141+
142+
Contains spec-level documentation.
143+
144+
Some of this is leftover from the first prototype. The documentation to pay
145+
attention to is `api.md` which describes the D-Bus API and expected patterns.
146+
147+
## `dbus/`
148+
149+
Contains D-Bus service description files for D-Bus service activation, as well
150+
as service policy files.
151+
152+
During development, changes to these require pushing to the correct directory
153+
`/usr/local/share/dbus-1/services` (or `system-services` if running on the
154+
system bus), and a restart.
155+
156+
## `systemd/`
157+
158+
systemd service definition files for managing D-Bus service activation via systemd.
159+
160+
During development, changes to these require pushing to the correct directory
161+
`/usr/local/lib/systemd/user` or `system` if running as a system service and
162+
reloading systemd's configuration with `systemctl daemon-reload`.
163+
164+
## `webext/`
165+
166+
A web extension that uses native messaging features to interact with the D-Bus
167+
API via the browser Credentials Management/WebAuthn API.
168+
169+
The `add-on/` directory contains the JavaScript and manifest that is loaded into
170+
the browser, and the `app/` directory contains a Python script that proxies
171+
messages between the browser and the D-Bus service.
172+
173+
This is intended to be temporary; eventually we would like support for this API
174+
to be upstreamed into Firefox and Chromium.
175+
176+
## `demo_client/`
177+
178+
A demo RP client that can be used for testing during development.
179+
180+
This is a Python client that mimics an RP, saving the created public keys to a
181+
local `user.json` file and verifying assertions against it.
182+
183+
You can use it like this:
184+
185+
```shell
186+
cd demo_client/
187+
./main.py create
188+
./main.py get
189+
```
190+
191+
## `contrib/`
192+
193+
Various helper files.
194+
195+
# Future Goals
196+
197+
## LSM Hardening
198+
199+
We should use all the LSM features possible, including SELinux, AppArmor and
200+
Landlock. We should also try to use `seccomp` where those fall short.
201+
202+
## Application Identity
203+
204+
Currently, credentialsd assumes that clients have the ability to request any
205+
origin. We should reduce this to only allowing some preconfigured list of
206+
trusted or "privileged clients" to request any origin.
207+
208+
What "trusted clients" means is not yet defined. This could be something like
209+
LSM labels, or even just a list of paths.
210+
211+
This list will need to be configurable by distros at least at install time, if
212+
not compile time. Steps must be taken to prevent modification of that list at runtime.
213+
214+
## Origin Binding
215+
216+
Eventually, if the application identity problem above is solved, then we would
217+
also like to allow certain clients access to request preconfigured origins based
218+
on a correlation between the application identity and the origin. We call these
219+
"unprivileged clients".
220+
221+
Potentially, this may mean hard-coding a list of trusted proxies, like the
222+
Flatpak or Snap daemons, to be trusted to set application identity properly. The
223+
applications they proxy access for would then be considered unprivileged
224+
clients.
225+
226+
(Whether this preconfiguration means that clients not on the list cannot call
227+
the D-Bus service at all, or whether they just have no binding to the origin is
228+
probably an implementation detail, or defense in depth.)
229+
230+
For more discussion on application identity and origin, see the
231+
[Origin Checking discussion][origin-discussion] on GitHub.
232+
233+
[origin-discussion]: https://github.com/linux-credentials/credentialsd/discussions/11
234+
235+
## Sandboxing
236+
237+
Eventually, we would like to sandbox I/O, like USB and Bluetooth, into separate
238+
processes so that malicious or buggy authenticators cannot corrupt the main
239+
service's memory or access privileged files. For now, all authenticator I/O and
240+
D-Bus service logic happens in the same process.

README.md

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -51,18 +51,6 @@ with `credentialsd` directly without an add-on. You can access a
5151

5252
[firefox-patch-flatpak]: https://download.opensuse.org/repositories/home:/MSirringhaus:/webauthn_devel/openSUSE_Factory_flatpak/
5353

54-
## Clients
55-
56-
There is a demo client in the `demo_client`. It mimics an RP, saving the created public keys to a local file and verifying assertions against it.
57-
58-
```shell
59-
cd demo_client/
60-
./main.py create
61-
./main.py get
62-
```
63-
64-
There is also a demo web extension that can be used to test the service in Firefox. Instructions are in [/webext/README.md]().
65-
6654
## Goals
6755

6856
The primary goal of this project is to provide a spec and reference

0 commit comments

Comments
 (0)