ssh: reject unsupported DSA key sizes

Fixes golang/go#19424.

Change-Id: I73370603dd612979420d608b73d67e673a52362b
Reviewed-on: https://go-review.googlesource.com/62870
Run-TryBot: Han-Wen Nienhuys <hanwen@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Filippo Valsorda <hi@filippo.io>
Reviewed-by: Adam Langley <agl@golang.org>
diff --git a/ssh/keys.go b/ssh/keys.go
index 7a8756a..b682c17 100644
--- a/ssh/keys.go
+++ b/ssh/keys.go
@@ -367,6 +367,17 @@
 	return "ssh-dss"
 }
 
+func checkDSAParams(param *dsa.Parameters) error {
+	// SSH specifies FIPS 186-2, which only provided a single size
+	// (1024 bits) DSA key. FIPS 186-3 allows for larger key
+	// sizes, which would confuse SSH.
+	if l := param.P.BitLen(); l != 1024 {
+		return fmt.Errorf("ssh: unsupported DSA key size %d", l)
+	}
+
+	return nil
+}
+
 // parseDSA parses an DSA key according to RFC 4253, section 6.6.
 func parseDSA(in []byte) (out PublicKey, rest []byte, err error) {
 	var w struct {
@@ -377,13 +388,18 @@
 		return nil, nil, err
 	}
 
+	param := dsa.Parameters{
+		P: w.P,
+		Q: w.Q,
+		G: w.G,
+	}
+	if err := checkDSAParams(&param); err != nil {
+		return nil, nil, err
+	}
+
 	key := &dsaPublicKey{
-		Parameters: dsa.Parameters{
-			P: w.P,
-			Q: w.Q,
-			G: w.G,
-		},
-		Y: w.Y,
+		Parameters: param,
+		Y:          w.Y,
 	}
 	return key, w.Rest, nil
 }
@@ -630,19 +646,28 @@
 }
 
 // NewSignerFromKey takes an *rsa.PrivateKey, *dsa.PrivateKey,
-// *ecdsa.PrivateKey or any other crypto.Signer and returns a corresponding
-// Signer instance. ECDSA keys must use P-256, P-384 or P-521.
+// *ecdsa.PrivateKey or any other crypto.Signer and returns a
+// corresponding Signer instance. ECDSA keys must use P-256, P-384 or
+// P-521. DSA keys must use parameter size L1024N160.
 func NewSignerFromKey(key interface{}) (Signer, error) {
 	switch key := key.(type) {
 	case crypto.Signer:
 		return NewSignerFromSigner(key)
 	case *dsa.PrivateKey:
-		return &dsaPrivateKey{key}, nil
+		return newDSAPrivateKey(key)
 	default:
 		return nil, fmt.Errorf("ssh: unsupported key type %T", key)
 	}
 }
 
+func newDSAPrivateKey(key *dsa.PrivateKey) (Signer, error) {
+	if err := checkDSAParams(&key.PublicKey.Parameters); err != nil {
+		return nil, err
+	}
+
+	return &dsaPrivateKey{key}, nil
+}
+
 type wrappedSigner struct {
 	signer crypto.Signer
 	pubKey PublicKey