Skip to content
This repository has been archived by the owner on May 26, 2022. It is now read-only.

only use a single certificate [do not merge] #37

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions conn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ var _ = Describe("Connection", func() {

// modify the cert chain such that verificiation will fail
invalidateCertChain := func(tlsConf *tls.Config) {
tlsConf.Certificates[0].Certificate = [][]byte{tlsConf.Certificates[0].Certificate[0]}
key, err := rsa.GenerateKey(rand.Reader, 1024)
Expect(err).ToNot(HaveOccurred())
tlsConf.Certificates[0].PrivateKey = key
}

BeforeEach(func() {
Expand Down Expand Up @@ -147,8 +149,8 @@ var _ = Describe("Connection", func() {
serverAddr, serverConnChan := runServer(serverTransport, "/ip4/127.0.0.1/udp/0/quic")

clientTransport, err := NewTransport(clientKey)
invalidateCertChain(clientTransport.(*transport).tlsConf)
Expect(err).ToNot(HaveOccurred())
invalidateCertChain(clientTransport.(*transport).tlsConf)
conn, err := clientTransport.Dial(context.Background(), serverAddr, serverID)
Expect(err).ToNot(HaveOccurred())
Eventually(func() bool { return conn.IsClosed() }).Should(BeTrue())
Expand All @@ -157,15 +159,15 @@ var _ = Describe("Connection", func() {

It("fails if the server presents an invalid cert chain", func() {
serverTransport, err := NewTransport(serverKey)
invalidateCertChain(serverTransport.(*transport).tlsConf)
Expect(err).ToNot(HaveOccurred())
invalidateCertChain(serverTransport.(*transport).tlsConf)
serverAddr, serverConnChan := runServer(serverTransport, "/ip4/127.0.0.1/udp/0/quic")

clientTransport, err := NewTransport(clientKey)
Expect(err).ToNot(HaveOccurred())
_, err = clientTransport.Dial(context.Background(), serverAddr, serverID)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("TLS handshake error: bad certificate"))
Expect(err.Error()).To(ContainSubstring("TLS handshake error"))
Consistently(serverConnChan).ShouldNot(Receive())
})

Expand All @@ -176,8 +178,8 @@ var _ = Describe("Connection", func() {

// first dial with an invalid cert chain
clientTransport1, err := NewTransport(clientKey)
invalidateCertChain(clientTransport1.(*transport).tlsConf)
Expect(err).ToNot(HaveOccurred())
invalidateCertChain(clientTransport1.(*transport).tlsConf)
_, err = clientTransport1.Dial(context.Background(), serverAddr, serverID)
Expect(err).ToNot(HaveOccurred())
Consistently(serverConnChan).ShouldNot(Receive())
Expand Down
47 changes: 11 additions & 36 deletions crypto.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package libp2pquic

import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/tls"
"crypto/x509"
Expand All @@ -21,29 +19,7 @@ const hostname = "quic.ipfs"
const certValidityPeriod = 180 * 24 * time.Hour
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might as well just make this infinite, at this point.


func generateConfig(privKey ic.PrivKey) (*tls.Config, error) {
key, hostCert, err := keyToCertificate(privKey)
if err != nil {
return nil, err
}
// The ephemeral key used just for a couple of connections (or a limited time).
ephemeralKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
return nil, err
}
// Sign the ephemeral key using the host key.
// This is the only time that the host's private key of the peer is needed.
// Note that this step could be done asynchronously, such that a running node doesn't need access its private key at all.
certTemplate := &x509.Certificate{
DNSNames: []string{hostname},
SerialNumber: big.NewInt(1),
NotBefore: time.Now().Add(-24 * time.Hour),
NotAfter: time.Now().Add(certValidityPeriod),
}
certDER, err := x509.CreateCertificate(rand.Reader, certTemplate, hostCert, ephemeralKey.Public(), key)
if err != nil {
return nil, err
}
cert, err := x509.ParseCertificate(certDER)
key, cert, err := keyToCertificate(privKey)
if err != nil {
return nil, err
}
Expand All @@ -52,22 +28,22 @@ func generateConfig(privKey ic.PrivKey) (*tls.Config, error) {
InsecureSkipVerify: true, // This is not insecure here. We will verify the cert chain ourselves.
ClientAuth: tls.RequireAnyClientCert,
Certificates: []tls.Certificate{{
Certificate: [][]byte{cert.Raw, hostCert.Raw},
PrivateKey: ephemeralKey,
Certificate: [][]byte{cert.Raw},
PrivateKey: key,
}},
}, nil
}

func getRemotePubKey(chain []*x509.Certificate) (ic.PubKey, error) {
if len(chain) != 2 {
return nil, errors.New("expected 2 certificates in the chain")
if len(chain) != 1 {
return nil, errors.New("expected one certificates in the chain")
}
pool := x509.NewCertPool()
pool.AddCert(chain[1])
pool.AddCert(chain[0])
if _, err := chain[0].Verify(x509.VerifyOptions{Roots: pool}); err != nil {
return nil, err
}
remotePubKey, err := x509.MarshalPKIXPublicKey(chain[1].PublicKey)
remotePubKey, err := x509.MarshalPKIXPublicKey(chain[0].PublicKey)
if err != nil {
return nil, err
}
Expand All @@ -80,11 +56,10 @@ func keyToCertificate(sk ic.PrivKey) (interface{}, *x509.Certificate, error) {
return nil, nil, err
}
tmpl := &x509.Certificate{
SerialNumber: sn,
NotBefore: time.Now().Add(-24 * time.Hour),
NotAfter: time.Now().Add(certValidityPeriod),
IsCA: true,
BasicConstraintsValid: true,
SerialNumber: sn,
NotBefore: time.Now().Add(-24 * time.Hour),
NotAfter: time.Now().Add(certValidityPeriod),
DNSNames: []string{hostname},
}

var publicKey, privateKey interface{}
Expand Down