Commit de3f35a2 authored by Marten Seemann's avatar Marten Seemann
Browse files

verify the server's certificate using tls.Config.VerifyPeerCertificate

Fixes #2.
parent c8b9d442
......@@ -9,4 +9,3 @@ This is an implementation of the [libp2p transport](https://github.com/libp2p/go
## Known limitations
* currently only works with RSA host keys
* [#2](https://github.com/marten-seemann/libp2p-quic-transport/issues/2)
......@@ -80,14 +80,14 @@ var _ = Describe("Connection", func() {
thirdPartyID, err := peer.IDFromPrivateKey(createPeer())
Expect(err).ToNot(HaveOccurred())
serverAddrChan, _ := runServer()
serverAddrChan, serverConnChan := runServer()
clientTransport, err := NewTransport(clientKey)
Expect(err).ToNot(HaveOccurred())
serverAddr := <-serverAddrChan
// dial, but expect the wrong peer ID
_, err = clientTransport.Dial(context.Background(), serverAddr, thirdPartyID)
Expect(err).To(MatchError("peer IDs don't match"))
// TODO(#2): don't accept a connection if the client's peer verification fails
// Consistently(serverConnChan).ShouldNot(Receive())
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("TLS handshake error: bad certificate"))
Consistently(serverConnChan).ShouldNot(Receive())
})
})
......@@ -10,8 +10,6 @@ import (
"math/big"
"time"
"github.com/lucas-clemente/quic-go"
"github.com/gogo/protobuf/proto"
ic "github.com/libp2p/go-libp2p-crypto"
pb "github.com/libp2p/go-libp2p-crypto/pb"
......@@ -20,10 +18,6 @@ import (
// mint certificate selection is broken.
const hostname = "quic.ipfs"
type connectionStater interface {
ConnectionState() quic.ConnectionState
}
// TODO: make this private
func GenerateConfig(privKey ic.PrivKey) (*tls.Config, error) {
key, hostCert, err := keyToCertificate(privKey)
......@@ -63,17 +57,16 @@ func GenerateConfig(privKey ic.PrivKey) (*tls.Config, error) {
}, nil
}
func getRemotePubKey(conn connectionStater) (ic.PubKey, error) {
certChain := conn.ConnectionState().PeerCertificates
if len(certChain) != 2 {
func getRemotePubKey(chain []*x509.Certificate) (ic.PubKey, error) {
if len(chain) != 2 {
return nil, errors.New("expected 2 certificates in the chain")
}
pool := x509.NewCertPool()
pool.AddCert(certChain[1])
if _, err := certChain[0].Verify(x509.VerifyOptions{Roots: pool}); err != nil {
pool.AddCert(chain[1])
if _, err := chain[0].Verify(x509.VerifyOptions{Roots: pool}); err != nil {
return nil, err
}
remotePubKey, err := x509.MarshalPKIXPublicKey(certChain[1].PublicKey)
remotePubKey, err := x509.MarshalPKIXPublicKey(chain[1].PublicKey)
if err != nil {
return nil, err
}
......
......@@ -60,7 +60,7 @@ func (l *listener) Accept() (tpt.Conn, error) {
if err != nil {
return nil, err
}
remotePubKey, err := getRemotePubKey(sess)
remotePubKey, err := getRemotePubKey(sess.ConnectionState().PeerCertificates)
if err != nil {
return nil, err
}
......
......@@ -2,6 +2,7 @@ package libp2pquic
import (
"context"
"crypto/x509"
"errors"
ic "github.com/libp2p/go-libp2p-crypto"
......@@ -45,11 +46,27 @@ func (t *transport) Dial(ctx context.Context, raddr ma.Multiaddr, p peer.ID) (tp
if err != nil {
return nil, err
}
sess, err := quicDialAddr(host, tlsConf, &quic.Config{Versions: []quic.VersionNumber{101}})
if err != nil {
return nil, err
var remotePubKey ic.PubKey
tlsConf.VerifyPeerCertificate = func(rawCerts [][]byte, _ [][]*x509.Certificate) error {
chain := make([]*x509.Certificate, len(rawCerts))
for i := 0; i < len(rawCerts); i++ {
cert, err := x509.ParseCertificate(rawCerts[i])
if err != nil {
return err
}
chain[i] = cert
}
var err error
remotePubKey, err = getRemotePubKey(chain)
if err != nil {
return err
}
if !p.MatchesPublicKey(remotePubKey) {
return errors.New("peer IDs don't match")
}
return nil
}
remotePubKey, err := getRemotePubKey(sess)
sess, err := quicDialAddr(host, tlsConf, &quic.Config{Versions: []quic.VersionNumber{101}})
if err != nil {
return nil, err
}
......@@ -57,11 +74,6 @@ func (t *transport) Dial(ctx context.Context, raddr ma.Multiaddr, p peer.ID) (tp
if err != nil {
return nil, err
}
if !p.MatchesPublicKey(remotePubKey) {
err := errors.New("peer IDs don't match")
sess.Close(err)
return nil, err
}
return &conn{
privKey: t.privKey,
localPeer: t.localPeer,
......
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