Coverage Report

Created: 2026-10-28 06:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cyclonedds/fuzz/fuzz_handshake/fuzz_handshake_harness.c
Line
Count
Source
1
#include "fuzz_handshake_harness.h"
2
#include "fuzz_handshake_expose.h"
3
4
#include <string.h>
5
#include <dlfcn.h>
6
7
#include <dds/features.h>
8
#include <dds__types.h>
9
#include <dds__init.h>
10
#include <dds__domain.h>
11
#include <ddsi__addrset.h>
12
#include <ddsi__handshake.h>
13
#include <ddsi__thread.h>
14
#include <ddsi__plist.h>
15
#include <ddsi__proxy_participant.h>
16
#include <ddsi__vendor.h>
17
#include <ddsi__protocol.h>
18
#include <ddsi__security_util.h>
19
#include <ddsi__xevent.h>
20
#include <ddsi__gc.h>
21
#include <dds__qos.h>
22
#include <dds/ddsi/ddsi_iid.h>
23
#include <dds/ddsi/ddsi_init.h>
24
#include <dds/ddsi/ddsi_participant.h>
25
#include <dds/ddsi/ddsi_entity_index.h>
26
#include <dds/ddsi/ddsi_unused.h>
27
#include <ddsi__security_omg.h>
28
#include <dds/security/core/dds_security_fsm.h>
29
#include <dds/security/core/dds_security_utils.h>
30
#include <dds/security/core/dds_security_serialize.h>
31
#include <dds/ddsrt/heap.h>
32
#include <dds/ddsrt/string.h>
33
#include <common/test_identity.h>
34
35
#include <openssl/pem.h>
36
37
const char *sec_config =
38
    "<Domain id=\"any\">"
39
    "  <Discovery>"
40
    "    <Tag>${CYCLONEDDS_PID}</Tag>"
41
    "  </Discovery>"
42
    "  <Tracing><Verbosity>finest</></>"
43
    "  <Security>"
44
    "    <Authentication>"
45
    "      <Library initFunction=\"init_authentication\" finalizeFunction=\"finalize_authentication\" path=\"dds_security_auth\"/>"
46
    "      <IdentityCertificate>data:," TEST_IDENTITY1_CERTIFICATE "</IdentityCertificate>"
47
    "      <PrivateKey>data:," TEST_IDENTITY1_PRIVATE_KEY "</PrivateKey>"
48
    "      <IdentityCA>data:," TEST_IDENTITY_CA1_CERTIFICATE "</IdentityCA>"
49
    "    </Authentication>"
50
    "    <Cryptographic>"
51
    "      <Library initFunction=\"init_crypto\" finalizeFunction=\"finalize_crypto\" path=\"dds_security_crypto\"/>"
52
    "    </Cryptographic>"
53
    "    <AccessControl>"
54
    "      <Library initFunction=\"init_access_control\" finalizeFunction=\"finalize_access_control\" path=\"dds_security_ac\"/>"
55
    "      <Governance></Governance>"
56
    "      <PermissionsCA></PermissionsCA>"
57
    "      <Permissions></Permissions>"
58
    "    </AccessControl>"
59
    "  </Security>"
60
    "</Domain>";
