diff options
Diffstat (limited to 'ssl/statem/statem.c')
-rw-r--r-- | ssl/statem/statem.c | 149 |
1 files changed, 85 insertions, 64 deletions
diff --git a/ssl/statem/statem.c b/ssl/statem/statem.c index 20f5bd584e6c..553546d93a41 100644 --- a/ssl/statem/statem.c +++ b/ssl/statem/statem.c @@ -1,12 +1,17 @@ /* - * Copyright 2015-2019 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2015-2022 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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" @@ -111,14 +116,8 @@ void ossl_statem_set_renegotiate(SSL *s) s->statem.request_state = TLS_ST_SW_HELLO_REQ; } -/* - * Put the state machine into an error state and send an alert if appropriate. - * This is a permanent error for the current connection. - */ -void ossl_statem_fatal(SSL *s, int al, int func, int reason, const char *file, - int line) +void ossl_statem_send_fatal(SSL *s, int al) { - ERR_put_error(ERR_LIB_SSL, func, reason, file, line); /* We shouldn't call SSLfatal() twice. Once is enough */ if (s->statem.in_init && s->statem.state == MSG_FLOW_ERROR) return; @@ -130,16 +129,32 @@ void ossl_statem_fatal(SSL *s, int al, int func, int reason, const char *file, } /* + * 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 *s, int al, int reason, const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + ERR_vset_error(ERR_LIB_SSL, reason, fmt, args); + va_end(args); + + ossl_statem_send_fatal(s, al); +} + +/* * This macro should only be called if we are already expecting to be in * a fatal error state. We verify that we are, and set it if not (this would * indicate a bug). */ -#define check_fatal(s, f) \ +#define check_fatal(s) \ do { \ if (!ossl_assert((s)->statem.in_init \ && (s)->statem.state == MSG_FLOW_ERROR)) \ - SSLfatal(s, SSL_AD_INTERNAL_ERROR, (f), \ - SSL_R_MISSING_FATAL); \ + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_MISSING_FATAL); \ } while (0) /* @@ -319,7 +334,7 @@ static int state_machine(SSL *s, int server) * If we are stateless then we already called SSL_clear() - don't do * it again and clear the STATELESS flag itself. */ - if ((s->s3->flags & TLS1_FLAGS_STATELESS) == 0 && !SSL_clear(s)) + if ((s->s3.flags & TLS1_FLAGS_STATELESS) == 0 && !SSL_clear(s)) return -1; } #ifndef OPENSSL_NO_SCTP @@ -356,33 +371,28 @@ static int state_machine(SSL *s, int server) if (SSL_IS_DTLS(s)) { if ((s->version & 0xff00) != (DTLS1_VERSION & 0xff00) && (server || (s->version & 0xff00) != (DTLS1_BAD_VER & 0xff00))) { - SSLfatal(s, SSL_AD_NO_ALERT, SSL_F_STATE_MACHINE, - ERR_R_INTERNAL_ERROR); + SSLfatal(s, SSL_AD_NO_ALERT, ERR_R_INTERNAL_ERROR); goto end; } } else { if ((s->version >> 8) != SSL3_VERSION_MAJOR) { - SSLfatal(s, SSL_AD_NO_ALERT, SSL_F_STATE_MACHINE, - ERR_R_INTERNAL_ERROR); + SSLfatal(s, SSL_AD_NO_ALERT, ERR_R_INTERNAL_ERROR); goto end; } } if (!ssl_security(s, SSL_SECOP_VERSION, 0, s->version, NULL)) { - SSLfatal(s, SSL_AD_NO_ALERT, SSL_F_STATE_MACHINE, - ERR_R_INTERNAL_ERROR); + SSLfatal(s, SSL_AD_NO_ALERT, ERR_R_INTERNAL_ERROR); goto end; } if (s->init_buf == NULL) { if ((buf = BUF_MEM_new()) == NULL) { - SSLfatal(s, SSL_AD_NO_ALERT, SSL_F_STATE_MACHINE, - ERR_R_INTERNAL_ERROR); + SSLfatal(s, SSL_AD_NO_ALERT, ERR_R_INTERNAL_ERROR); goto end; } if (!BUF_MEM_grow(buf, SSL3_RT_MAX_PLAIN_LENGTH)) { - SSLfatal(s, SSL_AD_NO_ALERT, SSL_F_STATE_MACHINE, - ERR_R_INTERNAL_ERROR); + SSLfatal(s, SSL_AD_NO_ALERT, ERR_R_INTERNAL_ERROR); goto end; } s->init_buf = buf; @@ -390,8 +400,7 @@ static int state_machine(SSL *s, int server) } if (!ssl3_setup_buffers(s)) { - SSLfatal(s, SSL_AD_NO_ALERT, SSL_F_STATE_MACHINE, - ERR_R_INTERNAL_ERROR); + SSLfatal(s, SSL_AD_NO_ALERT, ERR_R_INTERNAL_ERROR); goto end; } s->init_num = 0; @@ -399,7 +408,7 @@ static int state_machine(SSL *s, int server) /* * Should have been reset by tls_process_finished, too. */ - s->s3->change_cipher_spec = 0; + s->s3.change_cipher_spec = 0; /* * Ok, we now need to push on a buffering BIO ...but not with @@ -409,8 +418,7 @@ static int state_machine(SSL *s, int server) if (!SSL_IS_DTLS(s) || !BIO_dgram_is_sctp(SSL_get_wbio(s))) #endif if (!ssl_init_wbio_buffer(s)) { - SSLfatal(s, SSL_AD_NO_ALERT, SSL_F_STATE_MACHINE, - ERR_R_INTERNAL_ERROR); + SSLfatal(s, SSL_AD_NO_ALERT, ERR_R_INTERNAL_ERROR); goto end; } @@ -452,8 +460,8 @@ static int state_machine(SSL *s, int server) } } else { /* Error */ - check_fatal(s, SSL_F_STATE_MACHINE); - SSLerr(SSL_F_STATE_MACHINE, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + check_fatal(s); + ERR_raise(ERR_LIB_SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); goto end; } } @@ -574,7 +582,7 @@ static SUB_STATE_RETURN read_state_machine(SSL *s) /* * In DTLS we get the whole message in one go - header and body */ - ret = dtls_get_message(s, &mt, &len); + ret = dtls_get_message(s, &mt); } else { ret = tls_get_message_header(s, &mt); } @@ -598,19 +606,18 @@ static SUB_STATE_RETURN read_state_machine(SSL *s) if (!transition(s, mt)) return SUB_STATE_ERROR; - if (s->s3->tmp.message_size > max_message_size(s)) { - SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_READ_STATE_MACHINE, + if (s->s3.tmp.message_size > max_message_size(s)) { + SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_EXCESSIVE_MESSAGE_SIZE); return SUB_STATE_ERROR; } /* dtls_get_message already did this */ if (!SSL_IS_DTLS(s) - && s->s3->tmp.message_size > 0 - && !grow_init_buf(s, s->s3->tmp.message_size + && s->s3.tmp.message_size > 0 + && !grow_init_buf(s, s->s3.tmp.message_size + SSL3_HM_HEADER_LENGTH)) { - SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_READ_STATE_MACHINE, - ERR_R_BUF_LIB); + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_BUF_LIB); return SUB_STATE_ERROR; } @@ -618,19 +625,23 @@ static SUB_STATE_RETURN read_state_machine(SSL *s) /* Fall through */ case READ_STATE_BODY: - if (!SSL_IS_DTLS(s)) { - /* We already got this above for DTLS */ + if (SSL_IS_DTLS(s)) { + /* + * Actually we already have the body, but we give DTLS the + * opportunity to do any further processing. + */ + ret = dtls_get_message_body(s, &len); + } else { ret = tls_get_message_body(s, &len); - if (ret == 0) { - /* Could be non-blocking IO */ - return SUB_STATE_ERROR; - } + } + if (ret == 0) { + /* Could be non-blocking IO */ + return SUB_STATE_ERROR; } s->first_packet = 0; if (!PACKET_buf_init(&pkt, s->init_msg, len)) { - SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_READ_STATE_MACHINE, - ERR_R_INTERNAL_ERROR); + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); return SUB_STATE_ERROR; } ret = process_message(s, &pkt); @@ -640,7 +651,7 @@ static SUB_STATE_RETURN read_state_machine(SSL *s) switch (ret) { case MSG_PROCESS_ERROR: - check_fatal(s, SSL_F_READ_STATE_MACHINE); + check_fatal(s); return SUB_STATE_ERROR; case MSG_PROCESS_FINISHED_READING: @@ -664,7 +675,7 @@ static SUB_STATE_RETURN read_state_machine(SSL *s) st->read_state_work = post_process_message(s, st->read_state_work); switch (st->read_state_work) { case WORK_ERROR: - check_fatal(s, SSL_F_READ_STATE_MACHINE); + check_fatal(s); /* Fall through */ case WORK_MORE_A: case WORK_MORE_B: @@ -685,8 +696,7 @@ static SUB_STATE_RETURN read_state_machine(SSL *s) default: /* Shouldn't happen */ - SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_READ_STATE_MACHINE, - ERR_R_INTERNAL_ERROR); + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); return SUB_STATE_ERROR; } } @@ -801,7 +811,7 @@ static SUB_STATE_RETURN write_state_machine(SSL *s) break; case WRITE_TRAN_ERROR: - check_fatal(s, SSL_F_WRITE_STATE_MACHINE); + check_fatal(s); return SUB_STATE_ERROR; } break; @@ -809,7 +819,7 @@ static SUB_STATE_RETURN write_state_machine(SSL *s) case WRITE_STATE_PRE_WORK: switch (st->write_state_work = pre_work(s, st->write_state_work)) { case WORK_ERROR: - check_fatal(s, SSL_F_WRITE_STATE_MACHINE); + check_fatal(s); /* Fall through */ case WORK_MORE_A: case WORK_MORE_B: @@ -836,20 +846,32 @@ static SUB_STATE_RETURN write_state_machine(SSL *s) if (!WPACKET_init(&pkt, s->init_buf) || !ssl_set_handshake_header(s, &pkt, mt)) { WPACKET_cleanup(&pkt); - SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_WRITE_STATE_MACHINE, - ERR_R_INTERNAL_ERROR); + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); return SUB_STATE_ERROR; } - if (confunc != NULL && !confunc(s, &pkt)) { - WPACKET_cleanup(&pkt); - check_fatal(s, SSL_F_WRITE_STATE_MACHINE); - return SUB_STATE_ERROR; + if (confunc != NULL) { + int tmpret; + + tmpret = confunc(s, &pkt); + if (tmpret <= 0) { + WPACKET_cleanup(&pkt); + check_fatal(s); + return SUB_STATE_ERROR; + } else if (tmpret == 2) { + /* + * The construction function decided not to construct the + * message after all and continue. Skip sending. + */ + WPACKET_cleanup(&pkt); + st->write_state = WRITE_STATE_POST_WORK; + st->write_state_work = WORK_MORE_A; + break; + } /* else success */ } if (!ssl_close_construct_packet(s, &pkt, mt) || !WPACKET_finish(&pkt)) { WPACKET_cleanup(&pkt); - SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_WRITE_STATE_MACHINE, - ERR_R_INTERNAL_ERROR); + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); return SUB_STATE_ERROR; } @@ -870,7 +892,7 @@ static SUB_STATE_RETURN write_state_machine(SSL *s) case WRITE_STATE_POST_WORK: switch (st->write_state_work = post_work(s, st->write_state_work)) { case WORK_ERROR: - check_fatal(s, SSL_F_WRITE_STATE_MACHINE); + check_fatal(s); /* Fall through */ case WORK_MORE_A: case WORK_MORE_B: @@ -887,8 +909,7 @@ static SUB_STATE_RETURN write_state_machine(SSL *s) break; default: - SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_WRITE_STATE_MACHINE, - ERR_R_INTERNAL_ERROR); + SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); return SUB_STATE_ERROR; } } @@ -923,7 +944,7 @@ int ossl_statem_app_data_allowed(SSL *s) if (st->state == MSG_FLOW_UNINITED) return 0; - if (!s->s3->in_read_app_data || (s->s3->total_renegotiations == 0)) + if (!s->s3.in_read_app_data || (s->s3.total_renegotiations == 0)) return 0; if (s->server) { @@ -952,7 +973,7 @@ int ossl_statem_app_data_allowed(SSL *s) */ int ossl_statem_export_allowed(SSL *s) { - return s->s3->previous_server_finished_len != 0 + return s->s3.previous_server_finished_len != 0 && s->statem.hand_state != TLS_ST_SW_FINISHED; } |