(Called "cut through" for historical reasons in this patch.) Enables SSL3+ clients to send application data immediately following the Finished message even when negotiating full-handshakes. With this patch, clients can negotiate SSL connections in 1-RTT even when performing full-handshakes.kris/onging/CECPQ3_patch15
@@ -209,6 +209,12 @@ int ssl3_connect(SSL *s) | |||||
} | } | ||||
#endif | #endif | ||||
if (SSL_get_mode(s) & SSL_MODE_HANDSHAKE_CUTTHROUGH) | |||||
{ | |||||
/* Send app data along with CCS/Finished */ | |||||
s->s3->flags |= SSL3_FLAGS_DELAY_CLIENT_FINISHED; | |||||
} | |||||
for (;;) | for (;;) | ||||
{ | { | ||||
state=s->state; | state=s->state; | ||||
@@ -518,14 +524,32 @@ int ssl3_connect(SSL *s) | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
#ifndef OPENSSL_NO_TLSEXT | |||||
/* Allow NewSessionTicket if ticket expected */ | |||||
if (s->tlsext_ticket_expected) | |||||
s->s3->tmp.next_state=SSL3_ST_CR_SESSION_TICKET_A; | |||||
if ((SSL_get_mode(s) & SSL_MODE_HANDSHAKE_CUTTHROUGH) | |||||
&& ssl3_can_cutthrough(s) | |||||
&& s->s3->previous_server_finished_len == 0 /* no cutthrough on renegotiation (would complicate the state machine) */ | |||||
) | |||||
{ | |||||
if (s->s3->flags & SSL3_FLAGS_DELAY_CLIENT_FINISHED) | |||||
{ | |||||
s->state=SSL3_ST_CUTTHROUGH_COMPLETE; | |||||
s->s3->flags|=SSL3_FLAGS_POP_BUFFER; | |||||
s->s3->delay_buf_pop_ret=0; | |||||
} | |||||
else | |||||
{ | |||||
s->s3->tmp.next_state=SSL3_ST_CUTTHROUGH_COMPLETE; | |||||
} | |||||
} | |||||
else | else | ||||
{ | |||||
#ifndef OPENSSL_NO_TLSEXT | |||||
/* Allow NewSessionTicket if ticket expected */ | |||||
if (s->tlsext_ticket_expected) | |||||
s->s3->tmp.next_state=SSL3_ST_CR_SESSION_TICKET_A; | |||||
else | |||||
#endif | #endif | ||||
s->s3->tmp.next_state=SSL3_ST_CR_FINISHED_A; | |||||
s->s3->tmp.next_state=SSL3_ST_CR_FINISHED_A; | |||||
} | |||||
} | } | ||||
s->init_num=0; | s->init_num=0; | ||||
break; | break; | ||||
@@ -573,6 +597,24 @@ int ssl3_connect(SSL *s) | |||||
s->state=s->s3->tmp.next_state; | s->state=s->s3->tmp.next_state; | ||||
break; | break; | ||||
case SSL3_ST_CUTTHROUGH_COMPLETE: | |||||
#ifndef OPENSSL_NO_TLSEXT | |||||
/* Allow NewSessionTicket if ticket expected */ | |||||
if (s->tlsext_ticket_expected) | |||||
s->state=SSL3_ST_CR_SESSION_TICKET_A; | |||||
else | |||||
#endif | |||||
s->state=SSL3_ST_CR_FINISHED_A; | |||||
/* SSL_write() will take care of flushing buffered data if | |||||
* DELAY_CLIENT_FINISHED is set. | |||||
*/ | |||||
if (!(s->s3->flags & SSL3_FLAGS_DELAY_CLIENT_FINISHED)) | |||||
ssl_free_wbio_buffer(s); | |||||
ret = 1; | |||||
goto end; | |||||
/* break; */ | |||||
case SSL_ST_OK: | case SSL_ST_OK: | ||||
/* clean a few things up */ | /* clean a few things up */ | ||||
ssl3_cleanup_key_block(s); | ssl3_cleanup_key_block(s); | ||||
@@ -3963,9 +3963,22 @@ int ssl3_write(SSL *s, const void *buf, int len) | |||||
static int ssl3_read_internal(SSL *s, void *buf, int len, int peek) | static int ssl3_read_internal(SSL *s, void *buf, int len, int peek) | ||||
{ | { | ||||
int ret; | |||||
int n,ret; | |||||
ERR_clear_system_error(); | ERR_clear_system_error(); | ||||
if ((s->s3->flags & SSL3_FLAGS_POP_BUFFER) && (s->wbio == s->bbio)) | |||||
{ | |||||
/* Deal with an application that calls SSL_read() when handshake data | |||||
* is yet to be written. | |||||
*/ | |||||
if (BIO_wpending(s->wbio) > 0) | |||||
{ | |||||
s->rwstate=SSL_WRITING; | |||||
n=BIO_flush(s->wbio); | |||||
if (n <= 0) return(n); | |||||
s->rwstate=SSL_NOTHING; | |||||
} | |||||
} | |||||
if (s->s3->renegotiate) ssl3_renegotiate_check(s); | if (s->s3->renegotiate) ssl3_renegotiate_check(s); | ||||
s->s3->in_read_app_data=1; | s->s3->in_read_app_data=1; | ||||
ret=s->method->ssl_read_bytes(s,SSL3_RT_APPLICATION_DATA,buf,len,peek); | ret=s->method->ssl_read_bytes(s,SSL3_RT_APPLICATION_DATA,buf,len,peek); | ||||
@@ -689,6 +689,7 @@ struct ssl_session_st | |||||
* TLS only.) "Released" buffers are put onto a free-list in the context | * TLS only.) "Released" buffers are put onto a free-list in the context | ||||
* or just freed (depending on the context's setting for freelist_max_len). */ | * or just freed (depending on the context's setting for freelist_max_len). */ | ||||
#define SSL_MODE_RELEASE_BUFFERS 0x00000010L | #define SSL_MODE_RELEASE_BUFFERS 0x00000010L | ||||
/* Send the current time in the Random fields of the ClientHello and | /* Send the current time in the Random fields of the ClientHello and | ||||
* ServerHello records for compatibility with hypothetical implementations | * ServerHello records for compatibility with hypothetical implementations | ||||
* that require it. | * that require it. | ||||
@@ -752,6 +753,11 @@ struct ssl_session_st | |||||
#define SSL_CONF_TYPE_FILE 0x2 | #define SSL_CONF_TYPE_FILE 0x2 | ||||
#define SSL_CONF_TYPE_DIR 0x3 | #define SSL_CONF_TYPE_DIR 0x3 | ||||
/* When set, clients may send application data before receipt of CCS | |||||
* and Finished. This mode enables full-handshakes to 'complete' in | |||||
* one RTT. */ | |||||
#define SSL_MODE_HANDSHAKE_CUTTHROUGH 0x00000080L | |||||
/* Note: SSL[_CTX]_set_{options,mode} use |= op on the previous value, | /* Note: SSL[_CTX]_set_{options,mode} use |= op on the previous value, | ||||
* they cannot be used to clear bits. */ | * they cannot be used to clear bits. */ | ||||
@@ -1560,10 +1566,12 @@ extern "C" { | |||||
/* Is the SSL_connection established? */ | /* Is the SSL_connection established? */ | ||||
#define SSL_get_state(a) SSL_state(a) | #define SSL_get_state(a) SSL_state(a) | ||||
#define SSL_is_init_finished(a) (SSL_state(a) == SSL_ST_OK) | #define SSL_is_init_finished(a) (SSL_state(a) == SSL_ST_OK) | ||||
#define SSL_in_init(a) (SSL_state(a)&SSL_ST_INIT) | |||||
#define SSL_in_init(a) ((SSL_state(a)&SSL_ST_INIT) && \ | |||||
!SSL_cutthrough_complete(a)) | |||||
#define SSL_in_before(a) (SSL_state(a)&SSL_ST_BEFORE) | #define SSL_in_before(a) (SSL_state(a)&SSL_ST_BEFORE) | ||||
#define SSL_in_connect_init(a) (SSL_state(a)&SSL_ST_CONNECT) | #define SSL_in_connect_init(a) (SSL_state(a)&SSL_ST_CONNECT) | ||||
#define SSL_in_accept_init(a) (SSL_state(a)&SSL_ST_ACCEPT) | #define SSL_in_accept_init(a) (SSL_state(a)&SSL_ST_ACCEPT) | ||||
int SSL_cutthrough_complete(const SSL *s); | |||||
/* The following 2 states are kept in ssl->rstate when reads fail, | /* The following 2 states are kept in ssl->rstate when reads fail, | ||||
* you should not need these */ | * you should not need these */ | ||||
@@ -597,6 +597,7 @@ typedef struct ssl3_state_st | |||||
/*client */ | /*client */ | ||||
/* extra state */ | /* extra state */ | ||||
#define SSL3_ST_CW_FLUSH (0x100|SSL_ST_CONNECT) | #define SSL3_ST_CW_FLUSH (0x100|SSL_ST_CONNECT) | ||||
#define SSL3_ST_CUTTHROUGH_COMPLETE (0x101|SSL_ST_CONNECT) | |||||
/* write to server */ | /* write to server */ | ||||
#define SSL3_ST_CW_CLNT_HELLO_A (0x110|SSL_ST_CONNECT) | #define SSL3_ST_CW_CLNT_HELLO_A (0x110|SSL_ST_CONNECT) | ||||
#define SSL3_ST_CW_CLNT_HELLO_B (0x111|SSL_ST_CONNECT) | #define SSL3_ST_CW_CLNT_HELLO_B (0x111|SSL_ST_CONNECT) | ||||
@@ -3308,6 +3308,48 @@ void SSL_set_msg_callback(SSL *ssl, void (*cb)(int write_p, int version, int con | |||||
SSL_callback_ctrl(ssl, SSL_CTRL_SET_MSG_CALLBACK, (void (*)(void))cb); | SSL_callback_ctrl(ssl, SSL_CTRL_SET_MSG_CALLBACK, (void (*)(void))cb); | ||||
} | } | ||||
int SSL_cutthrough_complete(const SSL *s) | |||||
{ | |||||
return (!s->server && /* cutthrough only applies to clients */ | |||||
!s->hit && /* full-handshake */ | |||||
s->version >= SSL3_VERSION && | |||||
s->s3->in_read_app_data == 0 && /* cutthrough only applies to write() */ | |||||
(SSL_get_mode((SSL*)s) & SSL_MODE_HANDSHAKE_CUTTHROUGH) && /* cutthrough enabled */ | |||||
ssl3_can_cutthrough(s) && /* cutthrough allowed */ | |||||
s->s3->previous_server_finished_len == 0 && /* not a renegotiation handshake */ | |||||
(s->state == SSL3_ST_CR_SESSION_TICKET_A || /* ready to write app-data*/ | |||||
s->state == SSL3_ST_CR_FINISHED_A)); | |||||
} | |||||
int ssl3_can_cutthrough(const SSL *s) | |||||
{ | |||||
const SSL_CIPHER *c; | |||||
/* require a strong enough cipher */ | |||||
if (SSL_get_cipher_bits(s, NULL) < 128) | |||||
return 0; | |||||
/* require ALPN or NPN extension */ | |||||
if (!s->s3->alpn_selected | |||||
#ifndef OPENSSL_NO_NEXTPROTONEG | |||||
&& !s->s3->next_proto_neg_seen | |||||
#endif | |||||
) | |||||
{ | |||||
return 0; | |||||
} | |||||
/* require a forward-secret cipher */ | |||||
c = SSL_get_current_cipher(s); | |||||
if (!c || (c->algorithm_mkey != SSL_kEDH && | |||||
c->algorithm_mkey != SSL_kEECDH)) | |||||
{ | |||||
return 0; | |||||
} | |||||
return 1; | |||||
} | |||||
/* Allocates new EVP_MD_CTX and sets pointer to it into given pointer | /* Allocates new EVP_MD_CTX and sets pointer to it into given pointer | ||||
* vairable, freeing EVP_MD_CTX previously stored in that variable, if | * vairable, freeing EVP_MD_CTX previously stored in that variable, if | ||||
* any. If EVP_MD pointer is passed, initializes ctx with this md | * any. If EVP_MD pointer is passed, initializes ctx with this md | ||||
@@ -1294,6 +1294,8 @@ int tls1_check_chain(SSL *s, X509 *x, EVP_PKEY *pk, STACK_OF(X509) *chain, | |||||
void tls1_set_cert_validity(SSL *s); | void tls1_set_cert_validity(SSL *s); | ||||
#endif | #endif | ||||
int ssl3_can_cutthrough(const SSL *s); | |||||
EVP_MD_CTX* ssl_replace_hash(EVP_MD_CTX **hash,const EVP_MD *md) ; | EVP_MD_CTX* ssl_replace_hash(EVP_MD_CTX **hash,const EVP_MD *md) ; | ||||
void ssl_clear_hash_ctx(EVP_MD_CTX **hash); | void ssl_clear_hash_ctx(EVP_MD_CTX **hash); | ||||
int ssl_add_serverhello_renegotiate_ext(SSL *s, unsigned char *p, int *len, | int ssl_add_serverhello_renegotiate_ext(SSL *s, unsigned char *p, int *len, | ||||