s->psksession_id = NULL;
s->psksession_id_len = 0;
s->hello_retry_request = 0;
+ s->sent_tickets = 0;
s->error = 0;
s->hit = 0;
s->mode = ctx->mode;
s->max_cert_list = ctx->max_cert_list;
s->max_early_data = ctx->max_early_data;
+ s->recv_max_early_data = ctx->recv_max_early_data;
+ s->num_tickets = ctx->num_tickets;
/* Shallow copy of the ciphersuites stack */
s->tls13_ciphersuites = sk_SSL_CIPHER_dup(ctx->tls13_ciphersuites);
s->key_update = SSL_KEY_UPDATE_NONE;
+ s->allow_early_data_cb = ctx->allow_early_data_cb;
+ s->allow_early_data_cb_data = ctx->allow_early_data_cb_data;
+
if (!s->method->ssl_new(s))
goto err;
/* 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);
+ /* The buffering BIO is still in place */
+ if (ret)
+ (void)BIO_flush(s->wbio);
s->early_data_state = early_data_state;
return ret;
long SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg)
{
long l;
- int i;
/* For some cases with ctx == NULL perform syntax checks */
if (ctx == NULL) {
switch (cmd) {
case SSL_CTRL_SESS_NUMBER:
return lh_SSL_SESSION_num_items(ctx->sessions);
case SSL_CTRL_SESS_CONNECT:
- return CRYPTO_atomic_read(&ctx->stats.sess_connect, &i, ctx->lock)
- ? i : 0;
+ return tsan_load(&ctx->stats.sess_connect);
case SSL_CTRL_SESS_CONNECT_GOOD:
- return CRYPTO_atomic_read(&ctx->stats.sess_connect_good, &i, ctx->lock)
- ? i : 0;
+ return tsan_load(&ctx->stats.sess_connect_good);
case SSL_CTRL_SESS_CONNECT_RENEGOTIATE:
- return CRYPTO_atomic_read(&ctx->stats.sess_connect_renegotiate, &i,
- ctx->lock)
- ? i : 0;
+ return tsan_load(&ctx->stats.sess_connect_renegotiate);
case SSL_CTRL_SESS_ACCEPT:
- return CRYPTO_atomic_read(&ctx->stats.sess_accept, &i, ctx->lock)
- ? i : 0;
+ return tsan_load(&ctx->stats.sess_accept);
case SSL_CTRL_SESS_ACCEPT_GOOD:
- return CRYPTO_atomic_read(&ctx->stats.sess_accept_good, &i, ctx->lock)
- ? i : 0;
+ return tsan_load(&ctx->stats.sess_accept_good);
case SSL_CTRL_SESS_ACCEPT_RENEGOTIATE:
- return CRYPTO_atomic_read(&ctx->stats.sess_accept_renegotiate, &i,
- ctx->lock)
- ? i : 0;
+ return tsan_load(&ctx->stats.sess_accept_renegotiate);
case SSL_CTRL_SESS_HIT:
- return CRYPTO_atomic_read(&ctx->stats.sess_hit, &i, ctx->lock)
- ? i : 0;
+ return tsan_load(&ctx->stats.sess_hit);
case SSL_CTRL_SESS_CB_HIT:
- return CRYPTO_atomic_read(&ctx->stats.sess_cb_hit, &i, ctx->lock)
- ? i : 0;
+ return tsan_load(&ctx->stats.sess_cb_hit);
case SSL_CTRL_SESS_MISSES:
- return CRYPTO_atomic_read(&ctx->stats.sess_miss, &i, ctx->lock)
- ? i : 0;
+ return tsan_load(&ctx->stats.sess_miss);
case SSL_CTRL_SESS_TIMEOUTS:
- return CRYPTO_atomic_read(&ctx->stats.sess_timeout, &i, ctx->lock)
- ? i : 0;
+ return tsan_load(&ctx->stats.sess_timeout);
case SSL_CTRL_SESS_CACHE_FULL:
- return CRYPTO_atomic_read(&ctx->stats.sess_cache_full, &i, ctx->lock)
- ? i : 0;
+ return tsan_load(&ctx->stats.sess_cache_full);
case SSL_CTRL_MODE:
return (ctx->mode |= larg);
case SSL_CTRL_CLEAR_MODE:
return 1;
}
-static int ciphersuite_cb(const char *elem, int len, void *arg)
-{
- STACK_OF(SSL_CIPHER) *ciphersuites = (STACK_OF(SSL_CIPHER) *)arg;
- const SSL_CIPHER *cipher;
- /* Arbitrary sized temp buffer for the cipher name. Should be big enough */
- char name[80];
-
- if (len > (int)(sizeof(name) - 1)) {
- SSLerr(SSL_F_CIPHERSUITE_CB, SSL_R_NO_CIPHER_MATCH);
- return 0;
- }
-
- memcpy(name, elem, len);
- name[len] = '\0';
-
- cipher = ssl3_get_cipher_by_std_name(name);
- if (cipher == NULL) {
- SSLerr(SSL_F_CIPHERSUITE_CB, SSL_R_NO_CIPHER_MATCH);
- return 0;
- }
-
- if (!sk_SSL_CIPHER_push(ciphersuites, cipher)) {
- SSLerr(SSL_F_CIPHERSUITE_CB, ERR_R_INTERNAL_ERROR);
- return 0;
- }
-
- return 1;
-}
-
-static int set_ciphersuites(STACK_OF(SSL_CIPHER) **currciphers, const char *str)
-{
- STACK_OF(SSL_CIPHER) *newciphers = sk_SSL_CIPHER_new_null();
-
- if (newciphers == NULL)
- return 0;
-
- /* Parse the list. We explicitly allow an empty list */
- if (*str != '\0'
- && !CONF_parse_list(str, ':', 1, ciphersuite_cb, newciphers)) {
- sk_SSL_CIPHER_free(newciphers);
- return 0;
- }
- sk_SSL_CIPHER_free(*currciphers);
- *currciphers = newciphers;
-
- return 1;
-}
-
-static int update_cipher_list(STACK_OF(SSL_CIPHER) *cipher_list,
- STACK_OF(SSL_CIPHER) *tls13_ciphersuites)
-{
- int i;
-
- /*
- * Delete any existing TLSv1.3 ciphersuites. These are always first in the
- * list.
- */
- while (sk_SSL_CIPHER_num(cipher_list) > 0
- && sk_SSL_CIPHER_value(cipher_list, 0)->min_tls == TLS1_3_VERSION)
- sk_SSL_CIPHER_delete(cipher_list, 0);
-
- /* Insert the new TLSv1.3 ciphersuites */
- for (i = 0; i < sk_SSL_CIPHER_num(tls13_ciphersuites); i++)
- sk_SSL_CIPHER_insert(cipher_list,
- sk_SSL_CIPHER_value(tls13_ciphersuites, i), i);
-
- return 1;
-}
-
-int SSL_CTX_set_ciphersuites(SSL_CTX *ctx, const char *str)
-{
- int ret = set_ciphersuites(&(ctx->tls13_ciphersuites), str);
-
- if (ret && ctx->cipher_list != NULL) {
- /* We already have a cipher_list, so we need to update it */
- return update_cipher_list(ctx->cipher_list, ctx->tls13_ciphersuites);
- }
-
- return ret;
-}
-
-int SSL_set_ciphersuites(SSL *s, const char *str)
-{
- int ret = set_ciphersuites(&(s->tls13_ciphersuites), str);
-
- if (ret && s->cipher_list != NULL) {
- /* We already have a cipher_list, so we need to update it */
- return update_cipher_list(s->cipher_list, s->tls13_ciphersuites);
- }
-
- return ret;
-}
-
-char *SSL_get_shared_ciphers(const SSL *s, char *buf, int len)
+char *SSL_get_shared_ciphers(const SSL *s, char *buf, int size)
{
char *p;
- STACK_OF(SSL_CIPHER) *sk;
+ STACK_OF(SSL_CIPHER) *clntsk, *srvrsk;
const SSL_CIPHER *c;
int i;
- if ((s->session == NULL) || (s->session->ciphers == NULL) || (len < 2))
+ if (!s->server
+ || s->session == NULL
+ || s->session->ciphers == NULL
+ || size < 2)
return NULL;
p = buf;
- sk = s->session->ciphers;
+ clntsk = s->session->ciphers;
+ srvrsk = SSL_get_ciphers(s);
+ if (clntsk == NULL || srvrsk == NULL)
+ return NULL;
- if (sk_SSL_CIPHER_num(sk) == 0)
+ if (sk_SSL_CIPHER_num(clntsk) == 0 || sk_SSL_CIPHER_num(srvrsk) == 0)
return NULL;
- for (i = 0; i < sk_SSL_CIPHER_num(sk); i++) {
+ for (i = 0; i < sk_SSL_CIPHER_num(clntsk); i++) {
int n;
- c = sk_SSL_CIPHER_value(sk, i);
+ c = sk_SSL_CIPHER_value(clntsk, i);
+ if (sk_SSL_CIPHER_find(srvrsk, c) < 0)
+ continue;
+
n = strlen(c->name);
- if (n + 1 > len) {
+ if (n + 1 > size) {
if (p != buf)
--p;
*p = '\0';
strcpy(p, c->name);
p += n;
*(p++) = ':';
- len -= n + 1;
+ size -= n + 1;
}
p[-1] = '\0';
return buf;
if (type != TLSEXT_NAMETYPE_host_name)
return NULL;
- return s->session && !s->ext.hostname ?
+ /*
+ * TODO(OpenSSL1.2) clean up this compat mess. This API is
+ * currently a mix of "what did I configure" and "what did the
+ * peer send" and "what was actually negotiated"; we should have
+ * a clear distinction amongst those three.
+ */
+ if (SSL_in_init(s)) {
+ if (s->hit)
+ return s->session->ext.hostname;
+ return s->ext.hostname;
+ }
+ return (s->session != NULL && s->ext.hostname == NULL) ?
s->session->ext.hostname : s->ext.hostname;
}
ret->method = meth;
ret->min_proto_version = 0;
ret->max_proto_version = 0;
+ ret->mode = SSL_MODE_AUTO_RETRY;
ret->session_cache_mode = SSL_SESS_CACHE_SERVER;
ret->session_cache_size = SSL_SESSION_CACHE_MAX_SIZE_DEFAULT;
/* We take the system default. */
*/
ret->max_early_data = 0;
+ /*
+ * Default recv_max_early_data is a fully loaded single record. Could be
+ * split across multiple records in practice. We set this differently to
+ * max_early_data so that, in the default case, we do not advertise any
+ * support for early_data, but if a client were to send us some (e.g.
+ * because of an old, stale ticket) then we will tolerate it and skip over
+ * it.
+ */
+ ret->recv_max_early_data = SSL3_RT_MAX_PLAIN_LENGTH;
+
+ /* By default we send two session tickets automatically in TLSv1.3 */
+ ret->num_tickets = 2;
+
ssl_ctx_system_config(ret);
return ret;
/*
* If sid_ctx_length is 0 there is no specific application context
* associated with this session, so when we try to resume it and
- * SSL_VERIFY_PEER is requested, we have no indication that this is
- * actually a session for the proper application context, and the
- * *handshake* will fail, not just the resumption attempt.
- * Do not cache these sessions that are not resumable.
+ * SSL_VERIFY_PEER is requested to verify the client identity, we have no
+ * indication that this is actually a session for the proper application
+ * context, and the *handshake* will fail, not just the resumption attempt.
+ * Do not cache (on the server) these sessions that are not resumable
+ * (clients can set SSL_VERIFY_PEER without needing a sid_ctx set).
*/
- if (s->session->sid_ctx_length == 0
+ if (s->server && s->session->sid_ctx_length == 0
&& (s->verify_mode & SSL_VERIFY_PEER) != 0)
return;
i = s->session_ctx->session_cache_mode;
if ((i & mode) != 0
- && (!s->hit || SSL_IS_TLS13(s))
- && ((i & SSL_SESS_CACHE_NO_INTERNAL_STORE) != 0
- || SSL_CTX_add_session(s->session_ctx, s->session))
- && s->session_ctx->new_session_cb != NULL) {
- SSL_SESSION_up_ref(s->session);
- if (!s->session_ctx->new_session_cb(s, s->session))
- SSL_SESSION_free(s->session);
+ && (!s->hit || SSL_IS_TLS13(s))) {
+ /*
+ * Add the session to the internal cache. In server side TLSv1.3 we
+ * normally don't do this because by default it's a full stateless ticket
+ * with only a dummy session id so there is no reason to cache it,
+ * unless:
+ * - we are doing early_data, in which case we cache so that we can
+ * detect replays
+ * - the application has set a remove_session_cb so needs to know about
+ * session timeout events
+ * - SSL_OP_NO_TICKET is set in which case it is a stateful ticket
+ */
+ if ((i & SSL_SESS_CACHE_NO_INTERNAL_STORE) == 0
+ && (!SSL_IS_TLS13(s)
+ || !s->server
+ || (s->max_early_data > 0
+ && (s->options & SSL_OP_NO_ANTI_REPLAY) == 0)
+ || s->session_ctx->remove_session_cb != NULL
+ || (s->options & SSL_OP_NO_TICKET) != 0))
+ SSL_CTX_add_session(s->session_ctx, s->session);
+
+ /*
+ * Add the session to the external cache. We do this even in server side
+ * TLSv1.3 without early data because some applications just want to
+ * know about the creation of a session and aren't doing a full cache.
+ */
+ if (s->session_ctx->new_session_cb != NULL) {
+ SSL_SESSION_up_ref(s->session);
+ if (!s->session_ctx->new_session_cb(s, s->session))
+ SSL_SESSION_free(s->session);
+ }
}
/* auto flush every 255 connections */
if ((!(i & SSL_SESS_CACHE_NO_AUTO_CLEAR)) && ((i & mode) == mode)) {
- int *stat, val;
+ TSAN_QUALIFIER int *stat;
if (mode & SSL_SESS_CACHE_CLIENT)
stat = &s->session_ctx->stats.sess_connect_good;
else
stat = &s->session_ctx->stats.sess_accept_good;
- if (CRYPTO_atomic_read(stat, &val, s->session_ctx->lock)
- && (val & 0xff) == 0xff)
+ if ((tsan_load(stat) & 0xff) == 0xff)
SSL_CTX_flush_sessions(s->session_ctx, (unsigned long)time(NULL));
}
}
return 1;
s->wbio = BIO_pop(s->wbio);
- if (!ossl_assert(s->wbio != NULL))
- return 0;
BIO_free(s->bbio);
s->bbio = NULL;
return 1;
}
+int SSL_set_num_tickets(SSL *s, size_t num_tickets)
+{
+ s->num_tickets = num_tickets;
+
+ return 1;
+}
+
+size_t SSL_get_num_tickets(SSL *s)
+{
+ return s->num_tickets;
+}
+
+int SSL_CTX_set_num_tickets(SSL_CTX *ctx, size_t num_tickets)
+{
+ ctx->num_tickets = num_tickets;
+
+ return 1;
+}
+
+size_t SSL_CTX_get_num_tickets(SSL_CTX *ctx)
+{
+ return ctx->num_tickets;
+}
+
/*
* 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 (ext->present)
num++;
}
- present = OPENSSL_malloc(sizeof(*present) * num);
- if (present == NULL)
+ if ((present = OPENSSL_malloc(sizeof(*present) * num)) == NULL) {
+ SSLerr(SSL_F_SSL_CLIENT_HELLO_GET1_EXTENSIONS_PRESENT,
+ ERR_R_MALLOC_FAILURE);
return 0;
+ }
for (i = 0; i < s->clienthello->pre_proc_exts_len; i++) {
ext = s->clienthello->pre_proc_exts + i;
if (ext->present) {
return s->max_early_data;
}
+int SSL_CTX_set_recv_max_early_data(SSL_CTX *ctx, uint32_t recv_max_early_data)
+{
+ ctx->recv_max_early_data = recv_max_early_data;
+
+ return 1;
+}
+
+uint32_t SSL_CTX_get_recv_max_early_data(const SSL_CTX *ctx)
+{
+ return ctx->recv_max_early_data;
+}
+
+int SSL_set_recv_max_early_data(SSL *s, uint32_t recv_max_early_data)
+{
+ s->recv_max_early_data = recv_max_early_data;
+
+ return 1;
+}
+
+uint32_t SSL_get_recv_max_early_data(const SSL *s)
+{
+ return s->recv_max_early_data;
+}
+
__owur unsigned int ssl_get_max_send_fragment(const SSL *ssl)
{
/* Return any active Max Fragment Len extension */
return -1;
}
-void SSL_force_post_handshake_auth(SSL *ssl)
+void SSL_set_post_handshake_auth(SSL *ssl, int val)
{
- ssl->pha_forced = 1;
+ ssl->pha_enabled = val;
}
int SSL_verify_client_post_handshake(SSL *ssl)
ctx->ticket_cb_data = arg;
return 1;
}
+
+void SSL_CTX_set_allow_early_data_cb(SSL_CTX *ctx,
+ SSL_allow_early_data_cb_fn cb,
+ void *arg)
+{
+ ctx->allow_early_data_cb = cb;
+ ctx->allow_early_data_cb_data = arg;
+}
+
+void SSL_set_allow_early_data_cb(SSL *s,
+ SSL_allow_early_data_cb_fn cb,
+ void *arg)
+{
+ s->allow_early_data_cb = cb;
+ s->allow_early_data_cb_data = arg;
+}