Remove CERT_PKEY::valid_flags.

CERT_PKEY_SIGN isn't meaningful since, without strict mode, we always fall back
to SHA-1 anyway. So the digest is never NULL when CERT_PKEY_SIGN is computed.
The entire valid_flags is now back to it's pre-1.0.2 check of seeing if the
certificate and key are configured.

This finally removes the sensitivity between valid_flags and selecting the
digest, so we can defer choosing the digest all we like.

Change-Id: I9f9952498f512d7f0cc799497f7c5b52145a48af
Reviewed-on: https://boringssl-review.googlesource.com/2288
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c
index e6096e9..0bff2ef 100644
--- a/ssl/s3_clnt.c
+++ b/ssl/s3_clnt.c
@@ -1649,11 +1649,10 @@
 			OPENSSL_PUT_ERROR(SSL, ssl3_get_certificate_request, SSL_R_DECODE_ERROR);
 			goto err;
 			}
-		/* Clear certificate digests and validity flags */
+		/* Clear certificate digests. */
 		for (i = 0; i < SSL_PKEY_NUM; i++)
 			{
 			s->cert->pkeys[i].digest = NULL;
-			s->cert->pkeys[i].valid_flags = 0;
 			}
 		if (!tls1_process_sigalgs(s, &supported_signature_algorithms))
 			{
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index 66d6354..812a329 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -1806,7 +1806,6 @@
 		allow = srvr;
 		}
 
-	tls1_set_cert_validity(s);
 	ssl_get_compatible_server_ciphers(s, &mask_k, &mask_a);
 
 	for (i=0; i<sk_SSL_CIPHER_num(prio); i++)
diff --git a/ssl/ssl_cert.c b/ssl/ssl_cert.c
index 03f212e..761192f 100644
--- a/ssl/ssl_cert.c
+++ b/ssl/ssl_cert.c
@@ -290,7 +290,6 @@
 				goto err;
 				}
 			}
-		rpk->valid_flags = 0;
 		}
 	
 	/* Set digests to defaults. NB: we don't copy existing values as they
@@ -389,8 +388,6 @@
 			sk_X509_pop_free(cpk->chain, X509_free);
 			cpk->chain = NULL;
 			}
-		/* Clear all flags. */
-		cpk->valid_flags = 0;
 		}
 	}
 
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index e6ef24d..2059032 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -2104,11 +2104,16 @@
 	ssl_cert_set_cert_cb(s->cert, cb, arg);
 	}
 
