Annotation of embedaddon/strongswan/src/libcharon/plugins/save_keys/save_keys_listener.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2018 Tobias Brunner
! 3: * HSR Hochschule fuer Technik Rapperswil
! 4: *
! 5: * This program is free software; you can redistribute it and/or modify it
! 6: * under the terms of the GNU General Public License as published by the
! 7: * Free Software Foundation; either version 2 of the License, or (at your
! 8: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 9: *
! 10: * This program is distributed in the hope that it will be useful, but
! 11: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 12: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 13: * for more details.
! 14: */
! 15: /*
! 16: * Copyright (C) 2016 Codrut Cristian Grosu (codrut.cristian.grosu@gmail.com)
! 17: * Copyright (C) 2016 IXIA (http://www.ixiacom.com)
! 18: *
! 19: * Permission is hereby granted, free of charge, to any person obtaining a copy
! 20: * of this software and associated documentation files (the "Software"), to deal
! 21: * in the Software without restriction, including without limitation the rights
! 22: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
! 23: * copies of the Software, and to permit persons to whom the Software is
! 24: * furnished to do so, subject to the following conditions:
! 25: *
! 26: * The above copyright notice and this permission notice shall be included in
! 27: * all copies or substantial portions of the Software.
! 28: *
! 29: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
! 30: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
! 31: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
! 32: * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
! 33: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
! 34: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
! 35: * THE SOFTWARE.
! 36: */
! 37:
! 38: #define _GNU_SOURCE
! 39:
! 40: #include "save_keys_listener.h"
! 41:
! 42: #include <stdio.h>
! 43: #include <inttypes.h>
! 44: #include <errno.h>
! 45:
! 46: #include <daemon.h>
! 47:
! 48: typedef struct private_save_keys_listener_t private_save_keys_listener_t;
! 49: typedef struct algo_map_t algo_map_t;
! 50:
! 51: /**
! 52: * Name for IKEv1 decryption table file
! 53: */
! 54: static char *ikev1_name = "ikev1_decryption_table";
! 55:
! 56: /**
! 57: * Name for IKEv2 decryption table file
! 58: */
! 59: static char *ikev2_name = "ikev2_decryption_table";
! 60:
! 61: /**
! 62: * Name for esp decryption table file
! 63: */
! 64: static char *esp_name = "esp_sa";
! 65:
! 66: /**
! 67: * Private data.
! 68: */
! 69: struct private_save_keys_listener_t {
! 70:
! 71: /**
! 72: * Public interface.
! 73: */
! 74: save_keys_listener_t public;
! 75:
! 76: /**
! 77: * Path to the directory where the decryption tables will be stored.
! 78: */
! 79: char *path;
! 80:
! 81: /**
! 82: * Whether to save IKE keys
! 83: */
! 84: bool ike;
! 85:
! 86: /**
! 87: * Whether to save ESP keys
! 88: */
! 89: bool esp;
! 90: };
! 91:
! 92: METHOD(save_keys_listener_t, destroy, void,
! 93: private_save_keys_listener_t *this)
! 94: {
! 95: free(this);
! 96: }
! 97:
! 98: /**
! 99: * Mapping strongSwan identifiers to Wireshark names
! 100: */
! 101: struct algo_map_t {
! 102:
! 103: /**
! 104: * IKE identifier
! 105: */
! 106: const uint16_t ike;
! 107:
! 108: /**
! 109: * Optional key length
! 110: */
! 111: const int key_len;
! 112:
! 113: /**
! 114: * Name of the algorithm in wireshark
! 115: */
! 116: const char *name;
! 117: };
! 118:
! 119: /**
! 120: * Map an algorithm identifier to a name
! 121: */
! 122: static inline const char *algo_name(algo_map_t *map, int count,
! 123: uint16_t alg, int key_len)
! 124: {
! 125: int i;
! 126:
! 127: for (i = 0; i < count; i++)
! 128: {
! 129: if (map[i].ike == alg)
! 130: {
! 131: if (map[i].key_len == -1 || map[i].key_len == key_len)
! 132: {
! 133: return map[i].name;
! 134: }
! 135: }
! 136: }
! 137: return NULL;
! 138: }
! 139:
! 140: /**
! 141: * Wireshark IKE algorithm identifiers for encryption
! 142: */
! 143: static algo_map_t ike_encr[] = {
! 144: { ENCR_3DES, -1, "3DES [RFC2451]" },
! 145: { ENCR_NULL, -1, "NULL [RFC2410]" },
! 146: { ENCR_AES_CBC, 128, "AES-CBC-128 [RFC3602]" },
! 147: { ENCR_AES_CBC, 192, "AES-CBC-192 [RFC3602]" },
! 148: { ENCR_AES_CBC, 256, "AES-CBC-256 [RFC3602]" },
! 149: { ENCR_AES_CTR, 128, "AES-CTR-128 [RFC5930]" },
! 150: { ENCR_AES_CTR, 192, "AES-CTR-192 [RFC5930]" },
! 151: { ENCR_AES_CTR, 256, "AES-CTR-256 [RFC5930]" },
! 152: { ENCR_AES_GCM_ICV8, 128, "AES-GCM-128 with 8 octet ICV [RFC5282]" },
! 153: { ENCR_AES_GCM_ICV8, 192, "AES-GCM-192 with 8 octet ICV [RFC5282]" },
! 154: { ENCR_AES_GCM_ICV8, 256, "AES-GCM-256 with 8 octet ICV [RFC5282]" },
! 155: { ENCR_AES_GCM_ICV12, 128, "AES-GCM-128 with 12 octet ICV [RFC5282]" },
! 156: { ENCR_AES_GCM_ICV12, 192, "AES-GCM-192 with 12 octet ICV [RFC5282]" },
! 157: { ENCR_AES_GCM_ICV12, 256, "AES-GCM-256 with 12 octet ICV [RFC5282]" },
! 158: { ENCR_AES_GCM_ICV16, 128, "AES-GCM-128 with 16 octet ICV [RFC5282]" },
! 159: { ENCR_AES_GCM_ICV16, 192, "AES-GCM-192 with 16 octet ICV [RFC5282]" },
! 160: { ENCR_AES_GCM_ICV16, 256, "AES-GCM-256 with 16 octet ICV [RFC5282]" },
! 161: { ENCR_AES_CCM_ICV8, 128, "AES-CCM-128 with 8 octet ICV [RFC5282]" },
! 162: { ENCR_AES_CCM_ICV8, 192, "AES-CCM-192 with 8 octet ICV [RFC5282]" },
! 163: { ENCR_AES_CCM_ICV8, 256, "AES-CCM-256 with 8 octet ICV [RFC5282]" },
! 164: { ENCR_AES_CCM_ICV12, 128, "AES-CCM-128 with 12 octet ICV [RFC5282]" },
! 165: { ENCR_AES_CCM_ICV12, 192, "AES-CCM-192 with 12 octet ICV [RFC5282]" },
! 166: { ENCR_AES_CCM_ICV12, 256, "AES-CCM-256 with 12 octet ICV [RFC5282]" },
! 167: { ENCR_AES_CCM_ICV16, 128, "AES-CCM-128 with 16 octet ICV [RFC5282]" },
! 168: { ENCR_AES_CCM_ICV16, 192, "AES-CCM-192 with 16 octet ICV [RFC5282]" },
! 169: { ENCR_AES_CCM_ICV16, 256, "AES-CCM-256 with 16 octet ICV [RFC5282]" },
! 170: };
! 171:
! 172: /**
! 173: * Wireshark IKE algorithms for integrity
! 174: */
! 175: static algo_map_t ike_integ[] = {
! 176: { AUTH_HMAC_MD5_96, -1, "HMAC_MD5_96 [RFC2403]" },
! 177: { AUTH_HMAC_SHA1_96, -1, "HMAC_SHA1_96 [RFC2404]" },
! 178: { AUTH_HMAC_MD5_128, -1, "HMAC_MD5_128 [RFC4595]" },
! 179: { AUTH_HMAC_SHA1_160, -1, "HMAC_SHA1_160 [RFC4595]" },
! 180: { AUTH_HMAC_SHA2_256_128, -1, "HMAC_SHA2_256_128 [RFC4868]" },
! 181: { AUTH_HMAC_SHA2_384_192, -1, "HMAC_SHA2_384_192 [RFC4868]" },
! 182: { AUTH_HMAC_SHA2_512_256, -1, "HMAC_SHA2_512_256 [RFC4868]" },
! 183: { AUTH_HMAC_SHA2_256_96, -1, "HMAC_SHA2_256_96 [draft-ietf-ipsec-ciph-sha-256-00]" },
! 184: { AUTH_UNDEFINED, -1, "NONE [RFC4306]" },
! 185: };
! 186:
! 187: /**
! 188: * Map an IKE proposal
! 189: */
! 190: static inline void ike_names(proposal_t *proposal, const char **enc,
! 191: const char **integ)
! 192: {
! 193: uint16_t alg, len;
! 194:
! 195: if (proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &alg, &len))
! 196: {
! 197: *enc = algo_name(ike_encr, countof(ike_encr), alg, len);
! 198: }
! 199: if (encryption_algorithm_is_aead(alg))
! 200: {
! 201: alg = AUTH_UNDEFINED;
! 202: }
! 203: else if (!proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &alg, NULL))
! 204: {
! 205: return;
! 206: }
! 207: *integ = algo_name(ike_integ, countof(ike_integ), alg, -1);
! 208: }
! 209:
! 210: /**
! 211: * Wireshark ESP algorithm identifiers for encryption
! 212: */
! 213: static algo_map_t esp_encr[] = {
! 214: { ENCR_NULL, -1, "NULL" },
! 215: { ENCR_3DES, -1, "TripleDes-CBC [RFC2451]" },
! 216: { ENCR_AES_CBC, -1, "AES-CBC [RFC3602]" },
! 217: { ENCR_AES_CTR, -1, "AES-CTR [RFC3686]" },
! 218: { ENCR_DES, -1, "DES-CBC [RFC2405]" },
! 219: { ENCR_CAST, -1, "CAST5-CBC [RFC2144]" },
! 220: { ENCR_BLOWFISH, -1, "BLOWFISH-CBC [RFC2451]" },
! 221: { ENCR_TWOFISH_CBC, -1, "TWOFISH-CBC" },
! 222: { ENCR_AES_GCM_ICV8, -1, "AES-GCM [RFC4106]" },
! 223: { ENCR_AES_GCM_ICV12, -1, "AES-GCM [RFC4106]" },
! 224: { ENCR_AES_GCM_ICV16, -1, "AES-GCM [RFC4106]" },
! 225: };
! 226:
! 227: /**
! 228: * Wireshark ESP algorithms for integrity
! 229: */
! 230: static algo_map_t esp_integ[] = {
! 231: { AUTH_HMAC_SHA1_96, -1, "HMAC-SHA-1-96 [RFC2404]" },
! 232: { AUTH_HMAC_MD5_96, -1, "HMAC-MD5-96 [RFC2403]" },
! 233: { AUTH_HMAC_SHA2_256_128, -1, "HMAC-SHA-256-128 [RFC4868]" },
! 234: { AUTH_HMAC_SHA2_384_192, -1, "HMAC-SHA-384-192 [RFC4868]" },
! 235: { AUTH_HMAC_SHA2_512_256, -1, "HMAC-SHA-512-256 [RFC4868]" },
! 236: { AUTH_HMAC_SHA2_256_96, -1, "HMAC-SHA-256-96 [draft-ietf-ipsec-ciph-sha-256-00]" },
! 237: { AUTH_UNDEFINED, 64, "ANY 64 bit authentication [no checking]" },
! 238: { AUTH_UNDEFINED, 96, "ANY 96 bit authentication [no checking]" },
! 239: { AUTH_UNDEFINED, 128, "ANY 128 bit authentication [no checking]" },
! 240: { AUTH_UNDEFINED, 192, "ANY 192 bit authentication [no checking]" },
! 241: { AUTH_UNDEFINED, 256, "ANY 256 bit authentication [no checking]" },
! 242: { AUTH_UNDEFINED, -1, "NULL" },
! 243: };
! 244:
! 245: /**
! 246: * Map an ESP proposal
! 247: */
! 248: static inline void esp_names(proposal_t *proposal, const char **enc,
! 249: const char **integ)
! 250: {
! 251: uint16_t alg, len;
! 252:
! 253: if (proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &alg, &len))
! 254: {
! 255: *enc = algo_name(esp_encr, countof(esp_encr), alg, len);
! 256: }
! 257: len = -1;
! 258: if (!proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &alg, NULL))
! 259: {
! 260: switch (alg)
! 261: {
! 262: case ENCR_AES_GCM_ICV8:
! 263: len = 64;
! 264: break;
! 265: case ENCR_AES_GCM_ICV12:
! 266: len = 64;
! 267: break;
! 268: case ENCR_AES_GCM_ICV16:
! 269: len = 128;
! 270: break;
! 271: }
! 272: alg = AUTH_UNDEFINED;
! 273: }
! 274: *integ = algo_name(esp_integ, countof(esp_integ), alg, len);
! 275: }
! 276:
! 277: METHOD(listener_t, ike_derived_keys, bool,
! 278: private_save_keys_listener_t *this, ike_sa_t *ike_sa, chunk_t sk_ei,
! 279: chunk_t sk_er, chunk_t sk_ai, chunk_t sk_ar)
! 280: {
! 281: ike_version_t version;
! 282: ike_sa_id_t *id;
! 283: const char *enc = NULL, *integ = NULL;
! 284: char *path, *name;
! 285: FILE *file;
! 286:
! 287: if (!this->path || !this->ike)
! 288: {
! 289: return TRUE;
! 290: }
! 291:
! 292: version = ike_sa->get_version(ike_sa);
! 293: name = version == IKEV2 ? ikev2_name : ikev1_name;
! 294: if (asprintf(&path, "%s/%s", this->path, name) < 0)
! 295: {
! 296: DBG1(DBG_IKE, "failed to build path to IKE key table");
! 297: return TRUE;
! 298: }
! 299:
! 300: file = fopen(path, "a");
! 301: if (file)
! 302: {
! 303: id = ike_sa->get_id(ike_sa);
! 304: if (version == IKEV2)
! 305: {
! 306: ike_names(ike_sa->get_proposal(ike_sa), &enc, &integ);
! 307: if (enc && integ)
! 308: {
! 309: fprintf(file, "%.16"PRIx64",%.16"PRIx64",%+B,%+B,\"%s\","
! 310: "%+B,%+B,\"%s\"\n", be64toh(id->get_initiator_spi(id)),
! 311: be64toh(id->get_responder_spi(id)), &sk_ei, &sk_er,
! 312: enc, &sk_ai, &sk_ar, integ);
! 313: }
! 314: }
! 315: else
! 316: {
! 317: fprintf(file, "%.16"PRIx64",%+B\n",
! 318: be64toh(id->get_initiator_spi(id)), &sk_ei);
! 319: }
! 320: fclose(file);
! 321: }
! 322: else
! 323: {
! 324: DBG1(DBG_IKE, "failed to open IKE key table '%s': %s", path,
! 325: strerror(errno));
! 326: }
! 327: free(path);
! 328: return TRUE;
! 329: }
! 330:
! 331: METHOD(listener_t, child_derived_keys, bool,
! 332: private_save_keys_listener_t *this, ike_sa_t *ike_sa, child_sa_t *child_sa,
! 333: bool initiator, chunk_t encr_i, chunk_t encr_r, chunk_t integ_i,
! 334: chunk_t integ_r)
! 335: {
! 336: host_t *init, *resp;
! 337: uint32_t spi_i, spi_r;
! 338: const char *enc = NULL, *integ = NULL;
! 339: char *path, *family;
! 340: FILE *file;
! 341:
! 342: if (!this->path || !this->esp ||
! 343: child_sa->get_protocol(child_sa) != PROTO_ESP)
! 344: {
! 345: return TRUE;
! 346: }
! 347:
! 348: if (asprintf(&path, "%s/%s", this->path, esp_name) < 0)
! 349: {
! 350: DBG1(DBG_CHD, "failed to build path to ESP key table");
! 351: return TRUE;
! 352: }
! 353:
! 354: file = fopen(path, "a");
! 355: if (file)
! 356: {
! 357: esp_names(child_sa->get_proposal(child_sa), &enc, &integ);
! 358: if (enc && integ)
! 359: {
! 360: /* Since the IPs are printed this is not compatible with MOBIKE */
! 361: if (initiator)
! 362: {
! 363: init = ike_sa->get_my_host(ike_sa);
! 364: resp = ike_sa->get_other_host(ike_sa);
! 365: }
! 366: else
! 367: {
! 368: init = ike_sa->get_other_host(ike_sa);
! 369: resp = ike_sa->get_my_host(ike_sa);
! 370: }
! 371: spi_i = child_sa->get_spi(child_sa, initiator);
! 372: spi_r = child_sa->get_spi(child_sa, !initiator);
! 373: family = init->get_family(init) == AF_INET ? "IPv4" : "IPv6";
! 374: fprintf(file, "\"%s\",\"%H\",\"%H\",\"0x%.8x\",\"%s\",\"0x%+B\","
! 375: "\"%s\",\"0x%+B\"\n", family, init, resp, ntohl(spi_r), enc,
! 376: &encr_i, integ, &integ_i);
! 377: fprintf(file, "\"%s\",\"%H\",\"%H\",\"0x%.8x\",\"%s\",\"0x%+B\","
! 378: "\"%s\",\"0x%+B\"\n", family, resp, init, ntohl(spi_i), enc,
! 379: &encr_r, integ, &integ_r);
! 380: }
! 381: fclose(file);
! 382: }
! 383: else
! 384: {
! 385: DBG1(DBG_CHD, "failed to open ESP key table '%s': %s", path,
! 386: strerror(errno));
! 387: }
! 388: free(path);
! 389: return TRUE;
! 390: }
! 391:
! 392: /**
! 393: * See header.
! 394: */
! 395: save_keys_listener_t *save_keys_listener_create()
! 396: {
! 397: private_save_keys_listener_t *this;
! 398:
! 399: INIT(this,
! 400: .public = {
! 401: .listener = {
! 402: .ike_derived_keys = _ike_derived_keys,
! 403: .child_derived_keys = _child_derived_keys,
! 404: },
! 405: .destroy = _destroy,
! 406: },
! 407: .path = lib->settings->get_str(lib->settings,
! 408: "%s.plugins.save-keys.wireshark_keys",
! 409: NULL, lib->ns),
! 410: .esp = lib->settings->get_bool(lib->settings,
! 411: "%s.plugins.save-keys.esp",
! 412: FALSE, lib->ns),
! 413: .ike = lib->settings->get_bool(lib->settings,
! 414: "%s.plugins.save-keys.ike",
! 415: FALSE, lib->ns),
! 416: );
! 417:
! 418: if (this->path && (this->ike || this->esp))
! 419: {
! 420: char *keys = "IKE";
! 421:
! 422: if (this->ike && this->esp)
! 423: {
! 424: keys = "IKE AND ESP";
! 425: }
! 426: else if (this->esp)
! 427: {
! 428: keys = "ESP";
! 429: }
! 430: DBG0(DBG_DMN, "!!", keys, this->path);
! 431: DBG0(DBG_DMN, "!! WARNING: SAVING %s KEYS TO '%s'", keys, this->path);
! 432: DBG0(DBG_DMN, "!!", keys, this->path);
! 433: }
! 434: return &this->public;
! 435: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>