summaryrefslogtreecommitdiff
path: root/drivers/builtin_openssl2/ssl/s3_clnt.c
diff options
context:
space:
mode:
authormrezai <mhd.rezai@gmail.com>2016-04-15 19:03:35 +0430
committermrezai <mhd.rezai@gmail.com>2016-04-15 19:03:35 +0430
commite97922f22038e9049ed4c2db5b3736dfaa0edde3 (patch)
tree37e036a343e7482a387b7acd0a88509af78a69eb /drivers/builtin_openssl2/ssl/s3_clnt.c
parent880f4abda44a42532abb6f15999a90bc85f6264a (diff)
Update OpenSSL to version 1.0.2g
Diffstat (limited to 'drivers/builtin_openssl2/ssl/s3_clnt.c')
-rw-r--r--drivers/builtin_openssl2/ssl/s3_clnt.c471
1 files changed, 332 insertions, 139 deletions
diff --git a/drivers/builtin_openssl2/ssl/s3_clnt.c b/drivers/builtin_openssl2/ssl/s3_clnt.c
index cfa5080e6b..04cc9f54a9 100644
--- a/drivers/builtin_openssl2/ssl/s3_clnt.c
+++ b/drivers/builtin_openssl2/ssl/s3_clnt.c
@@ -317,11 +317,11 @@ int ssl3_connect(SSL *s)
s->state = SSL3_ST_CR_SESSION_TICKET_A;
}
#endif
- } else
+ } else {
s->state = SSL3_ST_CR_CERT_A;
+ }
s->init_num = 0;
break;
-
case SSL3_ST_CR_CERT_A:
case SSL3_ST_CR_CERT_B:
#ifndef OPENSSL_NO_TLSEXT
@@ -675,6 +675,7 @@ int ssl3_client_hello(SSL *s)
unsigned char *p, *d;
int i;
unsigned long l;
+ int al = 0;
#ifndef OPENSSL_NO_COMP
int j;
SSL_COMP *comp;
@@ -697,15 +698,64 @@ int ssl3_client_hello(SSL *s)
if (!ssl_get_new_session(s, 0))
goto err;
}
+ if (s->method->version == DTLS_ANY_VERSION) {
+ /* Determine which DTLS version to use */
+ int options = s->options;
+ /* If DTLS 1.2 disabled correct the version number */
+ if (options & SSL_OP_NO_DTLSv1_2) {
+ if (tls1_suiteb(s)) {
+ SSLerr(SSL_F_SSL3_CLIENT_HELLO,
+ SSL_R_ONLY_DTLS_1_2_ALLOWED_IN_SUITEB_MODE);
+ goto err;
+ }
+ /*
+ * Disabling all versions is silly: return an error.
+ */
+ if (options & SSL_OP_NO_DTLSv1) {
+ SSLerr(SSL_F_SSL3_CLIENT_HELLO, SSL_R_WRONG_SSL_VERSION);
+ goto err;
+ }
+ /*
+ * Update method so we don't use any DTLS 1.2 features.
+ */
+ s->method = DTLSv1_client_method();
+ s->version = DTLS1_VERSION;
+ } else {
+ /*
+ * We only support one version: update method
+ */
+ if (options & SSL_OP_NO_DTLSv1)
+ s->method = DTLSv1_2_client_method();
+ s->version = DTLS1_2_VERSION;
+ }
+ s->client_version = s->version;
+ }
/* else use the pre-loaded session */
p = s->s3->client_random;
- if (ssl_fill_hello_random(s, 0, p, SSL3_RANDOM_SIZE) <= 0)
+ /*
+ * for DTLS if client_random is initialized, reuse it, we are
+ * required to use same upon reply to HelloVerify
+ */
+ if (SSL_IS_DTLS(s)) {
+ size_t idx;
+ i = 1;
+ for (idx = 0; idx < sizeof(s->s3->client_random); idx++) {
+ if (p[idx]) {
+ i = 0;
+ break;
+ }
+ }
+ } else
+ i = 1;
+
+ if (i && ssl_fill_hello_random(s, 0, p,
+ sizeof(s->s3->client_random)) <= 0)
goto err;
/* Do the message type and length last */
- d = p = &(buf[4]);
+ d = p = ssl_handshake_start(s);
/*-
* version indicates the negotiated version: for example from
@@ -765,6 +815,17 @@ int ssl3_client_hello(SSL *s)
p += i;
}
+ /* cookie stuff for DTLS */
+ if (SSL_IS_DTLS(s)) {
+ if (s->d1->cookie_len > sizeof(s->d1->cookie)) {
+ SSLerr(SSL_F_SSL3_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ *(p++) = s->d1->cookie_len;
+ memcpy(p, s->d1->cookie, s->d1->cookie_len);
+ p += s->d1->cookie_len;
+ }
+
/* Ciphers supported */
i = ssl_cipher_list_to_bytes(s, SSL_get_ciphers(s), &(p[2]), 0);
if (i == 0) {
@@ -809,27 +870,21 @@ int ssl3_client_hello(SSL *s)
goto err;
}
if ((p =
- ssl_add_clienthello_tlsext(s, p,
- buf + SSL3_RT_MAX_PLAIN_LENGTH)) ==
- NULL) {
+ ssl_add_clienthello_tlsext(s, p, buf + SSL3_RT_MAX_PLAIN_LENGTH,
+ &al)) == NULL) {
+ ssl3_send_alert(s, SSL3_AL_FATAL, al);
SSLerr(SSL_F_SSL3_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
goto err;
}
#endif
- l = (p - d);
- d = buf;
- *(d++) = SSL3_MT_CLIENT_HELLO;
- l2n3(l, d);
-
+ l = p - d;
+ ssl_set_handshake_header(s, SSL3_MT_CLIENT_HELLO, l);
s->state = SSL3_ST_CW_CLNT_HELLO_B;
- /* number of bytes to write */
- s->init_num = p - buf;
- s->init_off = 0;
}
/* SSL3_ST_CW_CLNT_HELLO_B */
- return (ssl3_do_write(s, SSL3_RT_HANDSHAKE));
+ return ssl_do_write(s);
err:
s->state = SSL_ST_ERR;
return (-1);
@@ -839,13 +894,20 @@ int ssl3_get_server_hello(SSL *s)
{
STACK_OF(SSL_CIPHER) *sk;
const SSL_CIPHER *c;
+ CERT *ct = s->cert;
unsigned char *p, *d;
- int i, al, ok;
+ int i, al = SSL_AD_INTERNAL_ERROR, ok;
unsigned int j;
long n;
#ifndef OPENSSL_NO_COMP
SSL_COMP *comp;
#endif
+ /*
+ * Hello verify request and/or server hello version may not match so set
+ * first packet if we're negotiating version.
+ */
+ if (SSL_IS_DTLS(s))
+ s->first_packet = 1;
n = s->method->ssl_get_message(s,
SSL3_ST_CR_SRVR_HELLO_A,
@@ -854,7 +916,8 @@ int ssl3_get_server_hello(SSL *s)
if (!ok)
return ((int)n);
- if (SSL_version(s) == DTLS1_VERSION || SSL_version(s) == DTLS1_BAD_VER) {
+ if (SSL_IS_DTLS(s)) {
+ s->first_packet = 0;
if (s->s3->tmp.message_type == DTLS1_MT_HELLO_VERIFY_REQUEST) {
if (s->d1->send_cookie == 0) {
s->s3->tmp.reuse_message = 1;
@@ -875,6 +938,28 @@ int ssl3_get_server_hello(SSL *s)
}
d = p = (unsigned char *)s->init_msg;
+ if (s->method->version == DTLS_ANY_VERSION) {
+ /* Work out correct protocol version to use */
+ int hversion = (p[0] << 8) | p[1];
+ int options = s->options;
+ if (hversion == DTLS1_2_VERSION && !(options & SSL_OP_NO_DTLSv1_2))
+ s->method = DTLSv1_2_client_method();
+ else if (tls1_suiteb(s)) {
+ SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,
+ SSL_R_ONLY_DTLS_1_2_ALLOWED_IN_SUITEB_MODE);
+ s->version = hversion;
+ al = SSL_AD_PROTOCOL_VERSION;
+ goto f_err;
+ } else if (hversion == DTLS1_VERSION && !(options & SSL_OP_NO_DTLSv1))
+ s->method = DTLSv1_client_method();
+ else {
+ SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_WRONG_SSL_VERSION);
+ s->version = hversion;
+ al = SSL_AD_PROTOCOL_VERSION;
+ goto f_err;
+ }
+ s->session->ssl_version = s->version = s->method->version;
+ }
if ((p[0] != (s->version >> 8)) || (p[1] != (s->version & 0xff))) {
SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_WRONG_SSL_VERSION);
@@ -951,7 +1036,6 @@ int ssl3_get_server_hello(SSL *s)
*/
if (s->session->session_id_length > 0) {
if (!ssl_get_new_session(s, 0)) {
- al = SSL_AD_INTERNAL_ERROR;
goto f_err;
}
}
@@ -966,21 +1050,21 @@ int ssl3_get_server_hello(SSL *s)
SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_UNKNOWN_CIPHER_RETURNED);
goto f_err;
}
- /* TLS v1.2 only ciphersuites require v1.2 or later */
- if ((c->algorithm_ssl & SSL_TLSV1_2) &&
- (TLS1_get_version(s) < TLS1_2_VERSION)) {
- al = SSL_AD_ILLEGAL_PARAMETER;
- SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_WRONG_CIPHER_RETURNED);
- goto f_err;
- }
-#ifndef OPENSSL_NO_SRP
- if (((c->algorithm_mkey & SSL_kSRP) || (c->algorithm_auth & SSL_aSRP)) &&
- !(s->srp_ctx.srp_Mask & SSL_kSRP)) {
+ /* Set version disabled mask now we know version */
+ if (!SSL_USE_TLS1_2_CIPHERS(s))
+ ct->mask_ssl = SSL_TLSV1_2;
+ else
+ ct->mask_ssl = 0;
+ /*
+ * If it is a disabled cipher we didn't send it in client hello, so
+ * return an error.
+ */
+ if (c->algorithm_ssl & ct->mask_ssl ||
+ c->algorithm_mkey & ct->mask_k || c->algorithm_auth & ct->mask_a) {
al = SSL_AD_ILLEGAL_PARAMETER;
SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_WRONG_CIPHER_RETURNED);
goto f_err;
}
-#endif /* OPENSSL_NO_SRP */
p += ssl_put_cipher_by_char(s, NULL, NULL);
sk = ssl_get_ciphers_by_id(s);
@@ -1013,14 +1097,11 @@ int ssl3_get_server_hello(SSL *s)
}
s->s3->tmp.new_cipher = c;
/*
- * Don't digest cached records if TLS v1.2: we may need them for client
+ * Don't digest cached records if no sigalgs: we may need them for client
* authentication.
*/
- if (TLS1_get_version(s) < TLS1_2_VERSION
- && !ssl3_digest_cached_records(s)) {
- al = SSL_AD_INTERNAL_ERROR;
+ if (!SSL_USE_SIGALGS(s) && !ssl3_digest_cached_records(s))
goto f_err;
- }
/* lets get the compression algorithm */
/* COMPRESSION */
#ifdef OPENSSL_NO_COMP
@@ -1035,7 +1116,6 @@ int ssl3_get_server_hello(SSL *s)
* using compression.
*/
if (s->session->compress_meth != 0) {
- al = SSL_AD_INTERNAL_ERROR;
SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_INCONSISTENT_COMPRESSION);
goto f_err;
}
@@ -1068,16 +1148,9 @@ int ssl3_get_server_hello(SSL *s)
#ifndef OPENSSL_NO_TLSEXT
/* TLS extensions */
- if (s->version >= SSL3_VERSION) {
- if (!ssl_parse_serverhello_tlsext(s, &p, d, n, &al)) {
- /* 'al' set by ssl_parse_serverhello_tlsext */
- SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_PARSE_TLSEXT);
- goto f_err;
- }
- if (ssl_check_serverhello_tlsext(s) <= 0) {
- SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_SERVERHELLO_TLSEXT);
- goto err;
- }
+ if (!ssl_parse_serverhello_tlsext(s, &p, d, n)) {
+ SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_PARSE_TLSEXT);
+ goto err;
}
#endif
@@ -1240,6 +1313,14 @@ int ssl3_get_server_certificate(SSL *s)
}
if (need_cert) {
+ int exp_idx = ssl_cipher_get_cert_index(s->s3->tmp.new_cipher);
+ if (exp_idx >= 0 && i != exp_idx) {
+ x = NULL;
+ al = SSL_AD_ILLEGAL_PARAMETER;
+ SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE,
+ SSL_R_WRONG_CERTIFICATE_TYPE);
+ goto f_err;
+ }
sc->peer_cert_type = i;
CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509);
/*
@@ -1267,7 +1348,6 @@ int ssl3_get_server_certificate(SSL *s)
x = NULL;
ret = 1;
-
if (0) {
f_err:
ssl3_send_alert(s, SSL3_AL_FATAL, al);
@@ -1326,7 +1406,7 @@ int ssl3_get_key_exchange(SSL *s)
* Can't skip server key exchange if this is an ephemeral
* ciphersuite.
*/
- if (alg_k & (SSL_kEDH | SSL_kEECDH)) {
+ if (alg_k & (SSL_kDHE | SSL_kECDHE)) {
SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_UNEXPECTED_MESSAGE);
al = SSL_AD_UNEXPECTED_MESSAGE;
goto f_err;
@@ -1734,9 +1814,16 @@ int ssl3_get_key_exchange(SSL *s)
SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_LENGTH_TOO_SHORT);
goto f_err;
}
+ /*
+ * Check curve is one of our preferences, if not server has sent an
+ * invalid curve. ECParameters is 3 bytes.
+ */
+ if (!tls1_check_curve(s, p, 3)) {
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_WRONG_CURVE);
+ goto f_err;
+ }
- if ((*p != NAMED_CURVE_TYPE) ||
- ((curve_nid = tls1_ec_curve_id2nid(*(p + 2))) == 0)) {
+ if ((curve_nid = tls1_ec_curve_id2nid(*(p + 2))) == 0) {
al = SSL_AD_INTERNAL_ERROR;
SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,
SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS);
@@ -1824,29 +1911,16 @@ int ssl3_get_key_exchange(SSL *s)
/* if it was signed, check the signature */
if (pkey != NULL) {
- if (TLS1_get_version(s) >= TLS1_2_VERSION) {
- int sigalg;
+ if (SSL_USE_SIGALGS(s)) {
+ int rv;
if (2 > n) {
SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_LENGTH_TOO_SHORT);
goto f_err;
}
-
- sigalg = tls12_get_sigid(pkey);
- /* Should never happen */
- if (sigalg == -1) {
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+ rv = tls12_check_peer_sigalg(&md, s, p, pkey);
+ if (rv == -1)
goto err;
- }
- /* Check key type is consistent with signature */
- if (sigalg != (int)p[1]) {
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,
- SSL_R_WRONG_SIGNATURE_TYPE);
- al = SSL_AD_DECODE_ERROR;
- goto f_err;
- }
- md = tls12_get_hash(p[0]);
- if (md == NULL) {
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_UNKNOWN_DIGEST);
+ else if (rv == 0) {
goto f_err;
}
#ifdef SSL_DEBUG
@@ -1874,8 +1948,7 @@ int ssl3_get_key_exchange(SSL *s)
goto f_err;
}
#ifndef OPENSSL_NO_RSA
- if (pkey->type == EVP_PKEY_RSA
- && TLS1_get_version(s) < TLS1_2_VERSION) {
+ if (pkey->type == EVP_PKEY_RSA && !SSL_USE_SIGALGS(s)) {
int num;
unsigned int size;
@@ -1935,7 +2008,10 @@ int ssl3_get_key_exchange(SSL *s)
} else {
/* aNULL, aSRP or kPSK do not need public keys */
if (!(alg_a & (SSL_aNULL | SSL_aSRP)) && !(alg_k & SSL_kPSK)) {
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+ /* Might be wrong key type, check it */
+ if (ssl3_check_cert_and_algorithm(s))
+ /* Otherwise this shouldn't happen */
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
goto err;
}
/* still data left over */
@@ -2028,12 +2104,21 @@ int ssl3_get_certificate_request(SSL *s)
/* get the certificate types */
ctype_num = *(p++);
- if (ctype_num > SSL3_CT_NUMBER)
+ if (s->cert->ctypes) {
+ OPENSSL_free(s->cert->ctypes);
+ s->cert->ctypes = NULL;
+ }
+ if (ctype_num > SSL3_CT_NUMBER) {
+ /* If we exceed static buffer copy all to cert structure */
+ s->cert->ctypes = OPENSSL_malloc(ctype_num);
+ memcpy(s->cert->ctypes, p, ctype_num);
+ s->cert->ctype_num = (size_t)ctype_num;
ctype_num = SSL3_CT_NUMBER;
+ }
for (i = 0; i < ctype_num; i++)
s->s3->tmp.ctype[i] = p[i];
- p += ctype_num;
- if (TLS1_get_version(s) >= TLS1_2_VERSION) {
+ p += p[-1];
+ if (SSL_USE_SIGALGS(s)) {
n2s(p, llen);
/*
* Check we have enough room for signature algorithms and following
@@ -2045,12 +2130,22 @@ int ssl3_get_certificate_request(SSL *s)
SSL_R_DATA_LENGTH_TOO_LONG);
goto err;
}
- if ((llen & 1) || !tls1_process_sigalgs(s, p, llen)) {
+ /* Clear certificate digests and validity flags */
+ for (i = 0; i < SSL_PKEY_NUM; i++) {
+ s->cert->pkeys[i].digest = NULL;
+ s->cert->pkeys[i].valid_flags = 0;
+ }
+ if ((llen & 1) || !tls1_save_sigalgs(s, p, llen)) {
ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST,
SSL_R_SIGNATURE_ALGORITHMS_ERROR);
goto err;
}
+ if (!tls1_process_sigalgs(s)) {
+ ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
p += llen;
}
@@ -2339,9 +2434,28 @@ int ssl3_get_server_done(SSL *s)
return (ret);
}
+#ifndef OPENSSL_NO_DH
+static DH *get_server_static_dh_key(SESS_CERT *scert)
+{
+ DH *dh_srvr = NULL;
+ EVP_PKEY *spkey = NULL;
+ int idx = scert->peer_cert_type;
+
+ if (idx >= 0)
+ spkey = X509_get_pubkey(scert->peer_pkeys[idx].x509);
+ if (spkey) {
+ dh_srvr = EVP_PKEY_get1_DH(spkey);
+ EVP_PKEY_free(spkey);
+ }
+ if (dh_srvr == NULL)
+ SSLerr(SSL_F_GET_SERVER_STATIC_DH_KEY, ERR_R_INTERNAL_ERROR);
+ return dh_srvr;
+}
+#endif
+
int ssl3_send_client_key_exchange(SSL *s)
{
- unsigned char *p, *d;
+ unsigned char *p;
int n;
unsigned long alg_k;
#ifndef OPENSSL_NO_RSA
@@ -2361,8 +2475,7 @@ int ssl3_send_client_key_exchange(SSL *s)
#endif
if (s->state == SSL3_ST_CW_KEY_EXCH_A) {
- d = (unsigned char *)s->init_buf->data;
- p = &(d[4]);
+ p = ssl_handshake_start(s);
alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
@@ -2574,33 +2687,45 @@ int ssl3_send_client_key_exchange(SSL *s)
#ifndef OPENSSL_NO_DH
else if (alg_k & (SSL_kEDH | SSL_kDHr | SSL_kDHd)) {
DH *dh_srvr, *dh_clnt;
+ SESS_CERT *scert = s->session->sess_cert;
- if (s->session->sess_cert == NULL) {
+ if (scert == NULL) {
ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
SSL_R_UNEXPECTED_MESSAGE);
goto err;
}
- if (s->session->sess_cert->peer_dh_tmp != NULL)
- dh_srvr = s->session->sess_cert->peer_dh_tmp;
- else {
- /* we get them from the cert */
- ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
- SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
- SSL_R_UNABLE_TO_FIND_DH_PARAMETERS);
- goto err;
+ if (scert->peer_dh_tmp != NULL) {
+ dh_srvr = scert->peer_dh_tmp;
+ } else {
+ dh_srvr = get_server_static_dh_key(scert);
+ if (dh_srvr == NULL)
+ goto err;
}
- /* generate a new random key */
- if ((dh_clnt = DHparams_dup(dh_srvr)) == NULL) {
- SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_DH_LIB);
- goto err;
- }
- if (!DH_generate_key(dh_clnt)) {
- SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_DH_LIB);
- DH_free(dh_clnt);
- goto err;
+ if (s->s3->flags & TLS1_FLAGS_SKIP_CERT_VERIFY) {
+ /* Use client certificate key */
+ EVP_PKEY *clkey = s->cert->key->privatekey;
+ dh_clnt = NULL;
+ if (clkey)
+ dh_clnt = EVP_PKEY_get1_DH(clkey);
+ if (dh_clnt == NULL) {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+ ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ } else {
+ /* generate a new random key */
+ if ((dh_clnt = DHparams_dup(dh_srvr)) == NULL) {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_DH_LIB);
+ goto err;
+ }
+ if (!DH_generate_key(dh_clnt)) {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_DH_LIB);
+ DH_free(dh_clnt);
+ goto err;
+ }
}
/*
@@ -2609,6 +2734,8 @@ int ssl3_send_client_key_exchange(SSL *s)
*/
n = DH_compute_key(p, dh_srvr->pub_key, dh_clnt);
+ if (scert->peer_dh_tmp == NULL)
+ DH_free(dh_srvr);
if (n <= 0) {
SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_DH_LIB);
@@ -2625,11 +2752,15 @@ int ssl3_send_client_key_exchange(SSL *s)
/* clean up */
memset(p, 0, n);
- /* send off the data */
- n = BN_num_bytes(dh_clnt->pub_key);
- s2n(n, p);
- BN_bn2bin(dh_clnt->pub_key, p);
- n += 2;
+ if (s->s3->flags & TLS1_FLAGS_SKIP_CERT_VERIFY)
+ n = 0;
+ else {
+ /* send off the data */
+ n = BN_num_bytes(dh_clnt->pub_key);
+ s2n(n, p);
+ BN_bn2bin(dh_clnt->pub_key, p);
+ n += 2;
+ }
DH_free(dh_clnt);
}
@@ -3068,17 +3199,12 @@ int ssl3_send_client_key_exchange(SSL *s)
goto err;
}
- *(d++) = SSL3_MT_CLIENT_KEY_EXCHANGE;
- l2n3(n, d);
-
+ ssl_set_handshake_header(s, SSL3_MT_CLIENT_KEY_EXCHANGE, n);
s->state = SSL3_ST_CW_KEY_EXCH_B;
- /* number of bytes to write */
- s->init_num = n + 4;
- s->init_off = 0;
}
/* SSL3_ST_CW_KEY_EXCH_B */
- return (ssl3_do_write(s, SSL3_RT_HANDSHAKE));
+ return ssl_do_write(s);
err:
#ifndef OPENSSL_NO_ECDH
BN_CTX_free(bn_ctx);
@@ -3094,7 +3220,7 @@ int ssl3_send_client_key_exchange(SSL *s)
int ssl3_send_client_verify(SSL *s)
{
- unsigned char *p, *d;
+ unsigned char *p;
unsigned char data[MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH];
EVP_PKEY *pkey;
EVP_PKEY_CTX *pctx = NULL;
@@ -3106,8 +3232,7 @@ int ssl3_send_client_verify(SSL *s)
EVP_MD_CTX_init(&mctx);
if (s->state == SSL3_ST_CW_CERT_VRFY_A) {
- d = (unsigned char *)s->init_buf->data;
- p = &(d[4]);
+ p = ssl_handshake_start(s);
pkey = s->cert->key->privatekey;
/* Create context from key and test if sha1 is allowed as digest */
pctx = EVP_PKEY_CTX_new(pkey, NULL);
@@ -3116,7 +3241,7 @@ int ssl3_send_client_verify(SSL *s)
goto err;
}
if (EVP_PKEY_CTX_set_signature_md(pctx, EVP_sha1()) > 0) {
- if (TLS1_get_version(s) < TLS1_2_VERSION)
+ if (!SSL_USE_SIGALGS(s))
s->method->ssl3_enc->cert_verify_mac(s,
NID_sha1,
&(data
@@ -3128,7 +3253,7 @@ int ssl3_send_client_verify(SSL *s)
* For TLS v1.2 send signature algorithm and signature using agreed
* digest and cached handshake records.
*/
- if (TLS1_get_version(s) >= TLS1_2_VERSION) {
+ if (SSL_USE_SIGALGS(s)) {
long hdatalen = 0;
void *hdata;
const EVP_MD *md = s->cert->key->digest;
@@ -3212,16 +3337,12 @@ int ssl3_send_client_verify(SSL *s)
SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY, ERR_R_INTERNAL_ERROR);
goto err;
}
- *(d++) = SSL3_MT_CERTIFICATE_VERIFY;
- l2n3(n, d);
-
+ ssl_set_handshake_header(s, SSL3_MT_CERTIFICATE_VERIFY, n);
s->state = SSL3_ST_CW_CERT_VRFY_B;
- s->init_num = (int)n + 4;
- s->init_off = 0;
}
EVP_MD_CTX_cleanup(&mctx);
EVP_PKEY_CTX_free(pctx);
- return (ssl3_do_write(s, SSL3_RT_HANDSHAKE));
+ return ssl_do_write(s);
err:
EVP_MD_CTX_cleanup(&mctx);
EVP_PKEY_CTX_free(pctx);
@@ -3229,20 +3350,75 @@ int ssl3_send_client_verify(SSL *s)
return (-1);
}
+/*
+ * Check a certificate can be used for client authentication. Currently check
+ * cert exists, if we have a suitable digest for TLS 1.2 if static DH client
+ * certificates can be used and optionally checks suitability for Suite B.
+ */
+static int ssl3_check_client_certificate(SSL *s)
+{
+ unsigned long alg_k;
+ 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;
+ /*
+ * If strict mode check suitability of chain before using it. This also
+ * adjusts suite B digest if necessary.
+ */
+ if (s->cert->cert_flags & SSL_CERT_FLAGS_CHECK_TLS_STRICT &&
+ !tls1_check_chain(s, NULL, NULL, NULL, -2))
+ return 0;
+ alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
+ /* See if we can use client certificate for fixed DH */
+ if (alg_k & (SSL_kDHr | SSL_kDHd)) {
+ SESS_CERT *scert = s->session->sess_cert;
+ int i = scert->peer_cert_type;
+ EVP_PKEY *clkey = NULL, *spkey = NULL;
+ clkey = s->cert->key->privatekey;
+ /* If client key not DH assume it can be used */
+ if (EVP_PKEY_id(clkey) != EVP_PKEY_DH)
+ return 1;
+ if (i >= 0)
+ spkey = X509_get_pubkey(scert->peer_pkeys[i].x509);
+ if (spkey) {
+ /* Compare server and client parameters */
+ i = EVP_PKEY_cmp_parameters(clkey, spkey);
+ EVP_PKEY_free(spkey);
+ if (i != 1)
+ return 0;
+ }
+ s->s3->flags |= TLS1_FLAGS_SKIP_CERT_VERIFY;
+ }
+ return 1;
+}
+
int ssl3_send_client_certificate(SSL *s)
{
X509 *x509 = NULL;
EVP_PKEY *pkey = NULL;
int i;
- unsigned long l;
if (s->state == SSL3_ST_CW_CERT_A) {
- if ((s->cert == NULL) ||
- (s->cert->key->x509 == NULL) ||
- (s->cert->key->privatekey == NULL))
- s->state = SSL3_ST_CW_CERT_B;
- else
+ /* Let cert callback update client certificates if required */
+ if (s->cert->cert_cb) {
+ i = s->cert->cert_cb(s, s->cert->cert_cb_arg);
+ if (i < 0) {
+ s->rwstate = SSL_X509_LOOKUP;
+ return -1;
+ }
+ if (i == 0) {
+ ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ s->state = SSL_ST_ERR;
+ return 0;
+ }
+ s->rwstate = SSL_NOTHING;
+ }
+ if (ssl3_check_client_certificate(s))
s->state = SSL3_ST_CW_CERT_C;
+ else
+ s->state = SSL3_ST_CW_CERT_B;
}
/* We need to get a client cert */
@@ -3271,6 +3447,8 @@ int ssl3_send_client_certificate(SSL *s)
X509_free(x509);
if (pkey != NULL)
EVP_PKEY_free(pkey);
+ if (i && !ssl3_check_client_certificate(s))
+ i = 0;
if (i == 0) {
if (s->version == SSL3_VERSION) {
s->s3->tmp.cert_req = 0;
@@ -3287,20 +3465,17 @@ int ssl3_send_client_certificate(SSL *s)
if (s->state == SSL3_ST_CW_CERT_C) {
s->state = SSL3_ST_CW_CERT_D;
- l = ssl3_output_cert_chain(s,
- (s->s3->tmp.cert_req ==
- 2) ? NULL : s->cert->key->x509);
- if (!l) {
+ if (!ssl3_output_cert_chain(s,
+ (s->s3->tmp.cert_req ==
+ 2) ? NULL : s->cert->key)) {
SSLerr(SSL_F_SSL3_SEND_CLIENT_CERTIFICATE, ERR_R_INTERNAL_ERROR);
ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
s->state = SSL_ST_ERR;
return 0;
}
- s->init_num = (int)l;
- s->init_off = 0;
}
/* SSL3_ST_CW_CERT_D */
- return (ssl3_do_write(s, SSL3_RT_HANDSHAKE));
+ return ssl_do_write(s);
}
#define has_bits(i,m) (((i)&(m)) == (m))
@@ -3324,7 +3499,7 @@ int ssl3_check_cert_and_algorithm(SSL *s)
alg_a = s->s3->tmp.new_cipher->algorithm_auth;
/* we don't have a certificate */
- if ((alg_a & (SSL_aDH | SSL_aNULL | SSL_aKRB5)) || (alg_k & SSL_kPSK))
+ if ((alg_a & (SSL_aNULL | SSL_aKRB5)) || (alg_k & SSL_kPSK))
return (1);
sc = s->session->sess_cert;
@@ -3351,6 +3526,13 @@ int ssl3_check_cert_and_algorithm(SSL *s)
} else {
return 1;
}
+ } else if (alg_a & SSL_aECDSA) {
+ SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,
+ SSL_R_MISSING_ECDSA_SIGNING_CERT);
+ goto f_err;
+ } else if (alg_k & (SSL_kECDHr | SSL_kECDHe)) {
+ SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, SSL_R_MISSING_ECDH_CERT);
+ goto f_err;
}
#endif
pkey = X509_get_pubkey(sc->peer_pkeys[idx].x509);
@@ -3401,22 +3583,33 @@ int ssl3_check_cert_and_algorithm(SSL *s)
SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, ERR_R_INTERNAL_ERROR);
goto f_err;
}
- if ((alg_k & SSL_kDHr) && !has_bits(i, EVP_PK_DH | EVP_PKS_RSA)) {
+ if ((alg_k & SSL_kDHr) && !SSL_USE_SIGALGS(s) &&
+ !has_bits(i, EVP_PK_DH | EVP_PKS_RSA)) {
SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,
SSL_R_MISSING_DH_RSA_CERT);
goto f_err;
}
# ifndef OPENSSL_NO_DSA
- if ((alg_k & SSL_kDHd) && !has_bits(i, EVP_PK_DH | EVP_PKS_DSA)) {
+ if ((alg_k & SSL_kDHd) && !SSL_USE_SIGALGS(s) &&
+ !has_bits(i, EVP_PK_DH | EVP_PKS_DSA)) {
SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,
SSL_R_MISSING_DH_DSA_CERT);
goto f_err;
}
# endif
- /* Check DHE only: static DH not implemented. */
- if (alg_k & SSL_kEDH) {
- int dh_size = BN_num_bits(dh->p);
+ if (alg_k & (SSL_kDHE | SSL_kDHr | SSL_kDHd)) {
+ int dh_size;
+ if (alg_k & SSL_kDHE) {
+ dh_size = BN_num_bits(dh->p);
+ } else {
+ DH *dh_srvr = get_server_static_dh_key(sc);
+ if (dh_srvr == NULL)
+ goto f_err;
+ dh_size = BN_num_bits(dh_srvr->p);
+ DH_free(dh_srvr);
+ }
+
if ((!SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) && dh_size < 1024)
|| (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) && dh_size < 512)) {
SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, SSL_R_DH_KEY_TOO_SMALL);
@@ -3444,7 +3637,7 @@ int ssl3_check_cert_and_algorithm(SSL *s)
} else
#endif
#ifndef OPENSSL_NO_DH
- if (alg_k & SSL_kEDH) {
+ if (alg_k & SSL_kDHE) {
if (BN_num_bits(dh->p) >
SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)) {
/* We have a temporary DH key but it's too large. */