Closed willglynn closed 5 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?
( 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 ....
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.
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.
You're right in many counts. a few notes:
How about this as a path forward:
Another thing left to figure out:
/ip4/1.2.3.4/udp/1234/quic
and /ip4/1.2.3.4/udp/1234/curvecp
))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).cc @diasdavid
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
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.
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} ?
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.
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]
@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.
@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 :]
@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.
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:
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...
@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.
@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.
The cjdns is still evolving. We have started a http://fc00.io/ and are currently trying to specout cjdns protocol.
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).
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.
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?
@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.
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
).
@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.
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.
This is an ancient issue.
protocol/network#Encryption:
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.)