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