Various stylistic fixes
[strongswan.git] / src / charon-tkm / src / tkm / tkm_listener.c
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>
18 #include <encoding/payloads/auth_payload.h>
19 #include <utils/chunk.h>
20 #include <tkm/types.h>
21 #include <tkm/constants.h>
22 #include <tkm/client.h>
23
24 #include "tkm.h"
25 #include "tkm_listener.h"
26 #include "tkm_keymat.h"
27 #include "tkm_utils.h"
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
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;
59 enumerator_t* children;
60
61 children = peer->create_child_cfg_enumerator(peer);
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
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 {
81 auth_cfg_t *auth;
82 certificate_t *cert;
83 enumerator_t *rounds;
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
88 rounds = ike_sa->create_auth_cfg_enumerator((ike_sa_t *)ike_sa, FALSE);
89 while (rounds->enumerate(rounds, &auth))
90 {
91 cert = auth->get(auth, AUTH_RULE_SUBJECT_CERT);
92 if (cert)
93 {
94 chunk_t enc_user_cert;
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 */
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
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));
110 chunk_free(&enc_user_cert);
111 if (ike_cc_set_user_certificate(cc_id, ri_id, 1, user_cert) != TKM_OK)
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 */
120 enumerator = auth->create_enumerator(auth);
121 while (enumerator->enumerate(enumerator, &rule, &cert))
122 {
123 if (rule == AUTH_RULE_IM_CERT)
124 {
125 chunk_t enc_im_cert;
126 certificate_type im_cert;
127
128 if (!cert->get_encoding(cert, CERT_ASN1_DER, &enc_im_cert))
129 {
130 DBG1(DBG_IKE, "unable to extract encoded intermediate CA"
131 " certificate");
132 rounds->destroy(rounds);
133 enumerator->destroy(enumerator);
134 return FALSE;
135 }
136
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 {
156 const ca_id_type ca_id = 1;
157 certificate_type ca_cert;
158 chunk_t enc_ca_cert;
159
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
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
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 {
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
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
227 METHOD(listener_t, authorize, bool,
228 private_tkm_listener_t *this, ike_sa_t *ike_sa,
229 bool final, bool *success)
230 {
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
238 if (!final)
239 {
240 return TRUE;
241 }
242
243 keymat = (tkm_keymat_t*)ike_sa->get_keymat(ike_sa);
244 isa_id = keymat->get_isa_id(keymat);
245 DBG1(DBG_IKE, "TKM authorize listener called for ISA context %llu", isa_id);
246
247 cc_id = tkm->idmgr->acquire_id(tkm->idmgr, TKM_CTX_CC);
248 if (!cc_id)
249 {
250 DBG1(DBG_IKE, "unable to acquire CC context id");
251 *success = FALSE;
252 return TRUE;
253 }
254 if (!build_cert_chain(ike_sa, cc_id))
255 {
256 DBG1(DBG_IKE, "unable to build certificate chain");
257 *success = FALSE;
258 return TRUE;
259 }
260
261 auth = keymat->get_auth_payload(keymat);
262 if (!auth->ptr)
263 {
264 DBG1(DBG_IKE, "no AUTHENTICATION data available");
265 *success = FALSE;
266 }
267
268 other_init_msg = keymat->get_peer_init_msg(keymat);
269 if (!other_init_msg->ptr)
270 {
271 DBG1(DBG_IKE, "no peer init message available");
272 *success = FALSE;
273 }
274
275 chunk_to_sequence(auth, &signature, sizeof(signature_type));
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)
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
291 return TRUE;
292 }
293
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 {
298 tkm_keymat_t *keymat;
299 isa_id_type isa_id;
300 auth_payload_t *auth_payload;
301
302 if (!incoming || !plain || message->get_exchange_type(message) != IKE_AUTH)
303 {
304 return TRUE;
305 }
306
307 keymat = (tkm_keymat_t*)ike_sa->get_keymat(ike_sa);
308 isa_id = keymat->get_isa_id(keymat);
309 DBG1(DBG_IKE, "saving AUTHENTICATION payload for authorize hook"
310 " (ISA context %llu)", isa_id);
311
312 auth_payload = (auth_payload_t*)message->get_payload(message,
313 AUTHENTICATION);
314 if (auth_payload)
315 {
316 chunk_t auth_data;
317
318 auth_data = auth_payload->get_data(auth_payload);
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
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,
347 .message = _message,
348 .alert = _alert,
349 },
350 .destroy = _destroy,
351 },
352 );
353
354 return &this->public;
355 }