1 /* packet-corosync-totemnet.c
2 * Dissector routines for the lowest level(encryption/decryption) protocol used in Corosync cluster engine
3 * Copyright 2009 2010 2014 Masatake YAMATO <yamato@redhat.com>
4 * Copyright (c) 2010 2014 Red Hat, Inc.
5 *
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
9 *
10 * SPDX-License-Identifier: GPL-2.0-or-later
11 */
12
13 #include "config.h"
14
15 #include <epan/packet.h>
16 #include <epan/prefs.h>
17 #include <wsutil/wsgcrypt.h>
18 #include <wsutil/sober128.h>
19
20 static dissector_handle_t corosync_totemsrp_handle;
21
22 /* This dissector deals packets defined in totemnet.c of corosync
23 cluster engine. In the totemnet.c the packet is encrypted and decrypted
24 with LibTomCrypt. This dissector tries decrypting the packet with
25 sober128 and sha1 functions in wireshark. */
26
27 /*
28 * Dissector body
29 */
30
31 #define PORT_COROSYNC_TOTEMNET_RANGE "5404-5405" /* Not IANA registered */
32
33 /* Forward declaration we need below */
34 void proto_register_corosync_totemnet(void);
35 void proto_reg_handoff_corosync_totemnet(void);
36
37 /* Initialize the protocol and registered fields */
38 static int proto_corosync_totemnet = -1;
39
40 /* field of struct security_header */
41 static int hf_corosync_totemnet_security_header_hash_digest = -1;
42 static int hf_corosync_totemnet_security_header_salt = -1;
43 static int hf_corosync_totemnet_security_crypto_type = -1;
44 static int hf_corosync_totemnet_security_crypto_key = -1;
45
46 /* configurable parameters */
47 static gchar* corosync_totemnet_private_keys = NULL;
48 static gchar** corosync_totemnet_private_keys_list = NULL;
49
50 /* Initialize the subtree pointers */
51 static gint ett_corosync_totemnet_security_header = -1;
52
53 #define SALT_SIZE 16
54
55 #define TOTEM_CRYPTO_SOBER 0
56 #define TOTEM_CRYPTO_NSS 1
57
58 static const value_string corosync_totemnet_crypto_type[] = {
59 { TOTEM_CRYPTO_SOBER, "SOBER" },
60 { TOTEM_CRYPTO_NSS, "NSS" },
61 { 0, NULL }
62 };
63
64
65 static int
dissect_corosync_totemnet_security_header(tvbuff_t * tvb,packet_info * pinfo,proto_tree * parent_tree,gboolean check_crypt_type,const gchar * key)66 dissect_corosync_totemnet_security_header(tvbuff_t *tvb,
67 packet_info *pinfo, proto_tree *parent_tree,
68 gboolean check_crypt_type,
69 const gchar* key)
70 {
71 proto_item *item;
72 proto_tree *tree;
73
74 col_set_str(pinfo->cinfo, COL_PROTOCOL, "COROSYNC/TOTEMNET");
75 col_clear(pinfo->cinfo, COL_INFO);
76
77 if (parent_tree)
78 {
79 item = proto_tree_add_item(parent_tree, proto_corosync_totemnet, tvb, 0,
80 -1, ENC_NA);
81 tree = proto_item_add_subtree(item, ett_corosync_totemnet_security_header);
82
83 proto_tree_add_item(tree,
84 hf_corosync_totemnet_security_header_hash_digest,
85 tvb, 0, HASH_SHA1_LENGTH, ENC_NA);
86 proto_tree_add_item(tree,
87 hf_corosync_totemnet_security_header_salt,
88 tvb, HASH_SHA1_LENGTH, SALT_SIZE, ENC_NA);
89
90 if (check_crypt_type)
91 {
92 int io_len = tvb_reported_length(tvb);
93 proto_item * key_item;
94
95 proto_tree_add_item(tree,
96 hf_corosync_totemnet_security_crypto_type,
97 tvb, io_len - 1, 1, ENC_BIG_ENDIAN);
98 key_item = proto_tree_add_string(tree,
99 hf_corosync_totemnet_security_crypto_key,
100 tvb, 0, 0, key);
101 proto_item_set_generated(key_item);
102 }
103 }
104 return HASH_SHA1_LENGTH + SALT_SIZE;
105 }
106
107 /* About totemnet.c of corosync cluster engine:
108 *
109 * dissect_corosynec_totemnet_with_decryption() is derived from
110 * totemnet.c in corosync which is licensed under 3-clause BSD license.
111 * However, to merge this dissector to wireshark official source tree,
112 * corosync developers permit EXPLICITLY to reuse totemnet.c in GPL.
113 *
114 http://permalink.gmane.org/gmane.linux.redhat.cluster/19087
115 ------------------------------------------------------------
116 Steven Dake | 4 Jan 2011 22:02
117 Re: [Openais] packet dissectors for totempg, cman, clvmd, rgmanager, cpg,
118
119 On 12/14/2010 08:04 AM, Masatake YAMATO wrote:
120 > Thank you for replying.
121 >
122 >> Masatake,
123 >>
124 >> Masatake YAMATO napsal(a):
125 >>> I'd like to your advice more detail seriously.
126 >>> I've been developing this code for three years.
127 >>> I don't want to make this code garbage.
128 >>>
129 >>>> Masatake,
130 >>>> I'm pretty sure that biggest problem of your code was that it was
131 >>>> licensed under BSD (three clause, same as Corosync has)
132 >>>> license. Wireshark is licensed under GPL and even I like BSD licenses
133 >>>> much more, I would recommend you to try to relicense code under GPL
134 >>>> and send them this code.
135 >>>>
136 >>>> Regards,
137 >>>> Honza
138 >>> I got the similar comment from wireshark developer.
139 >>> Please, read the discussion:
140 >>> https://gitlab.com/wireshark/wireshark/-/issues/3232
141 >>>
142 >>
143 >> I've read that thread long time before I've sent previous mail, so
144 >> thats reason why I think that Wireshark developers just feel MUCH more
145 >> comfortable with GPL and thats reason why they just ignoring it.
146 >
147 > I see.
148 >
149 >>> In my understanding there is no legal problem in putting 3-clause BSD
150 >>> code into GPL code. Acutally wireshark includes some 3-clause BSD
151 >>> code:
152 >>>
153 nnn>>
154 >> Actually there is really not. BSD to GPL works without problem, but
155 >> many people just don't know it...
156 >
157 > ...it is too bad. I strongly believe FOSS developers should know the
158 > intent behind of the both licenses.
159 >
160 >>> epan/dissectors/packet-radiotap-defs.h:
161 >>> *//*-
162 >>> * Copyright (c) 2003, 2004 David Young. All rights reserved.
163 >>> *
164 ...
165 >>> *
166 >>> * Redistribution and use in source and binary forms, with or without
167 >>> * modification, are permitted provided that the following conditions
168 >>> * are met:
169 >>> * 1. Redistributions of source code must retain the above copyright
170 >>> * notice, this list of conditions and the following disclaimer.
171 >>> * 2. Redistributions in binary form must reproduce the above copyright
172 >>> * notice, this list of conditions and the following disclaimer in the
173 >>> * documentation and/or other materials provided with the distribution.
174 >>> * 3. The name of David Young may not be used to endorse or promote
175 >>> * products derived from this software without specific prior
176 >>> * written permission.
177 >>> *
178 >>> * THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY
179 >>> * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
180 >>> * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
181 >>> * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID
182 >>> * YOUNG BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
183 >>> * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
184 >>> * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
185 >>> * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
186 >>> * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
187 >>> * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
188 >>> * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
189 >>> * OF SUCH DAMAGE.
190 >>> *//*
191 >>> I'd like to separate the legal issue and preference. I think I
192 >>> understand the importance of preference of upstream
193 >>> developers. However, I'd like to clear the legal issue first.
194 >>>
195 >>
196 >> Legally it's ok. But as you said, developers preference are
197 >> different. And because you are trying to change THEIR code it's
198 >> sometimes better to play they rules.
199 >
200 > I see.
201 >
202 >>> I can image there are people who prefer to GPL as the license covering
203 >>> their software. But here I've taken some corosync code in my
204 >>> dissector. It is essential part of my dissector. And corosync is
205 >>
206 >> ^^^ This may be problem. Question is how big is that part and if it
207 >> can be possible to make exception there. Can you point that code?
208 >>
209 >> Steve, we were able to relicense HUGE portion of code in case of
210 >> libqb, are we able to make the same for Wireshark dissector?
211 >
212 > Could you see https://github.com/masatake/wireshark-plugin-rhcs/blob/master/src/packet-corosync-totemnet.c#L156
213 > I refer totemnet.c to write dissect_corosynec_totemnet_with_decryption() function.
214 >
215 >>> licensed in 3-clause BSD, as you know. I'd like to change the license
216 >>> to merge my code to upstream project. I cannot do it in this context.
217 >>> See https://gitlab.com/wireshark/wireshark/-/issues/3232#c13
218 >>> Thank you.
219 >>
220 >> Regards,
221 >> Honza
222 >
223 > Masatake YAMATO
224
225 Masatake,
226
227 Red Hat is the author of the totemnet file and can provide that code
228 under GPL if you like. We cannot modify the license for libtomcrypt as
229 we are not the authors. Feel free to change the license for that
230 particular code you rewrote in the link
231
232 > Could you see
233 https://github.com/masatake/wireshark-plugin-rhcs/blob/master/src/packet-corosync-totemnet.c#L156
234
235 under a GPL license if it helps move things along.
236
237 Regards
238 -steveu
239 */
240
241 static int
dissect_corosynec_totemnet_with_decryption(tvbuff_t * tvb,packet_info * pinfo,proto_tree * parent_tree,gboolean check_crypt_type,const gchar * key_for_trial)242 dissect_corosynec_totemnet_with_decryption(tvbuff_t *tvb,
243 packet_info *pinfo, proto_tree *parent_tree,
244 gboolean check_crypt_type,
245 const gchar* key_for_trial)
246 {
247 unsigned char keys[48];
248 sober128_prng keygen_prng_state;
249 sober128_prng stream_prng_state;
250 unsigned char *hmac_key = &keys[32];
251 unsigned char *cipher_key = &keys[16];
252 unsigned char *initial_vector = &keys[0];
253 unsigned char digest_comparison[HASH_SHA1_LENGTH];
254
255 int io_len;
256 guint8 *io_base;
257
258 #define PRIVATE_KEY_LEN_MAX 256
259 gchar private_key[PRIVATE_KEY_LEN_MAX];
260 gsize private_key_len;
261 unsigned char* hash_digest;
262 unsigned char* salt;
263
264 io_len = tvb_reported_length(tvb) - (check_crypt_type? 1: 0);
265 if (io_len < HASH_SHA1_LENGTH + SALT_SIZE) {
266 return 0;
267 }
268
269 io_base = (guint8 *)tvb_memdup(pinfo->pool, tvb, 0, io_len + (check_crypt_type? 1: 0));
270 if (check_crypt_type &&
271 ( io_base[io_len] != TOTEM_CRYPTO_SOBER )) {
272 return 0;
273 }
274
275 hash_digest = io_base;
276 salt = io_base + HASH_SHA1_LENGTH;
277
278
279 memset(private_key, 0, sizeof(private_key));
280
281 private_key_len = (strlen(key_for_trial)+4) & 0xFC;
282 (void) g_strlcpy(private_key, key_for_trial, private_key_len);
283
284 /*
285 * Generate MAC, CIPHER, IV keys from private key
286 */
287 memset (keys, 0, sizeof(keys));
288 sober128_start (&keygen_prng_state);
289 sober128_add_entropy(private_key,
290 (unsigned long)private_key_len, &keygen_prng_state);
291 sober128_add_entropy (salt, SALT_SIZE, &keygen_prng_state);
292 sober128_read (keys, sizeof (keys), &keygen_prng_state);
293
294 /*
295 * Setup stream cipher
296 */
297 sober128_start (&stream_prng_state);
298 sober128_add_entropy (cipher_key, 16, &stream_prng_state);
299 sober128_add_entropy (initial_vector, 16, &stream_prng_state);
300
301 /*
302 * Authenticate contents of message
303 */
304 if (ws_hmac_buffer(GCRY_MD_SHA1, digest_comparison, io_base + HASH_SHA1_LENGTH, io_len - HASH_SHA1_LENGTH, hmac_key, 16)) {
305 return 0;
306 }
307
308 if (memcmp (digest_comparison, hash_digest, HASH_SHA1_LENGTH) != 0)
309 return 0;
310
311 /*
312 * Decrypt the contents of the message with the cipher key
313 */
314
315 sober128_read (io_base + HASH_SHA1_LENGTH + SALT_SIZE,
316 io_len - (HASH_SHA1_LENGTH + SALT_SIZE),
317 &stream_prng_state);
318
319
320 /*
321 * Dissect the decrypted data
322 */
323 {
324 tvbuff_t *decrypted_tvb;
325 tvbuff_t *next_tvb;
326
327
328 decrypted_tvb = tvb_new_real_data(io_base, io_len, io_len);
329
330 tvb_set_child_real_data_tvbuff(tvb, decrypted_tvb);
331 add_new_data_source(pinfo, decrypted_tvb, "Decrypted Data");
332
333
334 dissect_corosync_totemnet_security_header(decrypted_tvb, pinfo, parent_tree,
335 check_crypt_type, key_for_trial);
336
337 next_tvb = tvb_new_subset_length_caplen(decrypted_tvb,
338 HASH_SHA1_LENGTH + SALT_SIZE,
339 io_len - (HASH_SHA1_LENGTH + SALT_SIZE),
340 io_len - (HASH_SHA1_LENGTH + SALT_SIZE));
341
342 return call_dissector(corosync_totemsrp_handle, next_tvb, pinfo, parent_tree) + HASH_SHA1_LENGTH + SALT_SIZE;
343 }
344 }
345
346 static int
dissect_corosynec_totemnet(tvbuff_t * tvb,packet_info * pinfo,proto_tree * parent_tree,void * data _U_)347 dissect_corosynec_totemnet(tvbuff_t *tvb,
348 packet_info *pinfo, proto_tree *parent_tree,
349 void *data _U_)
350 {
351 if (corosync_totemnet_private_keys_list)
352 {
353 static int last_key_index = -1;
354 int key_index;
355
356 static int last_check_crypt_type_index;
357 int check_crypt_type_index = -1;
358 gboolean check_crypt_type_list[] = {FALSE, TRUE};
359
360
361 if (last_key_index != -1)
362 {
363 int r;
364
365 r = dissect_corosynec_totemnet_with_decryption(tvb,
366 pinfo,
367 parent_tree,
368 check_crypt_type_list[last_check_crypt_type_index],
369 corosync_totemnet_private_keys_list[last_key_index]);
370 if (r > 0)
371 return r;
372 else
373 last_key_index = -1;
374 }
375
376 for (key_index = 0;
377 corosync_totemnet_private_keys_list[key_index];
378 key_index++)
379 {
380 for (check_crypt_type_index = 0;
381 check_crypt_type_index < 2;
382 check_crypt_type_index++)
383 {
384 int r;
385
386 r = dissect_corosynec_totemnet_with_decryption(tvb,
387 pinfo,
388 parent_tree,
389 check_crypt_type_list[check_crypt_type_index],
390 corosync_totemnet_private_keys_list[key_index]);
391 if (r > 0)
392 {
393 last_key_index = key_index;
394 last_check_crypt_type_index = check_crypt_type_index;
395 return r;
396 }
397 else if (r < 0)
398 break;
399
400 }
401 }
402 }
403
404 /* Not encrypted */
405 return call_dissector(corosync_totemsrp_handle, tvb, pinfo, parent_tree);
406 }
407
408 static void
corosync_totemnet_shutdown(void)409 corosync_totemnet_shutdown(void)
410 {
411 g_strfreev(corosync_totemnet_private_keys_list);
412 }
413
414 void
proto_register_corosync_totemnet(void)415 proto_register_corosync_totemnet(void)
416 {
417 module_t *corosync_totemnet_module;
418
419 static hf_register_info hf[] = {
420 { &hf_corosync_totemnet_security_header_hash_digest,
421 { "Hash digest", "corosync_totemnet.security_header_hash_digest",
422 FT_BYTES, BASE_NONE, NULL, 0x0,
423 NULL, HFILL }},
424 { &hf_corosync_totemnet_security_header_salt,
425 { "Salt", "corosync_totemnet.security_header_salt",
426 FT_BYTES, BASE_NONE, NULL, 0x0,
427 NULL, HFILL }},
428 { &hf_corosync_totemnet_security_crypto_type,
429 { "Cryptographic Type", "corosync_totemnet.security_crypto_type",
430 FT_UINT8, BASE_DEC, VALS(corosync_totemnet_crypto_type), 0x0,
431 NULL, HFILL }},
432 { &hf_corosync_totemnet_security_crypto_key,
433 { "Private Key for decryption", "corosync_totemnet.security_crypto_key",
434 FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
435 };
436
437 static gint *ett_corosync_totemnet[] = {
438 &ett_corosync_totemnet_security_header,
439 };
440
441 proto_corosync_totemnet = proto_register_protocol("Totemnet Layer of Corosync Cluster Engine",
442 "COROSYNC/TOTEMNET", "corosync_totemnet");
443 proto_register_field_array(proto_corosync_totemnet, hf, array_length(hf));
444 proto_register_subtree_array(ett_corosync_totemnet, array_length(ett_corosync_totemnet));
445
446 corosync_totemnet_module = prefs_register_protocol(proto_corosync_totemnet,
447 proto_reg_handoff_corosync_totemnet);
448
449 prefs_register_string_preference(corosync_totemnet_module, "private_keys", "Private keys",
450 "Semicolon-separated list of keys for decryption(e.g. key1;key2;..." ,
451 (const gchar **)&corosync_totemnet_private_keys);
452
453 register_shutdown_routine(corosync_totemnet_shutdown);
454 }
455
456 void
proto_reg_handoff_corosync_totemnet(void)457 proto_reg_handoff_corosync_totemnet(void)
458 {
459 static gboolean initialized = FALSE;
460 static dissector_handle_t corosync_totemnet_handle;
461
462
463 if (!initialized)
464 {
465 corosync_totemnet_handle = create_dissector_handle(dissect_corosynec_totemnet, proto_corosync_totemnet);
466 corosync_totemsrp_handle = find_dissector_add_dependency("corosync_totemsrp", proto_corosync_totemnet);
467
468 dissector_add_uint_range_with_preference("udp.port", PORT_COROSYNC_TOTEMNET_RANGE, corosync_totemnet_handle);
469 initialized = TRUE;
470 }
471
472 g_strfreev(corosync_totemnet_private_keys_list);
473 corosync_totemnet_private_keys_list = g_strsplit(corosync_totemnet_private_keys, ";", 0);
474 }
475
476 /*
477 * Editor modelines - https://www.wireshark.org/tools/modelines.html
478 *
479 * Local variables:
480 * c-basic-offset: 4
481 * tab-width: 8
482 * indent-tabs-mode: nil
483 * End:
484 *
485 * vi: set shiftwidth=4 tabstop=8 expandtab:
486 * :indentSize=4:tabSize=8:noTabs=true:
487 */
488