ssh: allow adding ed25519 keys to the agent

Fixes golang/go#15701

Change-Id: I561701e38b9d434ef44448bdbcfab203f3c31d99
Reviewed-on: https://go-review.googlesource.com/23141
Reviewed-by: Han-Wen Nienhuys <hanwen@google.com>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
diff --git a/ssh/agent/client.go b/ssh/agent/client.go
index 3f798e7..11d3094 100644
--- a/ssh/agent/client.go
+++ b/ssh/agent/client.go
@@ -25,6 +25,7 @@
 	"math/big"
 	"sync"
 
+	"golang.org/x/crypto/ed25519"
 	"golang.org/x/crypto/ssh"
 )
 
@@ -423,6 +424,14 @@
 	Constraints []byte `ssh:"rest"`
 }
 
+type ed25519KeyMsg struct {
+	Type        string `sshtype:"17|25"`
+	Pub         []byte
+	Priv        []byte
+	Comments    string
+	Constraints []byte `ssh:"rest"`
+}
+
 // Insert adds a private key to the agent.
 func (c *client) insertKey(s interface{}, comment string, constraints []byte) error {
 	var req []byte
@@ -464,6 +473,14 @@
 			Comments:    comment,
 			Constraints: constraints,
 		})
+	case *ed25519.PrivateKey:
+		req = ssh.Marshal(ed25519KeyMsg{
+			Type:        ssh.KeyAlgoED25519,
+			Pub:         []byte(*k)[32:],
+			Priv:        []byte(*k),
+			Comments:    comment,
+			Constraints: constraints,
+		})
 	default:
 		return fmt.Errorf("agent: unsupported key type %T", s)
 	}
@@ -510,6 +527,15 @@
 	Constraints []byte `ssh:"rest"`
 }
 
+type ed25519CertMsg struct {
+	Type        string `sshtype:"17|25"`
+	CertBytes   []byte
+	Pub         []byte
+	Priv        []byte
+	Comments    string
+	Constraints []byte `ssh:"rest"`
+}
+
 // Insert adds a private key to the agent. If a certificate is given,
 // that certificate is added instead as public key.
 func (c *client) Add(key AddedKey) error {
@@ -566,6 +592,14 @@
 			D:         k.D,
 			Comments:  comment,
 		})
+	case ed25519.PrivateKey:
+		req = ssh.Marshal(ed25519CertMsg{
+			Type:      cert.Type(),
+			CertBytes: cert.Marshal(),
+			Pub:       []byte(k)[32:],
+			Priv:      []byte(k),
+			Comments:  comment,
+		})
 	default:
 		return fmt.Errorf("agent: unsupported key type %T", s)
 	}
diff --git a/ssh/agent/client_test.go b/ssh/agent/client_test.go
index ec7198d..51a3e03 100644
--- a/ssh/agent/client_test.go
+++ b/ssh/agent/client_test.go
@@ -139,7 +139,7 @@
 }
 
 func TestAgent(t *testing.T) {
-	for _, keyType := range []string{"rsa", "dsa", "ecdsa"} {
+	for _, keyType := range []string{"rsa", "dsa", "ecdsa", "ed25519"} {
 		testAgent(t, testPrivateKeys[keyType], nil, 0)
 	}
 }