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>