agent: add agent server support for ed25519 keys.

the client library already supports them.

Fixes golang/go#16096

Change-Id: Iaa117ee31f706301e8b24c2775f5a604ef005440
Reviewed-on: https://go-review.googlesource.com/24285
Reviewed-by: Adam Langley <agl@golang.org>
diff --git a/ssh/agent/client.go b/ssh/agent/client.go
index a75668d..ecfd7c5 100644
--- a/ssh/agent/client.go
+++ b/ssh/agent/client.go
@@ -594,12 +594,12 @@
 			Comments:    comment,
 			Constraints: constraints,
 		})
-	case ed25519.PrivateKey:
+	case *ed25519.PrivateKey:
 		req = ssh.Marshal(ed25519CertMsg{
 			Type:        cert.Type(),
 			CertBytes:   cert.Marshal(),
-			Pub:         []byte(k)[32:],
-			Priv:        []byte(k),
+			Pub:         []byte(*k)[32:],
+			Priv:        []byte(*k),
 			Comments:    comment,
 			Constraints: constraints,
 		})
diff --git a/ssh/agent/server.go b/ssh/agent/server.go
index c562fa6..092fd8f 100644
--- a/ssh/agent/server.go
+++ b/ssh/agent/server.go
@@ -16,6 +16,7 @@
 	"log"
 	"math/big"
 
+	"golang.org/x/crypto/ed25519"
 	"golang.org/x/crypto/ssh"
 )
 
@@ -175,6 +176,15 @@
 	return &AddedKey{PrivateKey: priv, Comment: k.Comments}, nil
 }
 
+func parseEd25519Key(req []byte) (*AddedKey, error) {
+	var k ed25519KeyMsg
+	if err := ssh.Unmarshal(req, &k); err != nil {
+		return nil, err
+	}
+	priv := ed25519.PrivateKey(k.Priv)
+	return &AddedKey{PrivateKey: &priv, Comment: k.Comments}, nil
+}
+
 func parseDSAKey(req []byte) (*AddedKey, error) {
 	var k dsaKeyMsg
 	if err := ssh.Unmarshal(req, &k); err != nil {
@@ -219,6 +229,23 @@
 	return priv, nil
 }
 
+func parseEd25519Cert(req []byte) (*AddedKey, error) {
+	var k ed25519CertMsg
+	if err := ssh.Unmarshal(req, &k); err != nil {
+		return nil, err
+	}
+	pubKey, err := ssh.ParsePublicKey(k.CertBytes)
+	if err != nil {
+		return nil, err
+	}
+	priv := ed25519.PrivateKey(k.Priv)
+	cert, ok := pubKey.(*ssh.Certificate)
+	if !ok {
+		return nil, errors.New("agent: bad ED25519 certificate")
+	}
+	return &AddedKey{PrivateKey: &priv, Certificate: cert, Comment: k.Comments}, nil
+}
+
 func parseECDSAKey(req []byte) (*AddedKey, error) {
 	var k ecdsaKeyMsg
 	if err := ssh.Unmarshal(req, &k); err != nil {
@@ -367,12 +394,16 @@
 		addedKey, err = parseDSAKey(req)
 	case ssh.KeyAlgoECDSA256, ssh.KeyAlgoECDSA384, ssh.KeyAlgoECDSA521:
 		addedKey, err = parseECDSACert(req)
+	case ssh.KeyAlgoED25519:
+		addedKey, err = parseEd25519Key(req)
 	case ssh.CertAlgoRSAv01:
 		addedKey, err = parseRSACert(req)
 	case ssh.CertAlgoDSAv01:
 		addedKey, err = parseDSACert(req)
 	case ssh.CertAlgoECDSA256v01, ssh.CertAlgoECDSA384v01, ssh.CertAlgoECDSA521v01:
 		addedKey, err = parseECDSACert(req)
+	case ssh.CertAlgoED25519v01:
+		addedKey, err = parseEd25519Cert(req)
 	default:
 		return fmt.Errorf("agent: not implemented: %q", record.Type)
 	}
diff --git a/ssh/agent/server_test.go b/ssh/agent/server_test.go
index c324d6c..b5e92a6 100644
--- a/ssh/agent/server_test.go
+++ b/ssh/agent/server_test.go
@@ -153,6 +153,21 @@
 	}
 }
 
+func addCertToAgentSock(key crypto.PrivateKey, cert *ssh.Certificate) error {
+	a, b, err := netPipe()
+	if err != nil {
+		return err
+	}
+	agentServer := NewKeyring()
+	go ServeAgent(agentServer, a)
+
+	agentClient := NewClient(b)
+	if err := agentClient.Add(AddedKey{PrivateKey: key, Certificate: cert}); err != nil {
+		return fmt.Errorf("add: %v", err)
+	}
+	return verifyKey(agentClient)
+}
+
 func addCertToAgent(key crypto.PrivateKey, cert *ssh.Certificate) error {
 	sshAgent := NewKeyring()
 	if err := sshAgent.Add(AddedKey{PrivateKey: key, Certificate: cert}); err != nil {
@@ -182,5 +197,8 @@
 		if err := addCertToAgent(testPrivateKeys[keyType], cert); err != nil {
 			t.Fatalf("%v", err)
 		}
+		if err := addCertToAgentSock(testPrivateKeys[keyType], cert); err != nil {
+			t.Fatalf("%v", err)
+		}
 	}
 }