/*
* Copyright 2015-2022 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#if defined(__TANDEM) && defined(_SPT_MODEL_)
# include <spthread.h>
# include <spt_extensions.h> /* timeval */
#endif
#include "internal/cryptlib.h"
#include <openssl/rand.h>
#include "../ssl_local.h"
#include "statem_local.h"
#include <assert.h>
/*
* This file implements the SSL/TLS/DTLS state machines.
*
* There are two primary state machines:
*
* 1) Message flow state machine
* 2) Handshake state machine
*
* The Message flow state machine controls the reading and sending of messages
* including handling of non-blocking IO events, flushing of the underlying
* write BIO, handling unexpected messages, etc. It is itself broken into two
* separate sub-state machines which control reading and writing respectively.
*
* The Handshake state machine keeps track of the current SSL/TLS handshake
* state. Transitions of the handshake state are the result of events that
* occur within the Message flow state machine.
*
* Overall it looks like this:
*
* --------------------------------------------- -------------------
* | | | |
* | Message flow state machine | | |
* | | | |
* | -------------------- -------------------- | Transition | Handshake state |
* | | MSG_FLOW_READING | | MSG_FLOW_WRITING | | Event | machine |
* | | sub-state | | sub-state | |----------->| |
* | | machine for | | machine for | | | |
* | | reading messages | | writing messages | | | |
* | -------------------- -------------------- | | |
* | | | |
* --------------------------------------------- -------------------
*
*/
/* Sub state machine return values */
typedef enum {
/* Something bad happened or NBIO */
SUB_STATE_ERROR,
/* Sub state finished go to the next sub state */
SUB_STATE_FINISHED,
/* Sub state finished and handshake was completed */
SUB_STATE_END_HANDSHAKE
} SUB_STATE_RETURN;
static int state_machine(SSL_CONNECTION *s, int server);
static void init_read_state_machine(SSL_CONNECTION *s);
static SUB_STATE_RETURN read_state_machine(SSL_CONNECTION *s);
static void init_write_state_machine(SSL_CONNECTION *s);
static SUB_STATE_RETURN write_state_machine(SSL_CONNECTION *s);
OSSL_HANDSHAKE_STATE SSL_get_state(const SSL *ssl)
{
const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(ssl);
if (sc == NULL)
return TLS_ST_BEFORE;
return sc->statem.hand_state;
}
int SSL_in_init(const SSL *s)
{
const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
if (sc == NULL)
return 0;
return sc->statem.in_init;
}
int SSL_is_init_finished(const SSL *s)
{
const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
if (sc == NULL)
return 0;
return !(sc->statem.in_init) && (sc->statem.hand_state == TLS_ST_OK);
}
int SSL_in_before(const SSL *s)
{
const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
if (sc == NULL)
return 0;
/*
* Historically being "in before" meant before anything had happened. In the
* current code though we remain in the "before" state for a while after we
* have started the handshake process (e.g. as a server waiting for the
* first message to arrive). There "in before" is taken to mean "in before"
* and not started any handshake process yet.
*/
return (sc->statem.hand_state == TLS_ST_BEFORE)
&& (sc->statem.state == MSG_FLOW_UNINITED);
}
OSSL_HANDSHAKE_STATE ossl_statem_get_state(SSL_CONNECTION *s)
{
return s != NULL ? s->statem.hand_state : TLS_ST_BEFORE;
}
/*
* Clear the state machine state and reset back to MSG_FLOW_UNINITED
*/
void ossl_statem_clear(SSL_CONNECTION *s)
{
s->statem.state = MSG_FLOW_UNINITED;
s->statem.hand_state = TLS_ST_BEFORE;
ossl_statem_set_in_init(s, 1);
s->statem.no_cert_verify = 0;
}
/*
* Set the state machine up ready for a renegotiation handshake
*/
void ossl_statem_set_renegotiate(SSL_CONNECTION *s)
{
ossl_statem_set_in_init(s, 1);
s->statem.request_state = TLS_ST_SW_HELLO_REQ;
}
void ossl_statem_send_fatal(SSL_CONNECTION *s, int al)
{
/* We shouldn't call SSLfatal() twice. Once is enough */
if (s->statem.in_init && s->statem.state == MSG_FLOW_ERROR)
return;
ossl_statem_set_in_init(s, 1);
s->statem.state = MSG_FLOW_ERROR;
if (al != SSL_AD_NO_ALERT)
ssl3_send_alert(s, SSL3_AL_FATAL, al);
}
/*
* Error reporting building block that's used instead of ERR_set_error().
* In addition to what ERR_set_error() does, this puts the state machine
* into an error state and sends an alert if appropriate.
* This is a permanent error for the current connection.
*/
void ossl_statem_fatal(SSL_CONNECTION *s, int al, int