support of cert payloads
[strongswan.git] / src / charon / sa / states / initiator_init.c
1 /**
2 * @file initiator_init.c
3 *
4 * @brief Implementation of initiator_init_t.
5 *
6 */
7
8 /*
9 * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
10 * Copyright (C) 2005 Jan Hutter, Martin Willi
11 * Hochschule fuer Technik Rapperswil
12 *
13 * This program is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU General Public License as published by the
15 * Free Software Foundation; either version 2 of the License, or (at your
16 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
17 *
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 * for more details.
22 */
23
24 #include "initiator_init.h"
25
26
27 #include <daemon.h>
28 #include <sa/states/state.h>
29 #include <sa/states/ike_sa_init_requested.h>
30 #include <queues/jobs/retransmit_request_job.h>
31 #include <crypto/diffie_hellman.h>
32 #include <crypto/hashers/hasher.h>
33 #include <encoding/payloads/sa_payload.h>
34 #include <encoding/payloads/ke_payload.h>
35 #include <encoding/payloads/nonce_payload.h>
36
37
38 typedef struct private_initiator_init_t private_initiator_init_t;
39
40 /**
41 * Private data of a initiator_init_t object..
42 *
43 */
44 struct private_initiator_init_t {
45 /**
46 * Methods of the state_t interface.
47 */
48 initiator_init_t public;
49
50 /**
51 * Assigned IKE_SA.
52 */
53 protected_ike_sa_t *ike_sa;
54
55 /**
56 * Diffie hellman object used to generate public DH value.
57 * This objet is passed to the next state of type IKE_SA_INIT_REQUESTED.
58 */
59 diffie_hellman_t *diffie_hellman;
60
61 /**
62 * Sent nonce.
63 * This nonce is passed to the next state of type IKE_SA_INIT_REQUESTED.
64 */
65 chunk_t sent_nonce;
66
67 /**
68 * Assigned logger.
69 *
70 * Is logger of ike_sa!
71 */
72 logger_t *logger;
73
74 /**
75 * Builds the SA payload for this state.
76 *
77 * @param this calling object
78 * @param msg message_t object to add the SA payload
79 */
80 void (*build_sa_payload) (private_initiator_init_t *this, message_t *msg);
81
82 /**
83 * Builds the KE payload for this state.
84 *
85 * @param this calling object
86 * @param msg message_t object to add the KE payload
87 */
88 void (*build_ke_payload) (private_initiator_init_t *this, message_t *msg);
89
90 /**
91 * Builds the NONCE payload for this state.
92 *
93 * @param this calling object
94 * @param msg message_t object to add the NONCE payload
95 */
96 status_t (*build_nonce_payload) (private_initiator_init_t *this,message_t *msg);
97
98 /**
99 * Builds the NAT-T Notify(NAT_DETECTION_SOURCE_IP) and
100 * Notify(NAT_DETECTION_DESTINATION_IP) payloads for this state.
101 *
102 * @param this calling object
103 * @param msg message_t object to add the Notify payloads
104 */
105 void (*build_natd_payload) (private_initiator_init_t *this, message_t *msg, notify_message_type_t type, host_t *host);
106
107 /**
108 * Builds the NAT-T Notify(NAT_DETECTION_SOURCE_IP) and
109 * Notify(NAT_DETECTION_DESTINATION_IP) payloads for this state.
110 *
111 * @param this calling object
112 * @param msg message_t object to add the Notify payloads
113 */
114 void (*build_natd_payloads) (private_initiator_init_t *this, message_t *msg);
115
116 /**
117 * Destroy function called internally of this class after state change to state
118 * IKE_SA_INIT_REQUESTED succeeded.
119 *
120 * This destroy function does not destroy objects which were passed to the new state.
121 *
122 * @param this calling object
123 */
124 void (*destroy_after_state_change) (private_initiator_init_t *this);
125 };
126
127 /**
128 * Implementation of initiator_init_t.initiate_connection.
129 */
130 static status_t initiate_connection (private_initiator_init_t *this, connection_t *connection)
131 {
132 policy_t *policy;
133 diffie_hellman_group_t dh_group;
134 host_t *my_host, *other_host;
135 identification_t *my_id, *other_id;
136 char *name;
137
138 name = connection->get_name(connection);
139 this->ike_sa->set_connection(this->ike_sa, connection);
140
141 /* get policy */
142 policy = charon->policies->get_policy_by_name(charon->policies, name);
143 if (policy == NULL)
144 {
145 this->logger->log(this->logger, ERROR | LEVEL1,
146 "could not get a policy named '%s', aborting", name);
147 return DESTROY_ME;
148 }
149 this->ike_sa->set_policy(this->ike_sa, policy);
150
151 my_host = connection->get_my_host(connection);
152 other_host = connection->get_other_host(connection);
153 my_id = policy->get_my_id(policy);
154 other_id = policy->get_other_id(policy);
155
156 this->logger->log(this->logger, CONTROL, "initiating connection \"%s\": %s[%s]...%s[%s]",
157 name,
158 my_host->get_address(my_host),
159 my_id->get_string(my_id),
160 other_host->get_address(other_host),
161 other_id->get_string(other_id));
162
163 /* we must guess now a DH group. For that we choose our most preferred group */
164 dh_group = connection->get_dh_group(connection);
165
166 /* next step is done in retry_initiate_connection */
167 return this->public.retry_initiate_connection(&this->public, dh_group);
168 }
169
170 /**
171 * Implementation of initiator_init_t.retry_initiate_connection.
172 */
173 status_t retry_initiate_connection (private_initiator_init_t *this, diffie_hellman_group_t dh_group)
174 {
175 ike_sa_init_requested_t *next_state;
176 chunk_t ike_sa_init_request_data;
177 connection_t *connection;
178 ike_sa_id_t *ike_sa_id;
179 message_t *message;
180 status_t status;
181
182 this->diffie_hellman = diffie_hellman_create(dh_group);
183 if (this->diffie_hellman == NULL)
184 {
185 this->logger->log(this->logger, AUDIT, "DH group %s (%d) not supported, aborting",
186 mapping_find(diffie_hellman_group_m, dh_group), dh_group);
187 return DESTROY_ME;
188 }
189
190 connection = this->ike_sa->get_connection(this->ike_sa);
191 ike_sa_id = this->ike_sa->public.get_id(&(this->ike_sa->public));
192 ike_sa_id->set_responder_spi(ike_sa_id,0);
193
194 /* going to build message */
195 this->logger->log(this->logger, CONTROL|LEVEL2, "going to build message");
196 this->ike_sa->build_message(this->ike_sa, IKE_SA_INIT, TRUE, &message);
197
198 /* build SA payload */
199 this->build_sa_payload(this, message);
200 /* build KE payload */
201 this->build_ke_payload(this, message);
202 /* build Nonce payload */
203 status = this->build_nonce_payload(this, message);
204 if (status != SUCCESS)
205 {
206 this->logger->log(this->logger, ERROR, "building nonce payload failed, aborting");
207 message->destroy(message);
208 return DESTROY_ME;
209 }
210
211 /* build Notify(NAT-D) payloads */
212 this->build_natd_payloads(this, message);
213
214 /* message can now be sent (must not be destroyed) */
215 status = this->ike_sa->send_request(this->ike_sa, message);
216 if (status != SUCCESS)
217 {
218 this->logger->log(this->logger, AUDIT, "unable to initiate connection, could not send message, aborting");
219 message->destroy(message);
220 return DESTROY_ME;
221 }
222
223 message = this->ike_sa->get_last_requested_message(this->ike_sa);
224
225 ike_sa_init_request_data = message->get_packet_data(message);
226
227 /* state can now be changed */
228 this->logger->log(this->logger, CONTROL|LEVEL2, "create next state object");
229 next_state = ike_sa_init_requested_create(this->ike_sa, this->diffie_hellman, this->sent_nonce,ike_sa_init_request_data);
230 this->ike_sa->set_new_state(this->ike_sa,(state_t *) next_state);
231
232 this->logger->log(this->logger, CONTROL|LEVEL2, "destroy old state object");
233 this->destroy_after_state_change(this);
234 return SUCCESS;
235 }
236
237 /**
238 * Implementation of private_initiator_init_t.build_sa_payload.
239 */
240 static void build_sa_payload(private_initiator_init_t *this, message_t *msg)
241 {
242 sa_payload_t* sa_payload;
243 linked_list_t *proposal_list;
244 connection_t *connection;
245
246 this->logger->log(this->logger, CONTROL|LEVEL1, "building SA payload");
247
248 connection = this->ike_sa->get_connection(this->ike_sa);
249
250 proposal_list = connection->get_proposals(connection);
251
252 sa_payload = sa_payload_create_from_proposal_list(proposal_list);
253
254 this->logger->log(this->logger, CONTROL|LEVEL2, "add SA payload to message");
255 msg->add_payload(msg, (payload_t *) sa_payload);
256 }
257
258 /**
259 * Implementation of private_initiator_init_t.build_ke_payload.
260 */
261 static void build_ke_payload(private_initiator_init_t *this, message_t *msg)
262 {
263 ke_payload_t *ke_payload;
264 chunk_t key_data;
265 diffie_hellman_group_t dh_group;
266
267 this->logger->log(this->logger, CONTROL|LEVEL1, "building KE payload");
268
269 this->diffie_hellman->get_my_public_value(this->diffie_hellman, &key_data);
270 dh_group = this->diffie_hellman->get_dh_group(this->diffie_hellman);
271
272 ke_payload = ke_payload_create();
273 ke_payload->set_dh_group_number(ke_payload, dh_group);
274 ke_payload->set_key_exchange_data(ke_payload, key_data);
275
276 chunk_free(&key_data);
277
278 this->logger->log(this->logger, CONTROL|LEVEL2, "add KE payload to message");
279 msg->add_payload(msg, (payload_t *) ke_payload);
280 }
281
282 /**
283 * Implementation of private_initiator_init_t.build_nonce_payload.
284 */
285 static status_t build_nonce_payload(private_initiator_init_t *this, message_t *msg)
286 {
287 nonce_payload_t *nonce_payload;
288 randomizer_t *randomizer;
289 status_t status;
290
291 this->logger->log(this->logger, CONTROL|LEVEL1, "building NONCE payload");
292
293 this->logger->log(this->logger, CONTROL|LEVEL2, "get pseudo random bytes for NONCE");
294 randomizer = this->ike_sa->get_randomizer(this->ike_sa);
295
296 status = randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_SIZE, &(this->sent_nonce));
297 if (status != SUCCESS)
298 {
299 return status;
300 }
301
302 this->logger->log(this->logger, RAW|LEVEL2, "initiator NONCE",&(this->sent_nonce));
303
304 nonce_payload = nonce_payload_create();
305
306 nonce_payload->set_nonce(nonce_payload, this->sent_nonce);
307
308 this->logger->log(this->logger, CONTROL|LEVEL2, "add NONCE payload to message");
309 msg->add_payload(msg, (payload_t *) nonce_payload);
310 return SUCCESS;
311 }
312
313 /**
314 * Implementation of private_initiator_init_t.build_natd_payload.
315 */
316 static void build_natd_payload(private_initiator_init_t *this, message_t *msg, notify_message_type_t type, host_t *host)
317 {
318 chunk_t hash;
319 this->logger->log(this->logger, CONTROL|LEVEL1, "building Notify(NAT-D) payload");
320 notify_payload_t *notify_payload;
321 notify_payload = notify_payload_create();
322 /*notify_payload->set_protocol_id(notify_payload, NULL);*/
323 /*notify_payload->set_spi(notify_payload, NULL);*/
324 notify_payload->set_notify_message_type(notify_payload, type);
325 hash = this->ike_sa->generate_natd_hash(this->ike_sa,
326 msg->get_initiator_spi(msg),
327 msg->get_responder_spi(msg),
328 host);
329 notify_payload->set_notification_data(notify_payload, hash);
330 chunk_free(&hash);
331 this->logger->log(this->logger, CONTROL|LEVEL2, "add Notify(NAT-D) payload to message");
332 msg->add_payload(msg, (payload_t *) notify_payload);
333 }
334
335 /**
336 * Implementation of private_initiator_init_t.build_natd_payloads.
337 */
338 static void build_natd_payloads(private_initiator_init_t *this, message_t *msg)
339 {
340 connection_t *connection;
341 linked_list_t *hostlist;
342 iterator_t *hostiter;
343 host_t *host;
344
345 /*
346 * N(NAT_DETECTION_SOURCE_IP)+
347 */
348 hostlist = charon->interfaces->get_addresses(charon->interfaces);
349 hostiter = hostlist->create_iterator(hostlist, TRUE);
350 while(hostiter->iterate(hostiter, (void**)&host)) {
351 this->build_natd_payload(this, msg, NAT_DETECTION_SOURCE_IP,
352 host);
353 }
354 hostiter->destroy(hostiter);
355
356 /*
357 * N(NAT_DETECTION_DESTINATION_IP)
358 */
359 connection = this->ike_sa->get_connection(this->ike_sa);
360 this->build_natd_payload(this, msg, NAT_DETECTION_DESTINATION_IP,
361 connection->get_other_host(connection));
362 }
363
364 /**
365 * Implementation of state_t.process_message.
366 */
367 static status_t process_message(private_initiator_init_t *this, message_t *message)
368 {
369 this->logger->log(this->logger, ERROR, "in state INITIATOR_INIT, no message is processed");
370 return FAILED;
371 }
372
373 /**
374 * Implementation of state_t.get_state.
375 */
376 static ike_sa_state_t get_state(private_initiator_init_t *this)
377 {
378 return INITIATOR_INIT;
379 }
380
381 /**
382 * Implementation of state_t.destroy.
383 */
384 static void destroy(private_initiator_init_t *this)
385 {
386 this->logger->log(this->logger, CONTROL | LEVEL3, "going to destroy initiator_init_t state object");
387
388 /* destroy diffie hellman object */
389 if (this->diffie_hellman != NULL)
390 {
391 this->diffie_hellman->destroy(this->diffie_hellman);
392 }
393 if (this->sent_nonce.ptr != NULL)
394 {
395 free(this->sent_nonce.ptr);
396 }
397 free(this);
398 }
399
400 /**
401 * Implementation of private_initiator_init_t.destroy_after_state_change
402 */
403 static void destroy_after_state_change (private_initiator_init_t *this)
404 {
405 this->logger->log(this->logger, CONTROL | LEVEL3, "going to destroy initiator_init_t state object");
406 free(this);
407 }
408
409 /*
410 * Described in header.
411 */
412 initiator_init_t *initiator_init_create(protected_ike_sa_t *ike_sa)
413 {
414 private_initiator_init_t *this = malloc_thing(private_initiator_init_t);
415
416 /* interface functions */
417 this->public.state_interface.process_message = (status_t (*) (state_t *,message_t *)) process_message;
418 this->public.state_interface.get_state = (ike_sa_state_t (*) (state_t *)) get_state;
419 this->public.state_interface.destroy = (void (*) (state_t *)) destroy;
420
421 /* public functions */
422 this->public.initiate_connection = (status_t (*)(initiator_init_t *, connection_t*)) initiate_connection;
423 this->public.retry_initiate_connection = (status_t (*)(initiator_init_t *, int )) retry_initiate_connection;
424
425 /* private functions */
426 this->destroy_after_state_change = destroy_after_state_change;
427 this->build_nonce_payload = build_nonce_payload;
428 this->build_sa_payload = build_sa_payload;
429 this->build_ke_payload = build_ke_payload;
430 this->build_natd_payload = build_natd_payload;
431 this->build_natd_payloads = build_natd_payloads;
432
433 /* private data */
434 this->ike_sa = ike_sa;
435 this->logger = logger_manager->get_logger(logger_manager, IKE_SA);
436 this->sent_nonce = CHUNK_INITIALIZER;
437 this->diffie_hellman = NULL;
438
439 return &(this->public);
440 }