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);
- }
-