61
struct ddsi_cfgst *g_cfgst;
62
struct ddsi_guid g_ppguid;
63
struct ddsi_guid g_proxy_ppguid;
64
static struct ddsi_thread_state *thrst;
65
static struct ddsi_domaingv gv;
66
EVP_PKEY *g_private_key;
67
68
2.00M
#define FUZZ_HANDSHAKE_EVENT_HANDLED (-4)
69
ddsrt_atomic_uint32_t g_fsm_done;
70
ddsrt_atomic_uint32_t g_fuzz_events;
71
72
static ddsrt_dynlib_t auth_plugin_handle;
73
74
typedef DDS_Security_ValidationResult_t (*dhpkey2oct_t)(EVP_PKEY *, int, unsigned char **, uint32_t *, DDS_Security_SecurityException *);
75
static dhpkey2oct_t dh_public_key_to_oct_ptr = NULL;
76
77
typedef DDS_Security_ValidationResult_t (*gendhkeys_t)(EVP_PKEY **, int, DDS_Security_SecurityException *);
78
static gendhkeys_t generate_dh_keys_ptr = NULL;
79
80
typedef DDS_Security_ValidationResult_t (*cvas_t)(bool, EVP_PKEY *, const unsigned char *, const size_t, unsigned char **, size_t *, DDS_Security_SecurityException *);
81
static cvas_t create_validate_asymmetrical_signature_ptr = NULL;
82
83
struct {
84
    struct ddsi_participant *pp;
85
    struct ddsi_proxy_participant *proxy_pp;
86
    struct ddsi_handshake *hs;
87
} harness;
88
89
bool fuzz_handshake_init()
90
1
{
91
    // Load private key for remote identity
92
1
    BIO *bio;
93
1
    bio = BIO_new_mem_buf(TEST_IDENTITY3_PRIVATE_KEY, -1);
94
1
    if (!bio) abort();
95
1
    g_private_key = PEM_read_bio_PrivateKey(bio, NULL, NULL, "");
96
1
    if (!g_private_key) abort();
97
1
    BIO_free(bio);
98
99
    //ddsi_iid_init();
100
1
    ddsi_thread_states_init();
101
    // register the main thread, then claim it as spawned by Cyclone because the
102
    // internal processing has various asserts that it isn't an application thread
103
    // doing the dirty work
104
1
    thrst = ddsi_lookup_thread_state ();
105
1
    assert (thrst->state == DDSI_THREAD_STATE_LAZILY_CREATED);
106
1
    thrst->state = DDSI_THREAD_STATE_ALIVE;
107
1
    thrst->vtime.v = 0;
108
1
    ddsrt_atomic_stvoidp (&thrst->gv, &gv);
109
1
    memset(&gv, 0, sizeof(gv));
110
1
    ddsi_config_init_default(&gv.config);
111
1
    gv.config.transport_selector = DDSI_TRANS_NONE;
112
1
    ddsi_config_domain_init(&gv, NULL);
113
1
    ddsi_init(&gv, NULL);
114
1
    gv.handshake_include_optional = true;
115
1
    g_cfgst = ddsi_config_init(sec_config, &gv.config, 1);
116
117
    //FILE *fp = fopen("/dev/stdout", "w");
118
    //dds_log_cfg_init(&gv.logconfig, 1, DDS_LC_TRACE | DDS_LC_ERROR | DDS_LC_WARNING, NULL, fp);
119
120
    // Disable logging
121
1
    dds_log_cfg_init(&gv.logconfig, 1, 0, NULL, NULL);
122
123
    // We use a statically linked build, all functions we need to lookup need to be
124
    // exported from the plugin
125
    //
126
    // See src/security/builtin_plugins/authentication/CMakeLists.txt
127
1
    if (ddsrt_dlopen("dds_security_auth", true, &auth_plugin_handle) != DDS_RETCODE_OK)
128
0
      abort();
129
1
    if (ddsrt_dlsym(auth_plugin_handle, "generate_dh_keys", (void **)&generate_dh_keys_ptr) != DDS_RETCODE_OK)
130
0
      abort();
131
1
    if (ddsrt_dlsym(auth_plugin_handle, "dh_public_key_to_oct", (void **)&dh_public_key_to_oct_ptr) != DDS_RETCODE_OK)
132
0
      abort();
133
1
    if (ddsrt_dlsym(auth_plugin_handle, "create_validate_asymmetrical_signature", (void **)&create_validate_asymmetrical_signature_ptr) != DDS_RETCODE_OK)
134
0
      abort();
135
136
    // Create participant
137
1
    ddsi_thread_state_awake(ddsi_lookup_thread_state(), &gv);
138
1
    {
139
1
        ddsi_plist_t pplist;
140
1
        ddsi_plist_init_empty(&pplist);
141
1
        dds_qos_t *new_qos = dds_create_qos();
142
1
        ddsi_xqos_mergein_missing (new_qos, &gv.default_local_xqos_pp, ~(uint64_t)0);
143
1
        dds_apply_entity_naming(new_qos, NULL, &gv);
144
1
        ddsi_xqos_mergein_missing (&pplist.qos, new_qos, ~(uint64_t)0);
145
1
        dds_delete_qos(new_qos);
146
147
1
        ddsi_generate_participant_guid (&g_ppguid, &gv);
148
1
        dds_return_t ret = ddsi_new_participant(&g_ppguid, &gv, 0, &pplist);
149
1
        if(ret != DDS_RETCODE_OK) abort();
150
1
        harness.pp = ddsi_entidx_lookup_participant_guid(gv.entity_index, &g_ppguid);
151
1
        ddsi_plist_fini(&pplist);
152
1
    }
153
0
    ddsi_thread_state_asleep(ddsi_lookup_thread_state());
154
155
1
    return true;
156
1
}
157
158
static void hs_end_cb(UNUSED_ARG(struct ddsi_handshake *handshake),
159
                      UNUSED_ARG(struct ddsi_participant *pp),
160
                      UNUSED_ARG(struct ddsi_proxy_participant *proxy_pp),
161
                      UNUSED_ARG(enum ddsi_handshake_state state))
