ipfs / specs

Technical specifications for the IPFS protocol stack
https://specs.ipfs.tech
1.17k stars 232 forks source link

IPFS doesn't use TLS #29

Closed willglynn closed 5 years ago

willglynn commented 9 years ago

protocol/network#Encryption:

IPFS uses cyphersuites like TLS.

NOTE: we do not use TLS directly, because we do not want the CA system baggage. Most TLS implementations are very big. Since the IPFS model begins with keys, IPFS only needs to apply ciphers. This is a minimal portion of the whole TLS standard.

So you rolled your own transport encryption? I find this surprising, and I'm… skeptical.

This needs to be a new section (or an entirely separate document) rather than an aside.

(Also, I'll add that if all you want is to connect to something, exchange RSA public keys, and get an encrypted transport stream, TLS is entirely capable of providing that without involving CAs.)

willglynn commented 9 years ago

I flipped through the IPFS crypto code and didn't see anything screaming out as obviously wrong. I am curious about the choice of HMAC + stream ciphers over AEADs, and again I don't even remotely understand why TLS won't work here instead.

That said, I was trying only to figure out how IPFS encryption works in absence of documentation, and I am not an expert in this field. Some people who know more about crypto than I do say things like:

In the 1990's it was common for cryptographers to produce block ciphers and hash functions, and then developers would be tasked with composing them. In the talk I stepped through the design of, and attacks on, the SSLv3/TLS CBC construction as a demonstration that plausible-sounding design features can lead to disaster, but I'm going to omit that here because it worked better live. (Phillip Rogaway tried to warn about these issues when SSL, IPSec, etc were being developed, but sadly the right people didn't listen to him.)

So, for quite a long time now, cryptographers have understood that block ciphers and hash functions are too low-level an abstraction and that the constructions themselves need to be studied and standardised. The result is called authenticated encryption (AE)

– Adam Langley, author of much of Go crypto/*, in a recent blog post about AEADs

The point here is that the best security methods leverage the collective analytical ability of the cryptographic community. No single company (outside the military) has the financial resources necessary to evaluate a new cryptographic algorithm or shake the design flaws out of a complex protocol. The same holds true in cryptographic libraries. If you write your own, you will probably make mistakes. If you use one that's public and has been around for a while, some of the mistakes will have been found and corrected.

It's hard enough making strong cryptography work in a new system; it's just plain lunacy to use new cryptography when viable, long-studied alternatives exist. Yet most security companies, and even otherwise smart and sensible people, exhibit acute neophilia and are easily blinded by shiny new pieces of cryptography.

This doesn't mean that everything new is lousy. What it does mean is that everything new is suspect.

– Bruce Schneier in Cryptography: The Importance of Not Being Different from 1999

Anyone can invent a security system that he himself cannot break. I've said this so often that Cory Doctorow has named it "Schneier's Law": When someone hands you a security system and says, "I believe this is secure," the first thing you have to ask is, "Who the hell are you?" Show me what you've broken to demonstrate that your assertion of the system's security means something.

– Bruce Schneier again, as an aside in a 2006 Crypto-Gram

So: what makes TLS unsuitable for use in IPFS? Does that same rationale also apply to DTLS, SSH, and every other pre-existing transport encryption scheme? Why invent your own?

jbenet commented 9 years ago

( i wrote this before your second post )

We may use CurveCP. TLS 1.3 is also shaping up nicely, we may use it. And we may also just go for QUIC (inc DTLS).

So you rolled your own transport encryption? I find this surprising, and I'm… skeptical.

Why? I understand the dangers perfectly. But TLS is no pancea. Its implementations have been, for a long time, a bag of disasters. And the model is so lose-- easy to do something wrong with all the options. I actually found it easier to review one (AEAD-like) protocol that we can audit clearly, is written in Go (safer than C, much easier to audit), using primitives in the stdlib written by AGL.

In short, "crypto is hard" but that does not mean "never design new protocols". It means "label your protocols insecure until a strong part of the security community is confident in its design AND implementation". Otherwise, we'd be stuck forever :). (FWIW, TLS 1.3 and DTLS came out of orgs like Google making the same call).

To be clear, we label our stuff "insecure" until we have audited it professionally and exposed it to many other strong crypto engineers. So far, all of our networking stack is, under this definition, "insecure". Though as far as we know, it has stronger security guarantees already than many other p2p systems branded as secure (tl;dr: we have high standards)

This needs to be a new section (or an entirely separate document) rather than an aside.

Time. PRs accepted.

if all you want is to connect to something, exchange RSA public keys, and get an encrypted transport stream, TLS is entirely capable of providing that without involving CAs.

Most libraries I've seen require certs, or do not make it clear how to do it without, safely.

And no, not just RSA keys. people will be able to choose ed25519 keys soon enough, and maybe others later. Two peers, one using RSA and another using ed25519 should be able to talk. I don't recall whether TLS permits this (my guess is not, but i don't have nice docs atm (am offline)).


In any case, i'm all for being more secure with less work, just TLS has a ton of baggage i'd really like to end. CurveCP is a more attractive choice. But it makes other decisions too... DTLS is good when using QUIC ....

jbenet commented 9 years ago

I would add that if TLS can be used without all the X.509 nonsense, and with our own choice of pubkeys, including using different signing public keys (not the DHE keys) in the same conn, then we can consider breaking our "not TLS pls" stance.

willglynn commented 9 years ago

This needs to be a new section (or an entirely separate document) rather than an aside.

Time. PRs accepted.

I can see the code, so I can piece together an understanding of the current protocol. I was hoping to find a document to describe why it is what it is – what problem the IPFS encrypted transport layer needs to solve – in order to better understand it. This discussion is a good starting point.

Why? I understand the dangers perfectly. But TLS is no pancea. Its implementations have been, for a long time, a bag of disasters.

Maybe so, but applied crypto on the whole has been a bag of disasters, and there's a lot more people working on/near TLS (both protocols and implementations) than not. Staying near the crowd in general and using TLS in particular offers advantages.

And the model is so lose-- easy to do something wrong with all the options.

It seems even easier to do something wrong starting from scratch.

In short, "crypto is hard" but that does not mean "never design new protocols".

Agreed, there is a place for new protocols. I don't know exactly what problems this component is trying to solve, so I'm not sure this is one of them.

TLS is an existing protocol that offers an encrypted transport with mutual identity verification. Maybe IPFS genuinely needs something different, in which case a new protocol makes sense, but if not, I'll defer to Schneier:

it's just plain lunacy to use new cryptography when viable, long-studied alternatives exist

If TLS is viable, IPFS should use it.

It means "label your protocols insecure until a strong part of the security community is confident in its design AND implementation". Otherwise, we'd be stuck forever :)

I appreciate the labeling :-)

if all you want is to connect to something, exchange RSA public keys, and get an encrypted transport stream, TLS is entirely capable of providing that without involving CAs.

Most libraries I've seen require certs, or do not make it clear how to do it without, safely. … I would add that if TLS can be used without all the X.509 nonsense

Yes, TLS uses certificates for this purpose – certificates encoded in X.509 at that. This does not require that any CA is involved.

Certificates are a pre-existing way of linking identity with public keys, and presenting a certificate in a TLS handshake is a pre-existing way to assert that identity. I would favor their use for this purpose, even if the IPFS concept of identity is currently just "this is my key".

As for X.509, I've found that people often have a distaste for X.509 because of ASN.1, which can be charitably described as being flexible in all the wrong ways. However, the IPFS protocol as implemented today uses ASN.1 to encode RSA keys for transport, so ASN.1 must not be the dealbreaker. In fact, the IPFS protocol encodes public keys into an X.509 SubjectPublicKeyInfo structure right now. All that would be needed to make it an X.509 Certificate is to wrap that SubjectPublicKeyInfo in a TBSCertificate, fill in some fields with sensible defaults, and sign the result.

Further, even if X.509 were categorically rejected, that would still not rule out using TLS. One can use arbitrary cryptographic identifiers in place of X.509 certificates (e.g. PGP keys) – just identify them appropriately.

And no, not just RSA keys. people will be able to choose ed25519 keys soon enough, and maybe others later.

Good to know.

Two peers, one using RSA and another using ed25519 should be able to talk. I don't recall whether TLS permits this (my guess is not, but i don't have nice docs atm (am offline)).

Both parties need to understand and use the other's algorithm, but yes, TLS permits this. (Also, ed25519 in TLS is pre-standard.) Servers prove themselves to clients in one of two ways:

In either case, TLS key exchange employs the server's keypair and associated algorithm.

Clients wishing to assert their identity send a Certificate message followed by a CertificateVerify message. (Presumably this would be a requirement for IPFS, but it's optional for TLS on the whole.) CertificateVerify is signed with the client's private key, which the server then verifies using the client's public key. This is separate from the key exchange process, and it need not use the same algorithm, so long as both parties find it agreeable.

jbenet commented 9 years ago

You're right in many counts. a few notes:

How about this as a path forward:

Another thing left to figure out:

jbenet commented 9 years ago

cc @diasdavid

jbenet commented 8 years ago

Hey @willglynn -- would you be willing to help us out with some of this? would be good to move towards (perceived-to-be-)safer crypto.

I think we should add TLS and CurveCP to https://github.com/ipfs/go-libp2p as Transports

ghost commented 8 years ago

I think we should add TLS and CurveCP to https://github.com/ipfs/go-libp2p as Transports

Would that be transport-over-transport? I imagine we wouldn't neccessarily do it over TCP in the future. At least for cjdns' CryptoAuth, it could be e.g. TCP-over-CryptoAuth-over-UDP or QUIC-over-CryptoAuth-over-Ethernet.

jbenet commented 8 years ago

Would that be transport-over-transport? I imagine we wouldn't neccessarily do it over TCP in the future.

TCP is just one more transport, so layerings would look like:

/tcp/secio/<muxer> -- today
/tcp/tls/<muxer>
/curvecp/<muxer> -- secure, reliable
/quic -- secure, reliable, muxer

cjdns/CryptoAuth is secure, does it give either {reliable, muxing} ?

ghost commented 8 years ago

layerings would look like

We should work on getting that into multiaddr very soon! Together with /dns support! Saying this because they both require relaxing the current /key/value/key/value scheme.

cjdns/CryptoAuth is secure, does it give either {reliable, muxing} ?

CryptoAuth only gives you an unreliable channel per-peer. Reliability and muxing are done by TCP in the kernel (TUN/TAP interface). What would an unreliable channel be called, btw? It's just packets, not a stream. Maybe you can point me to something that clears these terms up, in our context.

ekr commented 8 years ago

Your two objections to TLS seem to be the tie to the PKI and the typical size of stacks. In that case, you might be interested in the folliwing:

[Edited to remove misattribution of the original objections]

jbenet commented 8 years ago

@ekr thank you for pointer to mint. we'll be revisiting this soon and adding TLS to go-libp2p as an auth transport so IPFS can use it.

jbenet commented 8 years ago

@ekr BTW, how confident are you on the Mint implementation? know if it has been professionally audited independently? I'd imagine cloudflare would do that, but now sure when.

And, know if the team has an interest in making a javascript version?

Otherwise we'll use https://github.com/digitalbazaar/forge in js-libp2p (unless someone brings up problems with it?) though it needs to implement TLS 1.3, i think.

In any case, good to see you around here, @ekr! sorry this was the thing to comment on :]

ekr commented 8 years ago

@jbenet it hasn't been audited yet. As you can see, the author is branding it as experimental for now. I think eventually he/we'll try to get some more review on it and figure out how to make it available in GoLang TLS. Tagging @bifurcation and @grittygrease on that.

As far as JS goes, the team from INRIA (@kaepora) has been working on a verified TLS 1.3 stack in JavaScript called ProScript but I'm not sure what the current state is.

jbenet commented 8 years ago

As far as JS goes, the team from INRIA (@kaepora) has been working on a verified TLS 1.3 stack in JavaScript called ProScript

that's excellent to hear. :heart: :lock: :heart: :lock: :heart: :lock: :heart: :lock: :heart: :lock: :heart: :lock: :heart: :lock: :heart: :lock: :heart: :lock: :heart: :lock:

dominictarr commented 8 years ago

from CryptoAuth section of cjdns docs

Like the rest of cjdns, it is designed to function with best effort data transit. unreliable.

The CryptoAuth handshake is based on piggybacking headers on top of regular data packets and while the traffic in handshake packets is encrypted and authenticated, it is not secure against replay attacks and has no forward secrecy if the private key is compromised.

I wouldn't consider that "secure", unless you really understand the implications of what a replay attack is able to achive, or what content a key compromise is able to recover...

Kubuxu commented 8 years ago

@dominictarr this happens only for first packet that is sent, and is done to reduce initial connection delay, if you don't want that it should be easy to just initialise CryptoAuth and send data with delay.

dominictarr commented 8 years ago

@Kubuxu hmm, well the problem is that the whitepaper doesn't clearly explain the properties of the crypto system (and issues arn't enabled on that repo so I can't raise that problem there)

The first problem is that it uses (ambigious) prose (instead of a terse notation, or pseudocode) to explain how it works, so reading that document I can't really tell what is happening... hopefully this is just a problem with the documentation and not CryptoAuth.

Kubuxu commented 8 years ago

The cjdns is still evolving. We have started a http://fc00.io/ and are currently trying to specout cjdns protocol.

troyronda commented 8 years ago

Any news on modifying IPFS to use TLS. I also think this topic could also use the TrustManager concept (https://github.com/ipfs/notes/issues/146).

jbenet commented 8 years ago

No big news yet, beyond "it's in the roadmap". We need to make concerted stabs at this, and place it in the roadmap. It did not make it to the core team's Q3 priorities, but perhaps Q4? That said others can take stabs at this.

The first section are relatively easy, given some libp2p transport familiarity. The latter prob have to involve @whyrusleeping and @diasdavid, at least for review.

alikic commented 8 years ago

We are experimenting with adding TLS 1.2 transport to go-libp2p, using standard golang "crypto/tls". We believe we understand it well, it involves creating replacement for go-libp2p-secio, we call it go-libp2p-tls. Right?

Can you elaborate what "adding TLS 1.2 and 1.3 transports to go-ipfs (1st layer of multistream)" is about? At this point we are OK with using TLS between peers only. Is "...(1st layer of multistream)" required for that?

whyrusleeping commented 8 years ago

@alikic So, when you connect to an ipfs node, you immediately get a multistream to select the encryption protocol. Right now it just has /secio/1.0.0 (or /plaintext/1.0.0 if you have the --disable-transport-encryption flag on). You would just have to inject your tls code to that part of the codebase.

whyrusleeping commented 8 years ago

You can use https://github.com/whyrusleeping/mss-nc to connect to an ipfs node and see these (mss-nc localhost 4001 then type ls).

jbenet commented 8 years ago

@whyrusleeping it may be good to just make a go-libp2p-tls module for @alikic -- or give directions how. so we can have it in go-ipfs. this should come to core. we should be able to do TLS 1.2 while 1.3 gets implemented in all the things.

danieldjewell commented 5 years ago

So, this issue has been open for (what github indicates) is >4 years.

From what I gather in /ipfs/specs/architecture/README.md - the protocol itself supports optional encryption? But that this isn't enabled by default?

From where I stand, here's what I see:

I appreciate that there's prioritization and so on, but really: (a) network protocols shouldn't be designed without encryption in 2019 (with very narrow and few exceptions) ... period ... and (b) if mandatory strong encryption isn't part of the protocol now, is that priority number 1? If not, why not? (To put it bluntly: if mandatory strong encryption is not a part of the protocol, 100% focus should be given to that beyond anything else. Period.)

It doesn't have to be TLS specifically (although one should never rewrite crypto from scratch...) ... look at how Signal has setup their protocol ... encrypted, end to end, automatic, strong crypto, good stuff.

Stebalien commented 5 years ago

This is an ancient issue.

  1. IPFS has mandatory encryption. While there is a plain-text transport, it's only used for debugging and has to be explicitly enabled (which completely disables encryption).
  2. We currently use a custom crypto transport (secio) but are in the process of switching to TLS1.3 by default. go-ipfs already has support for TLS1.3 and we will start using it by default in the near future.