summaryrefslogtreecommitdiffstats
path: root/meta/recipes-connectivity/openssl/openssl/0001-Added-handshake-history-reporting-when-test-fails.patch
blob: aa2e5bb80056048da7160220e2e0582a80d3c396 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
From 5ba65051fea0513db0d997f0ab7cafb9826ed74a Mon Sep 17 00:00:00 2001
From: William Lyu <William.Lyu@windriver.com>
Date: Fri, 20 Oct 2023 16:22:37 -0400
Subject: [PATCH] Added handshake history reporting when test fails

Upstream-Status: Submitted [https://github.com/openssl/openssl/pull/22481]

Signed-off-by: William Lyu <William.Lyu@windriver.com>
---
 test/helpers/handshake.c | 139 +++++++++++++++++++++++++++++----------
 test/helpers/handshake.h |  70 +++++++++++++++++++-
 test/ssl_test.c          |  44 +++++++++++++
 3 files changed, 218 insertions(+), 35 deletions(-)

diff --git a/test/helpers/handshake.c b/test/helpers/handshake.c
index e0422469e4..ae2ad59dd4 100644
--- a/test/helpers/handshake.c
+++ b/test/helpers/handshake.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2022 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2016-2023 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
@@ -24,6 +24,102 @@
 #include <netinet/sctp.h>
 #endif

+/* Shamelessly copied from test/helpers/ssl_test_ctx.c */
+/* Maps string names to various enumeration type */
+typedef struct {
+    const char *name;
+    int value;
+} enum_name_map;
+
+static const enum_name_map connect_phase_names[] = {
+    {"Handshake", HANDSHAKE},
+    {"RenegAppData", RENEG_APPLICATION_DATA},
+    {"RenegSetup", RENEG_SETUP},
+    {"RenegHandshake", RENEG_HANDSHAKE},
+    {"AppData", APPLICATION_DATA},
+    {"Shutdown", SHUTDOWN},
+    {"ConnectionDone", CONNECTION_DONE}
+};
+
+static const enum_name_map peer_status_names[] = {
+    {"PeerSuccess", PEER_SUCCESS},
+    {"PeerRetry", PEER_RETRY},
+    {"PeerError", PEER_ERROR},
+    {"PeerWaiting", PEER_WAITING},
+    {"PeerTestFail", PEER_TEST_FAILURE}
+};
+
+static const enum_name_map handshake_status_names[] = {
+    {"HandshakeSuccess", HANDSHAKE_SUCCESS},
+    {"ClientError", CLIENT_ERROR},
+    {"ServerError", SERVER_ERROR},
+    {"InternalError", INTERNAL_ERROR},
+    {"HandshakeRetry", HANDSHAKE_RETRY}
+};
+
+/* Shamelessly copied from test/helpers/ssl_test_ctx.c */
+static const char *enum_name(const enum_name_map *enums, size_t num_enums,
+                             int value)
+{
+    size_t i;
+    for (i = 0; i < num_enums; i++) {
+        if (enums[i].value == value) {
+            return enums[i].name;
+        }
+    }
+    return "InvalidValue";
+}
+
+const char *handshake_connect_phase_name(connect_phase_t phase)
+{
+    return enum_name(connect_phase_names, OSSL_NELEM(connect_phase_names),
+                     (int)phase);
+}
+
+const char *handshake_status_name(handshake_status_t handshake_status)
+{
+    return enum_name(handshake_status_names, OSSL_NELEM(handshake_status_names),
+                     (int)handshake_status);
+}
+
+const char *handshake_peer_status_name(peer_status_t peer_status)
+{
+    return enum_name(peer_status_names, OSSL_NELEM(peer_status_names),
+                     (int)peer_status);
+}
+
+static void save_loop_history(HANDSHAKE_HISTORY *history,
+                              connect_phase_t phase,
+                              handshake_status_t handshake_status,
+                              peer_status_t server_status,
+                              peer_status_t client_status,
+                              int client_turn_count,
+                              int is_client_turn)
+{
+    HANDSHAKE_HISTORY_ENTRY *new_entry = NULL;
+
+    /*
+     * Create a new history entry for a handshake loop with statuses given in
+     * the arguments. Potentially evicting the oldest entry when the
+     * ring buffer is full.
+     */
+    ++(history->last_idx);
+    history->last_idx &= MAX_HANDSHAKE_HISTORY_ENTRY_IDX_MASK;
+
+    new_entry = &((history->entries)[history->last_idx]);
+    new_entry->phase = phase;
+    new_entry->handshake_status = handshake_status;
+    new_entry->server_status = server_status;
+    new_entry->client_status = client_status;
+    new_entry->client_turn_count = client_turn_count;
+    new_entry->is_client_turn = is_client_turn;
+
+    /* Evict the oldest handshake loop entry when the ring buffer is full. */
+    if (history->entry_count < MAX_HANDSHAKE_HISTORY_ENTRY) {
+        ++(history->entry_count);
+    }
+}
+
 HANDSHAKE_RESULT *HANDSHAKE_RESULT_new(void)
 {
     HANDSHAKE_RESULT *ret;
@@ -719,15 +815,6 @@ static void configure_handshake_ssl(SSL *server, SSL *client,
         SSL_set_post_handshake_auth(client, 1);
 }

-/* The status for each connection phase. */
-typedef enum {
-    PEER_SUCCESS,
-    PEER_RETRY,
-    PEER_ERROR,
-    PEER_WAITING,
-    PEER_TEST_FAILURE
-} peer_status_t;
-
 /* An SSL object and associated read-write buffers. */
 typedef struct peer_st {
     SSL *ssl;
@@ -1074,17 +1161,6 @@ static void do_shutdown_step(PEER *peer)
     }
 }

-typedef enum {
-    HANDSHAKE,
-    RENEG_APPLICATION_DATA,
-    RENEG_SETUP,
-    RENEG_HANDSHAKE,
-    APPLICATION_DATA,
-    SHUTDOWN,
-    CONNECTION_DONE
-} connect_phase_t;
-
-
 static int renegotiate_op(const SSL_TEST_CTX *test_ctx)
 {
     switch (test_ctx->handshake_mode) {
@@ -1162,19 +1238,6 @@ static void do_connect_step(const SSL_TEST_CTX *test_ctx, PEER *peer,
     }
 }

-typedef enum {
-    /* Both parties succeeded. */
-    HANDSHAKE_SUCCESS,
-    /* Client errored. */
-    CLIENT_ERROR,
-    /* Server errored. */
-    SERVER_ERROR,
-    /* Peers are in inconsistent state. */
-    INTERNAL_ERROR,
-    /* One or both peers not done. */
-    HANDSHAKE_RETRY
-} handshake_status_t;
-
 /*
  * Determine the handshake outcome.
  * last_status: the status of the peer to have acted last.
@@ -1539,6 +1602,10 @@ static HANDSHAKE_RESULT *do_handshake_internal(

     start = time(NULL);

+    save_loop_history(&(ret->history),
+                      phase, status, server.status, client.status,
+                      client_turn_count, client_turn);
+
     /*
      * Half-duplex handshake loop.
      * Client and server speak to each other synchronously in the same process.
@@ -1560,6 +1627,10 @@ static HANDSHAKE_RESULT *do_handshake_internal(
                                       0 /* server went last */);
         }

