Improvements in OpenSSL Compat ERR Queue handling.

Configuration
- thread-local storaoge is selected when available
- '--enable-error-queue-per-thread' and '--disable-error-queue-per-thread' can
  be used as before to explicitly en-/disable the feature.

Implementation:
- with thread-local-storage, error queue is realized in one struct without
  allocations. Queue size is restricted to 16 entries (per thread), which
  is the same limit in OpenSSL 1.1.x.
- without thread-local-storage, all error queue operations are mutex locked
- wc_PeekErrorNodeLineData() and wc_GetErrorNodeErr() added for use by SSL
  functions to allow locked queue iterations/manipulations.
This commit is contained in:
Stefan Eissing 2022-12-07 18:14:45 +01:00
parent f6cb13b11b
commit 45f9ef5dd9
5 changed files with 809 additions and 374 deletions

View File

@ -1629,12 +1629,23 @@ fi
AC_ARG_ENABLE([error-queue-per-thread],
[AS_HELP_STRING([--enable-error-queue-per-thread],[Enable one error queue per thread. Requires thread local storage. (default: disabled)])],
[ ENABLED_ERRORQUEUEPERTHREAD=$enableval ],
[ ENABLED_ERRORQUEUEPERTHREAD=no ]
[ ENABLED_ERRORQUEUEPERTHREAD=check ]
)
if test "$ENABLED_ERRORQUEUEPERTHREAD" = "check"
then
AS_IF([test "$thread_ls_on" = "no"],
[ENABLED_ERRORQUEUEPERTHREAD=no],
[ENABLED_ERRORQUEUEPERTHREAD=yes])
fi
if test "$ENABLED_ERRORQUEUEPERTHREAD" = "yes"
then
AM_CFLAGS="$AM_CFLAGS -DERROR_QUEUE_PER_THREAD"
if test "$thread_ls_on" != "yes"
then
AC_MSG_ERROR(error-queue-per-thread needs thread-local storage.)
fi
AM_CFLAGS="$AM_CFLAGS -DERROR_QUEUE_PER_THREAD"
fi
# High Strength Build
@ -8831,6 +8842,7 @@ echo " * NXP SE050: $ENABLED_SE050"
echo " * Maxim Integrated MAXQ10XX: $ENABLED_MAXQ10XX"
echo " * PSA: $ENABLED_PSA"
echo " * System CA certs: $ENABLED_SYS_CA_CERTS"
echo " * ERR Queues per Thread: $ENABLED_ERRORQUEUEPERTHREAD"
echo ""
echo "---"

124
src/ssl.c
View File

