diff options
Diffstat (limited to 'meta/recipes-connectivity/openssl/openssl/0001-Added-handshake-history-reporting-when-test-fails.patch')
-rw-r--r-- | meta/recipes-connectivity/openssl/openssl/0001-Added-handshake-history-reporting-when-test-fails.patch | 367 |
1 files changed, 367 insertions, 0 deletions
diff --git a/meta/recipes-connectivity/openssl/openssl/0001-Added-handshake-history-reporting-when-test-fails.patch b/meta/recipes-connectivity/openssl/openssl/0001-Added-handshake-history-reporting-when-test-fails.patch new file mode 100644 index 0000000000..5b7365a353 --- /dev/null +++ b/meta/recipes-connectivity/openssl/openssl/0001-Added-handshake-history-reporting-when-test-fails.patch | |||
@@ -0,0 +1,367 @@ | |||
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 | @@ -25,6 +25,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 | @@ -726,15 +822,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 | @@ -1081,17 +1168,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 | @@ -1169,19 +1245,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 | @@ -1546,6 +1609,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 | @@ -1567,6 +1634,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 | |||