go.crypto/ssh: parse DSA private keys too.

R=golang-dev, agl
CC=golang-dev
https://golang.org/cl/13966043
diff --git a/ssh/keys.go b/ssh/keys.go
index 9738694..0c6c6b3 100644
--- a/ssh/keys.go
+++ b/ssh/keys.go
@@ -12,6 +12,7 @@
 	"crypto/elliptic"
 	"crypto/rsa"
 	"crypto/x509"
+	"encoding/asn1"
 	"encoding/base64"
 	"encoding/pem"
 	"errors"
@@ -557,8 +558,8 @@
 	return sshKey, nil
 }
 
-// ParsePublicKey parses a PEM encoded private key. Currently, only
-// PKCS#1, RSA and ECDSA private keys are supported.
+// ParsePublicKey parses a PEM encoded private key. It supports
+// PKCS#1, RSA, DSA and ECDSA private keys.
 func ParsePrivateKey(pemBytes []byte) (Signer, error) {
 	block, _ := pem.Decode(pemBytes)
 	if block == nil {
@@ -579,12 +580,48 @@
 			return nil, err
 		}
 		rawkey = ec
-
-		// TODO(hanwen): find doc for format and implement PEM parsing
-		// for DSA keys.
+	case "DSA PRIVATE KEY":
+		ec, err := parseDSAPrivate(block.Bytes)
+		if err != nil {
+			return nil, err
+		}
+		rawkey = ec
 	default:
 		return nil, fmt.Errorf("ssh: unsupported key type %q", block.Type)
 	}
 
 	return NewSignerFromKey(rawkey)
 }
+
+// parseDSAPrivate parses a DSA key in ASN.1 DER encoding, as
+// documented in the OpenSSL DSA manpage.
+// TODO(hanwen): move this in to crypto/x509 after the Go 1.2 freeze.
+func parseDSAPrivate(p []byte) (*dsa.PrivateKey, error) {
+	k := struct {
+		Version int
+		P       *big.Int
+		Q       *big.Int
+		G       *big.Int
+		Priv    *big.Int
+		Pub     *big.Int
+	}{}
+	rest, err := asn1.Unmarshal(p, &k)
+	if err != nil {
+		return nil, errors.New("ssh: failed to parse DSA key: " + err.Error())
+	}
+	if len(rest) > 0 {
+		return nil, errors.New("ssh: garbage after DSA key")
+	}
+
+	return &dsa.PrivateKey{
+		PublicKey: dsa.PublicKey{
+			Parameters: dsa.Parameters{
+				P: k.P,
+				Q: k.Q,
+				G: k.G,
+			},
+			Y: k.Priv,
+		},
+		X: k.Pub,
+	}, nil
+}
diff --git a/ssh/keys_test.go b/ssh/keys_test.go
index fb3f21e..595fb29 100644
--- a/ssh/keys_test.go
+++ b/ssh/keys_test.go
@@ -132,6 +132,37 @@
 	}
 }
 
+// ssh-keygen -t dsa -f /tmp/idsa.pem
+var dsaPEM = `-----BEGIN DSA PRIVATE KEY-----
+MIIBuwIBAAKBgQD6PDSEyXiI9jfNs97WuM46MSDCYlOqWw80ajN16AohtBncs1YB
+lHk//dQOvCYOsYaE+gNix2jtoRjwXhDsc25/IqQbU1ahb7mB8/rsaILRGIbA5WH3
+EgFtJmXFovDz3if6F6TzvhFpHgJRmLYVR8cqsezL3hEZOvvs2iH7MorkxwIVAJHD
+nD82+lxh2fb4PMsIiaXudAsBAoGAQRf7Q/iaPRn43ZquUhd6WwvirqUj+tkIu6eV
+2nZWYmXLlqFQKEy4Tejl7Wkyzr2OSYvbXLzo7TNxLKoWor6ips0phYPPMyXld14r
+juhT24CrhOzuLMhDduMDi032wDIZG4Y+K7ElU8Oufn8Sj5Wge8r6ANmmVgmFfynr
+FhdYCngCgYEA3ucGJ93/Mx4q4eKRDxcWD3QzWyqpbRVRRV1Vmih9Ha/qC994nJFz
+DQIdjxDIT2Rk2AGzMqFEB68Zc3O+Wcsmz5eWWzEwFxaTwOGWTyDqsDRLm3fD+QYj
+nOwuxb0Kce+gWI8voWcqC9cyRm09jGzu2Ab3Bhtpg8JJ8L7gS3MRZK4CFEx4UAfY
+Fmsr0W6fHB9nhS4/UXM8
+-----END DSA PRIVATE KEY-----`
+
+func TestParseDSA(t *testing.T) {
+	s, err := ParsePrivateKey([]byte(dsaPEM))
+	if err != nil {
+		t.Fatalf("ParsePrivateKey returned error: %s", err)
+	}
+
+	data := []byte("sign me")
+	sig, err := s.Sign(rand.Reader, data)
+	if err != nil {
+		t.Fatalf("dsa.Sign: %v", err)
+	}
+
+	if !s.PublicKey().Verify(data, sig) {
+		t.Error("Verify failed.")
+	}
+}
+
 func init() {
 	raw, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
 	ecdsaKey, _ = NewSignerFromKey(raw)