Openssl 1.1.0h
This commit is contained in:
@@ -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 |
|
||||
|_____________________________| |_______________________________|
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user