]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/charon-tkm/src/tkm/tkm_kernel_ipsec.c
Update copyright headers after acquisition by secunet
[thirdparty/strongswan.git] / src / charon-tkm / src / tkm / tkm_kernel_ipsec.c
CommitLineData
8a780242 1/*
d24b831f 2 * Copyright (C) 2017 Tobias Brunner
fa4f66cb 3 * Copyright (C) 2012-2014 Reto Buerki
8a780242 4 * Copyright (C) 2012 Adrian-Ken Rueegsegger
19ef2aec
TB
5 *
6 * Copyright (C) secunet Security Networks AG
8a780242
AKR
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 * for more details.
17 */
18
a642e3ba
RB
19#include <errno.h>
20#include <netinet/udp.h>
21#include <linux/xfrm.h>
8a780242 22#include <utils/debug.h>
6c237edb 23#include <utils/chunk.h>
b94a0bef
AKR
24#include <tkm/constants.h>
25#include <tkm/client.h>
8a780242 26
de202301 27#include "tkm.h"
4a152920 28#include "tkm_utils.h"
b94a0bef
AKR
29#include "tkm_types.h"
30#include "tkm_keymat.h"
8a780242
AKR
31#include "tkm_kernel_ipsec.h"
32
41eaaef7
RB
33/** From linux/in.h */
34#ifndef IP_XFRM_POLICY
35#define IP_XFRM_POLICY 17
36#endif
37
8a780242
AKR
38typedef struct private_tkm_kernel_ipsec_t private_tkm_kernel_ipsec_t;
39
40/**
41 * Private variables and functions of TKM kernel ipsec instance.
42 */
43struct private_tkm_kernel_ipsec_t {
44
45 /**
46 * Public tkm_kernel_ipsec interface.
47 */
48 tkm_kernel_ipsec_t public;
49
d0ab667c
AKR
50 /**
51 * RNG used for SPI generation.
52 */
53 rng_t *rng;
54
8a780242
AKR
55};
56
0d42a762
TB
57METHOD(kernel_ipsec_t, get_features, kernel_feature_t,
58 private_tkm_kernel_ipsec_t *this)
59{
60 return KERNEL_POLICY_SPI;
61}
62
8a780242
AKR
63METHOD(kernel_ipsec_t, get_spi, status_t,
64 private_tkm_kernel_ipsec_t *this, host_t *src, host_t *dst,
b12c53ce 65 uint8_t protocol, uint32_t *spi)
8a780242 66{
7cc6fa1a
AKR
67 bool result;
68
ae6f4ee3
RB
69 if (!this->rng)
70 {
71 this->rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
72 if (!this->rng)
73 {
74 DBG1(DBG_KNL, "unable to create RNG");
75 return FAILED;
76 }
77 }
78
b12c53ce
AS
79 result = this->rng->get_bytes(this->rng, sizeof(uint32_t),
80 (uint8_t *)spi);
d0ab667c 81 return result ? SUCCESS : FAILED;
8a780242
AKR
82}
83
84METHOD(kernel_ipsec_t, get_cpi, status_t,
85 private_tkm_kernel_ipsec_t *this, host_t *src, host_t *dst,
b12c53ce 86 uint16_t *cpi)
8a780242
AKR
87{
88 return NOT_SUPPORTED;
89}
90
91METHOD(kernel_ipsec_t, add_sa, status_t,
89da06ac
TB
92 private_tkm_kernel_ipsec_t *this, kernel_ipsec_sa_id_t *id,
93 kernel_ipsec_add_sa_t *data)
8a780242 94{
7cc6fa1a 95 esa_info_t esa;
7cc6fa1a
AKR
96 esp_spi_type spi_loc, spi_rem;
97 host_t *local, *peer;
98 chunk_t *nonce_loc, *nonce_rem;
99 nc_id_type nonce_loc_id;
100 esa_id_type esa_id;
101 nonce_type nc_rem;
102
89da06ac 103 if (data->enc_key.ptr == NULL)
b94a0bef 104 {
4a152920
AKR
105 DBG1(DBG_KNL, "Unable to get ESA information");
106 return FAILED;
107 }
89da06ac 108 esa = *(esa_info_t *)(data->enc_key.ptr);
4a152920
AKR
109
110 /* only handle the case where we have both distinct ESP spi's available */
89da06ac 111 if (esa.spi_r == id->spi)
4a152920
AKR
112 {
113 chunk_free(&esa.nonce_i);
114 chunk_free(&esa.nonce_r);
b94a0bef
AKR
115 return SUCCESS;
116 }
4a152920 117
89da06ac 118 if (data->initiator)
4a152920 119 {
89da06ac 120 spi_loc = id->spi;
4a152920 121 spi_rem = esa.spi_r;
89da06ac
TB
122 local = id->dst;
123 peer = id->src;
4a152920
AKR
124 nonce_loc = &esa.nonce_i;
125 nonce_rem = &esa.nonce_r;
126 }
127 else
128 {
129 spi_loc = esa.spi_r;
89da06ac
TB
130 spi_rem = id->spi;
131 local = id->src;
132 peer = id->dst;
4a152920
AKR
133 nonce_loc = &esa.nonce_r;
134 nonce_rem = &esa.nonce_i;
135 }
136
7cc6fa1a 137 esa_id = tkm->idmgr->acquire_id(tkm->idmgr, TKM_CTX_ESA);
59e7298f
AKR
138 if (esa_id == 0)
139 {
140 DBG1(DBG_KNL, "unable to acquire esa context id");
141 goto esa_id_failure;
142 }
143
89da06ac
TB
144 if (!tkm->sad->insert(tkm->sad, esa_id, data->reqid, local, peer,
145 spi_loc, spi_rem, id->proto))
de202301
AKR
146 {
147 DBG1(DBG_KNL, "unable to add entry (%llu) to SAD", esa_id);
4a152920 148 goto sad_failure;
de202301 149 }
4a152920
AKR
150
151 /*
152 * creation of first CHILD SA:
153 * no nonce and no dh contexts because the ones from the IKE SA are re-used
154 */
7cc6fa1a 155 nonce_loc_id = tkm->chunk_map->get_id(tkm->chunk_map, nonce_loc);
4a152920 156 if (nonce_loc_id == 0 && esa.dh_id == 0)
b94a0bef 157 {
89da06ac
TB
158 if (ike_esa_create_first(esa_id, esa.isa_id, data->reqid, 1, spi_loc,
159 spi_rem) != TKM_OK)
4a152920
AKR
160 {
161 DBG1(DBG_KNL, "child SA (%llu, first) creation failed", esa_id);
162 goto failure;
163 }
b94a0bef 164 }
4a152920
AKR
165 /* creation of child SA without PFS: no dh context */
166 else if (nonce_loc_id != 0 && esa.dh_id == 0)
167 {
0f0165c8 168 chunk_to_sequence(nonce_rem, &nc_rem, sizeof(nonce_type));
89da06ac
TB
169 if (ike_esa_create_no_pfs(esa_id, esa.isa_id, data->reqid, 1,
170 nonce_loc_id, nc_rem, data->initiator,
171 spi_loc, spi_rem) != TKM_OK)
4a152920
AKR
172 {
173 DBG1(DBG_KNL, "child SA (%llu, no PFS) creation failed", esa_id);
174 goto failure;
175 }
5460098c 176 tkm->chunk_map->remove(tkm->chunk_map, nonce_loc);
4a152920
AKR
177 tkm->idmgr->release_id(tkm->idmgr, TKM_CTX_NONCE, nonce_loc_id);
178 }
179 /* creation of subsequent child SA with PFS: nonce and dh context are set */
180 else
181 {
0f0165c8 182 chunk_to_sequence(nonce_rem, &nc_rem, sizeof(nonce_type));
89da06ac
TB
183 if (ike_esa_create(esa_id, esa.isa_id, data->reqid, 1, esa.dh_id,
184 nonce_loc_id, nc_rem, data->initiator, spi_loc,
185 spi_rem) != TKM_OK)
4a152920
AKR
186 {
187 DBG1(DBG_KNL, "child SA (%llu) creation failed", esa_id);
188 goto failure;
189 }
5460098c 190 tkm->chunk_map->remove(tkm->chunk_map, nonce_loc);
4a152920
AKR
191 tkm->idmgr->release_id(tkm->idmgr, TKM_CTX_NONCE, nonce_loc_id);
192 }
1c1400f0 193
4a152920
AKR
194 DBG1(DBG_KNL, "added child SA (esa: %llu, isa: %llu, esp_spi_loc: %x, "
195 "esp_spi_rem: %x, role: %s)", esa_id, esa.isa_id, ntohl(spi_loc),
89da06ac 196 ntohl(spi_rem), data->initiator ? "initiator" : "responder");
4a152920
AKR
197 chunk_free(&esa.nonce_i);
198 chunk_free(&esa.nonce_r);
199
6c237edb 200 return SUCCESS;
4a152920
AKR
201
202failure:
fc08e6af 203 ike_esa_reset(esa_id);
fa4f66cb 204 tkm->sad->remove(tkm->sad, esa_id);
4a152920
AKR
205sad_failure:
206 tkm->idmgr->release_id(tkm->idmgr, TKM_CTX_ESA, esa_id);
59e7298f 207esa_id_failure:
4a152920
AKR
208 chunk_free(&esa.nonce_i);
209 chunk_free(&esa.nonce_r);
210 return FAILED;
8a780242
AKR
211}
212
213METHOD(kernel_ipsec_t, query_sa, status_t,
89da06ac
TB
214 private_tkm_kernel_ipsec_t *this, kernel_ipsec_sa_id_t *id,
215 kernel_ipsec_query_sa_t *data, uint64_t *bytes, uint64_t *packets,
216 time_t *time)
8a780242
AKR
217{
218 return NOT_SUPPORTED;
219}
220
221METHOD(kernel_ipsec_t, del_sa, status_t,
89da06ac
TB
222 private_tkm_kernel_ipsec_t *this, kernel_ipsec_sa_id_t *id,
223 kernel_ipsec_del_sa_t *data)
8a780242 224{
d24b831f 225 esa_id_type esa_id;
7cc6fa1a 226
89da06ac 227 esa_id = tkm->sad->get_esa_id(tkm->sad, id->src, id->dst,
77295777 228 id->spi, id->proto, TRUE);
de202301
AKR
229 if (esa_id)
230 {
231 DBG1(DBG_KNL, "deleting child SA (esa: %llu, spi: %x)", esa_id,
89da06ac 232 ntohl(id->spi));
de202301
AKR
233 if (ike_esa_reset(esa_id) != TKM_OK)
234 {
235 DBG1(DBG_KNL, "child SA (%llu) deletion failed", esa_id);
236 return FAILED;
237 }
fa4f66cb 238 tkm->sad->remove(tkm->sad, esa_id);
de202301
AKR
239 tkm->idmgr->release_id(tkm->idmgr, TKM_CTX_ESA, esa_id);
240 }
6c237edb 241 return SUCCESS;
8a780242
AKR
242}
243
244METHOD(kernel_ipsec_t, update_sa, status_t,
89da06ac
TB
245 private_tkm_kernel_ipsec_t *this, kernel_ipsec_sa_id_t *id,
246 kernel_ipsec_update_sa_t *data)
8a780242
AKR
247{
248 return NOT_SUPPORTED;
249}
250
251METHOD(kernel_ipsec_t, flush_sas, status_t,
252 private_tkm_kernel_ipsec_t *this)
253{
254 DBG1(DBG_KNL, "flushing child SA entries");
6c237edb 255 return SUCCESS;
8a780242
AKR
256}
257
258METHOD(kernel_ipsec_t, add_policy, status_t,
89da06ac
TB
259 private_tkm_kernel_ipsec_t *this, kernel_ipsec_policy_id_t *id,
260 kernel_ipsec_manage_policy_t *data)
8a780242 261{
d24b831f
TB
262 esa_id_type esa_id;
263 uint32_t spi;
264 uint8_t proto;
265
266 if (id->dir == POLICY_OUT && data->type == POLICY_IPSEC &&
267 data->prio == POLICY_PRIORITY_DEFAULT)
268 {
269 if (data->sa->esp.use)
270 {
271 spi = data->sa->esp.spi;
272 proto = IPPROTO_ESP;
273 }
274 else if (data->sa->ah.use)
275 {
276 spi = data->sa->ah.spi;
277 proto = IPPROTO_AH;
278 }
279 else
280 {
281 return FAILED;
282 }
283 esa_id = tkm->sad->get_esa_id(tkm->sad, data->src, data->dst,
77295777 284 spi, proto, FALSE);
d24b831f
TB
285 if (!esa_id)
286 {
287 DBG1(DBG_KNL, "unable to find esa ID for policy (spi: %x)",
288 ntohl(spi));
289 return FAILED;
290 }
291 DBG1(DBG_KNL, "selecting child SA (esa: %llu, spi: %x)", esa_id,
292 ntohl(spi));
293 if (ike_esa_select(esa_id) != TKM_OK)
294 {
295 DBG1(DBG_KNL, "error selecting new child SA (%llu)", esa_id);
296 return FAILED;
297 }
298 }
6c237edb 299 return SUCCESS;
8a780242
AKR
300}
301
302METHOD(kernel_ipsec_t, query_policy, status_t,
89da06ac
TB
303 private_tkm_kernel_ipsec_t *this, kernel_ipsec_policy_id_t *id,
304 kernel_ipsec_query_policy_t *data, time_t *use_time)
8a780242
AKR
305{
306 return NOT_SUPPORTED;
307}
308
309METHOD(kernel_ipsec_t, del_policy, status_t,
89da06ac
TB
310 private_tkm_kernel_ipsec_t *this, kernel_ipsec_policy_id_t *id,
311 kernel_ipsec_manage_policy_t *data)
8a780242 312{
6c237edb 313 return SUCCESS;
8a780242
AKR
314}
315
316METHOD(kernel_ipsec_t, flush_policies, status_t,
317 private_tkm_kernel_ipsec_t *this)
318{
6c237edb 319 return SUCCESS;
8a780242
AKR
320}
321
322
323METHOD(kernel_ipsec_t, bypass_socket, bool,
324 private_tkm_kernel_ipsec_t *this, int fd, int family)
325{
a642e3ba
RB
326 struct xfrm_userpolicy_info policy;
327 u_int sol, ipsec_policy;
328
329 switch (family)
330 {
331 case AF_INET:
332 sol = SOL_IP;
333 ipsec_policy = IP_XFRM_POLICY;
334 break;
335 case AF_INET6:
336 sol = SOL_IPV6;
337 ipsec_policy = IPV6_XFRM_POLICY;
338 break;
339 default:
340 return FALSE;
341 }
342
343 memset(&policy, 0, sizeof(policy));
344 policy.action = XFRM_POLICY_ALLOW;
345 policy.sel.family = family;
346
347 policy.dir = XFRM_POLICY_OUT;
348 if (setsockopt(fd, sol, ipsec_policy, &policy, sizeof(policy)) < 0)
349 {
350 DBG1(DBG_KNL, "unable to set IPSEC_POLICY on socket: %s",
7cc6fa1a 351 strerror(errno));
a642e3ba
RB
352 return FALSE;
353 }
354 policy.dir = XFRM_POLICY_IN;
355 if (setsockopt(fd, sol, ipsec_policy, &policy, sizeof(policy)) < 0)
356 {
357 DBG1(DBG_KNL, "unable to set IPSEC_POLICY on socket: %s",
7cc6fa1a 358 strerror(errno));
a642e3ba
RB
359 return FALSE;
360 }
361 return TRUE;
8a780242
AKR
362}
363
364METHOD(kernel_ipsec_t, enable_udp_decap, bool,
b12c53ce 365 private_tkm_kernel_ipsec_t *this, int fd, int family, uint16_t port)
8a780242 366{
a642e3ba
RB
367 int type = UDP_ENCAP_ESPINUDP;
368
369 if (setsockopt(fd, SOL_UDP, UDP_ENCAP, &type, sizeof(type)) < 0)
370 {
371 DBG1(DBG_KNL, "unable to set UDP_ENCAP: %s", strerror(errno));
372 return FALSE;
373 }
374 return TRUE;
8a780242
AKR
375}
376
377METHOD(kernel_ipsec_t, destroy, void,
378 private_tkm_kernel_ipsec_t *this)
379{
d0ab667c 380 DESTROY_IF(this->rng);
8a780242
AKR
381 free(this);
382}
383
384/*
385 * Described in header.
386 */
387tkm_kernel_ipsec_t *tkm_kernel_ipsec_create()
388{
389 private_tkm_kernel_ipsec_t *this;
390
391 INIT(this,
392 .public = {
393 .interface = {
0d42a762 394 .get_features = _get_features,
8a780242
AKR
395 .get_spi = _get_spi,
396 .get_cpi = _get_cpi,
397 .add_sa = _add_sa,
398 .update_sa = _update_sa,
399 .query_sa = _query_sa,
400 .del_sa = _del_sa,
401 .flush_sas = _flush_sas,
402 .add_policy = _add_policy,
403 .query_policy = _query_policy,
404 .del_policy = _del_policy,
405 .flush_policies = _flush_policies,
406 .bypass_socket = _bypass_socket,
407 .enable_udp_decap = _enable_udp_decap,
408 .destroy = _destroy,
409 },
410 },
8a780242
AKR
411 );
412
8a780242
AKR
413 return &this->public;
414}