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
{
/*
* 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.
#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);
* 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);
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;
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) {
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;
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_FINISHED_READING:
+ 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)
{
/*
}
/*
- * 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.
*/
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;
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);
}
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);
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)) {
/*
* 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;
*/
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;
+}