Unverified Commit 3a88d269 authored by Marten Seemann's avatar Marten Seemann Committed by GitHub

Merge pull request #11 from libp2p/tls13

use TLS 1.3
parents 56882797 1018ec94
language: go language: go
go: go:
- "1.10.x" - "1.12rc1"
- "1.11.x"
# first part of the GOARCH workaround # first part of the GOARCH workaround
# setting the GOARCH directly doesn't work, since the value will be overwritten later # setting the GOARCH directly doesn't work, since the value will be overwritten later
......
...@@ -72,6 +72,7 @@ func generateConfig(privKey ic.PrivKey) (*tls.Config, error) { ...@@ -72,6 +72,7 @@ func generateConfig(privKey ic.PrivKey) (*tls.Config, error) {
return nil, err return nil, err
} }
return &tls.Config{ return &tls.Config{
MinVersion: tls.VersionTLS13,
InsecureSkipVerify: true, // This is not insecure here. We will verify the cert chain ourselves. InsecureSkipVerify: true, // This is not insecure here. We will verify the cert chain ourselves.
ClientAuth: tls.RequireAnyClientCert, ClientAuth: tls.RequireAnyClientCert,
Certificates: []tls.Certificate{{ Certificates: []tls.Certificate{{
......
...@@ -4,12 +4,19 @@ import ( ...@@ -4,12 +4,19 @@ import (
"context" "context"
"crypto/tls" "crypto/tls"
"net" "net"
"os"
cs "github.com/libp2p/go-conn-security" cs "github.com/libp2p/go-conn-security"
ci "github.com/libp2p/go-libp2p-crypto" ci "github.com/libp2p/go-libp2p-crypto"
peer "github.com/libp2p/go-libp2p-peer" peer "github.com/libp2p/go-libp2p-peer"
) )
// TLS 1.3 is opt-in in Go 1.12
// Activate it by setting the tls13 GODEBUG flag.
func init() {
os.Setenv("GODEBUG", os.Getenv("GODEBUG")+",tls13=1")
}
// ID is the protocol ID (used when negotiating with multistream) // ID is the protocol ID (used when negotiating with multistream)
const ID = "/tls/1.0.0" const ID = "/tls/1.0.0"
...@@ -43,32 +50,38 @@ var _ cs.Transport = &Transport{} ...@@ -43,32 +50,38 @@ var _ cs.Transport = &Transport{}
// SecureInbound runs the TLS handshake as a server. // SecureInbound runs the TLS handshake as a server.
func (t *Transport) SecureInbound(ctx context.Context, insecure net.Conn) (cs.Conn, error) { func (t *Transport) SecureInbound(ctx context.Context, insecure net.Conn) (cs.Conn, error) {
serv := tls.Server(insecure, t.identity.Config) serv := tls.Server(insecure, t.identity.Config)
return t.handshake(ctx, insecure, serv) return t.handshake(ctx, serv)
} }
// SecureOutbound runs the TLS handshake as a client. // SecureOutbound runs the TLS handshake as a client.
// Note that SecureOutbound will not return an error if the server doesn't
// accept the certificate. This is due to the fact that in TLS 1.3, the client
// sends its certificate and the ClientFinished in the same flight, and can send
// application data immediately afterwards.
// If the handshake fails, the server will close the connection. The client will
// notice this after 1 RTT when calling Read.
func (t *Transport) SecureOutbound(ctx context.Context, insecure net.Conn, p peer.ID) (cs.Conn, error) { func (t *Transport) SecureOutbound(ctx context.Context, insecure net.Conn, p peer.ID) (cs.Conn, error) {
cl := tls.Client(insecure, t.identity.ConfigForPeer(p)) cl := tls.Client(insecure, t.identity.ConfigForPeer(p))
return t.handshake(ctx, insecure, cl) return t.handshake(ctx, cl)
} }
func (t *Transport) handshake( func (t *Transport) handshake(ctx context.Context, tlsConn *tls.Conn,
ctx context.Context,
// in Go 1.10, we need to close the underlying net.Conn
// in Go 1.11 this was fixed, and tls.Conn.Close() works as well
insecure net.Conn,
tlsConn *tls.Conn,
) (cs.Conn, error) { ) (cs.Conn, error) {
// There's no way to pass a context to tls.Conn.Handshake(). // There's no way to pass a context to tls.Conn.Handshake().
// See https://github.com/golang/go/issues/18482. // See https://github.com/golang/go/issues/18482.
// Close the connection instead. // Close the connection instead.
select {
case <-ctx.Done():
tlsConn.Close()
default:
}
done := make(chan struct{}) done := make(chan struct{})
defer close(done) defer close(done)
go func() { go func() {
select { select {
case <-done: case <-done:
case <-ctx.Done(): case <-ctx.Done():
insecure.Close() tlsConn.Close()
} }
}() }()
......
...@@ -26,18 +26,19 @@ var _ = Describe("Transport", func() { ...@@ -26,18 +26,19 @@ var _ = Describe("Transport", func() {
createPeer := func() (peer.ID, ic.PrivKey) { createPeer := func() (peer.ID, ic.PrivKey) {
var priv ic.PrivKey var priv ic.PrivKey
if mrand.Int()%2 == 0 { if mrand.Int()%2 == 0 {
fmt.Fprintln(GinkgoWriter, " using an ECDSA key") fmt.Fprintf(GinkgoWriter, " using an ECDSA key: ")
var err error var err error
priv, _, err = ic.GenerateECDSAKeyPair(rand.Reader) priv, _, err = ic.GenerateECDSAKeyPair(rand.Reader)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
} else { } else {
fmt.Fprintln(GinkgoWriter, " using an RSA key") fmt.Fprintf(GinkgoWriter, " using an RSA key: ")
var err error var err error
priv, _, err = ic.GenerateRSAKeyPair(1024, rand.Reader) priv, _, err = ic.GenerateRSAKeyPair(1024, rand.Reader)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
} }
id, err := peer.IDFromPrivateKey(priv) id, err := peer.IDFromPrivateKey(priv)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
fmt.Fprintln(GinkgoWriter, id.Pretty())
return id, priv return id, priv
} }
...@@ -65,7 +66,7 @@ var _ = Describe("Transport", func() { ...@@ -65,7 +66,7 @@ var _ = Describe("Transport", func() {
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
identity.Config.Certificates[0].PrivateKey = key identity.Config.Certificates[0].PrivateKey = key
case *ecdsa.PrivateKey: case *ecdsa.PrivateKey:
key, err := ecdsa.GenerateKey(elliptic.P224(), rand.Reader) key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
identity.Config.Certificates[0].PrivateKey = key identity.Config.Certificates[0].PrivateKey = key
default: default:
...@@ -194,17 +195,14 @@ var _ = Describe("Transport", func() { ...@@ -194,17 +195,14 @@ var _ = Describe("Transport", func() {
go func() { go func() {
defer GinkgoRecover() defer GinkgoRecover()
_, err := serverTransport.SecureInbound(context.Background(), serverInsecureConn) _, err := serverTransport.SecureInbound(context.Background(), serverInsecureConn)
Expect(err).To(HaveOccurred()) Expect(err).To(MatchError("tls: invalid certificate signature"))
Expect(err.Error()).To(Or(
ContainSubstring("crypto/rsa: verification error"),
ContainSubstring("ECDSA verification failure"),
))
close(done) close(done)
}() }()
_, err = clientTransport.SecureOutbound(context.Background(), clientInsecureConn, serverID) conn, err := clientTransport.SecureOutbound(context.Background(), clientInsecureConn, serverID)
Expect(err).To(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("tls: bad certificate")) _, err = conn.Read([]byte{0})
Expect(err).To(MatchError("remote error: tls: error decrypting message"))
Eventually(done).Should(BeClosed()) Eventually(done).Should(BeClosed())
}) })
...@@ -222,16 +220,12 @@ var _ = Describe("Transport", func() { ...@@ -222,16 +220,12 @@ var _ = Describe("Transport", func() {
defer GinkgoRecover() defer GinkgoRecover()
_, err := serverTransport.SecureInbound(context.Background(), serverInsecureConn) _, err := serverTransport.SecureInbound(context.Background(), serverInsecureConn)
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
// TLS returns a weird error here: "remote error: tls: unexpected message" Expect(err.Error()).To(ContainSubstring("remote error: tls:"))
close(done) close(done)
}() }()
_, err = clientTransport.SecureOutbound(context.Background(), clientInsecureConn, serverID) _, err = clientTransport.SecureOutbound(context.Background(), clientInsecureConn, serverID)
Expect(err).To(HaveOccurred()) Expect(err).To(MatchError("tls: invalid certificate signature"))
Expect(err.Error()).To(Or(
ContainSubstring("crypto/rsa: verification error"),
ContainSubstring("ECDSA verification failure"),
))
Eventually(done).Should(BeClosed()) Eventually(done).Should(BeClosed())
}) })
}) })
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment