aboutsummaryrefslogtreecommitdiff
path: root/ssl/ssl_lib.c
diff options
context:
space:
mode:
Diffstat (limited to 'ssl/ssl_lib.c')
-rw-r--r--ssl/ssl_lib.c103
1 files changed, 87 insertions, 16 deletions
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 98057921f840..47adc3211c85 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -1,5 +1,5 @@
/*
- * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved.
* Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved
* Copyright 2005 Nokia. All rights reserved.
*
@@ -779,8 +779,10 @@ SSL *SSL_new(SSL_CTX *ctx)
s->ext.ecpointformats =
OPENSSL_memdup(ctx->ext.ecpointformats,
ctx->ext.ecpointformats_len);
- if (!s->ext.ecpointformats)
+ if (!s->ext.ecpointformats) {
+ s->ext.ecpointformats_len = 0;
goto err;
+ }
s->ext.ecpointformats_len =
ctx->ext.ecpointformats_len;
}
@@ -789,8 +791,10 @@ SSL *SSL_new(SSL_CTX *ctx)
OPENSSL_memdup(ctx->ext.supportedgroups,
ctx->ext.supportedgroups_len
* sizeof(*ctx->ext.supportedgroups));
- if (!s->ext.supportedgroups)
+ if (!s->ext.supportedgroups) {
+ s->ext.supportedgroups_len = 0;
goto err;
+ }
s->ext.supportedgroups_len = ctx->ext.supportedgroups_len;
}
#endif
@@ -800,8 +804,10 @@ SSL *SSL_new(SSL_CTX *ctx)
if (s->ctx->ext.alpn) {
s->ext.alpn = OPENSSL_malloc(s->ctx->ext.alpn_len);
- if (s->ext.alpn == NULL)
+ if (s->ext.alpn == NULL) {
+ s->ext.alpn_len = 0;
goto err;
+ }
memcpy(s->ext.alpn, s->ctx->ext.alpn, s->ctx->ext.alpn_len);
s->ext.alpn_len = s->ctx->ext.alpn_len;
}
@@ -1504,12 +1510,26 @@ int SSL_has_pending(const SSL *s)
{
/*
* Similar to SSL_pending() but returns a 1 to indicate that we have
- * unprocessed data available or 0 otherwise (as opposed to the number of
- * bytes available). Unlike SSL_pending() this will take into account
- * read_ahead data. A 1 return simply indicates that we have unprocessed
- * data. That data may not result in any application data, or we may fail
- * to parse the records for some reason.
+ * processed or unprocessed data available or 0 otherwise (as opposed to the
+ * number of bytes available). Unlike SSL_pending() this will take into
+ * account read_ahead data. A 1 return simply indicates that we have data.
+ * That data may not result in any application data, or we may fail to parse
+ * the records for some reason.
*/
+
+ /* Check buffered app data if any first */
+ if (SSL_IS_DTLS(s)) {
+ DTLS1_RECORD_DATA *rdata;
+ pitem *item, *iter;
+
+ iter = pqueue_iterator(s->rlayer.d->buffered_app_data.q);
+ while ((item = pqueue_next(&iter)) != NULL) {
+ rdata = item->data;
+ if (rdata->rrec.length > 0)
+ return 1;
+ }
+ }
+
if (RECORD_LAYER_processed_read_pending(&s->rlayer))
return 1;
@@ -1678,6 +1698,8 @@ static int ssl_start_async_job(SSL *s, struct ssl_async_args *args,
if (s->waitctx == NULL)
return -1;
}
+
+ s->rwstate = SSL_NOTHING;
switch (ASYNC_start_job(&s->job, s->waitctx, &ret, func, args,
sizeof(struct ssl_async_args))) {
case ASYNC_ERR:
@@ -2076,6 +2098,7 @@ int SSL_shutdown(SSL *s)
if ((s->mode & SSL_MODE_ASYNC) && ASYNC_get_current_job() == NULL) {
struct ssl_async_args args;
+ memset(&args, 0, sizeof(args));
args.s = s;
args.type = OTHERFUNC;
args.f.func_other = s->method->ssl_shutdown;
@@ -2113,6 +2136,11 @@ int SSL_key_update(SSL *s, int updatetype)
return 0;
}
+ if (RECORD_LAYER_write_pending(&s->rlayer)) {
+ SSLerr(SSL_F_SSL_KEY_UPDATE, SSL_R_BAD_WRITE_RETRY);
+ return 0;
+ }
+
ossl_statem_set_in_init(s, 1);
s->key_update = updatetype;
return 1;
@@ -2823,6 +2851,19 @@ void SSL_CTX_set_npn_select_cb(SSL_CTX *ctx,
}
#endif
+static int alpn_value_ok(const unsigned char *protos, unsigned int protos_len)
+{
+ unsigned int idx;
+
+ if (protos_len < 2 || protos == NULL)
+ return 0;
+
+ for (idx = 0; idx < protos_len; idx += protos[idx] + 1) {
+ if (protos[idx] == 0)
+ return 0;
+ }
+ return idx == protos_len;
+}
/*
* SSL_CTX_set_alpn_protos sets the ALPN protocol list on |ctx| to |protos|.
* |protos| must be in wire-format (i.e. a series of non-empty, 8-bit
@@ -2831,12 +2872,25 @@ void SSL_CTX_set_npn_select_cb(SSL_CTX *ctx,
int SSL_CTX_set_alpn_protos(SSL_CTX *ctx, const unsigned char *protos,
unsigned int protos_len)
{
- OPENSSL_free(ctx->ext.alpn);
- ctx->ext.alpn = OPENSSL_memdup(protos, protos_len);
- if (ctx->ext.alpn == NULL) {
+ unsigned char *alpn;
+
+ if (protos_len == 0 || protos == NULL) {
+ OPENSSL_free(ctx->ext.alpn);
+ ctx->ext.alpn = NULL;
+ ctx->ext.alpn_len = 0;
+ return 0;
+ }
+ /* Not valid per RFC */
+ if (!alpn_value_ok(protos, protos_len))
+ return 1;
+
+ alpn = OPENSSL_memdup(protos, protos_len);
+ if (alpn == NULL) {
SSLerr(SSL_F_SSL_CTX_SET_ALPN_PROTOS, ERR_R_MALLOC_FAILURE);
return 1;
}
+ OPENSSL_free(ctx->ext.alpn);
+ ctx->ext.alpn = alpn;
ctx->ext.alpn_len = protos_len;
return 0;
@@ -2850,12 +2904,25 @@ int SSL_CTX_set_alpn_protos(SSL_CTX *ctx, const unsigned char *protos,
int SSL_set_alpn_protos(SSL *ssl, const unsigned char *protos,
unsigned int protos_len)
{
- OPENSSL_free(ssl->ext.alpn);
- ssl->ext.alpn = OPENSSL_memdup(protos, protos_len);
- if (ssl->ext.alpn == NULL) {
+ unsigned char *alpn;
+
+ if (protos_len == 0 || protos == NULL) {
+ OPENSSL_free(ssl->ext.alpn);
+ ssl->ext.alpn = NULL;
+ ssl->ext.alpn_len = 0;
+ return 0;
+ }
+ /* Not valid per RFC */
+ if (!alpn_value_ok(protos, protos_len))
+ return 1;
+
+ alpn = OPENSSL_memdup(protos, protos_len);
+ if (alpn == NULL) {
SSLerr(SSL_F_SSL_SET_ALPN_PROTOS, ERR_R_MALLOC_FAILURE);
return 1;
}
+ OPENSSL_free(ssl->ext.alpn);
+ ssl->ext.alpn = alpn;
ssl->ext.alpn_len = protos_len;
return 0;
@@ -3657,6 +3724,7 @@ int SSL_do_handshake(SSL *s)
if ((s->mode & SSL_MODE_ASYNC) && ASYNC_get_current_job() == NULL) {
struct ssl_async_args args;
+ memset(&args, 0, sizeof(args));
args.s = s;
ret = ssl_start_async_job(s, &args, ssl_do_handshake_intern);
@@ -4512,8 +4580,11 @@ int ssl_handshake_hash(SSL *s, unsigned char *out, size_t outlen,
}
ctx = EVP_MD_CTX_new();
- if (ctx == NULL)
+ if (ctx == NULL) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_HANDSHAKE_HASH,
+ ERR_R_INTERNAL_ERROR);
goto err;
+ }
if (!EVP_MD_CTX_copy_ex(ctx, hdgst)
|| EVP_DigestFinal_ex(ctx, out, NULL) <= 0) {