From 4be7db5f60117b1bda8175b2e5e6251d291fbf59 Mon Sep 17 00:00:00 2001 From: Codrut Cristian Grosu Date: Fri, 2 Sep 2016 15:22:29 +0300 Subject: [PATCH] save-keys: Store derived IKE_SA keys in Wireshark format The path has to be set first, otherwise, nothing is done. --- conf/plugins/save-keys.opt | 7 + .../plugins/save_keys/save_keys_listener.c | 196 ++++++++++++++++++ 2 files changed, 203 insertions(+) diff --git a/conf/plugins/save-keys.opt b/conf/plugins/save-keys.opt index ef1fb93139..9835c75cb7 100644 --- a/conf/plugins/save-keys.opt +++ b/conf/plugins/save-keys.opt @@ -1,2 +1,9 @@ charon.plugins.save-keys.load := no Whether to load the plugin. + +charon.plugins.save-keys.wireshark_keys + Directory where the keys are stored in the format supported by Wireshark + + Directory where the keys are stored in the format supported by Wireshark. + IKEv1 keys are stored in the _ikev1_decryption_table_ file. + IKEv2 keys are stored in the _ikev2_decryption_table_ file. diff --git a/src/libcharon/plugins/save_keys/save_keys_listener.c b/src/libcharon/plugins/save_keys/save_keys_listener.c index 19205614ba..183b6a7921 100644 --- a/src/libcharon/plugins/save_keys/save_keys_listener.c +++ b/src/libcharon/plugins/save_keys/save_keys_listener.c @@ -21,9 +21,28 @@ * THE SOFTWARE. */ +#define _GNU_SOURCE + #include "save_keys_listener.h" +#include +#include +#include + +#include + typedef struct private_save_keys_listener_t private_save_keys_listener_t; +typedef struct algo_map_t algo_map_t; + +/** + * Name for IKEv1 decryption table file + */ +static char *ikev1_name = "ikev1_decryption_table"; + +/** + * Name for IKEv2 decryption table file + */ +static char *ikev2_name = "ikev2_decryption_table"; /** * Private data. @@ -34,6 +53,11 @@ struct private_save_keys_listener_t { * Public interface. */ save_keys_listener_t public; + + /** + * Path to the directory where the decryption tables will be stored. + */ + char *path; }; METHOD(save_keys_listener_t, destroy, void, @@ -42,6 +66,173 @@ METHOD(save_keys_listener_t, destroy, void, free(this); } +/** + * Mapping strongSwan identifiers to Wireshark names + */ +struct algo_map_t { + + /** + * IKE identifier + */ + const uint16_t ike; + + /** + * Optional key length + */ + const int key_len; + + /** + * Name of the algorithm in wireshark + */ + const char *name; +}; + +/** + * Map an algorithm identifier to a name + */ +static inline const char *algo_name(algo_map_t *map, int count, + uint16_t alg, int key_len) +{ + int i; + + for (i = 0; i < count; i++) + { + if (map[i].ike == alg) + { + if (map[i].key_len == -1 || map[i].key_len == key_len) + { + return map[i].name; + } + } + } + return NULL; +} + +/** + * Wireshark IKE algorithm identifiers for encryption + */ +static algo_map_t ike_encr[] = { + { ENCR_3DES, -1, "3DES [RFC2451]" }, + { ENCR_NULL, -1, "NULL [RFC2410]" }, + { ENCR_AES_CBC, 128, "AES-CBC-128 [RFC3602]" }, + { ENCR_AES_CBC, 192, "AES-CBC-192 [RFC3602]" }, + { ENCR_AES_CBC, 256, "AES-CBC-256 [RFC3602]" }, + { ENCR_AES_CTR, 128, "AES-CTR-128 [RFC5930]" }, + { ENCR_AES_CTR, 192, "AES-CTR-192 [RFC5930]" }, + { ENCR_AES_CTR, 256, "AES-CTR-256 [RFC5930]" }, + { ENCR_AES_GCM_ICV8, 128, "AES-GCM-128 with 8 octet ICV [RFC5282]" }, + { ENCR_AES_GCM_ICV8, 192, "AES-GCM-192 with 8 octet ICV [RFC5282]" }, + { ENCR_AES_GCM_ICV8, 256, "AES-GCM-256 with 8 octet ICV [RFC5282]" }, + { ENCR_AES_GCM_ICV12, 128, "AES-GCM-128 with 12 octet ICV [RFC5282]" }, + { ENCR_AES_GCM_ICV12, 192, "AES-GCM-192 with 12 octet ICV [RFC5282]" }, + { ENCR_AES_GCM_ICV12, 256, "AES-GCM-256 with 12 octet ICV [RFC5282]" }, + { ENCR_AES_GCM_ICV16, 128, "AES-GCM-128 with 16 octet ICV [RFC5282]" }, + { ENCR_AES_GCM_ICV16, 192, "AES-GCM-192 with 16 octet ICV [RFC5282]" }, + { ENCR_AES_GCM_ICV16, 256, "AES-GCM-256 with 16 octet ICV [RFC5282]" }, + { ENCR_AES_CCM_ICV8, 128, "AES-CCM-128 with 8 octet ICV [RFC5282]" }, + { ENCR_AES_CCM_ICV8, 192, "AES-CCM-192 with 8 octet ICV [RFC5282]" }, + { ENCR_AES_CCM_ICV8, 256, "AES-CCM-256 with 8 octet ICV [RFC5282]" }, + { ENCR_AES_CCM_ICV12, 128, "AES-CCM-128 with 12 octet ICV [RFC5282]" }, + { ENCR_AES_CCM_ICV12, 192, "AES-CCM-192 with 12 octet ICV [RFC5282]" }, + { ENCR_AES_CCM_ICV12, 256, "AES-CCM-256 with 12 octet ICV [RFC5282]" }, + { ENCR_AES_CCM_ICV16, 128, "AES-CCM-128 with 16 octet ICV [RFC5282]" }, + { ENCR_AES_CCM_ICV16, 192, "AES-CCM-192 with 16 octet ICV [RFC5282]" }, + { ENCR_AES_CCM_ICV16, 256, "AES-CCM-256 with 16 octet ICV [RFC5282]" }, +}; + +/** + * Wireshark IKE algorithms for integrity + */ +static algo_map_t ike_integ[] = { + { AUTH_HMAC_MD5_96, -1, "HMAC_MD5_96 [RFC2403]" }, + { AUTH_HMAC_SHA1_96, -1, "HMAC_SHA1_96 [RFC2404]" }, + { AUTH_HMAC_MD5_128, -1, "HMAC_MD5_128 [RFC4595]" }, + { AUTH_HMAC_SHA1_160, -1, "HMAC_SHA1_160 [RFC4595]" }, + { AUTH_HMAC_SHA2_256_128, -1, "HMAC_SHA2_256_128 [RFC4868]" }, + { AUTH_HMAC_SHA2_384_192, -1, "HMAC_SHA2_384_192 [RFC4868]" }, + { AUTH_HMAC_SHA2_512_256, -1, "HMAC_SHA2_512_256 [RFC4868]" }, + { AUTH_HMAC_SHA2_256_96, -1, "HMAC_SHA2_256_96 [draft-ietf-ipsec-ciph-sha-256-00]" }, + { AUTH_UNDEFINED, -1, "NONE [RFC4306]" }, +}; + +/** + * Map an IKE proposal + */ +static inline void ike_names(proposal_t *proposal, const char **enc, + const char **integ) +{ + uint16_t alg, len; + + if (proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &alg, &len)) + { + *enc = algo_name(ike_encr, countof(ike_encr), alg, len); + } + if (encryption_algorithm_is_aead(alg)) + { + alg = AUTH_UNDEFINED; + } + else if (!proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &alg, NULL)) + { + return; + } + *integ = algo_name(ike_integ, countof(ike_integ), alg, -1); +} + + +METHOD(listener_t, ike_derived_keys, bool, + private_save_keys_listener_t *this, ike_sa_t *ike_sa, chunk_t sk_ei, + chunk_t sk_er, chunk_t sk_ai, chunk_t sk_ar) +{ + ike_version_t version; + ike_sa_id_t *id; + const char *enc = NULL, *integ = NULL; + char *path, *name; + FILE *file; + + if (!this->path) + { + return TRUE; + } + + version = ike_sa->get_version(ike_sa); + name = version == IKEV2 ? ikev2_name : ikev1_name; + if (asprintf(&path, "%s/%s", this->path, name) < 0) + { + DBG1(DBG_IKE, "failed to build path to IKE key table"); + return TRUE; + } + + file = fopen(path, "a"); + if (file) + { + id = ike_sa->get_id(ike_sa); + if (version == IKEV2) + { + ike_names(ike_sa->get_proposal(ike_sa), &enc, &integ); + if (enc && integ) + { + fprintf(file, "%.16"PRIx64",%.16"PRIx64",%+B,%+B,\"%s\"," + "%+B,%+B,\"%s\"\n", be64toh(id->get_initiator_spi(id)), + be64toh(id->get_responder_spi(id)), &sk_ei, &sk_er, + enc, &sk_ai, &sk_ar, integ); + } + } + else + { + fprintf(file, "%.16"PRIx64",%+B\n", + be64toh(id->get_initiator_spi(id)), &sk_ei); + } + fclose(file); + } + else + { + DBG1(DBG_IKE, "failed to open IKE key table '%s': %s", path, + strerror(errno)); + } + free(path); + return TRUE; +} + /** * See header. */ @@ -52,9 +243,14 @@ save_keys_listener_t *save_keys_listener_create() INIT(this, .public = { .listener = { + .ike_derived_keys = _ike_derived_keys, }, .destroy = _destroy, }, + .path = lib->settings->get_str(lib->settings, + "%s.plugins.save-keys.wireshark_keys", + NULL, lib->ns), ); + return &this->public; } -- 2.39.2