Account for EVP_PKEY capabilities in selecting hash functions.

tls1_process_sigalgs now only determines the intersection between the peer
algorithms and those configured locally. That list is queried later to
determine the hash algorithm to use when signing CertificateVerify or
ServerKeyExchange.

This is needed to support client auth on Windows where smartcards or CAPI may
not support all hash functions.

As a bonus, this does away with more connection-global state. This avoids the
current situation where digests are chosen before keys are known (for
CertificateVerify) or for slots that don't exist.

Change-Id: Iec3619a103d691291d8ebe08ef77d574f2faf0e8
Reviewed-on: https://boringssl-review.googlesource.com/2280
Reviewed-by: Adam Langley <agl@google.com>
This commit is contained in:
David Benjamin
2014-11-18 22:22:33 +00:00
committed by Adam Langley
parent 033e5f47d1
commit ec2f27dee1
6 changed files with 48 additions and 93 deletions
+7 -19
View File
@@ -1565,7 +1565,6 @@ int ssl3_get_certificate_request(SSL *s)
{
int ok,ret=0;
unsigned long n;
unsigned int i;
X509_NAME *xn=NULL;
STACK_OF(X509_NAME) *ca_sk=NULL;
CBS cbs;
@@ -1649,11 +1648,6 @@ int ssl3_get_certificate_request(SSL *s)
OPENSSL_PUT_ERROR(SSL, ssl3_get_certificate_request, SSL_R_DECODE_ERROR);
goto err;
}
/* Clear certificate digests. */
for (i = 0; i < SSL_PKEY_NUM; i++)
{
s->cert->pkeys[i].digest = NULL;
}
if (!tls1_process_sigalgs(s, &supported_signature_algorithms))
{
ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_DECODE_ERROR);
@@ -2278,7 +2272,7 @@ int ssl3_send_cert_verify(SSL *s)
/* Write out the digest type if needbe. */
if (SSL_USE_SIGALGS(s))
{
md = s->cert->key->digest;
md = tls1_choose_signing_digest(s, pkey);
if (!tls12_get_sigandhash(p, pkey, md))
{
OPENSSL_PUT_ERROR(SSL, ssl3_send_cert_verify, ERR_R_INTERNAL_ERROR);
@@ -2337,17 +2331,11 @@ err:
return(-1);
}
/* Check a certificate can be used for client authentication. Currently
* check the cert exists and if we have a suitable digest for TLS 1.2.
*/
static int ssl3_check_client_certificate(SSL *s)
/* ssl3_has_client_certificate returns true if a client certificate is
* configured. */
static int ssl3_has_client_certificate(SSL *s)
{
if (!s->cert || !s->cert->key->x509 || !s->cert->key->privatekey)
return 0;
/* If no suitable signature algorithm can't use certificate */
if (SSL_USE_SIGALGS(s) && !s->cert->key->digest)
return 0;
return 1;
return s->cert && s->cert->key->x509 && s->cert->key->privatekey;
}
int ssl3_send_client_certificate(SSL *s)
@@ -2374,7 +2362,7 @@ int ssl3_send_client_certificate(SSL *s)
}
s->rwstate=SSL_NOTHING;
}
if (ssl3_check_client_certificate(s))
if (ssl3_has_client_certificate(s))
s->state=SSL3_ST_CW_CERT_C;
else
s->state=SSL3_ST_CW_CERT_B;
@@ -2408,7 +2396,7 @@ int ssl3_send_client_certificate(SSL *s)
if (x509 != NULL) X509_free(x509);
if (pkey != NULL) EVP_PKEY_free(pkey);
if (i && !ssl3_check_client_certificate(s))
if (i && !ssl3_has_client_certificate(s))
i = 0;
if (i == 0)
{
+8 -10
View File
@@ -1288,7 +1288,6 @@ int ssl3_send_server_key_exchange(SSL *s)
const char* psk_identity_hint = NULL;
size_t psk_identity_hint_len = 0;
EVP_PKEY *pkey;
const EVP_MD *md = NULL;
unsigned char *p,*d;
int al,i;
unsigned long alg_k;
@@ -1510,7 +1509,7 @@ int ssl3_send_server_key_exchange(SSL *s)
if (ssl_cipher_has_server_public_key(s->s3->tmp.new_cipher))
{
if ((pkey=ssl_get_sign_pkey(s,s->s3->tmp.new_cipher,&md))
if ((pkey=ssl_get_sign_pkey(s,s->s3->tmp.new_cipher))
== NULL)
{
al=SSL_AD_DECODE_ERROR;
@@ -1607,13 +1606,15 @@ int ssl3_send_server_key_exchange(SSL *s)
n+=u+2;
}
else
if (md)
{
const EVP_MD *md;
size_t sig_len = EVP_PKEY_size(pkey);
/* send signature algorithm */
if (SSL_USE_SIGALGS(s))
{
md = tls1_choose_signing_digest(s, pkey);
if (!tls12_get_sigandhash(p, pkey, md))
{
/* Should never happen */
@@ -1623,6 +1624,10 @@ int ssl3_send_server_key_exchange(SSL *s)
}
p+=2;
}
else
{
md = EVP_sha1();
}
if (!EVP_DigestSignInit(&md_ctx, NULL, md, NULL, pkey) ||
!EVP_DigestSignUpdate(&md_ctx, s->s3->client_random, SSL3_RANDOM_SIZE) ||
!EVP_DigestSignUpdate(&md_ctx, s->s3->server_random, SSL3_RANDOM_SIZE) ||
@@ -1637,13 +1642,6 @@ int ssl3_send_server_key_exchange(SSL *s)
if (SSL_USE_SIGALGS(s))
n += 2;
}
else
{
/* Is this error check actually needed? */
al=SSL_AD_HANDSHAKE_FAILURE;
OPENSSL_PUT_ERROR(SSL, ssl3_send_server_key_exchange, SSL_R_UNKNOWN_PKEY_TYPE);
goto f_err;
}
}
ssl_set_handshake_header(s, SSL3_MT_SERVER_KEY_EXCHANGE, n);
-13
View File
@@ -156,14 +156,6 @@ int SSL_get_ex_data_X509_STORE_CTX_idx(void)
return ssl_x509_store_ctx_idx;
}
void ssl_cert_set_default_md(CERT *cert)
{
/* Set digest values to defaults */
cert->pkeys[SSL_PKEY_RSA_SIGN].digest = EVP_sha1();
cert->pkeys[SSL_PKEY_RSA_ENC].digest = EVP_sha1();
cert->pkeys[SSL_PKEY_ECC].digest = EVP_sha1();
}
CERT *ssl_cert_new(void)
{
CERT *ret;
@@ -177,7 +169,6 @@ CERT *ssl_cert_new(void)
memset(ret,0,sizeof(CERT));
ret->key= &(ret->pkeys[SSL_PKEY_RSA_ENC]);
ssl_cert_set_default_md(ret);
return(ret);
}
@@ -292,10 +283,6 @@ CERT *ssl_cert_dup(CERT *cert)
}
}
/* Set digests to defaults. NB: we don't copy existing values as they
* will be set during handshake.
*/
ssl_cert_set_default_md(ret);
/* Peer sigalgs set to NULL as we get these from handshake too */
ret->peer_sigalgs = NULL;
ret->peer_sigalgslen = 0;
+1 -3
View File
@@ -2242,7 +2242,7 @@ CERT_PKEY *ssl_get_server_send_pkey(const SSL *s)
return &s->cert->pkeys[i];
}
EVP_PKEY *ssl_get_sign_pkey(SSL *s,const SSL_CIPHER *cipher, const EVP_MD **pmd)
EVP_PKEY *ssl_get_sign_pkey(SSL *s,const SSL_CIPHER *cipher)
{
unsigned long alg_a;
CERT *c;
@@ -2266,8 +2266,6 @@ EVP_PKEY *ssl_get_sign_pkey(SSL *s,const SSL_CIPHER *cipher, const EVP_MD **pmd)
OPENSSL_PUT_ERROR(SSL, ssl_get_sign_pkey, ERR_R_INTERNAL_ERROR);
return(NULL);
}
if (pmd)
*pmd = c->pkeys[idx].digest;
return c->pkeys[idx].privatekey;
}
+6 -4
View File
@@ -425,8 +425,6 @@ typedef struct cert_pkey_st
{
X509 *x509;
EVP_PKEY *privatekey;
/* Digest to use when signing */
const EVP_MD *digest;
/* Chain for this certificate */
STACK_OF(X509) *chain;
} CERT_PKEY;
@@ -759,7 +757,6 @@ void ssl_clear_cipher_ctx(SSL *s);
int ssl_clear_bad_session(SSL *s);
CERT *ssl_cert_new(void);
CERT *ssl_cert_dup(CERT *cert);
void ssl_cert_set_default_md(CERT *cert);
int ssl_cert_inst(CERT **o);
void ssl_cert_clear_certs(CERT *c);
void ssl_cert_free(CERT *c);
@@ -806,7 +803,7 @@ int ssl_undefined_function(SSL *s);
int ssl_undefined_void_function(void);
int ssl_undefined_const_function(const SSL *s);
CERT_PKEY *ssl_get_server_send_pkey(const SSL *s);
EVP_PKEY *ssl_get_sign_pkey(SSL *s,const SSL_CIPHER *c, const EVP_MD **pmd);
EVP_PKEY *ssl_get_sign_pkey(SSL *s,const SSL_CIPHER *c);
int ssl_cert_type(X509 *x,EVP_PKEY *pkey);
/* ssl_get_compatible_server_ciphers determines the key exchange and
@@ -1095,6 +1092,11 @@ int ssl_add_clienthello_renegotiate_ext(SSL *s, unsigned char *p, int *len,
int ssl_parse_clienthello_renegotiate_ext(SSL *s, CBS *cbs, int *out_alert);
long ssl_get_algorithm2(SSL *s);
int tls1_process_sigalgs(SSL *s, const CBS *sigalgs);
/* tls1_choose_signing_digest returns a digest for use with |pkey| based on the
* peer's preferences recorded for |s| and the digests supported by |pkey|. */
const EVP_MD *tls1_choose_signing_digest(SSL *s, EVP_PKEY *pkey);
size_t tls12_get_psigalgs(SSL *s, const unsigned char **psigs);
int tls12_check_peer_sigalg(const EVP_MD **out_md, int *out_alert, SSL *s,
CBS *cbs, EVP_PKEY *pkey);
+26 -44
View File
@@ -1426,7 +1426,6 @@ static int ssl_scan_clienthello_tlsext(SSL *s, CBS *cbs, int *out_alert)
{
int renegotiate_seen = 0;
CBS extensions;
size_t i;
s->should_ack_sni = 0;
s->s3->next_proto_neg_seen = 0;
@@ -1451,11 +1450,6 @@ static int ssl_scan_clienthello_tlsext(SSL *s, CBS *cbs, int *out_alert)
OPENSSL_free(s->cert->shared_sigalgs);
s->cert->shared_sigalgs = NULL;
}
/* Clear certificate digests. */
for (i = 0; i < SSL_PKEY_NUM; i++)
{
s->cert->pkeys[i].digest = NULL;
}
/* Clear ECC extensions */
if (s->s3->tmp.peer_ecpointformatlist != 0)
{
@@ -1815,9 +1809,6 @@ static int ssl_scan_clienthello_tlsext(SSL *s, CBS *cbs, int *out_alert)
OPENSSL_PUT_ERROR(SSL, ssl_scan_clienthello_tlsext, SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
return 0;
}
/* If no signature algorithms extension set default values */
if (!s->cert->peer_sigalgs)
ssl_cert_set_default_md(s->cert);
return 1;
}
@@ -2566,14 +2557,16 @@ const EVP_MD *tls12_get_hash(unsigned char hash_alg)
}
}
static int tls12_get_pkey_idx(unsigned char sig_alg)
/* tls12_get_pkey_type returns the EVP_PKEY type corresponding to TLS signature
* algorithm |sig_alg|. It returns -1 if the type is unknown. */
static int tls12_get_pkey_type(uint8_t sig_alg)
{
switch(sig_alg)
{
case TLSEXT_signature_rsa:
return SSL_PKEY_RSA_SIGN;
return EVP_PKEY_RSA;
case TLSEXT_signature_ecdsa:
return SSL_PKEY_ECC;
return EVP_PKEY_EC;
}
return -1;
}
@@ -2620,7 +2613,7 @@ static int tls12_do_shared_sigalgs(TLS_SIGALGS *shsig,
/* Skip disabled hashes or signature algorithms */
if (tls12_get_hash(ptmp[0]) == NULL)
continue;
if (tls12_get_pkey_idx(ptmp[1]) == -1)
if (tls12_get_pkey_type(ptmp[1]) == -1)
continue;
for (j = 0, atmp = allow; j < allowlen; j+=2, atmp+=2)
{
@@ -2701,11 +2694,7 @@ static int tls1_set_shared_sigalgs(SSL *s)
int tls1_process_sigalgs(SSL *s, const CBS *sigalgs)
{
int idx;
size_t i;
const EVP_MD *md;
CERT *c = s->cert;
TLS_SIGALGS *sigptr;
/* Extension ignored for inappropriate versions */
if (!SSL_USE_SIGALGS(s))
@@ -2721,36 +2710,29 @@ int tls1_process_sigalgs(SSL *s, const CBS *sigalgs)
return 0;
tls1_set_shared_sigalgs(s);
for (i = 0, sigptr = c->shared_sigalgs;
i < c->shared_sigalgslen; i++, sigptr++)
{
idx = tls12_get_pkey_idx(sigptr->rsign);
if (idx > 0 && c->pkeys[idx].digest == NULL)
{
md = tls12_get_hash(sigptr->rhash);
c->pkeys[idx].digest = md;
if (idx == SSL_PKEY_RSA_SIGN)
{
c->pkeys[SSL_PKEY_RSA_ENC].digest = md;
}
}
}
/* Set any remaining keys to default values. NOTE: if alg is
* not supported it stays as NULL.
*/
if (!c->pkeys[SSL_PKEY_RSA_SIGN].digest)
{
c->pkeys[SSL_PKEY_RSA_SIGN].digest = EVP_sha1();
c->pkeys[SSL_PKEY_RSA_ENC].digest = EVP_sha1();
}
if (!c->pkeys[SSL_PKEY_ECC].digest)
c->pkeys[SSL_PKEY_ECC].digest = EVP_sha1();
return 1;
}
const EVP_MD *tls1_choose_signing_digest(SSL *s, EVP_PKEY *pkey)
{
CERT *c = s->cert;
int type = EVP_PKEY_id(pkey);
size_t i;
/* Select the first shared digest supported by our key. */
for (i = 0; i < c->shared_sigalgslen; i++)
{
const EVP_MD *md = tls12_get_hash(c->shared_sigalgs[i].rhash);
if (md == NULL || tls12_get_pkey_type(c->shared_sigalgs[i].rsign) != type)
continue;
if (!EVP_PKEY_supports_digest(pkey, md))
continue;
return md;
}
/* If no suitable digest may be found, default to SHA-1. */
return EVP_sha1();
}
int SSL_get_sigalgs(SSL *s, int idx,
int *psign, int *phash, int *psignhash,