]> git.ipfire.org Git - thirdparty/openembedded/openembedded-core-contrib.git/blob
31bbbd86790db6d3237244503f956806980944e7
[thirdparty/openembedded/openembedded-core-contrib.git] /
1 From 5ba65051fea0513db0d997f0ab7cafb9826ed74a Mon Sep 17 00:00:00 2001
2 From: William Lyu <William.Lyu@windriver.com>
3 Date: Fri, 20 Oct 2023 16:22:37 -0400
4 Subject: [PATCH] Added handshake history reporting when test fails
5
6 Upstream-Status: Submitted [https://github.com/openssl/openssl/pull/22481]
7
8 Signed-off-by: William Lyu <William.Lyu@windriver.com>
9 ---
10 test/helpers/handshake.c | 137 +++++++++++++++++++++++++++++----------
11 test/helpers/handshake.h | 70 +++++++++++++++++++-
12 test/ssl_test.c | 44 +++++++++++++
13 3 files changed, 217 insertions(+), 34 deletions(-)
14
15 diff --git a/test/helpers/handshake.c b/test/helpers/handshake.c
16 index f611b3a..5703b48 100644
17 --- a/test/helpers/handshake.c
18 +++ b/test/helpers/handshake.c
19 @@ -24,6 +24,102 @@
20 #include <netinet/sctp.h>
21 #endif
22
23 +/* Shamelessly copied from test/helpers/ssl_test_ctx.c */
24 +/* Maps string names to various enumeration type */
25 +typedef struct {
26 + const char *name;
27 + int value;
28 +} enum_name_map;
29 +
30 +static const enum_name_map connect_phase_names[] = {
31 + {"Handshake", HANDSHAKE},
32 + {"RenegAppData", RENEG_APPLICATION_DATA},
33 + {"RenegSetup", RENEG_SETUP},
34 + {"RenegHandshake", RENEG_HANDSHAKE},
35 + {"AppData", APPLICATION_DATA},
36 + {"Shutdown", SHUTDOWN},
37 + {"ConnectionDone", CONNECTION_DONE}
38 +};
39 +
40 +static const enum_name_map peer_status_names[] = {
41 + {"PeerSuccess", PEER_SUCCESS},
42 + {"PeerRetry", PEER_RETRY},
43 + {"PeerError", PEER_ERROR},
44 + {"PeerWaiting", PEER_WAITING},
45 + {"PeerTestFail", PEER_TEST_FAILURE}
46 +};
47 +
48 +static const enum_name_map handshake_status_names[] = {
49 + {"HandshakeSuccess", HANDSHAKE_SUCCESS},
50 + {"ClientError", CLIENT_ERROR},
51 + {"ServerError", SERVER_ERROR},
52 + {"InternalError", INTERNAL_ERROR},
53 + {"HandshakeRetry", HANDSHAKE_RETRY}
54 +};
55 +
56 +/* Shamelessly copied from test/helpers/ssl_test_ctx.c */
57 +static const char *enum_name(const enum_name_map *enums, size_t num_enums,
58 + int value)
59 +{
60 + size_t i;
61 + for (i = 0; i < num_enums; i++) {
62 + if (enums[i].value == value) {
63 + return enums[i].name;
64 + }
65 + }
66 + return "InvalidValue";
67 +}
68 +
69 +const char *handshake_connect_phase_name(connect_phase_t phase)
70 +{
71 + return enum_name(connect_phase_names, OSSL_NELEM(connect_phase_names),
72 + (int)phase);
73 +}
74 +
75 +const char *handshake_status_name(handshake_status_t handshake_status)
76 +{
77 + return enum_name(handshake_status_names, OSSL_NELEM(handshake_status_names),
78 + (int)handshake_status);
79 +}
80 +
81 +const char *handshake_peer_status_name(peer_status_t peer_status)
82 +{
83 + return enum_name(peer_status_names, OSSL_NELEM(peer_status_names),
84 + (int)peer_status);
85 +}
86 +
87 +static void save_loop_history(HANDSHAKE_HISTORY *history,
88 + connect_phase_t phase,
89 + handshake_status_t handshake_status,
90 + peer_status_t server_status,
91 + peer_status_t client_status,
92 + int client_turn_count,
93 + int is_client_turn)
94 +{
95 + HANDSHAKE_HISTORY_ENTRY *new_entry = NULL;
96 +
97 + /*
98 + * Create a new history entry for a handshake loop with statuses given in
99 + * the arguments. Potentially evicting the oldest entry when the
100 + * ring buffer is full.
101 + */
102 + ++(history->last_idx);
103 + history->last_idx &= MAX_HANDSHAKE_HISTORY_ENTRY_IDX_MASK;
104 +
105 + new_entry = &((history->entries)[history->last_idx]);
106 + new_entry->phase = phase;
107 + new_entry->handshake_status = handshake_status;
108 + new_entry->server_status = server_status;
109 + new_entry->client_status = client_status;
110 + new_entry->client_turn_count = client_turn_count;
111 + new_entry->is_client_turn = is_client_turn;
112 +
113 + /* Evict the oldest handshake loop entry when the ring buffer is full. */
114 + if (history->entry_count < MAX_HANDSHAKE_HISTORY_ENTRY) {
115 + ++(history->entry_count);
116 + }
117 +}
118 +
119 HANDSHAKE_RESULT *HANDSHAKE_RESULT_new(void)
120 {
121 HANDSHAKE_RESULT *ret;
122 @@ -725,15 +821,6 @@ static void configure_handshake_ssl(SSL *server, SSL *client,
123 SSL_set_post_handshake_auth(client, 1);
124 }
125
126 -/* The status for each connection phase. */
127 -typedef enum {
128 - PEER_SUCCESS,
129 - PEER_RETRY,
130 - PEER_ERROR,
131 - PEER_WAITING,
132 - PEER_TEST_FAILURE
133 -} peer_status_t;
134 -
135 /* An SSL object and associated read-write buffers. */
136 typedef struct peer_st {
137 SSL *ssl;
138 @@ -1080,17 +1167,6 @@ static void do_shutdown_step(PEER *peer)
139 }
140 }
141
142 -typedef enum {
143 - HANDSHAKE,
144 - RENEG_APPLICATION_DATA,
145 - RENEG_SETUP,
146 - RENEG_HANDSHAKE,
147 - APPLICATION_DATA,
148 - SHUTDOWN,
149 - CONNECTION_DONE
150 -} connect_phase_t;
151 -
152 -
153 static int renegotiate_op(const SSL_TEST_CTX *test_ctx)
154 {
155 switch (test_ctx->handshake_mode) {
156 @@ -1168,19 +1244,6 @@ static void do_connect_step(const SSL_TEST_CTX *test_ctx, PEER *peer,
157 }
158 }
159
160 -typedef enum {
161 - /* Both parties succeeded. */
162 - HANDSHAKE_SUCCESS,
163 - /* Client errored. */
164 - CLIENT_ERROR,
165 - /* Server errored. */
166 - SERVER_ERROR,
167 - /* Peers are in inconsistent state. */
168 - INTERNAL_ERROR,
169 - /* One or both peers not done. */
170 - HANDSHAKE_RETRY
171 -} handshake_status_t;
172 -
173 /*
174 * Determine the handshake outcome.
175 * last_status: the status of the peer to have acted last.
176 @@ -1545,6 +1608,10 @@ static HANDSHAKE_RESULT *do_handshake_internal(
177
178 start = time(NULL);
179
180 + save_loop_history(&(ret->history),
181 + phase, status, server.status, client.status,
182 + client_turn_count, client_turn);
183 +
184 /*
185 * Half-duplex handshake loop.
186 * Client and server speak to each other synchronously in the same process.
187 @@ -1566,6 +1633,10 @@ static HANDSHAKE_RESULT *do_handshake_internal(
188 0 /* server went last */);
189 }
190
191 + save_loop_history(&(ret->history),
192 + phase, status, server.status, client.status,
193 + client_turn_count, client_turn);
194 +
195 switch (status) {
196 case HANDSHAKE_SUCCESS:
197 client_turn_count = 0;
198 diff --git a/test/helpers/handshake.h b/test/helpers/handshake.h
199 index 78b03f9..b9967c2 100644
200 --- a/test/helpers/handshake.h
201 +++ b/test/helpers/handshake.h
202 @@ -1,5 +1,5 @@
203 /*
204 - * Copyright 2016-2021 The OpenSSL Project Authors. All Rights Reserved.
205 + * Copyright 2016-2023 The OpenSSL Project Authors. All Rights Reserved.
206 *
207 * Licensed under the Apache License 2.0 (the "License"). You may not use
208 * this file except in compliance with the License. You can obtain a copy
209 @@ -12,6 +12,11 @@
210
211 #include "ssl_test_ctx.h"
212
213 +#define MAX_HANDSHAKE_HISTORY_ENTRY_BIT 4
214 +#define MAX_HANDSHAKE_HISTORY_ENTRY (1 << MAX_HANDSHAKE_HISTORY_ENTRY_BIT)
215 +#define MAX_HANDSHAKE_HISTORY_ENTRY_IDX_MASK \
216 + ((1 << MAX_HANDSHAKE_HISTORY_ENTRY_BIT) - 1)
217 +
218 typedef struct ctx_data_st {
219 unsigned char *npn_protocols;
220 size_t npn_protocols_len;
221 @@ -22,6 +27,63 @@ typedef struct ctx_data_st {
222 char *session_ticket_app_data;
223 } CTX_DATA;
224
225 +typedef enum {
226 + HANDSHAKE,
227 + RENEG_APPLICATION_DATA,
228 + RENEG_SETUP,
229 + RENEG_HANDSHAKE,
230 + APPLICATION_DATA,
231 + SHUTDOWN,
232 + CONNECTION_DONE
233 +} connect_phase_t;
234 +
235 +/* The status for each connection phase. */
236 +typedef enum {
237 + PEER_SUCCESS,
238 + PEER_RETRY,
239 + PEER_ERROR,
240 + PEER_WAITING,
241 + PEER_TEST_FAILURE
242 +} peer_status_t;
243 +
244 +typedef enum {
245 + /* Both parties succeeded. */
246 + HANDSHAKE_SUCCESS,
247 + /* Client errored. */
248 + CLIENT_ERROR,
249 + /* Server errored. */
250 + SERVER_ERROR,
251 + /* Peers are in inconsistent state. */
252 + INTERNAL_ERROR,
253 + /* One or both peers not done. */
254 + HANDSHAKE_RETRY
255 +} handshake_status_t;
256 +
257 +/* Stores the various status information in a handshake loop. */
258 +typedef struct handshake_history_entry_st {
259 + connect_phase_t phase;
260 + handshake_status_t handshake_status;
261 + peer_status_t server_status;
262 + peer_status_t client_status;
263 + int client_turn_count;
264 + int is_client_turn;
265 +} HANDSHAKE_HISTORY_ENTRY;
266 +
267 +typedef struct handshake_history_st {
268 + /* Implemented using ring buffer. */
269 + /*
270 + * The valid entries are |entries[last_idx]|, |entries[last_idx-1]|,
271 + * ..., etc., going up to |entry_count| number of entries. Note that when
272 + * the index into the array |entries| becomes < 0, we wrap around to
273 + * the end of |entries|.
274 + */
275 + HANDSHAKE_HISTORY_ENTRY entries[MAX_HANDSHAKE_HISTORY_ENTRY];
276 + /* The number of valid entries in |entries| array. */
277 + size_t entry_count;
278 + /* The index of the last valid entry in the |entries| array. */
279 + size_t last_idx;
280 +} HANDSHAKE_HISTORY;
281 +
282 typedef struct handshake_result {
283 ssl_test_result_t result;
284 /* These alerts are in the 2-byte format returned by the info_callback. */
285 @@ -77,6 +139,8 @@ typedef struct handshake_result {
286 char *cipher;
287 /* session ticket application data */
288 char *result_session_ticket_app_data;
289 + /* handshake loop history */
290 + HANDSHAKE_HISTORY history;
291 } HANDSHAKE_RESULT;
292
293 HANDSHAKE_RESULT *HANDSHAKE_RESULT_new(void);
294 @@ -95,4 +159,8 @@ int configure_handshake_ctx_for_srp(SSL_CTX *server_ctx, SSL_CTX *server2_ctx,
295 CTX_DATA *server2_ctx_data,
296 CTX_DATA *client_ctx_data);
297
298 +const char *handshake_connect_phase_name(connect_phase_t phase);
299 +const char *handshake_status_name(handshake_status_t handshake_status);
300 +const char *handshake_peer_status_name(peer_status_t peer_status);
301 +
302 #endif /* OSSL_TEST_HANDSHAKE_HELPER_H */
303 diff --git a/test/ssl_test.c b/test/ssl_test.c
304 index ea60851..9d6b093 100644
305 --- a/test/ssl_test.c
306 +++ b/test/ssl_test.c
307 @@ -26,6 +26,44 @@ static OSSL_LIB_CTX *libctx = NULL;
308 /* Currently the section names are of the form test-<number>, e.g. test-15. */
309 #define MAX_TESTCASE_NAME_LENGTH 100
310
311 +static void print_handshake_history(const HANDSHAKE_HISTORY *history)
312 +{
313 + size_t first_idx;
314 + size_t i;
315 + size_t cur_idx;
316 + const HANDSHAKE_HISTORY_ENTRY *cur_entry;
317 + const char header_template[] = "|%14s|%16s|%16s|%16s|%17s|%14s|";
318 + const char body_template[] = "|%14s|%16s|%16s|%16s|%17d|%14s|";
319 +
320 + TEST_info("The following is the server/client state "
321 + "in the most recent %d handshake loops.",
322 + MAX_HANDSHAKE_HISTORY_ENTRY);
323 +
324 + TEST_note("=================================================="
325 + "==================================================");
326 + TEST_note(header_template,
327 + "phase", "handshake status", "server status",
328 + "client status", "client turn count", "is client turn");
329 + TEST_note("+--------------+----------------+----------------"
330 + "+----------------+-----------------+--------------+");
331 +
332 + first_idx = (history->last_idx - history->entry_count + 1) &
333 + MAX_HANDSHAKE_HISTORY_ENTRY_IDX_MASK;
334 + for (i = 0; i < history->entry_count; ++i) {
335 + cur_idx = (first_idx + i) & MAX_HANDSHAKE_HISTORY_ENTRY_IDX_MASK;
336 + cur_entry = &(history->entries)[cur_idx];
337 + TEST_note(body_template,
338 + handshake_connect_phase_name(cur_entry->phase),
339 + handshake_status_name(cur_entry->handshake_status),
340 + handshake_peer_status_name(cur_entry->server_status),
341 + handshake_peer_status_name(cur_entry->client_status),
342 + cur_entry->client_turn_count,
343 + cur_entry->is_client_turn ? "true" : "false");
344 + }
345 + TEST_note("=================================================="
346 + "==================================================");
347 +}
348 +
349 static const char *print_alert(int alert)
350 {
351 return alert ? SSL_alert_desc_string_long(alert) : "no alert";
352 @@ -388,6 +426,12 @@ static int check_test(HANDSHAKE_RESULT *result, SSL_TEST_CTX *test_ctx)
353 ret &= check_client_sign_type(result, test_ctx);
354 ret &= check_client_ca_names(result, test_ctx);
355 }
356 +
357 + /* Print handshake loop history if any check fails. */
358 + if (!ret) {
359 + print_handshake_history(&(result->history));
360 + }
361 +
362 return ret;
363 }
364
365 --
366 2.25.1
367