X-Git-Url: https://git.openssl.org/?p=openssl.git;a=blobdiff_plain;f=ssl%2Fssl_lib.c;h=f169611c017c4b4e2012b86cf82bb2ca742e7b6a;hp=d3dddafad7bf6269dad45eaf5acecb712ca68546;hb=69687aa829bc8bdcaf5468eb3dd0ada13700b7aa;hpb=3fc8d856105e4716d3121348996ea3c61e7e4b7d diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index d3dddafad7..f169611c01 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -741,7 +741,7 @@ int SSL_has_matching_session_id(const SSL *ssl, const unsigned char *id, { /* * A quick examination of SSL_SESSION_hash and SSL_SESSION_cmp shows how - * we can "construct" a session to give us the desired check - ie. to + * we can "construct" a session to give us the desired check - i.e. to * find if there's a session in the hash table that would conflict with * any new session built out of this id/id_len and the ssl_version in use * by this SSL. @@ -1015,6 +1015,7 @@ void SSL_free(SSL *s) #endif OPENSSL_free(s->ext.ocsp.resp); OPENSSL_free(s->ext.alpn); + OPENSSL_free(s->ext.tls13_cookie); OPENSSL_free(s->clienthello); sk_X509_NAME_pop_free(s->client_CA, X509_NAME_free); @@ -1320,7 +1321,7 @@ int SSL_has_pending(const SSL *s) * data. That data may not result in any application data, or we may fail * to parse the records for some reason. */ - if (SSL_pending(s)) + if (RECORD_LAYER_processed_read_pending(&s->rlayer)) return 1; return RECORD_LAYER_read_pending(&s->rlayer); @@ -1545,6 +1546,17 @@ int ssl_read_internal(SSL *s, void *buf, size_t num, size_t *readbytes) return 0; } + if (s->early_data_state == SSL_EARLY_DATA_CONNECT_RETRY + || s->early_data_state == SSL_EARLY_DATA_ACCEPT_RETRY) { + SSLerr(SSL_F_SSL_READ_INTERNAL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + /* + * If we are a client and haven't received the ServerHello etc then we + * better do that + */ + ossl_statem_check_finish_init(s, 0); + if ((s->mode & SSL_MODE_ASYNC) && ASYNC_get_current_job() == NULL) { struct ssl_async_args args; int ret; @@ -1594,6 +1606,66 @@ int SSL_read_ex(SSL *s, void *buf, size_t num, size_t *readbytes) return ret; } +int SSL_read_early_data(SSL *s, void *buf, size_t num, size_t *readbytes) +{ + int ret; + + if (!s->server) { + SSLerr(SSL_F_SSL_READ_EARLY_DATA, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return SSL_READ_EARLY_DATA_ERROR; + } + + switch (s->early_data_state) { + case SSL_EARLY_DATA_NONE: + if (!SSL_in_before(s)) { + SSLerr(SSL_F_SSL_READ_EARLY_DATA, + ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return SSL_READ_EARLY_DATA_ERROR; + } + /* fall through */ + + case SSL_EARLY_DATA_ACCEPT_RETRY: + s->early_data_state = SSL_EARLY_DATA_ACCEPTING; + ret = SSL_accept(s); + if (ret <= 0) { + /* NBIO or error */ + s->early_data_state = SSL_EARLY_DATA_ACCEPT_RETRY; + return SSL_READ_EARLY_DATA_ERROR; + } + /* fall through */ + + case SSL_EARLY_DATA_READ_RETRY: + if (s->ext.early_data == SSL_EARLY_DATA_ACCEPTED) { + s->early_data_state = SSL_EARLY_DATA_READING; + ret = SSL_read_ex(s, buf, num, readbytes); + /* + * State machine will update early_data_state to + * SSL_EARLY_DATA_FINISHED_READING if we get an EndOfEarlyData + * message + */ + if (ret > 0 || (ret <= 0 && s->early_data_state + != SSL_EARLY_DATA_FINISHED_READING)) { + s->early_data_state = SSL_EARLY_DATA_READ_RETRY; + return ret > 0 ? SSL_READ_EARLY_DATA_SUCCESS + : SSL_READ_EARLY_DATA_ERROR; + } + } else { + s->early_data_state = SSL_EARLY_DATA_FINISHED_READING; + } + *readbytes = 0; + return SSL_READ_EARLY_DATA_FINISH; + + default: + SSLerr(SSL_F_SSL_READ_EARLY_DATA, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return SSL_READ_EARLY_DATA_ERROR; + } +} + +int SSL_get_early_data_status(const SSL *s) +{ + return s->ext.early_data; +} + static int ssl_peek_internal(SSL *s, void *buf, size_t num, size_t *readbytes) { if (s->handshake_func == NULL) { @@ -1667,6 +1739,15 @@ int ssl_write_internal(SSL *s, const void *buf, size_t num, size_t *written) return -1; } + if (s->early_data_state == SSL_EARLY_DATA_CONNECT_RETRY + || s->early_data_state == SSL_EARLY_DATA_ACCEPT_RETRY + || s->early_data_state == SSL_EARLY_DATA_READ_RETRY) { + SSLerr(SSL_F_SSL_WRITE_INTERNAL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + /* If we are a client and haven't sent the Finished we better do that */ + ossl_statem_check_finish_init(s, 1); + if ((s->mode & SSL_MODE_ASYNC) && ASYNC_get_current_job() == NULL) { int ret; struct ssl_async_args args; @@ -1716,6 +1797,51 @@ int SSL_write_ex(SSL *s, const void *buf, size_t num, size_t *written) return ret; } +int SSL_write_early_data(SSL *s, const void *buf, size_t num, size_t *written) +{ + int ret; + + switch (s->early_data_state) { + case SSL_EARLY_DATA_NONE: + if (s->server + || !SSL_in_before(s) + || s->session == NULL + || s->session->ext.max_early_data == 0) { + SSLerr(SSL_F_SSL_WRITE_EARLY_DATA, + ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + /* fall through */ + + case SSL_EARLY_DATA_CONNECT_RETRY: + s->early_data_state = SSL_EARLY_DATA_CONNECTING; + ret = SSL_connect(s); + if (ret <= 0) { + /* NBIO or error */ + s->early_data_state = SSL_EARLY_DATA_CONNECT_RETRY; + return 0; + } + /* fall through */ + + case SSL_EARLY_DATA_WRITE_RETRY: + s->early_data_state = SSL_EARLY_DATA_WRITING; + ret = SSL_write_ex(s, buf, num, written); + s->early_data_state = SSL_EARLY_DATA_WRITE_RETRY; + return ret; + + case SSL_EARLY_DATA_READ_RETRY: + /* We are a server writing to an unauthenticated client */ + s->early_data_state = SSL_EARLY_DATA_UNAUTH_WRITING; + ret = SSL_write_ex(s, buf, num, written); + s->early_data_state = SSL_EARLY_DATA_READ_RETRY; + return ret; + + default: + SSLerr(SSL_F_SSL_WRITE_EARLY_DATA, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } +} + int SSL_shutdown(SSL *s) { /* @@ -2420,8 +2546,8 @@ void SSL_CTX_set_alpn_select_cb(SSL_CTX *ctx, } /* - * SSL_get0_alpn_selected gets the selected ALPN protocol (if any) from - * |ssl|. On return it sets |*data| to point to |*len| bytes of protocol name + * SSL_get0_alpn_selected gets the selected ALPN protocol (if any) from |ssl|. + * On return it sets |*data| to point to |*len| bytes of protocol name * (not including the leading length-prefix byte). If the server didn't * respond with a negotiated protocol then |*len| will be zero. */ @@ -2623,6 +2749,12 @@ SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth) ret->ext.status_type = TLSEXT_STATUSTYPE_nothing; + /* + * Default max early data is a fully loaded single record. Could be split + * across multiple records in practice + */ + ret->max_early_data = SSL3_RT_MAX_PLAIN_LENGTH; + return ret; err: SSLerr(SSL_F_SSL_CTX_NEW, ERR_R_MALLOC_FAILURE); @@ -3015,10 +3147,7 @@ int SSL_get_error(const SSL *s, int i) } if (SSL_want_write(s)) { - /* - * Access wbio directly - in order to use the buffered bio if - * present - */ + /* Access wbio directly - in order to use the buffered bio if present */ bio = s->wbio; if (BIO_should_write(bio)) return (SSL_ERROR_WANT_WRITE); @@ -3073,6 +3202,8 @@ int SSL_do_handshake(SSL *s) return -1; } + ossl_statem_check_finish_init(s, -1); + s->method->ssl_renegotiate_check(s, 0); if (SSL_in_init(s) || SSL_in_before(s)) { @@ -3759,7 +3890,7 @@ void SSL_set_not_resumable_session_callback(SSL *ssl, /* * Allocates new EVP_MD_CTX and sets pointer to it into given pointer * variable, freeing EVP_MD_CTX previously stored in that variable, if any. - * If EVP_MD pointer is passed, initializes ctx with this md. + * If EVP_MD pointer is passed, initializes ctx with this |md|. * Returns the newly allocated ctx; */ @@ -4666,7 +4797,7 @@ int SSL_CTX_set_max_early_data(SSL_CTX *ctx, uint32_t max_early_data) return 1; } -uint32_t SSL_CTX_get_max_early_data(SSL_CTX *ctx) +uint32_t SSL_CTX_get_max_early_data(const SSL_CTX *ctx) { return ctx->max_early_data; } @@ -4678,7 +4809,7 @@ int SSL_set_max_early_data(SSL *s, uint32_t max_early_data) return 1; } -uint32_t SSL_get_max_early_data(SSL_CTX *s) +uint32_t SSL_get_max_early_data(const SSL_CTX *s) { return s->max_early_data; }