+        save_loop_history(&(ret->history),
+                          phase, status, server.status, client.status,
+                          client_turn_count, client_turn);
+
         switch (status) {
         case HANDSHAKE_SUCCESS:
             client_turn_count = 0;
diff --git a/test/helpers/handshake.h b/test/helpers/handshake.h
index 78b03f9f4b..b9967c2623 100644
--- a/test/helpers/handshake.h
+++ b/test/helpers/handshake.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2021 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2016-2023 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
@@ -12,6 +12,11 @@

 #include "ssl_test_ctx.h"

+#define MAX_HANDSHAKE_HISTORY_ENTRY_BIT 4
+#define MAX_HANDSHAKE_HISTORY_ENTRY (1 << MAX_HANDSHAKE_HISTORY_ENTRY_BIT)
+#define MAX_HANDSHAKE_HISTORY_ENTRY_IDX_MASK \
+    ((1 << MAX_HANDSHAKE_HISTORY_ENTRY_BIT) - 1)
+
 typedef struct ctx_data_st {
     unsigned char *npn_protocols;
     size_t npn_protocols_len;
@@ -22,6 +27,63 @@ typedef struct ctx_data_st {
     char *session_ticket_app_data;
 } CTX_DATA;

+typedef enum {
+    HANDSHAKE,
+    RENEG_APPLICATION_DATA,
+    RENEG_SETUP,
+    RENEG_HANDSHAKE,
+    APPLICATION_DATA,
+    SHUTDOWN,
+    CONNECTION_DONE
+} connect_phase_t;
+
+/* The status for each connection phase. */
+typedef enum {
+    PEER_SUCCESS,
+    PEER_RETRY,
+    PEER_ERROR,
+    PEER_WAITING,
+    PEER_TEST_FAILURE
+} peer_status_t;
+
+typedef enum {
+    /* Both parties succeeded. */
+    HANDSHAKE_SUCCESS,
+    /* Client errored. */
+    CLIENT_ERROR,
+    /* Server errored. */
+    SERVER_ERROR,
+    /* Peers are in inconsistent state. */
+    INTERNAL_ERROR,
+    /* One or both peers not done. */
+    HANDSHAKE_RETRY
+} handshake_status_t;
+
+/* Stores the various status information in a handshake loop. */
+typedef struct handshake_history_entry_st {
+    connect_phase_t phase;
+    handshake_status_t handshake_status;
+    peer_status_t server_status;
+    peer_status_t client_status;
+    int client_turn_count;
+    int is_client_turn;
+} HANDSHAKE_HISTORY_ENTRY;
+
+typedef struct handshake_history_st {
+    /* Implemented using ring buffer. */
+    /*
+     * The valid entries are |entries[last_idx]|, |entries[last_idx-1]|,
+     * ..., etc., going up to |entry_count| number of entries. Note that when
+     * the index into the array |entries| becomes < 0, we wrap around to
+     * the end of |entries|.
+     */
+    HANDSHAKE_HISTORY_ENTRY entries[MAX_HANDSHAKE_HISTORY_ENTRY];
+    /* The number of valid entries in |entries| array. */
+    size_t entry_count;
+    /* The index of the last valid entry in the |entries| array. */
+    size_t last_idx;
+} HANDSHAKE_HISTORY;
+
 typedef struct handshake_result {
     ssl_test_result_t result;
     /* These alerts are in the 2-byte format returned by the info_callback. */
@@ -77,6 +139,8 @@ typedef struct handshake_result {
     char *cipher;
     /* session ticket application data */
     char *result_session_ticket_app_data;
+    /* handshake loop history */
+    HANDSHAKE_HISTORY history;
 } HANDSHAKE_RESULT;

 HANDSHAKE_RESULT *HANDSHAKE_RESULT_new(void);
@@ -95,4 +159,8 @@ int configure_handshake_ctx_for_srp(SSL_CTX *server_ctx, SSL_CTX *server2_ctx,
                                     CTX_DATA *server2_ctx_data,
                                     CTX_DATA *client_ctx_data);

+const char *handshake_connect_phase_name(connect_phase_t phase);
+const char *handshake_status_name(handshake_status_t handshake_status);
+const char *handshake_peer_status_name(peer_status_t peer_status);
+
 #endif  /* OSSL_TEST_HANDSHAKE_HELPER_H */
diff --git a/test/ssl_test.c b/test/ssl_test.c
index ea608518f9..9d6b093c81 100644
--- a/test/ssl_test.c
+++ b/test/ssl_test.c
@@ -26,6 +26,44 @@ static OSSL_LIB_CTX *libctx = NULL;
 /* Currently the section names are of the form test-<number>, e.g. test-15. */
 #define MAX_TESTCASE_NAME_LENGTH 100

+static void print_handshake_history(const HANDSHAKE_HISTORY *history)
+{
+    size_t first_idx;
+    size_t i;
+    size_t cur_idx;
+    const HANDSHAKE_HISTORY_ENTRY *cur_entry;
+    const char header_template[] = "|%14s|%16s|%16s|%16s|%17s|%14s|";
+    const char body_template[]   = "|%14s|%16s|%16s|%16s|%17d|%14s|";
+
+    TEST_info("The following is the server/client state "
+              "in the most recent %d handshake loops.",
+              MAX_HANDSHAKE_HISTORY_ENTRY);
+
+    TEST_note("=================================================="
+              "==================================================");
+    TEST_note(header_template,
+              "phase", "handshake status", "server status",
+              "client status", "client turn count", "is client turn");
+    TEST_note("+--------------+----------------+----------------"
+              "+----------------+-----------------+--------------+");
+
+    first_idx = (history->last_idx - history->entry_count + 1) &
+                MAX_HANDSHAKE_HISTORY_ENTRY_IDX_MASK;
+    for (i = 0; i < history->entry_count; ++i) {
+        cur_idx = (first_idx + i) & MAX_HANDSHAKE_HISTORY_ENTRY_IDX_MASK;
+        cur_entry = &(history->entries)[cur_idx];
+        TEST_note(body_template,
+                  handshake_connect_phase_name(cur_entry->phase),
+                  handshake_status_name(cur_entry->handshake_status),
+                  handshake_peer_status_name(cur_entry->server_status),
+                  handshake_peer_status_name(cur_entry->client_status),
+                  cur_entry->client_turn_count,
+                  cur_entry->is_client_turn ? "true" : "false");
+    }
+    TEST_note("=================================================="
+              "==================================================");
+}
+
 static const char *print_alert(int alert)
 {
     return alert ? SSL_alert_desc_string_long(alert) : "no alert";
@@ -388,6 +426,12 @@ static int check_test(HANDSHAKE_RESULT *result, SSL_TEST_CTX *test_ctx)
         ret &= check_client_sign_type(result, test_ctx);
         ret &= check_client_ca_names(result, test_ctx);
     }
+
+    /* Print handshake loop history if any check fails. */
+    if (!ret) {
+        print_handshake_history(&(result->history));
+    }
+
     return ret;
 }

--
2.25.1