2 * Copyright (C) 2018 Tobias Brunner
3 * HSR Hochschule fuer Technik Rapperswil
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>.
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
16 * Copyright (C) 2016 Codrut Cristian Grosu (codrut.cristian.grosu@gmail.com)
17 * Copyright (C) 2016 IXIA (http://www.ixiacom.com)
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:
26 * The above copyright notice and this permission notice shall be included in
27 * all copies or substantial portions of the Software.
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
40 #include "save_keys_listener.h"
48 typedef struct private_save_keys_listener_t private_save_keys_listener_t
;
49 typedef struct algo_map_t algo_map_t
;
52 * Name for IKEv1 decryption table file
54 static char *ikev1_name
= "ikev1_decryption_table";
57 * Name for IKEv2 decryption table file
59 static char *ikev2_name
= "ikev2_decryption_table";
62 * Name for esp decryption table file
64 static char *esp_name
= "esp_sa";
69 struct private_save_keys_listener_t
{
74 save_keys_listener_t
public;
77 * Path to the directory where the decryption tables will be stored.
82 * Whether to save IKE keys
87 * Whether to save ESP keys
92 METHOD(save_keys_listener_t
, destroy
, void,
93 private_save_keys_listener_t
*this)
99 * Mapping strongSwan identifiers to Wireshark names
109 * Optional key length
114 * Name of the algorithm in wireshark
120 * Map an algorithm identifier to a name
122 static inline const char *algo_name(algo_map_t
*map
, int count
,
123 uint16_t alg
, int key_len
)
127 for (i
= 0; i
< count
; i
++)
129 if (map
[i
].ike
== alg
)
131 if (map
[i
].key_len
== -1 || map
[i
].key_len
== key_len
)
141 * Wireshark IKE algorithm identifiers for encryption
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]" },
173 * Wireshark IKE algorithms for integrity
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]" },
188 * Map an IKE proposal
190 static inline void ike_names(proposal_t
*proposal
, const char **enc
,
195 if (proposal
->get_algorithm(proposal
, ENCRYPTION_ALGORITHM
, &alg
, &len
))
197 *enc
= algo_name(ike_encr
, countof(ike_encr
), alg
, len
);
199 if (encryption_algorithm_is_aead(alg
))
201 alg
= AUTH_UNDEFINED
;
203 else if (!proposal
->get_algorithm(proposal
, INTEGRITY_ALGORITHM
, &alg
, NULL
))
207 *integ
= algo_name(ike_integ
, countof(ike_integ
), alg
, -1);
211 * Wireshark ESP algorithm identifiers for encryption
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]" },
228 * Wireshark ESP algorithms for integrity
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" },
246 * Map an ESP proposal
248 static inline void esp_names(proposal_t
*proposal
, const char **enc
,
253 if (proposal
->get_algorithm(proposal
, ENCRYPTION_ALGORITHM
, &alg
, &len
))
255 *enc
= algo_name(esp_encr
, countof(esp_encr
), alg
, len
);
258 if (!proposal
->get_algorithm(proposal
, INTEGRITY_ALGORITHM
, &alg
, NULL
))
262 case ENCR_AES_GCM_ICV8
:
265 case ENCR_AES_GCM_ICV12
:
268 case ENCR_AES_GCM_ICV16
:
272 alg
= AUTH_UNDEFINED
;
274 *integ
= algo_name(esp_integ
, countof(esp_integ
), alg
, len
);
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
)
281 ike_version_t version
;
283 const char *enc
= NULL
, *integ
= NULL
;
287 if (!this->path
|| !this->ike
)
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)
296 DBG1(DBG_IKE
, "failed to build path to IKE key table");
300 file
= fopen(path
, "a");
303 id
= ike_sa
->get_id(ike_sa
);
304 if (version
== IKEV2
)
306 ike_names(ike_sa
->get_proposal(ike_sa
), &enc
, &integ
);
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
);
317 fprintf(file
, "%.16"PRIx64
",%+B\n",
318 be64toh(id
->get_initiator_spi(id
)), &sk_ei
);
324 DBG1(DBG_IKE
, "failed to open IKE key table '%s': %s", path
,
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
,
337 uint32_t spi_i
, spi_r
;
338 const char *enc
= NULL
, *integ
= NULL
;
342 if (!this->path
|| !this->esp
||
343 child_sa
->get_protocol(child_sa
) != PROTO_ESP
)
348 if (asprintf(&path
, "%s/%s", this->path
, esp_name
) < 0)
350 DBG1(DBG_CHD
, "failed to build path to ESP key table");
354 file
= fopen(path
, "a");
357 esp_names(child_sa
->get_proposal(child_sa
), &enc
, &integ
);
360 /* Since the IPs are printed this is not compatible with MOBIKE */
363 init
= ike_sa
->get_my_host(ike_sa
);
364 resp
= ike_sa
->get_other_host(ike_sa
);
368 init
= ike_sa
->get_other_host(ike_sa
);
369 resp
= ike_sa
->get_my_host(ike_sa
);
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
);
385 DBG1(DBG_CHD
, "failed to open ESP key table '%s': %s", path
,
395 save_keys_listener_t
*save_keys_listener_create()
397 private_save_keys_listener_t
*this;
402 .ike_derived_keys
= _ike_derived_keys
,
403 .child_derived_keys
= _child_derived_keys
,
407 .path
= lib
->settings
->get_str(lib
->settings
,
408 "%s.plugins.save-keys.wireshark_keys",
410 .esp
= lib
->settings
->get_bool(lib
->settings
,
411 "%s.plugins.save-keys.esp",
413 .ike
= lib
->settings
->get_bool(lib
->settings
,
414 "%s.plugins.save-keys.ike",
418 if (this->path
&& (this->ike
|| this->esp
))
422 if (this->ike
&& this->esp
)
424 keys
= "IKE AND ESP";
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
);
434 return &this->public;