diff options
Diffstat (limited to 'openssl-1.1.0h/ssl/statem')
-rw-r--r-- | openssl-1.1.0h/ssl/statem/README | 63 | ||||
-rw-r--r-- | openssl-1.1.0h/ssl/statem/statem.c | 860 | ||||
-rw-r--r-- | openssl-1.1.0h/ssl/statem/statem.h | 116 | ||||
-rw-r--r-- | openssl-1.1.0h/ssl/statem/statem_clnt.c | 2946 | ||||
-rw-r--r-- | openssl-1.1.0h/ssl/statem/statem_dtls.c | 1220 | ||||
-rw-r--r-- | openssl-1.1.0h/ssl/statem/statem_lib.c | 1083 | ||||
-rw-r--r-- | openssl-1.1.0h/ssl/statem/statem_locl.h | 125 | ||||
-rw-r--r-- | openssl-1.1.0h/ssl/statem/statem_srvr.c | 3341 |
8 files changed, 9754 insertions, 0 deletions
diff --git a/openssl-1.1.0h/ssl/statem/README b/openssl-1.1.0h/ssl/statem/README new file mode 100644 index 0000000..145c69d --- /dev/null +++ b/openssl-1.1.0h/ssl/statem/README @@ -0,0 +1,63 @@ +State Machine Design +==================== + +This file provides some guidance on the thinking behind the design of the +state machine code to aid future maintenance. + +The state machine code replaces an older state machine present in OpenSSL +versions 1.0.2 and below. The new state machine has the following objectives: + - Remove duplication of state code between client and server + - Remove duplication of state code between TLS and DTLS + - Simplify transitions and bring the logic together in a single location + so that it is easier to validate + - Remove duplication of code between each of the message handling functions + - Receive a message first and then work out whether that is a valid + transition - not the other way around (the other way causes lots of issues + where we are expecting one type of message next but actually get something + else) + - Separate message flow state from handshake state (in order to better + understand each) + - message flow state = when to flush buffers; handling restarts in the + event of NBIO events; handling the common flow of steps for reading a + message and the common flow of steps for writing a message etc + - handshake state = what handshake message are we working on now + - Control complexity: only the state machine can change state: keep all + the state changes local to the state machine component + +The message flow state machine is divided into a reading sub-state machine and a +writing sub-state machine. See the source comments in statem.c for a more +detailed description of the various states and transitions possible. + +Conceptually the state machine component is designed as follows: + + libssl + | +---------------------------|-----statem.h-------------------------------------- + | + _______V____________________ + | | + | statem.c | + | | + | Core state machine code | + |____________________________| + statem_locl.h ^ ^ + _________| |_______ + | | + _____________|____________ _____________|____________ + | | | | + | statem_clnt.c | | statem_srvr.c | + | | | | + | TLS/DTLS client specific | | TLS/DTLS server specific | + | state machine code | | state machine code | + |__________________________| |__________________________| + | |_______________|__ | + | ________________| | | + | | | | + ____________V_______V________ ________V______V_______________ + | | | | + | statem_both.c | | statem_dtls.c | + | | | | + | Non core functions common | | Non core functions common to | + | to both servers and clients | | both DTLS servers and clients | + |_____________________________| |_______________________________| + diff --git a/openssl-1.1.0h/ssl/statem/statem.c b/openssl-1.1.0h/ssl/statem/statem.c new file mode 100644 index 0000000..b91ec0a --- /dev/null +++ b/openssl-1.1.0h/ssl/statem/statem.c @@ -0,0 +1,860 @@ +/* + * Copyright 2015-2018 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (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 + */ + +#include <openssl/rand.h> +#include "../ssl_locl.h" +#include "statem_locl.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 *s, int server); +static void init_read_state_machine(SSL *s); +static SUB_STATE_RETURN read_state_machine(SSL *s); +static void init_write_state_machine(SSL *s); +static SUB_STATE_RETURN write_state_machine(SSL *s); + +OSSL_HANDSHAKE_STATE SSL_get_state(const SSL *ssl) +{ + return ssl->statem.hand_state; +} + +int SSL_in_init(SSL *s) +{ + return s->statem.in_init; +} + +int SSL_is_init_finished(SSL *s) +{ + return !(s->statem.in_init) && (s->statem.hand_state == TLS_ST_OK); +} + +int SSL_in_before(SSL *s) +{ + /* + * 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 (s->statem.hand_state == TLS_ST_BEFORE) + && (s->statem.state == MSG_FLOW_UNINITED); +} + +/* + * Clear the state machine state and reset back to MSG_FLOW_UNINITED + */ +void ossl_statem_clear(SSL *s) +{ + s->statem.state = MSG_FLOW_UNINITED; + s->statem.hand_state = TLS_ST_BEFORE; + s->statem.in_init = 1; + s->statem.no_cert_verify = 0; +} + +/* + * Set the state machine up ready for a renegotiation handshake + */ +void ossl_statem_set_renegotiate(SSL *s) +{ + s->statem.state = MSG_FLOW_RENEGOTIATE; + s->statem.in_init = 1; +} + +/* + * Put the state machine into an error state. This is a permanent error for + * the current connection. + */ +void ossl_statem_set_error(SSL *s) +{ + s->statem.state = MSG_FLOW_ERROR; +} + +/* + * Discover whether the current connection is in the error state. + * + * Valid return values are: + * 1: Yes + * 0: No + */ +int ossl_statem_in_error(const SSL *s) +{ + if (s->statem.state == MSG_FLOW_ERROR) + return 1; + + return 0; +} + +void ossl_statem_set_in_init(SSL *s, int init) +{ + s->statem.in_init = init; +} + +int ossl_statem_get_in_handshake(SSL *s) +{ + return s->statem.in_handshake; +} + +void ossl_statem_set_in_handshake(SSL *s, int inhand) +{ + if (inhand) + s->statem.in_handshake++; + else + s->statem.in_handshake--; +} + +void ossl_statem_set_hello_verify_done(SSL *s) +{ + s->statem.state = MSG_FLOW_UNINITED; + s->statem.in_init = 1; + /* + * This will get reset (briefly) back to TLS_ST_BEFORE when we enter + * state_machine() because |state| is MSG_FLOW_UNINITED, but until then any + * calls to SSL_in_before() will return false. Also calls to + * SSL_state_string() and SSL_state_string_long() will return something + * sensible. + */ + s->statem.hand_state = TLS_ST_SR_CLNT_HELLO; +} + +int ossl_statem_connect(SSL *s) +{ + return state_machine(s, 0); +} + +int ossl_statem_accept(SSL *s) +{ + return state_machine(s, 1); +} + +typedef void (*info_cb) (const SSL *, int, int); + +static info_cb get_callback(SSL *s) +{ + if (s->info_callback != NULL) + return s->info_callback; + else if (s->ctx->info_callback != NULL) + return s->ctx->info_callback; + + return NULL; +} + +/* + * The main message flow state machine. We start in the MSG_FLOW_UNINITED or + * MSG_FLOW_RENEGOTIATE state and finish in MSG_FLOW_FINISHED. Valid states and + * transitions are as follows: + * + * MSG_FLOW_UNINITED MSG_FLOW_RENEGOTIATE + * | | + * +-----------------------+ + * v + * MSG_FLOW_WRITING <---> MSG_FLOW_READING + * | + * V + * MSG_FLOW_FINISHED + * | + * V + * [SUCCESS] + * + * We may exit at any point due to an error or NBIO event. If an NBIO event + * occurs then we restart at the point we left off when we are recalled. + * MSG_FLOW_WRITING and MSG_FLOW_READING have sub-state machines associated with them. + * + * In addition to the above there is also the MSG_FLOW_ERROR state. We can move + * into that state at any point in the event that an irrecoverable error occurs. + * + * Valid return values are: + * 1: Success + * <=0: NBIO or error + */ +static int state_machine(SSL *s, int server) +{ + BUF_MEM *buf = NULL; + unsigned long Time = (unsigned long)time(NULL); + void (*cb) (const SSL *ssl, int type, int val) = NULL; + OSSL_STATEM *st = &s->statem; + int ret = -1; + int ssret; + + if (st->state == MSG_FLOW_ERROR) { + /* Shouldn't have been called if we're already in the error state */ + return -1; + } + + RAND_add(&Time, sizeof(Time), 0); + ERR_clear_error(); + clear_sys_error(); + + cb = get_callback(s); + + st->in_handshake++; + if (!SSL_in_init(s) || SSL_in_before(s)) { + if (!SSL_clear(s)) + return -1; + } +#ifndef OPENSSL_NO_SCTP + if (SSL_IS_DTLS(s) && BIO_dgram_is_sctp(SSL_get_wbio(s))) { + /* + * Notify SCTP BIO socket to enter handshake mode and prevent stream + * identifier other than 0. + */ + BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE, + st->in_handshake, NULL); + } +#endif + +#ifndef OPENSSL_NO_HEARTBEATS + /* + * If we're awaiting a HeartbeatResponse, pretend we already got and + * don't await it anymore, because Heartbeats don't make sense during + * handshakes anyway. + */ + if (s->tlsext_hb_pending) { + if (SSL_IS_DTLS(s)) + dtls1_stop_timer(s); + s->tlsext_hb_pending = 0; + s->tlsext_hb_seq++; + } +#endif + + /* Initialise state machine */ + + if (st->state == MSG_FLOW_RENEGOTIATE) { + s->renegotiate = 1; + if (!server) + s->ctx->stats.sess_connect_renegotiate++; + } + + if (st->state == MSG_FLOW_UNINITED || st->state == MSG_FLOW_RENEGOTIATE) { + if (st->state == MSG_FLOW_UNINITED) { + st->hand_state = TLS_ST_BEFORE; + } + + s->server = server; + if (cb != NULL) + cb(s, SSL_CB_HANDSHAKE_START, 1); + + if (SSL_IS_DTLS(s)) { + if ((s->version & 0xff00) != (DTLS1_VERSION & 0xff00) && + (server || (s->version & 0xff00) != (DTLS1_BAD_VER & 0xff00))) { + SSLerr(SSL_F_STATE_MACHINE, ERR_R_INTERNAL_ERROR); + goto end; + } + } else { + if ((s->version >> 8) != SSL3_VERSION_MAJOR) { + SSLerr(SSL_F_STATE_MACHINE, ERR_R_INTERNAL_ERROR); + goto end; + } + } + + if (!ssl_security(s, SSL_SECOP_VERSION, 0, s->version, NULL)) { + SSLerr(SSL_F_STATE_MACHINE, SSL_R_VERSION_TOO_LOW); + goto end; + } + + if (s->init_buf == NULL) { + if ((buf = BUF_MEM_new()) == NULL) { + goto end; + } + if (!BUF_MEM_grow(buf, SSL3_RT_MAX_PLAIN_LENGTH)) { + goto end; + } + s->init_buf = buf; + buf = NULL; + } + + if (!ssl3_setup_buffers(s)) { + goto end; + } + s->init_num = 0; + + /* + * Should have been reset by tls_process_finished, too. + */ + s->s3->change_cipher_spec = 0; + + /* + * Ok, we now need to push on a buffering BIO ...but not with + * SCTP + */ +#ifndef OPENSSL_NO_SCTP + if (!SSL_IS_DTLS(s) || !BIO_dgram_is_sctp(SSL_get_wbio(s))) +#endif + if (!ssl_init_wbio_buffer(s)) { + goto end; + } + + if (!server || st->state != MSG_FLOW_RENEGOTIATE) { + if (!ssl3_init_finished_mac(s)) { + ossl_statem_set_error(s); + goto end; + } + } + + if (server) { + if (st->state != MSG_FLOW_RENEGOTIATE) { + s->ctx->stats.sess_accept++; + } else if ((s->options & SSL_OP_NO_RENEGOTIATION)) { + /* + * Shouldn't happen? The record layer should have prevented this + */ + SSLerr(SSL_F_STATE_MACHINE, ERR_R_INTERNAL_ERROR); + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + ossl_statem_set_error(s); + goto end; + } else if (!s->s3->send_connection_binding && + !(s->options & + SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)) { + /* + * Server attempting to renegotiate with client that doesn't + * support secure renegotiation. + */ + SSLerr(SSL_F_STATE_MACHINE, + SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED); + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); + ossl_statem_set_error(s); + goto end; + } else { + /* + * st->state == MSG_FLOW_RENEGOTIATE, we will just send a + * HelloRequest + */ + s->ctx->stats.sess_accept_renegotiate++; + } + + s->s3->tmp.cert_request = 0; + } else { + s->ctx->stats.sess_connect++; + + /* mark client_random uninitialized */ + memset(s->s3->client_random, 0, sizeof(s->s3->client_random)); + s->hit = 0; + + s->s3->tmp.cert_req = 0; + + if (SSL_IS_DTLS(s)) { + st->use_timer = 1; + } + } + + st->state = MSG_FLOW_WRITING; + init_write_state_machine(s); + st->read_state_first_init = 1; + } + + while (st->state != MSG_FLOW_FINISHED) { + if (st->state == MSG_FLOW_READING) { + ssret = read_state_machine(s); + if (ssret == SUB_STATE_FINISHED) { + st->state = MSG_FLOW_WRITING; + init_write_state_machine(s); + } else { + /* NBIO or error */ + goto end; + } + } else if (st->state == MSG_FLOW_WRITING) { + ssret = write_state_machine(s); + if (ssret == SUB_STATE_FINISHED) { + st->state = MSG_FLOW_READING; + init_read_state_machine(s); + } else if (ssret == SUB_STATE_END_HANDSHAKE) { + st->state = MSG_FLOW_FINISHED; + } else { + /* NBIO or error */ + goto end; + } + } else { + /* Error */ + ossl_statem_set_error(s); + goto end; + } + } + + st->state = MSG_FLOW_UNINITED; + ret = 1; + + end: + st->in_handshake--; + +#ifndef OPENSSL_NO_SCTP + if (SSL_IS_DTLS(s) && BIO_dgram_is_sctp(SSL_get_wbio(s))) { + /* + * Notify SCTP BIO socket to leave handshake mode and allow stream + * identifier other than 0. + */ + BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE, + st->in_handshake, NULL); + } +#endif + + BUF_MEM_free(buf); + if (cb != NULL) { + if (server) + cb(s, SSL_CB_ACCEPT_EXIT, ret); + else + cb(s, SSL_CB_CONNECT_EXIT, ret); + } + return ret; +} + +/* + * Initialise the MSG_FLOW_READING sub-state machine + */ +static void init_read_state_machine(SSL *s) +{ + OSSL_STATEM *st = &s->statem; + + st->read_state = READ_STATE_HEADER; +} + +static int grow_init_buf(SSL *s, size_t size) { + + size_t msg_offset = (char *)s->init_msg - s->init_buf->data; + + if (!BUF_MEM_grow_clean(s->init_buf, (int)size)) + return 0; + + if (size < msg_offset) + return 0; + + s->init_msg = s->init_buf->data + msg_offset; + + return 1; +} + +/* + * This function implements the sub-state machine when the message flow is in + * MSG_FLOW_READING. The valid sub-states and transitions are: + * + * READ_STATE_HEADER <--+<-------------+ + * | | | + * v | | + * READ_STATE_BODY -----+-->READ_STATE_POST_PROCESS + * | | + * +----------------------------+ + * v + * [SUB_STATE_FINISHED] + * + * READ_STATE_HEADER has the responsibility for reading in the message header + * and transitioning the state of the handshake state machine. + * + * READ_STATE_BODY reads in the rest of the message and then subsequently + * processes it. + * + * READ_STATE_POST_PROCESS is an optional step that may occur if some post + * processing activity performed on the message may block. + * + * Any of the above states could result in an NBIO event occurring in which case + * control returns to the calling application. When this function is recalled we + * will resume in the same state where we left off. + */ +static SUB_STATE_RETURN read_state_machine(SSL *s) +{ + OSSL_STATEM *st = &s->statem; + int ret, mt; + unsigned long len = 0; + int (*transition) (SSL *s, int mt); + PACKET pkt; + MSG_PROCESS_RETURN(*process_message) (SSL *s, PACKET *pkt); + WORK_STATE(*post_process_message) (SSL *s, WORK_STATE wst); + unsigned long (*max_message_size) (SSL *s); + void (*cb) (const SSL *ssl, int type, int val) = NULL; + + cb = get_callback(s); + + if (s->server) { + transition = ossl_statem_server_read_transition; + process_message = ossl_statem_server_process_message; + max_message_size = ossl_statem_server_max_message_size; + post_process_message = ossl_statem_server_post_process_message; + } else { + transition = ossl_statem_client_read_transition; + process_message = ossl_statem_client_process_message; + max_message_size = ossl_statem_client_max_message_size; + post_process_message = ossl_statem_client_post_process_message; + } + + if (st->read_state_first_init) { + s->first_packet = 1; + st->read_state_first_init = 0; + } + + while (1) { + switch (st->read_state) { + case READ_STATE_HEADER: + /* Get the state the peer wants to move to */ + if (SSL_IS_DTLS(s)) { + /* + * In DTLS we get the whole message in one go - header and body + */ + ret = dtls_get_message(s, &mt, &len); + } else { + ret = tls_get_message_header(s, &mt); + } + + if (ret == 0) { + /* Could be non-blocking IO */ + return SUB_STATE_ERROR; + } + + if (cb != NULL) { + /* Notify callback of an impending state change */ + if (s->server) + cb(s, SSL_CB_ACCEPT_LOOP, 1); + else + cb(s, SSL_CB_CONNECT_LOOP, 1); + } + /* + * Validate that we are allowed to move to the new state and move + * to that state if so + */ + if (!transition(s, mt)) { + ossl_statem_set_error(s); + return SUB_STATE_ERROR; + } + + if (s->s3->tmp.message_size > max_message_size(s)) { + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); + SSLerr(SSL_F_READ_STATE_MACHINE, 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 + + SSL3_HM_HEADER_LENGTH)) { + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + SSLerr(SSL_F_READ_STATE_MACHINE, ERR_R_BUF_LIB); + return SUB_STATE_ERROR; + } + + st->read_state = READ_STATE_BODY; + /* Fall through */ + + case READ_STATE_BODY: + if (!SSL_IS_DTLS(s)) { + /* We already got this above for DTLS */ + ret = tls_get_message_body(s, &len); + 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)) { + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + SSLerr(SSL_F_READ_STATE_MACHINE, ERR_R_INTERNAL_ERROR); + return SUB_STATE_ERROR; + } + ret = process_message(s, &pkt); + + /* Discard the packet data */ + s->init_num = 0; + + switch (ret) { + case MSG_PROCESS_ERROR: + return SUB_STATE_ERROR; + + case MSG_PROCESS_FINISHED_READING: + if (SSL_IS_DTLS(s)) { + dtls1_stop_timer(s); + } + return SUB_STATE_FINISHED; + + case MSG_PROCESS_CONTINUE_PROCESSING: + st->read_state = READ_STATE_POST_PROCESS; + st->read_state_work = WORK_MORE_A; + break; + + default: + st->read_state = READ_STATE_HEADER; + break; + } + break; + + case READ_STATE_POST_PROCESS: + st->read_state_work = post_process_message(s, st->read_state_work); + switch (st->read_state_work) { + default: + return SUB_STATE_ERROR; + + case WORK_FINISHED_CONTINUE: + st->read_state = READ_STATE_HEADER; + break; + + case WORK_FINISHED_STOP: + if (SSL_IS_DTLS(s)) { + dtls1_stop_timer(s); + } + return SUB_STATE_FINISHED; + } + break; + + default: + /* Shouldn't happen */ + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + SSLerr(SSL_F_READ_STATE_MACHINE, ERR_R_INTERNAL_ERROR); + ossl_statem_set_error(s); + return SUB_STATE_ERROR; + } + } +} + +/* + * Send a previously constructed message to the peer. + */ +static int statem_do_write(SSL *s) +{ + OSSL_STATEM *st = &s->statem; + + if (st->hand_state == TLS_ST_CW_CHANGE + || st->hand_state == TLS_ST_SW_CHANGE) { + if (SSL_IS_DTLS(s)) + return dtls1_do_write(s, SSL3_RT_CHANGE_CIPHER_SPEC); + else + return ssl3_do_write(s, SSL3_RT_CHANGE_CIPHER_SPEC); + } else { + return ssl_do_write(s); + } +} + +/* + * Initialise the MSG_FLOW_WRITING sub-state machine + */ +static void init_write_state_machine(SSL *s) +{ + OSSL_STATEM *st = &s->statem; + + st->write_state = WRITE_STATE_TRANSITION; +} + +/* + * This function implements the sub-state machine when the message flow is in + * MSG_FLOW_WRITING. The valid sub-states and transitions are: + * + * +-> WRITE_STATE_TRANSITION ------> [SUB_STATE_FINISHED] + * | | + * | v + * | WRITE_STATE_PRE_WORK -----> [SUB_STATE_END_HANDSHAKE] + * | | + * | v + * | WRITE_STATE_SEND + * | | + * | v + * | WRITE_STATE_POST_WORK + * | | + * +-------------+ + * + * WRITE_STATE_TRANSITION transitions the state of the handshake state machine + + * WRITE_STATE_PRE_WORK performs any work necessary to prepare the later + * sending of the message. This could result in an NBIO event occurring in + * which case control returns to the calling application. When this function + * is recalled we will resume in the same state where we left off. + * + * WRITE_STATE_SEND sends the message and performs any work to be done after + * sending. + * + * WRITE_STATE_POST_WORK performs any work necessary after the sending of the + * message has been completed. As for WRITE_STATE_PRE_WORK this could also + * result in an NBIO event. + */ +static SUB_STATE_RETURN write_state_machine(SSL *s) +{ + OSSL_STATEM *st = &s->statem; + int ret; + WRITE_TRAN(*transition) (SSL *s); + WORK_STATE(*pre_work) (SSL *s, WORK_STATE wst); + WORK_STATE(*post_work) (SSL *s, WORK_STATE wst); + int (*construct_message) (SSL *s); + void (*cb) (const SSL *ssl, int type, int val) = NULL; + + cb = get_callback(s); + + if (s->server) { + transition = ossl_statem_server_write_transition; + pre_work = ossl_statem_server_pre_work; + post_work = ossl_statem_server_post_work; + construct_message = ossl_statem_server_construct_message; + } else { + transition = ossl_statem_client_write_transition; + pre_work = ossl_statem_client_pre_work; + post_work = ossl_statem_client_post_work; + construct_message = ossl_statem_client_construct_message; + } + + while (1) { + switch (st->write_state) { + case WRITE_STATE_TRANSITION: + if (cb != NULL) { + /* Notify callback of an impending state change */ + if (s->server) + cb(s, SSL_CB_ACCEPT_LOOP, 1); + else + cb(s, SSL_CB_CONNECT_LOOP, 1); + } + switch (transition(s)) { + case WRITE_TRAN_CONTINUE: + st->write_state = WRITE_STATE_PRE_WORK; + st->write_state_work = WORK_MORE_A; + break; + + case WRITE_TRAN_FINISHED: + return SUB_STATE_FINISHED; + break; + + default: + return SUB_STATE_ERROR; + } + break; + + case WRITE_STATE_PRE_WORK: + switch (st->write_state_work = pre_work(s, st->write_state_work)) { + default: + return SUB_STATE_ERROR; + + case WORK_FINISHED_CONTINUE: + st->write_state = WRITE_STATE_SEND; + break; + + case WORK_FINISHED_STOP: + return SUB_STATE_END_HANDSHAKE; + } + if (construct_message(s) == 0) + return SUB_STATE_ERROR; + + /* Fall through */ + + case WRITE_STATE_SEND: + if (SSL_IS_DTLS(s) && st->use_timer) { + dtls1_start_timer(s); + } + ret = statem_do_write(s); + if (ret <= 0) { + return SUB_STATE_ERROR; + } + st->write_state = WRITE_STATE_POST_WORK; + st->write_state_work = WORK_MORE_A; + /* Fall through */ + + case WRITE_STATE_POST_WORK: + switch (st->write_state_work = post_work(s, st->write_state_work)) { + default: + return SUB_STATE_ERROR; + + case WORK_FINISHED_CONTINUE: + st->write_state = WRITE_STATE_TRANSITION; + break; + + case WORK_FINISHED_STOP: + return SUB_STATE_END_HANDSHAKE; + } + break; + + default: + return SUB_STATE_ERROR; + } + } +} + +/* + * Flush the write BIO + */ +int statem_flush(SSL *s) +{ + s->rwstate = SSL_WRITING; + if (BIO_flush(s->wbio) <= 0) { + return 0; + } + s->rwstate = SSL_NOTHING; + + return 1; +} + +/* + * Called by the record layer to determine whether application data is + * allowed to be sent in the current handshake state or not. + * + * Return values are: + * 1: Yes (application data allowed) + * 0: No (application data not allowed) + */ +int ossl_statem_app_data_allowed(SSL *s) +{ + OSSL_STATEM *st = &s->statem; + + if (st->state == MSG_FLOW_UNINITED || st->state == MSG_FLOW_RENEGOTIATE) + return 0; + + if (!s->s3->in_read_app_data || (s->s3->total_renegotiations == 0)) + return 0; + + if (s->server) { + /* + * If we're a server and we haven't got as far as writing our + * ServerHello yet then we allow app data + */ + if (st->hand_state == TLS_ST_BEFORE + || st->hand_state == TLS_ST_SR_CLNT_HELLO) + return 1; + } else { + /* + * If we're a client and we haven't read the ServerHello yet then we + * allow app data + */ + if (st->hand_state == TLS_ST_CW_CLNT_HELLO) + return 1; + } + + return 0; +} diff --git a/openssl-1.1.0h/ssl/statem/statem.h b/openssl-1.1.0h/ssl/statem/statem.h new file mode 100644 index 0000000..c669ee9 --- /dev/null +++ b/openssl-1.1.0h/ssl/statem/statem.h @@ -0,0 +1,116 @@ +/* + * Copyright 2015-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (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 + */ + +/***************************************************************************** + * * + * These enums should be considered PRIVATE to the state machine. No * + * non-state machine code should need to use these * + * * + *****************************************************************************/ +/* + * Valid return codes used for functions performing work prior to or after + * sending or receiving a message + */ +typedef enum { + /* Something went wrong */ + WORK_ERROR, + /* We're done working and there shouldn't be anything else to do after */ + WORK_FINISHED_STOP, + /* We're done working move onto the next thing */ + WORK_FINISHED_CONTINUE, + /* We're working on phase A */ + WORK_MORE_A, + /* We're working on phase B */ + WORK_MORE_B +} WORK_STATE; + +/* Write transition return codes */ +typedef enum { + /* Something went wrong */ + WRITE_TRAN_ERROR, + /* A transition was successfully completed and we should continue */ + WRITE_TRAN_CONTINUE, + /* There is no more write work to be done */ + WRITE_TRAN_FINISHED +} WRITE_TRAN; + +/* Message flow states */ +typedef enum { + /* No handshake in progress */ + MSG_FLOW_UNINITED, + /* A permanent error with this connection */ + MSG_FLOW_ERROR, + /* We are about to renegotiate */ + MSG_FLOW_RENEGOTIATE, + /* We are reading messages */ + MSG_FLOW_READING, + /* We are writing messages */ + MSG_FLOW_WRITING, + /* Handshake has finished */ + MSG_FLOW_FINISHED +} MSG_FLOW_STATE; + +/* Read states */ +typedef enum { + READ_STATE_HEADER, + READ_STATE_BODY, + READ_STATE_POST_PROCESS +} READ_STATE; + +/* Write states */ +typedef enum { + WRITE_STATE_TRANSITION, + WRITE_STATE_PRE_WORK, + WRITE_STATE_SEND, + WRITE_STATE_POST_WORK +} WRITE_STATE; + +/***************************************************************************** + * * + * This structure should be considered "opaque" to anything outside of the * + * state machine. No non-state machine code should be accessing the members * + * of this structure. * + * * + *****************************************************************************/ + +struct ossl_statem_st { + MSG_FLOW_STATE state; + WRITE_STATE write_state; + WORK_STATE write_state_work; + READ_STATE read_state; + WORK_STATE read_state_work; + OSSL_HANDSHAKE_STATE hand_state; + int in_init; + int read_state_first_init; + /* true when we are actually in SSL_accept() or SSL_connect() */ + int in_handshake; + /* Should we skip the CertificateVerify message? */ + unsigned int no_cert_verify; + int use_timer; +}; +typedef struct ossl_statem_st OSSL_STATEM; + +/***************************************************************************** + * * + * The following macros/functions represent the libssl internal API to the * + * state machine. Any libssl code may call these functions/macros * + * * + *****************************************************************************/ + +__owur int ossl_statem_accept(SSL *s); +__owur int ossl_statem_connect(SSL *s); +void ossl_statem_clear(SSL *s); +void ossl_statem_set_renegotiate(SSL *s); +void ossl_statem_set_error(SSL *s); +int ossl_statem_in_error(const SSL *s); +void ossl_statem_set_in_init(SSL *s, int init); +int ossl_statem_get_in_handshake(SSL *s); +void ossl_statem_set_in_handshake(SSL *s, int inhand); +void ossl_statem_set_hello_verify_done(SSL *s); +__owur int ossl_statem_app_data_allowed(SSL *s); diff --git a/openssl-1.1.0h/ssl/statem/statem_clnt.c b/openssl-1.1.0h/ssl/statem/statem_clnt.c new file mode 100644 index 0000000..6fa3f1d --- /dev/null +++ b/openssl-1.1.0h/ssl/statem/statem_clnt.c @@ -0,0 +1,2946 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (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 + */ + +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * Portions of the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the OpenSSL open source + * license provided above. + * + * ECC cipher suite support in OpenSSL originally written by + * Vipul Gupta and Sumit Gupta of Sun Microsystems Laboratories. + * + */ +/* ==================================================================== + * Copyright 2005 Nokia. All rights reserved. + * + * The portions of the attached software ("Contribution") is developed by + * Nokia Corporation and is licensed pursuant to the OpenSSL open source + * license. + * + * The Contribution, originally written by Mika Kousa and Pasi Eronen of + * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites + * support (see RFC 4279) to OpenSSL. + * + * No patent licenses or other rights except those expressly stated in + * the OpenSSL open source license shall be deemed granted or received + * expressly, by implication, estoppel, or otherwise. + * + * No assurances are provided by Nokia that the Contribution does not + * infringe the patent or other intellectual property rights of any third + * party or that the license provides you with all the necessary rights + * to make use of the Contribution. + * + * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN + * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA + * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY + * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR + * OTHERWISE. + */ + +#include <stdio.h> +#include "../ssl_locl.h" +#include "statem_locl.h" +#include <openssl/buffer.h> +#include <openssl/rand.h> +#include <openssl/objects.h> +#include <openssl/evp.h> +#include <openssl/md5.h> +#include <openssl/dh.h> +#include <openssl/bn.h> +#include <openssl/engine.h> + +static ossl_inline int cert_req_allowed(SSL *s); +static int key_exchange_expected(SSL *s); +static int ca_dn_cmp(const X509_NAME *const *a, const X509_NAME *const *b); +static int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk, + unsigned char *p); + +/* + * Is a CertificateRequest message allowed at the moment or not? + * + * Return values are: + * 1: Yes + * 0: No + */ +static ossl_inline int cert_req_allowed(SSL *s) +{ + /* TLS does not like anon-DH with client cert */ + if ((s->version > SSL3_VERSION + && (s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL)) + || (s->s3->tmp.new_cipher->algorithm_auth & (SSL_aSRP | SSL_aPSK))) + return 0; + + return 1; +} + +/* + * Should we expect the ServerKeyExchange message or not? + * + * Return values are: + * 1: Yes + * 0: No + */ +static int key_exchange_expected(SSL *s) +{ + long alg_k = s->s3->tmp.new_cipher->algorithm_mkey; + + /* + * Can't skip server key exchange if this is an ephemeral + * ciphersuite or for SRP + */ + if (alg_k & (SSL_kDHE | SSL_kECDHE | SSL_kDHEPSK | SSL_kECDHEPSK + | SSL_kSRP)) { + return 1; + } + + return 0; +} + +/* + * ossl_statem_client_read_transition() encapsulates the logic for the allowed + * handshake state transitions when the client is reading messages from the + * server. The message type that the server has sent is provided in |mt|. The + * current state is in |s->statem.hand_state|. + * + * Return values are: + * 1: Success (transition allowed) + * 0: Error (transition not allowed) + */ +int ossl_statem_client_read_transition(SSL *s, int mt) +{ + OSSL_STATEM *st = &s->statem; + int ske_expected; + + switch (st->hand_state) { + case TLS_ST_CW_CLNT_HELLO: + if (mt == SSL3_MT_SERVER_HELLO) { + st->hand_state = TLS_ST_CR_SRVR_HELLO; + return 1; + } + + if (SSL_IS_DTLS(s)) { + if (mt == DTLS1_MT_HELLO_VERIFY_REQUEST) { + st->hand_state = DTLS_ST_CR_HELLO_VERIFY_REQUEST; + return 1; + } + } + break; + + case TLS_ST_CR_SRVR_HELLO: + if (s->hit) { + if (s->tlsext_ticket_expected) { + if (mt == SSL3_MT_NEWSESSION_TICKET) { + st->hand_state = TLS_ST_CR_SESSION_TICKET; + return 1; + } + } else if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) { + st->hand_state = TLS_ST_CR_CHANGE; + return 1; + } + } else { + if (SSL_IS_DTLS(s) && mt == DTLS1_MT_HELLO_VERIFY_REQUEST) { + st->hand_state = DTLS_ST_CR_HELLO_VERIFY_REQUEST; + return 1; + } else if (s->version >= TLS1_VERSION + && s->tls_session_secret_cb != NULL + && s->session->tlsext_tick != NULL + && mt == SSL3_MT_CHANGE_CIPHER_SPEC) { + /* + * 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 message after the ServerHello to determine if + * the server is resuming. + */ + s->hit = 1; + st->hand_state = TLS_ST_CR_CHANGE; + return 1; + } else if (!(s->s3->tmp.new_cipher->algorithm_auth + & (SSL_aNULL | SSL_aSRP | SSL_aPSK))) { + if (mt == SSL3_MT_CERTIFICATE) { + st->hand_state = TLS_ST_CR_CERT; + return 1; + } + } else { + ske_expected = key_exchange_expected(s); + /* SKE is optional for some PSK ciphersuites */ + if (ske_expected + || ((s->s3->tmp.new_cipher->algorithm_mkey & SSL_PSK) + && mt == SSL3_MT_SERVER_KEY_EXCHANGE)) { + if (mt == SSL3_MT_SERVER_KEY_EXCHANGE) { + st->hand_state = TLS_ST_CR_KEY_EXCH; + return 1; + } + } else if (mt == SSL3_MT_CERTIFICATE_REQUEST + && cert_req_allowed(s)) { + st->hand_state = TLS_ST_CR_CERT_REQ; + return 1; + } else if (mt == SSL3_MT_SERVER_DONE) { + st->hand_state = TLS_ST_CR_SRVR_DONE; + return 1; + } + } + } + break; + + case TLS_ST_CR_CERT: + /* + * The CertificateStatus message is optional even if + * |tlsext_status_expected| is set + */ + if (s->tlsext_status_expected && mt == SSL3_MT_CERTIFICATE_STATUS) { + st->hand_state = TLS_ST_CR_CERT_STATUS; + return 1; + } + /* Fall through */ + + case TLS_ST_CR_CERT_STATUS: + ske_expected = key_exchange_expected(s); + /* SKE is optional for some PSK ciphersuites */ + if (ske_expected || ((s->s3->tmp.new_cipher->algorithm_mkey & SSL_PSK) + && mt == SSL3_MT_SERVER_KEY_EXCHANGE)) { + if (mt == SSL3_MT_SERVER_KEY_EXCHANGE) { + st->hand_state = TLS_ST_CR_KEY_EXCH; + return 1; + } + goto err; + } + /* Fall through */ + + case TLS_ST_CR_KEY_EXCH: + if (mt == SSL3_MT_CERTIFICATE_REQUEST) { + if (cert_req_allowed(s)) { + st->hand_state = TLS_ST_CR_CERT_REQ; + return 1; + } + goto err; + } + /* Fall through */ + + case TLS_ST_CR_CERT_REQ: + if (mt == SSL3_MT_SERVER_DONE) { + st->hand_state = TLS_ST_CR_SRVR_DONE; + return 1; + } + break; + + case TLS_ST_CW_FINISHED: + if (s->tlsext_ticket_expected) { + if (mt == SSL3_MT_NEWSESSION_TICKET) { + st->hand_state = TLS_ST_CR_SESSION_TICKET; + return 1; + } + } else if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) { + st->hand_state = TLS_ST_CR_CHANGE; + return 1; + } + break; + + case TLS_ST_CR_SESSION_TICKET: + if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) { + st->hand_state = TLS_ST_CR_CHANGE; + return 1; + } + break; + + case TLS_ST_CR_CHANGE: + if (mt == SSL3_MT_FINISHED) { + st->hand_state = TLS_ST_CR_FINISHED; + return 1; + } + break; + + default: + break; + } + + err: + /* No valid transition found */ + ssl3_send_alert(s, SSL3_AL_FATAL, SSL3_AD_UNEXPECTED_MESSAGE); + SSLerr(SSL_F_OSSL_STATEM_CLIENT_READ_TRANSITION, SSL_R_UNEXPECTED_MESSAGE); + return 0; +} + +/* + * client_write_transition() works out what handshake state to move to next + * when the client is writing messages to be sent to the server. + */ +WRITE_TRAN ossl_statem_client_write_transition(SSL *s) +{ + OSSL_STATEM *st = &s->statem; + + switch (st->hand_state) { + case TLS_ST_OK: + /* Renegotiation - fall through */ + case TLS_ST_BEFORE: + st->hand_state = TLS_ST_CW_CLNT_HELLO; + return WRITE_TRAN_CONTINUE; + + case TLS_ST_CW_CLNT_HELLO: + /* + * No transition at the end of writing because we don't know what + * we will be sent + */ + return WRITE_TRAN_FINISHED; + + case DTLS_ST_CR_HELLO_VERIFY_REQUEST: + st->hand_state = TLS_ST_CW_CLNT_HELLO; + return WRITE_TRAN_CONTINUE; + + case TLS_ST_CR_SRVR_DONE: + if (s->s3->tmp.cert_req) + st->hand_state = TLS_ST_CW_CERT; + else + st->hand_state = TLS_ST_CW_KEY_EXCH; + return WRITE_TRAN_CONTINUE; + + case TLS_ST_CW_CERT: + st->hand_state = TLS_ST_CW_KEY_EXCH; + return WRITE_TRAN_CONTINUE; + + case TLS_ST_CW_KEY_EXCH: + /* + * For TLS, cert_req is set to 2, so a cert chain of nothing is + * sent, but no verify packet is sent + */ + /* + * XXX: For now, we do not support client authentication in ECDH + * cipher suites with ECDH (rather than ECDSA) certificates. We + * need to skip the certificate verify message when client's + * ECDH public key is sent inside the client certificate. + */ + if (s->s3->tmp.cert_req == 1) { + st->hand_state = TLS_ST_CW_CERT_VRFY; + } else { + st->hand_state = TLS_ST_CW_CHANGE; + } + if (s->s3->flags & TLS1_FLAGS_SKIP_CERT_VERIFY) { + st->hand_state = TLS_ST_CW_CHANGE; + } + return WRITE_TRAN_CONTINUE; + + case TLS_ST_CW_CERT_VRFY: + st->hand_state = TLS_ST_CW_CHANGE; + return WRITE_TRAN_CONTINUE; + + case TLS_ST_CW_CHANGE: +#if defined(OPENSSL_NO_NEXTPROTONEG) + st->hand_state = TLS_ST_CW_FINISHED; +#else + if (!SSL_IS_DTLS(s) && s->s3->next_proto_neg_seen) + st->hand_state = TLS_ST_CW_NEXT_PROTO; + else + st->hand_state = TLS_ST_CW_FINISHED; +#endif + return WRITE_TRAN_CONTINUE; + +#if !defined(OPENSSL_NO_NEXTPROTONEG) + case TLS_ST_CW_NEXT_PROTO: + st->hand_state = TLS_ST_CW_FINISHED; + return WRITE_TRAN_CONTINUE; +#endif + + case TLS_ST_CW_FINISHED: + if (s->hit) { + st->hand_state = TLS_ST_OK; + ossl_statem_set_in_init(s, 0); + return WRITE_TRAN_CONTINUE; + } else { + return WRITE_TRAN_FINISHED; + } + + case TLS_ST_CR_FINISHED: + if (s->hit) { + st->hand_state = TLS_ST_CW_CHANGE; + return WRITE_TRAN_CONTINUE; + } else { + st->hand_state = TLS_ST_OK; + ossl_statem_set_in_init(s, 0); + return WRITE_TRAN_CONTINUE; + } + + default: + /* Shouldn't happen */ + return WRITE_TRAN_ERROR; + } +} + +/* + * Perform any pre work that needs to be done prior to sending a message from + * the client to the server. + */ +WORK_STATE ossl_statem_client_pre_work(SSL *s, WORK_STATE wst) +{ + OSSL_STATEM *st = &s->statem; + + switch (st->hand_state) { + case TLS_ST_CW_CLNT_HELLO: + s->shutdown = 0; + if (SSL_IS_DTLS(s)) { + /* every DTLS ClientHello resets Finished MAC */ + if (!ssl3_init_finished_mac(s)) { + ossl_statem_set_error(s); + return WORK_ERROR; + } + } + break; + + case TLS_ST_CW_CHANGE: + if (SSL_IS_DTLS(s)) { + if (s->hit) { + /* + * We're into the last flight so we don't retransmit these + * messages unless we need to. + */ + st->use_timer = 0; + } +#ifndef OPENSSL_NO_SCTP + if (BIO_dgram_is_sctp(SSL_get_wbio(s))) + return dtls_wait_for_dry(s); +#endif + } + return WORK_FINISHED_CONTINUE; + + case TLS_ST_OK: + return tls_finish_handshake(s, wst); + + default: + /* No pre work to be done */ + break; + } + + return WORK_FINISHED_CONTINUE; +} + +/* + * Perform any work that needs to be done after sending a message from the + * client to the server. + */ +WORK_STATE ossl_statem_client_post_work(SSL *s, WORK_STATE wst) +{ + OSSL_STATEM *st = &s->statem; + + s->init_num = 0; + + switch (st->hand_state) { + case TLS_ST_CW_CLNT_HELLO: + if (wst == WORK_MORE_A && statem_flush(s) != 1) + return WORK_MORE_A; + + if (SSL_IS_DTLS(s)) { + /* Treat the next message as the first packet */ + s->first_packet = 1; + } + break; + + case TLS_ST_CW_KEY_EXCH: + if (tls_client_key_exchange_post_work(s) == 0) + return WORK_ERROR; + break; + + case TLS_ST_CW_CHANGE: + s->session->cipher = s->s3->tmp.new_cipher; +#ifdef OPENSSL_NO_COMP + s->session->compress_meth = 0; +#else + if (s->s3->tmp.new_compression == NULL) + s->session->compress_meth = 0; + else + s->session->compress_meth = s->s3->tmp.new_compression->id; +#endif + if (!s->method->ssl3_enc->setup_key_block(s)) + return WORK_ERROR; + + if (!s->method->ssl3_enc->change_cipher_state(s, + SSL3_CHANGE_CIPHER_CLIENT_WRITE)) + return WORK_ERROR; + + if (SSL_IS_DTLS(s)) { +#ifndef OPENSSL_NO_SCTP + if (s->hit) { + /* + * Change to new shared key of SCTP-Auth, will be ignored if + * no SCTP used. + */ + BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY, + 0, NULL); + } +#endif + + dtls1_reset_seq_numbers(s, SSL3_CC_WRITE); + } + break; + + case TLS_ST_CW_FINISHED: +#ifndef OPENSSL_NO_SCTP + if (wst == WORK_MORE_A && SSL_IS_DTLS(s) && s->hit == 0) { + /* + * Change to new shared key of SCTP-Auth, will be ignored if + * no SCTP used. + */ + BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY, + 0, NULL); + } +#endif + if (statem_flush(s) != 1) + return WORK_MORE_B; + break; + + default: + /* No post work to be done */ + break; + } + + return WORK_FINISHED_CONTINUE; +} + +/* + * Construct a message to be sent from the client to the server. + * + * Valid return values are: + * 1: Success + * 0: Error + */ +int ossl_statem_client_construct_message(SSL *s) +{ + OSSL_STATEM *st = &s->statem; + + switch (st->hand_state) { + case TLS_ST_CW_CLNT_HELLO: + return tls_construct_client_hello(s); + + case TLS_ST_CW_CERT: + return tls_construct_client_certificate(s); + + case TLS_ST_CW_KEY_EXCH: + return tls_construct_client_key_exchange(s); + + case TLS_ST_CW_CERT_VRFY: + return tls_construct_client_verify(s); + + case TLS_ST_CW_CHANGE: + if (SSL_IS_DTLS(s)) + return dtls_construct_change_cipher_spec(s); + else + return tls_construct_change_cipher_spec(s); + +#if !defined(OPENSSL_NO_NEXTPROTONEG) + case TLS_ST_CW_NEXT_PROTO: + return tls_construct_next_proto(s); +#endif + case TLS_ST_CW_FINISHED: + return tls_construct_finished(s, + s->method-> + ssl3_enc->client_finished_label, + s->method-> + ssl3_enc->client_finished_label_len); + + default: + /* Shouldn't happen */ + break; + } + + return 0; +} + +/* + * Returns the maximum allowed length for the current message that we are + * reading. Excludes the message header. + */ +unsigned long ossl_statem_client_max_message_size(SSL *s) +{ + OSSL_STATEM *st = &s->statem; + + switch (st->hand_state) { + case TLS_ST_CR_SRVR_HELLO: + return SERVER_HELLO_MAX_LENGTH; + + case DTLS_ST_CR_HELLO_VERIFY_REQUEST: + return HELLO_VERIFY_REQUEST_MAX_LENGTH; + + case TLS_ST_CR_CERT: + return s->max_cert_list; + + case TLS_ST_CR_CERT_STATUS: + return SSL3_RT_MAX_PLAIN_LENGTH; + + case TLS_ST_CR_KEY_EXCH: + return SERVER_KEY_EXCH_MAX_LENGTH; + + case TLS_ST_CR_CERT_REQ: + /* + * Set to s->max_cert_list for compatibility with previous releases. In + * practice these messages can get quite long if servers are configured + * to provide a long list of acceptable CAs + */ + return s->max_cert_list; + + case TLS_ST_CR_SRVR_DONE: + return SERVER_HELLO_DONE_MAX_LENGTH; + + case TLS_ST_CR_CHANGE: + if (s->version == DTLS1_BAD_VER) + return 3; + return CCS_MAX_LENGTH; + + case TLS_ST_CR_SESSION_TICKET: + return SSL3_RT_MAX_PLAIN_LENGTH; + + case TLS_ST_CR_FINISHED: + return FINISHED_MAX_LENGTH; + + default: + /* Shouldn't happen */ + break; + } + + return 0; +} + +/* + * Process a message that the client has been received from the server. + */ +MSG_PROCESS_RETURN ossl_statem_client_process_message(SSL *s, PACKET *pkt) +{ + OSSL_STATEM *st = &s->statem; + + switch (st->hand_state) { + case TLS_ST_CR_SRVR_HELLO: + return tls_process_server_hello(s, pkt); + + case DTLS_ST_CR_HELLO_VERIFY_REQUEST: + return dtls_process_hello_verify(s, pkt); + + case TLS_ST_CR_CERT: + return tls_process_server_certificate(s, pkt); + + case TLS_ST_CR_CERT_STATUS: + return tls_process_cert_status(s, pkt); + + case TLS_ST_CR_KEY_EXCH: + return tls_process_key_exchange(s, pkt); + + case TLS_ST_CR_CERT_REQ: + return tls_process_certificate_request(s, pkt); + + case TLS_ST_CR_SRVR_DONE: + return tls_process_server_done(s, pkt); + + case TLS_ST_CR_CHANGE: + return tls_process_change_cipher_spec(s, pkt); + + case TLS_ST_CR_SESSION_TICKET: + return tls_process_new_session_ticket(s, pkt); + + case TLS_ST_CR_FINISHED: + return tls_process_finished(s, pkt); + + default: + /* Shouldn't happen */ + break; + } + + return MSG_PROCESS_ERROR; +} + +/* + * Perform any further processing required following the receipt of a message + * from the server + */ +WORK_STATE ossl_statem_client_post_process_message(SSL *s, WORK_STATE wst) +{ + OSSL_STATEM *st = &s->statem; + + switch (st->hand_state) { + case TLS_ST_CR_CERT_REQ: + return tls_prepare_client_certificate(s, wst); + + default: + break; + } + + /* Shouldn't happen */ + return WORK_ERROR; +} + +int tls_construct_client_hello(SSL *s) +{ + unsigned char *buf; + unsigned char *p, *d; + int i; + int protverr; + unsigned long l; + int al = 0; +#ifndef OPENSSL_NO_COMP + int j; + SSL_COMP *comp; +#endif + SSL_SESSION *sess = s->session; + + buf = (unsigned char *)s->init_buf->data; + + /* Work out what SSL/TLS/DTLS version to use */ + protverr = ssl_set_client_hello_version(s); + if (protverr != 0) { + SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, protverr); + goto err; + } + + if ((sess == NULL) || !ssl_version_supported(s, sess->ssl_version) || + /* + * In the case of EAP-FAST, we can have a pre-shared + * "ticket" without a session ID. + */ + (!sess->session_id_length && !sess->tlsext_tick) || + (sess->not_resumable)) { + if (!ssl_get_new_session(s, 0)) + goto err; + } + /* else use the pre-loaded session */ + + p = s->s3->client_random; + + /* + * 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 = ssl_handshake_start(s); + + /*- + * version indicates the negotiated version: for example from + * an SSLv2/v3 compatible client hello). The client_version + * field is the maximum version we permit and it is also + * used in RSA encrypted premaster secrets. Some servers can + * choke if we initially report a higher version then + * renegotiate to a lower one in the premaster secret. This + * didn't happen with TLS 1.0 as most servers supported it + * but it can with TLS 1.1 or later if the server only supports + * 1.0. + * + * Possible scenario with previous logic: + * 1. Client hello indicates TLS 1.2 + * 2. Server hello says TLS 1.0 + * 3. RSA encrypted premaster secret uses 1.2. + * 4. Handshake proceeds using TLS 1.0. + * 5. Server sends hello request to renegotiate. + * 6. Client hello indicates TLS v1.0 as we now + * know that is maximum server supports. + * 7. Server chokes on RSA encrypted premaster secret + * containing version 1.0. + * + * For interoperability it should be OK to always use the + * maximum version we support in client hello and then rely + * on the checking of version to ensure the servers isn't + * being inconsistent: for example initially negotiating with + * TLS 1.0 and renegotiating with TLS 1.2. We do this by using + * client_version in client hello and not resetting it to + * the negotiated version. + */ + *(p++) = s->client_version >> 8; + *(p++) = s->client_version & 0xff; + + /* Random stuff */ + memcpy(p, s->s3->client_random, SSL3_RANDOM_SIZE); + p += SSL3_RANDOM_SIZE; + + /* Session ID */ + if (s->new_session) + i = 0; + else + i = s->session->session_id_length; + *(p++) = i; + if (i != 0) { + if (i > (int)sizeof(s->session->session_id)) { + SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, ERR_R_INTERNAL_ERROR); + goto err; + } + memcpy(p, s->session->session_id, i); + p += i; + } + + /* cookie stuff for DTLS */ + if (SSL_IS_DTLS(s)) { + if (s->d1->cookie_len > sizeof(s->d1->cookie)) { + SSLerr(SSL_F_TLS_CONSTRUCT_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])); + if (i == 0) { + SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, SSL_R_NO_CIPHERS_AVAILABLE); + goto err; + } +#ifdef OPENSSL_MAX_TLS1_2_CIPHER_LENGTH + /* + * Some servers hang if client hello > 256 bytes as hack workaround + * chop number of supported ciphers to keep it well below this if we + * use TLS v1.2 + */ + if (TLS1_get_version(s) >= TLS1_2_VERSION + && i > OPENSSL_MAX_TLS1_2_CIPHER_LENGTH) + i = OPENSSL_MAX_TLS1_2_CIPHER_LENGTH & ~1; +#endif + s2n(i, p); + p += i; + + /* COMPRESSION */ +#ifdef OPENSSL_NO_COMP + *(p++) = 1; +#else + + if (!ssl_allow_compression(s) || !s->ctx->comp_methods) + j = 0; + else + j = sk_SSL_COMP_num(s->ctx->comp_methods); + *(p++) = 1 + j; + for (i = 0; i < j; i++) { + comp = sk_SSL_COMP_value(s->ctx->comp_methods, i); + *(p++) = comp->id; + } +#endif + *(p++) = 0; /* Add the NULL method */ + + /* TLS extensions */ + if (ssl_prepare_clienthello_tlsext(s) <= 0) { + SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, SSL_R_CLIENTHELLO_TLSEXT); + goto err; + } + if ((p = + 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_TLS_CONSTRUCT_CLIENT_HELLO, ERR_R_INTERNAL_ERROR); + goto err; + } + + l = p - d; + if (!ssl_set_handshake_header(s, SSL3_MT_CLIENT_HELLO, l)) { + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); + SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, ERR_R_INTERNAL_ERROR); + goto err; + } + + return 1; + err: + ossl_statem_set_error(s); + return 0; +} + +MSG_PROCESS_RETURN dtls_process_hello_verify(SSL *s, PACKET *pkt) +{ + int al; + unsigned int cookie_len; + PACKET cookiepkt; + + if (!PACKET_forward(pkt, 2) + || !PACKET_get_length_prefixed_1(pkt, &cookiepkt)) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_DTLS_PROCESS_HELLO_VERIFY, SSL_R_LENGTH_MISMATCH); + goto f_err; + } + + cookie_len = PACKET_remaining(&cookiepkt); + if (cookie_len > sizeof(s->d1->cookie)) { + al = SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_DTLS_PROCESS_HELLO_VERIFY, SSL_R_LENGTH_TOO_LONG); + goto f_err; + } + + if (!PACKET_copy_bytes(&cookiepkt, s->d1->cookie, cookie_len)) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_DTLS_PROCESS_HELLO_VERIFY, SSL_R_LENGTH_MISMATCH); + goto f_err; + } + s->d1->cookie_len = cookie_len; + + return MSG_PROCESS_FINISHED_READING; + f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + ossl_statem_set_error(s); + return MSG_PROCESS_ERROR; +} + +MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt) +{ + STACK_OF(SSL_CIPHER) *sk; + const SSL_CIPHER *c; + PACKET session_id; + size_t session_id_len; + const unsigned char *cipherchars; + int i, al = SSL_AD_INTERNAL_ERROR; + unsigned int compression; + unsigned int sversion; + int protverr; +#ifndef OPENSSL_NO_COMP + SSL_COMP *comp; +#endif + + if (!PACKET_get_net_2(pkt, &sversion)) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_LENGTH_MISMATCH); + goto f_err; + } + + protverr = ssl_choose_client_version(s, sversion); + if (protverr != 0) { + al = SSL_AD_PROTOCOL_VERSION; + SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, protverr); + goto f_err; + } + + /* load the server hello data */ + /* load the server random */ + if (!PACKET_copy_bytes(pkt, s->s3->server_random, SSL3_RANDOM_SIZE)) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_LENGTH_MISMATCH); + goto f_err; + } + + s->hit = 0; + + /* Get the session-id. */ + if (!PACKET_get_length_prefixed_1(pkt, &session_id)) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_LENGTH_MISMATCH); + goto f_err; + } + session_id_len = PACKET_remaining(&session_id); + if (session_id_len > sizeof(s->session->session_id) + || session_id_len > SSL3_SESSION_ID_SIZE) { + al = SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_SSL3_SESSION_ID_TOO_LONG); + goto f_err; + } + + if (!PACKET_get_bytes(pkt, &cipherchars, TLS_CIPHER_LEN)) { + SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_LENGTH_MISMATCH); + al = SSL_AD_DECODE_ERROR; + 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 && s->tls_session_secret_cb && + s->session->tlsext_tick) { + const SSL_CIPHER *pref_cipher = NULL; + s->session->master_key_length = sizeof(s->session->master_key); + if (s->tls_session_secret_cb(s, s->session->master_key, + &s->session->master_key_length, + NULL, &pref_cipher, + s->tls_session_secret_cb_arg)) { + 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) { + if (s->sid_ctx_length != s->session->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. + * 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) { + s->ctx->stats.sess_miss++; + if (!ssl_get_new_session(s, 0)) { + goto f_err; + } + } + + s->session->ssl_version = s->version; + s->session->session_id_length = session_id_len; + /* session_id_len could be 0 */ + if (session_id_len > 0) + memcpy(s->session->session_id, PACKET_data(&session_id), + session_id_len); + } + + /* Session version and negotiated protocol version should match */ + if (s->version != s->session->ssl_version) { + al = SSL_AD_PROTOCOL_VERSION; + + SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, + SSL_R_SSL_SESSION_VERSION_MISMATCH); + goto f_err; + } + + c = ssl_get_cipher_by_char(s, cipherchars); + if (c == NULL) { + /* unknown cipher */ + al = SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_UNKNOWN_CIPHER_RETURNED); + goto f_err; + } + /* + * Now that we know the version, update the check to see if it's an allowed + * version. + */ + s->s3->tmp.min_ver = s->version; + s->s3->tmp.max_ver = s->version; + /* + * If it is a disabled cipher we either didn't send it in client hello, + * or it's not allowed for the selected protocol. So we return an error. + */ + if (ssl_cipher_disabled(s, c, SSL_SECOP_CIPHER_CHECK, 1)) { + al = SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_WRONG_CIPHER_RETURNED); + goto f_err; + } + + sk = ssl_get_ciphers_by_id(s); + i = sk_SSL_CIPHER_find(sk, c); + if (i < 0) { + /* we did not say we would use this cipher */ + al = SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_WRONG_CIPHER_RETURNED); + goto f_err; + } + + /* + * Depending on the session caching (internal/external), the cipher + * and/or cipher_id values may not be set. Make sure that cipher_id is + * set and use it for comparison. + */ + if (s->session->cipher) + s->session->cipher_id = s->session->cipher->id; + if (s->hit && (s->session->cipher_id != c->id)) { + al = SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, + SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED); + goto f_err; + } + s->s3->tmp.new_cipher = c; + /* lets get the compression algorithm */ + /* COMPRESSION */ + 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; + } +#ifdef OPENSSL_NO_COMP + if (compression != 0) { + al = SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, + SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM); + goto f_err; + } + /* + * If compression is disabled we'd better not try to resume a session + * using compression. + */ + if (s->session->compress_meth != 0) { + SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_INCONSISTENT_COMPRESSION); + goto f_err; + } +#else + if (s->hit && compression != s->session->compress_meth) { + al = SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, + SSL_R_OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED); + goto f_err; + } + if (compression == 0) + comp = NULL; + else if (!ssl_allow_compression(s)) { + al = SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_COMPRESSION_DISABLED); + goto f_err; + } else { + comp = ssl3_comp_find(s->ctx->comp_methods, compression); + } + + if (compression != 0 && comp == NULL) { + al = SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, + SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM); + goto f_err; + } else { + s->s3->tmp.new_compression = comp; + } +#endif + + /* TLS extensions */ + if (!ssl_parse_serverhello_tlsext(s, pkt)) { + SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_PARSE_TLSEXT); + goto err; + } + + if (PACKET_remaining(pkt) != 0) { + /* wrong packet length */ + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_BAD_PACKET_LENGTH); + goto f_err; + } +#ifndef OPENSSL_NO_SCTP + if (SSL_IS_DTLS(s) && s->hit) { + unsigned char sctpauthkey[64]; + char labelbuffer[sizeof(DTLS1_SCTP_AUTH_LABEL)]; + + /* + * Add new shared key for SCTP-Auth, will be ignored if + * no SCTP used. + */ + memcpy(labelbuffer, DTLS1_SCTP_AUTH_LABEL, + sizeof(DTLS1_SCTP_AUTH_LABEL)); + + if (SSL_export_keying_material(s, sctpauthkey, + sizeof(sctpauthkey), + labelbuffer, + sizeof(labelbuffer), NULL, 0, 0) <= 0) + goto err; + + BIO_ctrl(SSL_get_wbio(s), + BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY, + sizeof(sctpauthkey), sctpauthkey); + } +#endif + + return MSG_PROCESS_CONTINUE_READING; + f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + err: + ossl_statem_set_error(s); + return MSG_PROCESS_ERROR; +} + +MSG_PROCESS_RETURN tls_process_server_certificate(SSL *s, PACKET *pkt) +{ + int al, i, ret = MSG_PROCESS_ERROR, exp_idx; + unsigned long cert_list_len, cert_len; + X509 *x = NULL; + const unsigned char *certstart, *certbytes; + STACK_OF(X509) *sk = NULL; + EVP_PKEY *pkey = NULL; + + if ((sk = sk_X509_new_null()) == NULL) { + SSLerr(SSL_F_TLS_PROCESS_SERVER_CERTIFICATE, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (!PACKET_get_net_3(pkt, &cert_list_len) + || PACKET_remaining(pkt) != cert_list_len) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_SERVER_CERTIFICATE, SSL_R_LENGTH_MISMATCH); + goto f_err; + } + while (PACKET_remaining(pkt)) { + if (!PACKET_get_net_3(pkt, &cert_len) + || !PACKET_get_bytes(pkt, &certbytes, cert_len)) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_SERVER_CERTIFICATE, + SSL_R_CERT_LENGTH_MISMATCH); + goto f_err; + } + + certstart = certbytes; + x = d2i_X509(NULL, (const unsigned char **)&certbytes, cert_len); + if (x == NULL) { + al = SSL_AD_BAD_CERTIFICATE; + SSLerr(SSL_F_TLS_PROCESS_SERVER_CERTIFICATE, ERR_R_ASN1_LIB); + goto f_err; + } + if (certbytes != (certstart + cert_len)) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_SERVER_CERTIFICATE, + SSL_R_CERT_LENGTH_MISMATCH); + goto f_err; + } + if (!sk_X509_push(sk, x)) { + SSLerr(SSL_F_TLS_PROCESS_SERVER_CERTIFICATE, ERR_R_MALLOC_FAILURE); + goto err; + } + x = NULL; + } + + i = ssl_verify_cert_chain(s, sk); + /* + * The documented interface is that SSL_VERIFY_PEER should be set in order + * for client side verification of the server certificate to take place. + * However, historically the code has only checked that *any* flag is set + * to cause server verification to take place. Use of the other flags makes + * no sense in client mode. An attempt to clean up the semantics was + * reverted because at least one application *only* set + * SSL_VERIFY_FAIL_IF_NO_PEER_CERT. Prior to the clean up this still caused + * server verification to take place, after the clean up it silently did + * nothing. SSL_CTX_set_verify()/SSL_set_verify() cannot validate the flags + * sent to them because they are void functions. Therefore, we now use the + * (less clean) historic behaviour of performing validation if any flag is + * set. The *documented* interface remains the same. + */ + if (s->verify_mode != SSL_VERIFY_NONE && i <= 0) { + al = ssl_verify_alarm_type(s->verify_result); + SSLerr(SSL_F_TLS_PROCESS_SERVER_CERTIFICATE, + SSL_R_CERTIFICATE_VERIFY_FAILED); + goto f_err; + } + ERR_clear_error(); /* but we keep s->verify_result */ + if (i > 1) { + SSLerr(SSL_F_TLS_PROCESS_SERVER_CERTIFICATE, i); + al = SSL_AD_HANDSHAKE_FAILURE; + goto f_err; + } + + s->session->peer_chain = sk; + /* + * Inconsistency alert: cert_chain does include the peer's certificate, + * which we don't include in statem_srvr.c + */ + x = sk_X509_value(sk, 0); + sk = NULL; + + pkey = X509_get0_pubkey(x); + + if (pkey == NULL || EVP_PKEY_missing_parameters(pkey)) { + x = NULL; + al = SSL3_AL_FATAL; + SSLerr(SSL_F_TLS_PROCESS_SERVER_CERTIFICATE, + SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS); + goto f_err; + } + + i = ssl_cert_type(x, pkey); + if (i < 0) { + x = NULL; + al = SSL3_AL_FATAL; + SSLerr(SSL_F_TLS_PROCESS_SERVER_CERTIFICATE, + SSL_R_UNKNOWN_CERTIFICATE_TYPE); + goto f_err; + } + + exp_idx = ssl_cipher_get_cert_index(s->s3->tmp.new_cipher); + if (exp_idx >= 0 && i != exp_idx + && (exp_idx != SSL_PKEY_GOST_EC || + (i != SSL_PKEY_GOST12_512 && i != SSL_PKEY_GOST12_256 + && i != SSL_PKEY_GOST01))) { + x = NULL; + al = SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_TLS_PROCESS_SERVER_CERTIFICATE, + SSL_R_WRONG_CERTIFICATE_TYPE); + goto f_err; + } + s->session->peer_type = i; + + X509_free(s->session->peer); + X509_up_ref(x); + s->session->peer = x; + s->session->verify_result = s->verify_result; + + x = NULL; + ret = MSG_PROCESS_CONTINUE_READING; + goto done; + + f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + err: + ossl_statem_set_error(s); + done: + X509_free(x); + sk_X509_pop_free(sk, X509_free); + return ret; +} + +static int tls_process_ske_psk_preamble(SSL *s, PACKET *pkt, int *al) +{ +#ifndef OPENSSL_NO_PSK + PACKET psk_identity_hint; + + /* PSK ciphersuites are preceded by an identity hint */ + + if (!PACKET_get_length_prefixed_2(pkt, &psk_identity_hint)) { + *al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_SKE_PSK_PREAMBLE, SSL_R_LENGTH_MISMATCH); + return 0; + } + + /* + * Store PSK identity hint for later use, hint is used in + * tls_construct_client_key_exchange. Assume that the maximum length of + * a PSK identity hint can be as long as the maximum length of a PSK + * identity. + */ + if (PACKET_remaining(&psk_identity_hint) > PSK_MAX_IDENTITY_LEN) { + *al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_TLS_PROCESS_SKE_PSK_PREAMBLE, SSL_R_DATA_LENGTH_TOO_LONG); + return 0; + } + + if (PACKET_remaining(&psk_identity_hint) == 0) { + OPENSSL_free(s->session->psk_identity_hint); + s->session->psk_identity_hint = NULL; + } else if (!PACKET_strndup(&psk_identity_hint, + &s->session->psk_identity_hint)) { + *al = SSL_AD_INTERNAL_ERROR; + return 0; + } + + return 1; +#else + SSLerr(SSL_F_TLS_PROCESS_SKE_PSK_PREAMBLE, ERR_R_INTERNAL_ERROR); + *al = SSL_AD_INTERNAL_ERROR; + return 0; +#endif +} + +static int tls_process_ske_srp(SSL *s, PACKET *pkt, EVP_PKEY **pkey, int *al) +{ +#ifndef OPENSSL_NO_SRP + PACKET prime, generator, salt, server_pub; + + if (!PACKET_get_length_prefixed_2(pkt, &prime) + || !PACKET_get_length_prefixed_2(pkt, &generator) + || !PACKET_get_length_prefixed_1(pkt, &salt) + || !PACKET_get_length_prefixed_2(pkt, &server_pub)) { + *al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_SKE_SRP, SSL_R_LENGTH_MISMATCH); + return 0; + } + + if ((s->srp_ctx.N = + BN_bin2bn(PACKET_data(&prime), + PACKET_remaining(&prime), NULL)) == NULL + || (s->srp_ctx.g = + BN_bin2bn(PACKET_data(&generator), + PACKET_remaining(&generator), NULL)) == NULL + || (s->srp_ctx.s = + BN_bin2bn(PACKET_data(&salt), + PACKET_remaining(&salt), NULL)) == NULL + || (s->srp_ctx.B = + BN_bin2bn(PACKET_data(&server_pub), + PACKET_remaining(&server_pub), NULL)) == NULL) { + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_PROCESS_SKE_SRP, ERR_R_BN_LIB); + return 0; + } + + if (!srp_verify_server_param(s, al)) { + *al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_SKE_SRP, SSL_R_BAD_SRP_PARAMETERS); + return 0; + } + + /* We must check if there is a certificate */ + if (s->s3->tmp.new_cipher->algorithm_auth & (SSL_aRSA | SSL_aDSS)) + *pkey = X509_get0_pubkey(s->session->peer); + + return 1; +#else + SSLerr(SSL_F_TLS_PROCESS_SKE_SRP, ERR_R_INTERNAL_ERROR); + *al = SSL_AD_INTERNAL_ERROR; + return 0; +#endif +} + +static int tls_process_ske_dhe(SSL *s, PACKET *pkt, EVP_PKEY **pkey, int *al) +{ +#ifndef OPENSSL_NO_DH + PACKET prime, generator, pub_key; + EVP_PKEY *peer_tmp = NULL; + + 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)) { + *al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_SKE_DHE, SSL_R_LENGTH_MISMATCH); + return 0; + } + + peer_tmp = EVP_PKEY_new(); + dh = DH_new(); + + if (peer_tmp == NULL || dh == NULL) { + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_PROCESS_SKE_DHE, ERR_R_MALLOC_FAILURE); + goto err; + } + + p = BN_bin2bn(PACKET_data(&prime), PACKET_remaining(&prime), NULL); + g = BN_bin2bn(PACKET_data(&generator), PACKET_remaining(&generator), NULL); + bnpub_key = BN_bin2bn(PACKET_data(&pub_key), PACKET_remaining(&pub_key), + NULL); + if (p == NULL || g == NULL || bnpub_key == NULL) { + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_PROCESS_SKE_DHE, ERR_R_BN_LIB); + goto err; + } + + /* test non-zero pubkey */ + 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; + } + + if (!DH_set0_pqg(dh, p, NULL, g)) { + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_PROCESS_SKE_DHE, ERR_R_BN_LIB); + 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); + goto err; + } + bnpub_key = NULL; + + if (!ssl_security(s, SSL_SECOP_TMP_DH, DH_security_bits(dh), 0, dh)) { + *al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_TLS_PROCESS_SKE_DHE, SSL_R_DH_KEY_TOO_SMALL); + goto err; + } + + if (EVP_PKEY_assign_DH(peer_tmp, dh) == 0) { + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_PROCESS_SKE_DHE, ERR_R_EVP_LIB); + goto err; + } + + s->s3->peer_tmp = peer_tmp; + + /* + * FIXME: This makes assumptions about which ciphersuites come with + * public keys. We should have a less ad-hoc way of doing this + */ + if (s->s3->tmp.new_cipher->algorithm_auth & (SSL_aRSA | SSL_aDSS)) + *pkey = X509_get0_pubkey(s->session->peer); + /* else anonymous DH, so no certificate or pkey. */ + + return 1; + + err: + BN_free(p); + BN_free(g); + BN_free(bnpub_key); + DH_free(dh); + EVP_PKEY_free(peer_tmp); + + return 0; +#else + SSLerr(SSL_F_TLS_PROCESS_SKE_DHE, ERR_R_INTERNAL_ERROR); + *al = SSL_AD_INTERNAL_ERROR; + return 0; +#endif +} + +static int tls_process_ske_ecdhe(SSL *s, PACKET *pkt, EVP_PKEY **pkey, int *al) +{ +#ifndef OPENSSL_NO_EC + PACKET encoded_pt; + const unsigned char *ecparams; + int curve_nid; + unsigned int curve_flags; + EVP_PKEY_CTX *pctx = NULL; + + /* + * Extract elliptic curve parameters and the server's ephemeral ECDH + * public key. For now we only support named (not generic) curves and + * ECParameters in this case is just three bytes. + */ + if (!PACKET_get_bytes(pkt, &ecparams, 3)) { + *al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_SKE_ECDHE, SSL_R_LENGTH_TOO_SHORT); + return 0; + } + /* + * Check curve is one of our preferences, if not server has sent an + * invalid curve. ECParameters is 3 bytes. + */ + if (!tls1_check_curve(s, ecparams, 3)) { + *al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_SKE_ECDHE, SSL_R_WRONG_CURVE); + return 0; + } + + curve_nid = tls1_ec_curve_id2nid(*(ecparams + 2), &curve_flags); + + if (curve_nid == 0) { + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_PROCESS_SKE_ECDHE, + SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS); + return 0; + } + + if ((curve_flags & TLS_CURVE_TYPE) == TLS_CURVE_CUSTOM) { + EVP_PKEY *key = EVP_PKEY_new(); + + if (key == NULL || !EVP_PKEY_set_type(key, curve_nid)) { + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_PROCESS_SKE_ECDHE, ERR_R_EVP_LIB); + EVP_PKEY_free(key); + return 0; + } + s->s3->peer_tmp = key; + } else { + /* Set up EVP_PKEY with named curve as parameters */ + pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL); + if (pctx == NULL + || EVP_PKEY_paramgen_init(pctx) <= 0 + || EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, curve_nid) <= 0 + || EVP_PKEY_paramgen(pctx, &s->s3->peer_tmp) <= 0) { + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_PROCESS_SKE_ECDHE, ERR_R_EVP_LIB); + EVP_PKEY_CTX_free(pctx); + return 0; + } + EVP_PKEY_CTX_free(pctx); + pctx = NULL; + } + + if (!PACKET_get_length_prefixed_1(pkt, &encoded_pt)) { + *al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_SKE_ECDHE, SSL_R_LENGTH_MISMATCH); + return 0; + } + + if (!EVP_PKEY_set1_tls_encodedpoint(s->s3->peer_tmp, + PACKET_data(&encoded_pt), + PACKET_remaining(&encoded_pt))) { + *al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_SKE_ECDHE, SSL_R_BAD_ECPOINT); + return 0; + } + + /* + * The ECC/TLS specification does not mention the use of DSA to sign + * ECParameters in the server key exchange message. We do support RSA + * and ECDSA. + */ + if (s->s3->tmp.new_cipher->algorithm_auth & SSL_aECDSA) + *pkey = X509_get0_pubkey(s->session->peer); + else if (s->s3->tmp.new_cipher->algorithm_auth & SSL_aRSA) + *pkey = X509_get0_pubkey(s->session->peer); + /* else anonymous ECDH, so no certificate or pkey. */ + + return 1; +#else + SSLerr(SSL_F_TLS_PROCESS_SKE_ECDHE, ERR_R_INTERNAL_ERROR); + *al = SSL_AD_INTERNAL_ERROR; + return 0; +#endif +} + +MSG_PROCESS_RETURN tls_process_key_exchange(SSL *s, PACKET *pkt) +{ + int al = -1; + long alg_k; + EVP_PKEY *pkey = NULL; + PACKET save_param_start, signature; + + alg_k = s->s3->tmp.new_cipher->algorithm_mkey; + + save_param_start = *pkt; + +#if !defined(OPENSSL_NO_EC) || !defined(OPENSSL_NO_DH) + EVP_PKEY_free(s->s3->peer_tmp); + s->s3->peer_tmp = NULL; +#endif + + if (alg_k & SSL_PSK) { + if (!tls_process_ske_psk_preamble(s, pkt, &al)) + goto err; + } + + /* Nothing else to do for plain PSK or RSAPSK */ + if (alg_k & (SSL_kPSK | SSL_kRSAPSK)) { + } else if (alg_k & SSL_kSRP) { + if (!tls_process_ske_srp(s, pkt, &pkey, &al)) + goto err; + } else if (alg_k & (SSL_kDHE | SSL_kDHEPSK)) { + if (!tls_process_ske_dhe(s, pkt, &pkey, &al)) + goto err; + } else if (alg_k & (SSL_kECDHE | SSL_kECDHEPSK)) { + if (!tls_process_ske_ecdhe(s, pkt, &pkey, &al)) + goto err; + } else if (alg_k) { + al = SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_UNEXPECTED_MESSAGE); + goto err; + } + + /* if it was signed, check the signature */ + if (pkey != NULL) { + PACKET params; + int maxsig; + const EVP_MD *md = NULL; + EVP_MD_CTX *md_ctx; + + /* + * |pkt| now points to the beginning of the signature, so the difference + * equals the length of the parameters. + */ + if (!PACKET_get_sub_packet(&save_param_start, ¶ms, + PACKET_remaining(&save_param_start) - + PACKET_remaining(pkt))) { + al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR); + goto err; + } + + if (SSL_USE_SIGALGS(s)) { + const unsigned char *sigalgs; + int rv; + if (!PACKET_get_bytes(pkt, &sigalgs, 2)) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_LENGTH_TOO_SHORT); + goto err; + } + rv = tls12_check_peer_sigalg(&md, s, sigalgs, pkey); + if (rv == -1) { + al = SSL_AD_INTERNAL_ERROR; + goto err; + } else if (rv == 0) { + al = SSL_AD_DECODE_ERROR; + goto err; + } +#ifdef SSL_DEBUG + fprintf(stderr, "USING TLSv1.2 HASH %s\n", EVP_MD_name(md)); +#endif + } else if (EVP_PKEY_id(pkey) == EVP_PKEY_RSA) { + md = EVP_md5_sha1(); + } else { + md = EVP_sha1(); + } + + if (!PACKET_get_length_prefixed_2(pkt, &signature) + || PACKET_remaining(pkt) != 0) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_LENGTH_MISMATCH); + goto err; + } + maxsig = EVP_PKEY_size(pkey); + if (maxsig < 0) { + al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR); + goto err; + } + + /* + * Check signature length + */ + if (PACKET_remaining(&signature) > (size_t)maxsig) { + /* wrong packet length */ + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, + SSL_R_WRONG_SIGNATURE_LENGTH); + goto err; + } + + md_ctx = EVP_MD_CTX_new(); + if (md_ctx == NULL) { + al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (EVP_VerifyInit_ex(md_ctx, md, NULL) <= 0 + || EVP_VerifyUpdate(md_ctx, &(s->s3->client_random[0]), + SSL3_RANDOM_SIZE) <= 0 + || EVP_VerifyUpdate(md_ctx, &(s->s3->server_random[0]), + SSL3_RANDOM_SIZE) <= 0 + || EVP_VerifyUpdate(md_ctx, PACKET_data(¶ms), + PACKET_remaining(¶ms)) <= 0) { + EVP_MD_CTX_free(md_ctx); + al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_EVP_LIB); + goto err; + } + if (EVP_VerifyFinal(md_ctx, PACKET_data(&signature), + PACKET_remaining(&signature), pkey) <= 0) { + /* bad signature */ + EVP_MD_CTX_free(md_ctx); + al = SSL_AD_DECRYPT_ERROR; + SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_BAD_SIGNATURE); + goto err; + } + EVP_MD_CTX_free(md_ctx); + } else { + /* aNULL, aSRP or PSK do not need public keys */ + if (!(s->s3->tmp.new_cipher->algorithm_auth & (SSL_aNULL | SSL_aSRP)) + && !(alg_k & SSL_PSK)) { + /* Might be wrong key type, check it */ + if (ssl3_check_cert_and_algorithm(s)) { + /* Otherwise this shouldn't happen */ + al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR); + } else { + al = SSL_AD_DECODE_ERROR; + } + goto err; + } + /* still data left over */ + if (PACKET_remaining(pkt) != 0) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_EXTRA_DATA_IN_MESSAGE); + goto err; + } + } + + return MSG_PROCESS_CONTINUE_READING; + err: + if (al != -1) + ssl3_send_alert(s, SSL3_AL_FATAL, al); + ossl_statem_set_error(s); + return MSG_PROCESS_ERROR; +} + +MSG_PROCESS_RETURN tls_process_certificate_request(SSL *s, PACKET *pkt) +{ + int ret = MSG_PROCESS_ERROR; + unsigned int list_len, ctype_num, i, name_len; + X509_NAME *xn = NULL; + const unsigned char *data; + const unsigned char *namestart, *namebytes; + STACK_OF(X509_NAME) *ca_sk = NULL; + + if ((ca_sk = sk_X509_NAME_new(ca_dn_cmp)) == NULL) { + SSLerr(SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST, ERR_R_MALLOC_FAILURE); + goto err; + } + + /* get the certificate types */ + if (!PACKET_get_1(pkt, &ctype_num) + || !PACKET_get_bytes(pkt, &data, ctype_num)) { + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + SSLerr(SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST, SSL_R_LENGTH_MISMATCH); + goto err; + } + 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); + if (s->cert->ctypes == NULL) { + SSLerr(SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST, ERR_R_MALLOC_FAILURE); + goto err; + } + memcpy(s->cert->ctypes, data, 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] = data[i]; + + if (SSL_USE_SIGALGS(s)) { + if (!PACKET_get_net_2(pkt, &list_len) + || !PACKET_get_bytes(pkt, &data, list_len)) { + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + SSLerr(SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST, + SSL_R_LENGTH_MISMATCH); + goto err; + } + + /* Clear certificate digests and validity flags */ + for (i = 0; i < SSL_PKEY_NUM; i++) { + s->s3->tmp.md[i] = NULL; + s->s3->tmp.valid_flags[i] = 0; + } + if ((list_len & 1) || !tls1_save_sigalgs(s, data, list_len)) { + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + SSLerr(SSL_F_TLS_PROCESS_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_TLS_PROCESS_CERTIFICATE_REQUEST, ERR_R_MALLOC_FAILURE); + goto err; + } + } else { + ssl_set_default_md(s); + } + + /* get the CA RDNs */ + if (!PACKET_get_net_2(pkt, &list_len) + || PACKET_remaining(pkt) != list_len) { + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + SSLerr(SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST, SSL_R_LENGTH_MISMATCH); + goto err; + } + + while (PACKET_remaining(pkt)) { + if (!PACKET_get_net_2(pkt, &name_len) + || !PACKET_get_bytes(pkt, &namebytes, name_len)) { + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + SSLerr(SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST, + SSL_R_LENGTH_MISMATCH); + goto err; + } + + namestart = namebytes; + + if ((xn = d2i_X509_NAME(NULL, (const unsigned char **)&namebytes, + name_len)) == NULL) { + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + SSLerr(SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST, ERR_R_ASN1_LIB); + goto err; + } + + if (namebytes != (namestart + name_len)) { + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + SSLerr(SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST, + SSL_R_CA_DN_LENGTH_MISMATCH); + goto err; + } + if (!sk_X509_NAME_push(ca_sk, xn)) { + SSLerr(SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST, ERR_R_MALLOC_FAILURE); + goto err; + } + xn = NULL; + } + + /* we should setup a certificate to return.... */ + s->s3->tmp.cert_req = 1; + s->s3->tmp.ctype_num = ctype_num; + sk_X509_NAME_pop_free(s->s3->tmp.ca_names, X509_NAME_free); + s->s3->tmp.ca_names = ca_sk; + ca_sk = NULL; + + ret = MSG_PROCESS_CONTINUE_PROCESSING; + goto done; + err: + ossl_statem_set_error(s); + done: + X509_NAME_free(xn); + sk_X509_NAME_pop_free(ca_sk, X509_NAME_free); + return ret; +} + +static int ca_dn_cmp(const X509_NAME *const *a, const X509_NAME *const *b) +{ + return (X509_NAME_cmp(*a, *b)); +} + +MSG_PROCESS_RETURN tls_process_new_session_ticket(SSL *s, PACKET *pkt) +{ + int al; + unsigned int ticklen; + unsigned long ticket_lifetime_hint; + + if (!PACKET_get_net_4(pkt, &ticket_lifetime_hint) + || !PACKET_get_net_2(pkt, &ticklen) + || 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. */ + if (ticklen == 0) + return MSG_PROCESS_CONTINUE_READING; + + 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. 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_TLS_PROCESS_NEW_SESSION_TICKET, ERR_R_MALLOC_FAILURE); + goto f_err; + } + + SSL_SESSION_free(s->session); + s->session = new_sess; + } + + OPENSSL_free(s->session->tlsext_tick); + s->session->tlsext_ticklen = 0; + + s->session->tlsext_tick = OPENSSL_malloc(ticklen); + if (s->session->tlsext_tick == NULL) { + SSLerr(SSL_F_TLS_PROCESS_NEW_SESSION_TICKET, ERR_R_MALLOC_FAILURE); + goto err; + } + if (!PACKET_copy_bytes(pkt, s->session->tlsext_tick, ticklen)) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_NEW_SESSION_TICKET, SSL_R_LENGTH_MISMATCH); + goto f_err; + } + + s->session->tlsext_tick_lifetime_hint = ticket_lifetime_hint; + s->session->tlsext_ticklen = ticklen; + /* + * 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 + * ServerHello. This allows the normal client session ID matching to work + * and we know much earlier that the ticket has been accepted. The + * other way is to set zero length session ID when the ticket is + * presented and rely on the handshake to determine session resumption. + * We choose the former approach because this fits in with assumptions + * elsewhere in OpenSSL. The session ID is set to the SHA256 (or SHA1 is + * SHA256 is disabled) hash of the ticket. + */ + if (!EVP_Digest(s->session->tlsext_tick, ticklen, + s->session->session_id, &s->session->session_id_length, + EVP_sha256(), NULL)) { + SSLerr(SSL_F_TLS_PROCESS_NEW_SESSION_TICKET, ERR_R_EVP_LIB); + goto err; + } + return MSG_PROCESS_CONTINUE_READING; + f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + err: + ossl_statem_set_error(s); + return MSG_PROCESS_ERROR; +} + +MSG_PROCESS_RETURN tls_process_cert_status(SSL *s, PACKET *pkt) +{ + int al; + unsigned long resplen; + unsigned int type; + + if (!PACKET_get_1(pkt, &type) + || type != TLSEXT_STATUSTYPE_ocsp) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CERT_STATUS, SSL_R_UNSUPPORTED_STATUS_TYPE); + goto f_err; + } + if (!PACKET_get_net_3(pkt, &resplen) + || PACKET_remaining(pkt) != resplen) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CERT_STATUS, SSL_R_LENGTH_MISMATCH); + goto f_err; + } + s->tlsext_ocsp_resp = OPENSSL_malloc(resplen); + if (s->tlsext_ocsp_resp == NULL) { + al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CERT_STATUS, ERR_R_MALLOC_FAILURE); + goto f_err; + } + if (!PACKET_copy_bytes(pkt, s->tlsext_ocsp_resp, resplen)) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CERT_STATUS, SSL_R_LENGTH_MISMATCH); + goto f_err; + } + s->tlsext_ocsp_resplen = resplen; + return MSG_PROCESS_CONTINUE_READING; + f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + ossl_statem_set_error(s); + return MSG_PROCESS_ERROR; +} + +MSG_PROCESS_RETURN tls_process_server_done(SSL *s, PACKET *pkt) +{ + if (PACKET_remaining(pkt) > 0) { + /* should contain no data */ + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + SSLerr(SSL_F_TLS_PROCESS_SERVER_DONE, SSL_R_LENGTH_MISMATCH); + ossl_statem_set_error(s); + return MSG_PROCESS_ERROR; + } +#ifndef OPENSSL_NO_SRP + if (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kSRP) { + if (SRP_Calc_A_param(s) <= 0) { + SSLerr(SSL_F_TLS_PROCESS_SERVER_DONE, SSL_R_SRP_A_CALC); + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + ossl_statem_set_error(s); + return MSG_PROCESS_ERROR; + } + } +#endif + + /* + * at this point we check that we have the required stuff from + * the server + */ + if (!ssl3_check_cert_and_algorithm(s)) { + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); + ossl_statem_set_error(s); + return MSG_PROCESS_ERROR; + } + + /* + * Call the ocsp status callback if needed. The |tlsext_ocsp_resp| and + * |tlsext_ocsp_resplen| values will be set if we actually received a status + * message, or NULL and -1 otherwise + */ + if (s->tlsext_status_type != -1 && s->ctx->tlsext_status_cb != NULL) { + int ret; + ret = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg); + if (ret == 0) { + ssl3_send_alert(s, SSL3_AL_FATAL, + SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE); + SSLerr(SSL_F_TLS_PROCESS_SERVER_DONE, + SSL_R_INVALID_STATUS_RESPONSE); + return MSG_PROCESS_ERROR; + } + if (ret < 0) { + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + SSLerr(SSL_F_TLS_PROCESS_SERVER_DONE, ERR_R_MALLOC_FAILURE); + return MSG_PROCESS_ERROR; + } + } +#ifndef OPENSSL_NO_CT + if (s->ct_validation_callback != NULL) { + /* Note we validate the SCTs whether or not we abort on error */ + if (!ssl_validate_ct(s) && (s->verify_mode & SSL_VERIFY_PEER)) { + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); + return MSG_PROCESS_ERROR; + } + } +#endif + + return MSG_PROCESS_FINISHED_READING; +} + +static int tls_construct_cke_psk_preamble(SSL *s, unsigned char **p, + size_t *pskhdrlen, int *al) +{ +#ifndef OPENSSL_NO_PSK + int ret = 0; + /* + * The callback needs PSK_MAX_IDENTITY_LEN + 1 bytes to return a + * \0-terminated identity. The last byte is for us for simulating + * strnlen. + */ + char identity[PSK_MAX_IDENTITY_LEN + 1]; + size_t identitylen = 0; + unsigned char psk[PSK_MAX_PSK_LEN]; + unsigned char *tmppsk = NULL; + char *tmpidentity = NULL; + size_t psklen = 0; + + if (s->psk_client_callback == NULL) { + SSLerr(SSL_F_TLS_CONSTRUCT_CKE_PSK_PREAMBLE, SSL_R_PSK_NO_CLIENT_CB); + *al = SSL_AD_INTERNAL_ERROR; + goto err; + } + + memset(identity, 0, sizeof(identity)); + + psklen = s->psk_client_callback(s, s->session->psk_identity_hint, + identity, sizeof(identity) - 1, + psk, sizeof(psk)); + + if (psklen > PSK_MAX_PSK_LEN) { + SSLerr(SSL_F_TLS_CONSTRUCT_CKE_PSK_PREAMBLE, ERR_R_INTERNAL_ERROR); + *al = SSL_AD_HANDSHAKE_FAILURE; + goto err; + } else if (psklen == 0) { + SSLerr(SSL_F_TLS_CONSTRUCT_CKE_PSK_PREAMBLE, + SSL_R_PSK_IDENTITY_NOT_FOUND); + *al = SSL_AD_HANDSHAKE_FAILURE; + goto err; + } + + identitylen = strlen(identity); + if (identitylen > PSK_MAX_IDENTITY_LEN) { + SSLerr(SSL_F_TLS_CONSTRUCT_CKE_PSK_PREAMBLE, ERR_R_INTERNAL_ERROR); + *al = SSL_AD_HANDSHAKE_FAILURE; + goto err; + } + + tmppsk = OPENSSL_memdup(psk, psklen); + tmpidentity = OPENSSL_strdup(identity); + if (tmppsk == NULL || tmpidentity == NULL) { + SSLerr(SSL_F_TLS_CONSTRUCT_CKE_PSK_PREAMBLE, ERR_R_MALLOC_FAILURE); + *al = SSL_AD_INTERNAL_ERROR; + goto err; + } + + OPENSSL_free(s->s3->tmp.psk); + s->s3->tmp.psk = tmppsk; + s->s3->tmp.psklen = psklen; + tmppsk = NULL; + OPENSSL_free(s->session->psk_identity); + s->session->psk_identity = tmpidentity; + tmpidentity = NULL; + s2n(identitylen, *p); + memcpy(*p, identity, identitylen); + *pskhdrlen = 2 + identitylen; + *p += identitylen; + + ret = 1; + + err: + OPENSSL_cleanse(psk, psklen); + OPENSSL_cleanse(identity, sizeof(identity)); + OPENSSL_clear_free(tmppsk, psklen); + OPENSSL_clear_free(tmpidentity, identitylen); + + return ret; +#else + SSLerr(SSL_F_TLS_CONSTRUCT_CKE_PSK_PREAMBLE, ERR_R_INTERNAL_ERROR); + *al = SSL_AD_INTERNAL_ERROR; + return 0; +#endif +} + +static int tls_construct_cke_rsa(SSL *s, unsigned char **p, int *len, int *al) +{ +#ifndef OPENSSL_NO_RSA + unsigned char *q; + EVP_PKEY *pkey = NULL; + EVP_PKEY_CTX *pctx = NULL; + size_t enclen; + unsigned char *pms = NULL; + size_t pmslen = 0; + + if (s->session->peer == NULL) { + /* + * We should always have a server certificate with SSL_kRSA. + */ + SSLerr(SSL_F_TLS_CONSTRUCT_CKE_RSA, ERR_R_INTERNAL_ERROR); + return 0; + } + + pkey = X509_get0_pubkey(s->session->peer); + if (EVP_PKEY_get0_RSA(pkey) == NULL) { + SSLerr(SSL_F_TLS_CONSTRUCT_CKE_RSA, ERR_R_INTERNAL_ERROR); + return 0; + } + + pmslen = SSL_MAX_MASTER_KEY_LENGTH; + pms = OPENSSL_malloc(pmslen); + if (pms == NULL) { + SSLerr(SSL_F_TLS_CONSTRUCT_CKE_RSA, ERR_R_MALLOC_FAILURE); + *al = SSL_AD_INTERNAL_ERROR; + return 0; + } + + pms[0] = s->client_version >> 8; + pms[1] = s->client_version & 0xff; + if (RAND_bytes(pms + 2, pmslen - 2) <= 0) { + goto err; + } + + q = *p; + /* Fix buf for TLS and beyond */ + if (s->version > SSL3_VERSION) + *p += 2; + pctx = EVP_PKEY_CTX_new(pkey, NULL); + if (pctx == NULL || EVP_PKEY_encrypt_init(pctx) <= 0 + || EVP_PKEY_encrypt(pctx, NULL, &enclen, pms, pmslen) <= 0) { + SSLerr(SSL_F_TLS_CONSTRUCT_CKE_RSA, ERR_R_EVP_LIB); + goto err; + } + if (EVP_PKEY_encrypt(pctx, *p, &enclen, pms, pmslen) <= 0) { + SSLerr(SSL_F_TLS_CONSTRUCT_CKE_RSA, SSL_R_BAD_RSA_ENCRYPT); + goto err; + } + *len = enclen; + EVP_PKEY_CTX_free(pctx); + pctx = NULL; +# ifdef PKCS1_CHECK + if (s->options & SSL_OP_PKCS1_CHECK_1) + (*p)[1]++; + if (s->options & SSL_OP_PKCS1_CHECK_2) + tmp_buf[0] = 0x70; +# endif + + /* Fix buf for TLS and beyond */ + if (s->version > SSL3_VERSION) { + s2n(*len, q); + *len += 2; + } + + s->s3->tmp.pms = pms; + s->s3->tmp.pmslen = pmslen; + + return 1; + err: + OPENSSL_clear_free(pms, pmslen); + EVP_PKEY_CTX_free(pctx); + + return 0; +#else + SSLerr(SSL_F_TLS_CONSTRUCT_CKE_RSA, ERR_R_INTERNAL_ERROR); + *al = SSL_AD_INTERNAL_ERROR; + return 0; +#endif +} + +static int tls_construct_cke_dhe(SSL *s, unsigned char **p, int *len, int *al) +{ +#ifndef OPENSSL_NO_DH + DH *dh_clnt = NULL; + const BIGNUM *pub_key; + EVP_PKEY *ckey = NULL, *skey = NULL; + + skey = s->s3->peer_tmp; + if (skey == NULL) { + SSLerr(SSL_F_TLS_CONSTRUCT_CKE_DHE, ERR_R_INTERNAL_ERROR); + return 0; + } + ckey = ssl_generate_pkey(skey); + if (ckey == NULL) { + SSLerr(SSL_F_TLS_CONSTRUCT_CKE_DHE, ERR_R_INTERNAL_ERROR); + return 0; + } + + dh_clnt = EVP_PKEY_get0_DH(ckey); + + if (dh_clnt == NULL || ssl_derive(s, ckey, skey) == 0) { + SSLerr(SSL_F_TLS_CONSTRUCT_CKE_DHE, ERR_R_INTERNAL_ERROR); + EVP_PKEY_free(ckey); + return 0; + } + + /* send off the data */ + DH_get0_key(dh_clnt, &pub_key, NULL); + *len = BN_num_bytes(pub_key); + s2n(*len, *p); + BN_bn2bin(pub_key, *p); + *len += 2; + EVP_PKEY_free(ckey); + + return 1; +#else + SSLerr(SSL_F_TLS_CONSTRUCT_CKE_DHE, ERR_R_INTERNAL_ERROR); + *al = SSL_AD_INTERNAL_ERROR; + return 0; +#endif +} + +static int tls_construct_cke_ecdhe(SSL *s, unsigned char **p, int *len, int *al) +{ +#ifndef OPENSSL_NO_EC + unsigned char *encodedPoint = NULL; + int encoded_pt_len = 0; + EVP_PKEY *ckey = NULL, *skey = NULL; + + skey = s->s3->peer_tmp; + if (skey == NULL) { + SSLerr(SSL_F_TLS_CONSTRUCT_CKE_ECDHE, ERR_R_INTERNAL_ERROR); + return 0; + } + + ckey = ssl_generate_pkey(skey); + if (ckey == NULL) { + SSLerr(SSL_F_TLS_CONSTRUCT_CKE_ECDHE, ERR_R_INTERNAL_ERROR); + goto err; + } + + if (ssl_derive(s, ckey, skey) == 0) { + SSLerr(SSL_F_TLS_CONSTRUCT_CKE_ECDHE, ERR_R_EVP_LIB); + goto err; + } + + /* Generate encoding of client key */ + encoded_pt_len = EVP_PKEY_get1_tls_encodedpoint(ckey, &encodedPoint); + + if (encoded_pt_len == 0) { + SSLerr(SSL_F_TLS_CONSTRUCT_CKE_ECDHE, ERR_R_EC_LIB); + goto err; + } + + EVP_PKEY_free(ckey); + ckey = NULL; + + *len = encoded_pt_len; + + /* length of encoded point */ + **p = *len; + *p += 1; + /* copy the point */ + memcpy(*p, encodedPoint, *len); + /* increment len to account for length field */ + *len += 1; + + OPENSSL_free(encodedPoint); + + return 1; + err: + EVP_PKEY_free(ckey); + return 0; +#else + SSLerr(SSL_F_TLS_CONSTRUCT_CKE_ECDHE, ERR_R_INTERNAL_ERROR); + *al = SSL_AD_INTERNAL_ERROR; + return 0; +#endif +} + +static int tls_construct_cke_gost(SSL *s, unsigned char **p, int *len, int *al) +{ +#ifndef OPENSSL_NO_GOST + /* GOST key exchange message creation */ + EVP_PKEY_CTX *pkey_ctx = NULL; + X509 *peer_cert; + size_t msglen; + unsigned int md_len; + unsigned char shared_ukm[32], tmp[256]; + EVP_MD_CTX *ukm_hash = NULL; + int dgst_nid = NID_id_GostR3411_94; + unsigned char *pms = NULL; + size_t pmslen = 0; + + if ((s->s3->tmp.new_cipher->algorithm_auth & SSL_aGOST12) != 0) + dgst_nid = NID_id_GostR3411_2012_256; + + /* + * Get server certificate PKEY and create ctx from it + */ + peer_cert = s->session->peer; + if (!peer_cert) { + *al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_TLS_CONSTRUCT_CKE_GOST, + SSL_R_NO_GOST_CERTIFICATE_SENT_BY_PEER); + return 0; + } + + pkey_ctx = EVP_PKEY_CTX_new(X509_get0_pubkey(peer_cert), NULL); + if (pkey_ctx == NULL) { + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_CONSTRUCT_CKE_GOST, ERR_R_MALLOC_FAILURE); + return 0; + } + /* + * If we have send a certificate, and certificate key + * parameters match those of server certificate, use + * certificate key for key exchange + */ + + /* Otherwise, generate ephemeral key pair */ + pmslen = 32; + pms = OPENSSL_malloc(pmslen); + if (pms == NULL) { + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_CONSTRUCT_CKE_GOST, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (EVP_PKEY_encrypt_init(pkey_ctx) <= 0 + /* Generate session key */ + || RAND_bytes(pms, pmslen) <= 0) { + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_CONSTRUCT_CKE_GOST, ERR_R_INTERNAL_ERROR); + goto err; + }; + /* + * Compute shared IV and store it in algorithm-specific context + * data + */ + ukm_hash = EVP_MD_CTX_new(); + if (ukm_hash == NULL + || EVP_DigestInit(ukm_hash, EVP_get_digestbynid(dgst_nid)) <= 0 + || EVP_DigestUpdate(ukm_hash, s->s3->client_random, + SSL3_RANDOM_SIZE) <= 0 + || EVP_DigestUpdate(ukm_hash, s->s3->server_random, + SSL3_RANDOM_SIZE) <= 0 + || EVP_DigestFinal_ex(ukm_hash, shared_ukm, &md_len) <= 0) { + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_CONSTRUCT_CKE_GOST, ERR_R_INTERNAL_ERROR); + goto err; + } + EVP_MD_CTX_free(ukm_hash); + ukm_hash = NULL; + if (EVP_PKEY_CTX_ctrl(pkey_ctx, -1, EVP_PKEY_OP_ENCRYPT, + EVP_PKEY_CTRL_SET_IV, 8, shared_ukm) < 0) { + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_CONSTRUCT_CKE_GOST, SSL_R_LIBRARY_BUG); + goto err; + } + /* Make GOST keytransport blob message */ + /* + * Encapsulate it into sequence + */ + *((*p)++) = V_ASN1_SEQUENCE | V_ASN1_CONSTRUCTED; + msglen = 255; + if (EVP_PKEY_encrypt(pkey_ctx, tmp, &msglen, pms, pmslen) <= 0) { + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_CONSTRUCT_CKE_GOST, SSL_R_LIBRARY_BUG); + goto err; + } + if (msglen >= 0x80) { + *((*p)++) = 0x81; + *((*p)++) = msglen & 0xff; + *len = msglen + 3; + } else { + *((*p)++) = msglen & 0xff; + *len = msglen + 2; + } + memcpy(*p, tmp, msglen); + + EVP_PKEY_CTX_free(pkey_ctx); + s->s3->tmp.pms = pms; + s->s3->tmp.pmslen = pmslen; + + return 1; + err: + EVP_PKEY_CTX_free(pkey_ctx); + OPENSSL_clear_free(pms, pmslen); + EVP_MD_CTX_free(ukm_hash); + return 0; +#else + SSLerr(SSL_F_TLS_CONSTRUCT_CKE_GOST, ERR_R_INTERNAL_ERROR); + *al = SSL_AD_INTERNAL_ERROR; + return 0; +#endif +} + +static int tls_construct_cke_srp(SSL *s, unsigned char **p, int *len, int *al) +{ +#ifndef OPENSSL_NO_SRP + if (s->srp_ctx.A != NULL) { + /* send off the data */ + *len = BN_num_bytes(s->srp_ctx.A); + s2n(*len, *p); + BN_bn2bin(s->srp_ctx.A, *p); + *len += 2; + } else { + SSLerr(SSL_F_TLS_CONSTRUCT_CKE_SRP, ERR_R_INTERNAL_ERROR); + return 0; + } + OPENSSL_free(s->session->srp_username); + s->session->srp_username = OPENSSL_strdup(s->srp_ctx.login); + if (s->session->srp_username == NULL) { + SSLerr(SSL_F_TLS_CONSTRUCT_CKE_SRP, ERR_R_MALLOC_FAILURE); + return 0; + } + + return 1; +#else + SSLerr(SSL_F_TLS_CONSTRUCT_CKE_SRP, ERR_R_INTERNAL_ERROR); + *al = SSL_AD_INTERNAL_ERROR; + return 0; +#endif +} + +int tls_construct_client_key_exchange(SSL *s) +{ + unsigned char *p; + int len; + size_t pskhdrlen = 0; + unsigned long alg_k; + int al = -1; + + alg_k = s->s3->tmp.new_cipher->algorithm_mkey; + + p = ssl_handshake_start(s); + + if ((alg_k & SSL_PSK) + && !tls_construct_cke_psk_preamble(s, &p, &pskhdrlen, &al)) + goto err; + + if (alg_k & SSL_kPSK) { + len = 0; + } else if (alg_k & (SSL_kRSA | SSL_kRSAPSK)) { + if (!tls_construct_cke_rsa(s, &p, &len, &al)) + goto err; + } else if (alg_k & (SSL_kDHE | SSL_kDHEPSK)) { + if (!tls_construct_cke_dhe(s, &p, &len, &al)) + goto err; + } else if (alg_k & (SSL_kECDHE | SSL_kECDHEPSK)) { + if (!tls_construct_cke_ecdhe(s, &p, &len, &al)) + goto err; + } else if (alg_k & SSL_kGOST) { + if (!tls_construct_cke_gost(s, &p, &len, &al)) + goto err; + } else if (alg_k & SSL_kSRP) { + if (!tls_construct_cke_srp(s, &p, &len, &al)) + goto err; + } else { + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); + SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR); + goto err; + } + + len += pskhdrlen; + + if (!ssl_set_handshake_header(s, SSL3_MT_CLIENT_KEY_EXCHANGE, len)) { + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); + SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR); + goto err; + } + + return 1; + err: + if (al != -1) + ssl3_send_alert(s, SSL3_AL_FATAL, al); + OPENSSL_clear_free(s->s3->tmp.pms, s->s3->tmp.pmslen); + s->s3->tmp.pms = NULL; +#ifndef OPENSSL_NO_PSK + OPENSSL_clear_free(s->s3->tmp.psk, s->s3->tmp.psklen); + s->s3->tmp.psk = NULL; +#endif + ossl_statem_set_error(s); + return 0; +} + +int tls_client_key_exchange_post_work(SSL *s) +{ + unsigned char *pms = NULL; + size_t pmslen = 0; + + pms = s->s3->tmp.pms; + pmslen = s->s3->tmp.pmslen; + +#ifndef OPENSSL_NO_SRP + /* Check for SRP */ + if (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kSRP) { + if (!srp_generate_client_master_secret(s)) { + SSLerr(SSL_F_TLS_CLIENT_KEY_EXCHANGE_POST_WORK, + ERR_R_INTERNAL_ERROR); + goto err; + } + return 1; + } +#endif + + if (pms == NULL && !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)) { + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + SSLerr(SSL_F_TLS_CLIENT_KEY_EXCHANGE_POST_WORK, ERR_R_MALLOC_FAILURE); + goto err; + } + if (!ssl_generate_master_secret(s, pms, pmslen, 1)) { + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + SSLerr(SSL_F_TLS_CLIENT_KEY_EXCHANGE_POST_WORK, ERR_R_INTERNAL_ERROR); + /* ssl_generate_master_secret frees the pms even on error */ + pms = NULL; + pmslen = 0; + goto err; + } + pms = NULL; + pmslen = 0; + +#ifndef OPENSSL_NO_SCTP + if (SSL_IS_DTLS(s)) { + unsigned char sctpauthkey[64]; + char labelbuffer[sizeof(DTLS1_SCTP_AUTH_LABEL)]; + + /* + * Add new shared key for SCTP-Auth, will be ignored if no SCTP + * used. + */ + memcpy(labelbuffer, DTLS1_SCTP_AUTH_LABEL, + sizeof(DTLS1_SCTP_AUTH_LABEL)); + + if (SSL_export_keying_material(s, sctpauthkey, + sizeof(sctpauthkey), labelbuffer, + sizeof(labelbuffer), NULL, 0, 0) <= 0) + goto err; + + BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY, + sizeof(sctpauthkey), sctpauthkey); + } +#endif + + return 1; + err: + OPENSSL_clear_free(pms, pmslen); + s->s3->tmp.pms = NULL; + return 0; +} + +int tls_construct_client_verify(SSL *s) +{ + unsigned char *p; + EVP_PKEY *pkey; + const EVP_MD *md = s->s3->tmp.md[s->cert->key - s->cert->pkeys]; + EVP_MD_CTX *mctx; + unsigned u = 0; + unsigned long n = 0; + long hdatalen = 0; + void *hdata; + + mctx = EVP_MD_CTX_new(); + if (mctx == NULL) { + SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY, ERR_R_MALLOC_FAILURE); + goto err; + } + + p = ssl_handshake_start(s); + pkey = s->cert->key->privatekey; + + hdatalen = BIO_get_mem_data(s->s3->handshake_buffer, &hdata); + if (hdatalen <= 0) { + SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY, ERR_R_INTERNAL_ERROR); + goto err; + } + if (SSL_USE_SIGALGS(s)) { + if (!tls12_get_sigandhash(p, pkey, md)) { + SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY, ERR_R_INTERNAL_ERROR); + goto err; + } + p += 2; + n = 2; + } +#ifdef SSL_DEBUG + fprintf(stderr, "Using client alg %s\n", EVP_MD_name(md)); +#endif + if (!EVP_SignInit_ex(mctx, md, NULL) + || !EVP_SignUpdate(mctx, hdata, hdatalen) + || (s->version == SSL3_VERSION + && !EVP_MD_CTX_ctrl(mctx, EVP_CTRL_SSL3_MASTER_SECRET, + s->session->master_key_length, + s->session->master_key)) + || !EVP_SignFinal(mctx, p + 2, &u, pkey)) { + SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY, ERR_R_EVP_LIB); + goto err; + } +#ifndef OPENSSL_NO_GOST + { + int pktype = EVP_PKEY_id(pkey); + if (pktype == NID_id_GostR3410_2001 + || pktype == NID_id_GostR3410_2012_256 + || pktype == NID_id_GostR3410_2012_512) + BUF_reverse(p + 2, NULL, u); + } +#endif + + s2n(u, p); + n += u + 2; + /* Digest cached records and discard handshake buffer */ + if (!ssl3_digest_cached_records(s, 0)) + goto err; + if (!ssl_set_handshake_header(s, SSL3_MT_CERTIFICATE_VERIFY, n)) { + SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY, ERR_R_INTERNAL_ERROR); + goto err; + } + + EVP_MD_CTX_free(mctx); + return 1; + err: + EVP_MD_CTX_free(mctx); + return 0; +} + +/* + * 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) +{ + 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->s3->tmp.md[s->cert->key - s->cert->pkeys]) + 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; + return 1; +} + +WORK_STATE tls_prepare_client_certificate(SSL *s, WORK_STATE wst) +{ + X509 *x509 = NULL; + EVP_PKEY *pkey = NULL; + int i; + + if (wst == WORK_MORE_A) { + /* 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 WORK_MORE_A; + } + if (i == 0) { + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + ossl_statem_set_error(s); + return 0; + } + s->rwstate = SSL_NOTHING; + } + if (ssl3_check_client_certificate(s)) + return WORK_FINISHED_CONTINUE; + + /* Fall through to WORK_MORE_B */ + wst = WORK_MORE_B; + } + + /* We need to get a client cert */ + if (wst == WORK_MORE_B) { + /* + * If we get an error, we need to ssl->rwstate=SSL_X509_LOOKUP; + * return(-1); We then get retied later + */ + i = ssl_do_client_cert_cb(s, &x509, &pkey); + if (i < 0) { + s->rwstate = SSL_X509_LOOKUP; + return WORK_MORE_B; + } + s->rwstate = SSL_NOTHING; + if ((i == 1) && (pkey != NULL) && (x509 != NULL)) { + if (!SSL_use_certificate(s, x509) || !SSL_use_PrivateKey(s, pkey)) + i = 0; + } else if (i == 1) { + i = 0; + SSLerr(SSL_F_TLS_PREPARE_CLIENT_CERTIFICATE, + SSL_R_BAD_DATA_RETURNED_BY_CALLBACK); + } + + X509_free(x509); + 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; + ssl3_send_alert(s, SSL3_AL_WARNING, SSL_AD_NO_CERTIFICATE); + return WORK_FINISHED_CONTINUE; + } else { + s->s3->tmp.cert_req = 2; + if (!ssl3_digest_cached_records(s, 0)) { + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + ossl_statem_set_error(s); + return 0; + } + } + } + + return WORK_FINISHED_CONTINUE; + } + + /* Shouldn't ever get here */ + return WORK_ERROR; +} + +int tls_construct_client_certificate(SSL *s) +{ + if (!ssl3_output_cert_chain(s, + (s->s3->tmp.cert_req == + 2) ? NULL : s->cert->key)) { + SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_CERTIFICATE, ERR_R_INTERNAL_ERROR); + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + ossl_statem_set_error(s); + return 0; + } + + return 1; +} + +#define has_bits(i,m) (((i)&(m)) == (m)) + +int ssl3_check_cert_and_algorithm(SSL *s) +{ + int i; +#ifndef OPENSSL_NO_EC + int idx; +#endif + long alg_k, alg_a; + EVP_PKEY *pkey = NULL; + int al = SSL_AD_HANDSHAKE_FAILURE; + + alg_k = s->s3->tmp.new_cipher->algorithm_mkey; + alg_a = s->s3->tmp.new_cipher->algorithm_auth; + + /* we don't have a certificate */ + if ((alg_a & SSL_aNULL) || (alg_k & SSL_kPSK)) + return (1); + + /* This is the passed certificate */ + +#ifndef OPENSSL_NO_EC + idx = s->session->peer_type; + if (idx == SSL_PKEY_ECC) { + if (ssl_check_srvr_ecc_cert_and_alg(s->session->peer, s) == 0) { + /* check failed */ + SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, SSL_R_BAD_ECC_CERT); + goto f_err; + } 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; + } +#endif + pkey = X509_get0_pubkey(s->session->peer); + i = X509_certificate_type(s->session->peer, pkey); + + /* Check that we have a certificate if we require one */ + if ((alg_a & SSL_aRSA) && !has_bits(i, EVP_PK_RSA | EVP_PKT_SIGN)) { + SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, + SSL_R_MISSING_RSA_SIGNING_CERT); + goto f_err; + } +#ifndef OPENSSL_NO_DSA + else if ((alg_a & SSL_aDSS) && !has_bits(i, EVP_PK_DSA | EVP_PKT_SIGN)) { + SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, + SSL_R_MISSING_DSA_SIGNING_CERT); + goto f_err; + } +#endif +#ifndef OPENSSL_NO_RSA + if (alg_k & (SSL_kRSA | SSL_kRSAPSK) && + !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; + } +#endif +#ifndef OPENSSL_NO_DH + if ((alg_k & SSL_kDHE) && (s->s3->peer_tmp == NULL)) { + al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, ERR_R_INTERNAL_ERROR); + goto f_err; + } +#endif + + return (1); + f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + return (0); +} + +#ifndef OPENSSL_NO_NEXTPROTONEG +int tls_construct_next_proto(SSL *s) +{ + unsigned int len, padding_len; + unsigned char *d; + + len = s->next_proto_negotiated_len; + padding_len = 32 - ((len + 2) % 32); + d = (unsigned char *)s->init_buf->data; + d[4] = len; + memcpy(d + 5, s->next_proto_negotiated, len); + d[5 + len] = padding_len; + memset(d + 6 + len, 0, padding_len); + *(d++) = SSL3_MT_NEXT_PROTO; + l2n3(2 + len + padding_len, d); + s->init_num = 4 + 2 + len + padding_len; + s->init_off = 0; + + return 1; +} +#endif + +int ssl_do_client_cert_cb(SSL *s, X509 **px509, EVP_PKEY **ppkey) +{ + int i = 0; +#ifndef OPENSSL_NO_ENGINE + if (s->ctx->client_cert_engine) { + i = ENGINE_load_ssl_client_cert(s->ctx->client_cert_engine, s, + SSL_get_client_CA_list(s), + px509, ppkey, NULL, NULL, NULL); + if (i != 0) + return i; + } +#endif + if (s->ctx->client_cert_cb) + 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 i, j = 0; + const 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; + + 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, 0)) + continue; + j = s->method->put_cipher_by_char(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 = s->method->put_cipher_by_char(&scsv, p); + p += j; + } + 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 = s->method->put_cipher_by_char(&scsv, p); + p += j; + } + } + + return (p - q); +} diff --git a/openssl-1.1.0h/ssl/statem/statem_dtls.c b/openssl-1.1.0h/ssl/statem/statem_dtls.c new file mode 100644 index 0000000..6b80620 --- /dev/null +++ b/openssl-1.1.0h/ssl/statem/statem_dtls.c @@ -0,0 +1,1220 @@ +/* + * Copyright 2005-2018 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (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 + */ + +#include <limits.h> +#include <string.h> +#include <stdio.h> +#include "../ssl_locl.h" +#include "statem_locl.h" +#include <openssl/buffer.h> +#include <openssl/objects.h> +#include <openssl/evp.h> +#include <openssl/x509.h> + +#define RSMBLY_BITMASK_SIZE(msg_len) (((msg_len) + 7) / 8) + +#define RSMBLY_BITMASK_MARK(bitmask, start, end) { \ + if ((end) - (start) <= 8) { \ + long ii; \ + for (ii = (start); ii < (end); ii++) bitmask[((ii) >> 3)] |= (1 << ((ii) & 7)); \ + } else { \ + long ii; \ + bitmask[((start) >> 3)] |= bitmask_start_values[((start) & 7)]; \ + for (ii = (((start) >> 3) + 1); ii < ((((end) - 1)) >> 3); ii++) bitmask[ii] = 0xff; \ + bitmask[(((end) - 1) >> 3)] |= bitmask_end_values[((end) & 7)]; \ + } } + +#define RSMBLY_BITMASK_IS_COMPLETE(bitmask, msg_len, is_complete) { \ + long ii; \ + OPENSSL_assert((msg_len) > 0); \ + is_complete = 1; \ + if (bitmask[(((msg_len) - 1) >> 3)] != bitmask_end_values[((msg_len) & 7)]) is_complete = 0; \ + if (is_complete) for (ii = (((msg_len) - 1) >> 3) - 1; ii >= 0 ; ii--) \ + if (bitmask[ii] != 0xff) { is_complete = 0; break; } } + +static unsigned char bitmask_start_values[] = + { 0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80 }; +static unsigned char bitmask_end_values[] = + { 0xff, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f }; + +static void dtls1_fix_message_header(SSL *s, unsigned long frag_off, + unsigned long frag_len); +static unsigned char *dtls1_write_message_header(SSL *s, unsigned char *p); +static void dtls1_set_message_header_int(SSL *s, unsigned char mt, + unsigned long len, + unsigned short seq_num, + unsigned long frag_off, + unsigned long frag_len); +static int dtls_get_reassembled_message(SSL *s, long *len); + +static hm_fragment *dtls1_hm_fragment_new(unsigned long frag_len, + int reassembly) +{ + hm_fragment *frag = NULL; + unsigned char *buf = NULL; + unsigned char *bitmask = NULL; + + frag = OPENSSL_malloc(sizeof(*frag)); + if (frag == NULL) + return NULL; + + if (frag_len) { + buf = OPENSSL_malloc(frag_len); + if (buf == NULL) { + OPENSSL_free(frag); + return NULL; + } + } + + /* zero length fragment gets zero frag->fragment */ + frag->fragment = buf; + + /* Initialize reassembly bitmask if necessary */ + if (reassembly) { + bitmask = OPENSSL_zalloc(RSMBLY_BITMASK_SIZE(frag_len)); + if (bitmask == NULL) { + OPENSSL_free(buf); + OPENSSL_free(frag); + return NULL; + } + } + + frag->reassembly = bitmask; + + return frag; +} + +void dtls1_hm_fragment_free(hm_fragment *frag) +{ + if (!frag) + return; + if (frag->msg_header.is_ccs) { + EVP_CIPHER_CTX_free(frag->msg_header. + saved_retransmit_state.enc_write_ctx); + EVP_MD_CTX_free(frag->msg_header.saved_retransmit_state.write_hash); + } + OPENSSL_free(frag->fragment); + OPENSSL_free(frag->reassembly); + OPENSSL_free(frag); +} + +/* + * send s->init_buf in records of type 'type' (SSL3_RT_HANDSHAKE or + * SSL3_RT_CHANGE_CIPHER_SPEC) + */ +int dtls1_do_write(SSL *s, int type) +{ + int ret; + unsigned int curr_mtu; + int retry = 1; + unsigned int len, frag_off, mac_size, blocksize, used_len; + + if (!dtls1_query_mtu(s)) + return -1; + + if (s->d1->mtu < dtls1_min_mtu(s)) + /* should have something reasonable now */ + return -1; + + if (s->init_off == 0 && type == SSL3_RT_HANDSHAKE) + OPENSSL_assert(s->init_num == + (int)s->d1->w_msg_hdr.msg_len + DTLS1_HM_HEADER_LENGTH); + + if (s->write_hash) { + if (s->enc_write_ctx + && (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(s->enc_write_ctx)) & + EVP_CIPH_FLAG_AEAD_CIPHER) != 0) + mac_size = 0; + else + mac_size = EVP_MD_CTX_size(s->write_hash); + } else + mac_size = 0; + + if (s->enc_write_ctx && + (EVP_CIPHER_CTX_mode(s->enc_write_ctx) == EVP_CIPH_CBC_MODE)) + blocksize = 2 * EVP_CIPHER_CTX_block_size(s->enc_write_ctx); + else + blocksize = 0; + + frag_off = 0; + s->rwstate = SSL_NOTHING; + + /* s->init_num shouldn't ever be < 0...but just in case */ + while (s->init_num > 0) { + if (type == SSL3_RT_HANDSHAKE && s->init_off != 0) { + /* We must be writing a fragment other than the first one */ + + if (frag_off > 0) { + /* This is the first attempt at writing out this fragment */ + + if (s->init_off <= DTLS1_HM_HEADER_LENGTH) { + /* + * Each fragment that was already sent must at least have + * contained the message header plus one other byte. + * Therefore |init_off| must have progressed by at least + * |DTLS1_HM_HEADER_LENGTH + 1| bytes. If not something went + * wrong. + */ + return -1; + } + + /* + * Adjust |init_off| and |init_num| to allow room for a new + * message header for this fragment. + */ + s->init_off -= DTLS1_HM_HEADER_LENGTH; + s->init_num += DTLS1_HM_HEADER_LENGTH; + } else { + /* + * We must have been called again after a retry so use the + * fragment offset from our last attempt. We do not need + * to adjust |init_off| and |init_num| as above, because + * that should already have been done before the retry. + */ + frag_off = s->d1->w_msg_hdr.frag_off; + } + } + + used_len = BIO_wpending(s->wbio) + DTLS1_RT_HEADER_LENGTH + + mac_size + blocksize; + if (s->d1->mtu > used_len) + curr_mtu = s->d1->mtu - used_len; + else + curr_mtu = 0; + + if (curr_mtu <= DTLS1_HM_HEADER_LENGTH) { + /* + * grr.. we could get an error if MTU picked was wrong + */ + ret = BIO_flush(s->wbio); + if (ret <= 0) { + s->rwstate = SSL_WRITING; + return ret; + } + used_len = DTLS1_RT_HEADER_LENGTH + mac_size + blocksize; + if (s->d1->mtu > used_len + DTLS1_HM_HEADER_LENGTH) { + curr_mtu = s->d1->mtu - used_len; + } else { + /* Shouldn't happen */ + return -1; + } + } + + /* + * We just checked that s->init_num > 0 so this cast should be safe + */ + if (((unsigned int)s->init_num) > curr_mtu) + len = curr_mtu; + else + len = s->init_num; + + if (len > s->max_send_fragment) + len = s->max_send_fragment; + + /* + * XDTLS: this function is too long. split out the CCS part + */ + if (type == SSL3_RT_HANDSHAKE) { + if (len < DTLS1_HM_HEADER_LENGTH) { + /* + * len is so small that we really can't do anything sensible + * so fail + */ + return -1; + } + dtls1_fix_message_header(s, frag_off, len - DTLS1_HM_HEADER_LENGTH); + + dtls1_write_message_header(s, + (unsigned char *)&s->init_buf-> + data[s->init_off]); + } + + ret = dtls1_write_bytes(s, type, &s->init_buf->data[s->init_off], len); + if (ret < 0) { + /* + * might need to update MTU here, but we don't know which + * previous packet caused the failure -- so can't really + * retransmit anything. continue as if everything is fine and + * wait for an alert to handle the retransmit + */ + if (retry && BIO_ctrl(SSL_get_wbio(s), + BIO_CTRL_DGRAM_MTU_EXCEEDED, 0, NULL) > 0) { + if (!(SSL_get_options(s) & SSL_OP_NO_QUERY_MTU)) { + if (!dtls1_query_mtu(s)) + return -1; + /* Have one more go */ + retry = 0; + } else + return -1; + } else { + return (-1); + } + } else { + + /* + * bad if this assert fails, only part of the handshake message + * got sent. but why would this happen? + */ + OPENSSL_assert(len == (unsigned int)ret); + + if (type == SSL3_RT_HANDSHAKE && !s->d1->retransmitting) { + /* + * should not be done for 'Hello Request's, but in that case + * we'll ignore the result anyway + */ + unsigned char *p = + (unsigned char *)&s->init_buf->data[s->init_off]; + const struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr; + int xlen; + + if (frag_off == 0 && s->version != DTLS1_BAD_VER) { + /* + * reconstruct message header is if it is being sent in + * single fragment + */ + *p++ = msg_hdr->type; + l2n3(msg_hdr->msg_len, p); + s2n(msg_hdr->seq, p); + l2n3(0, p); + l2n3(msg_hdr->msg_len, p); + p -= DTLS1_HM_HEADER_LENGTH; + xlen = ret; + } else { + p += DTLS1_HM_HEADER_LENGTH; + xlen = ret - DTLS1_HM_HEADER_LENGTH; + } + + if (!ssl3_finish_mac(s, p, xlen)) + return -1; + } + + if (ret == s->init_num) { + if (s->msg_callback) + s->msg_callback(1, s->version, type, s->init_buf->data, + (size_t)(s->init_off + s->init_num), s, + s->msg_callback_arg); + + s->init_off = 0; /* done writing this message */ + s->init_num = 0; + + return (1); + } + s->init_off += ret; + s->init_num -= ret; + ret -= DTLS1_HM_HEADER_LENGTH; + frag_off += ret; + + /* + * We save the fragment offset for the next fragment so we have it + * available in case of an IO retry. We don't know the length of the + * next fragment yet so just set that to 0 for now. It will be + * updated again later. + */ + dtls1_fix_message_header(s, frag_off, 0); + } + } + return (0); +} + +int dtls_get_message(SSL *s, int *mt, unsigned long *len) +{ + struct hm_header_st *msg_hdr; + unsigned char *p; + unsigned long msg_len; + int ok; + long tmplen; + + msg_hdr = &s->d1->r_msg_hdr; + memset(msg_hdr, 0, sizeof(*msg_hdr)); + + again: + ok = dtls_get_reassembled_message(s, &tmplen); + if (tmplen == DTLS1_HM_BAD_FRAGMENT || tmplen == DTLS1_HM_FRAGMENT_RETRY) { + /* bad fragment received */ + goto again; + } else if (tmplen <= 0 && !ok) { + return 0; + } + + *mt = s->s3->tmp.message_type; + + p = (unsigned char *)s->init_buf->data; + + if (*mt == SSL3_MT_CHANGE_CIPHER_SPEC) { + if (s->msg_callback) { + s->msg_callback(0, s->version, SSL3_RT_CHANGE_CIPHER_SPEC, + p, 1, s, s->msg_callback_arg); + } + /* + * This isn't a real handshake message so skip the processing below. + */ + *len = (unsigned long)tmplen; + return 1; + } + + msg_len = msg_hdr->msg_len; + + /* reconstruct message header */ + *(p++) = msg_hdr->type; + l2n3(msg_len, p); + s2n(msg_hdr->seq, p); + l2n3(0, p); + l2n3(msg_len, p); + if (s->version != DTLS1_BAD_VER) { + p -= DTLS1_HM_HEADER_LENGTH; + msg_len += DTLS1_HM_HEADER_LENGTH; + } + + /* + * If receiving Finished, record MAC of prior handshake messages for + * Finished verification. + */ + if (*mt == SSL3_MT_FINISHED && !ssl3_take_mac(s)) { + /* SSLfatal() already called */ + return 0; + } + + if (!ssl3_finish_mac(s, p, msg_len)) + return 0; + if (s->msg_callback) + s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, + p, msg_len, s, s->msg_callback_arg); + + memset(msg_hdr, 0, sizeof(*msg_hdr)); + + s->d1->handshake_read_seq++; + + s->init_msg = s->init_buf->data + DTLS1_HM_HEADER_LENGTH; + *len = s->init_num; + + return 1; +} + +/* + * dtls1_max_handshake_message_len returns the maximum number of bytes + * permitted in a DTLS handshake message for |s|. The minimum is 16KB, but + * may be greater if the maximum certificate list size requires it. + */ +static unsigned long dtls1_max_handshake_message_len(const SSL *s) +{ + unsigned long max_len = + DTLS1_HM_HEADER_LENGTH + SSL3_RT_MAX_ENCRYPTED_LENGTH; + if (max_len < (unsigned long)s->max_cert_list) + return s->max_cert_list; + return max_len; +} + +static int dtls1_preprocess_fragment(SSL *s, struct hm_header_st *msg_hdr) +{ + size_t frag_off, frag_len, msg_len; + + msg_len = msg_hdr->msg_len; + frag_off = msg_hdr->frag_off; + frag_len = msg_hdr->frag_len; + + /* sanity checking */ + if ((frag_off + frag_len) > msg_len + || msg_len > dtls1_max_handshake_message_len(s)) { + SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT, SSL_R_EXCESSIVE_MESSAGE_SIZE); + return SSL_AD_ILLEGAL_PARAMETER; + } + + if (s->d1->r_msg_hdr.frag_off == 0) { /* first fragment */ + /* + * msg_len is limited to 2^24, but is effectively checked against + * dtls_max_handshake_message_len(s) above + */ + if (!BUF_MEM_grow_clean(s->init_buf, msg_len + DTLS1_HM_HEADER_LENGTH)) { + SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT, ERR_R_BUF_LIB); + return SSL_AD_INTERNAL_ERROR; + } + + s->s3->tmp.message_size = msg_len; + s->d1->r_msg_hdr.msg_len = msg_len; + s->s3->tmp.message_type = msg_hdr->type; + s->d1->r_msg_hdr.type = msg_hdr->type; + s->d1->r_msg_hdr.seq = msg_hdr->seq; + } else if (msg_len != s->d1->r_msg_hdr.msg_len) { + /* + * They must be playing with us! BTW, failure to enforce upper limit + * would open possibility for buffer overrun. + */ + SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT, SSL_R_EXCESSIVE_MESSAGE_SIZE); + return SSL_AD_ILLEGAL_PARAMETER; + } + + return 0; /* no error */ +} + +static int dtls1_retrieve_buffered_fragment(SSL *s, int *ok) +{ + /*- + * (0) check whether the desired fragment is available + * if so: + * (1) copy over the fragment to s->init_buf->data[] + * (2) update s->init_num + */ + pitem *item; + hm_fragment *frag; + int al; + + *ok = 0; + + do { + item = pqueue_peek(s->d1->buffered_messages); + if (item == NULL) + return 0; + + frag = (hm_fragment *)item->data; + + if (frag->msg_header.seq < s->d1->handshake_read_seq) { + /* This is a stale message that has been buffered so clear it */ + pqueue_pop(s->d1->buffered_messages); + dtls1_hm_fragment_free(frag); + pitem_free(item); + item = NULL; + frag = NULL; + } + } while (item == NULL); + + /* Don't return if reassembly still in progress */ + if (frag->reassembly != NULL) + return 0; + + if (s->d1->handshake_read_seq == frag->msg_header.seq) { + unsigned long frag_len = frag->msg_header.frag_len; + pqueue_pop(s->d1->buffered_messages); + + al = dtls1_preprocess_fragment(s, &frag->msg_header); + + if (al == 0) { /* no alert */ + unsigned char *p = + (unsigned char *)s->init_buf->data + DTLS1_HM_HEADER_LENGTH; + memcpy(&p[frag->msg_header.frag_off], frag->fragment, + frag->msg_header.frag_len); + } + + dtls1_hm_fragment_free(frag); + pitem_free(item); + + if (al == 0) { + *ok = 1; + return frag_len; + } + + ssl3_send_alert(s, SSL3_AL_FATAL, al); + s->init_num = 0; + *ok = 0; + return -1; + } else + return 0; +} + +static int +dtls1_reassemble_fragment(SSL *s, const struct hm_header_st *msg_hdr, int *ok) +{ + hm_fragment *frag = NULL; + pitem *item = NULL; + int i = -1, is_complete; + unsigned char seq64be[8]; + unsigned long frag_len = msg_hdr->frag_len; + + if ((msg_hdr->frag_off + frag_len) > msg_hdr->msg_len || + msg_hdr->msg_len > dtls1_max_handshake_message_len(s)) + goto err; + + if (frag_len == 0) + return DTLS1_HM_FRAGMENT_RETRY; + + /* Try to find item in queue */ + memset(seq64be, 0, sizeof(seq64be)); + seq64be[6] = (unsigned char)(msg_hdr->seq >> 8); + seq64be[7] = (unsigned char)msg_hdr->seq; + item = pqueue_find(s->d1->buffered_messages, seq64be); + + if (item == NULL) { + frag = dtls1_hm_fragment_new(msg_hdr->msg_len, 1); + if (frag == NULL) + goto err; + memcpy(&(frag->msg_header), msg_hdr, sizeof(*msg_hdr)); + frag->msg_header.frag_len = frag->msg_header.msg_len; + frag->msg_header.frag_off = 0; + } else { + frag = (hm_fragment *)item->data; + if (frag->msg_header.msg_len != msg_hdr->msg_len) { + item = NULL; + frag = NULL; + goto err; + } + } + + /* + * If message is already reassembled, this must be a retransmit and can + * be dropped. In this case item != NULL and so frag does not need to be + * freed. + */ + if (frag->reassembly == NULL) { + unsigned char devnull[256]; + + while (frag_len) { + i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, NULL, + devnull, + frag_len > + sizeof(devnull) ? sizeof(devnull) : + frag_len, 0); + if (i <= 0) + goto err; + frag_len -= i; + } + return DTLS1_HM_FRAGMENT_RETRY; + } + + /* read the body of the fragment (header has already been read */ + i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, NULL, + frag->fragment + msg_hdr->frag_off, + frag_len, 0); + if ((unsigned long)i != frag_len) + i = -1; + if (i <= 0) + goto err; + + RSMBLY_BITMASK_MARK(frag->reassembly, (long)msg_hdr->frag_off, + (long)(msg_hdr->frag_off + frag_len)); + + RSMBLY_BITMASK_IS_COMPLETE(frag->reassembly, (long)msg_hdr->msg_len, + is_complete); + + if (is_complete) { + OPENSSL_free(frag->reassembly); + frag->reassembly = NULL; + } + + if (item == NULL) { + item = pitem_new(seq64be, frag); + if (item == NULL) { + i = -1; + goto err; + } + + item = pqueue_insert(s->d1->buffered_messages, item); + /* + * pqueue_insert fails iff a duplicate item is inserted. However, + * |item| cannot be a duplicate. If it were, |pqueue_find|, above, + * would have returned it and control would never have reached this + * branch. + */ + OPENSSL_assert(item != NULL); + } + + return DTLS1_HM_FRAGMENT_RETRY; + + err: + if (item == NULL) + dtls1_hm_fragment_free(frag); + *ok = 0; + return i; +} + +static int +dtls1_process_out_of_seq_message(SSL *s, const struct hm_header_st *msg_hdr, + int *ok) +{ + int i = -1; + hm_fragment *frag = NULL; + pitem *item = NULL; + unsigned char seq64be[8]; + unsigned long frag_len = msg_hdr->frag_len; + + if ((msg_hdr->frag_off + frag_len) > msg_hdr->msg_len) + goto err; + + /* Try to find item in queue, to prevent duplicate entries */ + memset(seq64be, 0, sizeof(seq64be)); + seq64be[6] = (unsigned char)(msg_hdr->seq >> 8); + seq64be[7] = (unsigned char)msg_hdr->seq; + item = pqueue_find(s->d1->buffered_messages, seq64be); + + /* + * If we already have an entry and this one is a fragment, don't discard + * it and rather try to reassemble it. + */ + if (item != NULL && frag_len != msg_hdr->msg_len) + item = NULL; + + /* + * Discard the message if sequence number was already there, is too far + * in the future, already in the queue or if we received a FINISHED + * before the SERVER_HELLO, which then must be a stale retransmit. + */ + if (msg_hdr->seq <= s->d1->handshake_read_seq || + msg_hdr->seq > s->d1->handshake_read_seq + 10 || item != NULL || + (s->d1->handshake_read_seq == 0 && msg_hdr->type == SSL3_MT_FINISHED)) { + unsigned char devnull[256]; + + while (frag_len) { + i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, NULL, + devnull, + frag_len > + sizeof(devnull) ? sizeof(devnull) : + frag_len, 0); + if (i <= 0) + goto err; + frag_len -= i; + } + } else { + if (frag_len != msg_hdr->msg_len) + return dtls1_reassemble_fragment(s, msg_hdr, ok); + + if (frag_len > dtls1_max_handshake_message_len(s)) + goto err; + + frag = dtls1_hm_fragment_new(frag_len, 0); + if (frag == NULL) + goto err; + + memcpy(&(frag->msg_header), msg_hdr, sizeof(*msg_hdr)); + + if (frag_len) { + /* + * read the body of the fragment (header has already been read + */ + i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, NULL, + frag->fragment, frag_len, 0); + if ((unsigned long)i != frag_len) + i = -1; + if (i <= 0) + goto err; + } + + item = pitem_new(seq64be, frag); + if (item == NULL) + goto err; + + item = pqueue_insert(s->d1->buffered_messages, item); + /* + * pqueue_insert fails iff a duplicate item is inserted. However, + * |item| cannot be a duplicate. If it were, |pqueue_find|, above, + * would have returned it. Then, either |frag_len| != + * |msg_hdr->msg_len| in which case |item| is set to NULL and it will + * have been processed with |dtls1_reassemble_fragment|, above, or + * the record will have been discarded. + */ + OPENSSL_assert(item != NULL); + } + + return DTLS1_HM_FRAGMENT_RETRY; + + err: + if (item == NULL) + dtls1_hm_fragment_free(frag); + *ok = 0; + return i; +} + +static int dtls_get_reassembled_message(SSL *s, long *len) +{ + unsigned char wire[DTLS1_HM_HEADER_LENGTH]; + unsigned long mlen, frag_off, frag_len; + int i, al, recvd_type; + struct hm_header_st msg_hdr; + int ok; + + redo: + /* see if we have the required fragment already */ + if ((frag_len = dtls1_retrieve_buffered_fragment(s, &ok)) || ok) { + if (ok) + s->init_num = frag_len; + *len = frag_len; + return ok; + } + + /* read handshake message header */ + i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, &recvd_type, wire, + DTLS1_HM_HEADER_LENGTH, 0); + if (i <= 0) { /* nbio, or an error */ + s->rwstate = SSL_READING; + *len = i; + return 0; + } + if (recvd_type == SSL3_RT_CHANGE_CIPHER_SPEC) { + if (wire[0] != SSL3_MT_CCS) { + al = SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_DTLS_GET_REASSEMBLED_MESSAGE, + SSL_R_BAD_CHANGE_CIPHER_SPEC); + goto f_err; + } + + memcpy(s->init_buf->data, wire, i); + s->init_num = i - 1; + s->init_msg = s->init_buf->data + 1; + s->s3->tmp.message_type = SSL3_MT_CHANGE_CIPHER_SPEC; + s->s3->tmp.message_size = i - 1; + *len = i - 1; + return 1; + } + + /* Handshake fails if message header is incomplete */ + if (i != DTLS1_HM_HEADER_LENGTH) { + al = SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_DTLS_GET_REASSEMBLED_MESSAGE, SSL_R_UNEXPECTED_MESSAGE); + goto f_err; + } + + /* parse the message fragment header */ + dtls1_get_message_header(wire, &msg_hdr); + + mlen = msg_hdr.msg_len; + frag_off = msg_hdr.frag_off; + frag_len = msg_hdr.frag_len; + + /* + * We must have at least frag_len bytes left in the record to be read. + * Fragments must not span records. + */ + if (frag_len > RECORD_LAYER_get_rrec_length(&s->rlayer)) { + al = SSL3_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_DTLS_GET_REASSEMBLED_MESSAGE, SSL_R_BAD_LENGTH); + goto f_err; + } + + /* + * if this is a future (or stale) message it gets buffered + * (or dropped)--no further processing at this time + * While listening, we accept seq 1 (ClientHello with cookie) + * although we're still expecting seq 0 (ClientHello) + */ + if (msg_hdr.seq != s->d1->handshake_read_seq) { + *len = dtls1_process_out_of_seq_message(s, &msg_hdr, &ok); + return ok; + } + + if (frag_len && frag_len < mlen) { + *len = dtls1_reassemble_fragment(s, &msg_hdr, &ok); + return ok; + } + + if (!s->server && s->d1->r_msg_hdr.frag_off == 0 && + wire[0] == SSL3_MT_HELLO_REQUEST) { + /* + * The server may always send 'Hello Request' messages -- we are + * doing a handshake anyway now, so ignore them if their format is + * correct. Does not count for 'Finished' MAC. + */ + if (wire[1] == 0 && wire[2] == 0 && wire[3] == 0) { + if (s->msg_callback) + s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, + wire, DTLS1_HM_HEADER_LENGTH, s, + s->msg_callback_arg); + + s->init_num = 0; + goto redo; + } else { /* Incorrectly formatted Hello request */ + + al = SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_DTLS_GET_REASSEMBLED_MESSAGE, + SSL_R_UNEXPECTED_MESSAGE); + goto f_err; + } + } + + if ((al = dtls1_preprocess_fragment(s, &msg_hdr))) + goto f_err; + + if (frag_len > 0) { + unsigned char *p = + (unsigned char *)s->init_buf->data + DTLS1_HM_HEADER_LENGTH; + + i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, NULL, + &p[frag_off], frag_len, 0); + + /* + * This shouldn't ever fail due to NBIO because we already checked + * that we have enough data in the record + */ + if (i <= 0) { + s->rwstate = SSL_READING; + *len = i; + return 0; + } + } else + i = 0; + + /* + * XDTLS: an incorrectly formatted fragment should cause the handshake + * to fail + */ + if (i != (int)frag_len) { + al = SSL3_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_DTLS_GET_REASSEMBLED_MESSAGE, SSL3_AD_ILLEGAL_PARAMETER); + goto f_err; + } + + /* + * Note that s->init_num is *not* used as current offset in + * s->init_buf->data, but as a counter summing up fragments' lengths: as + * soon as they sum up to handshake packet length, we assume we have got + * all the fragments. + */ + *len = s->init_num = frag_len; + return 1; + + f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + s->init_num = 0; + *len = -1; + return 0; +} + +/*- + * for these 2 messages, we need to + * ssl->enc_read_ctx re-init + * ssl->rlayer.read_sequence zero + * ssl->s3->read_mac_secret re-init + * ssl->session->read_sym_enc assign + * ssl->session->read_compression assign + * ssl->session->read_hash assign + */ +int dtls_construct_change_cipher_spec(SSL *s) +{ + unsigned char *p; + + p = (unsigned char *)s->init_buf->data; + *p++ = SSL3_MT_CCS; + s->d1->handshake_write_seq = s->d1->next_handshake_write_seq; + s->init_num = DTLS1_CCS_HEADER_LENGTH; + + if (s->version == DTLS1_BAD_VER) { + s->d1->next_handshake_write_seq++; + s2n(s->d1->handshake_write_seq, p); + s->init_num += 2; + } + + s->init_off = 0; + + dtls1_set_message_header_int(s, SSL3_MT_CCS, 0, + s->d1->handshake_write_seq, 0, 0); + + /* buffer the message to handle re-xmits */ + if (!dtls1_buffer_message(s, 1)) { + SSLerr(SSL_F_DTLS_CONSTRUCT_CHANGE_CIPHER_SPEC, ERR_R_INTERNAL_ERROR); + return 0; + } + + return 1; +} + +#ifndef OPENSSL_NO_SCTP +/* + * Wait for a dry event. Should only be called at a point in the handshake + * where we are not expecting any data from the peer (except possibly an alert). + */ +WORK_STATE dtls_wait_for_dry(SSL *s) +{ + int ret; + long len; + + /* read app data until dry event */ + ret = BIO_dgram_sctp_wait_for_dry(SSL_get_wbio(s)); + if (ret < 0) + return WORK_ERROR; + + if (ret == 0) { + /* + * We're not expecting any more messages from the peer at this point - + * but we could get an alert. If an alert is waiting then we will never + * return successfully. Therefore we attempt to read a message. This + * should never succeed but will process any waiting alerts. + */ + if (dtls_get_reassembled_message(s, &len)) { + /* The call succeeded! This should never happen */ + SSLerr(SSL_F_DTLS_WAIT_FOR_DRY, SSL_R_UNEXPECTED_MESSAGE); + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); + ossl_statem_set_error(s); + return WORK_ERROR; + } + + s->s3->in_read_app_data = 2; + s->rwstate = SSL_READING; + BIO_clear_retry_flags(SSL_get_rbio(s)); + BIO_set_retry_read(SSL_get_rbio(s)); + return WORK_MORE_A; + } + return WORK_FINISHED_CONTINUE; +} +#endif + +int dtls1_read_failed(SSL *s, int code) +{ + if (code > 0) { + SSLerr(SSL_F_DTLS1_READ_FAILED, ERR_R_INTERNAL_ERROR); + return 1; + } + + if (!dtls1_is_timer_expired(s)) { + /* + * not a timeout, none of our business, let higher layers handle + * this. in fact it's probably an error + */ + return code; + } +#ifndef OPENSSL_NO_HEARTBEATS + /* done, no need to send a retransmit */ + if (!SSL_in_init(s) && !s->tlsext_hb_pending) +#else + /* done, no need to send a retransmit */ + if (!SSL_in_init(s)) +#endif + { + BIO_set_flags(SSL_get_rbio(s), BIO_FLAGS_READ); + return code; + } + + return dtls1_handle_timeout(s); +} + +int dtls1_get_queue_priority(unsigned short seq, int is_ccs) +{ + /* + * The index of the retransmission queue actually is the message sequence + * number, since the queue only contains messages of a single handshake. + * However, the ChangeCipherSpec has no message sequence number and so + * using only the sequence will result in the CCS and Finished having the + * same index. To prevent this, the sequence number is multiplied by 2. + * In case of a CCS 1 is subtracted. This does not only differ CSS and + * Finished, it also maintains the order of the index (important for + * priority queues) and fits in the unsigned short variable. + */ + return seq * 2 - is_ccs; +} + +int dtls1_retransmit_buffered_messages(SSL *s) +{ + pqueue *sent = s->d1->sent_messages; + piterator iter; + pitem *item; + hm_fragment *frag; + int found = 0; + + iter = pqueue_iterator(sent); + + for (item = pqueue_next(&iter); item != NULL; item = pqueue_next(&iter)) { + frag = (hm_fragment *)item->data; + if (dtls1_retransmit_message(s, (unsigned short) + dtls1_get_queue_priority + (frag->msg_header.seq, + frag->msg_header.is_ccs), &found) <= 0) + return -1; + } + + return 1; +} + +int dtls1_buffer_message(SSL *s, int is_ccs) +{ + pitem *item; + hm_fragment *frag; + unsigned char seq64be[8]; + + /* + * this function is called immediately after a message has been + * serialized + */ + OPENSSL_assert(s->init_off == 0); + + frag = dtls1_hm_fragment_new(s->init_num, 0); + if (frag == NULL) + return 0; + + memcpy(frag->fragment, s->init_buf->data, s->init_num); + + if (is_ccs) { + /* For DTLS1_BAD_VER the header length is non-standard */ + OPENSSL_assert(s->d1->w_msg_hdr.msg_len + + ((s->version == + DTLS1_BAD_VER) ? 3 : DTLS1_CCS_HEADER_LENGTH) + == (unsigned int)s->init_num); + } else { + OPENSSL_assert(s->d1->w_msg_hdr.msg_len + + DTLS1_HM_HEADER_LENGTH == (unsigned int)s->init_num); + } + + frag->msg_header.msg_len = s->d1->w_msg_hdr.msg_len; + frag->msg_header.seq = s->d1->w_msg_hdr.seq; + frag->msg_header.type = s->d1->w_msg_hdr.type; + frag->msg_header.frag_off = 0; + frag->msg_header.frag_len = s->d1->w_msg_hdr.msg_len; + frag->msg_header.is_ccs = is_ccs; + + /* save current state */ + frag->msg_header.saved_retransmit_state.enc_write_ctx = s->enc_write_ctx; + frag->msg_header.saved_retransmit_state.write_hash = s->write_hash; + frag->msg_header.saved_retransmit_state.compress = s->compress; + frag->msg_header.saved_retransmit_state.session = s->session; + frag->msg_header.saved_retransmit_state.epoch = + DTLS_RECORD_LAYER_get_w_epoch(&s->rlayer); + + memset(seq64be, 0, sizeof(seq64be)); + seq64be[6] = + (unsigned + char)(dtls1_get_queue_priority(frag->msg_header.seq, + frag->msg_header.is_ccs) >> 8); + seq64be[7] = + (unsigned + char)(dtls1_get_queue_priority(frag->msg_header.seq, + frag->msg_header.is_ccs)); + + item = pitem_new(seq64be, frag); + if (item == NULL) { + dtls1_hm_fragment_free(frag); + return 0; + } + + pqueue_insert(s->d1->sent_messages, item); + return 1; +} + +int dtls1_retransmit_message(SSL *s, unsigned short seq, int *found) +{ + int ret; + /* XDTLS: for now assuming that read/writes are blocking */ + pitem *item; + hm_fragment *frag; + unsigned long header_length; + unsigned char seq64be[8]; + struct dtls1_retransmit_state saved_state; + + /*- + OPENSSL_assert(s->init_num == 0); + OPENSSL_assert(s->init_off == 0); + */ + + /* XDTLS: the requested message ought to be found, otherwise error */ + memset(seq64be, 0, sizeof(seq64be)); + seq64be[6] = (unsigned char)(seq >> 8); + seq64be[7] = (unsigned char)seq; + + item = pqueue_find(s->d1->sent_messages, seq64be); + if (item == NULL) { + SSLerr(SSL_F_DTLS1_RETRANSMIT_MESSAGE, ERR_R_INTERNAL_ERROR); + *found = 0; + return 0; + } + + *found = 1; + frag = (hm_fragment *)item->data; + + if (frag->msg_header.is_ccs) + header_length = DTLS1_CCS_HEADER_LENGTH; + else + header_length = DTLS1_HM_HEADER_LENGTH; + + memcpy(s->init_buf->data, frag->fragment, + frag->msg_header.msg_len + header_length); + s->init_num = frag->msg_header.msg_len + header_length; + + dtls1_set_message_header_int(s, frag->msg_header.type, + frag->msg_header.msg_len, + frag->msg_header.seq, 0, + frag->msg_header.frag_len); + + /* save current state */ + saved_state.enc_write_ctx = s->enc_write_ctx; + saved_state.write_hash = s->write_hash; + saved_state.compress = s->compress; + saved_state.session = s->session; + saved_state.epoch = DTLS_RECORD_LAYER_get_w_epoch(&s->rlayer); + + s->d1->retransmitting = 1; + + /* restore state in which the message was originally sent */ + s->enc_write_ctx = frag->msg_header.saved_retransmit_state.enc_write_ctx; + s->write_hash = frag->msg_header.saved_retransmit_state.write_hash; + s->compress = frag->msg_header.saved_retransmit_state.compress; + s->session = frag->msg_header.saved_retransmit_state.session; + DTLS_RECORD_LAYER_set_saved_w_epoch(&s->rlayer, + frag->msg_header. + saved_retransmit_state.epoch); + + ret = dtls1_do_write(s, frag->msg_header.is_ccs ? + SSL3_RT_CHANGE_CIPHER_SPEC : SSL3_RT_HANDSHAKE); + + /* restore current state */ + s->enc_write_ctx = saved_state.enc_write_ctx; + s->write_hash = saved_state.write_hash; + s->compress = saved_state.compress; + s->session = saved_state.session; + DTLS_RECORD_LAYER_set_saved_w_epoch(&s->rlayer, saved_state.epoch); + + s->d1->retransmitting = 0; + + (void)BIO_flush(s->wbio); + return ret; +} + +void dtls1_set_message_header(SSL *s, + unsigned char mt, unsigned long len, + unsigned long frag_off, unsigned long frag_len) +{ + if (frag_off == 0) { + s->d1->handshake_write_seq = s->d1->next_handshake_write_seq; + s->d1->next_handshake_write_seq++; + } + + dtls1_set_message_header_int(s, mt, len, s->d1->handshake_write_seq, + frag_off, frag_len); +} + +/* don't actually do the writing, wait till the MTU has been retrieved */ +static void +dtls1_set_message_header_int(SSL *s, unsigned char mt, + unsigned long len, unsigned short seq_num, + unsigned long frag_off, unsigned long frag_len) +{ + struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr; + + msg_hdr->type = mt; + msg_hdr->msg_len = len; + msg_hdr->seq = seq_num; + msg_hdr->frag_off = frag_off; + msg_hdr->frag_len = frag_len; +} + +static void +dtls1_fix_message_header(SSL *s, unsigned long frag_off, unsigned long frag_len) +{ + struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr; + + msg_hdr->frag_off = frag_off; + msg_hdr->frag_len = frag_len; +} + +static unsigned char *dtls1_write_message_header(SSL *s, unsigned char *p) +{ + struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr; + + *p++ = msg_hdr->type; + l2n3(msg_hdr->msg_len, p); + + s2n(msg_hdr->seq, p); + l2n3(msg_hdr->frag_off, p); + l2n3(msg_hdr->frag_len, p); + + return p; +} + +void dtls1_get_message_header(unsigned char *data, struct hm_header_st *msg_hdr) +{ + memset(msg_hdr, 0, sizeof(*msg_hdr)); + msg_hdr->type = *(data++); + n2l3(data, msg_hdr->msg_len); + + n2s(data, msg_hdr->seq); + n2l3(data, msg_hdr->frag_off); + n2l3(data, msg_hdr->frag_len); +} diff --git a/openssl-1.1.0h/ssl/statem/statem_lib.c b/openssl-1.1.0h/ssl/statem/statem_lib.c new file mode 100644 index 0000000..36d410b --- /dev/null +++ b/openssl-1.1.0h/ssl/statem/statem_lib.c @@ -0,0 +1,1083 @@ +/* + * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (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 + */ + +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * ECC cipher suite support in OpenSSL originally developed by + * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. + */ + +#include <limits.h> +#include <string.h> +#include <stdio.h> +#include "../ssl_locl.h" +#include "statem_locl.h" +#include <openssl/buffer.h> +#include <openssl/objects.h> +#include <openssl/evp.h> +#include <openssl/x509.h> + +/* + * send s->init_buf in records of type 'type' (SSL3_RT_HANDSHAKE or + * SSL3_RT_CHANGE_CIPHER_SPEC) + */ +int ssl3_do_write(SSL *s, int type) +{ + int ret; + + ret = ssl3_write_bytes(s, type, &s->init_buf->data[s->init_off], + s->init_num); + if (ret < 0) + return (-1); + if (type == SSL3_RT_HANDSHAKE) + /* + * should not be done for 'Hello Request's, but in that case we'll + * ignore the result anyway + */ + if (!ssl3_finish_mac(s, + (unsigned char *)&s->init_buf->data[s->init_off], + ret)) + return -1; + + if (ret == s->init_num) { + if (s->msg_callback) + s->msg_callback(1, s->version, type, s->init_buf->data, + (size_t)(s->init_off + s->init_num), s, + s->msg_callback_arg); + return (1); + } + s->init_off += ret; + s->init_num -= ret; + return (0); +} + +int tls_construct_finished(SSL *s, const char *sender, int slen) +{ + unsigned char *p; + int i; + unsigned long l; + + p = ssl_handshake_start(s); + + i = s->method->ssl3_enc->final_finish_mac(s, + sender, slen, + s->s3->tmp.finish_md); + if (i <= 0) + return 0; + s->s3->tmp.finish_md_len = i; + memcpy(p, s->s3->tmp.finish_md, i); + l = i; + + /* + * Copy the finished so we can use it for renegotiation checks + */ + if (!s->server) { + OPENSSL_assert(i <= EVP_MAX_MD_SIZE); + memcpy(s->s3->previous_client_finished, s->s3->tmp.finish_md, i); + s->s3->previous_client_finished_len = i; + } else { + OPENSSL_assert(i <= EVP_MAX_MD_SIZE); + memcpy(s->s3->previous_server_finished, s->s3->tmp.finish_md, i); + s->s3->previous_server_finished_len = i; + } + + if (!ssl_set_handshake_header(s, SSL3_MT_FINISHED, l)) { + SSLerr(SSL_F_TLS_CONSTRUCT_FINISHED, ERR_R_INTERNAL_ERROR); + return 0; + } + + return 1; +} + +/* + * ssl3_take_mac calculates the Finished MAC for the handshakes messages seen + * to far. + */ +int ssl3_take_mac(SSL *s) +{ + const char *sender; + int slen; + + if (!s->server) { + sender = s->method->ssl3_enc->server_finished_label; + slen = s->method->ssl3_enc->server_finished_label_len; + } else { + sender = s->method->ssl3_enc->client_finished_label; + slen = s->method->ssl3_enc->client_finished_label_len; + } + + s->s3->tmp.peer_finish_md_len = + s->method->ssl3_enc->final_finish_mac(s, sender, slen, + s->s3->tmp.peer_finish_md); + + if (s->s3->tmp.peer_finish_md_len == 0) { + SSLerr(SSL_F_SSL3_TAKE_MAC, ERR_R_INTERNAL_ERROR); + return 0; + } + + return 1; +} + +MSG_PROCESS_RETURN tls_process_change_cipher_spec(SSL *s, PACKET *pkt) +{ + int al; + long remain; + + remain = PACKET_remaining(pkt); + /* + * 'Change Cipher Spec' is just a single byte, which should already have + * been consumed by ssl_get_message() so there should be no bytes left, + * unless we're using DTLS1_BAD_VER, which has an extra 2 bytes + */ + if (SSL_IS_DTLS(s)) { + if ((s->version == DTLS1_BAD_VER + && remain != DTLS1_CCS_HEADER_LENGTH + 1) + || (s->version != DTLS1_BAD_VER + && remain != DTLS1_CCS_HEADER_LENGTH - 1)) { + al = SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_TLS_PROCESS_CHANGE_CIPHER_SPEC, + SSL_R_BAD_CHANGE_CIPHER_SPEC); + goto f_err; + } + } else { + if (remain != 0) { + al = SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_TLS_PROCESS_CHANGE_CIPHER_SPEC, + SSL_R_BAD_CHANGE_CIPHER_SPEC); + goto f_err; + } + } + + /* Check we have a cipher to change to */ + if (s->s3->tmp.new_cipher == NULL) { + al = SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_TLS_PROCESS_CHANGE_CIPHER_SPEC, SSL_R_CCS_RECEIVED_EARLY); + goto f_err; + } + + s->s3->change_cipher_spec = 1; + if (!ssl3_do_change_cipher_spec(s)) { + al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CHANGE_CIPHER_SPEC, ERR_R_INTERNAL_ERROR); + goto f_err; + } + + if (SSL_IS_DTLS(s)) { + dtls1_reset_seq_numbers(s, SSL3_CC_READ); + + if (s->version == DTLS1_BAD_VER) + s->d1->handshake_read_seq++; + +#ifndef OPENSSL_NO_SCTP + /* + * Remember that a CCS has been received, so that an old key of + * SCTP-Auth can be deleted when a CCS is sent. Will be ignored if no + * SCTP is used + */ + BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_AUTH_CCS_RCVD, 1, NULL); +#endif + } + + return MSG_PROCESS_CONTINUE_READING; + f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + ossl_statem_set_error(s); + return MSG_PROCESS_ERROR; +} + +MSG_PROCESS_RETURN tls_process_finished(SSL *s, PACKET *pkt) +{ + int al, i; + + /* If this occurs, we have missed a message */ + if (!s->s3->change_cipher_spec) { + al = SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_TLS_PROCESS_FINISHED, SSL_R_GOT_A_FIN_BEFORE_A_CCS); + goto f_err; + } + s->s3->change_cipher_spec = 0; + + i = s->s3->tmp.peer_finish_md_len; + + if ((unsigned long)i != PACKET_remaining(pkt)) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_FINISHED, SSL_R_BAD_DIGEST_LENGTH); + goto f_err; + } + + if (CRYPTO_memcmp(PACKET_data(pkt), s->s3->tmp.peer_finish_md, i) != 0) { + al = SSL_AD_DECRYPT_ERROR; + SSLerr(SSL_F_TLS_PROCESS_FINISHED, SSL_R_DIGEST_CHECK_FAILED); + goto f_err; + } + + /* + * Copy the finished so we can use it for renegotiation checks + */ + if (s->server) { + OPENSSL_assert(i <= EVP_MAX_MD_SIZE); + memcpy(s->s3->previous_client_finished, s->s3->tmp.peer_finish_md, i); + s->s3->previous_client_finished_len = i; + } else { + OPENSSL_assert(i <= EVP_MAX_MD_SIZE); + memcpy(s->s3->previous_server_finished, s->s3->tmp.peer_finish_md, i); + s->s3->previous_server_finished_len = i; + } + + return MSG_PROCESS_FINISHED_READING; + f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + ossl_statem_set_error(s); + return MSG_PROCESS_ERROR; +} + +int tls_construct_change_cipher_spec(SSL *s) +{ + unsigned char *p; + + p = (unsigned char *)s->init_buf->data; + *p = SSL3_MT_CCS; + s->init_num = 1; + s->init_off = 0; + + return 1; +} + +unsigned long ssl3_output_cert_chain(SSL *s, CERT_PKEY *cpk) +{ + unsigned char *p; + unsigned long l = 3 + SSL_HM_HEADER_LENGTH(s); + + if (!ssl_add_cert_chain(s, cpk, &l)) + return 0; + + l -= 3 + SSL_HM_HEADER_LENGTH(s); + p = ssl_handshake_start(s); + l2n3(l, p); + l += 3; + + if (!ssl_set_handshake_header(s, SSL3_MT_CERTIFICATE, l)) { + SSLerr(SSL_F_SSL3_OUTPUT_CERT_CHAIN, ERR_R_INTERNAL_ERROR); + return 0; + } + return l + SSL_HM_HEADER_LENGTH(s); +} + +WORK_STATE tls_finish_handshake(SSL *s, WORK_STATE wst) +{ + void (*cb) (const SSL *ssl, int type, int val) = NULL; + + /* clean a few things up */ + ssl3_cleanup_key_block(s); + + if (!SSL_IS_DTLS(s)) { + /* + * We don't do this in DTLS because we may still need the init_buf + * in case there are any unexpected retransmits + */ + BUF_MEM_free(s->init_buf); + s->init_buf = NULL; + } + + ssl_free_wbio_buffer(s); + + s->init_num = 0; + + if (!s->server || s->renegotiate == 2) { + /* skipped if we just sent a HelloRequest */ + s->renegotiate = 0; + s->new_session = 0; + + if (s->server) { + ssl_update_cache(s, SSL_SESS_CACHE_SERVER); + + s->ctx->stats.sess_accept_good++; + s->handshake_func = ossl_statem_accept; + } else { + ssl_update_cache(s, SSL_SESS_CACHE_CLIENT); + if (s->hit) + s->ctx->stats.sess_hit++; + + s->handshake_func = ossl_statem_connect; + s->ctx->stats.sess_connect_good++; + } + + if (s->info_callback != NULL) + cb = s->info_callback; + else if (s->ctx->info_callback != NULL) + cb = s->ctx->info_callback; + + if (cb != NULL) + cb(s, SSL_CB_HANDSHAKE_DONE, 1); + + if (SSL_IS_DTLS(s)) { + /* done with handshaking */ + s->d1->handshake_read_seq = 0; + s->d1->handshake_write_seq = 0; + s->d1->next_handshake_write_seq = 0; + dtls1_clear_received_buffer(s); + } + } + + return WORK_FINISHED_STOP; +} + +int tls_get_message_header(SSL *s, int *mt) +{ + /* s->init_num < SSL3_HM_HEADER_LENGTH */ + int skip_message, i, recvd_type, al; + unsigned char *p; + unsigned long l; + + p = (unsigned char *)s->init_buf->data; + + do { + while (s->init_num < SSL3_HM_HEADER_LENGTH) { + i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, &recvd_type, + &p[s->init_num], + SSL3_HM_HEADER_LENGTH - s->init_num, + 0); + if (i <= 0) { + s->rwstate = SSL_READING; + return 0; + } + if (recvd_type == SSL3_RT_CHANGE_CIPHER_SPEC) { + /* + * A ChangeCipherSpec must be a single byte and may not occur + * in the middle of a handshake message. + */ + if (s->init_num != 0 || i != 1 || p[0] != SSL3_MT_CCS) { + al = SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_TLS_GET_MESSAGE_HEADER, + SSL_R_BAD_CHANGE_CIPHER_SPEC); + goto f_err; + } + s->s3->tmp.message_type = *mt = SSL3_MT_CHANGE_CIPHER_SPEC; + s->init_num = i - 1; + s->init_msg = s->init_buf->data; + s->s3->tmp.message_size = i; + return 1; + } else if (recvd_type != SSL3_RT_HANDSHAKE) { + al = SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_TLS_GET_MESSAGE_HEADER, SSL_R_CCS_RECEIVED_EARLY); + goto f_err; + } + s->init_num += i; + } + + skip_message = 0; + if (!s->server) + if (p[0] == SSL3_MT_HELLO_REQUEST) + /* + * The server may always send 'Hello Request' messages -- + * we are doing a handshake anyway now, so ignore them if + * their format is correct. Does not count for 'Finished' + * MAC. + */ + if (p[1] == 0 && p[2] == 0 && p[3] == 0) { + s->init_num = 0; + skip_message = 1; + + if (s->msg_callback) + s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, + p, SSL3_HM_HEADER_LENGTH, s, + s->msg_callback_arg); + } + } while (skip_message); + /* s->init_num == SSL3_HM_HEADER_LENGTH */ + + *mt = *p; + s->s3->tmp.message_type = *(p++); + + if (RECORD_LAYER_is_sslv2_record(&s->rlayer)) { + /* + * Only happens with SSLv3+ in an SSLv2 backward compatible + * ClientHello + * + * Total message size is the remaining record bytes to read + * plus the SSL3_HM_HEADER_LENGTH bytes that we already read + */ + l = RECORD_LAYER_get_rrec_length(&s->rlayer) + + SSL3_HM_HEADER_LENGTH; + s->s3->tmp.message_size = l; + + s->init_msg = s->init_buf->data; + s->init_num = SSL3_HM_HEADER_LENGTH; + } else { + n2l3(p, l); + /* BUF_MEM_grow takes an 'int' parameter */ + if (l > (INT_MAX - SSL3_HM_HEADER_LENGTH)) { + al = SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_TLS_GET_MESSAGE_HEADER, SSL_R_EXCESSIVE_MESSAGE_SIZE); + goto f_err; + } + s->s3->tmp.message_size = l; + + s->init_msg = s->init_buf->data + SSL3_HM_HEADER_LENGTH; + s->init_num = 0; + } + + return 1; + f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + return 0; +} + +int tls_get_message_body(SSL *s, unsigned long *len) +{ + long n; + unsigned char *p; + int i; + + if (s->s3->tmp.message_type == SSL3_MT_CHANGE_CIPHER_SPEC) { + /* We've already read everything in */ + *len = (unsigned long)s->init_num; + return 1; + } + + p = s->init_msg; + n = s->s3->tmp.message_size - s->init_num; + while (n > 0) { + i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, NULL, + &p[s->init_num], n, 0); + if (i <= 0) { + s->rwstate = SSL_READING; + *len = 0; + return 0; + } + s->init_num += i; + n -= i; + } + + /* + * If receiving Finished, record MAC of prior handshake messages for + * Finished verification. + */ + if (*(s->init_buf->data) == SSL3_MT_FINISHED && !ssl3_take_mac(s)) { + /* SSLfatal() already called */ + *len = 0; + return 0; + } + + /* Feed this message into MAC computation. */ + if (RECORD_LAYER_is_sslv2_record(&s->rlayer)) { + if (!ssl3_finish_mac(s, (unsigned char *)s->init_buf->data, + s->init_num)) { + SSLerr(SSL_F_TLS_GET_MESSAGE_BODY, ERR_R_EVP_LIB); + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + *len = 0; + return 0; + } + if (s->msg_callback) + s->msg_callback(0, SSL2_VERSION, 0, s->init_buf->data, + (size_t)s->init_num, s, s->msg_callback_arg); + } else { + if (!ssl3_finish_mac(s, (unsigned char *)s->init_buf->data, + s->init_num + SSL3_HM_HEADER_LENGTH)) { + SSLerr(SSL_F_TLS_GET_MESSAGE_BODY, ERR_R_EVP_LIB); + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + *len = 0; + return 0; + } + if (s->msg_callback) + s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, s->init_buf->data, + (size_t)s->init_num + SSL3_HM_HEADER_LENGTH, s, + s->msg_callback_arg); + } + + /* + * init_num should never be negative...should probably be declared + * unsigned + */ + if (s->init_num < 0) { + SSLerr(SSL_F_TLS_GET_MESSAGE_BODY, ERR_R_INTERNAL_ERROR); + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + *len = 0; + return 0; + } + *len = (unsigned long)s->init_num; + return 1; +} + +int ssl_cert_type(const X509 *x, const EVP_PKEY *pk) +{ + if (pk == NULL && (pk = X509_get0_pubkey(x)) == NULL) + return -1; + + switch (EVP_PKEY_id(pk)) { + default: + return -1; + case EVP_PKEY_RSA: + return SSL_PKEY_RSA_ENC; + case EVP_PKEY_DSA: + return SSL_PKEY_DSA_SIGN; +#ifndef OPENSSL_NO_EC + case EVP_PKEY_EC: + return SSL_PKEY_ECC; +#endif +#ifndef OPENSSL_NO_GOST + case NID_id_GostR3410_2001: + return SSL_PKEY_GOST01; + case NID_id_GostR3410_2012_256: + return SSL_PKEY_GOST12_256; + case NID_id_GostR3410_2012_512: + return SSL_PKEY_GOST12_512; +#endif + } +} + +int ssl_verify_alarm_type(long type) +{ + int al; + + switch (type) { + case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: + case X509_V_ERR_UNABLE_TO_GET_CRL: + case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER: + al = SSL_AD_UNKNOWN_CA; + break; + case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: + case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: + case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: + case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: + case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: + case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: + case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: + case X509_V_ERR_CERT_NOT_YET_VALID: + case X509_V_ERR_CRL_NOT_YET_VALID: + case X509_V_ERR_CERT_UNTRUSTED: + case X509_V_ERR_CERT_REJECTED: + case X509_V_ERR_HOSTNAME_MISMATCH: + case X509_V_ERR_EMAIL_MISMATCH: + case X509_V_ERR_IP_ADDRESS_MISMATCH: + case X509_V_ERR_DANE_NO_MATCH: + case X509_V_ERR_EE_KEY_TOO_SMALL: + case X509_V_ERR_CA_KEY_TOO_SMALL: + case X509_V_ERR_CA_MD_TOO_WEAK: + al = SSL_AD_BAD_CERTIFICATE; + break; + case X509_V_ERR_CERT_SIGNATURE_FAILURE: + case X509_V_ERR_CRL_SIGNATURE_FAILURE: + al = SSL_AD_DECRYPT_ERROR; + break; + case X509_V_ERR_CERT_HAS_EXPIRED: + case X509_V_ERR_CRL_HAS_EXPIRED: + al = SSL_AD_CERTIFICATE_EXPIRED; + break; + case X509_V_ERR_CERT_REVOKED: + al = SSL_AD_CERTIFICATE_REVOKED; + break; + case X509_V_ERR_UNSPECIFIED: + case X509_V_ERR_OUT_OF_MEM: + case X509_V_ERR_INVALID_CALL: + case X509_V_ERR_STORE_LOOKUP: + al = SSL_AD_INTERNAL_ERROR; + break; + case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: + case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: + case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: + case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: + case X509_V_ERR_CERT_CHAIN_TOO_LONG: + case X509_V_ERR_PATH_LENGTH_EXCEEDED: + case X509_V_ERR_INVALID_CA: + al = SSL_AD_UNKNOWN_CA; + break; + case X509_V_ERR_APPLICATION_VERIFICATION: + al = SSL_AD_HANDSHAKE_FAILURE; + break; + case X509_V_ERR_INVALID_PURPOSE: + al = SSL_AD_UNSUPPORTED_CERTIFICATE; + break; + default: + al = SSL_AD_CERTIFICATE_UNKNOWN; + break; + } + return (al); +} + +int ssl_allow_compression(SSL *s) +{ + if (s->options & SSL_OP_NO_COMPRESSION) + return 0; + return ssl_security(s, SSL_SECOP_COMPRESSION, 0, 0, NULL); +} + +static int version_cmp(const SSL *s, int a, int b) +{ + int dtls = SSL_IS_DTLS(s); + + if (a == b) + return 0; + if (!dtls) + return a < b ? -1 : 1; + return DTLS_VERSION_LT(a, b) ? -1 : 1; +} + +typedef struct { + int version; + const SSL_METHOD *(*cmeth) (void); + const SSL_METHOD *(*smeth) (void); +} version_info; + +#if TLS_MAX_VERSION != TLS1_2_VERSION +# error Code needs update for TLS_method() support beyond TLS1_2_VERSION. +#endif + +static const version_info tls_version_table[] = { +#ifndef OPENSSL_NO_TLS1_2 + {TLS1_2_VERSION, tlsv1_2_client_method, tlsv1_2_server_method}, +#else + {TLS1_2_VERSION, NULL, NULL}, +#endif +#ifndef OPENSSL_NO_TLS1_1 + {TLS1_1_VERSION, tlsv1_1_client_method, tlsv1_1_server_method}, +#else + {TLS1_1_VERSION, NULL, NULL}, +#endif +#ifndef OPENSSL_NO_TLS1 + {TLS1_VERSION, tlsv1_client_method, tlsv1_server_method}, +#else + {TLS1_VERSION, NULL, NULL}, +#endif +#ifndef OPENSSL_NO_SSL3 + {SSL3_VERSION, sslv3_client_method, sslv3_server_method}, +#else + {SSL3_VERSION, NULL, NULL}, +#endif + {0, NULL, NULL}, +}; + +#if DTLS_MAX_VERSION != DTLS1_2_VERSION +# error Code needs update for DTLS_method() support beyond DTLS1_2_VERSION. +#endif + +static const version_info dtls_version_table[] = { +#ifndef OPENSSL_NO_DTLS1_2 + {DTLS1_2_VERSION, dtlsv1_2_client_method, dtlsv1_2_server_method}, +#else + {DTLS1_2_VERSION, NULL, NULL}, +#endif +#ifndef OPENSSL_NO_DTLS1 + {DTLS1_VERSION, dtlsv1_client_method, dtlsv1_server_method}, + {DTLS1_BAD_VER, dtls_bad_ver_client_method, NULL}, +#else + {DTLS1_VERSION, NULL, NULL}, + {DTLS1_BAD_VER, NULL, NULL}, +#endif + {0, NULL, NULL}, +}; + +/* + * ssl_method_error - Check whether an SSL_METHOD is enabled. + * + * @s: The SSL handle for the candidate method + * @method: the intended method. + * + * Returns 0 on success, or an SSL error reason on failure. + */ +static int ssl_method_error(const SSL *s, const SSL_METHOD *method) +{ + int version = method->version; + + if ((s->min_proto_version != 0 && + version_cmp(s, version, s->min_proto_version) < 0) || + ssl_security(s, SSL_SECOP_VERSION, 0, version, NULL) == 0) + return SSL_R_VERSION_TOO_LOW; + + if (s->max_proto_version != 0 && + version_cmp(s, version, s->max_proto_version) > 0) + return SSL_R_VERSION_TOO_HIGH; + + if ((s->options & method->mask) != 0) + return SSL_R_UNSUPPORTED_PROTOCOL; + if ((method->flags & SSL_METHOD_NO_SUITEB) != 0 && tls1_suiteb(s)) + return SSL_R_AT_LEAST_TLS_1_2_NEEDED_IN_SUITEB_MODE; + else if ((method->flags & SSL_METHOD_NO_FIPS) != 0 && FIPS_mode()) + return SSL_R_AT_LEAST_TLS_1_0_NEEDED_IN_FIPS_MODE; + + return 0; +} + +/* + * ssl_version_supported - Check that the specified `version` is supported by + * `SSL *` instance + * + * @s: The SSL handle for the candidate method + * @version: Protocol version to test against + * + * Returns 1 when supported, otherwise 0 + */ +int ssl_version_supported(const SSL *s, int version) +{ + const version_info *vent; + const version_info *table; + + switch (s->method->version) { + default: + /* Version should match method version for non-ANY method */ + return version_cmp(s, version, s->version) == 0; + case TLS_ANY_VERSION: + table = tls_version_table; + break; + case DTLS_ANY_VERSION: + table = dtls_version_table; + break; + } + + for (vent = table; + vent->version != 0 && version_cmp(s, version, vent->version) <= 0; + ++vent) { + if (vent->cmeth != NULL && + version_cmp(s, version, vent->version) == 0 && + ssl_method_error(s, vent->cmeth()) == 0) { + return 1; + } + } + return 0; +} + +/* + * ssl_check_version_downgrade - In response to RFC7507 SCSV version + * fallback indication from a client check whether we're using the highest + * supported protocol version. + * + * @s server SSL handle. + * + * Returns 1 when using the highest enabled version, 0 otherwise. + */ +int ssl_check_version_downgrade(SSL *s) +{ + const version_info *vent; + const version_info *table; + + /* + * Check that the current protocol is the highest enabled version + * (according to s->ctx->method, as version negotiation may have changed + * s->method). + */ + if (s->version == s->ctx->method->version) + return 1; + + /* + * Apparently we're using a version-flexible SSL_METHOD (not at its + * highest protocol version). + */ + if (s->ctx->method->version == TLS_method()->version) + table = tls_version_table; + else if (s->ctx->method->version == DTLS_method()->version) + table = dtls_version_table; + else { + /* Unexpected state; fail closed. */ + return 0; + } + + for (vent = table; vent->version != 0; ++vent) { + if (vent->smeth != NULL && ssl_method_error(s, vent->smeth()) == 0) + return s->version == vent->version; + } + return 0; +} + +/* + * ssl_set_version_bound - set an upper or lower bound on the supported (D)TLS + * protocols, provided the initial (D)TLS method is version-flexible. This + * function sanity-checks the proposed value and makes sure the method is + * version-flexible, then sets the limit if all is well. + * + * @method_version: The version of the current SSL_METHOD. + * @version: the intended limit. + * @bound: pointer to limit to be updated. + * + * Returns 1 on success, 0 on failure. + */ +int ssl_set_version_bound(int method_version, int version, int *bound) +{ + if (version == 0) { + *bound = version; + return 1; + } + + /*- + * Restrict TLS methods to TLS protocol versions. + * Restrict DTLS methods to DTLS protocol versions. + * Note, DTLS version numbers are decreasing, use comparison macros. + * + * Note that for both lower-bounds we use explicit versions, not + * (D)TLS_MIN_VERSION. This is because we don't want to break user + * configurations. If the MIN (supported) version ever rises, the user's + * "floor" remains valid even if no longer available. We don't expect the + * MAX ceiling to ever get lower, so making that variable makes sense. + */ + switch (method_version) { + default: + /* + * XXX For fixed version methods, should we always fail and not set any + * bounds, always succeed and not set any bounds, or set the bounds and + * arrange to fail later if they are not met? At present fixed-version + * methods are not subject to controls that disable individual protocol + * versions. + */ + return 0; + + case TLS_ANY_VERSION: + if (version < SSL3_VERSION || version > TLS_MAX_VERSION) + return 0; + break; + + case DTLS_ANY_VERSION: + if (DTLS_VERSION_GT(version, DTLS_MAX_VERSION) || + DTLS_VERSION_LT(version, DTLS1_BAD_VER)) + return 0; + break; + } + + *bound = version; + return 1; +} + +/* + * ssl_choose_server_version - Choose server (D)TLS version. Called when the + * client HELLO is received to select the final server protocol version and + * the version specific method. + * + * @s: server SSL handle. + * + * Returns 0 on success or an SSL error reason number on failure. + */ +int ssl_choose_server_version(SSL *s) +{ + /*- + * With version-flexible methods we have an initial state with: + * + * s->method->version == (D)TLS_ANY_VERSION, + * s->version == (D)TLS_MAX_VERSION. + * + * So we detect version-flexible methods via the method version, not the + * handle version. + */ + int server_version = s->method->version; + int client_version = s->client_version; + const version_info *vent; + const version_info *table; + int disabled = 0; + + switch (server_version) { + default: + if (version_cmp(s, client_version, s->version) < 0) + return SSL_R_WRONG_SSL_VERSION; + /* + * If this SSL handle is not from a version flexible method we don't + * (and never did) check min/max FIPS or Suite B constraints. Hope + * that's OK. It is up to the caller to not choose fixed protocol + * versions they don't want. If not, then easy to fix, just return + * ssl_method_error(s, s->method) + */ + return 0; + case TLS_ANY_VERSION: + table = tls_version_table; + break; + case DTLS_ANY_VERSION: + table = dtls_version_table; + break; + } + + for (vent = table; vent->version != 0; ++vent) { + const SSL_METHOD *method; + + if (vent->smeth == NULL || + version_cmp(s, client_version, vent->version) < 0) + continue; + method = vent->smeth(); + if (ssl_method_error(s, method) == 0) { + s->version = vent->version; + s->method = method; + return 0; + } + disabled = 1; + } + return disabled ? SSL_R_UNSUPPORTED_PROTOCOL : SSL_R_VERSION_TOO_LOW; +} + +/* + * ssl_choose_client_version - Choose client (D)TLS version. Called when the + * server HELLO is received to select the final client protocol version and + * the version specific method. + * + * @s: client SSL handle. + * @version: The proposed version from the server's HELLO. + * + * Returns 0 on success or an SSL error reason number on failure. + */ +int ssl_choose_client_version(SSL *s, int version) +{ + const version_info *vent; + const version_info *table; + + switch (s->method->version) { + default: + if (version != s->version) + return SSL_R_WRONG_SSL_VERSION; + /* + * If this SSL handle is not from a version flexible method we don't + * (and never did) check min/max, FIPS or Suite B constraints. Hope + * that's OK. It is up to the caller to not choose fixed protocol + * versions they don't want. If not, then easy to fix, just return + * ssl_method_error(s, s->method) + */ + return 0; + case TLS_ANY_VERSION: + table = tls_version_table; + break; + case DTLS_ANY_VERSION: + table = dtls_version_table; + break; + } + + for (vent = table; vent->version != 0; ++vent) { + const SSL_METHOD *method; + int err; + + if (version != vent->version) + continue; + if (vent->cmeth == NULL) + break; + method = vent->cmeth(); + err = ssl_method_error(s, method); + if (err != 0) + return err; + s->method = method; + s->version = version; + return 0; + } + + return SSL_R_UNSUPPORTED_PROTOCOL; +} + +/* + * ssl_get_client_min_max_version - get minimum and maximum client version + * @s: The SSL connection + * @min_version: The minimum supported version + * @max_version: The maximum supported version + * + * Work out what version we should be using for the initial ClientHello if the + * version is initially (D)TLS_ANY_VERSION. We apply any explicit SSL_OP_NO_xxx + * options, the MinProtocol and MaxProtocol configuration commands, any Suite B + * or FIPS_mode() constraints and any floor imposed by the security level here, + * so we don't advertise the wrong protocol version to only reject the outcome later. + * + * Computing the right floor matters. If, e.g., TLS 1.0 and 1.2 are enabled, + * TLS 1.1 is disabled, but the security level, Suite-B and/or MinProtocol + * only allow TLS 1.2, we want to advertise TLS1.2, *not* TLS1. + * + * Returns 0 on success or an SSL error reason number on failure. On failure + * min_version and max_version will also be set to 0. + */ +int ssl_get_client_min_max_version(const SSL *s, int *min_version, + int *max_version) +{ + int version; + int hole; + const SSL_METHOD *single = NULL; + const SSL_METHOD *method; + const version_info *table; + const version_info *vent; + + switch (s->method->version) { + default: + /* + * If this SSL handle is not from a version flexible method we don't + * (and never did) check min/max FIPS or Suite B constraints. Hope + * that's OK. It is up to the caller to not choose fixed protocol + * versions they don't want. If not, then easy to fix, just return + * ssl_method_error(s, s->method) + */ + *min_version = *max_version = s->version; + return 0; + case TLS_ANY_VERSION: + table = tls_version_table; + break; + case DTLS_ANY_VERSION: + table = dtls_version_table; + break; + } + + /* + * SSL_OP_NO_X disables all protocols above X *if* there are some protocols + * below X enabled. This is required in order to maintain the "version + * capability" vector contiguous. Any versions with a NULL client method + * (protocol version client is disabled at compile-time) is also a "hole". + * + * Our initial state is hole == 1, version == 0. That is, versions above + * the first version in the method table are disabled (a "hole" above + * the valid protocol entries) and we don't have a selected version yet. + * + * Whenever "hole == 1", and we hit an enabled method, its version becomes + * the selected version, and the method becomes a candidate "single" + * method. We're no longer in a hole, so "hole" becomes 0. + * + * If "hole == 0" and we hit an enabled method, then "single" is cleared, + * as we support a contiguous range of at least two methods. If we hit + * a disabled method, then hole becomes true again, but nothing else + * changes yet, because all the remaining methods may be disabled too. + * If we again hit an enabled method after the new hole, it becomes + * selected, as we start from scratch. + */ + *min_version = version = 0; + hole = 1; + for (vent = table; vent->version != 0; ++vent) { + /* + * A table entry with a NULL client method is still a hole in the + * "version capability" vector. + */ + if (vent->cmeth == NULL) { + hole = 1; + continue; + } + method = vent->cmeth(); + if (ssl_method_error(s, method) != 0) { + hole = 1; + } else if (!hole) { + single = NULL; + *min_version = method->version; + } else { + version = (single = method)->version; + *min_version = version; + hole = 0; + } + } + + *max_version = version; + + /* Fail if everything is disabled */ + if (version == 0) + return SSL_R_NO_PROTOCOLS_AVAILABLE; + + return 0; +} + +/* + * ssl_set_client_hello_version - Work out what version we should be using for + * the initial ClientHello. + * + * @s: client SSL handle. + * + * Returns 0 on success or an SSL error reason number on failure. + */ +int ssl_set_client_hello_version(SSL *s) +{ + int ver_min, ver_max, ret; + + ret = ssl_get_client_min_max_version(s, &ver_min, &ver_max); + + if (ret != 0) + return ret; + + s->client_version = s->version = ver_max; + return 0; +} diff --git a/openssl-1.1.0h/ssl/statem/statem_locl.h b/openssl-1.1.0h/ssl/statem/statem_locl.h new file mode 100644 index 0000000..5dbc62b --- /dev/null +++ b/openssl-1.1.0h/ssl/statem/statem_locl.h @@ -0,0 +1,125 @@ +/* + * Copyright 2015-2018 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (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 + */ + +/***************************************************************************** + * * + * The following definitions are PRIVATE to the state machine. They should * + * NOT be used outside of the state machine. * + * * + *****************************************************************************/ + +/* Max message length definitions */ + +/* The spec allows for a longer length than this, but we limit it */ +#define HELLO_VERIFY_REQUEST_MAX_LENGTH 258 +#define SERVER_HELLO_MAX_LENGTH 20000 +#define SERVER_KEY_EXCH_MAX_LENGTH 102400 +#define SERVER_HELLO_DONE_MAX_LENGTH 0 +#define CCS_MAX_LENGTH 1 +/* Max should actually be 36 but we are generous */ +#define FINISHED_MAX_LENGTH 64 + +/* Message processing return codes */ +typedef enum { + /* Something bad happened */ + MSG_PROCESS_ERROR, + /* We've finished reading - swap to writing */ + MSG_PROCESS_FINISHED_READING, + /* + * We've completed the main processing of this message but there is some + * post processing to be done. + */ + MSG_PROCESS_CONTINUE_PROCESSING, + /* We've finished this message - read the next message */ + MSG_PROCESS_CONTINUE_READING +} MSG_PROCESS_RETURN; + +/* Flush the write BIO */ +int statem_flush(SSL *s); +int ssl3_take_mac(SSL *s); + +/* + * TLS/DTLS client state machine functions + */ +int ossl_statem_client_read_transition(SSL *s, int mt); +WRITE_TRAN ossl_statem_client_write_transition(SSL *s); +WORK_STATE ossl_statem_client_pre_work(SSL *s, WORK_STATE wst); +WORK_STATE ossl_statem_client_post_work(SSL *s, WORK_STATE wst); +int ossl_statem_client_construct_message(SSL *s); +unsigned long ossl_statem_client_max_message_size(SSL *s); +MSG_PROCESS_RETURN ossl_statem_client_process_message(SSL *s, PACKET *pkt); +WORK_STATE ossl_statem_client_post_process_message(SSL *s, WORK_STATE wst); + +/* + * TLS/DTLS server state machine functions + */ +int ossl_statem_server_read_transition(SSL *s, int mt); +WRITE_TRAN ossl_statem_server_write_transition(SSL *s); +WORK_STATE ossl_statem_server_pre_work(SSL *s, WORK_STATE wst); +WORK_STATE ossl_statem_server_post_work(SSL *s, WORK_STATE wst); +int ossl_statem_server_construct_message(SSL *s); +unsigned long ossl_statem_server_max_message_size(SSL *s); +MSG_PROCESS_RETURN ossl_statem_server_process_message(SSL *s, PACKET *pkt); +WORK_STATE ossl_statem_server_post_process_message(SSL *s, WORK_STATE wst); + +/* Functions for getting new message data */ +__owur int tls_get_message_header(SSL *s, int *mt); +__owur int tls_get_message_body(SSL *s, unsigned long *len); +__owur int dtls_get_message(SSL *s, int *mt, unsigned long *len); + +/* Message construction and processing functions */ +__owur MSG_PROCESS_RETURN tls_process_change_cipher_spec(SSL *s, PACKET *pkt); +__owur MSG_PROCESS_RETURN tls_process_finished(SSL *s, PACKET *pkt); +__owur int tls_construct_change_cipher_spec(SSL *s); +__owur int dtls_construct_change_cipher_spec(SSL *s); + +__owur int tls_construct_finished(SSL *s, const char *sender, int slen); +__owur WORK_STATE tls_finish_handshake(SSL *s, WORK_STATE wst); +__owur WORK_STATE dtls_wait_for_dry(SSL *s); + +/* some client-only functions */ +__owur int tls_construct_client_hello(SSL *s); +__owur MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt); +__owur MSG_PROCESS_RETURN tls_process_certificate_request(SSL *s, PACKET *pkt); +__owur MSG_PROCESS_RETURN tls_process_new_session_ticket(SSL *s, PACKET *pkt); +__owur MSG_PROCESS_RETURN tls_process_cert_status(SSL *s, PACKET *pkt); +__owur MSG_PROCESS_RETURN tls_process_server_done(SSL *s, PACKET *pkt); +__owur int tls_construct_client_verify(SSL *s); +__owur WORK_STATE tls_prepare_client_certificate(SSL *s, WORK_STATE wst); +__owur int tls_construct_client_certificate(SSL *s); +__owur int ssl_do_client_cert_cb(SSL *s, X509 **px509, EVP_PKEY **ppkey); +__owur int tls_construct_client_key_exchange(SSL *s); +__owur int tls_client_key_exchange_post_work(SSL *s); +__owur int tls_construct_cert_status(SSL *s); +__owur MSG_PROCESS_RETURN tls_process_key_exchange(SSL *s, PACKET *pkt); +__owur MSG_PROCESS_RETURN tls_process_server_certificate(SSL *s, PACKET *pkt); +__owur int ssl3_check_cert_and_algorithm(SSL *s); +#ifndef OPENSSL_NO_NEXTPROTONEG +__owur int tls_construct_next_proto(SSL *s); +#endif +__owur MSG_PROCESS_RETURN dtls_process_hello_verify(SSL *s, PACKET *pkt); + +/* some server-only functions */ +__owur MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt); +__owur WORK_STATE tls_post_process_client_hello(SSL *s, WORK_STATE wst); +__owur int tls_construct_server_hello(SSL *s); +__owur int tls_construct_hello_request(SSL *s); +__owur int dtls_construct_hello_verify_request(SSL *s); +__owur int tls_construct_server_certificate(SSL *s); +__owur int tls_construct_server_key_exchange(SSL *s); +__owur int tls_construct_certificate_request(SSL *s); +__owur int tls_construct_server_done(SSL *s); +__owur MSG_PROCESS_RETURN tls_process_client_certificate(SSL *s, PACKET *pkt); +__owur MSG_PROCESS_RETURN tls_process_client_key_exchange(SSL *s, PACKET *pkt); +__owur WORK_STATE tls_post_process_client_key_exchange(SSL *s, WORK_STATE wst); +__owur MSG_PROCESS_RETURN tls_process_cert_verify(SSL *s, PACKET *pkt); +#ifndef OPENSSL_NO_NEXTPROTONEG +__owur MSG_PROCESS_RETURN tls_process_next_proto(SSL *s, PACKET *pkt); +#endif +__owur int tls_construct_new_session_ticket(SSL *s); diff --git a/openssl-1.1.0h/ssl/statem/statem_srvr.c b/openssl-1.1.0h/ssl/statem/statem_srvr.c new file mode 100644 index 0000000..c7cd9eb --- /dev/null +++ b/openssl-1.1.0h/ssl/statem/statem_srvr.c @@ -0,0 +1,3341 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (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 + */ + +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * Portions of the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the OpenSSL open source + * license provided above. + * + * ECC cipher suite support in OpenSSL originally written by + * Vipul Gupta and Sumit Gupta of Sun Microsystems Laboratories. + * + */ +/* ==================================================================== + * Copyright 2005 Nokia. All rights reserved. + * + * The portions of the attached software ("Contribution") is developed by + * Nokia Corporation and is licensed pursuant to the OpenSSL open source + * license. + * + * The Contribution, originally written by Mika Kousa and Pasi Eronen of + * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites + * support (see RFC 4279) to OpenSSL. + * + * No patent licenses or other rights except those expressly stated in + * the OpenSSL open source license shall be deemed granted or received + * expressly, by implication, estoppel, or otherwise. + * + * No assurances are provided by Nokia that the Contribution does not + * infringe the patent or other intellectual property rights of any third + * party or that the license provides you with all the necessary rights + * to make use of the Contribution. + * + * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN + * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA + * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY + * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR + * OTHERWISE. + */ + +#include <stdio.h> +#include "../ssl_locl.h" +#include "statem_locl.h" +#include "internal/constant_time_locl.h" +#include <openssl/buffer.h> +#include <openssl/rand.h> +#include <openssl/objects.h> +#include <openssl/evp.h> +#include <openssl/hmac.h> +#include <openssl/x509.h> +#include <openssl/dh.h> +#include <openssl/bn.h> +#include <openssl/md5.h> + +static STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, + PACKET *cipher_suites, + STACK_OF(SSL_CIPHER) + **skp, int sslv2format, + int *al); + +/* + * server_read_transition() encapsulates the logic for the allowed handshake + * state transitions when the server is reading messages from the client. The + * message type that the client has sent is provided in |mt|. The current state + * is in |s->statem.hand_state|. + * + * Valid return values are: + * 1: Success (transition allowed) + * 0: Error (transition not allowed) + */ +int ossl_statem_server_read_transition(SSL *s, int mt) +{ + OSSL_STATEM *st = &s->statem; + + switch (st->hand_state) { + case TLS_ST_BEFORE: + case DTLS_ST_SW_HELLO_VERIFY_REQUEST: + if (mt == SSL3_MT_CLIENT_HELLO) { + st->hand_state = TLS_ST_SR_CLNT_HELLO; + return 1; + } + break; + + case TLS_ST_SW_SRVR_DONE: + /* + * If we get a CKE message after a ServerDone then either + * 1) We didn't request a Certificate + * OR + * 2) If we did request one then + * a) We allow no Certificate to be returned + * AND + * b) We are running SSL3 (in TLS1.0+ the client must return a 0 + * list if we requested a certificate) + */ + if (mt == SSL3_MT_CLIENT_KEY_EXCHANGE) { + if (s->s3->tmp.cert_request) { + if (s->version == SSL3_VERSION) { + if ((s->verify_mode & SSL_VERIFY_PEER) + && (s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) { + /* + * This isn't an unexpected message as such - we're just + * not going to accept it because we require a client + * cert. + */ + ssl3_send_alert(s, SSL3_AL_FATAL, + SSL3_AD_HANDSHAKE_FAILURE); + SSLerr(SSL_F_OSSL_STATEM_SERVER_READ_TRANSITION, + SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE); + return 0; + } + st->hand_state = TLS_ST_SR_KEY_EXCH; + return 1; + } + } else { + st->hand_state = TLS_ST_SR_KEY_EXCH; + return 1; + } + } else if (s->s3->tmp.cert_request) { + if (mt == SSL3_MT_CERTIFICATE) { + st->hand_state = TLS_ST_SR_CERT; + return 1; + } + } + break; + + case TLS_ST_SR_CERT: + if (mt == SSL3_MT_CLIENT_KEY_EXCHANGE) { + st->hand_state = TLS_ST_SR_KEY_EXCH; + return 1; + } + break; + + case TLS_ST_SR_KEY_EXCH: + /* + * We should only process a CertificateVerify message if we have + * received a Certificate from the client. If so then |s->session->peer| + * will be non NULL. In some instances a CertificateVerify message is + * not required even if the peer has sent a Certificate (e.g. such as in + * the case of static DH). In that case |st->no_cert_verify| should be + * set. + */ + if (s->session->peer == NULL || st->no_cert_verify) { + if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) { + /* + * For the ECDH ciphersuites when the client sends its ECDH + * pub key in a certificate, the CertificateVerify message is + * not sent. Also for GOST ciphersuites when the client uses + * its key from the certificate for key exchange. + */ + st->hand_state = TLS_ST_SR_CHANGE; + return 1; + } + } else { + if (mt == SSL3_MT_CERTIFICATE_VERIFY) { + st->hand_state = TLS_ST_SR_CERT_VRFY; + return 1; + } + } + break; + + case TLS_ST_SR_CERT_VRFY: + if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) { + st->hand_state = TLS_ST_SR_CHANGE; + return 1; + } + break; + + case TLS_ST_SR_CHANGE: +#ifndef OPENSSL_NO_NEXTPROTONEG + if (s->s3->next_proto_neg_seen) { + if (mt == SSL3_MT_NEXT_PROTO) { + st->hand_state = TLS_ST_SR_NEXT_PROTO; + return 1; + } + } else { +#endif + if (mt == SSL3_MT_FINISHED) { + st->hand_state = TLS_ST_SR_FINISHED; + return 1; + } +#ifndef OPENSSL_NO_NEXTPROTONEG + } +#endif + break; + +#ifndef OPENSSL_NO_NEXTPROTONEG + case TLS_ST_SR_NEXT_PROTO: + if (mt == SSL3_MT_FINISHED) { + st->hand_state = TLS_ST_SR_FINISHED; + return 1; + } + break; +#endif + + case TLS_ST_SW_FINISHED: + if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) { + st->hand_state = TLS_ST_SR_CHANGE; + return 1; + } + break; + + default: + break; + } + + /* No valid transition found */ + ssl3_send_alert(s, SSL3_AL_FATAL, SSL3_AD_UNEXPECTED_MESSAGE); + SSLerr(SSL_F_OSSL_STATEM_SERVER_READ_TRANSITION, SSL_R_UNEXPECTED_MESSAGE); + return 0; +} + +/* + * Should we send a ServerKeyExchange message? + * + * Valid return values are: + * 1: Yes + * 0: No + */ +static int send_server_key_exchange(SSL *s) +{ + unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey; + + /* + * only send a ServerKeyExchange if DH or fortezza but we have a + * sign only certificate PSK: may send PSK identity hints For + * ECC ciphersuites, we send a serverKeyExchange message only if + * the cipher suite is either ECDH-anon or ECDHE. In other cases, + * the server certificate contains the server's public key for + * key exchange. + */ + if (alg_k & (SSL_kDHE | SSL_kECDHE) + /* + * PSK: send ServerKeyExchange if PSK identity hint if + * provided + */ +#ifndef OPENSSL_NO_PSK + /* Only send SKE if we have identity hint for plain PSK */ + || ((alg_k & (SSL_kPSK | SSL_kRSAPSK)) + && s->cert->psk_identity_hint) + /* For other PSK always send SKE */ + || (alg_k & (SSL_PSK & (SSL_kDHEPSK | SSL_kECDHEPSK))) +#endif +#ifndef OPENSSL_NO_SRP + /* SRP: send ServerKeyExchange */ + || (alg_k & SSL_kSRP) +#endif + ) { + return 1; + } + + return 0; +} + +/* + * Should we send a CertificateRequest message? + * + * Valid return values are: + * 1: Yes + * 0: No + */ +static int send_certificate_request(SSL *s) +{ + if ( + /* don't request cert unless asked for it: */ + s->verify_mode & SSL_VERIFY_PEER + /* + * if SSL_VERIFY_CLIENT_ONCE is set, don't request cert + * during re-negotiation: + */ + && (s->s3->tmp.finish_md_len == 0 || + !(s->verify_mode & SSL_VERIFY_CLIENT_ONCE)) + /* + * never request cert in anonymous ciphersuites (see + * section "Certificate request" in SSL 3 drafts and in + * RFC 2246): + */ + && (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL) + /* + * ... except when the application insists on + * verification (against the specs, but statem_clnt.c accepts + * this for SSL 3) + */ + || (s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) + /* don't request certificate for SRP auth */ + && !(s->s3->tmp.new_cipher->algorithm_auth & SSL_aSRP) + /* + * With normal PSK Certificates and Certificate Requests + * are omitted + */ + && !(s->s3->tmp.new_cipher->algorithm_auth & SSL_aPSK)) { + return 1; + } + + return 0; +} + +/* + * server_write_transition() works out what handshake state to move to next + * when the server is writing messages to be sent to the client. + */ +WRITE_TRAN ossl_statem_server_write_transition(SSL *s) +{ + OSSL_STATEM *st = &s->statem; + + switch (st->hand_state) { + case TLS_ST_BEFORE: + /* Just go straight to trying to read from the client */ + return WRITE_TRAN_FINISHED; + + case TLS_ST_OK: + /* We must be trying to renegotiate */ + st->hand_state = TLS_ST_SW_HELLO_REQ; + return WRITE_TRAN_CONTINUE; + + case TLS_ST_SW_HELLO_REQ: + st->hand_state = TLS_ST_OK; + ossl_statem_set_in_init(s, 0); + return WRITE_TRAN_CONTINUE; + + case TLS_ST_SR_CLNT_HELLO: + if (SSL_IS_DTLS(s) && !s->d1->cookie_verified + && (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE)) + st->hand_state = DTLS_ST_SW_HELLO_VERIFY_REQUEST; + else + st->hand_state = TLS_ST_SW_SRVR_HELLO; + return WRITE_TRAN_CONTINUE; + + case DTLS_ST_SW_HELLO_VERIFY_REQUEST: + return WRITE_TRAN_FINISHED; + + case TLS_ST_SW_SRVR_HELLO: + if (s->hit) { + if (s->tlsext_ticket_expected) + st->hand_state = TLS_ST_SW_SESSION_TICKET; + else + st->hand_state = TLS_ST_SW_CHANGE; + } else { + /* Check if it is anon DH or anon ECDH, */ + /* normal PSK or SRP */ + if (!(s->s3->tmp.new_cipher->algorithm_auth & + (SSL_aNULL | SSL_aSRP | SSL_aPSK))) { + st->hand_state = TLS_ST_SW_CERT; + } else if (send_server_key_exchange(s)) { + st->hand_state = TLS_ST_SW_KEY_EXCH; + } else if (send_certificate_request(s)) { + st->hand_state = TLS_ST_SW_CERT_REQ; + } else { + st->hand_state = TLS_ST_SW_SRVR_DONE; + } + } + return WRITE_TRAN_CONTINUE; + + case TLS_ST_SW_CERT: + if (s->tlsext_status_expected) { + st->hand_state = TLS_ST_SW_CERT_STATUS; + return WRITE_TRAN_CONTINUE; + } + /* Fall through */ + + case TLS_ST_SW_CERT_STATUS: + if (send_server_key_exchange(s)) { + st->hand_state = TLS_ST_SW_KEY_EXCH; + return WRITE_TRAN_CONTINUE; + } + /* Fall through */ + + case TLS_ST_SW_KEY_EXCH: + if (send_certificate_request(s)) { + st->hand_state = TLS_ST_SW_CERT_REQ; + return WRITE_TRAN_CONTINUE; + } + /* Fall through */ + + case TLS_ST_SW_CERT_REQ: + st->hand_state = TLS_ST_SW_SRVR_DONE; + return WRITE_TRAN_CONTINUE; + + case TLS_ST_SW_SRVR_DONE: + return WRITE_TRAN_FINISHED; + + case TLS_ST_SR_FINISHED: + if (s->hit) { + st->hand_state = TLS_ST_OK; + ossl_statem_set_in_init(s, 0); + return WRITE_TRAN_CONTINUE; + } else if (s->tlsext_ticket_expected) { + st->hand_state = TLS_ST_SW_SESSION_TICKET; + } else { + st->hand_state = TLS_ST_SW_CHANGE; + } + return WRITE_TRAN_CONTINUE; + + case TLS_ST_SW_SESSION_TICKET: + st->hand_state = TLS_ST_SW_CHANGE; + return WRITE_TRAN_CONTINUE; + + case TLS_ST_SW_CHANGE: + st->hand_state = TLS_ST_SW_FINISHED; + return WRITE_TRAN_CONTINUE; + + case TLS_ST_SW_FINISHED: + if (s->hit) { + return WRITE_TRAN_FINISHED; + } + st->hand_state = TLS_ST_OK; + ossl_statem_set_in_init(s, 0); + return WRITE_TRAN_CONTINUE; + + default: + /* Shouldn't happen */ + return WRITE_TRAN_ERROR; + } +} + +/* + * Perform any pre work that needs to be done prior to sending a message from + * the server to the client. + */ +WORK_STATE ossl_statem_server_pre_work(SSL *s, WORK_STATE wst) +{ + OSSL_STATEM *st = &s->statem; + + switch (st->hand_state) { + case TLS_ST_SW_HELLO_REQ: + s->shutdown = 0; + if (SSL_IS_DTLS(s)) + dtls1_clear_sent_buffer(s); + break; + + case DTLS_ST_SW_HELLO_VERIFY_REQUEST: + s->shutdown = 0; + if (SSL_IS_DTLS(s)) { + dtls1_clear_sent_buffer(s); + /* We don't buffer this message so don't use the timer */ + st->use_timer = 0; + } + break; + + case TLS_ST_SW_SRVR_HELLO: + if (SSL_IS_DTLS(s)) { + /* + * Messages we write from now on should be buffered and + * retransmitted if necessary, so we need to use the timer now + */ + st->use_timer = 1; + } + break; + + case TLS_ST_SW_SRVR_DONE: +#ifndef OPENSSL_NO_SCTP + if (SSL_IS_DTLS(s) && BIO_dgram_is_sctp(SSL_get_wbio(s))) + return dtls_wait_for_dry(s); +#endif + return WORK_FINISHED_CONTINUE; + + case TLS_ST_SW_SESSION_TICKET: + if (SSL_IS_DTLS(s)) { + /* + * We're into the last flight. We don't retransmit the last flight + * unless we need to, so we don't use the timer + */ + st->use_timer = 0; + } + break; + + case TLS_ST_SW_CHANGE: + s->session->cipher = s->s3->tmp.new_cipher; + if (!s->method->ssl3_enc->setup_key_block(s)) { + ossl_statem_set_error(s); + return WORK_ERROR; + } + if (SSL_IS_DTLS(s)) { + /* + * We're into the last flight. We don't retransmit the last flight + * unless we need to, so we don't use the timer. This might have + * already been set to 0 if we sent a NewSessionTicket message, + * but we'll set it again here in case we didn't. + */ + st->use_timer = 0; + } + return WORK_FINISHED_CONTINUE; + + case TLS_ST_OK: + return tls_finish_handshake(s, wst); + + default: + /* No pre work to be done */ + break; + } + + return WORK_FINISHED_CONTINUE; +} + +/* + * Perform any work that needs to be done after sending a message from the + * server to the client. + */ +WORK_STATE ossl_statem_server_post_work(SSL *s, WORK_STATE wst) +{ + OSSL_STATEM *st = &s->statem; + + s->init_num = 0; + + switch (st->hand_state) { + case TLS_ST_SW_HELLO_REQ: + if (statem_flush(s) != 1) + return WORK_MORE_A; + if (!ssl3_init_finished_mac(s)) { + ossl_statem_set_error(s); + return WORK_ERROR; + } + break; + + case DTLS_ST_SW_HELLO_VERIFY_REQUEST: + if (statem_flush(s) != 1) + return WORK_MORE_A; + /* HelloVerifyRequest resets Finished MAC */ + if (s->version != DTLS1_BAD_VER && !ssl3_init_finished_mac(s)) { + ossl_statem_set_error(s); + return WORK_ERROR; + } + /* + * The next message should be another ClientHello which we need to + * treat like it was the first packet + */ + s->first_packet = 1; + break; + + case TLS_ST_SW_SRVR_HELLO: +#ifndef OPENSSL_NO_SCTP + if (SSL_IS_DTLS(s) && s->hit) { + unsigned char sctpauthkey[64]; + char labelbuffer[sizeof(DTLS1_SCTP_AUTH_LABEL)]; + + /* + * Add new shared key for SCTP-Auth, will be ignored if no + * SCTP used. + */ + memcpy(labelbuffer, DTLS1_SCTP_AUTH_LABEL, + sizeof(DTLS1_SCTP_AUTH_LABEL)); + + if (SSL_export_keying_material(s, sctpauthkey, + sizeof(sctpauthkey), labelbuffer, + sizeof(labelbuffer), NULL, 0, + 0) <= 0) { + ossl_statem_set_error(s); + return WORK_ERROR; + } + + BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY, + sizeof(sctpauthkey), sctpauthkey); + } +#endif + break; + + case TLS_ST_SW_CHANGE: +#ifndef OPENSSL_NO_SCTP + if (SSL_IS_DTLS(s) && !s->hit) { + /* + * Change to new shared key of SCTP-Auth, will be ignored if + * no SCTP used. + */ + BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY, + 0, NULL); + } +#endif + if (!s->method->ssl3_enc->change_cipher_state(s, + SSL3_CHANGE_CIPHER_SERVER_WRITE)) + { + ossl_statem_set_error(s); + return WORK_ERROR; + } + + if (SSL_IS_DTLS(s)) + dtls1_reset_seq_numbers(s, SSL3_CC_WRITE); + break; + + case TLS_ST_SW_SRVR_DONE: + if (statem_flush(s) != 1) + return WORK_MORE_A; + break; + + case TLS_ST_SW_FINISHED: + if (statem_flush(s) != 1) + return WORK_MORE_A; +#ifndef OPENSSL_NO_SCTP + if (SSL_IS_DTLS(s) && s->hit) { + /* + * Change to new shared key of SCTP-Auth, will be ignored if + * no SCTP used. + */ + BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY, + 0, NULL); + } +#endif + break; + + default: + /* No post work to be done */ + break; + } + + return WORK_FINISHED_CONTINUE; +} + +/* + * Construct a message to be sent from the server to the client. + * + * Valid return values are: + * 1: Success + * 0: Error + */ +int ossl_statem_server_construct_message(SSL *s) +{ + OSSL_STATEM *st = &s->statem; + + switch (st->hand_state) { + case DTLS_ST_SW_HELLO_VERIFY_REQUEST: + return dtls_construct_hello_verify_request(s); + + case TLS_ST_SW_HELLO_REQ: + return tls_construct_hello_request(s); + + case TLS_ST_SW_SRVR_HELLO: + return tls_construct_server_hello(s); + + case TLS_ST_SW_CERT: + return tls_construct_server_certificate(s); + + case TLS_ST_SW_KEY_EXCH: + return tls_construct_server_key_exchange(s); + + case TLS_ST_SW_CERT_REQ: + return tls_construct_certificate_request(s); + + case TLS_ST_SW_SRVR_DONE: + return tls_construct_server_done(s); + + case TLS_ST_SW_SESSION_TICKET: + return tls_construct_new_session_ticket(s); + + case TLS_ST_SW_CERT_STATUS: + return tls_construct_cert_status(s); + + case TLS_ST_SW_CHANGE: + if (SSL_IS_DTLS(s)) + return dtls_construct_change_cipher_spec(s); + else + return tls_construct_change_cipher_spec(s); + + case TLS_ST_SW_FINISHED: + return tls_construct_finished(s, + s->method-> + ssl3_enc->server_finished_label, + s->method-> + ssl3_enc->server_finished_label_len); + + default: + /* Shouldn't happen */ + break; + } + + return 0; +} + +/* + * Maximum size (excluding the Handshake header) of a ClientHello message, + * calculated as follows: + * + * 2 + # client_version + * 32 + # only valid length for random + * 1 + # length of session_id + * 32 + # maximum size for session_id + * 2 + # length of cipher suites + * 2^16-2 + # maximum length of cipher suites array + * 1 + # length of compression_methods + * 2^8-1 + # maximum length of compression methods + * 2 + # length of extensions + * 2^16-1 # maximum length of extensions + */ +#define CLIENT_HELLO_MAX_LENGTH 131396 + +#define CLIENT_KEY_EXCH_MAX_LENGTH 2048 +#define NEXT_PROTO_MAX_LENGTH 514 + +/* + * Returns the maximum allowed length for the current message that we are + * reading. Excludes the message header. + */ +unsigned long ossl_statem_server_max_message_size(SSL *s) +{ + OSSL_STATEM *st = &s->statem; + + switch (st->hand_state) { + case TLS_ST_SR_CLNT_HELLO: + return CLIENT_HELLO_MAX_LENGTH; + + case TLS_ST_SR_CERT: + return s->max_cert_list; + + case TLS_ST_SR_KEY_EXCH: + return CLIENT_KEY_EXCH_MAX_LENGTH; + + case TLS_ST_SR_CERT_VRFY: + return SSL3_RT_MAX_PLAIN_LENGTH; + +#ifndef OPENSSL_NO_NEXTPROTONEG + case TLS_ST_SR_NEXT_PROTO: + return NEXT_PROTO_MAX_LENGTH; +#endif + + case TLS_ST_SR_CHANGE: + return CCS_MAX_LENGTH; + + case TLS_ST_SR_FINISHED: + return FINISHED_MAX_LENGTH; + + default: + /* Shouldn't happen */ + break; + } + + return 0; +} + +/* + * Process a message that the server has received from the client. + */ +MSG_PROCESS_RETURN ossl_statem_server_process_message(SSL *s, PACKET *pkt) +{ + OSSL_STATEM *st = &s->statem; + + switch (st->hand_state) { + case TLS_ST_SR_CLNT_HELLO: + return tls_process_client_hello(s, pkt); + + case TLS_ST_SR_CERT: + return tls_process_client_certificate(s, pkt); + + case TLS_ST_SR_KEY_EXCH: + return tls_process_client_key_exchange(s, pkt); + + case TLS_ST_SR_CERT_VRFY: + return tls_process_cert_verify(s, pkt); + +#ifndef OPENSSL_NO_NEXTPROTONEG + case TLS_ST_SR_NEXT_PROTO: + return tls_process_next_proto(s, pkt); +#endif + + case TLS_ST_SR_CHANGE: + return tls_process_change_cipher_spec(s, pkt); + + case TLS_ST_SR_FINISHED: + return tls_process_finished(s, pkt); + + default: + /* Shouldn't happen */ + break; + } + + return MSG_PROCESS_ERROR; +} + +/* + * Perform any further processing required following the receipt of a message + * from the client + */ +WORK_STATE ossl_statem_server_post_process_message(SSL *s, WORK_STATE wst) +{ + OSSL_STATEM *st = &s->statem; + + switch (st->hand_state) { + case TLS_ST_SR_CLNT_HELLO: + return tls_post_process_client_hello(s, wst); + + case TLS_ST_SR_KEY_EXCH: + return tls_post_process_client_key_exchange(s, wst); + + default: + break; + } + + /* Shouldn't happen */ + return WORK_ERROR; +} + +#ifndef OPENSSL_NO_SRP +static int ssl_check_srp_ext_ClientHello(SSL *s, int *al) +{ + int ret = SSL_ERROR_NONE; + + *al = SSL_AD_UNRECOGNIZED_NAME; + + if ((s->s3->tmp.new_cipher->algorithm_mkey & SSL_kSRP) && + (s->srp_ctx.TLS_ext_srp_username_callback != NULL)) { + if (s->srp_ctx.login == NULL) { + /* + * RFC 5054 says SHOULD reject, we do so if There is no srp + * login name + */ + ret = SSL3_AL_FATAL; + *al = SSL_AD_UNKNOWN_PSK_IDENTITY; + } else { + ret = SSL_srp_server_param_with_username(s, al); + } + } + return ret; +} +#endif + +int tls_construct_hello_request(SSL *s) +{ + if (!ssl_set_handshake_header(s, SSL3_MT_HELLO_REQUEST, 0)) { + SSLerr(SSL_F_TLS_CONSTRUCT_HELLO_REQUEST, ERR_R_INTERNAL_ERROR); + ossl_statem_set_error(s); + return 0; + } + + return 1; +} + +unsigned int dtls_raw_hello_verify_request(unsigned char *buf, + unsigned char *cookie, + unsigned char cookie_len) +{ + unsigned int msg_len; + unsigned char *p; + + p = buf; + /* Always use DTLS 1.0 version: see RFC 6347 */ + *(p++) = DTLS1_VERSION >> 8; + *(p++) = DTLS1_VERSION & 0xFF; + + *(p++) = (unsigned char)cookie_len; + memcpy(p, cookie, cookie_len); + p += cookie_len; + msg_len = p - buf; + + return msg_len; +} + +int dtls_construct_hello_verify_request(SSL *s) +{ + unsigned int len; + unsigned char *buf; + + buf = (unsigned char *)s->init_buf->data; + + if (s->ctx->app_gen_cookie_cb == NULL || + s->ctx->app_gen_cookie_cb(s, s->d1->cookie, + &(s->d1->cookie_len)) == 0 || + s->d1->cookie_len > 255) { + SSLerr(SSL_F_DTLS_CONSTRUCT_HELLO_VERIFY_REQUEST, + SSL_R_COOKIE_GEN_CALLBACK_FAILURE); + ossl_statem_set_error(s); + return 0; + } + + len = dtls_raw_hello_verify_request(&buf[DTLS1_HM_HEADER_LENGTH], + s->d1->cookie, s->d1->cookie_len); + + dtls1_set_message_header(s, DTLS1_MT_HELLO_VERIFY_REQUEST, len, 0, len); + len += DTLS1_HM_HEADER_LENGTH; + + /* number of bytes to write */ + s->init_num = len; + s->init_off = 0; + + return 1; +} + +MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt) +{ + int i, al = SSL_AD_INTERNAL_ERROR; + unsigned int j, complen = 0; + unsigned long id; + const SSL_CIPHER *c; +#ifndef OPENSSL_NO_COMP + SSL_COMP *comp = NULL; +#endif + STACK_OF(SSL_CIPHER) *ciphers = NULL; + int protverr; + /* |cookie| will only be initialized for DTLS. */ + PACKET session_id, cipher_suites, compression, extensions, cookie; + int is_v2_record; + static const unsigned char null_compression = 0; + + is_v2_record = RECORD_LAYER_is_sslv2_record(&s->rlayer); + + PACKET_null_init(&cookie); + /* First lets get s->client_version set correctly */ + if (is_v2_record) { + unsigned int version; + unsigned int mt; + /*- + * An SSLv3/TLSv1 backwards-compatible CLIENT-HELLO in an SSLv2 + * header is sent directly on the wire, not wrapped as a TLS + * record. Our record layer just processes the message length and passes + * the rest right through. Its format is: + * Byte Content + * 0-1 msg_length - decoded by the record layer + * 2 msg_type - s->init_msg points here + * 3-4 version + * 5-6 cipher_spec_length + * 7-8 session_id_length + * 9-10 challenge_length + * ... ... + */ + + if (!PACKET_get_1(pkt, &mt) + || mt != SSL2_MT_CLIENT_HELLO) { + /* + * Should never happen. We should have tested this in the record + * layer in order to have determined that this is a SSLv2 record + * in the first place + */ + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, ERR_R_INTERNAL_ERROR); + goto err; + } + + if (!PACKET_get_net_2(pkt, &version)) { + /* No protocol version supplied! */ + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_UNKNOWN_PROTOCOL); + goto err; + } + if (version == 0x0002) { + /* This is real SSLv2. We don't support it. */ + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_UNKNOWN_PROTOCOL); + goto err; + } else if ((version & 0xff00) == (SSL3_VERSION_MAJOR << 8)) { + /* SSLv3/TLS */ + s->client_version = version; + } else { + /* No idea what protocol this is */ + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_UNKNOWN_PROTOCOL); + goto err; + } + } else { + /* + * use version from inside client hello, not from record header (may + * differ: see RFC 2246, Appendix E, second paragraph) + */ + if (!PACKET_get_net_2(pkt, (unsigned int *)&s->client_version)) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_LENGTH_TOO_SHORT); + goto f_err; + } + } + + /* + * Do SSL/TLS version negotiation if applicable. For DTLS we just check + * versions are potentially compatible. Version negotiation comes later. + */ + if (!SSL_IS_DTLS(s)) { + protverr = ssl_choose_server_version(s); + } else if (s->method->version != DTLS_ANY_VERSION && + DTLS_VERSION_LT(s->client_version, s->version)) { + protverr = SSL_R_VERSION_TOO_LOW; + } else { + protverr = 0; + } + + if (protverr) { + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, protverr); + if ((!s->enc_write_ctx && !s->write_hash)) { + /* + * similar to ssl3_get_record, send alert using remote version + * number + */ + s->version = s->client_version; + } + al = SSL_AD_PROTOCOL_VERSION; + goto f_err; + } + + /* Parse the message and load client random. */ + if (is_v2_record) { + /* + * Handle an SSLv2 backwards compatible ClientHello + * Note, this is only for SSLv3+ using the backward compatible format. + * Real SSLv2 is not supported, and is rejected above. + */ + unsigned int cipher_len, session_id_len, challenge_len; + PACKET challenge; + + if (!PACKET_get_net_2(pkt, &cipher_len) + || !PACKET_get_net_2(pkt, &session_id_len) + || !PACKET_get_net_2(pkt, &challenge_len)) { + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, + SSL_R_RECORD_LENGTH_MISMATCH); + al = SSL_AD_DECODE_ERROR; + goto f_err; + } + + if (session_id_len > SSL_MAX_SSL_SESSION_ID_LENGTH) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_LENGTH_MISMATCH); + goto f_err; + } + + if (!PACKET_get_sub_packet(pkt, &cipher_suites, cipher_len) + || !PACKET_get_sub_packet(pkt, &session_id, session_id_len) + || !PACKET_get_sub_packet(pkt, &challenge, challenge_len) + /* No extensions. */ + || PACKET_remaining(pkt) != 0) { + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, + SSL_R_RECORD_LENGTH_MISMATCH); + al = SSL_AD_DECODE_ERROR; + goto f_err; + } + + /* Load the client random and compression list. */ + challenge_len = challenge_len > SSL3_RANDOM_SIZE ? SSL3_RANDOM_SIZE : + challenge_len; + memset(s->s3->client_random, 0, SSL3_RANDOM_SIZE); + if (!PACKET_copy_bytes(&challenge, + s->s3->client_random + SSL3_RANDOM_SIZE - + challenge_len, challenge_len) + /* Advertise only null compression. */ + || !PACKET_buf_init(&compression, &null_compression, 1)) { + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, ERR_R_INTERNAL_ERROR); + al = SSL_AD_INTERNAL_ERROR; + goto f_err; + } + + PACKET_null_init(&extensions); + } else { + /* Regular ClientHello. */ + if (!PACKET_copy_bytes(pkt, s->s3->client_random, SSL3_RANDOM_SIZE) + || !PACKET_get_length_prefixed_1(pkt, &session_id)) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_LENGTH_MISMATCH); + goto f_err; + } + + if (PACKET_remaining(&session_id) > SSL_MAX_SSL_SESSION_ID_LENGTH) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_LENGTH_MISMATCH); + goto f_err; + } + + if (SSL_IS_DTLS(s)) { + if (!PACKET_get_length_prefixed_1(pkt, &cookie)) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_LENGTH_MISMATCH); + goto f_err; + } + /* + * If we require cookies and this ClientHello doesn't contain one, + * just return since we do not want to allocate any memory yet. + * So check cookie length... + */ + if (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE) { + if (PACKET_remaining(&cookie) == 0) + return 1; + } + } + + if (!PACKET_get_length_prefixed_2(pkt, &cipher_suites) + || !PACKET_get_length_prefixed_1(pkt, &compression)) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_LENGTH_MISMATCH); + goto f_err; + } + /* Could be empty. */ + extensions = *pkt; + } + + if (SSL_IS_DTLS(s)) { + /* Empty cookie was already handled above by returning early. */ + if (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE) { + if (s->ctx->app_verify_cookie_cb != NULL) { + if (s->ctx->app_verify_cookie_cb(s, PACKET_data(&cookie), + PACKET_remaining(&cookie)) == + 0) { + al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, + SSL_R_COOKIE_MISMATCH); + goto f_err; + /* else cookie verification succeeded */ + } + /* default verification */ + } else if (!PACKET_equal(&cookie, s->d1->cookie, s->d1->cookie_len)) { + al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_COOKIE_MISMATCH); + goto f_err; + } + s->d1->cookie_verified = 1; + } + if (s->method->version == DTLS_ANY_VERSION) { + protverr = ssl_choose_server_version(s); + if (protverr != 0) { + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, protverr); + s->version = s->client_version; + al = SSL_AD_PROTOCOL_VERSION; + goto f_err; + } + } + } + + s->hit = 0; + + /* + * We don't allow resumption in a backwards compatible ClientHello. + * TODO(openssl-team): in TLS1.1+, session_id MUST be empty. + * + * Versions before 0.9.7 always allow clients to resume sessions in + * renegotiation. 0.9.7 and later allow this by default, but optionally + * ignore resumption requests with flag + * SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION (it's a new flag rather + * than a change to default behavior so that applications relying on + * this for security won't even compile against older library versions). + * 1.0.1 and later also have a function SSL_renegotiate_abbreviated() to + * request renegotiation but not a new session (s->new_session remains + * unset): for servers, this essentially just means that the + * SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION setting will be + * ignored. + */ + if (is_v2_record || + (s->new_session && + (s->options & SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION))) { + if (!ssl_get_new_session(s, 1)) + goto err; + } else { + i = ssl_get_prev_session(s, &extensions, &session_id); + /* + * Only resume if the session's version matches the negotiated + * version. + * RFC 5246 does not provide much useful advice on resumption + * with a different protocol version. It doesn't forbid it but + * the sanity of such behaviour would be questionable. + * In practice, clients do not accept a version mismatch and + * will abort the handshake with an error. + */ + if (i == 1 && s->version == s->session->ssl_version) { + /* previous session */ + s->hit = 1; + } else if (i == -1) { + goto err; + } else { + /* i == 0 */ + if (!ssl_get_new_session(s, 1)) + goto err; + } + } + + if (ssl_bytes_to_cipher_list(s, &cipher_suites, &(ciphers), + is_v2_record, &al) == NULL) { + goto f_err; + } + + /* If it is a hit, check that the cipher is in the list */ + if (s->hit) { + j = 0; + id = s->session->cipher->id; + +#ifdef CIPHER_DEBUG + fprintf(stderr, "client sent %d ciphers\n", sk_SSL_CIPHER_num(ciphers)); +#endif + for (i = 0; i < sk_SSL_CIPHER_num(ciphers); i++) { + c = sk_SSL_CIPHER_value(ciphers, i); +#ifdef CIPHER_DEBUG + fprintf(stderr, "client [%2d of %2d]:%s\n", + i, sk_SSL_CIPHER_num(ciphers), SSL_CIPHER_get_name(c)); +#endif + if (c->id == id) { + j = 1; + break; + } + } + if (j == 0) { + /* + * we need to have the cipher in the cipher list if we are asked + * to reuse it + */ + al = SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, + SSL_R_REQUIRED_CIPHER_MISSING); + goto f_err; + } + } + + complen = PACKET_remaining(&compression); + for (j = 0; j < complen; j++) { + if (PACKET_data(&compression)[j] == 0) + break; + } + + if (j >= complen) { + /* no compress */ + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_NO_COMPRESSION_SPECIFIED); + goto f_err; + } + + /* TLS extensions */ + if (s->version >= SSL3_VERSION) { + if (!ssl_parse_clienthello_tlsext(s, &extensions)) { + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_PARSE_TLSEXT); + goto err; + } + } + + /* + * Check if we want to use external pre-shared secret for this handshake + * for not reused session only. We need to generate server_random before + * calling tls_session_secret_cb in order to allow SessionTicket + * processing to use it in key derivation. + */ + { + unsigned char *pos; + pos = s->s3->server_random; + if (ssl_fill_hello_random(s, 1, pos, SSL3_RANDOM_SIZE) <= 0) { + goto f_err; + } + } + + if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb) { + const SSL_CIPHER *pref_cipher = NULL; + + s->session->master_key_length = sizeof(s->session->master_key); + if (s->tls_session_secret_cb(s, s->session->master_key, + &s->session->master_key_length, ciphers, + &pref_cipher, + s->tls_session_secret_cb_arg)) { + s->hit = 1; + s->session->ciphers = ciphers; + s->session->verify_result = X509_V_OK; + + ciphers = NULL; + + /* check if some cipher was preferred by call back */ + pref_cipher = + pref_cipher ? pref_cipher : ssl3_choose_cipher(s, + s-> + session->ciphers, + SSL_get_ciphers + (s)); + if (pref_cipher == NULL) { + al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_NO_SHARED_CIPHER); + goto f_err; + } + + s->session->cipher = pref_cipher; + sk_SSL_CIPHER_free(s->cipher_list); + s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers); + sk_SSL_CIPHER_free(s->cipher_list_by_id); + s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers); + } + } + + /* + * Worst case, we will use the NULL compression, but if we have other + * options, we will now look for them. We have complen-1 compression + * algorithms from the client, starting at q. + */ + s->s3->tmp.new_compression = NULL; +#ifndef OPENSSL_NO_COMP + /* This only happens if we have a cache hit */ + if (s->session->compress_meth != 0) { + int m, comp_id = s->session->compress_meth; + unsigned int k; + /* Perform sanity checks on resumed compression algorithm */ + /* Can't disable compression */ + if (!ssl_allow_compression(s)) { + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, + SSL_R_INCONSISTENT_COMPRESSION); + goto f_err; + } + /* Look for resumed compression method */ + for (m = 0; m < sk_SSL_COMP_num(s->ctx->comp_methods); m++) { + comp = sk_SSL_COMP_value(s->ctx->comp_methods, m); + if (comp_id == comp->id) { + s->s3->tmp.new_compression = comp; + break; + } + } + if (s->s3->tmp.new_compression == NULL) { + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, + SSL_R_INVALID_COMPRESSION_ALGORITHM); + goto f_err; + } + /* Look for resumed method in compression list */ + for (k = 0; k < complen; k++) { + if (PACKET_data(&compression)[k] == comp_id) + break; + } + if (k >= complen) { + al = SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, + SSL_R_REQUIRED_COMPRESSION_ALGORITHM_MISSING); + goto f_err; + } + } else if (s->hit) + comp = NULL; + else if (ssl_allow_compression(s) && s->ctx->comp_methods) { + /* See if we have a match */ + int m, nn, v, done = 0; + unsigned int o; + + nn = sk_SSL_COMP_num(s->ctx->comp_methods); + for (m = 0; m < nn; m++) { + comp = sk_SSL_COMP_value(s->ctx->comp_methods, m); + v = comp->id; + for (o = 0; o < complen; o++) { + if (v == PACKET_data(&compression)[o]) { + done = 1; + break; + } + } + if (done) + break; + } + if (done) + s->s3->tmp.new_compression = comp; + else + comp = NULL; + } +#else + /* + * If compression is disabled we'd better not try to resume a session + * using compression. + */ + if (s->session->compress_meth != 0) { + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_INCONSISTENT_COMPRESSION); + goto f_err; + } +#endif + + /* + * Given s->session->ciphers and SSL_get_ciphers, we must pick a cipher + */ + + if (!s->hit) { +#ifdef OPENSSL_NO_COMP + s->session->compress_meth = 0; +#else + s->session->compress_meth = (comp == NULL) ? 0 : comp->id; +#endif + sk_SSL_CIPHER_free(s->session->ciphers); + s->session->ciphers = ciphers; + if (ciphers == NULL) { + al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, ERR_R_INTERNAL_ERROR); + goto f_err; + } + ciphers = NULL; + if (!tls1_set_server_sigalgs(s)) { + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_CLIENTHELLO_TLSEXT); + goto err; + } + } + + sk_SSL_CIPHER_free(ciphers); + return MSG_PROCESS_CONTINUE_PROCESSING; + f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + err: + ossl_statem_set_error(s); + + sk_SSL_CIPHER_free(ciphers); + return MSG_PROCESS_ERROR; + +} + +WORK_STATE tls_post_process_client_hello(SSL *s, WORK_STATE wst) +{ + int al = SSL_AD_HANDSHAKE_FAILURE; + const SSL_CIPHER *cipher; + + if (wst == WORK_MORE_A) { + if (!s->hit) { + /* Let cert callback update server certificates if required */ + if (s->cert->cert_cb) { + int rv = s->cert->cert_cb(s, s->cert->cert_cb_arg); + if (rv == 0) { + al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_POST_PROCESS_CLIENT_HELLO, + SSL_R_CERT_CB_ERROR); + goto f_err; + } + if (rv < 0) { + s->rwstate = SSL_X509_LOOKUP; + return WORK_MORE_A; + } + s->rwstate = SSL_NOTHING; + } + cipher = + ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s)); + + if (cipher == NULL) { + SSLerr(SSL_F_TLS_POST_PROCESS_CLIENT_HELLO, + SSL_R_NO_SHARED_CIPHER); + goto f_err; + } + s->s3->tmp.new_cipher = cipher; + /* check whether we should disable session resumption */ + if (s->not_resumable_session_cb != NULL) + s->session->not_resumable = s->not_resumable_session_cb(s, + ((cipher->algorithm_mkey & (SSL_kDHE | SSL_kECDHE)) != 0)); + if (s->session->not_resumable) + /* do not send a session ticket */ + s->tlsext_ticket_expected = 0; + } else { + /* Session-id reuse */ + s->s3->tmp.new_cipher = s->session->cipher; + } + + if (!(s->verify_mode & SSL_VERIFY_PEER)) { + if (!ssl3_digest_cached_records(s, 0)) { + al = SSL_AD_INTERNAL_ERROR; + goto f_err; + } + } + + /*- + * we now have the following setup. + * client_random + * cipher_list - our preferred list of ciphers + * ciphers - the clients preferred list of ciphers + * compression - basically ignored right now + * ssl version is set - sslv3 + * s->session - The ssl session has been setup. + * s->hit - session reuse flag + * s->s3->tmp.new_cipher- the new cipher to use. + */ + + /* Handles TLS extensions that we couldn't check earlier */ + if (s->version >= SSL3_VERSION) { + if (!ssl_check_clienthello_tlsext_late(s, &al)) { + SSLerr(SSL_F_TLS_POST_PROCESS_CLIENT_HELLO, + SSL_R_CLIENTHELLO_TLSEXT); + goto f_err; + } + } + + wst = WORK_MORE_B; + } +#ifndef OPENSSL_NO_SRP + if (wst == WORK_MORE_B) { + int ret; + if ((ret = ssl_check_srp_ext_ClientHello(s, &al)) < 0) { + /* + * callback indicates further work to be done + */ + s->rwstate = SSL_X509_LOOKUP; + return WORK_MORE_B; + } + if (ret != SSL_ERROR_NONE) { + /* + * This is not really an error but the only means to for + * a client to detect whether srp is supported. + */ + if (al != TLS1_AD_UNKNOWN_PSK_IDENTITY) + SSLerr(SSL_F_TLS_POST_PROCESS_CLIENT_HELLO, + SSL_R_CLIENTHELLO_TLSEXT); + else + SSLerr(SSL_F_TLS_POST_PROCESS_CLIENT_HELLO, + SSL_R_PSK_IDENTITY_NOT_FOUND); + goto f_err; + } + } +#endif + s->renegotiate = 2; + + return WORK_FINISHED_STOP; + f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + ossl_statem_set_error(s); + return WORK_ERROR; +} + +int tls_construct_server_hello(SSL *s) +{ + unsigned char *buf; + unsigned char *p, *d; + int i, sl; + int al = 0; + unsigned long l; + + buf = (unsigned char *)s->init_buf->data; + + /* Do the message type and length last */ + d = p = ssl_handshake_start(s); + + *(p++) = s->version >> 8; + *(p++) = s->version & 0xff; + + /* + * Random stuff. Filling of the server_random takes place in + * tls_process_client_hello() + */ + memcpy(p, s->s3->server_random, SSL3_RANDOM_SIZE); + p += SSL3_RANDOM_SIZE; + + /*- + * There are several cases for the session ID to send + * back in the server hello: + * - For session reuse from the session cache, + * we send back the old session ID. + * - If stateless session reuse (using a session ticket) + * is successful, we send back the client's "session ID" + * (which doesn't actually identify the session). + * - If it is a new session, we send back the new + * session ID. + * - However, if we want the new session to be single-use, + * we send back a 0-length session ID. + * s->hit is non-zero in either case of session reuse, + * so the following won't overwrite an ID that we're supposed + * to send back. + */ + if (s->session->not_resumable || + (!(s->ctx->session_cache_mode & SSL_SESS_CACHE_SERVER) + && !s->hit)) + s->session->session_id_length = 0; + + sl = s->session->session_id_length; + if (sl > (int)sizeof(s->session->session_id)) { + SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_HELLO, ERR_R_INTERNAL_ERROR); + ossl_statem_set_error(s); + return 0; + } + *(p++) = sl; + memcpy(p, s->session->session_id, sl); + p += sl; + + /* put the cipher */ + i = ssl3_put_cipher_by_char(s->s3->tmp.new_cipher, p); + p += i; + + /* put the compression method */ +#ifdef OPENSSL_NO_COMP + *(p++) = 0; +#else + if (s->s3->tmp.new_compression == NULL) + *(p++) = 0; + else + *(p++) = s->s3->tmp.new_compression->id; +#endif + + if (ssl_prepare_serverhello_tlsext(s) <= 0) { + SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_HELLO, SSL_R_SERVERHELLO_TLSEXT); + ossl_statem_set_error(s); + return 0; + } + if ((p = + ssl_add_serverhello_tlsext(s, p, buf + SSL3_RT_MAX_PLAIN_LENGTH, + &al)) == NULL) { + ssl3_send_alert(s, SSL3_AL_FATAL, al); + SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_HELLO, ERR_R_INTERNAL_ERROR); + ossl_statem_set_error(s); + return 0; + } + + /* do the header */ + l = (p - d); + if (!ssl_set_handshake_header(s, SSL3_MT_SERVER_HELLO, l)) { + SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_HELLO, ERR_R_INTERNAL_ERROR); + ossl_statem_set_error(s); + return 0; + } + + return 1; +} + +int tls_construct_server_done(SSL *s) +{ + if (!ssl_set_handshake_header(s, SSL3_MT_SERVER_DONE, 0)) { + SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_DONE, ERR_R_INTERNAL_ERROR); + ossl_statem_set_error(s); + return 0; + } + + if (!s->s3->tmp.cert_request) { + if (!ssl3_digest_cached_records(s, 0)) { + ossl_statem_set_error(s); + } + } + + return 1; +} + +int tls_construct_server_key_exchange(SSL *s) +{ +#ifndef OPENSSL_NO_DH + EVP_PKEY *pkdh = NULL; + int j; +#endif +#ifndef OPENSSL_NO_EC + unsigned char *encodedPoint = NULL; + int encodedlen = 0; + int curve_id = 0; +#endif + EVP_PKEY *pkey; + const EVP_MD *md = NULL; + unsigned char *p, *d; + int al, i; + unsigned long type; + int n; + const BIGNUM *r[4]; + int nr[4], kn; + BUF_MEM *buf; + EVP_MD_CTX *md_ctx = EVP_MD_CTX_new(); + + if (md_ctx == NULL) { + SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE); + al = SSL_AD_INTERNAL_ERROR; + goto f_err; + } + + type = s->s3->tmp.new_cipher->algorithm_mkey; + + buf = s->init_buf; + + r[0] = r[1] = r[2] = r[3] = NULL; + n = 0; +#ifndef OPENSSL_NO_PSK + if (type & SSL_PSK) { + /* + * reserve size for record length and PSK identity hint + */ + n += 2; + if (s->cert->psk_identity_hint) + n += strlen(s->cert->psk_identity_hint); + } + /* Plain PSK or RSAPSK nothing to do */ + if (type & (SSL_kPSK | SSL_kRSAPSK)) { + } else +#endif /* !OPENSSL_NO_PSK */ +#ifndef OPENSSL_NO_DH + if (type & (SSL_kDHE | SSL_kDHEPSK)) { + CERT *cert = s->cert; + + EVP_PKEY *pkdhp = NULL; + DH *dh; + + if (s->cert->dh_tmp_auto) { + DH *dhp = ssl_get_auto_dh(s); + pkdh = EVP_PKEY_new(); + if (pkdh == NULL || dhp == NULL) { + DH_free(dhp); + al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); + goto f_err; + } + EVP_PKEY_assign_DH(pkdh, dhp); + pkdhp = pkdh; + } else { + pkdhp = cert->dh_tmp; + } + if ((pkdhp == NULL) && (s->cert->dh_tmp_cb != NULL)) { + DH *dhp = s->cert->dh_tmp_cb(s, 0, 1024); + pkdh = ssl_dh_to_pkey(dhp); + if (pkdh == NULL) { + al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); + goto f_err; + } + pkdhp = pkdh; + } + if (pkdhp == NULL) { + al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, + SSL_R_MISSING_TMP_DH_KEY); + goto f_err; + } + if (!ssl_security(s, SSL_SECOP_TMP_DH, + EVP_PKEY_security_bits(pkdhp), 0, pkdhp)) { + al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, + SSL_R_DH_KEY_TOO_SMALL); + goto f_err; + } + if (s->s3->tmp.pkey != NULL) { + SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); + goto err; + } + + s->s3->tmp.pkey = ssl_generate_pkey(pkdhp); + + if (s->s3->tmp.pkey == NULL) { + SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_R_EVP_LIB); + goto err; + } + + dh = EVP_PKEY_get0_DH(s->s3->tmp.pkey); + + EVP_PKEY_free(pkdh); + pkdh = NULL; + + DH_get0_pqg(dh, &r[0], NULL, &r[1]); + DH_get0_key(dh, &r[2], NULL); + } else +#endif +#ifndef OPENSSL_NO_EC + if (type & (SSL_kECDHE | SSL_kECDHEPSK)) { + int nid; + + if (s->s3->tmp.pkey != NULL) { + SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); + goto err; + } + + /* Get NID of appropriate shared curve */ + nid = tls1_shared_curve(s, -2); + curve_id = tls1_ec_nid2curve_id(nid); + if (curve_id == 0) { + SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, + SSL_R_UNSUPPORTED_ELLIPTIC_CURVE); + goto err; + } + s->s3->tmp.pkey = ssl_generate_pkey_curve(curve_id); + /* Generate a new key for this curve */ + if (s->s3->tmp.pkey == NULL) { + al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_R_EVP_LIB); + goto f_err; + } + + /* Encode the public key. */ + encodedlen = EVP_PKEY_get1_tls_encodedpoint(s->s3->tmp.pkey, + &encodedPoint); + if (encodedlen == 0) { + SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_R_EC_LIB); + goto err; + } + + /* + * We only support named (not generic) curves in ECDH ephemeral key + * exchanges. In this situation, we need four additional bytes to + * encode the entire ServerECDHParams structure. + */ + n += 4 + encodedlen; + + /* + * We'll generate the serverKeyExchange message explicitly so we + * can set these to NULLs + */ + r[0] = NULL; + r[1] = NULL; + r[2] = NULL; + r[3] = NULL; + } else +#endif /* !OPENSSL_NO_EC */ +#ifndef OPENSSL_NO_SRP + if (type & SSL_kSRP) { + if ((s->srp_ctx.N == NULL) || + (s->srp_ctx.g == NULL) || + (s->srp_ctx.s == NULL) || (s->srp_ctx.B == NULL)) { + SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, + SSL_R_MISSING_SRP_PARAM); + goto err; + } + r[0] = s->srp_ctx.N; + r[1] = s->srp_ctx.g; + r[2] = s->srp_ctx.s; + r[3] = s->srp_ctx.B; + } else +#endif + { + al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, + SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE); + goto f_err; + } + for (i = 0; i < 4 && r[i] != NULL; i++) { + nr[i] = BN_num_bytes(r[i]); +#ifndef OPENSSL_NO_SRP + if ((i == 2) && (type & SSL_kSRP)) + n += 1 + nr[i]; + else +#endif +#ifndef OPENSSL_NO_DH + /*- + * for interoperability with some versions of the Microsoft TLS + * stack, we need to zero pad the DHE pub key to the same length + * as the prime, so use the length of the prime here + */ + if ((i == 2) && (type & (SSL_kDHE | SSL_kDHEPSK))) + n += 2 + nr[0]; + else +#endif + n += 2 + nr[i]; + } + + if (!(s->s3->tmp.new_cipher->algorithm_auth & (SSL_aNULL | SSL_aSRP)) + && !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_PSK)) { + if ((pkey = ssl_get_sign_pkey(s, s->s3->tmp.new_cipher, &md)) + == NULL) { + al = SSL_AD_DECODE_ERROR; + goto f_err; + } + kn = EVP_PKEY_size(pkey); + /* Allow space for signature algorithm */ + if (SSL_USE_SIGALGS(s)) + kn += 2; + /* Allow space for signature length */ + kn += 2; + } else { + pkey = NULL; + kn = 0; + } + + if (!BUF_MEM_grow_clean(buf, n + SSL_HM_HEADER_LENGTH(s) + kn)) { + SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_LIB_BUF); + goto err; + } + d = p = ssl_handshake_start(s); + +#ifndef OPENSSL_NO_PSK + if (type & SSL_PSK) { + /* copy PSK identity hint */ + if (s->cert->psk_identity_hint) { + size_t len = strlen(s->cert->psk_identity_hint); + if (len > PSK_MAX_IDENTITY_LEN) { + /* + * Should not happen - we already checked this when we set + * the identity hint + */ + SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); + goto err; + } + s2n(len, p); + memcpy(p, s->cert->psk_identity_hint, len); + p += len; + } else { + s2n(0, p); + } + } +#endif + + for (i = 0; i < 4 && r[i] != NULL; i++) { +#ifndef OPENSSL_NO_SRP + if ((i == 2) && (type & SSL_kSRP)) { + *p = nr[i]; + p++; + } else +#endif +#ifndef OPENSSL_NO_DH + /*- + * for interoperability with some versions of the Microsoft TLS + * stack, we need to zero pad the DHE pub key to the same length + * as the prime + */ + if ((i == 2) && (type & (SSL_kDHE | SSL_kDHEPSK))) { + s2n(nr[0], p); + for (j = 0; j < (nr[0] - nr[2]); ++j) { + *p = 0; + ++p; + } + } else +#endif + s2n(nr[i], p); + BN_bn2bin(r[i], p); + p += nr[i]; + } + +#ifndef OPENSSL_NO_EC + if (type & (SSL_kECDHE | SSL_kECDHEPSK)) { + /* + * XXX: For now, we only support named (not generic) curves. In + * this situation, the serverKeyExchange message has: [1 byte + * CurveType], [2 byte CurveName] [1 byte length of encoded + * point], followed by the actual encoded point itself + */ + *p = NAMED_CURVE_TYPE; + p += 1; + *p = 0; + p += 1; + *p = curve_id; + p += 1; + *p = encodedlen; + p += 1; + memcpy(p, encodedPoint, encodedlen); + OPENSSL_free(encodedPoint); + encodedPoint = NULL; + p += encodedlen; + } +#endif + + /* not anonymous */ + if (pkey != NULL) { + /* + * n is the length of the params, they start at &(d[4]) and p + * points to the space at the end. + */ + if (md) { + /* send signature algorithm */ + if (SSL_USE_SIGALGS(s)) { + if (!tls12_get_sigandhash(p, pkey, md)) { + /* Should never happen */ + al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); + goto f_err; + } + p += 2; + } +#ifdef SSL_DEBUG + fprintf(stderr, "Using hash %s\n", EVP_MD_name(md)); +#endif + if (EVP_SignInit_ex(md_ctx, md, NULL) <= 0 + || EVP_SignUpdate(md_ctx, &(s->s3->client_random[0]), + SSL3_RANDOM_SIZE) <= 0 + || EVP_SignUpdate(md_ctx, &(s->s3->server_random[0]), + SSL3_RANDOM_SIZE) <= 0 + || EVP_SignUpdate(md_ctx, d, n) <= 0 + || EVP_SignFinal(md_ctx, &(p[2]), + (unsigned int *)&i, pkey) <= 0) { + SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_LIB_EVP); + al = SSL_AD_INTERNAL_ERROR; + goto f_err; + } + s2n(i, p); + n += i + 2; + if (SSL_USE_SIGALGS(s)) + n += 2; + } else { + /* Is this error check actually needed? */ + al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, + SSL_R_UNKNOWN_PKEY_TYPE); + goto f_err; + } + } + + if (!ssl_set_handshake_header(s, SSL3_MT_SERVER_KEY_EXCHANGE, n)) { + al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR); + goto f_err; + } + + EVP_MD_CTX_free(md_ctx); + return 1; + f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + err: +#ifndef OPENSSL_NO_DH + EVP_PKEY_free(pkdh); +#endif +#ifndef OPENSSL_NO_EC + OPENSSL_free(encodedPoint); +#endif + EVP_MD_CTX_free(md_ctx); + ossl_statem_set_error(s); + return 0; +} + +int tls_construct_certificate_request(SSL *s) +{ + unsigned char *p, *d; + int i, j, nl, off, n; + STACK_OF(X509_NAME) *sk = NULL; + X509_NAME *name; + BUF_MEM *buf; + + buf = s->init_buf; + + d = p = ssl_handshake_start(s); + + /* get the list of acceptable cert types */ + p++; + n = ssl3_get_req_cert_type(s, p); + d[0] = n; + p += n; + n++; + + if (SSL_USE_SIGALGS(s)) { + const unsigned char *psigs; + unsigned char *etmp = p; + nl = tls12_get_psigalgs(s, 1, &psigs); + /* Skip over length for now */ + p += 2; + nl = tls12_copy_sigalgs(s, p, psigs, nl); + /* Now fill in length */ + s2n(nl, etmp); + p += nl; + n += nl + 2; + } + + off = n; + p += 2; + n += 2; + + sk = SSL_get_client_CA_list(s); + nl = 0; + if (sk != NULL) { + for (i = 0; i < sk_X509_NAME_num(sk); i++) { + name = sk_X509_NAME_value(sk, i); + j = i2d_X509_NAME(name, NULL); + if (!BUF_MEM_grow_clean(buf, SSL_HM_HEADER_LENGTH(s) + n + j + 2)) { + SSLerr(SSL_F_TLS_CONSTRUCT_CERTIFICATE_REQUEST, ERR_R_BUF_LIB); + goto err; + } + p = ssl_handshake_start(s) + n; + s2n(j, p); + i2d_X509_NAME(name, &p); + n += 2 + j; + nl += 2 + j; + } + } + /* else no CA names */ + p = ssl_handshake_start(s) + off; + s2n(nl, p); + + if (!ssl_set_handshake_header(s, SSL3_MT_CERTIFICATE_REQUEST, n)) { + SSLerr(SSL_F_TLS_CONSTRUCT_CERTIFICATE_REQUEST, ERR_R_INTERNAL_ERROR); + goto err; + } + + s->s3->tmp.cert_request = 1; + + return 1; + err: + ossl_statem_set_error(s); + return 0; +} + +static int tls_process_cke_psk_preamble(SSL *s, PACKET *pkt, int *al) +{ +#ifndef OPENSSL_NO_PSK + unsigned char psk[PSK_MAX_PSK_LEN]; + size_t psklen; + PACKET psk_identity; + + if (!PACKET_get_length_prefixed_2(pkt, &psk_identity)) { + *al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CKE_PSK_PREAMBLE, SSL_R_LENGTH_MISMATCH); + return 0; + } + if (PACKET_remaining(&psk_identity) > PSK_MAX_IDENTITY_LEN) { + *al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CKE_PSK_PREAMBLE, SSL_R_DATA_LENGTH_TOO_LONG); + return 0; + } + if (s->psk_server_callback == NULL) { + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CKE_PSK_PREAMBLE, SSL_R_PSK_NO_SERVER_CB); + return 0; + } + + if (!PACKET_strndup(&psk_identity, &s->session->psk_identity)) { + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CKE_PSK_PREAMBLE, ERR_R_INTERNAL_ERROR); + return 0; + } + + psklen = s->psk_server_callback(s, s->session->psk_identity, + psk, sizeof(psk)); + + if (psklen > PSK_MAX_PSK_LEN) { + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CKE_PSK_PREAMBLE, ERR_R_INTERNAL_ERROR); + return 0; + } else if (psklen == 0) { + /* + * PSK related to the given identity not found + */ + *al = SSL_AD_UNKNOWN_PSK_IDENTITY; + SSLerr(SSL_F_TLS_PROCESS_CKE_PSK_PREAMBLE, + SSL_R_PSK_IDENTITY_NOT_FOUND); + return 0; + } + + OPENSSL_free(s->s3->tmp.psk); + s->s3->tmp.psk = OPENSSL_memdup(psk, psklen); + OPENSSL_cleanse(psk, psklen); + + if (s->s3->tmp.psk == NULL) { + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CKE_PSK_PREAMBLE, ERR_R_MALLOC_FAILURE); + return 0; + } + + s->s3->tmp.psklen = psklen; + + return 1; +#else + /* Should never happen */ + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CKE_PSK_PREAMBLE, ERR_R_INTERNAL_ERROR); + return 0; +#endif +} + +static int tls_process_cke_rsa(SSL *s, PACKET *pkt, int *al) +{ +#ifndef OPENSSL_NO_RSA + unsigned char rand_premaster_secret[SSL_MAX_MASTER_KEY_LENGTH]; + int decrypt_len; + unsigned char decrypt_good, version_good; + size_t j, padding_len; + PACKET enc_premaster; + RSA *rsa = NULL; + unsigned char *rsa_decrypt = NULL; + int ret = 0; + + rsa = EVP_PKEY_get0_RSA(s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey); + if (rsa == NULL) { + *al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_TLS_PROCESS_CKE_RSA, SSL_R_MISSING_RSA_CERTIFICATE); + return 0; + } + + /* SSLv3 and pre-standard DTLS omit the length bytes. */ + if (s->version == SSL3_VERSION || s->version == DTLS1_BAD_VER) { + enc_premaster = *pkt; + } else { + if (!PACKET_get_length_prefixed_2(pkt, &enc_premaster) + || PACKET_remaining(pkt) != 0) { + *al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CKE_RSA, SSL_R_LENGTH_MISMATCH); + return 0; + } + } + + /* + * We want to be sure that the plaintext buffer size makes it safe to + * iterate over the entire size of a premaster secret + * (SSL_MAX_MASTER_KEY_LENGTH). Reject overly short RSA keys because + * their ciphertext cannot accommodate a premaster secret anyway. + */ + if (RSA_size(rsa) < SSL_MAX_MASTER_KEY_LENGTH) { + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CKE_RSA, RSA_R_KEY_SIZE_TOO_SMALL); + return 0; + } + + rsa_decrypt = OPENSSL_malloc(RSA_size(rsa)); + if (rsa_decrypt == NULL) { + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CKE_RSA, ERR_R_MALLOC_FAILURE); + return 0; + } + + /* + * We must not leak whether a decryption failure occurs because of + * Bleichenbacher's attack on PKCS #1 v1.5 RSA padding (see RFC 2246, + * section 7.4.7.1). The code follows that advice of the TLS RFC and + * generates a random premaster secret for the case that the decrypt + * fails. See https://tools.ietf.org/html/rfc5246#section-7.4.7.1 + */ + + if (RAND_bytes(rand_premaster_secret, sizeof(rand_premaster_secret)) <= 0) + goto err; + + /* + * Decrypt with no padding. PKCS#1 padding will be removed as part of + * the timing-sensitive code below. + */ + decrypt_len = RSA_private_decrypt(PACKET_remaining(&enc_premaster), + PACKET_data(&enc_premaster), + rsa_decrypt, rsa, RSA_NO_PADDING); + if (decrypt_len < 0) + goto err; + + /* Check the padding. See RFC 3447, section 7.2.2. */ + + /* + * The smallest padded premaster is 11 bytes of overhead. Small keys + * are publicly invalid, so this may return immediately. This ensures + * PS is at least 8 bytes. + */ + if (decrypt_len < 11 + SSL_MAX_MASTER_KEY_LENGTH) { + *al = SSL_AD_DECRYPT_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CKE_RSA, SSL_R_DECRYPTION_FAILED); + goto err; + } + + padding_len = decrypt_len - SSL_MAX_MASTER_KEY_LENGTH; + decrypt_good = constant_time_eq_int_8(rsa_decrypt[0], 0) & + constant_time_eq_int_8(rsa_decrypt[1], 2); + for (j = 2; j < padding_len - 1; j++) { + decrypt_good &= ~constant_time_is_zero_8(rsa_decrypt[j]); + } + decrypt_good &= constant_time_is_zero_8(rsa_decrypt[padding_len - 1]); + + /* + * If the version in the decrypted pre-master secret is correct then + * version_good will be 0xff, otherwise it'll be zero. The + * Klima-Pokorny-Rosa extension of Bleichenbacher's attack + * (http://eprint.iacr.org/2003/052/) exploits the version number + * check as a "bad version oracle". Thus version checks are done in + * constant time and are treated like any other decryption error. + */ + version_good = + constant_time_eq_8(rsa_decrypt[padding_len], + (unsigned)(s->client_version >> 8)); + version_good &= + constant_time_eq_8(rsa_decrypt[padding_len + 1], + (unsigned)(s->client_version & 0xff)); + + /* + * The premaster secret must contain the same version number as the + * ClientHello to detect version rollback attacks (strangely, the + * protocol does not offer such protection for DH ciphersuites). + * However, buggy clients exist that send the negotiated protocol + * version instead if the server does not support the requested + * protocol version. If SSL_OP_TLS_ROLLBACK_BUG is set, tolerate such + * clients. + */ + if (s->options & SSL_OP_TLS_ROLLBACK_BUG) { + unsigned char workaround_good; + workaround_good = constant_time_eq_8(rsa_decrypt[padding_len], + (unsigned)(s->version >> 8)); + workaround_good &= + constant_time_eq_8(rsa_decrypt[padding_len + 1], + (unsigned)(s->version & 0xff)); + version_good |= workaround_good; + } + + /* + * Both decryption and version must be good for decrypt_good to + * remain non-zero (0xff). + */ + decrypt_good &= version_good; + + /* + * Now copy rand_premaster_secret over from p using + * decrypt_good_mask. If decryption failed, then p does not + * contain valid plaintext, however, a check above guarantees + * it is still sufficiently large to read from. + */ + for (j = 0; j < sizeof(rand_premaster_secret); j++) { + rsa_decrypt[padding_len + j] = + constant_time_select_8(decrypt_good, + rsa_decrypt[padding_len + j], + rand_premaster_secret[j]); + } + + if (!ssl_generate_master_secret(s, rsa_decrypt + padding_len, + sizeof(rand_premaster_secret), 0)) { + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CKE_RSA, ERR_R_INTERNAL_ERROR); + goto err; + } + + ret = 1; + err: + OPENSSL_free(rsa_decrypt); + return ret; +#else + /* Should never happen */ + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CKE_RSA, ERR_R_INTERNAL_ERROR); + return 0; +#endif +} + +static int tls_process_cke_dhe(SSL *s, PACKET *pkt, int *al) +{ +#ifndef OPENSSL_NO_DH + EVP_PKEY *skey = NULL; + DH *cdh; + unsigned int i; + BIGNUM *pub_key; + const unsigned char *data; + EVP_PKEY *ckey = NULL; + int ret = 0; + + if (!PACKET_get_net_2(pkt, &i) || PACKET_remaining(pkt) != i) { + *al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_TLS_PROCESS_CKE_DHE, + SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG); + goto err; + } + skey = s->s3->tmp.pkey; + if (skey == NULL) { + *al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_TLS_PROCESS_CKE_DHE, SSL_R_MISSING_TMP_DH_KEY); + goto err; + } + + if (PACKET_remaining(pkt) == 0L) { + *al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_TLS_PROCESS_CKE_DHE, SSL_R_MISSING_TMP_DH_KEY); + goto err; + } + if (!PACKET_get_bytes(pkt, &data, i)) { + /* We already checked we have enough data */ + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CKE_DHE, ERR_R_INTERNAL_ERROR); + goto err; + } + ckey = EVP_PKEY_new(); + if (ckey == NULL || EVP_PKEY_copy_parameters(ckey, skey) == 0) { + SSLerr(SSL_F_TLS_PROCESS_CKE_DHE, SSL_R_BN_LIB); + goto err; + } + cdh = EVP_PKEY_get0_DH(ckey); + pub_key = BN_bin2bn(data, i, NULL); + + if (pub_key == NULL || !DH_set0_key(cdh, pub_key, NULL)) { + SSLerr(SSL_F_TLS_PROCESS_CKE_DHE, ERR_R_INTERNAL_ERROR); + if (pub_key != NULL) + BN_free(pub_key); + goto err; + } + + if (ssl_derive(s, skey, ckey) == 0) { + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CKE_DHE, ERR_R_INTERNAL_ERROR); + goto err; + } + + ret = 1; + EVP_PKEY_free(s->s3->tmp.pkey); + s->s3->tmp.pkey = NULL; + err: + EVP_PKEY_free(ckey); + return ret; +#else + /* Should never happen */ + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CKE_DHE, ERR_R_INTERNAL_ERROR); + return 0; +#endif +} + +static int tls_process_cke_ecdhe(SSL *s, PACKET *pkt, int *al) +{ +#ifndef OPENSSL_NO_EC + EVP_PKEY *skey = s->s3->tmp.pkey; + EVP_PKEY *ckey = NULL; + int ret = 0; + + if (PACKET_remaining(pkt) == 0L) { + /* We don't support ECDH client auth */ + *al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_TLS_PROCESS_CKE_ECDHE, SSL_R_MISSING_TMP_ECDH_KEY); + goto err; + } else { + unsigned int i; + const unsigned char *data; + + /* + * Get client's public key from encoded point in the + * ClientKeyExchange message. + */ + + /* Get encoded point length */ + if (!PACKET_get_1(pkt, &i) || !PACKET_get_bytes(pkt, &data, i) + || PACKET_remaining(pkt) != 0) { + *al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CKE_ECDHE, SSL_R_LENGTH_MISMATCH); + goto err; + } + ckey = EVP_PKEY_new(); + if (ckey == NULL || EVP_PKEY_copy_parameters(ckey, skey) <= 0) { + SSLerr(SSL_F_TLS_PROCESS_CKE_ECDHE, ERR_R_EVP_LIB); + goto err; + } + if (EVP_PKEY_set1_tls_encodedpoint(ckey, data, i) == 0) { + *al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_TLS_PROCESS_CKE_ECDHE, ERR_R_EC_LIB); + goto err; + } + } + + if (ssl_derive(s, skey, ckey) == 0) { + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CKE_ECDHE, ERR_R_INTERNAL_ERROR); + goto err; + } + + ret = 1; + EVP_PKEY_free(s->s3->tmp.pkey); + s->s3->tmp.pkey = NULL; + err: + EVP_PKEY_free(ckey); + + return ret; +#else + /* Should never happen */ + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CKE_ECDHE, ERR_R_INTERNAL_ERROR); + return 0; +#endif +} + +static int tls_process_cke_srp(SSL *s, PACKET *pkt, int *al) +{ +#ifndef OPENSSL_NO_SRP + unsigned int i; + const unsigned char *data; + + if (!PACKET_get_net_2(pkt, &i) + || !PACKET_get_bytes(pkt, &data, i)) { + *al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CKE_SRP, SSL_R_BAD_SRP_A_LENGTH); + return 0; + } + if ((s->srp_ctx.A = BN_bin2bn(data, i, NULL)) == NULL) { + SSLerr(SSL_F_TLS_PROCESS_CKE_SRP, ERR_R_BN_LIB); + return 0; + } + if (BN_ucmp(s->srp_ctx.A, s->srp_ctx.N) >= 0 || BN_is_zero(s->srp_ctx.A)) { + *al = SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_TLS_PROCESS_CKE_SRP, SSL_R_BAD_SRP_PARAMETERS); + return 0; + } + OPENSSL_free(s->session->srp_username); + s->session->srp_username = OPENSSL_strdup(s->srp_ctx.login); + if (s->session->srp_username == NULL) { + SSLerr(SSL_F_TLS_PROCESS_CKE_SRP, ERR_R_MALLOC_FAILURE); + return 0; + } + + if (!srp_generate_server_master_secret(s)) { + SSLerr(SSL_F_TLS_PROCESS_CKE_SRP, ERR_R_INTERNAL_ERROR); + return 0; + } + + return 1; +#else + /* Should never happen */ + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CKE_SRP, ERR_R_INTERNAL_ERROR); + return 0; +#endif +} + +static int tls_process_cke_gost(SSL *s, PACKET *pkt, int *al) +{ +#ifndef OPENSSL_NO_GOST + EVP_PKEY_CTX *pkey_ctx; + EVP_PKEY *client_pub_pkey = NULL, *pk = NULL; + unsigned char premaster_secret[32]; + const unsigned char *start; + size_t outlen = 32, inlen; + unsigned long alg_a; + int Ttag, Tclass; + long Tlen; + long sess_key_len; + const unsigned char *data; + int ret = 0; + + /* Get our certificate private key */ + alg_a = s->s3->tmp.new_cipher->algorithm_auth; + if (alg_a & SSL_aGOST12) { + /* + * New GOST ciphersuites have SSL_aGOST01 bit too + */ + pk = s->cert->pkeys[SSL_PKEY_GOST12_512].privatekey; + if (pk == NULL) { + pk = s->cert->pkeys[SSL_PKEY_GOST12_256].privatekey; + } + if (pk == NULL) { + pk = s->cert->pkeys[SSL_PKEY_GOST01].privatekey; + } + } else if (alg_a & SSL_aGOST01) { + pk = s->cert->pkeys[SSL_PKEY_GOST01].privatekey; + } + + pkey_ctx = EVP_PKEY_CTX_new(pk, NULL); + if (pkey_ctx == NULL) { + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CKE_GOST, ERR_R_MALLOC_FAILURE); + return 0; + } + if (EVP_PKEY_decrypt_init(pkey_ctx) <= 0) { + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CKE_GOST, ERR_R_INTERNAL_ERROR); + return 0; + } + /* + * If client certificate is present and is of the same type, maybe + * use it for key exchange. Don't mind errors from + * EVP_PKEY_derive_set_peer, because it is completely valid to use a + * client certificate for authorization only. + */ + client_pub_pkey = X509_get0_pubkey(s->session->peer); + if (client_pub_pkey) { + if (EVP_PKEY_derive_set_peer(pkey_ctx, client_pub_pkey) <= 0) + ERR_clear_error(); + } + /* Decrypt session key */ + sess_key_len = PACKET_remaining(pkt); + if (!PACKET_get_bytes(pkt, &data, sess_key_len)) { + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CKE_GOST, ERR_R_INTERNAL_ERROR); + goto err; + } + if (ASN1_get_object((const unsigned char **)&data, &Tlen, &Ttag, + &Tclass, sess_key_len) != V_ASN1_CONSTRUCTED + || Ttag != V_ASN1_SEQUENCE || Tclass != V_ASN1_UNIVERSAL) { + *al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CKE_GOST, SSL_R_DECRYPTION_FAILED); + goto err; + } + start = data; + inlen = Tlen; + if (EVP_PKEY_decrypt + (pkey_ctx, premaster_secret, &outlen, start, inlen) <= 0) { + *al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CKE_GOST, SSL_R_DECRYPTION_FAILED); + goto err; + } + /* Generate master secret */ + if (!ssl_generate_master_secret(s, premaster_secret, + sizeof(premaster_secret), 0)) { + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CKE_GOST, ERR_R_INTERNAL_ERROR); + goto err; + } + /* Check if pubkey from client certificate was used */ + if (EVP_PKEY_CTX_ctrl + (pkey_ctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 2, NULL) > 0) + s->statem.no_cert_verify = 1; + + ret = 1; + err: + EVP_PKEY_CTX_free(pkey_ctx); + return ret; +#else + /* Should never happen */ + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CKE_GOST, ERR_R_INTERNAL_ERROR); + return 0; +#endif +} + +MSG_PROCESS_RETURN tls_process_client_key_exchange(SSL *s, PACKET *pkt) +{ + int al = -1; + unsigned long alg_k; + + alg_k = s->s3->tmp.new_cipher->algorithm_mkey; + + /* For PSK parse and retrieve identity, obtain PSK key */ + if ((alg_k & SSL_PSK) && !tls_process_cke_psk_preamble(s, pkt, &al)) + goto err; + + if (alg_k & SSL_kPSK) { + /* Identity extracted earlier: should be nothing left */ + if (PACKET_remaining(pkt) != 0) { + al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, + SSL_R_LENGTH_MISMATCH); + goto err; + } + /* PSK handled by ssl_generate_master_secret */ + if (!ssl_generate_master_secret(s, NULL, 0, 0)) { + al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR); + goto err; + } + } else if (alg_k & (SSL_kRSA | SSL_kRSAPSK)) { + if (!tls_process_cke_rsa(s, pkt, &al)) + goto err; + } else if (alg_k & (SSL_kDHE | SSL_kDHEPSK)) { + if (!tls_process_cke_dhe(s, pkt, &al)) + goto err; + } else if (alg_k & (SSL_kECDHE | SSL_kECDHEPSK)) { + if (!tls_process_cke_ecdhe(s, pkt, &al)) + goto err; + } else if (alg_k & SSL_kSRP) { + if (!tls_process_cke_srp(s, pkt, &al)) + goto err; + } else if (alg_k & SSL_kGOST) { + if (!tls_process_cke_gost(s, pkt, &al)) + goto err; + } else { + al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, + SSL_R_UNKNOWN_CIPHER_TYPE); + goto err; + } + + return MSG_PROCESS_CONTINUE_PROCESSING; + err: + if (al != -1) + ssl3_send_alert(s, SSL3_AL_FATAL, al); +#ifndef OPENSSL_NO_PSK + OPENSSL_clear_free(s->s3->tmp.psk, s->s3->tmp.psklen); + s->s3->tmp.psk = NULL; +#endif + ossl_statem_set_error(s); + return MSG_PROCESS_ERROR; +} + +WORK_STATE tls_post_process_client_key_exchange(SSL *s, WORK_STATE wst) +{ +#ifndef OPENSSL_NO_SCTP + if (wst == WORK_MORE_A) { + if (SSL_IS_DTLS(s)) { + unsigned char sctpauthkey[64]; + char labelbuffer[sizeof(DTLS1_SCTP_AUTH_LABEL)]; + /* + * Add new shared key for SCTP-Auth, will be ignored if no SCTP + * used. + */ + memcpy(labelbuffer, DTLS1_SCTP_AUTH_LABEL, + sizeof(DTLS1_SCTP_AUTH_LABEL)); + + if (SSL_export_keying_material(s, sctpauthkey, + sizeof(sctpauthkey), labelbuffer, + sizeof(labelbuffer), NULL, 0, + 0) <= 0) { + ossl_statem_set_error(s); + return WORK_ERROR;; + } + + BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY, + sizeof(sctpauthkey), sctpauthkey); + } + } +#endif + + if (s->statem.no_cert_verify || !s->session->peer) { + /* + * No certificate verify or no peer certificate so we no longer need + * the handshake_buffer + */ + if (!ssl3_digest_cached_records(s, 0)) { + ossl_statem_set_error(s); + return WORK_ERROR; + } + return WORK_FINISHED_CONTINUE; + } else { + if (!s->s3->handshake_buffer) { + SSLerr(SSL_F_TLS_POST_PROCESS_CLIENT_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); + ossl_statem_set_error(s); + return WORK_ERROR; + } + /* + * For sigalgs freeze the handshake buffer. If we support + * extms we've done this already so this is a no-op + */ + if (!ssl3_digest_cached_records(s, 1)) { + ossl_statem_set_error(s); + return WORK_ERROR; + } + } + + return WORK_FINISHED_CONTINUE; +} + +MSG_PROCESS_RETURN tls_process_cert_verify(SSL *s, PACKET *pkt) +{ + EVP_PKEY *pkey = NULL; + const unsigned char *sig, *data; +#ifndef OPENSSL_NO_GOST + unsigned char *gost_data = NULL; +#endif + int al, ret = MSG_PROCESS_ERROR; + int type = 0, j; + unsigned int len; + X509 *peer; + const EVP_MD *md = NULL; + long hdatalen = 0; + void *hdata; + + EVP_MD_CTX *mctx = EVP_MD_CTX_new(); + + if (mctx == NULL) { + SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, ERR_R_MALLOC_FAILURE); + al = SSL_AD_INTERNAL_ERROR; + goto f_err; + } + + peer = s->session->peer; + pkey = X509_get0_pubkey(peer); + if (pkey == NULL) { + al = SSL_AD_INTERNAL_ERROR; + goto f_err; + } + + type = X509_certificate_type(peer, pkey); + + if (!(type & EVP_PKT_SIGN)) { + SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, + SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE); + al = SSL_AD_ILLEGAL_PARAMETER; + goto f_err; + } + + if (SSL_USE_SIGALGS(s)) { + int rv; + + if (!PACKET_get_bytes(pkt, &sig, 2)) { + al = SSL_AD_DECODE_ERROR; + goto f_err; + } + rv = tls12_check_peer_sigalg(&md, s, sig, pkey); + if (rv == -1) { + al = SSL_AD_INTERNAL_ERROR; + goto f_err; + } else if (rv == 0) { + al = SSL_AD_DECODE_ERROR; + goto f_err; + } +#ifdef SSL_DEBUG + fprintf(stderr, "USING TLSv1.2 HASH %s\n", EVP_MD_name(md)); +#endif + } else { + /* Use default digest for this key type */ + int idx = ssl_cert_type(NULL, pkey); + if (idx >= 0) + md = s->s3->tmp.md[idx]; + if (md == NULL) { + al = SSL_AD_INTERNAL_ERROR; + goto f_err; + } + } + + /* Check for broken implementations of GOST ciphersuites */ + /* + * If key is GOST and len is exactly 64 or 128, it is signature without + * length field (CryptoPro implementations at least till TLS 1.2) + */ +#ifndef OPENSSL_NO_GOST + if (!SSL_USE_SIGALGS(s) + && ((PACKET_remaining(pkt) == 64 + && (EVP_PKEY_id(pkey) == NID_id_GostR3410_2001 + || EVP_PKEY_id(pkey) == NID_id_GostR3410_2012_256)) + || (PACKET_remaining(pkt) == 128 + && EVP_PKEY_id(pkey) == NID_id_GostR3410_2012_512))) { + len = PACKET_remaining(pkt); + } else +#endif + if (!PACKET_get_net_2(pkt, &len)) { + SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, SSL_R_LENGTH_MISMATCH); + al = SSL_AD_DECODE_ERROR; + goto f_err; + } + + j = EVP_PKEY_size(pkey); + if (((int)len > j) || ((int)PACKET_remaining(pkt) > j) + || (PACKET_remaining(pkt) == 0)) { + SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, SSL_R_WRONG_SIGNATURE_SIZE); + al = SSL_AD_DECODE_ERROR; + goto f_err; + } + if (!PACKET_get_bytes(pkt, &data, len)) { + SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, SSL_R_LENGTH_MISMATCH); + al = SSL_AD_DECODE_ERROR; + goto f_err; + } + + hdatalen = BIO_get_mem_data(s->s3->handshake_buffer, &hdata); + if (hdatalen <= 0) { + SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, ERR_R_INTERNAL_ERROR); + al = SSL_AD_INTERNAL_ERROR; + goto f_err; + } +#ifdef SSL_DEBUG + fprintf(stderr, "Using client verify alg %s\n", EVP_MD_name(md)); +#endif + if (!EVP_VerifyInit_ex(mctx, md, NULL) + || !EVP_VerifyUpdate(mctx, hdata, hdatalen)) { + SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, ERR_R_EVP_LIB); + al = SSL_AD_INTERNAL_ERROR; + goto f_err; + } +#ifndef OPENSSL_NO_GOST + { + int pktype = EVP_PKEY_id(pkey); + if (pktype == NID_id_GostR3410_2001 + || pktype == NID_id_GostR3410_2012_256 + || pktype == NID_id_GostR3410_2012_512) { + if ((gost_data = OPENSSL_malloc(len)) == NULL) { + SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, ERR_R_MALLOC_FAILURE); + al = SSL_AD_INTERNAL_ERROR; + goto f_err; + } + BUF_reverse(gost_data, data, len); + data = gost_data; + } + } +#endif + + if (s->version == SSL3_VERSION + && !EVP_MD_CTX_ctrl(mctx, EVP_CTRL_SSL3_MASTER_SECRET, + s->session->master_key_length, + s->session->master_key)) { + SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, ERR_R_EVP_LIB); + al = SSL_AD_INTERNAL_ERROR; + goto f_err; + } + + if (EVP_VerifyFinal(mctx, data, len, pkey) <= 0) { + al = SSL_AD_DECRYPT_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, SSL_R_BAD_SIGNATURE); + goto f_err; + } + + ret = MSG_PROCESS_CONTINUE_READING; + if (0) { + f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + ossl_statem_set_error(s); + } + BIO_free(s->s3->handshake_buffer); + s->s3->handshake_buffer = NULL; + EVP_MD_CTX_free(mctx); +#ifndef OPENSSL_NO_GOST + OPENSSL_free(gost_data); +#endif + return ret; +} + +MSG_PROCESS_RETURN tls_process_client_certificate(SSL *s, PACKET *pkt) +{ + int i, al = SSL_AD_INTERNAL_ERROR, ret = MSG_PROCESS_ERROR; + X509 *x = NULL; + unsigned long l, llen; + const unsigned char *certstart, *certbytes; + STACK_OF(X509) *sk = NULL; + PACKET spkt; + + if ((sk = sk_X509_new_null()) == NULL) { + SSLerr(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE, ERR_R_MALLOC_FAILURE); + goto f_err; + } + + if (!PACKET_get_net_3(pkt, &llen) + || !PACKET_get_sub_packet(pkt, &spkt, llen) + || PACKET_remaining(pkt) != 0) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE, SSL_R_LENGTH_MISMATCH); + goto f_err; + } + + while (PACKET_remaining(&spkt) > 0) { + if (!PACKET_get_net_3(&spkt, &l) + || !PACKET_get_bytes(&spkt, &certbytes, l)) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE, + SSL_R_CERT_LENGTH_MISMATCH); + goto f_err; + } + + certstart = certbytes; + x = d2i_X509(NULL, (const unsigned char **)&certbytes, l); + if (x == NULL) { + SSLerr(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE, ERR_R_ASN1_LIB); + goto f_err; + } + if (certbytes != (certstart + l)) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE, + SSL_R_CERT_LENGTH_MISMATCH); + goto f_err; + } + if (!sk_X509_push(sk, x)) { + SSLerr(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE, ERR_R_MALLOC_FAILURE); + goto f_err; + } + x = NULL; + } + + if (sk_X509_num(sk) <= 0) { + /* TLS does not mind 0 certs returned */ + if (s->version == SSL3_VERSION) { + al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE, + SSL_R_NO_CERTIFICATES_RETURNED); + goto f_err; + } + /* Fail for TLS only if we required a certificate */ + else if ((s->verify_mode & SSL_VERIFY_PEER) && + (s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) { + SSLerr(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE, + SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE); + al = SSL_AD_HANDSHAKE_FAILURE; + goto f_err; + } + /* No client certificate so digest cached records */ + if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s, 0)) { + goto f_err; + } + } else { + EVP_PKEY *pkey; + i = ssl_verify_cert_chain(s, sk); + if (i <= 0) { + al = ssl_verify_alarm_type(s->verify_result); + SSLerr(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE, + SSL_R_CERTIFICATE_VERIFY_FAILED); + goto f_err; + } + if (i > 1) { + SSLerr(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE, i); + al = SSL_AD_HANDSHAKE_FAILURE; + goto f_err; + } + pkey = X509_get0_pubkey(sk_X509_value(sk, 0)); + if (pkey == NULL) { + al = SSL3_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE, + SSL_R_UNKNOWN_CERTIFICATE_TYPE); + goto f_err; + } + } + + X509_free(s->session->peer); + s->session->peer = sk_X509_shift(sk); + s->session->verify_result = s->verify_result; + + sk_X509_pop_free(s->session->peer_chain, X509_free); + s->session->peer_chain = sk; + /* + * Inconsistency alert: cert_chain does *not* include the peer's own + * certificate, while we do include it in statem_clnt.c + */ + sk = NULL; + ret = MSG_PROCESS_CONTINUE_READING; + goto done; + + f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + ossl_statem_set_error(s); + done: + X509_free(x); + sk_X509_pop_free(sk, X509_free); + return ret; +} + +int tls_construct_server_certificate(SSL *s) +{ + CERT_PKEY *cpk; + + cpk = ssl_get_server_send_pkey(s); + if (cpk == NULL) { + SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_CERTIFICATE, ERR_R_INTERNAL_ERROR); + ossl_statem_set_error(s); + return 0; + } + + if (!ssl3_output_cert_chain(s, cpk)) { + SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_CERTIFICATE, ERR_R_INTERNAL_ERROR); + ossl_statem_set_error(s); + return 0; + } + + return 1; +} + +int tls_construct_new_session_ticket(SSL *s) +{ + unsigned char *senc = NULL; + EVP_CIPHER_CTX *ctx = NULL; + HMAC_CTX *hctx = NULL; + unsigned char *p, *macstart; + const unsigned char *const_p; + int len, slen_full, slen; + SSL_SESSION *sess; + unsigned int hlen; + SSL_CTX *tctx = s->session_ctx; + unsigned char iv[EVP_MAX_IV_LENGTH]; + unsigned char key_name[TLSEXT_KEYNAME_LENGTH]; + int iv_len; + + /* get session encoding length */ + slen_full = i2d_SSL_SESSION(s->session, NULL); + /* + * Some length values are 16 bits, so forget it if session is too + * long + */ + if (slen_full == 0 || slen_full > 0xFF00) { + ossl_statem_set_error(s); + return 0; + } + senc = OPENSSL_malloc(slen_full); + if (senc == NULL) { + ossl_statem_set_error(s); + return 0; + } + + ctx = EVP_CIPHER_CTX_new(); + hctx = HMAC_CTX_new(); + if (ctx == NULL || hctx == NULL) { + SSLerr(SSL_F_TLS_CONSTRUCT_NEW_SESSION_TICKET, ERR_R_MALLOC_FAILURE); + goto err; + } + + p = senc; + if (!i2d_SSL_SESSION(s->session, &p)) + goto err; + + /* + * create a fresh copy (not shared with other threads) to clean up + */ + const_p = senc; + sess = d2i_SSL_SESSION(NULL, &const_p, slen_full); + if (sess == NULL) + goto err; + sess->session_id_length = 0; /* ID is irrelevant for the ticket */ + + slen = i2d_SSL_SESSION(sess, NULL); + if (slen == 0 || slen > slen_full) { /* shouldn't ever happen */ + SSL_SESSION_free(sess); + goto err; + } + p = senc; + if (!i2d_SSL_SESSION(sess, &p)) { + SSL_SESSION_free(sess); + goto err; + } + SSL_SESSION_free(sess); + + /*- + * Grow buffer if need be: the length calculation is as + * follows handshake_header_length + + * 4 (ticket lifetime hint) + 2 (ticket length) + + * sizeof(keyname) + max_iv_len (iv length) + + * max_enc_block_size (max encrypted session * length) + + * max_md_size (HMAC) + session_length. + */ + if (!BUF_MEM_grow(s->init_buf, + SSL_HM_HEADER_LENGTH(s) + 6 + sizeof(key_name) + + EVP_MAX_IV_LENGTH + EVP_MAX_BLOCK_LENGTH + + EVP_MAX_MD_SIZE + slen)) + goto err; + + p = ssl_handshake_start(s); + /* + * Initialize HMAC and cipher contexts. If callback present it does + * all the work otherwise use generated values from parent ctx. + */ + if (tctx->tlsext_ticket_key_cb) { + /* if 0 is returned, write an empty ticket */ + int ret = tctx->tlsext_ticket_key_cb(s, key_name, iv, ctx, + hctx, 1); + + if (ret == 0) { + l2n(0, p); /* timeout */ + s2n(0, p); /* length */ + if (!ssl_set_handshake_header + (s, SSL3_MT_NEWSESSION_TICKET, p - ssl_handshake_start(s))) + goto err; + OPENSSL_free(senc); + EVP_CIPHER_CTX_free(ctx); + HMAC_CTX_free(hctx); + return 1; + } + if (ret < 0) + goto err; + iv_len = EVP_CIPHER_CTX_iv_length(ctx); + } else { + const EVP_CIPHER *cipher = EVP_aes_256_cbc(); + + iv_len = EVP_CIPHER_iv_length(cipher); + if (RAND_bytes(iv, iv_len) <= 0) + goto err; + if (!EVP_EncryptInit_ex(ctx, cipher, NULL, + tctx->tlsext_tick_aes_key, iv)) + goto err; + if (!HMAC_Init_ex(hctx, tctx->tlsext_tick_hmac_key, + sizeof(tctx->tlsext_tick_hmac_key), + EVP_sha256(), NULL)) + goto err; + memcpy(key_name, tctx->tlsext_tick_key_name, + sizeof(tctx->tlsext_tick_key_name)); + } + + /* + * Ticket lifetime hint (advisory only): We leave this unspecified + * for resumed session (for simplicity), and guess that tickets for + * new sessions will live as long as their sessions. + */ + l2n(s->hit ? 0 : s->session->timeout, p); + + /* Skip ticket length for now */ + p += 2; + /* Output key name */ + macstart = p; + memcpy(p, key_name, sizeof(key_name)); + p += sizeof(key_name); + /* output IV */ + memcpy(p, iv, iv_len); + p += iv_len; + /* Encrypt session data */ + if (!EVP_EncryptUpdate(ctx, p, &len, senc, slen)) + goto err; + p += len; + if (!EVP_EncryptFinal(ctx, p, &len)) + goto err; + p += len; + + if (!HMAC_Update(hctx, macstart, p - macstart)) + goto err; + if (!HMAC_Final(hctx, p, &hlen)) + goto err; + + EVP_CIPHER_CTX_free(ctx); + HMAC_CTX_free(hctx); + ctx = NULL; + hctx = NULL; + + p += hlen; + /* Now write out lengths: p points to end of data written */ + /* Total length */ + len = p - ssl_handshake_start(s); + /* Skip ticket lifetime hint */ + p = ssl_handshake_start(s) + 4; + s2n(len - 6, p); + if (!ssl_set_handshake_header(s, SSL3_MT_NEWSESSION_TICKET, len)) + goto err; + OPENSSL_free(senc); + + return 1; + err: + OPENSSL_free(senc); + EVP_CIPHER_CTX_free(ctx); + HMAC_CTX_free(hctx); + ossl_statem_set_error(s); + return 0; +} + +int tls_construct_cert_status(SSL *s) +{ + unsigned char *p; + size_t msglen; + + /*- + * Grow buffer if need be: the length calculation is as + * follows handshake_header_length + + * 1 (ocsp response type) + 3 (ocsp response length) + * + (ocsp response) + */ + msglen = 4 + s->tlsext_ocsp_resplen; + if (!BUF_MEM_grow(s->init_buf, SSL_HM_HEADER_LENGTH(s) + msglen)) + goto err; + + p = ssl_handshake_start(s); + + /* status type */ + *(p++) = s->tlsext_status_type; + /* length of OCSP response */ + l2n3(s->tlsext_ocsp_resplen, p); + /* actual response */ + memcpy(p, s->tlsext_ocsp_resp, s->tlsext_ocsp_resplen); + + if (!ssl_set_handshake_header(s, SSL3_MT_CERTIFICATE_STATUS, msglen)) + goto err; + + return 1; + + err: + ossl_statem_set_error(s); + return 0; +} + +#ifndef OPENSSL_NO_NEXTPROTONEG +/* + * tls_process_next_proto reads a Next Protocol Negotiation handshake message. + * It sets the next_proto member in s if found + */ +MSG_PROCESS_RETURN tls_process_next_proto(SSL *s, PACKET *pkt) +{ + PACKET next_proto, padding; + size_t next_proto_len; + + /*- + * The payload looks like: + * uint8 proto_len; + * uint8 proto[proto_len]; + * uint8 padding_len; + * uint8 padding[padding_len]; + */ + if (!PACKET_get_length_prefixed_1(pkt, &next_proto) + || !PACKET_get_length_prefixed_1(pkt, &padding) + || PACKET_remaining(pkt) > 0) { + SSLerr(SSL_F_TLS_PROCESS_NEXT_PROTO, SSL_R_LENGTH_MISMATCH); + goto err; + } + + if (!PACKET_memdup(&next_proto, &s->next_proto_negotiated, &next_proto_len)) { + s->next_proto_negotiated_len = 0; + goto err; + } + + s->next_proto_negotiated_len = (unsigned char)next_proto_len; + + return MSG_PROCESS_CONTINUE_READING; + err: + ossl_statem_set_error(s); + return MSG_PROCESS_ERROR; +} +#endif + +#define SSLV2_CIPHER_LEN 3 + +STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, + PACKET *cipher_suites, + STACK_OF(SSL_CIPHER) **skp, + int sslv2format, int *al) +{ + const SSL_CIPHER *c; + STACK_OF(SSL_CIPHER) *sk; + int n; + /* 3 = SSLV2_CIPHER_LEN > TLS_CIPHER_LEN = 2. */ + unsigned char cipher[SSLV2_CIPHER_LEN]; + + s->s3->send_connection_binding = 0; + + n = sslv2format ? SSLV2_CIPHER_LEN : TLS_CIPHER_LEN; + + if (PACKET_remaining(cipher_suites) == 0) { + SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST, SSL_R_NO_CIPHERS_SPECIFIED); + *al = SSL_AD_ILLEGAL_PARAMETER; + return NULL; + } + + if (PACKET_remaining(cipher_suites) % n != 0) { + SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST, + SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST); + *al = SSL_AD_DECODE_ERROR; + return NULL; + } + + sk = sk_SSL_CIPHER_new_null(); + if (sk == NULL) { + SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST, ERR_R_MALLOC_FAILURE); + *al = SSL_AD_INTERNAL_ERROR; + return NULL; + } + + if (sslv2format) { + size_t numciphers = PACKET_remaining(cipher_suites) / n; + PACKET sslv2ciphers = *cipher_suites; + unsigned int leadbyte; + unsigned char *raw; + + /* + * We store the raw ciphers list in SSLv3+ format so we need to do some + * preprocessing to convert the list first. If there are any SSLv2 only + * ciphersuites with a non-zero leading byte then we are going to + * slightly over allocate because we won't store those. But that isn't a + * problem. + */ + raw = OPENSSL_malloc(numciphers * TLS_CIPHER_LEN); + s->s3->tmp.ciphers_raw = raw; + if (raw == NULL) { + *al = SSL_AD_INTERNAL_ERROR; + goto err; + } + for (s->s3->tmp.ciphers_rawlen = 0; + PACKET_remaining(&sslv2ciphers) > 0; + raw += TLS_CIPHER_LEN) { + if (!PACKET_get_1(&sslv2ciphers, &leadbyte) + || (leadbyte == 0 + && !PACKET_copy_bytes(&sslv2ciphers, raw, + TLS_CIPHER_LEN)) + || (leadbyte != 0 + && !PACKET_forward(&sslv2ciphers, TLS_CIPHER_LEN))) { + *al = SSL_AD_INTERNAL_ERROR; + OPENSSL_free(s->s3->tmp.ciphers_raw); + s->s3->tmp.ciphers_raw = NULL; + s->s3->tmp.ciphers_rawlen = 0; + goto err; + } + if (leadbyte == 0) + s->s3->tmp.ciphers_rawlen += TLS_CIPHER_LEN; + } + } else if (!PACKET_memdup(cipher_suites, &s->s3->tmp.ciphers_raw, + &s->s3->tmp.ciphers_rawlen)) { + *al = SSL_AD_INTERNAL_ERROR; + goto err; + } + + while (PACKET_copy_bytes(cipher_suites, cipher, n)) { + /* + * SSLv3 ciphers wrapped in an SSLv2-compatible ClientHello have the + * first byte set to zero, while true SSLv2 ciphers have a non-zero + * first byte. We don't support any true SSLv2 ciphers, so skip them. + */ + if (sslv2format && cipher[0] != '\0') + continue; + + /* Check for TLS_EMPTY_RENEGOTIATION_INFO_SCSV */ + if ((cipher[n - 2] == ((SSL3_CK_SCSV >> 8) & 0xff)) && + (cipher[n - 1] == (SSL3_CK_SCSV & 0xff))) { + /* SCSV fatal if renegotiating */ + if (s->renegotiate) { + SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST, + SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING); + *al = SSL_AD_HANDSHAKE_FAILURE; + goto err; + } + s->s3->send_connection_binding = 1; + continue; + } + + /* Check for TLS_FALLBACK_SCSV */ + if ((cipher[n - 2] == ((SSL3_CK_FALLBACK_SCSV >> 8) & 0xff)) && + (cipher[n - 1] == (SSL3_CK_FALLBACK_SCSV & 0xff))) { + /* + * The SCSV indicates that the client previously tried a higher + * version. Fail if the current version is an unexpected + * downgrade. + */ + if (!ssl_check_version_downgrade(s)) { + SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST, + SSL_R_INAPPROPRIATE_FALLBACK); + *al = SSL_AD_INAPPROPRIATE_FALLBACK; + goto err; + } + continue; + } + + /* For SSLv2-compat, ignore leading 0-byte. */ + c = ssl_get_cipher_by_char(s, sslv2format ? &cipher[1] : cipher); + if (c != NULL) { + if (!sk_SSL_CIPHER_push(sk, c)) { + SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST, ERR_R_MALLOC_FAILURE); + *al = SSL_AD_INTERNAL_ERROR; + goto err; + } + } + } + if (PACKET_remaining(cipher_suites) > 0) { + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST, ERR_R_INTERNAL_ERROR); + goto err; + } + + *skp = sk; + return sk; + err: + sk_SSL_CIPHER_free(sk); + return NULL; +} |