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]" }, 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: }