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

Add Support for Encrypted/Authenticated Listeners #2129

Open
wants to merge 3 commits into
base: dev
Choose a base branch
from

Conversation

dr7ana
Copy link
Collaborator

@dr7ana dr7ana commented Jan 30, 2023

User can specify encrypted listener addresses and comma-delimited public keys to be accepted by exposed encrypted listener. Keys must be attached to a listener address.

Example:

bind_curve=tcp://0.0.0.0:1234|pubkeyA,pubkeyB
bind_curve=tcp://0.0.0.0:5678|pubkeyC,pubkeyD

In the given example above, port 1234 is only accessible by whitelisted pubkeys A and B, while 5678 is accessible by C and D.

Fixes: #2122

@dr7ana dr7ana force-pushed the ipc-listener-2122 branch 3 times, most recently from 2ca7d4c to db24984 Compare January 30, 2023 20:34
@dr7ana dr7ana changed the title Ipc listener 2122 Add Support for Encrypted/Authenticated Listeners Jan 30, 2023
llarp/config/config.cpp Outdated Show resolved Hide resolved
llarp/config/config.hpp Outdated Show resolved Hide resolved
- created option to add encrypted listeners with paired pubkeys in unordered_map, plus access verification
- pubkeys stored in unordered set, changed lambda for listen_curve
- pubkeys are comma-delimited and paired with bind address in config file
@majestrate majestrate added this to the 0.9.12 milestone Feb 5, 2023
@dr7ana dr7ana self-assigned this Feb 14, 2023
llarp/config/config.cpp Outdated Show resolved Hide resolved
llarp/rpc/rpc_server.cpp Outdated Show resolved Hide resolved
llarp/rpc/rpc_server.cpp Outdated Show resolved Hide resolved
llarp/rpc/rpc_server.cpp Outdated Show resolved Hide resolved
@dr7ana dr7ana force-pushed the ipc-listener-2122 branch 2 times, most recently from e8c1b77 to 15e7caa Compare February 14, 2023 17:14
@jagerman
Copy link
Member

This is going to need some deeper changes in lokinet to make it work w.r.t. to lokinet-side "server" pubkey, so for right now let's put this on hold until we can come back to it (likely after some other refactors are merged). Some notes on what is required to make this work follow.


The main issue is where we specify the OMQ listener keypair: right now, we default-construct the OxenMQ instance during Router construction, which results in OxenMQ generating a new random keypair at every startup. For a curve listener this is fairly useless because it means you'd have to go get this pubkey (which right now we don't even log, much less expose in any useful way) every time you want to use the client: you couldn't, for instance, set up a script that periodically polls lokinet for stats because every time the server restarts you'd have to (manually) obtain the new server pubkey and update it in the script.

What we need here is two pieces:

  1. For a service node, we want to use the service node's x25519 keypair itself. This is the same key as the ed25519 keypair we use for the router already, just converted into x25519 keyspace. (We could call on libsodium to convert, but it's probably easier to just use the pre-converted x25519 keypair that oxend gives us through the get_service_privkey endpoint that we already call to get the ed25519 keypair).

This gets complicated, though, because we have to re-create the OxenMQ instance after we get this keypair and give it the new keypair we got from oxend.

In storage server, we solve this problem by using two OxenMQ instances: we create a temporary one during instantiation that only has one job: connecting to oxend and getting the keys. This basically blocks startup until it succeeds, at which point we destroy that object and reconstruct a new OxenMQ using the just-fetched private key.

Lokinet likely needs to do something similar, but currently that is difficult because of how the OxenMQ instance is embedded in the Router instance (and this is the instance that we use to get the keys from oxend). Likely a solution here is going to require us setting up a temporary OxenMQ instance to extract the keys very early in the startup (before we construct the router god object) and passing those keys into Router construction so that the OxenMQ instance that Router owns can get constructed with the keys.

  1. For lokinet clients, we want to store a persistent x25519 private key in a generated file in the data directory. We can generate and store a new key if this doesn't already exist, and (when curve listening is enabled) we should log the x25519 pubkey (not privkey!) in the startup logging. Then it's just a matter of getting this once, putting into your logging script (or whatever is connecting to your lokinet rpc) and you're done.

This file-backed private key we then feed into the Router construction (similar to the snode case) so that it creates the OxenMQ instance with this key.

@jagerman jagerman modified the milestones: 0.9.12, 0.9.13 Feb 14, 2023
@jagerman
Copy link
Member

An alternative here would be to update OxenMQ to support a per-socket key in the listen_curve call. Currently it just uses a master key, but there's no ZMQ requirement for that: we could set up the listened ZMQ socket with a distinct keypair.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add encrypted/authenticated IPC listener support
3 participants