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

PeerIDs and QUIC #37

Closed
Stebalien opened this issue Oct 27, 2017 · 7 comments
Closed

PeerIDs and QUIC #37

Stebalien opened this issue Oct 27, 2017 · 7 comments
Assignees

Comments

@Stebalien
Copy link
Member

Question: Given that QUIC has built-in crypto, how should we associate PeerIDs with QUIC connections.

Our options are:

  1. Do it ourselves. That is, establish the connection and then perform an additional handshake to authenticate it. Nobody likes this option.
  2. Use our peer keys as our QUIC keys. This is reasonably simple and the closest to secio.
  3. Given that, as far as I know, TLS 1.3 will require that all keys have certificates, we could generate ephemeral keys for QUIC and then sign them with our peer key. That is, there must be a certificate chain from the peer key to the QUIC key. This would allow us to (a) keep our key offline and (b) have interesting identity structures (may, eventually, tie in with DIDs).

@whyrusleeping @Kubuxu @lgierth @marten-seemann

@marten-seemann
Copy link
Contributor

marten-seemann commented Oct 27, 2017

Option 3 has the advantage that it's usually hard (impossible?) to get the peer's public key exported from the Go TLS implementation (and also from mint, the TLS 1.3 implementation I'm using for QUIC). The certificate (chain) would be easily accessible via the tls.ConnectionState.

@marten-seemann
Copy link
Contributor

I implemented option 3 using TLS 1.2 as a proof of concept: https://gist.github.com/marten-seemann/33482be37e31dc8288c53af0b2abf13a. You can run this gist, it will create a server instance and connect to it with a client, each peer verifying the other's identity.

For this PoC, I implemented peers from scratch (and didn't use go-libp2p-peer and go-libp2p-crypto), because I need access to raw ECDSA keys, which the libp2p libs currently don't provide.

The handshake works as follows:

  1. Every peer has a public / private key pair (ECDSA here, but could be RSA as well). The peer ID is derived from the public key (in this PoC by taking the SHA256 hash of the public key).
  2. The peer uses its key pair to create a (self-signed) TLS certificate. This cert can be valid for a week or so, making it possible to run a node without keeping the private key on the same machine.
  3. When starting a new server / client, the node generates an ephemeral key, which is signed by the cert generated in 2.

Note that for the sake of simplicity, in my PoC, I'm using a global self-signed CA certificate to sign the peer's certificate. This cert is shared by client and server and added to the root CA pool. The only reason for doing this is such that I can the Go standard library certificate verification. In IPFS, we probably don't want to hardcode a CA cert into every node. That means we will have to do the cert chain verification manually, instead of relying on the standard library doing this for us (this is not too hard: parse the certificates, check that the chain is correctly signed, and check a few metadata cert fields, e.g. the expiry dates). I'll be happy to update the code if we decide to move forward with this.

Authenticating a peer in that scheme is straightforward. The peers dial a TLS connection, and once the handshake completes, the verified certificate chain can be obtained from the TLS connection state. The peer then looks at the certificate in the chain that was created using the remote peer's public / private key pair, and checks that the hash of the public key matches the peer ID.

I'm hoping to get feedback about this from as many people as possible. Tagging @jbenet, @Stebalien, @whyrusleeping, @Kubuxu, @diasdavid, @lgierth here (please tag anyone I've forgotten here as well). This handshake might be terribly broken. My background is not in crypto engineering, so I don't trust it at all at this moment, but I hope that this is a good starting point for a thorough analysis and discussion.

@Kubuxu Kubuxu self-assigned this Nov 9, 2017
@marten-seemann
Copy link
Contributor

@jbenet, @Stebalien, @whyrusleeping, @Kubuxu, @diasdavid, @lgierth: Any feedback?

@Stebalien
Copy link
Member Author

Sorry, I thought I responded to this ages ago. LGTM as long as we don't expose the connection until we've checked the signatures.

In IPFS, we probably don't want to hardcode a CA cert into every node. That means we will have to do the cert chain verification manually, instead of relying on the standard library doing this for us (this is not too hard: parse the certificates, check that the chain is correctly signed, and check a few metadata cert fields, e.g. the expiry dates).

Agreed.


Also, in the certificate generated by the peer ID, we should probably encode some statement to the effect: "this (ephemeral) key may be used to authenticate connections to peer $self". That way, we can extend this in the future to add support for, e.g., delegation. Unfortunately, I'm not familiar enough with x509 to know where this information should go.

@ghost
Copy link

ghost commented Nov 25, 2017

Option 3 sounds good to me!

Will the setup with TLS 1.3 be the same as you described above? I'm thinking there's not much need for TLS 1.2 in a new system.

Otherwise I think this LGTM 👍 :)

@mxinden
Copy link
Member

mxinden commented Mar 26, 2021

As far as I can tell both the discussion and the Golang implementation have settled on option (3), thus I am closing here. If I am not mistaken a libp2p QUIC specification is yet to be written.

@mxinden mxinden closed this as completed Mar 26, 2021
@MarcoPolo
Copy link
Contributor

For posterity, you should use the peer authentication scheme in the libp2p spec to tie a peer id to a QUIC connection.

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

5 participants