+static int ssl_has_key(SSL *s, size_t idx)
+	{
+	CERT_PKEY *cpk = &s->cert->pkeys[idx];
+	return cpk->x509 && cpk->privatekey;
+	}
+
 void ssl_get_compatible_server_ciphers(SSL *s, unsigned long *out_mask_k,
 	unsigned long *out_mask_a)
 	{
 	CERT *c = s->cert;
-	CERT_PKEY *cpk;
 	int rsa_enc, rsa_sign, dh_tmp;
 	unsigned long mask_k, mask_a;
 	int have_ecc_cert, ecdsa_ok;
@@ -2126,12 +2131,9 @@
 	dh_tmp = (c->dh_tmp != NULL || c->dh_tmp_cb != NULL);
 
 	have_ecdh_tmp = (c->ecdh_tmp || c->ecdh_tmp_cb || c->ecdh_tmp_auto);
-	cpk = &(c->pkeys[SSL_PKEY_RSA_ENC]);
-	rsa_enc = cpk->valid_flags & CERT_PKEY_VALID;
-	cpk = &(c->pkeys[SSL_PKEY_RSA_SIGN]);
-	rsa_sign = cpk->valid_flags & CERT_PKEY_SIGN;
-	cpk = &(c->pkeys[SSL_PKEY_ECC]);
-	have_ecc_cert = cpk->valid_flags & CERT_PKEY_VALID;
+	rsa_enc = ssl_has_key(s, SSL_PKEY_RSA_ENC);
+	rsa_sign = ssl_has_key(s, SSL_PKEY_RSA_SIGN);
+	have_ecc_cert = ssl_has_key(s, SSL_PKEY_ECC);
 	mask_k = 0;
 	mask_a = 0;
 
@@ -2149,16 +2151,15 @@
 	mask_a |= SSL_aNULL;
 
 	/* An ECC certificate may be usable for ECDSA cipher suites depending on
-         * the key usage extension. */
+         * the key usage extension and on the client's curve preferences. */
 	if (have_ecc_cert)
 		{
-		cpk = &c->pkeys[SSL_PKEY_ECC];
-		x = cpk->x509;
+		x = c->pkeys[SSL_PKEY_ECC].x509;
 		/* This call populates extension flags (ex_flags) */
 		X509_check_purpose(x, -1, 0);
 		ecdsa_ok = (x->ex_flags & EXFLAG_KUSAGE) ?
 		    (x->ex_kusage & X509v3_KU_DIGITAL_SIGNATURE) : 1;
-		if (!(cpk->valid_flags & CERT_PKEY_SIGN))
+		if (!tls1_check_ec_cert(s, x))
 			ecdsa_ok = 0;
 		if (ecdsa_ok)
 			{
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index c2aeb61..7f20b84 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -421,13 +421,6 @@
 #define SSL_GET_MESSAGE_DONT_HASH_MESSAGE 0
 #define SSL_GET_MESSAGE_HASH_MESSAGE 1
 
-/* Flags for a CERT_PKEY. */
-
-/* Certificate can be used with this session */
-#define CERT_PKEY_VALID		0x1
-/* Certificate can also be used for signing */
-#define CERT_PKEY_SIGN		0x2
-
 typedef struct cert_pkey_st
 	{
 	X509 *x509;
@@ -436,11 +429,6 @@
 	const EVP_MD *digest;
 	/* Chain for this certificate */
 	STACK_OF(X509) *chain;
-	/* Set if CERT_PKEY can be used with current SSL session: e.g.
-	 * appropriate curve, signature algorithms etc. If zero it can't be
-	 * used at all.
-	 */
-	int valid_flags;
 	} CERT_PKEY;
 
 typedef struct cert_st
@@ -1046,6 +1034,13 @@
 int tls1_set_curves(uint16_t **out_curve_ids, size_t *out_curve_ids_len,
 	const int *curves, size_t ncurves);
 
+/* tls1_check_ec_cert returns one if |x| is an ECC certificate with curve and
+ * point format compatible with the client's preferences. Otherwise it returns
+ * zero. */
+int tls1_check_ec_cert(SSL *s, X509 *x);
+
+/* tls1_check_ec_tmp_key returns one if the EC temporary key is compatible with
+ * client extensions and zero otherwise. */
 int tls1_check_ec_tmp_key(SSL *s);
 
 int tls1_shared_list(SSL *s,
@@ -1073,8 +1068,6 @@
 
 int tls1_set_sigalgs_list(CERT *c, const char *str, int client);
 int tls1_set_sigalgs(CERT *c, const int *salg, size_t salglen, int client);
-void tls1_check_chain(SSL *s, size_t idx);
-void tls1_set_cert_validity(SSL *s);
 
 /* ssl_ctx_log_rsa_client_key_exchange logs |premaster| to |ctx|, if logging is
  * enabled. It returns one on success and zero on failure. The entry is
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index a3d7228..d88fdea 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -654,36 +654,30 @@
 		}
 	}
 
-/* Check cert parameters compatible with extensions: currently just checks
- * EC certificates have compatible curves and compression.
- */
-static int tls1_check_cert_param(SSL *s, X509 *x)
+int tls1_check_ec_cert(SSL *s, X509 *x)
 	{
-	uint8_t comp_id;
+	int ret = 0;
+	EVP_PKEY *pkey = X509_get_pubkey(x);
 	uint16_t curve_id;
-	EVP_PKEY *pkey;
-	int rv;
-	pkey = X509_get_pubkey(x);
-	if (!pkey)
-		return 0;
-	/* If not EC nothing to do */
-	if (pkey->type != EVP_PKEY_EC)
+	uint8_t comp_id;
+
+	if (!pkey ||
+		pkey->type != EVP_PKEY_EC ||
+		!tls1_curve_params_from_ec_key(&curve_id, &comp_id, pkey->pkey.ec) ||
+		!tls1_check_curve_id(s, curve_id) ||
+		!tls1_check_point_format(s, comp_id))
 		{
-		EVP_PKEY_free(pkey);
-		return 1;
+		goto done;
 		}
-	rv = tls1_curve_params_from_ec_key(&curve_id, &comp_id, pkey->pkey.ec);
-	EVP_PKEY_free(pkey);
-	if (!rv)
-		return 0;
-	/* Can't check curve_id for client certs as we don't have a
-	 * supported curves extension. */
-	if (s->server && !tls1_check_curve_id(s, curve_id))
-		return 0;
-	return tls1_check_point_format(s, comp_id);
+
+	ret = 1;
+
+done:
+	if (pkey)
+		EVP_PKEY_free(pkey);
+	return ret;
 	}
 
-/* Check EC temporary key is compatible with client extensions */
 int tls1_check_ec_tmp_key(SSL *s)
 	{
 	uint16_t curve_id;
@@ -1457,11 +1451,10 @@
 		OPENSSL_free(s->cert->shared_sigalgs);
 		s->cert->shared_sigalgs = NULL;
 		}
-	/* Clear certificate digests and validity flags */
+	/* Clear certificate digests. */
 	for (i = 0; i < SSL_PKEY_NUM; i++)
 		{
 		s->cert->pkeys[i].digest = NULL;
-		s->cert->pkeys[i].valid_flags = 0;
 		}
 	/* Clear ECC extensions */
 	if (s->s3->tmp.peer_ecpointformatlist != 0)
@@ -2915,35 +2908,3 @@
 	return 0;
 	}
 
-/* Check certificate chain is consistent with TLS extensions and is usable by
- * server. This allows the server to check chains before attempting to use them.
- */
-
-void tls1_check_chain(SSL *s, size_t idx)
-	{
-	CERT_PKEY *cpk = &s->cert->pkeys[idx];
-
-	/* Clear the flags. */
-	cpk->valid_flags = 0;
-
-	/* If no cert or key, forget it. */
-	if (!cpk->x509 || !cpk->privatekey)
-		return;
-
-	/* Check cert parameters are consistent */
-	if (!tls1_check_cert_param(s, cpk->x509))
-		return;
-
-	cpk->valid_flags = CERT_PKEY_VALID;
-	if (!SSL_USE_SIGALGS(s) || cpk->digest)
-		cpk->valid_flags |= CERT_PKEY_SIGN;
-	}
-
-/* Set validity of certificates in an SSL structure */
-void tls1_set_cert_validity(SSL *s)
-	{
-	tls1_check_chain(s, SSL_PKEY_RSA_ENC);
-	tls1_check_chain(s, SSL_PKEY_RSA_SIGN);
-	tls1_check_chain(s, SSL_PKEY_ECC);
-	}
-