diff options
Diffstat (limited to 'epan/dissectors/packet-corosync-totemnet.c')
-rw-r--r-- | epan/dissectors/packet-corosync-totemnet.c | 486 |
1 files changed, 486 insertions, 0 deletions
diff --git a/epan/dissectors/packet-corosync-totemnet.c b/epan/dissectors/packet-corosync-totemnet.c new file mode 100644 index 00000000..132155e1 --- /dev/null +++ b/epan/dissectors/packet-corosync-totemnet.c @@ -0,0 +1,486 @@ +/* packet-corosync-totemnet.c + * Dissector routines for the lowest level(encryption/decryption) protocol used in Corosync cluster engine + * Copyright 2009 2010 2014 Masatake YAMATO <yamato@redhat.com> + * Copyright (c) 2010 2014 Red Hat, Inc. + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "config.h" + +#include <epan/packet.h> +#include <epan/prefs.h> +#include <wsutil/wsgcrypt.h> +#include <wsutil/sober128.h> + +static dissector_handle_t corosync_totemnet_handle; +static dissector_handle_t corosync_totemsrp_handle; + +/* This dissector deals packets defined in totemnet.c of corosync + cluster engine. In the totemnet.c the packet is encrypted and decrypted + with LibTomCrypt. This dissector tries decrypting the packet with + sober128 and sha1 functions in wireshark. */ + +/* + * Dissector body + */ + +#define PORT_COROSYNC_TOTEMNET_RANGE "5404-5405" /* Not IANA registered */ + +/* Forward declaration we need below */ +void proto_register_corosync_totemnet(void); +void proto_reg_handoff_corosync_totemnet(void); + +/* Initialize the protocol and registered fields */ +static int proto_corosync_totemnet = -1; + +/* field of struct security_header */ +static int hf_corosync_totemnet_security_header_hash_digest = -1; +static int hf_corosync_totemnet_security_header_salt = -1; +static int hf_corosync_totemnet_security_crypto_type = -1; +static int hf_corosync_totemnet_security_crypto_key = -1; + +/* configurable parameters */ +static gchar* corosync_totemnet_private_keys = NULL; +static gchar** corosync_totemnet_private_keys_list = NULL; + +/* Initialize the subtree pointers */ +static gint ett_corosync_totemnet_security_header = -1; + +#define SALT_SIZE 16 + +#define TOTEM_CRYPTO_SOBER 0 +#define TOTEM_CRYPTO_NSS 1 + +static const value_string corosync_totemnet_crypto_type[] = { + { TOTEM_CRYPTO_SOBER, "SOBER" }, + { TOTEM_CRYPTO_NSS, "NSS" }, + { 0, NULL } +}; + + +static int +dissect_corosync_totemnet_security_header(tvbuff_t *tvb, + packet_info *pinfo, proto_tree *parent_tree, + gboolean check_crypt_type, + const gchar* key) +{ + proto_item *item; + proto_tree *tree; + + col_set_str(pinfo->cinfo, COL_PROTOCOL, "COROSYNC/TOTEMNET"); + col_clear(pinfo->cinfo, COL_INFO); + + if (parent_tree) + { + item = proto_tree_add_item(parent_tree, proto_corosync_totemnet, tvb, 0, + -1, ENC_NA); + tree = proto_item_add_subtree(item, ett_corosync_totemnet_security_header); + + proto_tree_add_item(tree, + hf_corosync_totemnet_security_header_hash_digest, + tvb, 0, HASH_SHA1_LENGTH, ENC_NA); + proto_tree_add_item(tree, + hf_corosync_totemnet_security_header_salt, + tvb, HASH_SHA1_LENGTH, SALT_SIZE, ENC_NA); + + if (check_crypt_type) + { + int io_len = tvb_reported_length(tvb); + proto_item * key_item; + + proto_tree_add_item(tree, + hf_corosync_totemnet_security_crypto_type, + tvb, io_len - 1, 1, ENC_BIG_ENDIAN); + key_item = proto_tree_add_string(tree, + hf_corosync_totemnet_security_crypto_key, + tvb, 0, 0, key); + proto_item_set_generated(key_item); + } + } + return HASH_SHA1_LENGTH + SALT_SIZE; +} + +/* About totemnet.c of corosync cluster engine: + * + * dissect_corosynec_totemnet_with_decryption() is derived from + * totemnet.c in corosync which is licensed under 3-clause BSD license. + * However, to merge this dissector to wireshark official source tree, + * corosync developers permit EXPLICITLY to reuse totemnet.c in GPL. + * + http://permalink.gmane.org/gmane.linux.redhat.cluster/19087 + ------------------------------------------------------------ + Steven Dake | 4 Jan 2011 22:02 + Re: [Openais] packet dissectors for totempg, cman, clvmd, rgmanager, cpg, + +On 12/14/2010 08:04 AM, Masatake YAMATO wrote: +> Thank you for replying. +> +>> Masatake, +>> +>> Masatake YAMATO napsal(a): +>>> I'd like to your advice more detail seriously. +>>> I've been developing this code for three years. +>>> I don't want to make this code garbage. +>>> +>>>> Masatake, +>>>> I'm pretty sure that biggest problem of your code was that it was +>>>> licensed under BSD (three clause, same as Corosync has) +>>>> license. Wireshark is licensed under GPL and even I like BSD licenses +>>>> much more, I would recommend you to try to relicense code under GPL +>>>> and send them this code. +>>>> +>>>> Regards, +>>>> Honza +>>> I got the similar comment from wireshark developer. +>>> Please, read the discussion: +>>> https://gitlab.com/wireshark/wireshark/-/issues/3232 +>>> +>> +>> I've read that thread long time before I've sent previous mail, so +>> thats reason why I think that Wireshark developers just feel MUCH more +>> comfortable with GPL and thats reason why they just ignoring it. +> +> I see. +> +>>> In my understanding there is no legal problem in putting 3-clause BSD +>>> code into GPL code. Acutally wireshark includes some 3-clause BSD +>>> code: +>>> +nnn>> +>> Actually there is really not. BSD to GPL works without problem, but +>> many people just don't know it... +> +> ...it is too bad. I strongly believe FOSS developers should know the +> intent behind of the both licenses. +> +>>> epan/dissectors/packet-radiotap-defs.h: +>>> *//*- +>>> * Copyright (c) 2003, 2004 David Young. All rights reserved. +>>> * +... +>>> * +>>> * Redistribution and use in source and binary forms, with or without +>>> * modification, are permitted provided that the following conditions +>>> * are met: +>>> * 1. Redistributions of source code must retain the above copyright +>>> * notice, this list of conditions and the following disclaimer. +>>> * 2. Redistributions in binary form must reproduce the above copyright +>>> * notice, this list of conditions and the following disclaimer in the +>>> * documentation and/or other materials provided with the distribution. +>>> * 3. The name of David Young may not be used to endorse or promote +>>> * products derived from this software without specific prior +>>> * written permission. +>>> * +>>> * THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY +>>> * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +>>> * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +>>> * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID +>>> * YOUNG BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +>>> * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +>>> * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +>>> * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +>>> * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +>>> * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +>>> * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +>>> * OF SUCH DAMAGE. +>>> *//* +>>> I'd like to separate the legal issue and preference. I think I +>>> understand the importance of preference of upstream +>>> developers. However, I'd like to clear the legal issue first. +>>> +>> +>> Legally it's ok. But as you said, developers preference are +>> different. And because you are trying to change THEIR code it's +>> sometimes better to play they rules. +> +> I see. +> +>>> I can image there are people who prefer to GPL as the license covering +>>> their software. But here I've taken some corosync code in my +>>> dissector. It is essential part of my dissector. And corosync is +>> +>> ^^^ This may be problem. Question is how big is that part and if it +>> can be possible to make exception there. Can you point that code? +>> +>> Steve, we were able to relicense HUGE portion of code in case of +>> libqb, are we able to make the same for Wireshark dissector? +> +> Could you see https://github.com/masatake/wireshark-plugin-rhcs/blob/master/src/packet-corosync-totemnet.c#L156 +> I refer totemnet.c to write dissect_corosynec_totemnet_with_decryption() function. +> +>>> licensed in 3-clause BSD, as you know. I'd like to change the license +>>> to merge my code to upstream project. I cannot do it in this context. +>>> See https://gitlab.com/wireshark/wireshark/-/issues/3232#c13 +>>> Thank you. +>> +>> Regards, +>> Honza +> +> Masatake YAMATO + +Masatake, + +Red Hat is the author of the totemnet file and can provide that code +under GPL if you like. We cannot modify the license for libtomcrypt as +we are not the authors. Feel free to change the license for that +particular code you rewrote in the link + +> Could you see +https://github.com/masatake/wireshark-plugin-rhcs/blob/master/src/packet-corosync-totemnet.c#L156 + +under a GPL license if it helps move things along. + +Regards +-steveu + */ + +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) +{ + unsigned char keys[48]; + sober128_prng keygen_prng_state; + sober128_prng stream_prng_state; + unsigned char *hmac_key = &keys[32]; + unsigned char *cipher_key = &keys[16]; + unsigned char *initial_vector = &keys[0]; + unsigned char digest_comparison[HASH_SHA1_LENGTH]; + + int io_len; + guint8 *io_base; + +#define PRIVATE_KEY_LEN_MAX 256 + gchar private_key[PRIVATE_KEY_LEN_MAX]; + gsize private_key_len; + unsigned char* hash_digest; + unsigned char* salt; + + io_len = tvb_reported_length(tvb) - (check_crypt_type? 1: 0); + if (io_len < HASH_SHA1_LENGTH + SALT_SIZE) { + return 0; + } + + io_base = (guint8 *)tvb_memdup(pinfo->pool, tvb, 0, io_len + (check_crypt_type? 1: 0)); + if (check_crypt_type && + ( io_base[io_len] != TOTEM_CRYPTO_SOBER )) { + return 0; + } + + hash_digest = io_base; + salt = io_base + HASH_SHA1_LENGTH; + + + memset(private_key, 0, sizeof(private_key)); + + private_key_len = (strlen(key_for_trial)+4) & 0xFC; + (void) g_strlcpy(private_key, key_for_trial, private_key_len); + + /* + * Generate MAC, CIPHER, IV keys from private key + */ + memset(keys, 0, sizeof(keys)); + sober128_start(&keygen_prng_state); + sober128_add_entropy(private_key, + (unsigned long)private_key_len, &keygen_prng_state); + sober128_add_entropy(salt, SALT_SIZE, &keygen_prng_state); + sober128_read(keys, sizeof (keys), &keygen_prng_state); + + /* + * Setup stream cipher + */ + sober128_start (&stream_prng_state); + sober128_add_entropy (cipher_key, 16, &stream_prng_state); + sober128_add_entropy (initial_vector, 16, &stream_prng_state); + + /* + * Authenticate contents of message + */ + if (ws_hmac_buffer(GCRY_MD_SHA1, digest_comparison, io_base + HASH_SHA1_LENGTH, io_len - HASH_SHA1_LENGTH, hmac_key, 16)) { + return 0; + } + + if (memcmp (digest_comparison, hash_digest, HASH_SHA1_LENGTH) != 0) + return 0; + + /* + * Decrypt the contents of the message with the cipher key + */ + + sober128_read(io_base + HASH_SHA1_LENGTH + SALT_SIZE, + io_len - (HASH_SHA1_LENGTH + SALT_SIZE), + &stream_prng_state); + + + /* + * Dissect the decrypted data + */ + { + tvbuff_t *decrypted_tvb; + tvbuff_t *next_tvb; + + + decrypted_tvb = tvb_new_real_data(io_base, io_len, io_len); + + tvb_set_child_real_data_tvbuff(tvb, decrypted_tvb); + add_new_data_source(pinfo, decrypted_tvb, "Decrypted Data"); + + + dissect_corosync_totemnet_security_header(decrypted_tvb, pinfo, parent_tree, + check_crypt_type, key_for_trial); + + next_tvb = tvb_new_subset_length(decrypted_tvb, + HASH_SHA1_LENGTH + SALT_SIZE, + io_len - (HASH_SHA1_LENGTH + SALT_SIZE)); + + return call_dissector(corosync_totemsrp_handle, next_tvb, pinfo, parent_tree) + HASH_SHA1_LENGTH + SALT_SIZE; + } +} + +static int +dissect_corosynec_totemnet(tvbuff_t *tvb, + packet_info *pinfo, proto_tree *parent_tree, + void *data _U_) +{ + if (corosync_totemnet_private_keys_list) + { + static int last_key_index = -1; + int key_index; + + static int last_check_crypt_type_index; + int check_crypt_type_index = -1; + gboolean check_crypt_type_list[] = {FALSE, TRUE}; + + + if (last_key_index != -1) + { + int r; + + r = dissect_corosynec_totemnet_with_decryption(tvb, + pinfo, + parent_tree, + check_crypt_type_list[last_check_crypt_type_index], + corosync_totemnet_private_keys_list[last_key_index]); + if (r > 0) + return r; + else + last_key_index = -1; + } + + for (key_index = 0; + corosync_totemnet_private_keys_list[key_index]; + key_index++) + { + for (check_crypt_type_index = 0; + check_crypt_type_index < 2; + check_crypt_type_index++) + { + int r; + + r = dissect_corosynec_totemnet_with_decryption(tvb, + pinfo, + parent_tree, + check_crypt_type_list[check_crypt_type_index], + corosync_totemnet_private_keys_list[key_index]); + if (r > 0) + { + last_key_index = key_index; + last_check_crypt_type_index = check_crypt_type_index; + return r; + } + else if (r < 0) + break; + + } + } + } + + /* Not encrypted */ + return call_dissector(corosync_totemsrp_handle, tvb, pinfo, parent_tree); +} + +static void +corosync_totemnet_shutdown(void) +{ + g_strfreev(corosync_totemnet_private_keys_list); +} + +void +proto_register_corosync_totemnet(void) +{ + module_t *corosync_totemnet_module; + + static hf_register_info hf[] = { + { &hf_corosync_totemnet_security_header_hash_digest, + { "Hash digest", "corosync_totemnet.security_header_hash_digest", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_corosync_totemnet_security_header_salt, + { "Salt", "corosync_totemnet.security_header_salt", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + { &hf_corosync_totemnet_security_crypto_type, + { "Cryptographic Type", "corosync_totemnet.security_crypto_type", + FT_UINT8, BASE_DEC, VALS(corosync_totemnet_crypto_type), 0x0, + NULL, HFILL }}, + { &hf_corosync_totemnet_security_crypto_key, + { "Private Key for decryption", "corosync_totemnet.security_crypto_key", + FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, + }; + + static gint *ett_corosync_totemnet[] = { + &ett_corosync_totemnet_security_header, + }; + + proto_corosync_totemnet = proto_register_protocol("Totemnet Layer of Corosync Cluster Engine", + "COROSYNC/TOTEMNET", "corosync_totemnet"); + proto_register_field_array(proto_corosync_totemnet, hf, array_length(hf)); + proto_register_subtree_array(ett_corosync_totemnet, array_length(ett_corosync_totemnet)); + + corosync_totemnet_module = prefs_register_protocol(proto_corosync_totemnet, + proto_reg_handoff_corosync_totemnet); + + prefs_register_string_preference(corosync_totemnet_module, "private_keys", "Private keys", + "Semicolon-separated list of keys for decryption(e.g. key1;key2;..." , + (const gchar **)&corosync_totemnet_private_keys); + + register_shutdown_routine(corosync_totemnet_shutdown); + + corosync_totemnet_handle = register_dissector("corosync_totemnet", dissect_corosynec_totemnet, proto_corosync_totemnet); +} + +void +proto_reg_handoff_corosync_totemnet(void) +{ + static gboolean initialized = FALSE; + + if (!initialized) + { + corosync_totemsrp_handle = find_dissector_add_dependency("corosync_totemsrp", proto_corosync_totemnet); + + dissector_add_uint_range_with_preference("udp.port", PORT_COROSYNC_TOTEMNET_RANGE, corosync_totemnet_handle); + initialized = TRUE; + } + + g_strfreev(corosync_totemnet_private_keys_list); + corosync_totemnet_private_keys_list = g_strsplit(corosync_totemnet_private_keys, ";", 0); +} + +/* + * Editor modelines - https://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * vi: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ |