]>
Commit | Line | Data |
---|---|---|
c6c8d740 RB |
1 | /* |
2 | * Copyrigth (C) 2012 Reto Buerki | |
3 | * Copyright (C) 2012 Adrian-Ken Rueegsegger | |
4 | * Hochschule fuer Technik Rapperswil | |
5 | * | |
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>. | |
10 | * | |
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 | |
14 | * for more details. | |
15 | */ | |
16 | ||
17 | #include <daemon.h> | |
9df56456 RB |
18 | #include <encoding/payloads/auth_payload.h> |
19 | #include <utils/chunk.h> | |
c6c8d740 | 20 | #include <tkm/types.h> |
39727696 RB |
21 | #include <tkm/constants.h> |
22 | #include <tkm/client.h> | |
c6c8d740 | 23 | |
351bd59d | 24 | #include "tkm.h" |
c6c8d740 RB |
25 | #include "tkm_listener.h" |
26 | #include "tkm_keymat.h" | |
39727696 | 27 | #include "tkm_utils.h" |
c6c8d740 RB |
28 | |
29 | typedef struct private_tkm_listener_t private_tkm_listener_t; | |
30 | ||
31 | /** | |
32 | * Private data of a tkm_listener_t object. | |
33 | */ | |
34 | struct private_tkm_listener_t { | |
35 | ||
36 | /** | |
37 | * Public tkm_listener_t interface. | |
38 | */ | |
39 | tkm_listener_t public; | |
40 | ||
41 | }; | |
42 | ||
9099d2ba AKR |
43 | /** |
44 | * Return id of remote identity. | |
45 | * | |
46 | * TODO: Replace this with the lookup for the remote identitiy id. | |
47 | * | |
48 | * Currently the reqid of the first child SA in peer config of IKE SA is | |
49 | * returned. Might choose wrong reqid if IKE SA has multiple child configs | |
50 | * with different reqids. | |
51 | * | |
52 | * @param peer_cfg Remote peer config | |
53 | * @return remote identity id if found, 0 otherwise | |
54 | */ | |
55 | static ri_id_type get_remote_identity_id(peer_cfg_t *peer) | |
56 | { | |
57 | ri_id_type remote_id = 0; | |
58 | child_cfg_t *child; | |
7cc6fa1a AKR |
59 | enumerator_t* children; |
60 | ||
61 | children = peer->create_child_cfg_enumerator(peer); | |
9099d2ba AKR |
62 | |
63 | /* pick the reqid of the first child, no need to enumerate all children. */ | |
64 | children->enumerate(children, &child); | |
65 | remote_id = child->get_reqid(child); | |
66 | children->destroy(children); | |
67 | ||
68 | return remote_id; | |
69 | } | |
70 | ||
351bd59d AKR |
71 | /** |
72 | * Build a TKM certificate chain context with given cc id. | |
73 | * | |
74 | * @param ike_sa IKE SA containing auth config to build certificate chain from | |
75 | * @param cc_id Certificate chain ID | |
76 | * @return TRUE if certificate chain was built successfully, | |
77 | * FALSE otherwise | |
78 | */ | |
79 | static bool build_cert_chain(const ike_sa_t * const ike_sa, cc_id_type cc_id) | |
80 | { | |
351bd59d AKR |
81 | auth_cfg_t *auth; |
82 | certificate_t *cert; | |
83 | enumerator_t *rounds; | |
7cc6fa1a AKR |
84 | |
85 | DBG1(DBG_IKE, "building certificate chain context %llu for IKE SA %s", | |
86 | cc_id, ike_sa->get_name((ike_sa_t *)ike_sa)); | |
87 | ||
351bd59d | 88 | rounds = ike_sa->create_auth_cfg_enumerator((ike_sa_t *)ike_sa, FALSE); |
9099d2ba | 89 | while (rounds->enumerate(rounds, &auth)) |
351bd59d AKR |
90 | { |
91 | cert = auth->get(auth, AUTH_RULE_SUBJECT_CERT); | |
92 | if (cert) | |
93 | { | |
351bd59d | 94 | chunk_t enc_user_cert; |
7cc6fa1a AKR |
95 | ri_id_type ri_id; |
96 | certificate_type user_cert; | |
97 | auth_rule_t rule; | |
98 | enumerator_t *enumerator; | |
99 | ||
100 | /* set user certificate */ | |
351bd59d AKR |
101 | if (!cert->get_encoding(cert, CERT_ASN1_DER, &enc_user_cert)) |
102 | { | |
103 | DBG1(DBG_IKE, "unable to extract encoded user certificate"); | |
104 | rounds->destroy(rounds); | |
105 | return FALSE; | |
106 | } | |
107 | ||
7cc6fa1a AKR |
108 | ri_id = get_remote_identity_id(ike_sa->get_peer_cfg((ike_sa_t *)ike_sa)); |
109 | chunk_to_sequence(&enc_user_cert, &user_cert, sizeof(certificate_type)); | |
351bd59d | 110 | chunk_free(&enc_user_cert); |
9099d2ba | 111 | if (ike_cc_set_user_certificate(cc_id, ri_id, 1, user_cert) != TKM_OK) |
351bd59d AKR |
112 | { |
113 | DBG1(DBG_IKE, "error setting user certificate of cert chain" | |
114 | " (cc_id: %llu)", cc_id); | |
115 | rounds->destroy(rounds); | |
116 | return FALSE; | |
117 | } | |
118 | ||
119 | /* process intermediate CA certificates */ | |
7cc6fa1a | 120 | enumerator = auth->create_enumerator(auth); |
351bd59d AKR |
121 | while (enumerator->enumerate(enumerator, &rule, &cert)) |
122 | { | |
123 | if (rule == AUTH_RULE_IM_CERT) | |
124 | { | |
125 | chunk_t enc_im_cert; | |
7cc6fa1a AKR |
126 | certificate_type im_cert; |
127 | ||
351bd59d AKR |
128 | if (!cert->get_encoding(cert, CERT_ASN1_DER, &enc_im_cert)) |
129 | { | |
130 | DBG1(DBG_IKE, "unable to extract encoded intermediate CA" | |
7cc6fa1a | 131 | " certificate"); |
351bd59d AKR |
132 | rounds->destroy(rounds); |
133 | enumerator->destroy(enumerator); | |
134 | return FALSE; | |
135 | } | |
136 | ||
351bd59d AKR |
137 | chunk_to_sequence(&enc_im_cert, &im_cert, |
138 | sizeof(certificate_type)); | |
139 | chunk_free(&enc_im_cert); | |
140 | if (ike_cc_add_certificate(cc_id, 1, im_cert) != TKM_OK) | |
141 | { | |
142 | DBG1(DBG_IKE, "error adding intermediate certificate to" | |
143 | " cert chain (cc_id: %llu)", cc_id); | |
144 | rounds->destroy(rounds); | |
145 | enumerator->destroy(enumerator); | |
146 | return FALSE; | |
147 | } | |
148 | } | |
149 | } | |
150 | enumerator->destroy(enumerator); | |
151 | ||
152 | /* finally add CA certificate */ | |
153 | cert = auth->get(auth, AUTH_RULE_CA_CERT); | |
154 | if (cert) | |
155 | { | |
7cc6fa1a AKR |
156 | const ca_id_type ca_id = 1; |
157 | certificate_type ca_cert; | |
351bd59d | 158 | chunk_t enc_ca_cert; |
7cc6fa1a | 159 | |
351bd59d AKR |
160 | if (!cert->get_encoding(cert, CERT_ASN1_DER, &enc_ca_cert)) |
161 | { | |
162 | DBG1(DBG_IKE, "unable to extract encoded CA certificate"); | |
163 | rounds->destroy(rounds); | |
164 | return FALSE; | |
165 | } | |
166 | ||
351bd59d AKR |
167 | chunk_to_sequence(&enc_ca_cert, &ca_cert, |
168 | sizeof(certificate_type)); | |
169 | chunk_free(&enc_ca_cert); | |
170 | if (ike_cc_add_certificate(cc_id, 1, ca_cert) != TKM_OK) | |
171 | { | |
172 | DBG1(DBG_IKE, "error adding CA certificate to cert chain " | |
173 | "(cc_id: %llu)", cc_id); | |
174 | rounds->destroy(rounds); | |
175 | return FALSE; | |
176 | } | |
177 | ||
178 | if (ike_cc_check_ca(cc_id, ca_id) != TKM_OK) | |
179 | { | |
180 | DBG1(DBG_IKE, "certificate chain (cc_id: %llu) not based on" | |
181 | " trusted CA (ca_id: %llu)", cc_id, ca_id); | |
182 | rounds->destroy(rounds); | |
183 | return FALSE; | |
184 | } | |
185 | ||
186 | rounds->destroy(rounds); | |
187 | return TRUE; | |
188 | } | |
189 | else | |
190 | { | |
191 | DBG1(DBG_IKE, "no CA certificate"); | |
192 | } | |
193 | } | |
194 | else | |
195 | { | |
196 | DBG1(DBG_IKE, "no subject certificate for remote peer"); | |
197 | } | |
198 | } | |
199 | ||
200 | rounds->destroy(rounds); | |
201 | return FALSE; | |
202 | } | |
203 | ||
89b1d5f3 AKR |
204 | METHOD(listener_t, alert, bool, |
205 | private_tkm_listener_t *this, ike_sa_t *ike_sa, | |
206 | alert_t alert, va_list args) | |
207 | { | |
208 | if (alert == ALERT_KEEP_ON_CHILD_SA_FAILURE) | |
209 | { | |
7cc6fa1a AKR |
210 | tkm_keymat_t *keymat; |
211 | isa_id_type isa_id; | |
212 | ||
213 | keymat = (tkm_keymat_t*)ike_sa->get_keymat(ike_sa); | |
214 | isa_id = keymat->get_isa_id(keymat); | |
215 | ||
89b1d5f3 AKR |
216 | DBG1(DBG_IKE, "TKM alert listener called for ISA context %llu", isa_id); |
217 | if (ike_isa_skip_create_first(isa_id) != TKM_OK) | |
218 | { | |
219 | DBG1(DBG_IKE, "Skip of first child SA creation failed for ISA " | |
220 | "context %llu", isa_id); | |
221 | } | |
222 | } | |
223 | ||
224 | return TRUE; | |
225 | } | |
226 | ||
c6c8d740 RB |
227 | METHOD(listener_t, authorize, bool, |
228 | private_tkm_listener_t *this, ike_sa_t *ike_sa, | |
229 | bool final, bool *success) | |
230 | { | |
7cc6fa1a AKR |
231 | tkm_keymat_t *keymat; |
232 | isa_id_type isa_id; | |
233 | cc_id_type cc_id; | |
234 | chunk_t *auth, *other_init_msg; | |
235 | signature_type signature; | |
236 | init_message_type init_msg; | |
237 | ||
c6c8d740 RB |
238 | if (!final) |
239 | { | |
240 | return TRUE; | |
241 | } | |
242 | ||
7cc6fa1a AKR |
243 | keymat = (tkm_keymat_t*)ike_sa->get_keymat(ike_sa); |
244 | isa_id = keymat->get_isa_id(keymat); | |
c6c8d740 RB |
245 | DBG1(DBG_IKE, "TKM authorize listener called for ISA context %llu", isa_id); |
246 | ||
7cc6fa1a | 247 | cc_id = tkm->idmgr->acquire_id(tkm->idmgr, TKM_CTX_CC); |
351bd59d AKR |
248 | if (!cc_id) |
249 | { | |
250 | DBG1(DBG_IKE, "unable to acquire CC context id"); | |
251 | *success = FALSE; | |
252 | return TRUE; | |
253 | } | |
7cc6fa1a | 254 | if (!build_cert_chain(ike_sa, cc_id)) |
351bd59d AKR |
255 | { |
256 | DBG1(DBG_IKE, "unable to build certificate chain"); | |
257 | *success = FALSE; | |
258 | return TRUE; | |
259 | } | |
260 | ||
7cc6fa1a | 261 | auth = keymat->get_auth_payload(keymat); |
9df56456 RB |
262 | if (!auth->ptr) |
263 | { | |
264 | DBG1(DBG_IKE, "no AUTHENTICATION data available"); | |
265 | *success = FALSE; | |
266 | } | |
267 | ||
7cc6fa1a | 268 | other_init_msg = keymat->get_peer_init_msg(keymat); |
832488b1 AKR |
269 | if (!other_init_msg->ptr) |
270 | { | |
271 | DBG1(DBG_IKE, "no peer init message available"); | |
272 | *success = FALSE; | |
273 | } | |
274 | ||
0f0165c8 | 275 | chunk_to_sequence(auth, &signature, sizeof(signature_type)); |
832488b1 AKR |
276 | chunk_to_sequence(other_init_msg, &init_msg, sizeof(init_message_type)); |
277 | ||
278 | if (ike_isa_auth(isa_id, cc_id, init_msg, signature) != TKM_OK) | |
39727696 RB |
279 | { |
280 | DBG1(DBG_IKE, "TKM based authentication failed" | |
281 | " for ISA context %llu", isa_id); | |
282 | *success = FALSE; | |
283 | } | |
284 | else | |
285 | { | |
286 | DBG1(DBG_IKE, "TKM based authentication successful" | |
287 | " for ISA context %llu", isa_id); | |
288 | *success = TRUE; | |
289 | } | |
290 | ||
c6c8d740 RB |
291 | return TRUE; |
292 | } | |
293 | ||
9df56456 RB |
294 | METHOD(listener_t, message, bool, |
295 | private_tkm_listener_t *this, ike_sa_t *ike_sa, | |
296 | message_t *message, bool incoming, bool plain) | |
297 | { | |
7cc6fa1a AKR |
298 | tkm_keymat_t *keymat; |
299 | isa_id_type isa_id; | |
300 | auth_payload_t *auth_payload; | |
301 | ||
9df56456 RB |
302 | if (!incoming || !plain || message->get_exchange_type(message) != IKE_AUTH) |
303 | { | |
304 | return TRUE; | |
305 | } | |
306 | ||
7cc6fa1a AKR |
307 | keymat = (tkm_keymat_t*)ike_sa->get_keymat(ike_sa); |
308 | isa_id = keymat->get_isa_id(keymat); | |
9df56456 | 309 | DBG1(DBG_IKE, "saving AUTHENTICATION payload for authorize hook" |
7cc6fa1a | 310 | " (ISA context %llu)", isa_id); |
9df56456 | 311 | |
7cc6fa1a AKR |
312 | auth_payload = (auth_payload_t*)message->get_payload(message, |
313 | AUTHENTICATION); | |
9df56456 RB |
314 | if (auth_payload) |
315 | { | |
7cc6fa1a AKR |
316 | chunk_t auth_data; |
317 | ||
318 | auth_data = auth_payload->get_data(auth_payload); | |
9df56456 RB |
319 | keymat->set_auth_payload(keymat, &auth_data); |
320 | } | |
321 | else | |
322 | { | |
323 | DBG1(DBG_IKE, "unable to extract AUTHENTICATION payload, authorize will" | |
324 | " fail"); | |
325 | } | |
326 | ||
327 | return TRUE; | |
328 | } | |
329 | ||
c6c8d740 RB |
330 | METHOD(tkm_listener_t, destroy, void, |
331 | private_tkm_listener_t *this) | |
332 | { | |
333 | free(this); | |
334 | } | |
335 | ||
336 | /** | |
337 | * See header | |
338 | */ | |
339 | tkm_listener_t *tkm_listener_create() | |
340 | { | |
341 | private_tkm_listener_t *this; | |
342 | ||
343 | INIT(this, | |
344 | .public = { | |
345 | .listener = { | |
346 | .authorize = _authorize, | |
9df56456 | 347 | .message = _message, |
89b1d5f3 | 348 | .alert = _alert, |
c6c8d740 RB |
349 | }, |
350 | .destroy = _destroy, | |
351 | }, | |
352 | ); | |
353 | ||
354 | return &this->public; | |
355 | } |