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
go:
- "1.10.x"
- "1.11.x"
- "1.12rc1"
# first part of the GOARCH workaround
# 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) {
return nil, err
}
return &tls.Config{
MinVersion: tls.VersionTLS13,
InsecureSkipVerify: true, // This is not insecure here. We will verify the cert chain ourselves.
ClientAuth: tls.RequireAnyClientCert,
Certificates: []tls.Certificate{{
......
......@@ -4,12 +4,19 @@ import (
"context"
"crypto/tls"
"net"
"os"
cs "github.com/libp2p/go-conn-security"
ci "github.com/libp2p/go-libp2p-crypto"
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)
const ID = "/tls/1.0.0"
......@@ -43,32 +50,38 @@ var _ cs.Transport = &Transport{}
// SecureInbound runs the TLS handshake as a server.
func (t *Transport) SecureInbound(ctx context.Context, insecure net.Conn) (cs.Conn, error) {
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.
// 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) {
cl := tls.Client(insecure, t.identity.ConfigForPeer(p))
return t.handshake(ctx, insecure, cl)
return t.handshake(ctx, cl)
}
func (t *Transport) handshake(
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,
func (t *Transport) handshake(ctx context.Context, tlsConn *tls.Conn,
) (cs.Conn, error) {
// There's no way to pass a context to tls.Conn.Handshake().
// See https://github.com/golang/go/issues/18482.
// Close the connection instead.
select {
case <-ctx.Done():
tlsConn.Close()
default:
}
done := make(chan struct{})
defer close(done)
go func() {
select {
case <-done:
case <-ctx.Done():
insecure.Close()
tlsConn.Close()
}
}()
......
......@@ -26,18 +26,19 @@ var _ = Describe("Transport", func() {
createPeer := func() (peer.ID, ic.PrivKey) {
var priv ic.PrivKey
if mrand.Int()%2 == 0 {
fmt.Fprintln(GinkgoWriter, " using an ECDSA key")
fmt.Fprintf(GinkgoWriter, " using an ECDSA key: ")
var err error
priv, _, err = ic.GenerateECDSAKeyPair(rand.Reader)
Expect(err).ToNot(HaveOccurred())
} else {
fmt.Fprintln(GinkgoWriter, " using an RSA key")
fmt.Fprintf(GinkgoWriter, " using an RSA key: ")
var err error
priv, _, err = ic.GenerateRSAKeyPair(1024, rand.Reader)
Expect(err).ToNot(HaveOccurred())
}
id, err := peer.IDFromPrivateKey(priv)
Expect(err).ToNot(HaveOccurred())
fmt.Fprintln(GinkgoWriter, id.Pretty())
return id, priv
}
......@@ -65,7 +66,7 @@ var _ = Describe("Transport", func() {
Expect(err).ToNot(HaveOccurred())
identity.Config.Certificates[0].PrivateKey = key
case *ecdsa.PrivateKey:
key, err := ecdsa.GenerateKey(elliptic.P224(), rand.Reader)
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
Expect(err).ToNot(HaveOccurred())
identity.Config.Certificates[0].PrivateKey = key
default:
......@@ -194,17 +195,14 @@ var _ = Describe("Transport", func() {
go func() {
defer GinkgoRecover()
_, err := serverTransport.SecureInbound(context.Background(), serverInsecureConn)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(Or(
ContainSubstring("crypto/rsa: verification error"),
ContainSubstring("ECDSA verification failure"),
))
Expect(err).To(MatchError("tls: invalid certificate signature"))
close(done)
}()
_, err = clientTransport.SecureOutbound(context.Background(), clientInsecureConn, serverID)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("tls: bad certificate"))
conn, err := clientTransport.SecureOutbound(context.Background(), clientInsecureConn, serverID)
Expect(err).ToNot(HaveOccurred())
_, err = conn.Read([]byte{0})
Expect(err).To(MatchError("remote error: tls: error decrypting message"))
Eventually(done).Should(BeClosed())
})
......@@ -222,16 +220,12 @@ var _ = Describe("Transport", func() {
defer GinkgoRecover()
_, err := serverTransport.SecureInbound(context.Background(), serverInsecureConn)
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)
}()
_, err = clientTransport.SecureOutbound(context.Background(), clientInsecureConn, serverID)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(Or(
ContainSubstring("crypto/rsa: verification error"),
ContainSubstring("ECDSA verification failure"),
))
Expect(err).To(MatchError("tls: invalid certificate signature"))
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