Annotation of embedaddon/strongswan/src/libcharon/plugins/save_keys/save_keys_listener.c, revision 1.1.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>