Hey Steve,

Thank you for your feedback.

> - uses extra crypto functionality which is not already part of wireguard; and
> - passes messages across public networks using that functionality; and
>
> For what it's worth, if it would be possible to also encapsulate your control protocol inside wireguard, that would be vastly preferable: it allows the transport cryptography to be implemented in one place, once (i.e. in wireguard), and lets wirehub be a purely organisational overlay for managing links, rather than touching the crypto and introducing troubling extra complexities.

I agree.

The main issue to implement this is to accept message_handshake_initiation
packet from unknown initiators. WireHub peers discover themselves through the
DHT. One peer does not know in advance what peers will communicate with it. The
current implementation of WireGuard drops packets from unset peers.

I plan to implement a replay mechanism of the message_handshake_initiation
packet, where WireHub peeks it, decrypts the initiator's public key, and if
unknown and has enough workbit, will add it to WireGuard's peers before
replaying the packet. The main advantage is to avoid adding usage-specific
features to WireGuard, but I need to re-implement part of the WireGuard crypto
scheme (plus the replay mechanism might be a little dirty).

Another approach might be to modify WireGuard to add a hook called when a
unknown peer initiates a session. When it happens, a userland app (here,
WireHub) is called to accept or reject dynamically the initiator. This reduces
the overhead of processing twice the message_handshake_initiation packet from
the previous solution, but it would add complexity to the WireGuard's code.

    on_message_handshake_initiation(m) {
        // decrypt static_public

        if (unknown_peer(static_public)) {
            if (hook) {
                r = hook(static_public)     // call dynamically WireHub
            }

            // if no hook or hook rejects initiator, drop packet
            if (!hook or !r.accept_initiator) {
                return drop();
            }

            // else add iniatiator to peers
            set_peer(iniator.static_public,
                allowed_ips=r.allowed_ips,
                endpoint=iniator.endpoint,
                preshared_key=r.preshared_key,
                persistent_keep_alive=r.persistent_keep_alive)
        }

        // process message_handshake_initiation
    }

> - clamps the wireguard keys in some unspecified way to embed a proof-of-work (in fairness, I haven't read the code, so please correct me if I have misunderstood).

The workbit of a Curve25519 key is the count of trailing zeros of a derivation
of the public key.

    workbit(sk, namespace='public') {
        k = pub(sk)
        h = blake2b(k ⊕ namespace)
        wb = trailing_0s(h) // see __builtin_clz
        return wb
    }

WireHub peers only accept peers which public key has enough workbits. This makes
identity expensive to generate, which mitigates Sybil attacks.

When workbit is incremented by one, the count of possible Curve25519 keys is
divided by 2. I don't know if it's a problem? I explored other PoW scheme, but
the current implementation is the simplest one I found.

> I would also love to see some sort of PKI option with this project, to avoid having to explicitly trust all the peers. I'd prefer to be able to simply provide the peers with a signature they can present to other peers that proves they can be trusted (or even better, have that signature generated by a nominated host at connect / setup time for each peer, which avoids much of the shenanigans involved with handling expiry, revocations etc.) Having the ability to tell all peers on the network to immediately terminate all connections with a specific compromised peer would also be handy.

I plan to build this on top of WireHub, once it will be more mature.

A PKI daemon may read peer's certificates, signed by a given authority, keeps a
list of the trusted peers and updates in live the wirehub's conf file.

Cheers,
Gawen