# include <openssl/engine.h>
#endif
+static int ssl_set_version(SSL *s);
static int ca_dn_cmp(const X509_NAME *const *a, const X509_NAME *const *b);
-#ifndef OPENSSL_NO_TLSEXT
static int ssl3_check_finished(SSL *s);
-#endif
+static int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk,
+ unsigned char *p,
+ int (*put_cb) (const SSL_CIPHER *,
+ unsigned char *));
-#ifndef OPENSSL_NO_SSL3_METHOD
-static const SSL_METHOD *ssl3_get_client_method(int ver)
-{
- if (ver == SSL3_VERSION)
- return (SSLv3_client_method());
- else
- return (NULL);
-}
-IMPLEMENT_ssl3_meth_func(SSLv3_client_method,
- ssl_undefined_function,
- ssl3_connect, ssl3_get_client_method)
-#endif
int ssl3_connect(SSL *s)
{
BUF_MEM *buf = NULL;
goto end;
}
- if (!ssl_security(s, SSL_SECOP_VERSION, 0, s->version, NULL)) {
+ if (s->version != TLS_ANY_VERSION &&
+ !ssl_security(s, SSL_SECOP_VERSION, 0, s->version, NULL)) {
SSLerr(SSL_F_SSL3_CONNECT, SSL_R_VERSION_TOO_LOW);
return -1;
}
if (s->hit) {
s->state = SSL3_ST_CR_FINISHED_A;
-#ifndef OPENSSL_NO_TLSEXT
if (s->tlsext_ticket_expected) {
/* receive renewed session ticket */
s->state = SSL3_ST_CR_SESSION_TICKET_A;
}
-#endif
} else {
s->state = SSL3_ST_CR_CERT_A;
}
break;
case SSL3_ST_CR_CERT_A:
case SSL3_ST_CR_CERT_B:
-#ifndef OPENSSL_NO_TLSEXT
/* Noop (ret = 0) for everything but EAP-FAST. */
ret = ssl3_check_finished(s);
if (ret < 0)
s->init_num = 0;
break;
}
-#endif
+
/* Check if it is anon DH/ECDH, SRP auth */
/* or PSK */
if (!
(s->s3->tmp.
new_cipher->algorithm_auth & (SSL_aNULL | SSL_aSRP))
-&& !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)) {
+ && !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)) {
ret = ssl3_get_server_certificate(s);
if (ret <= 0)
goto end;
-#ifndef OPENSSL_NO_TLSEXT
+
if (s->tlsext_status_expected)
s->state = SSL3_ST_CR_CERT_STATUS_A;
else
skip = 1;
s->state = SSL3_ST_CR_KEY_EXCH_A;
}
-#else
- } else
- skip = 1;
- s->state = SSL3_ST_CR_KEY_EXCH_A;
-#endif
s->init_num = 0;
break;
if (ret <= 0)
goto end;
-#if defined(OPENSSL_NO_TLSEXT) || defined(OPENSSL_NO_NEXTPROTONEG)
+#if defined(OPENSSL_NO_NEXTPROTONEG)
s->state = SSL3_ST_CW_FINISHED_A;
#else
if (s->s3->next_proto_neg_seen)
break;
-#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
+#if !defined(OPENSSL_NO_NEXTPROTONEG)
case SSL3_ST_CW_NEXT_PROTO_A:
case SSL3_ST_CW_NEXT_PROTO_B:
ret = ssl3_send_next_proto(s);
s->s3->delay_buf_pop_ret = 0;
}
} else {
-#ifndef OPENSSL_NO_TLSEXT
/*
* Allow NewSessionTicket if ticket expected
*/
if (s->tlsext_ticket_expected)
s->s3->tmp.next_state = SSL3_ST_CR_SESSION_TICKET_A;
else
-#endif
-
s->s3->tmp.next_state = SSL3_ST_CR_FINISHED_A;
}
s->init_num = 0;
break;
-#ifndef OPENSSL_NO_TLSEXT
case SSL3_ST_CR_SESSION_TICKET_A:
case SSL3_ST_CR_SESSION_TICKET_B:
ret = ssl3_get_new_session_ticket(s);
s->state = SSL3_ST_CR_KEY_EXCH_A;
s->init_num = 0;
break;
-#endif
case SSL3_ST_CR_FINISHED_A:
case SSL3_ST_CR_FINISHED_B:
return (ret);
}
+/*
+ * Work out what version we should be using for the initial ClientHello if
+ * the version is currently set to (D)TLS_ANY_VERSION.
+ * Returns 1 on success
+ * Returns 0 on error
+ */
+static int ssl_set_version(SSL *s)
+{
+ unsigned long mask, options = s->options;
+
+ if (s->method->version == TLS_ANY_VERSION) {
+ /*
+ * SSL_OP_NO_X disables all protocols above X *if* there are
+ * some protocols below X enabled. This is required in order
+ * to maintain "version capability" vector contiguous. So
+ * that if application wants to disable TLS1.0 in favour of
+ * TLS1>=1, it would be insufficient to pass SSL_NO_TLSv1, the
+ * answer is SSL_OP_NO_TLSv1|SSL_OP_NO_SSLv3.
+ */
+ mask = SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1
+#if !defined(OPENSSL_NO_SSL3)
+ | SSL_OP_NO_SSLv3
+#endif
+ ;
+#if !defined(OPENSSL_NO_TLS1_2_CLIENT)
+ if (options & SSL_OP_NO_TLSv1_2) {
+ if ((options & mask) != mask) {
+ s->version = TLS1_1_VERSION;
+ } else {
+ SSLerr(SSL_F_SSL_SET_VERSION, SSL_R_NO_PROTOCOLS_AVAILABLE);
+ return 0;
+ }
+ } else {
+ s->version = TLS1_2_VERSION;
+ }
+#else
+ if ((options & mask) == mask) {
+ SSLerr(SSL_F_SSL_SET_VERSION, SSL_R_NO_PROTOCOLS_AVAILABLE);
+ return 0;
+ }
+ s->version = TLS1_1_VERSION;
+#endif
+
+ mask &= ~SSL_OP_NO_TLSv1_1;
+ if ((options & SSL_OP_NO_TLSv1_1) && (options & mask) != mask)
+ s->version = TLS1_VERSION;
+ mask &= ~SSL_OP_NO_TLSv1;
+#if !defined(OPENSSL_NO_SSL3)
+ if ((options & SSL_OP_NO_TLSv1) && (options & mask) != mask)
+ s->version = SSL3_VERSION;
+#endif
+
+ if (s->version != TLS1_2_VERSION && tls1_suiteb(s)) {
+ SSLerr(SSL_F_SSL_SET_VERSION,
+ SSL_R_ONLY_TLS_1_2_ALLOWED_IN_SUITEB_MODE);
+ return 0;
+ }
+
+ if (s->version == SSL3_VERSION && FIPS_mode()) {
+ SSLerr(SSL_F_SSL_SET_VERSION, SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE);
+ return 0;
+ }
+
+ } else if (s->method->version == DTLS_ANY_VERSION) {
+ /* Determine which DTLS version to use */
+ /* If DTLS 1.2 disabled correct the version number */
+ if (options & SSL_OP_NO_DTLSv1_2) {
+ if (tls1_suiteb(s)) {
+ SSLerr(SSL_F_SSL_SET_VERSION,
+ SSL_R_ONLY_DTLS_1_2_ALLOWED_IN_SUITEB_MODE);
+ return 0;
+ }
+ /*
+ * Disabling all versions is silly: return an error.
+ */
+ if (options & SSL_OP_NO_DTLSv1) {
+ SSLerr(SSL_F_SSL_SET_VERSION, SSL_R_WRONG_SSL_VERSION);
+ return 0;
+ }
+ /*
+ * 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;
+
+ return 1;
+}
+
int ssl3_client_hello(SSL *s)
{
unsigned char *buf;
int j;
SSL_COMP *comp;
#endif
- unsigned long mask, options = s->options;
buf = (unsigned char *)s->init_buf->data;
if (s->state == SSL3_ST_CW_CLNT_HELLO_A) {
SSL_SESSION *sess = s->session;
- if (s->method->version == TLS_ANY_VERSION ) {
- /*
- * SSL_OP_NO_X disables all protocols above X *if* there are
- * some protocols below X enabled. This is required in order
- * to maintain "version capability" vector contiguous. So
- * that if application wants to disable TLS1.0 in favour of
- * TLS1>=1, it would be insufficient to pass SSL_NO_TLSv1, the
- * answer is SSL_OP_NO_TLSv1|SSL_OP_NO_SSLv3.
- */
- mask = SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1
-#if !defined(OPENSSL_NO_SSL3)
- | SSL_OP_NO_SSLv3
-#endif
- ;
-#if !defined(OPENSSL_NO_TLS1_2_CLIENT)
- s->version = TLS1_2_VERSION;
-
- if ((options & SSL_OP_NO_TLSv1_2) && (options & mask) != mask)
- s->version = TLS1_1_VERSION;
-#else
- s->version = TLS1_1_VERSION;
-#endif
- mask &= ~SSL_OP_NO_TLSv1_1;
- if ((options & SSL_OP_NO_TLSv1_1) && (options & mask) != mask)
- s->version = TLS1_VERSION;
- mask &= ~SSL_OP_NO_TLSv1;
-#if !defined(OPENSSL_NO_SSL3)
- if ((options & SSL_OP_NO_TLSv1) && (options & mask) != mask)
- s->version = SSL3_VERSION;
- mask &= ~SSL_OP_NO_SSLv3;
-#endif
- s->client_version = s->version;
- } else if (s->method->version == DTLS_ANY_VERSION) {
- /* Determine which DTLS version to use */
- /* 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;
- }
+ /* Work out what SSL/TLS/DTLS version to use */
+ if (ssl_set_version(s) == 0)
+ goto err;
if ((sess == NULL) || (sess->ssl_version != s->version) ||
-#ifdef OPENSSL_NO_TLSEXT
- !sess->session_id_length ||
-#else
/*
* In the case of EAP-FAST, we can have a pre-shared
* "ticket" without a session ID.
*/
(!sess->session_id_length && !sess->tlsext_tick) ||
-#endif
(sess->not_resumable)) {
if (!ssl_get_new_session(s, 0))
goto err;
#endif
*(p++) = 0; /* Add the NULL method */
-#ifndef OPENSSL_NO_TLSEXT
/* TLS extensions */
if (ssl_prepare_clienthello_tlsext(s) <= 0) {
SSLerr(SSL_F_SSL3_CLIENT_HELLO, SSL_R_CLIENTHELLO_TLSEXT);
SSLerr(SSL_F_SSL3_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
goto err;
}
-#endif
l = p - d;
if (!ssl_set_handshake_header(s, SSL3_MT_CLIENT_HELLO, l)) {
{
STACK_OF(SSL_CIPHER) *sk;
const SSL_CIPHER *c;
- CERT *ct = s->cert;
unsigned char *p, *d;
int i, al = SSL_AD_INTERNAL_ERROR, ok;
unsigned int j;
* 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;
+ s->first_packet = 1;
n = s->method->ssl_get_message(s,
SSL3_ST_CR_SRVR_HELLO_A,
if (!ok)
return ((int)n);
+ s->first_packet = 0;
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;
if (FIPS_mode()) {
SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,
SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE);
- goto err;
+ al = SSL_AD_PROTOCOL_VERSION;
+ goto f_err;
}
s->method = SSLv3_client_method();
} else
s->method = TLSv1_2_client_method();
} else {
SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_UNSUPPORTED_PROTOCOL);
- goto err;
+ al = SSL_AD_PROTOCOL_VERSION;
+ goto f_err;
}
s->session->ssl_version = s->version = s->method->version;
if (!ssl_security(s, SSL_SECOP_VERSION, 0, s->version, NULL)) {
SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_VERSION_TOO_LOW);
- goto err;
+ al = SSL_AD_PROTOCOL_VERSION;
+ goto f_err;
}
} else if (s->method->version == DTLS_ANY_VERSION) {
/* Work out correct protocol version to use */
al = SSL_AD_PROTOCOL_VERSION;
goto f_err;
}
- s->version = s->method->version;
+ s->session->ssl_version = s->version = s->method->version;
} else if ((p[0] != (s->version >> 8)) || (p[1] != (s->version & 0xff))) {
SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_WRONG_SSL_VERSION);
s->version = (s->version & 0xff00) | p[1];
SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_SSL3_SESSION_ID_TOO_LONG);
goto f_err;
}
-#ifndef OPENSSL_NO_TLSEXT
+
/*
* Check if we can resume the session based on external pre-shared secret.
* EAP-FAST (RFC 4851) supports two types of session resumption.
goto f_err;
}
}
-#endif /* OPENSSL_NO_TLSEXT */
if (j != 0 && j == s->session->session_id_length
&& memcmp(p, s->session->session_id, j) == 0) {
}
/* Set version disabled mask now we know version */
if (!SSL_USE_TLS1_2_CIPHERS(s))
- ct->mask_ssl = SSL_TLSV1_2;
+ s->s3->tmp.mask_ssl = SSL_TLSV1_2;
else
- ct->mask_ssl = 0;
+ s->s3->tmp.mask_ssl = 0;
/*
* If it is a disabled cipher we didn't send it in client hello, so
* return an error.
}
#endif
-#ifndef OPENSSL_NO_TLSEXT
/* TLS extensions */
if (!ssl_parse_serverhello_tlsext(s, &p, d, n)) {
SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_PARSE_TLSEXT);
goto err;
}
-#endif
if (p != (d + n)) {
/* wrong packet length */
SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
goto err;
}
+
+ if (EVP_PKEY_bits(pkey) <= SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)) {
+ al = SSL_AD_UNEXPECTED_MESSAGE;
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_UNEXPECTED_MESSAGE);
+ goto f_err;
+ }
+
s->session->sess_cert->peer_rsa_tmp = rsa;
rsa = NULL;
}
}
/* 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;
+ s->s3->tmp.md[i] = NULL;
+ s->s3->tmp.valid_flags[i] = 0;
}
if ((llen & 1) || !tls1_save_sigalgs(s, p, llen)) {
ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
return (X509_NAME_cmp(*a, *b));
}
-#ifndef OPENSSL_NO_TLSEXT
int ssl3_get_new_session_ticket(SSL *s)
{
int ok, al, ret = 0, ticklen;
}
p = d = (unsigned char *)s->init_msg;
+
+ if (s->session->session_id_length > 0) {
+ int i = s->session_ctx->session_cache_mode;
+ SSL_SESSION *new_sess;
+ /*
+ * We reused an existing session, so we need to replace it with a new
+ * one
+ */
+ if (i & SSL_SESS_CACHE_CLIENT) {
+ /*
+ * Remove the old session from the cache
+ */
+ if (i & SSL_SESS_CACHE_NO_INTERNAL_STORE) {
+ if (s->session_ctx->remove_session_cb != NULL)
+ s->session_ctx->remove_session_cb(s->session_ctx,
+ s->session);
+ } else {
+ /* We carry on if this fails */
+ SSL_CTX_remove_session(s->session_ctx, s->session);
+ }
+ }
+
+ if ((new_sess = ssl_session_dup(s->session, 0)) == 0) {
+ al = SSL_AD_INTERNAL_ERROR;
+ SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET, ERR_R_MALLOC_FAILURE);
+ goto f_err;
+ }
+
+ SSL_SESSION_free(s->session);
+ s->session = new_sess;
+ }
+
n2l(p, s->session->tlsext_tick_lifetime_hint);
n2s(p, ticklen);
/* ticket_lifetime_hint + ticket_length + ticket */
s->state = SSL_ST_ERR;
return (-1);
}
-#endif
int ssl3_get_server_done(SSL *s)
{
}
DH_free(dh_clnt);
-
- /* perhaps clean things up a bit EAY EAY EAY EAY */
}
#endif
#endif
/* If we haven't written everything save PMS */
if (n <= 0) {
- s->cert->pms = pms;
- s->cert->pmslen = pmslen;
+ s->s3->tmp.pms = pms;
+ s->s3->tmp.pmslen = pmslen;
} else {
/* If we don't have a PMS restore */
if (pms == NULL) {
- pms = s->cert->pms;
- pmslen = s->cert->pmslen;
+ pms = s->s3->tmp.pms;
+ pmslen = s->s3->tmp.pmslen;
}
if (pms == NULL) {
ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
session->master_key,
pms, pmslen);
OPENSSL_clear_free(pms, pmslen);
- s->cert->pms = NULL;
+ s->s3->tmp.pms = NULL;
if (s->session->master_key_length < 0) {
ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
err:
OPENSSL_clear_free(pms, pmslen);
- s->cert->pms = NULL;
+ s->s3->tmp.pms = NULL;
#ifndef OPENSSL_NO_EC
BN_CTX_free(bn_ctx);
OPENSSL_free(encodedPoint);
if (SSL_USE_SIGALGS(s)) {
long hdatalen = 0;
void *hdata;
- const EVP_MD *md = s->cert->key->digest;
+ const EVP_MD *md = s->s3->tmp.md[s->cert->key - s->cert->pkeys];
hdatalen = BIO_get_mem_data(s->s3->handshake_buffer, &hdata);
if (hdatalen <= 0 || !tls12_get_sigandhash(p, pkey, md)) {
SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY, ERR_R_INTERNAL_ERROR);
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)
+ if (SSL_USE_SIGALGS(s) && !s->s3->tmp.md[s->cert->key - s->cert->pkeys])
return 0;
/*
* If strict mode check suitability of chain before using it. This also
int i, idx;
long alg_k, alg_a;
EVP_PKEY *pkey = NULL;
+ int pkey_bits;
SESS_CERT *sc;
#ifndef OPENSSL_NO_RSA
RSA *rsa;
#ifndef OPENSSL_NO_DH
DH *dh;
#endif
+ int al = SSL_AD_HANDSHAKE_FAILURE;
alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
alg_a = s->s3->tmp.new_cipher->algorithm_auth;
}
#endif
pkey = X509_get_pubkey(sc->peer_pkeys[idx].x509);
+ pkey_bits = EVP_PKEY_bits(pkey);
i = X509_certificate_type(sc->peer_pkeys[idx].x509, pkey);
EVP_PKEY_free(pkey);
}
#endif
#ifndef OPENSSL_NO_RSA
- if ((alg_k & SSL_kRSA) &&
- !(has_bits(i, EVP_PK_RSA | EVP_PKT_ENC) || (rsa != NULL))) {
- SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,
- SSL_R_MISSING_RSA_ENCRYPTING_CERT);
- goto f_err;
+ if (alg_k & SSL_kRSA) {
+ if (!SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) &&
+ !has_bits(i, EVP_PK_RSA | EVP_PKT_ENC)) {
+ SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,
+ SSL_R_MISSING_RSA_ENCRYPTING_CERT);
+ goto f_err;
+ } else if (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher)) {
+ if (pkey_bits <= SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)) {
+ if (!has_bits(i, EVP_PK_RSA | EVP_PKT_ENC)) {
+ SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,
+ SSL_R_MISSING_RSA_ENCRYPTING_CERT);
+ goto f_err;
+ }
+ if (rsa != NULL) {
+ /* server key exchange is not allowed. */
+ al = SSL_AD_INTERNAL_ERROR;
+ SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, ERR_R_INTERNAL_ERROR);
+ goto f_err;
+ }
+ }
+ }
}
#endif
#ifndef OPENSSL_NO_DH
- if ((alg_k & SSL_kDHE) &&
- !(has_bits(i, EVP_PK_DH | EVP_PKT_EXCH) || (dh != NULL))) {
- SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, SSL_R_MISSING_DH_KEY);
+ if ((alg_k & SSL_kDHE) && (dh == NULL)) {
+ al = SSL_AD_INTERNAL_ERROR;
+ SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, ERR_R_INTERNAL_ERROR);
goto f_err;
} else if ((alg_k & SSL_kDHr) && !SSL_USE_SIGALGS(s) &&
!has_bits(i, EVP_PK_DH | EVP_PKS_RSA)) {
# endif
#endif
- if (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) && !has_bits(i, EVP_PKT_EXP)) {
+ if (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) &&
+ pkey_bits > SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)) {
#ifndef OPENSSL_NO_RSA
if (alg_k & SSL_kRSA) {
- if (rsa == NULL
- || RSA_size(rsa) * 8 >
+ if (rsa == NULL) {
+ SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,
+ SSL_R_MISSING_EXPORT_TMP_RSA_KEY);
+ goto f_err;
+ } else if (RSA_bits(rsa) >
SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)) {
+ /* We have a temporary RSA key but it's too large. */
+ al = SSL_AD_EXPORT_RESTRICTION;
SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,
SSL_R_MISSING_EXPORT_TMP_RSA_KEY);
goto f_err;
} else
#endif
#ifndef OPENSSL_NO_DH
- if (alg_k & (SSL_kDHE | SSL_kDHr | SSL_kDHd)) {
- if (dh == NULL
- || DH_size(dh) * 8 >
+ if (alg_k & SSL_kDHE) {
+ if (DH_bits(dh) >
SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)) {
+ /* We have a temporary DH key but it's too large. */
+ al = SSL_AD_EXPORT_RESTRICTION;
SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,
SSL_R_MISSING_EXPORT_TMP_DH_KEY);
goto f_err;
}
+ } else if (alg_k & (SSL_kDHr | SSL_kDHd)) {
+ /* The cert should have had an export DH key. */
+ al = SSL_AD_EXPORT_RESTRICTION;
+ SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,
+ SSL_R_MISSING_EXPORT_TMP_DH_KEY);
+ goto f_err;
} else
#endif
{
}
return (1);
f_err:
- ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
+ ssl3_send_alert(s, SSL3_AL_FATAL, al);
err:
return (0);
}
-#ifndef OPENSSL_NO_TLSEXT
/*
* Normally, we can tell if the server is resuming the session from
* the session ID. EAP-FAST (RFC 4851), however, relies on the next server
return 0;
}
-# ifndef OPENSSL_NO_NEXTPROTONEG
+#ifndef OPENSSL_NO_NEXTPROTONEG
int ssl3_send_next_proto(SSL *s)
{
unsigned int len, padding_len;
return ssl3_do_write(s, SSL3_RT_HANDSHAKE);
}
-# endif
#endif
int ssl_do_client_cert_cb(SSL *s, X509 **px509, EVP_PKEY **ppkey)
i = s->ctx->client_cert_cb(s, px509, ppkey);
return i;
}
+
+int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk,
+ unsigned char *p,
+ int (*put_cb) (const SSL_CIPHER *,
+ unsigned char *))
+{
+ int i, j = 0;
+ SSL_CIPHER *c;
+ unsigned char *q;
+ int empty_reneg_info_scsv = !s->renegotiate;
+ /* Set disabled masks for this session */
+ ssl_set_client_disabled(s);
+
+ if (sk == NULL)
+ return (0);
+ q = p;
+ if (put_cb == NULL)
+ put_cb = s->method->put_cipher_by_char;
+
+ for (i = 0; i < sk_SSL_CIPHER_num(sk); i++) {
+ c = sk_SSL_CIPHER_value(sk, i);
+ /* Skip disabled ciphers */
+ if (ssl_cipher_disabled(s, c, SSL_SECOP_CIPHER_SUPPORTED))
+ continue;
+#ifdef OPENSSL_SSL_DEBUG_BROKEN_PROTOCOL
+ if (c->id == SSL3_CK_SCSV) {
+ if (!empty_reneg_info_scsv)
+ continue;
+ else
+ empty_reneg_info_scsv = 0;
+ }
+#endif
+ j = put_cb(c, p);
+ p += j;
+ }
+ /*
+ * If p == q, no ciphers; caller indicates an error. Otherwise, add
+ * applicable SCSVs.
+ */
+ if (p != q) {
+ if (empty_reneg_info_scsv) {
+ static SSL_CIPHER scsv = {
+ 0, NULL, SSL3_CK_SCSV, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+ j = put_cb(&scsv, p);
+ p += j;
+#ifdef OPENSSL_RI_DEBUG
+ fprintf(stderr,
+ "TLS_EMPTY_RENEGOTIATION_INFO_SCSV sent by client\n");
+#endif
+ }
+ if (s->mode & SSL_MODE_SEND_FALLBACK_SCSV) {
+ static SSL_CIPHER scsv = {
+ 0, NULL, SSL3_CK_FALLBACK_SCSV, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+ j = put_cb(&scsv, p);
+ p += j;
+ }
+ }
+
+ return (p - q);
+}