From 77e7ef99c8cadc8ba769c1971a3acc8d7844adb0 Mon Sep 17 00:00:00 2001 From: Hidde Beydals Date: Sat, 17 Apr 2021 00:08:01 +0200 Subject: [PATCH] plumbing: transport/ssh, support more formats in `NewPublicKeys` SSH helper (#298) * Add failing ED25519 encrypted PEM test Signed-off-by: Hidde Beydals * Support more formats in `NewPublicKeys` SSH helper By switching to `ParsePrivateKey` and `ParsePrivateKeyWithPassphrase` from `crypto/ssh`, which has support for RSA (PKCS#1), PKCS#8, DSA (OpenSSL), and ECDSA private keys. Signed-off-by: Hidde Beydals --- plumbing/transport/ssh/auth_method.go | 22 ++++------------------ plumbing/transport/ssh/auth_method_test.go | 7 +++++++ 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/plumbing/transport/ssh/auth_method.go b/plumbing/transport/ssh/auth_method.go index b79a74e41..568ec86ee 100644 --- a/plumbing/transport/ssh/auth_method.go +++ b/plumbing/transport/ssh/auth_method.go @@ -1,8 +1,6 @@ package ssh import ( - "crypto/x509" - "encoding/pem" "errors" "fmt" "io/ioutil" @@ -121,27 +119,15 @@ type PublicKeys struct { // NewPublicKeys returns a PublicKeys from a PEM encoded private key. An // encryption password should be given if the pemBytes contains a password // encrypted PEM block otherwise password should be empty. It supports RSA -// (PKCS#1), DSA (OpenSSL), and ECDSA private keys. +// (PKCS#1), PKCS#8, DSA (OpenSSL), and ECDSA private keys. func NewPublicKeys(user string, pemBytes []byte, password string) (*PublicKeys, error) { - block, _ := pem.Decode(pemBytes) - if block == nil { - return nil, errors.New("invalid PEM data") - } - if x509.IsEncryptedPEMBlock(block) { - key, err := x509.DecryptPEMBlock(block, []byte(password)) - if err != nil { - return nil, err - } - - block = &pem.Block{Type: block.Type, Bytes: key} - pemBytes = pem.EncodeToMemory(block) - } - signer, err := ssh.ParsePrivateKey(pemBytes) + if _, ok := err.(*ssh.PassphraseMissingError); ok { + signer, err = ssh.ParsePrivateKeyWithPassphrase(pemBytes, []byte(password)) + } if err != nil { return nil, err } - return &PublicKeys{User: user, Signer: signer}, nil } diff --git a/plumbing/transport/ssh/auth_method_test.go b/plumbing/transport/ssh/auth_method_test.go index 2cbcded2d..ade344f76 100644 --- a/plumbing/transport/ssh/auth_method_test.go +++ b/plumbing/transport/ssh/auth_method_test.go @@ -145,6 +145,13 @@ func (*SuiteCommon) TestNewPublicKeysWithEncryptedPEM(c *C) { c.Assert(auth, NotNil) } +func (*SuiteCommon) TestNewPublicKeysWithEncryptedEd25519PEM(c *C) { + f := testdata.PEMEncryptedKeys[2] + auth, err := NewPublicKeys("foo", f.PEMBytes, f.EncryptionKey) + c.Assert(err, IsNil) + c.Assert(auth, NotNil) +} + func (*SuiteCommon) TestNewPublicKeysFromFile(c *C) { f, err := ioutil.TempFile("", "ssh-test") c.Assert(err, IsNil)