rustdesk / rustdesk/rustdesk-server

Proof of concept: rustdesk_server tcp only handshake / secured tcp stream

Open
#394 9 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

enhancement
Dominant language
Rust
Stars
10.4k
Forks
2.6k
PR merge metrics
No merged PRs in 30d

Description

Describe the solution you'd like
Please publish the server side related to client [ start_tcp(server: ServerPtr, host: String)]
(https://github.com/rustdesk/rustdesk/blob/0d75f71d16b9712b959423f6ae8fe5de7502e8f2/src/rendezvous_mediator.rs#L334)

Describe alternatives you've considered
Forking the rustdesk-server for allowing tcp only handshake.
RustDesk already have a option for allowing a tcp only handshake while it is compiled with TEST_TCP .
It works perfectly with hbbs / hbbr from rustdesk-server-pro docker image but not with oss server.

After updating libs/hbb_common on rustdesk_server we can refactor the handle_tcp

  • It needs to use the new FramedStream with Option<Encrypt>
  • It needs to send RendezvousMessage KeyExchange
  • It needs to send stream.set_key(Key) for enabling secure tcp

as a proof of concept I modified the RustDesk client for adding an option to choose between UDP and TCP mode.
Next I quickly modified an oss rustdesk-server for working with this tcp enabled RustDesk client.
I added this when the tcp connection

let (our_pk_b, out_sk_b) = box_::gen_keypair();
// …
let mut msg_out = RendezvousMessage::new();

let (key, sk) = Self::get_server_sk(&key);
match sk {
    Some(sk) => {
        let pk = sk.public_key();
        let sm = sign::sign(&our_pk_b.0, &sk);

        let bytes_sm = Bytes::from(sm);
        msg_out.set_key_exchange(KeyExchange {
            keys: vec![bytes_sm],
            ..Default::default()
        });
        log::debug!(
            "KeyExchange {:?} -> bytes: {:?}",
            addr,
            hex::encode(Bytes::from(msg_out.write_to_bytes().unwrap()))
        );
        //stream.set_key(pk);
        Self::send_to_sink(&mut sink, msg_out).await;
    }
    None => {
    }
}

it sends a correct message to the client, the client answers also a KeyExchange message but with with two keys generated with create_symmetric_key_msg(their_pk_b: [u8; 32]) .
Basically it creates a symetric key with sodiumoxide, encrypt it with the server ed25519 public key a null nonce and our ed25519 private key.
The server receive the KeyExchange, because it has 2 keys, it decrypts the sodiumoxide secret box with client pk and server sk , get the symetric key and issue stream.set_key(pk);.
Now the 21116 tcp port must be secured and can handle RegisterPeer…
The protocol can be hardened by using a random nonce and transmit it back to the server.

Additional context
Add any other context about the feature request here.

Notes

  • Please write in english only. If you provide some images in different languages, you're required to write a translation in english.
  • In any case, NEVER put here the content if your id_ed25519 file

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by examining handle_tcp after updating libs/hbb_common, then compare the client start_tcp flow in src/rendezvous_mediator.rs and create_symmetric_key_msg in src/common.rs. Trace RendezvousMessage KeyExchange and FramedStream handling, including stream.set_key. Done means the 21116 TCP port completes the exchange securely and handles RegisterPeer.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
backend, networking, security
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.