Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Design a simple credential distribution mechanism for WireGuard experiments #2772

Open
ainghazal opened this issue Jul 1, 2024 · 4 comments
Assignees
Labels
discuss invites discussion from contributors research prototype

Comments

@ainghazal
Copy link

ainghazal commented Jul 1, 2024

Problem statement

We need a simple way of distributing credentials for probing target WireGuard nodes. We assume we're able to control abuse, for instance by adding firewall rules to the wireguard node restricting what are allowed IP addresses routed from the gateway.

In a recent conversation with @hellais we said that we'd like an implementation that keeps as little state as possible: this means that we can control what information is passed to the clients via the VPN endpoint API, and/or hardcoding tokens on the experiment itself. On the wireguard server, we need to generate the list of public keys (and IP allocations) for the set of allowed Peers -- but we'd rather avoid modifying the configuration file dynamically.

We agree that we can pre-compute a number of public keys (a 32-byte Curve25519 point) on the server; this number needs only to be big enough to practically minimize the likelihood of a "collision" (i.e., two probes attempting to use the same encryption key).

This constrain is given by WireGuard design:

Since a public key uniquely identifies a peer, the outer external 
source IP of an encrypted WireGuard packet is used to identify
the remote endpoint of a peer, enabling peers to roam freely between
different external IPs, between mobile networks for example

Design Discussion

  • On the server-side: given a (sufficiently big) number N of allowed Peers, 1) compute N 32-byte random numbers with a known seed, 2) derive their public keys, 3) assign a unique allowed IP to each of them, 4) serialize this info as a valid wireguard configuration file and start the wireguard server with this configuration.

Do note that Curve25519 clamping may need to be accounted for (i.e., different private keys can result in the same public key), although the likelihood of this happening is possibly negligible.

  • On the client-side: given a known seed, 1) initialize the PRNG with the known seed, 2) pick a random 32-byte number between 0 and N, 3) use the 32-byte number as the private key, 4) derive the public key, 5) derive the IP using the same deterministic rule as the server did, 5) use these credentials+config (plus the preshared key) to connect to the server.

Choice of PRNG

Minor detail (need to benchmark it for practical usage), but we could either iterate through the whole range every time, if using a LCG (as the default PRNG in Go), that will give us O(n) complexity, or perhaps use a generator that allows skip-ahead, and thus O(1).

Priority & Deadlines

This would be the main blocker for distributing wireguard experiments to clients. At this point I'd say we're not on time to make it to the July release, so I would tentatively assign it to the September probe-cli release cycle. For sure testing from VPs can start as soon as I have a prototype ready.

@ainghazal ainghazal added bug Something isn't working triage labels Jul 1, 2024
@ainghazal
Copy link
Author

@hellais thoughts or preferences?

@ainghazal ainghazal added discuss invites discussion from contributors research prototype and removed bug Something isn't working triage labels Jul 1, 2024
@ainghazal ainghazal self-assigned this Jul 1, 2024
@hellais hellais self-assigned this Jul 11, 2024
@hellais
Copy link
Member

hellais commented Jul 11, 2024

I think we need to have a call to discuss this. We are currently a full capacity and we should aim for the simplest possible solution. Can do something like a github gist that just has in it the stuff you need and you hardcode that in your experiment? Alternatively would a OONI Run v2 link with custom options be sufficient?

@ainghazal
Copy link
Author

ainghazal commented Jul 12, 2024

fwiw, I got a binary util that can deterministically create server and peer configs given a pre-defined seed (and, implicitly, a chosen CIDR).

working on containerizing and integration tests.

@ainghazal
Copy link
Author

ainghazal commented Jul 12, 2024

would a OONI Run v2 link with custom options be sufficient?

that is already possible in the wireguard experiment. in fact, I had designed the wg MVP to support only an oonirun descriptor to avoid dealing with credential distribution (still, the distributors of the oonirun link should take into account how public the link is, and how many users are likely to attempt the test within the same time range). the scope of this issue is only related to exposing the experiment to the generality of users, so we should be free to drop prio for the time being.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
discuss invites discussion from contributors research prototype
Projects
None yet
Development

No branches or pull requests

2 participants