2 * Copyright (C) 2012 Reto Buerki
3 * Copyright (C) 2012 Adrian-Ken Rueegsegger
4 * Hochschule fuer Technik Rapperswil
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 #include <netinet/udp.h>
19 #include <linux/xfrm.h>
20 #include <utils/debug.h>
21 #include <utils/chunk.h>
22 #include <tkm/constants.h>
23 #include <tkm/client.h>
26 #include "tkm_utils.h"
27 #include "tkm_types.h"
28 #include "tkm_keymat.h"
29 #include "tkm_kernel_sad.h"
30 #include "tkm_kernel_ipsec.h"
32 typedef struct private_tkm_kernel_ipsec_t private_tkm_kernel_ipsec_t
;
35 * Private variables and functions of TKM kernel ipsec instance.
37 struct private_tkm_kernel_ipsec_t
{
40 * Public tkm_kernel_ipsec interface.
42 tkm_kernel_ipsec_t
public;
45 * RNG used for SPI generation.
50 * CHILD/ESP SA database.
52 tkm_kernel_sad_t
*sad
;
56 METHOD(kernel_ipsec_t
, get_spi
, status_t
,
57 private_tkm_kernel_ipsec_t
*this, host_t
*src
, host_t
*dst
,
58 u_int8_t protocol
, u_int32_t reqid
, u_int32_t
*spi
)
60 DBG1(DBG_KNL
, "getting SPI for reqid {%u}", reqid
);
61 const bool result
= this->rng
->get_bytes(this->rng
, sizeof(u_int32_t
),
63 return result ? SUCCESS
: FAILED
;
66 METHOD(kernel_ipsec_t
, get_cpi
, status_t
,
67 private_tkm_kernel_ipsec_t
*this, host_t
*src
, host_t
*dst
,
68 u_int32_t reqid
, u_int16_t
*cpi
)
73 METHOD(kernel_ipsec_t
, add_sa
, status_t
,
74 private_tkm_kernel_ipsec_t
*this, host_t
*src
, host_t
*dst
,
75 u_int32_t spi
, u_int8_t protocol
, u_int32_t reqid
, mark_t mark
,
76 u_int32_t tfc
, lifetime_cfg_t
*lifetime
, u_int16_t enc_alg
, chunk_t enc_key
,
77 u_int16_t int_alg
, chunk_t int_key
, ipsec_mode_t mode
, u_int16_t ipcomp
,
78 u_int16_t cpi
, bool encap
, bool esn
, bool inbound
,
79 traffic_selector_t
* src_ts
, traffic_selector_t
* dst_ts
)
81 if (enc_key
.ptr
== NULL
)
83 DBG1(DBG_KNL
, "Unable to get ESA information");
86 esa_info_t esa
= *(esa_info_t
*)(enc_key
.ptr
);
88 /* only handle the case where we have both distinct ESP spi's available */
91 chunk_free(&esa
.nonce_i
);
92 chunk_free(&esa
.nonce_r
);
96 /* Initiator if encr_r is passed as enc_key to the inbound add_sa call */
97 const bool initiator
= esa
.is_encr_r
&& inbound
;
99 esp_spi_type spi_loc
, spi_rem
;
100 host_t
*local
, *peer
;
101 chunk_t
*nonce_loc
, *nonce_rem
;
108 nonce_loc
= &esa
.nonce_i
;
109 nonce_rem
= &esa
.nonce_r
;
117 nonce_loc
= &esa
.nonce_r
;
118 nonce_rem
= &esa
.nonce_i
;
121 const nc_id_type nonce_loc_id
= tkm
->chunk_map
->get_id(tkm
->chunk_map
,
124 const esa_id_type esa_id
= tkm
->idmgr
->acquire_id(tkm
->idmgr
, TKM_CTX_ESA
);
125 if (!this->sad
->insert(this->sad
, esa_id
, peer
, local
, spi_loc
, protocol
))
127 DBG1(DBG_KNL
, "unable to add entry (%llu) to SAD", esa_id
);
132 * creation of first CHILD SA:
133 * no nonce and no dh contexts because the ones from the IKE SA are re-used
135 if (nonce_loc_id
== 0 && esa
.dh_id
== 0)
137 if (ike_esa_create_first(esa_id
, esa
.isa_id
, 1, 1, ntohl(spi_loc
),
138 ntohl(spi_rem
)) != TKM_OK
)
140 DBG1(DBG_KNL
, "child SA (%llu, first) creation failed", esa_id
);
144 /* creation of child SA without PFS: no dh context */
145 else if (nonce_loc_id
!= 0 && esa
.dh_id
== 0)
148 chunk_to_sequence(nonce_rem
, &nc_rem
, sizeof(nonce_type
));
149 if (ike_esa_create_no_pfs(esa_id
, esa
.isa_id
, 1, 1, nonce_loc_id
,
150 nc_rem
, initiator
, ntohl(spi_loc
),
151 ntohl(spi_rem
)) != TKM_OK
)
153 DBG1(DBG_KNL
, "child SA (%llu, no PFS) creation failed", esa_id
);
156 tkm
->idmgr
->release_id(tkm
->idmgr
, TKM_CTX_NONCE
, nonce_loc_id
);
158 /* creation of subsequent child SA with PFS: nonce and dh context are set */
162 chunk_to_sequence(nonce_rem
, &nc_rem
, sizeof(nonce_type
));
163 if (ike_esa_create(esa_id
, esa
.isa_id
, 1, 1, esa
.dh_id
, nonce_loc_id
,
164 nc_rem
, initiator
, ntohl(spi_loc
),
165 ntohl(spi_rem
)) != TKM_OK
)
167 DBG1(DBG_KNL
, "child SA (%llu) creation failed", esa_id
);
170 tkm
->idmgr
->release_id(tkm
->idmgr
, TKM_CTX_NONCE
, nonce_loc_id
);
172 if (ike_esa_select(esa_id
) != TKM_OK
)
174 DBG1(DBG_KNL
, "error selecting new child SA (%llu)", esa_id
);
175 if (ike_esa_reset(esa_id
) != TKM_OK
)
177 DBG1(DBG_KNL
, "child SA (%llu) deletion failed", esa_id
);
182 DBG1(DBG_KNL
, "added child SA (esa: %llu, isa: %llu, esp_spi_loc: %x, "
183 "esp_spi_rem: %x, role: %s)", esa_id
, esa
.isa_id
, ntohl(spi_loc
),
184 ntohl(spi_rem
), initiator ?
"initiator" : "responder");
185 chunk_free(&esa
.nonce_i
);
186 chunk_free(&esa
.nonce_r
);
191 this->sad
->remove(this->sad
, esa_id
);
193 tkm
->idmgr
->release_id(tkm
->idmgr
, TKM_CTX_ESA
, esa_id
);
194 chunk_free(&esa
.nonce_i
);
195 chunk_free(&esa
.nonce_r
);
199 METHOD(kernel_ipsec_t
, query_sa
, status_t
,
200 private_tkm_kernel_ipsec_t
*this, host_t
*src
, host_t
*dst
,
201 u_int32_t spi
, u_int8_t protocol
, mark_t mark
, u_int64_t
*bytes
,
204 return NOT_SUPPORTED
;
207 METHOD(kernel_ipsec_t
, del_sa
, status_t
,
208 private_tkm_kernel_ipsec_t
*this, host_t
*src
, host_t
*dst
,
209 u_int32_t spi
, u_int8_t protocol
, u_int16_t cpi
, mark_t mark
)
211 const esa_id_type esa_id
= this->sad
->get_esa_id(this->sad
, src
, dst
, spi
,
215 DBG1(DBG_KNL
, "deleting child SA (esa: %llu, spi: %x)", esa_id
,
217 if (ike_esa_reset(esa_id
) != TKM_OK
)
219 DBG1(DBG_KNL
, "child SA (%llu) deletion failed", esa_id
);
222 this->sad
->remove(this->sad
, esa_id
);
223 tkm
->idmgr
->release_id(tkm
->idmgr
, TKM_CTX_ESA
, esa_id
);
228 METHOD(kernel_ipsec_t
, update_sa
, status_t
,
229 private_tkm_kernel_ipsec_t
*this, u_int32_t spi
, u_int8_t protocol
,
230 u_int16_t cpi
, host_t
*src
, host_t
*dst
, host_t
*new_src
, host_t
*new_dst
,
231 bool old_encap
, bool new_encap
, mark_t mark
)
233 return NOT_SUPPORTED
;
236 METHOD(kernel_ipsec_t
, flush_sas
, status_t
,
237 private_tkm_kernel_ipsec_t
*this)
239 DBG1(DBG_KNL
, "flushing child SA entries");
243 METHOD(kernel_ipsec_t
, add_policy
, status_t
,
244 private_tkm_kernel_ipsec_t
*this, host_t
*src
, host_t
*dst
,
245 traffic_selector_t
*src_ts
, traffic_selector_t
*dst_ts
,
246 policy_dir_t direction
, policy_type_t type
, ipsec_sa_cfg_t
*sa
,
247 mark_t mark
, policy_priority_t priority
)
252 METHOD(kernel_ipsec_t
, query_policy
, status_t
,
253 private_tkm_kernel_ipsec_t
*this, traffic_selector_t
*src_ts
,
254 traffic_selector_t
*dst_ts
, policy_dir_t direction
, mark_t mark
,
257 return NOT_SUPPORTED
;
260 METHOD(kernel_ipsec_t
, del_policy
, status_t
,
261 private_tkm_kernel_ipsec_t
*this, traffic_selector_t
*src_ts
,
262 traffic_selector_t
*dst_ts
, policy_dir_t direction
, u_int32_t reqid
,
263 mark_t mark
, policy_priority_t prio
)
268 METHOD(kernel_ipsec_t
, flush_policies
, status_t
,
269 private_tkm_kernel_ipsec_t
*this)
275 METHOD(kernel_ipsec_t
, bypass_socket
, bool,
276 private_tkm_kernel_ipsec_t
*this, int fd
, int family
)
278 struct xfrm_userpolicy_info policy
;
279 u_int sol
, ipsec_policy
;
285 ipsec_policy
= IP_XFRM_POLICY
;
289 ipsec_policy
= IPV6_XFRM_POLICY
;
295 memset(&policy
, 0, sizeof(policy
));
296 policy
.action
= XFRM_POLICY_ALLOW
;
297 policy
.sel
.family
= family
;
299 policy
.dir
= XFRM_POLICY_OUT
;
300 if (setsockopt(fd
, sol
, ipsec_policy
, &policy
, sizeof(policy
)) < 0)
302 DBG1(DBG_KNL
, "unable to set IPSEC_POLICY on socket: %s",
306 policy
.dir
= XFRM_POLICY_IN
;
307 if (setsockopt(fd
, sol
, ipsec_policy
, &policy
, sizeof(policy
)) < 0)
309 DBG1(DBG_KNL
, "unable to set IPSEC_POLICY on socket: %s",
316 METHOD(kernel_ipsec_t
, enable_udp_decap
, bool,
317 private_tkm_kernel_ipsec_t
*this, int fd
, int family
, u_int16_t port
)
319 int type
= UDP_ENCAP_ESPINUDP
;
321 if (setsockopt(fd
, SOL_UDP
, UDP_ENCAP
, &type
, sizeof(type
)) < 0)
323 DBG1(DBG_KNL
, "unable to set UDP_ENCAP: %s", strerror(errno
));
329 METHOD(kernel_ipsec_t
, destroy
, void,
330 private_tkm_kernel_ipsec_t
*this)
332 DESTROY_IF(this->rng
);
333 DESTROY_IF(this->sad
);
338 * Described in header.
340 tkm_kernel_ipsec_t
*tkm_kernel_ipsec_create()
342 private_tkm_kernel_ipsec_t
*this;
350 .update_sa
= _update_sa
,
351 .query_sa
= _query_sa
,
353 .flush_sas
= _flush_sas
,
354 .add_policy
= _add_policy
,
355 .query_policy
= _query_policy
,
356 .del_policy
= _del_policy
,
357 .flush_policies
= _flush_policies
,
358 .bypass_socket
= _bypass_socket
,
359 .enable_udp_decap
= _enable_udp_decap
,
363 .rng
= lib
->crypto
->create_rng(lib
->crypto
, RNG_WEAK
),
364 .sad
= tkm_kernel_sad_create(),
369 DBG1(DBG_KNL
, "unable to create RNG");
375 DBG1(DBG_KNL
, "unable to create SAD");
380 return &this->public;