- first attempt for connection loading and starting via "stroke"
[strongswan.git] / Source / 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) 2005 Jan Hutter, Martin Willi
10 * Hochschule fuer Technik Rapperswil
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * for more details.
21 */
22
23 #include "initiator_init.h"
24
25
26 #include <daemon.h>
27 #include <sa/states/state.h>
28 #include <sa/states/ike_sa_init_requested.h>
29 #include <utils/allocator.h>
30 #include <queues/jobs/retransmit_request_job.h>
31 #include <transforms/diffie_hellman.h>
32 #include <encoding/payloads/sa_payload.h>
33 #include <encoding/payloads/ke_payload.h>
34 #include <encoding/payloads/nonce_payload.h>
35
36
37 typedef struct private_initiator_init_t private_initiator_init_t;
38
39 /**
40 * Private data of a initiator_init_t object..
41 *
42 */
43 struct private_initiator_init_t {
44 /**
45 * Methods of the state_t interface.
46 */
47 initiator_init_t public;
48
49 /**
50 * Assigned IKE_SA.
51 */
52 protected_ike_sa_t *ike_sa;
53
54 /**
55 * Diffie hellman object used to generate public DH value.
56 * This objet is passed to the next state of type IKE_SA_INIT_REQUESTED.
57 */
58 diffie_hellman_t *diffie_hellman;
59
60 /**
61 * Sent nonce.
62 * This nonce is passed to the next state of type IKE_SA_INIT_REQUESTED.
63 */
64 chunk_t sent_nonce;
65
66 /**
67 * Assigned logger.
68 *
69 * Is logger of ike_sa!
70 */
71 logger_t *logger;
72
73 /**
74 * Builds the SA payload for this state.
75 *
76 * @param this calling object
77 * @param request message_t object to add the SA payload
78 */
79 void (*build_sa_payload) (private_initiator_init_t *this, message_t *request);
80
81 /**
82 * Builds the KE payload for this state.
83 *
84 * @param this calling object
85 * @param request message_t object to add the KE payload
86 */
87 void (*build_ke_payload) (private_initiator_init_t *this, message_t *request);
88
89 /**
90 * Builds the NONCE payload for this state.
91 *
92 * @param this calling object
93 * @param request message_t object to add the NONCE payload
94 */
95 void (*build_nonce_payload) (private_initiator_init_t *this,message_t *request);
96
97 /**
98 * Destroy function called internally of this class after state change to state
99 * IKE_SA_INIT_REQUESTED succeeded.
100 *
101 * This destroy function does not destroy objects which were passed to the new state.
102 *
103 * @param this calling object
104 */
105 void (*destroy_after_state_change) (private_initiator_init_t *this);
106 };
107
108 /**
109 * Implementation of initiator_init_t.initiate_connection.
110 */
111 static status_t initiate_connection (private_initiator_init_t *this, char *name)
112 {
113 init_config_t *init_config;
114 sa_config_t *sa_config;
115 status_t status;
116 diffie_hellman_group_t dh_group;
117
118 this->logger->log(this->logger, CONTROL, "Initializing connection %s",name);
119
120 /* get configs */
121 status = charon->configuration->get_init_config_for_name(charon->configuration,name,&init_config);
122 if (status != SUCCESS)
123 {
124 this->logger->log(this->logger, ERROR | LEVEL1, "Could not retrieve INIT configuration informations for %s",name);
125 return DELETE_ME;
126 }
127 this->ike_sa->set_init_config(this->ike_sa,init_config);
128 status = charon->configuration->get_sa_config_for_name(charon->configuration,name,&sa_config);
129 if (status != SUCCESS)
130 {
131 this->logger->log(this->logger, ERROR | LEVEL1, "Could not retrieve SA configuration informations for %s",name);
132 return DELETE_ME;
133 }
134 this->ike_sa->set_sa_config(this->ike_sa,sa_config);
135
136 /* host informations are read from configuration */
137 this->ike_sa->set_other_host(this->ike_sa,init_config->get_other_host_clone(init_config));
138 this->ike_sa->set_my_host(this->ike_sa,init_config->get_my_host_clone(init_config));
139
140 /* we must guess now a DH group. For that we choose our most preferred group */
141 dh_group = init_config->get_dh_group(init_config);
142
143 /* next step is done in retry_initiate_connection */
144 return this->public.retry_initiate_connection(&(this->public), dh_group);
145 }
146
147 /**
148 * Implementation of initiator_init_t.retry_initiate_connection.
149 */
150 status_t retry_initiate_connection (private_initiator_init_t *this, diffie_hellman_group_t dh_group)
151 {
152 ike_sa_init_requested_t *next_state;
153 chunk_t ike_sa_init_request_data;
154 init_config_t *init_config;
155 ike_sa_id_t *ike_sa_id;
156 message_t *message;
157 status_t status;
158
159 if (dh_group == MODP_UNDEFINED)
160 {
161 this->logger->log(this->logger, AUDIT, "No DH group acceptable for initialization, Aborting");
162 return DELETE_ME;
163 }
164
165 init_config = this->ike_sa->get_init_config(this->ike_sa);
166 this->diffie_hellman = diffie_hellman_create(dh_group);
167 ike_sa_id = this->ike_sa->public.get_id(&(this->ike_sa->public));
168 ike_sa_id->set_responder_spi(ike_sa_id,0);
169
170 /* going to build message */
171 this->logger->log(this->logger, CONTROL|LEVEL2, "Going to build message");
172 this->ike_sa->build_message(this->ike_sa, IKE_SA_INIT, TRUE, &message);
173
174 /* build SA payload */
175 this->build_sa_payload(this, message);
176
177 /* build KE payload */
178 this->build_ke_payload(this, message);
179
180 /* build Nonce payload */
181 this->build_nonce_payload(this,message);
182
183
184 /* message can now be sent (must not be destroyed) */
185 status = this->ike_sa->send_request(this->ike_sa, message);
186 if (status != SUCCESS)
187 {
188 this->logger->log(this->logger, AUDIT, "Unable to initiate connection, could not send message. Aborting");
189 message->destroy(message);
190 return DELETE_ME;
191 }
192
193 message = this->ike_sa->get_last_requested_message(this->ike_sa);
194
195 ike_sa_init_request_data = message->get_packet_data(message);
196
197 /* state can now be changed */
198 this->logger->log(this->logger, CONTROL|LEVEL2, "Create next state object");
199 next_state = ike_sa_init_requested_create(this->ike_sa, this->diffie_hellman, this->sent_nonce,ike_sa_init_request_data);
200 this->ike_sa->set_new_state(this->ike_sa,(state_t *) next_state);
201
202 this->logger->log(this->logger, CONTROL|LEVEL2, "Destroy old sate object");
203 this->destroy_after_state_change(this);
204 return SUCCESS;
205 }
206
207 /**
208 * Implementation of private_initiator_init_t.build_sa_payload.
209 */
210 static void build_sa_payload(private_initiator_init_t *this, message_t *request)
211 {
212 sa_payload_t* sa_payload;
213 linked_list_t *proposal_list;
214 init_config_t *init_config;
215
216 this->logger->log(this->logger, CONTROL|LEVEL1, "Building SA payload");
217
218 init_config = this->ike_sa->get_init_config(this->ike_sa);
219
220 proposal_list = init_config->get_proposals(init_config);
221
222 sa_payload = sa_payload_create_from_proposal_list(proposal_list);
223
224 this->logger->log(this->logger, CONTROL|LEVEL2, "Add SA payload to message");
225 request->add_payload(request, (payload_t *) sa_payload);
226 }
227
228 /**
229 * Implementation of private_initiator_init_t.build_ke_payload.
230 */
231 static void build_ke_payload(private_initiator_init_t *this, message_t *request)
232 {
233 ke_payload_t *ke_payload;
234 chunk_t key_data;
235 diffie_hellman_group_t dh_group;
236
237 this->logger->log(this->logger, CONTROL|LEVEL1, "Building KE payload");
238
239 this->diffie_hellman->get_my_public_value(this->diffie_hellman,&key_data);
240 dh_group = this->diffie_hellman->get_dh_group(this->diffie_hellman);
241
242 ke_payload = ke_payload_create();
243 ke_payload->set_dh_group_number(ke_payload, dh_group);
244 ke_payload->set_key_exchange_data(ke_payload, key_data);
245
246 allocator_free_chunk(&key_data);
247
248 this->logger->log(this->logger, CONTROL|LEVEL2, "Add KE payload to message");
249 request->add_payload(request, (payload_t *) ke_payload);
250 }
251
252 /**
253 * Implementation of private_initiator_init_t.build_nonce_payload.
254 */
255 static void build_nonce_payload(private_initiator_init_t *this, message_t *request)
256 {
257 nonce_payload_t *nonce_payload;
258 randomizer_t *randomizer;
259
260 this->logger->log(this->logger, CONTROL|LEVEL1, "Building NONCE payload");
261
262 this->logger->log(this->logger, CONTROL|LEVEL2, "Get pseudo random bytes for NONCE");
263 randomizer = this->ike_sa->get_randomizer(this->ike_sa);
264
265 randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_SIZE, &(this->sent_nonce));
266
267 this->logger->log(this->logger, RAW|LEVEL2, "Initiator NONCE",&(this->sent_nonce));
268
269 nonce_payload = nonce_payload_create();
270
271 nonce_payload->set_nonce(nonce_payload, this->sent_nonce);
272
273 this->logger->log(this->logger, CONTROL|LEVEL2, "Add NONCE payload to message");
274 request->add_payload(request, (payload_t *) nonce_payload);
275 }
276
277 /**
278 * Implementation of state_t.process_message.
279 */
280 static status_t process_message(private_initiator_init_t *this, message_t *message)
281 {
282 this->logger->log(this->logger, ERROR, "In state INITIATOR_INIT, no message is processed");
283 return FAILED;
284 }
285
286 /**
287 * Implementation of state_t.get_state.
288 */
289 static ike_sa_state_t get_state(private_initiator_init_t *this)
290 {
291 return INITIATOR_INIT;
292 }
293
294 /**
295 * Implementation of state_t.destroy.
296 */
297 static void destroy(private_initiator_init_t *this)
298 {
299 this->logger->log(this->logger, CONTROL | LEVEL3, "Going to destroy initiator_init_t state object");
300
301 /* destroy diffie hellman object */
302 if (this->diffie_hellman != NULL)
303 {
304 this->diffie_hellman->destroy(this->diffie_hellman);
305 }
306 if (this->sent_nonce.ptr != NULL)
307 {
308 allocator_free(this->sent_nonce.ptr);
309 }
310 allocator_free(this);
311 }
312
313 /**
314 * Implementation of private_initiator_init_t.destroy_after_state_change
315 */
316 static void destroy_after_state_change (private_initiator_init_t *this)
317 {
318 this->logger->log(this->logger, CONTROL | LEVEL3, "Going to destroy initiator_init_t state object");
319 allocator_free(this);
320 }
321
322 /*
323 * Described in header.
324 */
325 initiator_init_t *initiator_init_create(protected_ike_sa_t *ike_sa)
326 {
327 private_initiator_init_t *this = allocator_alloc_thing(private_initiator_init_t);
328
329 /* interface functions */
330 this->public.state_interface.process_message = (status_t (*) (state_t *,message_t *)) process_message;
331 this->public.state_interface.get_state = (ike_sa_state_t (*) (state_t *)) get_state;
332 this->public.state_interface.destroy = (void (*) (state_t *)) destroy;
333
334 /* public functions */
335 this->public.initiate_connection = (status_t (*)(initiator_init_t *, char *)) initiate_connection;
336 this->public.retry_initiate_connection = (status_t (*)(initiator_init_t *, int )) retry_initiate_connection;
337
338 /* private functions */
339 this->destroy_after_state_change = destroy_after_state_change;
340 this->build_nonce_payload = build_nonce_payload;
341 this->build_sa_payload = build_sa_payload;
342 this->build_ke_payload = build_ke_payload;
343
344 /* private data */
345 this->ike_sa = ike_sa;
346 this->logger = this->ike_sa->get_logger(this->ike_sa);
347 this->sent_nonce = CHUNK_INITIALIZER;
348 this->diffie_hellman = NULL;
349
350 return &(this->public);
351 }