@ -17045,51 +17045,12 @@ cleanup:
unsigned long wolfSSL_ERR_get_error(void)
{
int ret;
WOLFSSL_ENTER("wolfSSL_ERR_get_error");
#ifdef WOLFSSL_HAVE_ERROR_QUEUE
ret = wc_PullErrorNode(NULL, NULL, NULL);
if (ret < 0) {
if (ret == BAD_STATE_E) {
ret = 0; /* no errors in queue */
}
else {
WOLFSSL_MSG("Error with pulling error node!");
WOLFSSL_LEAVE("wolfSSL_ERR_get_error", ret);
ret = 0 - ret; /* return absolute value of error */
/* panic and try to clear out nodes */
wc_ClearErrorNodes();
}
}
else {
int idx = wc_GetCurrentIdx();
if (idx < 0) {
WOLFSSL_MSG("Error with getting current index!");
ret = BAD_STATE_E;
WOLFSSL_LEAVE("wolfSSL_ERR_get_error", ret);
/* panic and try to clear out nodes and reset queue state */
wc_ClearErrorNodes();
}
else if (idx > 0) {
idx -= 1;
wc_RemoveErrorNode(idx);
}
else {
/* if current idx is 0 then the queue only had one node */
wc_RemoveErrorNode(idx);
}
}
return ret;
return wc_GetErrorNodeErr();
#else
(void)ret;
return (unsigned long)(0 - NOT_COMPILED_IN);
#endif /* WOLFSSL_HAVE_ERROR_QUEUE */
#endif
}
#ifdef WOLFSSL_HAVE_ERROR_QUEUE
@ -33220,63 +33181,42 @@ int wolfSSL_AsyncPoll(WOLFSSL* ssl, WOLF_EVENT_FLAG flags)
#endif /* WOLFSSL_ASYNC_CRYPT */
#ifdef OPENSSL_EXTRA
static int peek_ignore_err(int err)
{
switch(err) {
case -WANT_READ:
case -WANT_WRITE:
case -ZERO_RETURN:
case -WOLFSSL_ERROR_ZERO_RETURN:
case -SOCKET_PEER_CLOSED_E:
case -SOCKET_ERROR_E:
return 1;
default:
return 0;
}
}
unsigned long wolfSSL_ERR_peek_error_line_data(const char **file, int *line,
const char **data, int *flags)
{
unsigned long err;
WOLFSSL_ENTER("wolfSSL_ERR_peek_error_line_data");
err = wc_PeekErrorNodeLineData(file, line, data, flags, peek_ignore_err);
(void)line;
(void)file;
/* No data or flags stored - error display only in Nginx. */
if (data != NULL) {
*data = "";
}
if (flags != NULL) {
*flags = 0;
}
#ifdef WOLFSSL_HAVE_ERROR_QUEUE
{
int ret = 0;
int idx = wc_GetCurrentIdx();
while (1) {
ret = wc_PeekErrorNode(idx, file, NULL, line);
if (ret == BAD_MUTEX_E || ret == BAD_FUNC_ARG || ret == BAD_STATE_E) {
WOLFSSL_MSG("Issue peeking at error node in queue");
return 0;
}
/* OpenSSL uses positive error codes */
if (ret < 0) {
ret = -ret;
}
if (ret == -ASN_NO_PEM_HEADER)
return (ERR_LIB_PEM << 24) | PEM_R_NO_START_LINE;
#ifdef OPENSSL_ALL
/* PARSE_ERROR is returned if an HTTP request is detected. */
if (ret == -SSL_R_HTTP_REQUEST)
return (ERR_LIB_SSL << 24) | -SSL_R_HTTP_REQUEST;
#endif
#if defined(OPENSSL_ALL) && defined(WOLFSSL_PYTHON)
if (ret == ASN1_R_HEADER_TOO_LONG) {
return (ERR_LIB_ASN1 << 24) | ASN1_R_HEADER_TOO_LONG;
}
#endif
if (ret != -WANT_READ && ret != -WANT_WRITE &&
ret != -ZERO_RETURN && ret != -WOLFSSL_ERROR_ZERO_RETURN &&
ret != -SOCKET_PEER_CLOSED_E && ret != -SOCKET_ERROR_E)
break;
wc_RemoveErrorNode(idx);
}
return (unsigned long)ret;
}
#else
return (unsigned long)(0 - NOT_COMPILED_IN);
if (err == -ASN_NO_PEM_HEADER)
return (ERR_LIB_PEM << 24) | PEM_R_NO_START_LINE;
#ifdef OPENSSL_ALL
/* PARSE_ERROR is returned if an HTTP request is detected. */
else if (err == -SSL_R_HTTP_REQUEST)
return (ERR_LIB_SSL << 24) | -SSL_R_HTTP_REQUEST;
#endif
#if defined(OPENSSL_ALL) && defined(WOLFSSL_PYTHON)
else if (ret == ASN1_R_HEADER_TOO_LONG)
return (ERR_LIB_ASN1 << 24) | ASN1_R_HEADER_TOO_LONG;
#endif
return err;
}
#endif

View File

