From 955b8056cb4ace524eac46ca500a07cf64a43445 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Fri, 11 Jan 2019 13:51:35 +0700 Subject: [PATCH] add support for ECDSA keys --- p2p/security/tls/crypto.go | 19 ++++++++- p2p/security/tls/libp2p_tls_suite_test.go | 5 +++ p2p/security/tls/transport_test.go | 49 ++++++++++++++++++----- 3 files changed, 61 insertions(+), 12 deletions(-) diff --git a/p2p/security/tls/crypto.go b/p2p/security/tls/crypto.go index 1a6812a18e..583fe39c14 100644 --- a/p2p/security/tls/crypto.go +++ b/p2p/security/tls/crypto.go @@ -5,6 +5,7 @@ import ( "crypto/tls" "crypto/x509" "errors" + "fmt" "math/big" "time" @@ -93,7 +94,14 @@ func getRemotePubKey(chain []*x509.Certificate) (ic.PubKey, error) { if err != nil { return nil, err } - return ic.UnmarshalRsaPublicKey(remotePubKey) + switch chain[0].PublicKeyAlgorithm { + case x509.RSA: + return ic.UnmarshalRsaPublicKey(remotePubKey) + case x509.ECDSA: + return ic.UnmarshalECDSAPublicKey(remotePubKey) + default: + return nil, fmt.Errorf("unexpected public key algorithm: %d", chain[0].PublicKeyAlgorithm) + } } func keyToCertificate(sk ic.PrivKey) (interface{}, *x509.Certificate, error) { @@ -124,7 +132,14 @@ func keyToCertificate(sk ic.PrivKey) (interface{}, *x509.Certificate, error) { } publicKey = &k.PublicKey privateKey = k - // TODO: add support for ECDSA + case pb.KeyType_ECDSA: + k, err := x509.ParseECPrivateKey(pbmes.GetData()) + if err != nil { + return nil, nil, err + } + publicKey = &k.PublicKey + privateKey = k + // TODO: add support for Ed25519 default: return nil, nil, errors.New("unsupported key type for TLS") } diff --git a/p2p/security/tls/libp2p_tls_suite_test.go b/p2p/security/tls/libp2p_tls_suite_test.go index 3303ed3030..e0e6785862 100644 --- a/p2p/security/tls/libp2p_tls_suite_test.go +++ b/p2p/security/tls/libp2p_tls_suite_test.go @@ -1,6 +1,7 @@ package libp2ptls import ( + mrand "math/rand" "testing" . "github.com/onsi/ginkgo" @@ -11,3 +12,7 @@ func TestLibp2pTLS(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "libp2p TLS Suite") } + +var _ = BeforeSuite(func() { + mrand.Seed(GinkgoRandomSeed()) +}) diff --git a/p2p/security/tls/transport_test.go b/p2p/security/tls/transport_test.go index bc4d5b3813..d06326d90f 100644 --- a/p2p/security/tls/transport_test.go +++ b/p2p/security/tls/transport_test.go @@ -2,9 +2,12 @@ package libp2ptls import ( "context" + "crypto/ecdsa" + "crypto/elliptic" "crypto/rand" "crypto/rsa" - "crypto/x509" + "fmt" + mrand "math/rand" "net" cs "github.com/libp2p/go-conn-security" @@ -21,10 +24,18 @@ var _ = Describe("Transport", func() { ) createPeer := func() (peer.ID, ic.PrivKey) { - key, err := rsa.GenerateKey(rand.Reader, 1024) - Expect(err).ToNot(HaveOccurred()) - priv, err := ic.UnmarshalRsaPrivateKey(x509.MarshalPKCS1PrivateKey(key)) - Expect(err).ToNot(HaveOccurred()) + var priv ic.PrivKey + if mrand.Int()%2 == 0 { + fmt.Fprintln(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") + var err error + priv, _, err = ic.GenerateRSAKeyPair(1024, rand.Reader) + Expect(err).ToNot(HaveOccurred()) + } id, err := peer.IDFromPrivateKey(priv) Expect(err).ToNot(HaveOccurred()) return id, priv @@ -48,13 +59,24 @@ var _ = Describe("Transport", func() { // modify the cert chain such that verificiation will fail invalidateCertChain := func(identity *Identity) { - key, err := rsa.GenerateKey(rand.Reader, 1024) - Expect(err).ToNot(HaveOccurred()) - identity.Config.Certificates[0].PrivateKey = key + switch identity.Config.Certificates[0].PrivateKey.(type) { + case *rsa.PrivateKey: + key, err := rsa.GenerateKey(rand.Reader, 1024) + Expect(err).ToNot(HaveOccurred()) + identity.Config.Certificates[0].PrivateKey = key + case *ecdsa.PrivateKey: + key, err := ecdsa.GenerateKey(elliptic.P224(), rand.Reader) + Expect(err).ToNot(HaveOccurred()) + identity.Config.Certificates[0].PrivateKey = key + default: + Fail("unexpected private key type") + } } BeforeEach(func() { + fmt.Fprintf(GinkgoWriter, "Initializing a server") serverID, serverKey = createPeer() + fmt.Fprintf(GinkgoWriter, "Initializing a client") clientID, clientKey = createPeer() }) @@ -135,6 +157,7 @@ var _ = Describe("Transport", func() { }) It("fails if the peer ID doesn't match", func() { + fmt.Fprintf(GinkgoWriter, "Creating another peer") thirdPartyID, _ := createPeer() serverTransport, err := New(serverKey) @@ -172,7 +195,10 @@ var _ = Describe("Transport", func() { defer GinkgoRecover() _, err := serverTransport.SecureInbound(context.Background(), serverInsecureConn) Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("crypto/rsa: verification error")) + Expect(err.Error()).To(Or( + ContainSubstring("crypto/rsa: verification error"), + ContainSubstring("ECDSA verification failure"), + )) close(done) }() @@ -202,7 +228,10 @@ var _ = Describe("Transport", func() { _, err = clientTransport.SecureOutbound(context.Background(), clientInsecureConn, serverID) Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("crypto/rsa: verification error")) + Expect(err.Error()).To(Or( + ContainSubstring("crypto/rsa: verification error"), + ContainSubstring("ECDSA verification failure"), + )) Eventually(done).Should(BeClosed()) }) })