1 /*
2 * Copyright 2025 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License 2.0 (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
8 */
9
10 #include <stdio.h>
11 #include <string.h>
12
13 #include <openssl/crypto.h>
14 #include <openssl/ssl.h>
15
16 #include "helpers/ssltestlib.h"
17 #include "testutil.h"
18
19 /**
20 * @brief Global static variables for certificate and key handling.
21 *
22 * These variables store the paths and context used for managing
23 * certificates and private keys in the application.
24 *
25 * - certsdir: Directory containing trusted certificates.
26 * - cert: Path to the certificate file in use.
27 * - privkey: Path to the private key file.
28 * - mcount: Number of mallocs counted
29 * - rcount: Number of reallocs counted
30 * - fcount: Number of frees counted
31 * - scount: Number of mallocs counted prior to workload
32 */
33 static char *cert = NULL;
34 static char *privkey = NULL;
35 static int mcount, rcount, fcount, scount;
36
37 /**
38 * @brief Performs an SSL/TLS handshake between a test client and server.
39 *
40 * This function sets up SSL/TLS contexts and objects for both client and
41 * server, then initiates a handshake to verify successful connection
42 * establishment. It is intended for use in testing scenarios to validate
43 * handshake behavior using specified certificates and keys.
44 *
45 * @return 1 on successful handshake, 0 on failure.
46 *
47 * @note The function uses @c TEST_true() macros to validate intermediate
48 * steps. All SSL objects and contexts are freed before returning.
49 */
do_handshake(OSSL_LIB_CTX * libctx)50 static int do_handshake(OSSL_LIB_CTX *libctx)
51 {
52 SSL_CTX *cctx = NULL, *sctx = NULL;
53 SSL *clientssl = NULL, *serverssl = NULL;
54 int testresult = 0;
55
56 if (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(),
57 TLS_client_method(),
58 TLS1_VERSION, 0,
59 &sctx, &cctx, cert, privkey)))
60 return 0;
61
62 /* Now do a handshake */
63 if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl,
64 &clientssl, NULL, NULL))
65 || !TEST_true(create_ssl_connection(serverssl, clientssl,
66 SSL_ERROR_NONE)))
67 goto end;
68
69 testresult = 1;
70
71 end:
72 SSL_free(serverssl);
73 SSL_free(clientssl);
74 SSL_CTX_free(sctx);
75 SSL_CTX_free(cctx);
76
77 return testresult;
78 }
79
80 /**
81 * @brief run our workload to count the number of allocations we make.
82 *
83 * Creates a new OpenSSL library context and performs a test SSL/TLS
84 * handshake. The number of malloc operations is recorded and printed for
85 * diagnostic purposes.
86 *
87 * @return 1 if the handshake succeeds, 0 otherwise.
88 */
test_record_alloc_counts(void)89 static int test_record_alloc_counts(void)
90 {
91 int ret;
92 OSSL_LIB_CTX *libctx;
93
94 libctx = OSSL_LIB_CTX_new();
95 if (!TEST_ptr(libctx))
96 return 0;
97
98 ret = do_handshake(libctx);
99
100 OSSL_LIB_CTX_free(libctx);
101 libctx = NULL;
102
103 return ret;
104 }
105
106 /**
107 * @brief run our workload to count the number of allocations we make.
108 *
109 * Creates a new OpenSSL library context and performs a test SSL/TLS
110 * handshake.
111 *
112 * Note this is exactly the same as test_record_alloc_counts with 1 difference
113 * The test always returns 1. We do this because with allocation failures
114 * in effect, we can't expect things to work, so we always return success
115 * so that the test keeps running.
116 */
test_alloc_failures(void)117 static int test_alloc_failures(void)
118 {
119 OSSL_LIB_CTX *libctx;
120
121 libctx = OSSL_LIB_CTX_new();
122 if (!TEST_ptr(libctx))
123 return 1;
124
125 do_handshake(libctx);
126
127 OSSL_LIB_CTX_free(libctx);
128 libctx = NULL;
129
130 return 1;
131 }
132
test_report_alloc_counts(void)133 static int test_report_alloc_counts(void)
134 {
135 CRYPTO_get_alloc_counts(&mcount, &rcount, &fcount);
136 /*
137 * Report our memory allocations from the count run
138 * NOTE: We report a number of allocations to skip here
139 * (the scount value). These are the allocations that took
140 * place while the test harness itself was getting setup
141 * (i.e. calling OPENSSL_init_crypto/etc). We can't fail
142 * those allocations as they will cause the test to fail before
143 * we have even run the workload. So report them so we can
144 * allow them to function before we start doing any real testing
145 */
146 TEST_info("skip: %d count %d\n", scount, mcount - scount);
147 return 1;
148 }
149
setup_tests(void)150 int setup_tests(void)
151 {
152 char *opmode = NULL;
153 char *certsdir = NULL;
154
155 if (!TEST_ptr(opmode = test_get_argument(0)))
156 goto err;
157
158 if (!TEST_ptr(certsdir = test_get_argument(1)))
159 goto err;
160
161 cert = test_mk_file_path(certsdir, "servercert.pem");
162 if (cert == NULL)
163 goto err;
164
165 privkey = test_mk_file_path(certsdir, "serverkey.pem");
166 if (privkey == NULL)
167 goto err;
168
169 if (strcmp(opmode, "count") == 0) {
170 CRYPTO_get_alloc_counts(&scount, &rcount, &fcount);
171 ADD_TEST(test_record_alloc_counts);
172 ADD_TEST(test_report_alloc_counts);
173 } else {
174 ADD_TEST(test_alloc_failures);
175 }
176 return 1;
177
178 err:
179 OPENSSL_free(cert);
180 OPENSSL_free(privkey);
181 return 0;
182 }
183
cleanup_tests(void)184 void cleanup_tests(void)
185 {
186 OPENSSL_free(cert);
187 OPENSSL_free(privkey);
188 }
189