openssl/test/handshake-memfail.c

189 lines
5.2 KiB
C

/*
* Copyright 2025 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <stdio.h>
#include <string.h>
#include <openssl/crypto.h>
#include <openssl/ssl.h>
#include "helpers/ssltestlib.h"
#include "testutil.h"
/**
* @brief Global static variables for certificate and key handling.
*
* These variables store the paths and context used for managing
* certificates and private keys in the application.
*
* - certsdir: Directory containing trusted certificates.
* - cert: Path to the certificate file in use.
* - privkey: Path to the private key file.
* - mcount: Number of mallocs counted
* - rcount: Number of reallocs counted
* - fcount: Number of frees counted
* - scount: Number of mallocs counted prior to workload
*/
static char *cert = NULL;
static char *privkey = NULL;
static int mcount, rcount, fcount, scount;
/**
* @brief Performs an SSL/TLS handshake between a test client and server.
*
* This function sets up SSL/TLS contexts and objects for both client and
* server, then initiates a handshake to verify successful connection
* establishment. It is intended for use in testing scenarios to validate
* handshake behavior using specified certificates and keys.
*
* @return 1 on successful handshake, 0 on failure.
*
* @note The function uses @c TEST_true() macros to validate intermediate
* steps. All SSL objects and contexts are freed before returning.
*/
static int do_handshake(OSSL_LIB_CTX *libctx)
{
SSL_CTX *cctx = NULL, *sctx = NULL;
SSL *clientssl = NULL, *serverssl = NULL;
int testresult = 0;
if (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(),
TLS_client_method(),
TLS1_VERSION, 0,
&sctx, &cctx, cert, privkey)))
return 0;
/* Now do a handshake */
if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl,
&clientssl, NULL, NULL))
|| !TEST_true(create_ssl_connection(serverssl, clientssl,
SSL_ERROR_NONE)))
goto end;
testresult = 1;
end:
SSL_free(serverssl);
SSL_free(clientssl);
SSL_CTX_free(sctx);
SSL_CTX_free(cctx);
return testresult;
}
/**
* @brief run our workload to count the number of allocations we make.
*
* Creates a new OpenSSL library context and performs a test SSL/TLS
* handshake. The number of malloc operations is recorded and printed for
* diagnostic purposes.
*
* @return 1 if the handshake succeeds, 0 otherwise.
*/
static int test_record_alloc_counts(void)
{
int ret;
OSSL_LIB_CTX *libctx;
libctx = OSSL_LIB_CTX_new();
if (!TEST_ptr(libctx))
return 0;
ret = do_handshake(libctx);
OSSL_LIB_CTX_free(libctx);
libctx = NULL;
return ret;
}
/**
* @brief run our workload to count the number of allocations we make.
*
* Creates a new OpenSSL library context and performs a test SSL/TLS
* handshake.
*
* Note this is exactly the same as test_record_alloc_counts with 1 difference
* The test always returns 1. We do this because with allocation failures
* in effect, we can't expect things to work, so we always return success
* so that the test keeps running.
*/
static int test_alloc_failures(void)
{
OSSL_LIB_CTX *libctx;
libctx = OSSL_LIB_CTX_new();
if (!TEST_ptr(libctx))
return 1;
do_handshake(libctx);
OSSL_LIB_CTX_free(libctx);
libctx = NULL;
return 1;
}
static int test_report_alloc_counts(void)
{
CRYPTO_get_alloc_counts(&mcount, &rcount, &fcount);
/*
* Report our memory allocations from the count run
* NOTE: We report a number of allocations to skip here
* (the scount value). These are the allocations that took
* place while the test harness itself was getting setup
* (i.e. calling OPENSSL_init_crypto/etc). We can't fail
* those allocations as they will cause the test to fail before
* we have even run the workload. So report them so we can
* allow them to function before we start doing any real testing
*/
TEST_info("skip: %d count %d\n", scount, mcount - scount);
return 1;
}
int setup_tests(void)
{
char *opmode = NULL;
char *certsdir = NULL;
if (!TEST_ptr(opmode = test_get_argument(0)))
goto err;
if (!TEST_ptr(certsdir = test_get_argument(1)))
goto err;
cert = test_mk_file_path(certsdir, "servercert.pem");
if (cert == NULL)
goto err;
privkey = test_mk_file_path(certsdir, "serverkey.pem");
if (privkey == NULL)
goto err;
if (strcmp(opmode, "count") == 0) {
CRYPTO_get_alloc_counts(&scount, &rcount, &fcount);
ADD_TEST(test_record_alloc_counts);
ADD_TEST(test_report_alloc_counts);
} else {
ADD_TEST(test_alloc_failures);
}
return 1;
err:
OPENSSL_free(cert);
OPENSSL_free(privkey);
return 0;
}
void cleanup_tests(void)
{
OPENSSL_free(cert);
OPENSSL_free(privkey);
}