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