crypto/tls: create certs w/o KeyEncipherment KU for non-RSA keys in generate_cert.go

Summary

The crypto/tls/generate_cert.go utility should only set the template
x509.Certificate's KeyUsage field to a value with the
x509.KeyUsageKeyEncipherment bits set when the certificate subject
public key is an RSA public key, not an ECDSA or ED25519 public key.

Background

RFC 5480 describes the usage of ECDSA elliptic curve subject keys with
X.509. Unfortunately while Section 3 "Key Usages Bits" indicates which
key usage bits MAY be used with a certificate that indicates
id-ecPublicKey in the SubjectPublicKeyInfo field it doesn't provide
guidance on which usages should *not* be included (e.g. the
keyEncipherment bit, which is particular to RSA key exchange). The same
problem is present in RFC 8410 Section 5 describing Key Usage Bits for
ED25519 elliptic curve subject keys.

There's an update to RFC 5480 in last call stage within the IETF LAMPS
WG, draft-ietf-lamps-5480-ku-clarifications-00. This update is meant
to clarify the allowed Key Usages extension values for certificates with
ECDSA subject public keys by adding:

> If the keyUsage extension is present in a certificate that indicates
> id-ecPublicKey as algorithm of AlgorithmIdentifier [RFC2986] in
> SubjectPublicKeyInfo, then following values MUST NOT be present:
>
> keyEncipherment; and
> dataEncipherment.

I don't believe there is an update for RFC 8410 in the works but I
suspect it will be clarified similarly in the future.

This commit updates generate_cert.go to ensure when the certificate
public key is ECDSA or ED25519 the generated certificate has the
x509.Certificate.KeyUsage field set to a value that doesn't include KUs
specific to RSA. For ECDSA keys this will adhere to the updated RFC 5480
language.

Fixes #36499

Change-Id: Ib1b0757c039b7fe97fc6d1e826fe6b88856c1964
GitHub-Last-Rev: a8f34fb33dde90e09b6f9a27b2598a82b3023abb
GitHub-Pull-Request: golang/go#36500
Reviewed-on: https://go-review.googlesource.com/c/go/+/214337
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Run-TryBot: Filippo Valsorda <filippo@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
diff --git a/src/crypto/tls/generate_cert.go b/src/crypto/tls/generate_cert.go
index f1d69c4..1857185 100644
--- a/src/crypto/tls/generate_cert.go
+++ b/src/crypto/tls/generate_cert.go
@@ -81,6 +81,16 @@
 		log.Fatalf("Failed to generate private key: %v", err)
 	}
 
+	// ECDSA, ED25519 and RSA subject keys should have the DigitalSignature
+	// KeyUsage bits set in the x509.Certificate template
+	keyUsage := x509.KeyUsageDigitalSignature
+	// Only RSA subject keys should have the KeyEncipherment KeyUsage bits set. In
+	// the context of TLS this KeyUsage is particular to RSA key exchange and
+	// authentication.
+	if _, isRSA := priv.(*rsa.PrivateKey); isRSA {
+		keyUsage |= x509.KeyUsageKeyEncipherment
+	}
+
 	var notBefore time.Time
 	if len(*validFrom) == 0 {
 		notBefore = time.Now()
@@ -107,7 +117,7 @@
 		NotBefore: notBefore,
 		NotAfter:  notAfter,
 
-		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
+		KeyUsage:              keyUsage,
 		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
 		BasicConstraintsValid: true,
 	}