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