162
327
{
163
    //printf("HANDSHAKE END: %d\n", state); fflush(stdout);
164
327
}
165
166
static void fsm_debug_func(UNUSED_ARG(struct dds_security_fsm *fsm), DDS_SECURITY_FSM_DEBUG_ACT act, UNUSED_ARG(const dds_security_fsm_state *current), int event_id, UNUSED_ARG(void *arg))
167
3.05M
{
168
    // This event is never generated by the state machine.
169
    // The fuzzer throws it in at the end of its events to signal that it's done
170
    // and the handshake can be abandoned.
171
3.05M
    if (act == DDS_SECURITY_FSM_DEBUG_ACT_HANDLING && event_id == DDS_SECURITY_FSM_EVENT_DELETE) {
172
4.35k
        ddsrt_atomic_st32(&g_fsm_done, 1);
173
4.35k
    }
174
175
    // This event is used to serialize the fuzzer, as the state machine is driven by a
176
    // separate thread. The fuzzer generates events and waits for the state machine to
177
    // finish the resulting transition. This prevents triggering any race conditions which
178
    // may result from a bug in the fuzzing harness. Further, the handshake data structures
179
    // containing the messages from a remote participant are being reused, so overwriting them
180
    // before the state machine handled a message will lead nowhere. Lastly, the harness does
181
    // not need to concern itself with locking.
182
3.05M
    if (act == DDS_SECURITY_FSM_DEBUG_ACT_HANDLING && event_id == FUZZ_HANDSHAKE_EVENT_HANDLED) {
183
474k
        ddsrt_atomic_inc32(&g_fuzz_events);
184
474k
    }
185
3.05M
}
186
187
4.35k
void fuzz_handshake_reset(bool initiate_remote) {
188
4.35k
    ddsrt_atomic_st32(&g_fsm_done, 0);
189
4.35k
    ddsrt_atomic_st32(&g_fuzz_events, 0);
190
191
    // Create proxy participant
192
4.35k
    ddsi_plist_t pplist;
193
4.35k
    ddsi_plist_init_empty(&pplist);
194
4.35k
    pplist.present |= PP_IDENTITY_TOKEN;
195
4.35k
    ddsi_token_t identity_token = {
196
4.35k
        .class_id = ddsrt_strdup(DDS_SECURITY_AUTH_TOKEN_CLASS_ID),
197
4.35k
        .properties = {
198
4.35k
            .n = 0,
199
4.35k
            .props = NULL
200
4.35k
        },
201
4.35k
        .binary_properties = {
202
4.35k
            .n = 0,
203
4.35k
            .props = NULL
204
4.35k
        }
205
4.35k
    };
206
207
4.35k
    pplist.identity_token = identity_token;
208
4.35k
    union { uint64_t u64; uint32_t u32[2]; } u;
209
4.35k
    u.u32[0] = gv.ppguid_base.prefix.u[1];
210
4.35k
    u.u32[1] = gv.ppguid_base.prefix.u[2];
211
4.35k
    u.u64 += ddsi_iid_gen ();
212
4.35k
    g_proxy_ppguid.prefix.u[0] = gv.ppguid_base.prefix.u[0];
213
4.35k
    g_proxy_ppguid.prefix.u[1] = u.u32[0];
214
4.35k
    g_proxy_ppguid.prefix.u[2] = u.u32[1];
215
4.35k
    g_proxy_ppguid.entityid.u = DDSI_ENTITYID_PARTICIPANT;
216
4.35k
    if (!initiate_remote) {
217
4.19k
        g_proxy_ppguid.prefix.s[0] = 0xff;
218
4.19k
        g_proxy_ppguid.prefix.s[1] = 0xff;
219
4.19k
        g_proxy_ppguid.prefix.s[2] = 0xff;
220
4.19k
    } else {
221
155
        g_proxy_ppguid.prefix.s[0] = 0x00;
222
155
        g_proxy_ppguid.prefix.s[1] = 0x00;
223
155
        g_proxy_ppguid.prefix.s[2] = 0x00;
224
155
    }
225
226
4.35k
    ddsrt_wctime_t timestamp = { .v = dds_time() };
227
228
    // We avoid generating network traffic by using DDSI_TRANS_NONE
229
    // This is the only valid locator for that "network".
230
4.35k
    const ddsi_locator_t loc = {
231
4.35k
      .kind = 2147483647, .address = {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, .port = 0
232
4.35k
    };
233
4.35k
    struct ddsi_addrset *as = ddsi_new_addrset();
234
4.35k
    ddsi_add_locator_to_addrset(&gv,as, &loc, gv.xmit_conns_data);
235
4.35k
    assert(!ddsi_addrset_empty_uc(as));
236
237
4.35k
    ddsi_thread_state_awake(ddsi_lookup_thread_state(), &gv);
238
4.35k
    if (!ddsi_new_proxy_participant(&harness.proxy_pp, &gv,
239
4.35k
            &g_proxy_ppguid,
240
4.35k
            DDSI_DISC_BUILTIN_ENDPOINT_PARTICIPANT_SECURE_ANNOUNCER|
241
4.35k
            DDSI_BUILTIN_ENDPOINT_PARTICIPANT_STATELESS_MESSAGE_ANNOUNCER|DDSI_BUILTIN_ENDPOINT_PARTICIPANT_STATELESS_MESSAGE_DETECTOR,
242
4.35k
            as,
243
4.35k
            ddsi_ref_addrset(as),
244
4.35k
            &pplist,
245
4.35k
            DDS_INFINITY,
246
4.35k
            DDSI_VENDORID_ECLIPSE,
247
4.35k
            timestamp,
248
4.35k
            0)) {
249
0
        abort();
250
0
    }
251
4.35k
    ddsi_thread_state_asleep(ddsi_lookup_thread_state());
252
4.35k
    ddsi_plist_fini(&pplist);
253
254
4.35k
    harness.hs = ddsi_handshake_find(harness.pp, harness.proxy_pp);
255
4.35k
    if (harness.hs == NULL) abort();
256
257
    // We abuse the debug function for the serialization of the fuzzer thread
258
    // and the handshake fsm thread.
259
4.35k
    dds_security_fsm_set_debug(harness.hs->fsm, fsm_debug_func);
260
4.35k
    harness.hs->end_cb = hs_end_cb;
261
4.35k
    ddsi_handshake_release(harness.hs);
262
4.35k
}
263
264
164k
void fuzz_handshake_handle_timeout(void) {
265
164k
    dds_security_fsm_dispatch(harness.hs->fsm, DDS_SECURITY_FSM_EVENT_TIMEOUT, false);
266
164k
}
267
268
10.3k
static DDS_Security_ValidationResult_t create_dh_key(int algo, unsigned char **data, uint32_t *len) {
269
10.3k
    EVP_PKEY *key;
270
10.3k
    DDS_Security_SecurityException ex = {0};
271
10.3k
    DDS_Security_ValidationResult_t result = generate_dh_keys_ptr(&key, algo, &ex);
272
10.3k
    if (result != DDS_SECURITY_VALIDATION_OK) goto out;
273
274
10.3k
    result = dh_public_key_to_oct_ptr(key, algo, data, len, &ex);
275
10.3k
out:
276
10.3k
    EVP_PKEY_free(key);
277
10.3k
    DDS_Security_Exception_reset(&ex);
278
10.3k
    return result;
279
10.3k
}
280
281
202k
void fuzz_handshake_handle_request(ddsi_dataholder_t *token) {
282
202k
    struct ddsi_participant_generic_message msg;
283
202k
    msg.message_class_id = DDS_SECURITY_AUTH_HANDSHAKE;
284
202k
    msg.message_data.n = 1;
285
202k
    msg.message_data.tags = token;
286
202k
    token->class_id = DDS_SECURITY_AUTH_HANDSHAKE_REQUEST_TOKEN_ID;
287
288
758k
    for (uint32_t i = 0; i < token->binary_properties.n; i++) {
289
556k
        dds_binaryproperty_t *binprop = &token->binary_properties.props[i];
290
        // To avoid fuzzing openssl, always use a valid certificate
291
556k
        if (strcmp(binprop->name, "c.id") == 0) {
292
161k
            ddsrt_free(binprop->value.value);
293
161k
            binprop->value.length = strlen(TEST_IDENTITY3_CERTIFICATE);
294
161k
            binprop->value.value = (unsigned char *) ddsrt_strdup(TEST_IDENTITY3_CERTIFICATE);
295
161k
        }
296
        // Provide a valid dh public key
297
556k
        if (strcmp(binprop->name, "dh1") == 0) {
298
9.11k
            unsigned char *data;
299
9.11k
            uint32_t len;
300
9.11k
            if (create_dh_key(1, &data, &len) == DDS_SECURITY_VALIDATION_OK) {
301
9.11k
                ddsrt_free(binprop->value.value);
302
9.11k
                binprop->value.length = len;
303
9.11k
                binprop->value.value = data;
304
9.11k
            }
305
9.11k
        }
306
556k
    }
307
202k
    ddsi_handshake_handle_message(harness.hs, harness.pp, harness.proxy_pp, &msg);
308
202k
}
309
310
static void create_signature(const DDS_Security_BinaryProperty_t **bprops, uint32_t n_bprops, unsigned char **signature, size_t *signatureLen)
311
2.27k
{
312
2.27k
    unsigned char *buffer;
313
2.27k
    size_t size;
314
2.27k
    DDS_Security_Serializer serializer = DDS_Security_Serializer_new(4096, 4096);
315
2.27k
    DDS_Security_Serialize_BinaryPropertyArray(serializer, bprops, n_bprops);
316
2.27k
    DDS_Security_Serializer_buffer(serializer, &buffer, &size);
317
2.27k
    DDS_Security_SecurityException ex;
318
2.27k
    (void) create_validate_asymmetrical_signature_ptr(true, g_private_key, buffer, size, signature, signatureLen, &ex);
319
2.27k
    ddsrt_free(buffer);
320
2.27k
    DDS_Security_Serializer_free(serializer);
321
2.27k
}
322
323
static void create_hash(const DDS_Security_DataHolder *dh, DDS_Security_BinaryProperty_t *bprop, const char *name)
324
43.0k
{
325
43.0k
    unsigned char *buffer;
326
43.0k
    size_t size;
327
328
43.0k
    DDS_Security_BinaryProperty_t *tokens = DDS_Security_BinaryPropertySeq_allocbuf(5);
329
43.0k
    const DDS_Security_BinaryProperty_t *c_id = DDS_Security_DataHolder_find_binary_property(dh, "c.id");
330
43.0k
    uint32_t tokidx = 0;
331
43.0k
    if (c_id) DDS_Security_BinaryProperty_copy(&tokens[tokidx++], c_id);
332
43.0k
    const DDS_Security_BinaryProperty_t *c_perm = DDS_Security_DataHolder_find_binary_property(dh, "c.perm");
333
43.0k
    if (c_perm) DDS_Security_BinaryProperty_copy(&tokens[tokidx++], c_perm);
334
43.0k
    const DDS_Security_BinaryProperty_t *c_pdata = DDS_Security_DataHolder_find_binary_property(dh, "c.pdata");
335
43.0k
    if (c_pdata) DDS_Security_BinaryProperty_copy(&tokens[tokidx++], c_pdata);
336
43.0k
    const DDS_Security_BinaryProperty_t *c_dsign_algo = DDS_Security_DataHolder_find_binary_property(dh, "c.dsign_algo");
337
43.0k
    if (c_dsign_algo) DDS_Security_BinaryProperty_copy(&tokens[tokidx++], c_dsign_algo);
338
43.0k
    const DDS_Security_BinaryProperty_t *c_kagree_algo = DDS_Security_DataHolder_find_binary_property(dh, "c.kagree_algo");
339
43.0k
    if (c_kagree_algo) DDS_Security_BinaryProperty_copy(&tokens[tokidx++], c_kagree_algo);
340
43.0k
    DDS_Security_BinaryPropertySeq seq = { ._length = tokidx, ._buffer = tokens };
341
43.0k
    DDS_Security_Serializer serializer = DDS_Security_Serializer_new(4096, 4096);
342
43.0k
    DDS_Security_Serialize_BinaryPropertySeq(serializer, &seq);
343
43.0k
    DDS_Security_Serializer_buffer(serializer, &buffer, &size);
344
345
43.0k
    unsigned char *hash = ddsrt_malloc(SHA256_DIGEST_LENGTH);
346
43.0k
    SHA256(buffer, size, hash);
347
43.0k
    ddsrt_free(buffer);
348
43.0k
    DDS_Security_Serializer_free(serializer);
349
350
43.0k
    bprop->name = ddsrt_strdup(name);
351
43.0k
    bprop->value._length = SHA256_DIGEST_LENGTH;
352
43.0k
    bprop->value._maximum = SHA256_DIGEST_LENGTH;
353
43.0k
    bprop->value._buffer = hash;
354
43.0k
    DDS_Security_BinaryPropertySeq_deinit(&seq);
355
43.0k
}
356
357
43.0k
void fuzz_handshake_handle_reply(ddsi_dataholder_t *token) {
358
43.0k
    struct ddsi_participant_generic_message msg;
359
43.0k
    msg.message_class_id = DDS_SECURITY_AUTH_HANDSHAKE;
360
43.0k
    msg.message_data.n = 1;
361
43.0k
    msg.message_data.tags = token;
362
43.0k
    token->class_id = DDS_SECURITY_AUTH_HANDSHAKE_REPLY_TOKEN_ID;
363
43.0k
    const DDS_Security_BinaryProperty_t *c1 = NULL;
364
43.0k
    const DDS_Security_BinaryProperty_t *c2 = NULL;
365
43.0k
    const DDS_Security_BinaryProperty_t *dh1 = NULL;
366
43.0k
    const DDS_Security_BinaryProperty_t *dh2 = NULL;
367
43.0k
    const DDS_Security_BinaryProperty_t *hash_c1 = NULL;
368
43.0k
    const DDS_Security_BinaryProperty_t *kagree_algo = NULL;
369
370
43.0k
    if (harness.hs->handshake_message_out != NULL) {
371
        // Using gv.handshake_include_optional = true;
372
778
        c1 = DDS_Security_DataHolder_find_binary_property(harness.hs->handshake_message_out, "challenge1");
373
778
        dh1 = DDS_Security_DataHolder_find_binary_property(harness.hs->handshake_message_out, "dh1");
374
778
        hash_c1 = DDS_Security_DataHolder_find_binary_property(harness.hs->handshake_message_out, "hash_c1");
375
778
        kagree_algo = DDS_Security_DataHolder_find_binary_property(harness.hs->handshake_message_out, "c.kagree_algo");
376
778
    }
377
378
    // First fix up the values necessary for the hash
379
74.8k
    for (uint32_t i = 0; i < token->binary_properties.n; i++) {
380
31.8k
        dds_binaryproperty_t *binprop = &token->binary_properties.props[i];
381
        // To avoid fuzzing openssl, always use a valid certificate
382
31.8k
        if (strcmp(binprop->name, "c.id") == 0) {
383
2.88k
            ddsrt_free(binprop->value.value);
384
2.88k
            binprop->value.length = strlen(TEST_IDENTITY3_CERTIFICATE);
385
2.88k
            binprop->value.value = (unsigned char *) ddsrt_strdup(TEST_IDENTITY3_CERTIFICATE);
386
2.88k
        }
387
31.8k
        if ((strcmp(binprop->name, "challenge1") == 0) && c1) {
388
429
            ddsrt_free(binprop->value.value);
389
429
            binprop->value.length = DDS_SECURITY_AUTHENTICATION_CHALLENGE_SIZE;
390
429
            binprop->value.value = ddsrt_malloc(DDS_SECURITY_AUTHENTICATION_CHALLENGE_SIZE);
391
429
            memcpy(binprop->value.value, c1->value._buffer, DDS_SECURITY_AUTHENTICATION_CHALLENGE_SIZE);
392
429
        }
393
        // Provide a valid dh public key
394
31.8k
        if ((strcmp(binprop->name, "dh2") == 0) && kagree_algo) {
395
1.18k
            int algo = 1;
396
1.18k
            if (strncmp((const char *)kagree_algo->value._buffer, "ECDH+prime256v1-CEUM", kagree_algo->value._length) == 0) algo = 2;
397
1.18k
            unsigned char *data;
398
1.18k
            uint32_t len;
399
1.18k
            if (create_dh_key(algo, &data, &len) == DDS_SECURITY_VALIDATION_OK) {
400
1.18k
                ddsrt_free(binprop->value.value);
401
1.18k
                binprop->value.length = len;
402
1.18k
                binprop->value.value = data;
403
1.18k
            }
404
1.18k
        }
405
31.8k
    }
406
407
    // Generate the hash to be signed
408
43.0k
    DDS_Security_DataHolder token_holder;
409
43.0k
    ddsi_omg_shallow_copyin_DataHolder(&token_holder, token);
410
43.0k
    c2 = DDS_Security_DataHolder_find_binary_property(&token_holder, "challenge2");
411
43.0k
    dh2 = DDS_Security_DataHolder_find_binary_property(&token_holder, "dh2");
412
43.0k
    DDS_Security_BinaryProperty_t hash_c2 = {0};
413
43.0k
    create_hash(&token_holder, &hash_c2, "hash_c2");
414
415
74.8k
    for (uint32_t i = 0; i < token->binary_properties.n; i++) {
416
31.8k
        dds_binaryproperty_t *binprop = &token->binary_properties.props[i];
417
        // Need to provide a valid signature for the handshake to succeed
418
31.8k
        if (strcmp(binprop->name, "signature") == 0 && hash_c1 && c1 && c2 && dh1 && c2 && dh2 && hash_c2.value._buffer) {
419
1.18k
            unsigned char *signature;
420
1.18k
            size_t signatureLen;
421
1.18k
            const DDS_Security_BinaryProperty_t *bprops[] = { &hash_c2, c2, dh2, c1, dh1, hash_c1};
422
1.18k
            create_signature(bprops, 6, &signature, &signatureLen);
423
1.18k
            ddsrt_free(binprop->value.value);
424
1.18k
            binprop->value.length = (uint32_t) signatureLen;
425
1.18k
            binprop->value.value = signature;
426
1.18k
        }
427
31.8k
    }
428
43.0k
    DDS_Security_BinaryProperty_deinit(&hash_c2);
429
43.0k
    ddsi_handshake_handle_message(harness.hs, harness.pp, harness.proxy_pp, &msg);
430
43.0k
    ddsi_omg_shallow_free_DataHolder(&token_holder);
431
43.0k
}
432
433
37.3k
void fuzz_handshake_handle_final(ddsi_dataholder_t *token) {
434
37.3k
    struct ddsi_participant_generic_message msg;
435
37.3k
    msg.message_class_id = DDS_SECURITY_AUTH_HANDSHAKE;
436
37.3k
    msg.message_data.n = 1;
437
37.3k
    msg.message_data.tags = token;
438
37.3k
    token->class_id = DDS_SECURITY_AUTH_HANDSHAKE_FINAL_TOKEN_ID;
439
440
37.3k
    const DDS_Security_BinaryProperty_t *c1 = NULL;
441
37.3k
    const DDS_Security_BinaryProperty_t *c2 = NULL;
442
37.3k
    const DDS_Security_BinaryProperty_t *dh1 = NULL;
443
37.3k
    const DDS_Security_BinaryProperty_t *dh2 = NULL;
444
37.3k
    const DDS_Security_BinaryProperty_t *hash_c1 = NULL;
445
37.3k
    const DDS_Security_BinaryProperty_t *hash_c2 = NULL;
446
447
37.3k
    if (harness.hs->handshake_message_out != NULL) {
448
        // Using gv.handshake_include_optional = true;
449
1.82k
        c1 = DDS_Security_DataHolder_find_binary_property(harness.hs->handshake_message_out, "challenge1");
450
1.82k
        c2 = DDS_Security_DataHolder_find_binary_property(harness.hs->handshake_message_out, "challenge2");
451
1.82k
        dh1 = DDS_Security_DataHolder_find_binary_property(harness.hs->handshake_message_out, "dh1");
452
1.82k
        dh2 = DDS_Security_DataHolder_find_binary_property(harness.hs->handshake_message_out, "dh2");
453
1.82k
        hash_c1 = DDS_Security_DataHolder_find_binary_property(harness.hs->handshake_message_out, "hash_c1");
454
1.82k
        hash_c2 = DDS_Security_DataHolder_find_binary_property(harness.hs->handshake_message_out, "hash_c2");
455
1.82k
    }
456
457
75.1k
    for (uint32_t i = 0; i < token->binary_properties.n; i++) {
458
37.7k
        dds_binaryproperty_t *binprop = &token->binary_properties.props[i];
459
        // Need to copy the correct values for challenge2 from the relation for the handshake to succeed
460
37.7k
        if ((strcmp(binprop->name, "challenge1") == 0) && c1) {
461
673
            ddsrt_free(binprop->value.value);
462
673
            binprop->value.length = DDS_SECURITY_AUTHENTICATION_CHALLENGE_SIZE;
463
673
            binprop->value.value = ddsrt_malloc(DDS_SECURITY_AUTHENTICATION_CHALLENGE_SIZE);
464
673
            memcpy(binprop->value.value, c1->value._buffer, DDS_SECURITY_AUTHENTICATION_CHALLENGE_SIZE);
465
673
        }
466
37.7k
        if ((strcmp(binprop->name, "challenge2") == 0) && c2) {
467
629
            ddsrt_free(binprop->value.value);
468
629
            binprop->value.length = DDS_SECURITY_AUTHENTICATION_CHALLENGE_SIZE;
469
629
            binprop->value.value = ddsrt_malloc(DDS_SECURITY_AUTHENTICATION_CHALLENGE_SIZE);
470
629
            memcpy(binprop->value.value, c2->value._buffer, DDS_SECURITY_AUTHENTICATION_CHALLENGE_SIZE);
471
629
        }
472
        // Need to provide a valid signature for the handshake to succeed
473
37.7k
        if (strcmp(binprop->name, "signature") == 0 && hash_c1 && c1 && c2 && dh1 && c2 && dh2 && hash_c2) {
474
1.08k
            unsigned char *signature;
475
1.08k
            size_t signatureLen;
476
1.08k
            const DDS_Security_BinaryProperty_t *bprops[] = { hash_c1, c1, dh1, c2, dh2, hash_c2 };
477
1.08k
            create_signature(bprops, 6, &signature, &signatureLen);
478
1.08k
            ddsrt_free(binprop->value.value);
479
1.08k
            binprop->value.length = (uint32_t) signatureLen;
480
1.08k
            binprop->value.value = signature;
481
1.08k
        }
482
37.7k
    }
483
484
37.3k
    ddsi_handshake_handle_message(harness.hs, harness.pp, harness.proxy_pp, &msg);
485
37.3k
}
486
487
27.0k
void fuzz_handshake_handle_crypto_tokens(void) {
488
27.0k
    ddsi_thread_state_awake(ddsi_lookup_thread_state(), &gv);
489
27.0k
    ddsi_handshake_crypto_tokens_received(harness.hs);
490
27.0k
    ddsi_thread_state_asleep(ddsi_lookup_thread_state());
491
27.0k
}
492
493
474k
void fuzz_handshake_wait_for_event(uint32_t event) {
494
474k
    dds_security_fsm_dispatch(harness.hs->fsm, FUZZ_HANDSHAKE_EVENT_HANDLED, false);
495
55.4G
    while(ddsrt_atomic_ld32(&g_fuzz_events) != event) {}
496
474k
}
497
498
4.35k
void fuzz_handshake_wait_for_completion(void) {
499
4.35k
    dds_security_fsm_dispatch(harness.hs->fsm, DDS_SECURITY_FSM_EVENT_DELETE, false);
500
26.8M
    while(ddsrt_atomic_ld32(&g_fsm_done) == 0) {}
501
4.35k
    ddsrt_wctime_t timestamp = { .v = dds_time() };
502
4.35k
    ddsi_thread_state_awake(ddsi_lookup_thread_state(), &gv);
503
4.35k
    ddsi_delete_proxy_participant_by_guid(&gv, &g_proxy_ppguid, timestamp, 1);
504
4.35k
    ddsi_thread_state_asleep(ddsi_lookup_thread_state());
505
4.35k
    harness.proxy_pp = NULL;
506
4.35k
    harness.hs = NULL;
507
508
    // To actually delete all we created we need to step the what is normally
509
    // done by 4 different threads in the background (multi-stage cleanup via
510
    // the GC involves bubbles sent through the delivery queues; and then one
511
    // has to "send" the messages queued by the handshake code).
512
4.35k
    bool x;
513
4.35k
    do {
514
4.35k
      x = false;
515
4.35k
      if (ddsi_gcreq_queue_step (gv.gcreq_queue))
516
0
        x = true;
517
4.35k
      if (ddsi_dqueue_step_deaf (gv.builtins_dqueue))
518
0
        x = true;
519
4.35k
      if (ddsi_dqueue_step_deaf (gv.user_dqueue))
520
0
        x = true;
521
4.35k
      ddsi_xeventq_step (gv.xevents);
522
4.35k
    } while (x);
523
4.35k
}