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>