47cfef5ac1de7f6d8c923a30abbe51b6620292b9
[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 = peer->create_child_cfg_enumerator(peer);
60
61 /* pick the reqid of the first child, no need to enumerate all children. */
62 children->enumerate(children, &child);
63 remote_id = child->get_reqid(child);
64 children->destroy(children);
65
66 return remote_id;
67 }
68
69 /**
70 * Build a TKM certificate chain context with given cc id.
71 *
72 * @param ike_sa IKE SA containing auth config to build certificate chain from
73 * @param cc_id Certificate chain ID
74 * @return TRUE if certificate chain was built successfully,
75 * FALSE otherwise
76 */
77 static bool build_cert_chain(const ike_sa_t * const ike_sa, cc_id_type cc_id)
78 {
79 DBG1(DBG_IKE, "building certificate chain context %llu for IKE SA %s",
80 cc_id, ike_sa->get_name((ike_sa_t *)ike_sa));
81
82 auth_cfg_t *auth;
83 certificate_t *cert;
84 enumerator_t *rounds;
85 rounds = ike_sa->create_auth_cfg_enumerator((ike_sa_t *)ike_sa, FALSE);
86 while (rounds->enumerate(rounds, &auth))
87 {
88 cert = auth->get(auth, AUTH_RULE_SUBJECT_CERT);
89 if (cert)
90 {
91 /* set user certificate */
92 chunk_t enc_user_cert;
93 if (!cert->get_encoding(cert, CERT_ASN1_DER, &enc_user_cert))
94 {
95 DBG1(DBG_IKE, "unable to extract encoded user certificate");
96 rounds->destroy(rounds);
97 return FALSE;
98 }
99
100 ri_id_type ri_id = get_remote_identity_id(ike_sa->get_peer_cfg((ike_sa_t *)ike_sa));
101 certificate_type user_cert;
102 chunk_to_sequence(&enc_user_cert, &user_cert,
103 sizeof(certificate_type));
104 chunk_free(&enc_user_cert);
105 if (ike_cc_set_user_certificate(cc_id, ri_id, 1, user_cert) != TKM_OK)
106 {
107 DBG1(DBG_IKE, "error setting user certificate of cert chain"
108 " (cc_id: %llu)", cc_id);
109 rounds->destroy(rounds);
110 return FALSE;
111 }
112
113 /* process intermediate CA certificates */
114 auth_rule_t rule;
115 enumerator_t *enumerator = auth->create_enumerator(auth);
116 while (enumerator->enumerate(enumerator, &rule, &cert))
117 {
118 if (rule == AUTH_RULE_IM_CERT)
119 {
120 chunk_t enc_im_cert;
121 if (!cert->get_encoding(cert, CERT_ASN1_DER, &enc_im_cert))
122 {
123 DBG1(DBG_IKE, "unable to extract encoded intermediate CA"
124 " certificate");
125 rounds->destroy(rounds);
126 enumerator->destroy(enumerator);
127 return FALSE;
128 }
129
130 certificate_type im_cert;
131 chunk_to_sequence(&enc_im_cert, &im_cert,
132 sizeof(certificate_type));
133 chunk_free(&enc_im_cert);
134 if (ike_cc_add_certificate(cc_id, 1, im_cert) != TKM_OK)
135 {
136 DBG1(DBG_IKE, "error adding intermediate certificate to"
137 " cert chain (cc_id: %llu)", cc_id);
138 rounds->destroy(rounds);
139 enumerator->destroy(enumerator);
140 return FALSE;
141 }
142 }
143 }
144 enumerator->destroy(enumerator);
145
146 /* finally add CA certificate */
147 cert = auth->get(auth, AUTH_RULE_CA_CERT);
148 if (cert)
149 {
150 chunk_t enc_ca_cert;
151 if (!cert->get_encoding(cert, CERT_ASN1_DER, &enc_ca_cert))
152 {
153 DBG1(DBG_IKE, "unable to extract encoded CA certificate");
154 rounds->destroy(rounds);
155 return FALSE;
156 }
157
158 const ca_id_type ca_id = 1;
159 certificate_type ca_cert;
160 chunk_to_sequence(&enc_ca_cert, &ca_cert,
161 sizeof(certificate_type));
162 chunk_free(&enc_ca_cert);
163 if (ike_cc_add_certificate(cc_id, 1, ca_cert) != TKM_OK)
164 {
165 DBG1(DBG_IKE, "error adding CA certificate to cert chain "
166 "(cc_id: %llu)", cc_id);
167 rounds->destroy(rounds);
168 return FALSE;
169 }
170
171 if (ike_cc_check_ca(cc_id, ca_id) != TKM_OK)
172 {
173 DBG1(DBG_IKE, "certificate chain (cc_id: %llu) not based on"
174 " trusted CA (ca_id: %llu)", cc_id, ca_id);
175 rounds->destroy(rounds);
176 return FALSE;
177 }
178
179 rounds->destroy(rounds);
180 return TRUE;
181 }
182 else
183 {
184 DBG1(DBG_IKE, "no CA certificate");
185 }
186 }
187 else
188 {
189 DBG1(DBG_IKE, "no subject certificate for remote peer");
190 }
191 }
192
193 rounds->destroy(rounds);
194 return FALSE;
195 }
196
197 METHOD(listener_t, alert, bool,
198 private_tkm_listener_t *this, ike_sa_t *ike_sa,
199 alert_t alert, va_list args)
200 {
201 if (alert == ALERT_KEEP_ON_CHILD_SA_FAILURE)
202 {
203 tkm_keymat_t * const keymat = (tkm_keymat_t*)ike_sa->get_keymat(ike_sa);
204 const isa_id_type isa_id = keymat->get_isa_id(keymat);
205 DBG1(DBG_IKE, "TKM alert listener called for ISA context %llu", isa_id);
206 if (ike_isa_skip_create_first(isa_id) != TKM_OK)
207 {
208 DBG1(DBG_IKE, "Skip of first child SA creation failed for ISA "
209 "context %llu", isa_id);
210 }
211 }
212
213 return TRUE;
214 }
215
216 METHOD(listener_t, authorize, bool,
217 private_tkm_listener_t *this, ike_sa_t *ike_sa,
218 bool final, bool *success)
219 {
220 if (!final)
221 {
222 return TRUE;
223 }
224
225 tkm_keymat_t * const keymat = (tkm_keymat_t*)ike_sa->get_keymat(ike_sa);
226 const isa_id_type isa_id = keymat->get_isa_id(keymat);
227 DBG1(DBG_IKE, "TKM authorize listener called for ISA context %llu", isa_id);
228
229 const cc_id_type cc_id = tkm->idmgr->acquire_id(tkm->idmgr, TKM_CTX_CC);
230 if (!cc_id)
231 {
232 DBG1(DBG_IKE, "unable to acquire CC context id");
233 *success = FALSE;
234 return TRUE;
235 }
236 const bool cc_success = build_cert_chain(ike_sa, cc_id);
237 if (!cc_success)
238 {
239 DBG1(DBG_IKE, "unable to build certificate chain");
240 *success = FALSE;
241 return TRUE;
242 }
243
244 const chunk_t * const auth = keymat->get_auth_payload(keymat);
245 if (!auth->ptr)
246 {
247 DBG1(DBG_IKE, "no AUTHENTICATION data available");
248 *success = FALSE;
249 }
250
251 const chunk_t * const other_init_msg = keymat->get_peer_init_msg(keymat);
252 if (!other_init_msg->ptr)
253 {
254 DBG1(DBG_IKE, "no peer init message available");
255 *success = FALSE;
256 }
257
258 signature_type signature;
259 chunk_to_sequence(auth, &signature, sizeof(signature_type));
260 init_message_type init_msg;
261 chunk_to_sequence(other_init_msg, &init_msg, sizeof(init_message_type));
262
263 if (ike_isa_auth(isa_id, cc_id, init_msg, signature) != TKM_OK)
264 {
265 DBG1(DBG_IKE, "TKM based authentication failed"
266 " for ISA context %llu", isa_id);
267 *success = FALSE;
268 }
269 else
270 {
271 DBG1(DBG_IKE, "TKM based authentication successful"
272 " for ISA context %llu", isa_id);
273 *success = TRUE;
274 }
275
276 return TRUE;
277 }
278
279 METHOD(listener_t, message, bool,
280 private_tkm_listener_t *this, ike_sa_t *ike_sa,
281 message_t *message, bool incoming, bool plain)
282 {
283 if (!incoming || !plain || message->get_exchange_type(message) != IKE_AUTH)
284 {
285 return TRUE;
286 }
287
288 tkm_keymat_t * const keymat = (tkm_keymat_t*)ike_sa->get_keymat(ike_sa);
289 const isa_id_type isa_id = keymat->get_isa_id(keymat);
290 DBG1(DBG_IKE, "saving AUTHENTICATION payload for authorize hook"
291 " (ISA context %llu)", isa_id);
292
293 auth_payload_t * const auth_payload =
294 (auth_payload_t*)message->get_payload(message, AUTHENTICATION);
295 if (auth_payload)
296 {
297 const chunk_t auth_data = auth_payload->get_data(auth_payload);
298 keymat->set_auth_payload(keymat, &auth_data);
299 }
300 else
301 {
302 DBG1(DBG_IKE, "unable to extract AUTHENTICATION payload, authorize will"
303 " fail");
304 }
305
306 return TRUE;
307 }
308
309 METHOD(tkm_listener_t, destroy, void,
310 private_tkm_listener_t *this)
311 {
312 free(this);
313 }
314
315 /**
316 * See header
317 */
318 tkm_listener_t *tkm_listener_create()
319 {
320 private_tkm_listener_t *this;
321
322 INIT(this,
323 .public = {
324 .listener = {
325 .authorize = _authorize,
326 .message = _message,
327 .alert = _alert,
328 },
329 .destroy = _destroy,
330 },
331 );
332
333 return &this->public;
334 }