|
| 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. |
0 commit comments