X-Git-Url: https://git.openssl.org/?p=openssl.git;a=blobdiff_plain;f=ssl%2Fssl_lib.c;h=f169611c017c4b4e2012b86cf82bb2ca742e7b6a;hp=8304c732ae7673488149d3c1ba3a69d3be48d29d;hb=69687aa829bc8bdcaf5468eb3dd0ada13700b7aa;hpb=6b1bb98fad044a6f6b1aec9daee95d6cb450210e diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 8304c732ae..f169611c01 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -551,6 +551,7 @@ SSL *SSL_new(SSL_CTX *ctx) s->mode = ctx->mode; s->max_cert_list = ctx->max_cert_list; s->references = 1; + s->max_early_data = ctx->max_early_data; /* * Earlier library versions used to copy the pointer to the CERT, not @@ -740,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. @@ -1014,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); @@ -1319,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); @@ -1532,6 +1534,47 @@ static int ssl_io_intern(void *vargs) return -1; } +int ssl_read_internal(SSL *s, void *buf, size_t num, size_t *readbytes) +{ + if (s->handshake_func == NULL) { + SSLerr(SSL_F_SSL_READ_INTERNAL, SSL_R_UNINITIALIZED); + return -1; + } + + if (s->shutdown & SSL_RECEIVED_SHUTDOWN) { + s->rwstate = SSL_NOTHING; + 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; + + args.s = s; + args.buf = buf; + args.num = num; + args.type = READFUNC; + args.f.func_read = s->method->ssl_read; + + ret = ssl_start_async_job(s, &args, ssl_io_intern); + *readbytes = s->asyncrw; + return ret; + } else { + return s->method->ssl_read(s, buf, num, readbytes); + } +} + int SSL_read(SSL *s, void *buf, int num) { int ret; @@ -1542,7 +1585,7 @@ int SSL_read(SSL *s, void *buf, int num) return -1; } - ret = SSL_read_ex(s, buf, (size_t)num, &readbytes); + ret = ssl_read_internal(s, buf, (size_t)num, &readbytes); /* * The cast is safe here because ret should be <= INT_MAX because num is @@ -1555,17 +1598,84 @@ int SSL_read(SSL *s, void *buf, int num) } int SSL_read_ex(SSL *s, void *buf, size_t num, size_t *readbytes) +{ + int ret = ssl_read_internal(s, buf, num, readbytes); + + if (ret < 0) + ret = 0; + 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) { - SSLerr(SSL_F_SSL_READ_EX, SSL_R_UNINITIALIZED); + SSLerr(SSL_F_SSL_PEEK_INTERNAL, SSL_R_UNINITIALIZED); return -1; } if (s->shutdown & SSL_RECEIVED_SHUTDOWN) { - s->rwstate = SSL_NOTHING; - return (0); + return 0; } - if ((s->mode & SSL_MODE_ASYNC) && ASYNC_get_current_job() == NULL) { struct ssl_async_args args; int ret; @@ -1574,13 +1684,13 @@ int SSL_read_ex(SSL *s, void *buf, size_t num, size_t *readbytes) args.buf = buf; args.num = num; args.type = READFUNC; - args.f.func_read = s->method->ssl_read; + args.f.func_read = s->method->ssl_peek; ret = ssl_start_async_job(s, &args, ssl_io_intern); *readbytes = s->asyncrw; return ret; } else { - return s->method->ssl_read(s, buf, num, readbytes); + return s->method->ssl_peek(s, buf, num, readbytes); } } @@ -1594,7 +1704,7 @@ int SSL_peek(SSL *s, void *buf, int num) return -1; } - ret = SSL_peek_ex(s, buf, (size_t)num, &readbytes); + ret = ssl_peek_internal(s, buf, (size_t)num, &readbytes); /* * The cast is safe here because ret should be <= INT_MAX because num is @@ -1606,31 +1716,53 @@ int SSL_peek(SSL *s, void *buf, int num) return ret; } + int SSL_peek_ex(SSL *s, void *buf, size_t num, size_t *readbytes) +{ + int ret = ssl_peek_internal(s, buf, num, readbytes); + + if (ret < 0) + ret = 0; + return ret; +} + +int ssl_write_internal(SSL *s, const void *buf, size_t num, size_t *written) { if (s->handshake_func == NULL) { - SSLerr(SSL_F_SSL_PEEK_EX, SSL_R_UNINITIALIZED); + SSLerr(SSL_F_SSL_WRITE_INTERNAL, SSL_R_UNINITIALIZED); return -1; } - if (s->shutdown & SSL_RECEIVED_SHUTDOWN) { - return (0); + if (s->shutdown & SSL_SENT_SHUTDOWN) { + s->rwstate = SSL_NOTHING; + SSLerr(SSL_F_SSL_WRITE_INTERNAL, SSL_R_PROTOCOL_IS_SHUTDOWN); + 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) { - struct ssl_async_args args; int ret; + struct ssl_async_args args; args.s = s; - args.buf = buf; + args.buf = (void *)buf; args.num = num; - args.type = READFUNC; - args.f.func_read = s->method->ssl_peek; + args.type = WRITEFUNC; + args.f.func_write = s->method->ssl_write; ret = ssl_start_async_job(s, &args, ssl_io_intern); - *readbytes = s->asyncrw; + *written = s->asyncrw; return ret; } else { - return s->method->ssl_peek(s, buf, num, readbytes); + return s->method->ssl_write(s, buf, num, written); } } @@ -1644,7 +1776,7 @@ int SSL_write(SSL *s, const void *buf, int num) return -1; } - ret = SSL_write_ex(s, buf, (size_t)num, &written); + ret = ssl_write_internal(s, buf, (size_t)num, &written); /* * The cast is safe here because ret should be <= INT_MAX because num is @@ -1658,32 +1790,55 @@ int SSL_write(SSL *s, const void *buf, int num) int SSL_write_ex(SSL *s, const void *buf, size_t num, size_t *written) { - if (s->handshake_func == NULL) { - SSLerr(SSL_F_SSL_WRITE_EX, SSL_R_UNINITIALIZED); - return -1; - } + int ret = ssl_write_internal(s, buf, num, written); - if (s->shutdown & SSL_SENT_SHUTDOWN) { - s->rwstate = SSL_NOTHING; - SSLerr(SSL_F_SSL_WRITE_EX, SSL_R_PROTOCOL_IS_SHUTDOWN); - return (-1); - } + if (ret < 0) + ret = 0; + return ret; +} - if ((s->mode & SSL_MODE_ASYNC) && ASYNC_get_current_job() == NULL) { - int ret; - struct ssl_async_args args; +int SSL_write_early_data(SSL *s, const void *buf, size_t num, size_t *written) +{ + int ret; - args.s = s; - args.buf = (void *)buf; - args.num = num; - args.type = WRITEFUNC; - args.f.func_write = s->method->ssl_write; + 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 */ - ret = ssl_start_async_job(s, &args, ssl_io_intern); - *written = s->asyncrw; + 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; - } else { - return s->method->ssl_write(s, buf, num, written); + + 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; } } @@ -2391,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. */ @@ -2476,11 +2631,6 @@ SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth) if (!OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL)) return NULL; - if (FIPS_mode() && (meth->version < TLS1_VERSION)) { - SSLerr(SSL_F_SSL_CTX_NEW, SSL_R_AT_LEAST_TLS_1_0_NEEDED_IN_FIPS_MODE); - return NULL; - } - if (SSL_get_ex_data_X509_STORE_CTX_idx() < 0) { SSLerr(SSL_F_SSL_CTX_NEW, SSL_R_X509_VERIFICATION_SETUP_PROBLEMS); goto err; @@ -2599,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); @@ -2991,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); @@ -3049,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)) { @@ -3584,11 +3739,6 @@ void *SSL_CTX_get_ex_data(const SSL_CTX *s, int idx) return (CRYPTO_get_ex_data(&s->ex_data, idx)); } -int ssl_ok(SSL *s) -{ - return (1); -} - X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *ctx) { return (ctx->cert_store); @@ -3740,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; */ @@ -4639,3 +4789,27 @@ int bytes_to_cipher_list(SSL *s, PACKET *cipher_suites, sk_SSL_CIPHER_free(scsvs); return 0; } + +int SSL_CTX_set_max_early_data(SSL_CTX *ctx, uint32_t max_early_data) +{ + ctx->max_early_data = max_early_data; + + return 1; +} + +uint32_t SSL_CTX_get_max_early_data(const SSL_CTX *ctx) +{ + return ctx->max_early_data; +} + +int SSL_set_max_early_data(SSL *s, uint32_t max_early_data) +{ + s->max_early_data = max_early_data; + + return 1; +} + +uint32_t SSL_get_max_early_data(const SSL_CTX *s) +{ + return s->max_early_data; +}