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