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

defining security protocols for point-to-point encryption #139

Closed
dominictarr opened this issue Mar 10, 2015 · 9 comments
Closed

defining security protocols for point-to-point encryption #139

dominictarr opened this issue Mar 10, 2015 · 9 comments

Comments

@dominictarr
Copy link
Contributor

To communicate securely, you need to connect to an address, and use a protocol to encrypt the application protocol. In p2p systems, peers addresses change, so you usually have a lookup system.
In bit torrent this lookup is a tracker / dht, and in bitcoin they have a gossip system. Ssb is a gossip system, and the pub messages are the part look up part of it.

Currently, pub messages just have an address. To make communication between peers secure, it needs to have a cipher too. ciphers are complicated. Even the underlying cryptographic primitives change, but also, you can change the way those primitives combine.

Assuming that improvement will be found even in good security protocols, it will be necessary to upgrade those protocols. That means that there will be times when multiple protocols are in use within a network.

At least, we'll need a way to specify what protocols an address is using. Also, there are sometimes addresses that may use some other network rather than IP (!) for example, tor - although tor is over ip, the concept of an ip address is abstracted away.

here is my idea for a protocol description

net(<ipaddress>) | privacyStream(chacha20(), diffieHelman(modp15)) | secureStream(blake2s())

this could be represented as a JSON ast,

[['net', <ip>], ['privacy-stream', ['chacha20'], ['diffie-helman', 'modp15']], ['secure-stream', ['blake2s']]]

you'll notice this a lot like lisp. the top level function calls create streams, which are piped together. This uses brackets, and thus is a tree, because sometimes primitives have their own arguments. a straight list, say separated with / like a file system can't encode this unambigiously, you have to know how many arguments each term takes, so it can't be statically analyzed unless you know what a given term is. Here is where this proposal differs from

This can setup the various parts of the protocol, as well as primitives to those protocols, even if they it turn have their own arguments... and if you want to communicate over some new fangled networking polyfill like cjdns or tor or space lazers or something that doesn't use ip you can do that too.

To check if you can communicate with another peer, just scan through their connection stream, and check that you support all of their parameters.

Then, we need a way to express that a protocol suite is safe to use. I guess we can make that with using wild cards? maybe:

[['net', /.*/], ['privacy-stream', ['chacha20'], ['diffie-helman', 'modp15']]]

in a protocol audit message... when upgrading your protocol, you'd choose what protocols you think are safe, or who you trust to make that call. Then your instance can tell what it should use to upgrade.

Now, just need a way to generate a string that describes what my address will be.
In the above example, the only thing that will change is my ip address and port. so it's only the net call that may change... Oh also, we may want to listen on multiple addresses at once (the legacy protocol, and the new protocol)

hmm. maybe this:

createServer(...).listen([
  //new private stream
  [['net'], ['privacy-stream', ['chacha20'], ['diffie-helman', 'modp15']]],
  //new private stream, over ws
  [['ws'], ['privacy-stream', ['chacha20'], ['diffie-helman', 'modp15']]],
  //legacy plain text stream
  [['ws', true]]
])

then that would have a getAddress method that gave a full description of what it was using including ports and ip addresses.

@pfrazee
Copy link
Contributor

pfrazee commented Mar 10, 2015

Some of this is outside my expertise, so I'm going to offer thoughts where I can.

Here is where this proposal differs from

You forgot to finish your

['net', <ip>]

'net' isn't very specific. If 'ws' is also a possible value, then I'd suggest 'tcp' instead of 'net' (if that's what 'net' represents)

Currently, pub messages just have an address. To make communication between peers secure, it needs to have a cipher too.

Until a node has received pub messages for the target, will they have to use an unencrypted connection? Is there a security advantage to broadcasting ciphers over the feed instead of during a connection handshake?

How will peers create private-streams within the local network, where pub messages are not typically used to find peers?

@dominictarr
Copy link
Contributor Author

yeah, 'net' should be 'tcp'.. and maybe the 'net' module should be called 'tcp' too.

Ideally, you'd put the encryption protocol in the invite code too.

I think the design is overall simpler if there is not a handshake.
The problems is you can't encrypt the handshake, and you can't upgrade it either.

I think that traditional TLS is designed for a completely different problem than we have.
We can have a way simpler design, since we already know keys, and we can gossip information about peers around too, even if two peers can't communicate directly.

@dominictarr
Copy link
Contributor Author

see also the discussion here: ipfs/kubo#34

@pfrazee
Copy link
Contributor

pfrazee commented Mar 10, 2015

The problems is you can't encrypt the handshake, and you can't upgrade it either.

can you go into some more detail on that? why is that an issue?

@dominictarr
Copy link
Contributor Author

If you have a plaintext handshake, then that part isn't private, so it puts a ceiling on the level of security that is possible. You leak metadata - What keys you are using, who you are communicating with. You can upgrade the ciphers but you probably cannot upgrade the handshake itself.

This might be acceptable for some threat models,
but if you want to upgrade away from that later, you can't easily.
because the idea of one protocol is baked into your system.

@pfrazee
Copy link
Contributor

pfrazee commented Mar 10, 2015

You leak metadata - What keys you are using, who you are communicating with

Ok, thanks, that's what I was missing. That's a reasonable improvement.

The remaining hole in my thinking is what happens when the cipher is not known ahead of time, which (even if the cipher is included in the invite) might still happen. Since we have integrity guarantees in the data structures, I'm inclined to allow non-private (plaintext) communication as a failure mode, but I guess the question is what are the implications of non-private connections and what are the scenarios when they are acceptable or unacceptable, if ever?

@dominictarr
Copy link
Contributor Author

That is how email works (!).

I can imagine some being okay to have their data shared over plaintext, but others not.
maybe you would post a message "never replicate my data over plaintext (or these weak ciphers...)"

Obviously the cipher needs to be known for someone to use that invite, so people shouldn't use weird ciphers in their invites. that is reasonable.

@dominictarr
Copy link
Contributor Author

I mean, it may happen, but a p2p system must be designed so that it all still works even if you can't communicate with some peers - normally the reason for that is because of a network partition. Here we might encounter a protocol partition but the same design principle should save us.

@dominictarr
Copy link
Contributor Author

closing, we now have secret-handshake, and decided not to attempt algorithm agility.

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

No branches or pull requests

2 participants