]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/libcharon/plugins/save_keys/save_keys_listener.c
save-keys: Add warning message to log if keys are being saved
[thirdparty/strongswan.git] / src / libcharon / plugins / save_keys / save_keys_listener.c
CommitLineData
1da1ba01
TB
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 */
345cd468
CCG
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
4be7db5f
CCG
38#define _GNU_SOURCE
39
345cd468
CCG
40#include "save_keys_listener.h"
41
4be7db5f
CCG
42#include <stdio.h>
43#include <inttypes.h>
44#include <errno.h>
45
46#include <daemon.h>
47
345cd468 48typedef struct private_save_keys_listener_t private_save_keys_listener_t;
4be7db5f
CCG
49typedef struct algo_map_t algo_map_t;
50
51/**
52 * Name for IKEv1 decryption table file
53 */
54static char *ikev1_name = "ikev1_decryption_table";
55
56/**
57 * Name for IKEv2 decryption table file
58 */
59static char *ikev2_name = "ikev2_decryption_table";
345cd468 60
88e151d1
CCG
61/**
62 * Name for esp decryption table file
63 */
64static char *esp_name = "esp_sa";
65
345cd468
CCG
66/**
67 * Private data.
68 */
69struct private_save_keys_listener_t {
70
71 /**
72 * Public interface.
73 */
74 save_keys_listener_t public;
4be7db5f
CCG
75
76 /**
77 * Path to the directory where the decryption tables will be stored.
78 */
79 char *path;
1da1ba01
TB
80
81 /**
82 * Whether to save IKE keys
83 */
84 bool ike;
85
86 /**
87 * Whether to save ESP keys
88 */
89 bool esp;
345cd468
CCG
90};
91
92METHOD(save_keys_listener_t, destroy, void,
93 private_save_keys_listener_t *this)
94{
95 free(this);
96}
97
4be7db5f
CCG
98/**
99 * Mapping strongSwan identifiers to Wireshark names
100 */
101struct 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 */
122static 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 */
143static 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 */
175static 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 */
190static 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
88e151d1
CCG
210/**
211 * Wireshark ESP algorithm identifiers for encryption
212 */
213static 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 */
230static 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 */
248static 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}
4be7db5f
CCG
276
277METHOD(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
1da1ba01 287 if (!this->path || !this->ike)
4be7db5f
CCG
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
88e151d1
CCG
331METHOD(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
1da1ba01
TB
342 if (!this->path || !this->esp ||
343 child_sa->get_protocol(child_sa) != PROTO_ESP)
88e151d1
CCG
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
345cd468
CCG
392/**
393 * See header.
394 */
395save_keys_listener_t *save_keys_listener_create()
396{
397 private_save_keys_listener_t *this;
398
399 INIT(this,
400 .public = {
401 .listener = {
4be7db5f 402 .ike_derived_keys = _ike_derived_keys,
88e151d1 403 .child_derived_keys = _child_derived_keys,
345cd468
CCG
404 },
405 .destroy = _destroy,
406 },
4be7db5f
CCG
407 .path = lib->settings->get_str(lib->settings,
408 "%s.plugins.save-keys.wireshark_keys",
409 NULL, lib->ns),
1da1ba01
TB
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),
345cd468 416 );
4be7db5f 417
bac71410
TB
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 }
345cd468
CCG
434 return &this->public;
435}