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

IPFS doesn't use TLS #29

Closed
willglynn opened this issue Sep 11, 2015 · 27 comments
Closed

IPFS doesn't use TLS #29

willglynn opened this issue Sep 11, 2015 · 27 comments

Comments

@willglynn
Copy link

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
Copy link
Author

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
Copy link
Member

jbenet commented Sep 13, 2015

( 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
Copy link
Member

jbenet commented Sep 13, 2015

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
Copy link
Author

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 an RSA key exchange, the client generates a premaster secret and encrypts it with the server's public key, which the server then decrypts with its private key.
  • In a DH key exchange, the sever generates DH parameters and signs them with its private key, which the client then verifies using the server's public key.

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
Copy link
Member

jbenet commented Sep 18, 2015

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

  • we'll be changing the format for keys, we'll be using our own, self describing wrapper format (like multihash). but yes, we'll allow ASN.1 as we'll have to for compatibility.
  • the X.509 stuff is just way too complicated for most of IPFS use case. as i mentioned, we originally intended to work on a secure channel implementation and submit it to the crypto community to be analyzed. but agree with you though that until that happens, we should use something well-vetted.

How about this as a path forward:

  • we define our key format, etc. (we also want to allow users to provide their own keys, like pgp keys)
  • we figure out our PKI things -- see the very, very early https://github.com/ipfs/specs/tree/master/keychain thing we're making. (basically content addressed PKI with all the crypto artifacts floating in IPFS)
  • we figure out how to make this work nicely with TLS
  • we switch from this thing to TLS/TCP instead.

Another thing left to figure out:

  • should the encrypted channel be part of a multiaddr, or just be selectable via multistream.
    • argument for multiaddr: different transports will obviate some, like QUIC includes DTLS, CurveCP includes reliability. /ip4/1.2.3.4/udp/1234/quic and /ip4/1.2.3.4/udp/1234/curvecp))
    • argument for multiaddr: can inspect the address and discard all addrs without an encryption channel, or those that use undesired encryption channels. (allowing nodes to not even connect to old, unsupported nodes)
    • argument for multistream: allows different encrypted transports to be used over one transport without an additional multiaddr. (could still do this with multiaddr by specifiying multiauth as a placeholder multiaddr protocol or something, e.g. /ip4/1.2.3.4/tcp/1234/multiauth could provide TLS and some other protocol).

@jbenet
Copy link
Member

jbenet commented Sep 19, 2015

cc @diasdavid

@daviddias daviddias mentioned this issue Oct 1, 2015
@jbenet
Copy link
Member

jbenet commented Nov 22, 2015

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
Copy link

ghost commented Nov 22, 2015

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
Copy link
Member

jbenet commented Nov 22, 2015

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
Copy link

ghost commented Nov 22, 2015

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
Copy link

ekr commented Jun 4, 2016

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:

  • RFC 7250 permits raw keys instead of certs with TLS
  • Mint (https://github.com/bifurcation/mint) is a lightweight TLS 1.3-only stack written in Go but matching the GoLang TLS API. It doesn't support RFC 7250 but easily could be made to, I suspect.

[Edited to remove misattribution of the original objections]

@jbenet
Copy link
Member

jbenet commented Jun 4, 2016

@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
Copy link
Member

jbenet commented Jun 4, 2016

@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
Copy link

ekr commented Jun 4, 2016

@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
Copy link
Member

jbenet commented Jun 4, 2016

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. ❤️ 🔒 ❤️ 🔒 ❤️ 🔒 ❤️ 🔒 ❤️ 🔒 ❤️ 🔒 ❤️ 🔒 ❤️ 🔒 ❤️ 🔒 ❤️ 🔒

@dominictarr
Copy link

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
Copy link
Member

Kubuxu commented Jun 9, 2016

@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
Copy link

@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
Copy link
Member

Kubuxu commented Jun 9, 2016

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

@troyronda
Copy link

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

@jbenet
Copy link
Member

jbenet commented Aug 15, 2016

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.

  • make TLS transports in libp2p
    • adding TLS 1.2 transports to go-libp2p
    • adding TLS 1.2 transports to js-libp2p
    • adding TLS 1.3 transports to go-libp2p
    • adding TLS 1.3 transports to js-libp2p
  • support TLS 1.2 and 1.3 in ipfs
    • adding TLS 1.2 and 1.3 transports to go-ipfs (1st layer of multistream)
    • adding TLS 1.2 and 1.3 transports to js-ipfs (1st layer of multistream)

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
Copy link

alikic commented Sep 12, 2016

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
Copy link
Member

@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
Copy link
Member

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
Copy link
Member

jbenet commented Sep 12, 2016

@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.

@daviddias daviddias removed the libp2p label May 5, 2018
@danieldjewell
Copy link

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:

  • It's 2019. There is, in my not so humble opinion, really absolutely zero reason that every protocol/communication/etc. shouldn't make use of strong cryptography. (Okay, there are probably a few notable exceptions - mainly stemming from resource constrained systems ... but even then, there are Arduino libraries that can do RSA/AES/TLS ... might be slow, but eh.) Sure: in the past, before the days of AES CPU instructions (think SSL accelerator PCI card), the computational cost of cryptography was high - not today.
  • There should not be even an option for plaintext - one cannot rely on users to properly configure encryption: it must work out-of-the-box. Even providing users the mere option of customizing settings can open up security risks. (e.g. purposefully misconfiguring a server to use weak/low-grade encryption that is flawed or easily broken)
  • The lack of progress on this issue is troubling to me. How big of a priority is this to the team?

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
Copy link
Member

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.

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

No branches or pull requests