@ -35234,6 +35234,13 @@ static void post_auth_version_cb(WOLFSSL* ssl)
/* do handshake and then test version error */
AssertIntEQ(wolfSSL_accept(ssl), WOLFSSL_SUCCESS);
AssertStrEQ("TLSv1.2", wolfSSL_get_version(ssl));
}
static void post_auth_version_client_cb(WOLFSSL* ssl)
{
/* do handshake and then test version error */
AssertIntEQ(wolfSSL_connect(ssl), WOLFSSL_SUCCESS);
AssertStrEQ("TLSv1.2", wolfSSL_get_version(ssl));
AssertIntEQ(wolfSSL_verify_client_post_handshake(ssl), WOLFSSL_FAILURE);
#if defined(OPENSSL_ALL) && !defined(NO_ERROR_QUEUE)
/* check was added to error queue */
@ -35299,8 +35306,9 @@ static int test_wolfSSL_Tls13_postauth(void)
XMEMSET(&client_cbf, 0, sizeof(callback_functions));
server_cbf.method = wolfTLSv1_2_server_method;
server_cbf.ssl_ready = set_post_auth_cb;
client_cbf.ssl_ready = set_post_auth_cb;
server_cbf.on_result = post_auth_version_cb;
client_cbf.ssl_ready = set_post_auth_cb;
client_cbf.on_result = post_auth_version_client_cb;
server_args.callbacks = &server_cbf;
client_args.callbacks = &client_cbf;
@ -35316,6 +35324,7 @@ static int test_wolfSSL_Tls13_postauth(void)
server_cbf.ssl_ready = set_post_auth_cb;
client_cbf.ssl_ready = set_post_auth_cb;
server_cbf.on_result = post_auth_cb;
client_cbf.on_result = NULL;
server_args.callbacks = &server_cbf;
client_args.callbacks = &client_cbf;
@ -38731,12 +38740,22 @@ static int test_wolfSSL_PKCS8_d2i(void)
defined(OPENSSL_EXTRA) && defined(DEBUG_WOLFSSL)
#define LOGGING_THREADS 5
#define ERROR_COUNT 10
/* copied from logging.c since this is not exposed otherwise */
#ifndef ERROR_QUEUE_MAX
#ifdef ERROR_QUEUE_PER_THREAD
#define ERROR_QUEUE_MAX 16
#else
/* this breaks from compat of unlimited error queue size */
#define ERROR_QUEUE_MAX 100
#endif
#endif
static volatile int loggingThreadsReady;
static THREAD_RETURN WOLFSSL_THREAD test_logging(void* args)
{
const char* file;
int line;
int err;
unsigned long err;
int errorCount = 0;
int i;
@ -38753,6 +38772,7 @@ static THREAD_RETURN WOLFSSL_THREAD test_logging(void* args)
AssertIntEQ(errorCount, ERROR_COUNT);
/* test max queue behavior, trying to add an arbitrary 3 errors over */
ERR_clear_error(); /* ERR_get_error_line() does not remove */
errorCount = 0;
for (i = 0; i < ERROR_QUEUE_MAX + 3; i++)
ERR_put_error(ERR_LIB_PEM, SYS_F_ACCEPT, -990 - i, __FILE__, __LINE__);

File diff suppressed because it is too large Load Diff

View File

@ -122,9 +122,12 @@ WOLFSSL_API void wolfSSL_Debugging_OFF(void);
WOLFSSL_LOCAL void wc_ClearErrorNodes(void);
WOLFSSL_LOCAL int wc_PullErrorNode(const char **file, const char **reason,
int *line);
WOLFSSL_LOCAL int wc_GetCurrentIdx(void);
WOLFSSL_API int wc_SetLoggingHeap(void* h);
WOLFSSL_API int wc_ERR_remove_state(void);
WOLFSSL_LOCAL unsigned long wc_PeekErrorNodeLineData(
const char **file, int *line, const char **data, int *flags,
int (*ignore_err)(int err));
WOLFSSL_LOCAL unsigned long wc_GetErrorNodeErr(void);
#if !defined(NO_FILESYSTEM) && !defined(NO_STDIO_FILESYSTEM)
WOLFSSL_API void wc_ERR_print_errors_fp(XFILE fp);
WOLFSSL_API void wc_ERR_print_errors_cb(int (*cb)(const char *str,