Return to save_keys_listener.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libcharon / plugins / save_keys |
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]" }, 1.1.1.2 ! misho 237: { AUTH_HMAC_SHA2_256_256, -1, "ANY 256 bit authentication [no checking]" }, 1.1 misho 238: { AUTH_UNDEFINED, 64, "ANY 64 bit authentication [no checking]" }, 239: { AUTH_UNDEFINED, 96, "ANY 96 bit authentication [no checking]" }, 240: { AUTH_UNDEFINED, 128, "ANY 128 bit authentication [no checking]" }, 241: { AUTH_UNDEFINED, 192, "ANY 192 bit authentication [no checking]" }, 242: { AUTH_UNDEFINED, 256, "ANY 256 bit authentication [no checking]" }, 243: { AUTH_UNDEFINED, -1, "NULL" }, 244: }; 245: 246: /** 247: * Map an ESP proposal 248: */ 249: static inline void esp_names(proposal_t *proposal, const char **enc, 250: const char **integ) 251: { 252: uint16_t alg, len; 253: 254: if (proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &alg, &len)) 255: { 256: *enc = algo_name(esp_encr, countof(esp_encr), alg, len); 257: } 258: len = -1; 259: if (!proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &alg, NULL)) 260: { 261: switch (alg) 262: { 263: case ENCR_AES_GCM_ICV8: 264: len = 64; 265: break; 266: case ENCR_AES_GCM_ICV12: 1.1.1.2 ! misho 267: len = 96; 1.1 misho 268: break; 269: case ENCR_AES_GCM_ICV16: 270: len = 128; 271: break; 272: } 273: alg = AUTH_UNDEFINED; 274: } 275: *integ = algo_name(esp_integ, countof(esp_integ), alg, len); 276: } 277: 278: METHOD(listener_t, ike_derived_keys, bool, 279: private_save_keys_listener_t *this, ike_sa_t *ike_sa, chunk_t sk_ei, 280: chunk_t sk_er, chunk_t sk_ai, chunk_t sk_ar) 281: { 282: ike_version_t version; 283: ike_sa_id_t *id; 284: const char *enc = NULL, *integ = NULL; 285: char *path, *name; 286: FILE *file; 287: 288: if (!this->path || !this->ike) 289: { 290: return TRUE; 291: } 292: 293: version = ike_sa->get_version(ike_sa); 294: name = version == IKEV2 ? ikev2_name : ikev1_name; 295: if (asprintf(&path, "%s/%s", this->path, name) < 0) 296: { 297: DBG1(DBG_IKE, "failed to build path to IKE key table"); 298: return TRUE; 299: } 300: 301: file = fopen(path, "a"); 302: if (file) 303: { 304: id = ike_sa->get_id(ike_sa); 305: if (version == IKEV2) 306: { 307: ike_names(ike_sa->get_proposal(ike_sa), &enc, &integ); 308: if (enc && integ) 309: { 310: fprintf(file, "%.16"PRIx64",%.16"PRIx64",%+B,%+B,\"%s\"," 311: "%+B,%+B,\"%s\"\n", be64toh(id->get_initiator_spi(id)), 312: be64toh(id->get_responder_spi(id)), &sk_ei, &sk_er, 313: enc, &sk_ai, &sk_ar, integ); 314: } 315: } 316: else 317: { 318: fprintf(file, "%.16"PRIx64",%+B\n", 319: be64toh(id->get_initiator_spi(id)), &sk_ei); 320: } 321: fclose(file); 322: } 323: else 324: { 325: DBG1(DBG_IKE, "failed to open IKE key table '%s': %s", path, 326: strerror(errno)); 327: } 328: free(path); 329: return TRUE; 330: } 331: 332: METHOD(listener_t, child_derived_keys, bool, 333: private_save_keys_listener_t *this, ike_sa_t *ike_sa, child_sa_t *child_sa, 334: bool initiator, chunk_t encr_i, chunk_t encr_r, chunk_t integ_i, 335: chunk_t integ_r) 336: { 337: host_t *init, *resp; 338: uint32_t spi_i, spi_r; 339: const char *enc = NULL, *integ = NULL; 340: char *path, *family; 341: FILE *file; 342: 343: if (!this->path || !this->esp || 344: child_sa->get_protocol(child_sa) != PROTO_ESP) 345: { 346: return TRUE; 347: } 348: 349: if (asprintf(&path, "%s/%s", this->path, esp_name) < 0) 350: { 351: DBG1(DBG_CHD, "failed to build path to ESP key table"); 352: return TRUE; 353: } 354: 355: file = fopen(path, "a"); 356: if (file) 357: { 358: esp_names(child_sa->get_proposal(child_sa), &enc, &integ); 359: if (enc && integ) 360: { 361: /* Since the IPs are printed this is not compatible with MOBIKE */ 362: if (initiator) 363: { 364: init = ike_sa->get_my_host(ike_sa); 365: resp = ike_sa->get_other_host(ike_sa); 366: } 367: else 368: { 369: init = ike_sa->get_other_host(ike_sa); 370: resp = ike_sa->get_my_host(ike_sa); 371: } 372: spi_i = child_sa->get_spi(child_sa, initiator); 373: spi_r = child_sa->get_spi(child_sa, !initiator); 374: family = init->get_family(init) == AF_INET ? "IPv4" : "IPv6"; 375: fprintf(file, "\"%s\",\"%H\",\"%H\",\"0x%.8x\",\"%s\",\"0x%+B\"," 376: "\"%s\",\"0x%+B\"\n", family, init, resp, ntohl(spi_r), enc, 377: &encr_i, integ, &integ_i); 378: fprintf(file, "\"%s\",\"%H\",\"%H\",\"0x%.8x\",\"%s\",\"0x%+B\"," 379: "\"%s\",\"0x%+B\"\n", family, resp, init, ntohl(spi_i), enc, 380: &encr_r, integ, &integ_r); 381: } 382: fclose(file); 383: } 384: else 385: { 386: DBG1(DBG_CHD, "failed to open ESP key table '%s': %s", path, 387: strerror(errno)); 388: } 389: free(path); 390: return TRUE; 391: } 392: 393: /** 394: * See header. 395: */ 396: save_keys_listener_t *save_keys_listener_create() 397: { 398: private_save_keys_listener_t *this; 399: 400: INIT(this, 401: .public = { 402: .listener = { 403: .ike_derived_keys = _ike_derived_keys, 404: .child_derived_keys = _child_derived_keys, 405: }, 406: .destroy = _destroy, 407: }, 408: .path = lib->settings->get_str(lib->settings, 409: "%s.plugins.save-keys.wireshark_keys", 410: NULL, lib->ns), 411: .esp = lib->settings->get_bool(lib->settings, 412: "%s.plugins.save-keys.esp", 413: FALSE, lib->ns), 414: .ike = lib->settings->get_bool(lib->settings, 415: "%s.plugins.save-keys.ike", 416: FALSE, lib->ns), 417: ); 418: 419: if (this->path && (this->ike || this->esp)) 420: { 421: char *keys = "IKE"; 422: 423: if (this->ike && this->esp) 424: { 425: keys = "IKE AND ESP"; 426: } 427: else if (this->esp) 428: { 429: keys = "ESP"; 430: } 431: DBG0(DBG_DMN, "!!", keys, this->path); 432: DBG0(DBG_DMN, "!! WARNING: SAVING %s KEYS TO '%s'", keys, this->path); 433: DBG0(DBG_DMN, "!!", keys, this->path); 434: } 435: return &this->public; 436: }