*/
#include <stdio.h>
+#include <time.h>
#include "../ssl_locl.h"
#include "statem_locl.h"
#include <openssl/buffer.h>
return 1;
}
break;
+
+ case TLS_ST_OK:
+ if (mt == SSL3_MT_NEWSESSION_TICKET) {
+ st->hand_state = TLS_ST_CR_SESSION_TICKET;
+ return 1;
+ }
+ break;
}
/* No valid transition found */
return 1;
}
break;
+
+ case TLS_ST_OK:
+ if (mt == SSL3_MT_HELLO_REQUEST) {
+ st->hand_state = TLS_ST_CR_HELLO_REQ;
+ return 1;
+ }
+ break;
}
err:
st->hand_state = TLS_ST_CW_FINISHED;
return WRITE_TRAN_CONTINUE;
+ case TLS_ST_CR_SESSION_TICKET:
case TLS_ST_CW_FINISHED:
st->hand_state = TLS_ST_OK;
ossl_statem_set_in_init(s, 0);
return WRITE_TRAN_CONTINUE;
+
+ case TLS_ST_OK:
+ /* Just go straight to trying to read from the server */
+ return WRITE_TRAN_FINISHED;
}
}
return WRITE_TRAN_ERROR;
case TLS_ST_OK:
+ if (!s->renegotiate) {
+ /*
+ * We haven't requested a renegotiation ourselves so we must have
+ * received a message from the server. Better read it.
+ */
+ return WRITE_TRAN_FINISHED;
+ }
/* Renegotiation - fall through */
case TLS_ST_BEFORE:
st->hand_state = TLS_ST_CW_CLNT_HELLO;
ossl_statem_set_in_init(s, 0);
return WRITE_TRAN_CONTINUE;
}
+
+ case TLS_ST_CR_HELLO_REQ:
+ /*
+ * If we can renegotiate now then do so, otherwise wait for a more
+ * convenient time.
+ */
+ if (ssl3_renegotiate_check(s, 1)) {
+ if (!tls_setup_handshake(s)) {
+ ossl_statem_set_error(s);
+ return WRITE_TRAN_ERROR;
+ }
+ st->hand_state = TLS_ST_CW_CLNT_HELLO;
+ return WRITE_TRAN_CONTINUE;
+ }
+ st->hand_state = TLS_ST_OK;
+ ossl_statem_set_in_init(s, 0);
+ return WRITE_TRAN_CONTINUE;
}
}
break;
case TLS_ST_OK:
- return tls_finish_handshake(s, wst);
+ return tls_finish_handshake(s, wst, 1);
}
return WORK_FINISHED_CONTINUE;
case TLS_ST_CR_FINISHED:
return tls_process_finished(s, pkt);
+ case TLS_ST_CR_HELLO_REQ:
+ return tls_process_hello_req(s, pkt);
+
case TLS_ST_CR_ENCRYPTED_EXTENSIONS:
return tls_process_encrypted_extensions(s, pkt);
}
}
/* else use the pre-loaded session */
+ /* This is a real handshake so make sure we clean it up at the end */
+ s->statem.cleanuphand = 1;
+
p = s->s3->client_random;
/*
}
/* Session ID */
- if (s->new_session)
+ if (s->new_session || s->session->ssl_version == TLS1_3_VERSION)
sess_id_len = 0;
else
sess_id_len = s->session->session_id_length;
goto f_err;
}
+ /* We do this immediately so we know what format the ServerHello is in */
protverr = ssl_choose_client_version(s, sversion);
if (protverr != 0) {
al = SSL_AD_PROTOCOL_VERSION;
goto f_err;
}
- s->hit = 0;
-
/* Get the session-id. */
if (!SSL_IS_TLS13(s)) {
if (!PACKET_get_length_prefixed_1(pkt, &session_id)) {
goto f_err;
}
- /*
- * Check if we can resume the session based on external pre-shared secret.
- * EAP-FAST (RFC 4851) supports two types of session resumption.
- * Resumption based on server-side state works with session IDs.
- * Resumption based on pre-shared Protected Access Credentials (PACs)
- * works by overriding the SessionTicket extension at the application
- * layer, and does not send a session ID. (We do not know whether EAP-FAST
- * servers would honour the session ID.) Therefore, the session ID alone
- * is not a reliable indicator of session resumption, so we first check if
- * we can resume, and later peek at the next handshake message to see if the
- * server wants to resume.
- */
- if (s->version >= TLS1_VERSION && !SSL_IS_TLS13(s)
- && s->ext.session_secret_cb != NULL && s->session->ext.tick) {
- const SSL_CIPHER *pref_cipher = NULL;
+ if (!SSL_IS_TLS13(s)) {
+ if (!PACKET_get_1(pkt, &compression)) {
+ SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_LENGTH_MISMATCH);
+ al = SSL_AD_DECODE_ERROR;
+ goto f_err;
+ }
+ } else {
+ compression = 0;
+ }
+
+ /* TLS extensions */
+ if (PACKET_remaining(pkt) == 0) {
+ PACKET_null_init(&extpkt);
+ } else if (!PACKET_as_length_prefixed_2(pkt, &extpkt)) {
+ al = SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_BAD_LENGTH);
+ goto f_err;
+ }
+
+ context = SSL_IS_TLS13(s) ? EXT_TLS1_3_SERVER_HELLO
+ : EXT_TLS1_2_SERVER_HELLO;
+ if (!tls_collect_extensions(s, &extpkt, context, &extensions, &al))
+ goto f_err;
+
+ s->hit = 0;
+
+ if (SSL_IS_TLS13(s)) {
+ /* This will set s->hit if we are resuming */
+ if (!tls_parse_extension(s, TLSEXT_IDX_psk,
+ EXT_TLS1_3_SERVER_HELLO,
+ extensions, NULL, 0, &al))
+ goto f_err;
+ } else {
/*
- * s->session->master_key_length is a size_t, but this is an int for
- * backwards compat reasons
+ * Check if we can resume the session based on external pre-shared
+ * secret. EAP-FAST (RFC 4851) supports two types of session resumption.
+ * Resumption based on server-side state works with session IDs.
+ * Resumption based on pre-shared Protected Access Credentials (PACs)
+ * works by overriding the SessionTicket extension at the application
+ * layer, and does not send a session ID. (We do not know whether
+ * EAP-FAST servers would honour the session ID.) Therefore, the session
+ * ID alone is not a reliable indicator of session resumption, so we
+ * first check if we can resume, and later peek at the next handshake
+ * message to see if the server wants to resume.
*/
- int master_key_length;
- master_key_length = sizeof(s->session->master_key);
- if (s->ext.session_secret_cb(s, s->session->master_key,
- &master_key_length,
- NULL, &pref_cipher,
- s->ext.session_secret_cb_arg)
- && master_key_length > 0) {
- s->session->master_key_length = master_key_length;
- s->session->cipher = pref_cipher ?
- pref_cipher : ssl_get_cipher_by_char(s, cipherchars);
- } else {
- SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, ERR_R_INTERNAL_ERROR);
- al = SSL_AD_INTERNAL_ERROR;
- goto f_err;
+ if (s->version >= TLS1_VERSION
+ && s->ext.session_secret_cb != NULL && s->session->ext.tick) {
+ const SSL_CIPHER *pref_cipher = NULL;
+ /*
+ * s->session->master_key_length is a size_t, but this is an int for
+ * backwards compat reasons
+ */
+ int master_key_length;
+ master_key_length = sizeof(s->session->master_key);
+ if (s->ext.session_secret_cb(s, s->session->master_key,
+ &master_key_length,
+ NULL, &pref_cipher,
+ s->ext.session_secret_cb_arg)
+ && master_key_length > 0) {
+ s->session->master_key_length = master_key_length;
+ s->session->cipher = pref_cipher ?
+ pref_cipher : ssl_get_cipher_by_char(s, cipherchars);
+ } else {
+ SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, ERR_R_INTERNAL_ERROR);
+ al = SSL_AD_INTERNAL_ERROR;
+ goto f_err;
+ }
}
+
+ if (session_id_len != 0
+ && session_id_len == s->session->session_id_length
+ && memcmp(PACKET_data(&session_id), s->session->session_id,
+ session_id_len) == 0)
+ s->hit = 1;
}
- if (session_id_len != 0 && session_id_len == s->session->session_id_length
- && memcmp(PACKET_data(&session_id), s->session->session_id,
- session_id_len) == 0) {
+ if (s->hit) {
if (s->sid_ctx_length != s->session->sid_ctx_length
- || memcmp(s->session->sid_ctx, s->sid_ctx, s->sid_ctx_length)) {
+ || memcmp(s->session->sid_ctx, s->sid_ctx, s->sid_ctx_length)) {
/* actually a client application bug */
al = SSL_AD_ILLEGAL_PARAMETER;
SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO,
SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT);
goto f_err;
}
- s->hit = 1;
} else {
/*
* If we were trying for session-id reuse but the server
- * didn't echo the ID, make a new SSL_SESSION.
+ * didn't resume, make a new SSL_SESSION.
* In the case of EAP-FAST and PAC, we do not send a session ID,
* so the PAC-based session secret is always preserved. It'll be
* overwritten if the server refuses resumption.
*/
- if (s->session->session_id_length > 0) {
+ if (s->session->session_id_length > 0
+ || (SSL_IS_TLS13(s)
+ && s->session->ext.tick_identity
+ != TLSEXT_PSK_BAD_IDENTITY)) {
s->ctx->stats.sess_miss++;
if (!ssl_get_new_session(s, 0)) {
goto f_err;
goto f_err;
}
s->s3->tmp.new_cipher = c;
- /* lets get the compression algorithm */
- /* COMPRESSION */
- if (!SSL_IS_TLS13(s)) {
- if (!PACKET_get_1(pkt, &compression)) {
- SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_LENGTH_MISMATCH);
- al = SSL_AD_DECODE_ERROR;
- goto f_err;
- }
- } else {
- compression = 0;
- }
#ifdef OPENSSL_NO_COMP
if (compression != 0) {
}
#endif
- /* TLS extensions */
- if (PACKET_remaining(pkt) == 0) {
- PACKET_null_init(&extpkt);
- } else if (!PACKET_as_length_prefixed_2(pkt, &extpkt)) {
- al = SSL_AD_DECODE_ERROR;
- SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_BAD_LENGTH);
- goto f_err;
- }
-
- context = SSL_IS_TLS13(s) ? EXT_TLS1_3_SERVER_HELLO
- : EXT_TLS1_2_SERVER_HELLO;
- if (!tls_collect_extensions(s, &extpkt, context, &extensions, &al)
- || !tls_parse_all_extensions(s, context, extensions, NULL, 0, &al))
+ if (!tls_parse_all_extensions(s, context, extensions, NULL, 0, &al))
goto f_err;
#ifndef OPENSSL_NO_SCTP
DH *dh = NULL;
BIGNUM *p = NULL, *g = NULL, *bnpub_key = NULL;
+ int check_bits = 0;
+
if (!PACKET_get_length_prefixed_2(pkt, &prime)
|| !PACKET_get_length_prefixed_2(pkt, &generator)
|| !PACKET_get_length_prefixed_2(pkt, &pub_key)) {
goto err;
}
- if (BN_is_zero(p) || BN_is_zero(g) || BN_is_zero(bnpub_key)) {
+ /* test non-zero pupkey */
+ if (BN_is_zero(bnpub_key)) {
*al = SSL_AD_DECODE_ERROR;
SSLerr(SSL_F_TLS_PROCESS_SKE_DHE, SSL_R_BAD_DH_VALUE);
goto err;
}
p = g = NULL;
+ if (DH_check_params(dh, &check_bits) == 0 || check_bits != 0) {
+ *al = SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_TLS_PROCESS_SKE_DHE, SSL_R_BAD_DH_VALUE);
+ goto err;
+ }
+
if (!DH_set0_key(dh, bnpub_key, NULL)) {
*al = SSL_AD_INTERNAL_ERROR;
SSLerr(SSL_F_TLS_PROCESS_SKE_DHE, ERR_R_BN_LIB);
{
int al;
unsigned int ticklen;
- unsigned long ticket_lifetime_hint;
+ unsigned long ticket_lifetime_hint, age_add = 0;
unsigned int sess_len;
+ RAW_EXTENSION *exts = NULL;
if (!PACKET_get_net_4(pkt, &ticket_lifetime_hint)
+ || (SSL_IS_TLS13(s) && !PACKET_get_net_4(pkt, &age_add))
|| !PACKET_get_net_2(pkt, &ticklen)
- || PACKET_remaining(pkt) != ticklen) {
+ || (!SSL_IS_TLS13(s) && PACKET_remaining(pkt) != ticklen)
+ || (SSL_IS_TLS13(s) && (ticklen == 0
+ || PACKET_remaining(pkt) < ticklen))) {
al = SSL_AD_DECODE_ERROR;
SSLerr(SSL_F_TLS_PROCESS_NEW_SESSION_TICKET, SSL_R_LENGTH_MISMATCH);
goto f_err;
}
- /* Server is allowed to change its mind and send an empty ticket. */
+ /*
+ * Server is allowed to change its mind (in <=TLSv1.2) and send an empty
+ * ticket. We already checked this TLSv1.3 case above, so it should never
+ * be 0 here in that instance
+ */
if (ticklen == 0)
return MSG_PROCESS_CONTINUE_READING;
+ /* TODO(TLS1.3): Is this a suitable test for TLS1.3? */
if (s->session->session_id_length > 0) {
int i = s->session_ctx->session_cache_mode;
SSL_SESSION *new_sess;
s->session = new_sess;
}
+ /*
+ * Technically the cast to long here is not guaranteed by the C standard -
+ * but we use it elsewhere, so this should be ok.
+ */
+ s->session->time = (long)time(NULL);
+
OPENSSL_free(s->session->ext.tick);
s->session->ext.tick = NULL;
s->session->ext.ticklen = 0;
}
s->session->ext.tick_lifetime_hint = ticket_lifetime_hint;
+ s->session->ext.tick_age_add = age_add;
s->session->ext.ticklen = ticklen;
+
+ if (SSL_IS_TLS13(s)) {
+ PACKET extpkt;
+
+ if (!PACKET_as_length_prefixed_2(pkt, &extpkt)
+ || !tls_collect_extensions(s, &extpkt,
+ EXT_TLS1_3_NEW_SESSION_TICKET,
+ &exts, &al)
+ || !tls_parse_all_extensions(s, EXT_TLS1_3_NEW_SESSION_TICKET,
+ exts, NULL, 0, &al)) {
+ SSLerr(SSL_F_TLS_PROCESS_NEW_SESSION_TICKET, SSL_R_BAD_EXTENSION);
+ goto f_err;
+ }
+ }
+
/*
* There are two ways to detect a resumed ticket session. One is to set
* an appropriate session ID and then the server must return a match in
goto err;
}
s->session->session_id_length = sess_len;
+
+ /* This is a standalone message in TLSv1.3, so there is no more to read */
+ if (SSL_IS_TLS13(s)) {
+ ssl_update_cache(s, SSL_SESS_CACHE_CLIENT);
+ return MSG_PROCESS_FINISHED_READING;
+ }
+
return MSG_PROCESS_CONTINUE_READING;
f_err:
ssl3_send_alert(s, SSL3_AL_FATAL, al);
}
#endif
+MSG_PROCESS_RETURN tls_process_hello_req(SSL *s, PACKET *pkt)
+{
+ if (PACKET_remaining(pkt) > 0) {
+ /* should contain no data */
+ SSLerr(SSL_F_TLS_PROCESS_HELLO_REQ, SSL_R_LENGTH_MISMATCH);
+ ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ ossl_statem_set_error(s);
+ return MSG_PROCESS_ERROR;
+ }
+
+ /*
+ * This is a historical discrepancy maintained for compatibility
+ * reasons. If a TLS client receives a HelloRequest it will attempt
+ * an abbreviated handshake. However if a DTLS client receives a
+ * HelloRequest it will do a full handshake.
+ */
+ if (SSL_IS_DTLS(s))
+ SSL_renegotiate(s);
+ else
+ SSL_renegotiate_abbreviated(s);
+
+ return MSG_PROCESS_FINISHED_READING;
+}
+
static MSG_PROCESS_RETURN tls_process_encrypted_extensions(SSL *s, PACKET *pkt)
{
int al = SSL_AD_INTERNAL_ERROR;