- refactored ike proposal
[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_manager->get_init_config_for_name(charon->configuration_manager,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_manager->get_sa_config_for_name(charon->configuration_manager,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 message->destroy(message);
163 return DELETE_ME;
164 }
165
166 init_config = this->ike_sa->get_init_config(this->ike_sa);
167 this->diffie_hellman = diffie_hellman_create(dh_group);
168 ike_sa_id = this->ike_sa->public.get_id(&(this->ike_sa->public));
169 ike_sa_id->set_responder_spi(ike_sa_id,0);
170
171 /* going to build message */
172 this->logger->log(this->logger, CONTROL|LEVEL2, "Going to build message");
173 this->ike_sa->build_message(this->ike_sa, IKE_SA_INIT, TRUE, &message);
174
175 /* build SA payload */
176 this->build_sa_payload(this, message);
177
178 /* build KE payload */
179 this->build_ke_payload(this, message);
180
181 /* build Nonce payload */
182 this->build_nonce_payload(this,message);
183
184
185 /* message can now be sent (must not be destroyed) */
186 status = this->ike_sa->send_request(this->ike_sa, message);
187 if (status != SUCCESS)
188 {
189 this->logger->log(this->logger, AUDIT, "Unable to initiate connection, could not send message. Aborting");
190 message->destroy(message);
191 return DELETE_ME;
192 }
193
194 message = this->ike_sa->get_last_requested_message(this->ike_sa);
195
196 ike_sa_init_request_data = message->get_packet_data(message);
197
198 /* state can now be changed */
199 this->logger->log(this->logger, CONTROL|LEVEL2, "Create next state object");
200 next_state = ike_sa_init_requested_create(this->ike_sa, this->diffie_hellman, this->sent_nonce,ike_sa_init_request_data);
201 this->ike_sa->set_new_state(this->ike_sa,(state_t *) next_state);
202
203 this->logger->log(this->logger, CONTROL|LEVEL2, "Destroy old sate object");
204 this->destroy_after_state_change(this);
205 return SUCCESS;
206 }
207
208 /**
209 * Implementation of private_initiator_init_t.build_sa_payload.
210 */
211 static void build_sa_payload(private_initiator_init_t *this, message_t *request)
212 {
213 sa_payload_t* sa_payload;
214 linked_list_t *proposal_list;
215 init_config_t *init_config;
216
217 this->logger->log(this->logger, CONTROL|LEVEL1, "Building SA payload");
218
219 init_config = this->ike_sa->get_init_config(this->ike_sa);
220
221 proposal_list = init_config->get_proposals(init_config);
222
223 sa_payload = sa_payload_create_from_proposal_list(proposal_list);
224
225 this->logger->log(this->logger, CONTROL|LEVEL2, "Add SA payload to message");
226 request->add_payload(request, (payload_t *) sa_payload);
227 }
228
229 /**
230 * Implementation of private_initiator_init_t.build_ke_payload.
231 */
232 static void build_ke_payload(private_initiator_init_t *this, message_t *request)
233 {
234 ke_payload_t *ke_payload;
235 chunk_t key_data;
236 diffie_hellman_group_t dh_group;
237
238 this->logger->log(this->logger, CONTROL|LEVEL1, "Building KE payload");
239
240 this->diffie_hellman->get_my_public_value(this->diffie_hellman,&key_data);
241 dh_group = this->diffie_hellman->get_dh_group(this->diffie_hellman);
242
243 ke_payload = ke_payload_create();
244 ke_payload->set_dh_group_number(ke_payload, dh_group);
245 ke_payload->set_key_exchange_data(ke_payload, key_data);
246
247 allocator_free_chunk(&key_data);
248
249 this->logger->log(this->logger, CONTROL|LEVEL2, "Add KE payload to message");
250 request->add_payload(request, (payload_t *) ke_payload);
251 }
252
253 /**
254 * Implementation of private_initiator_init_t.build_nonce_payload.
255 */
256 static void build_nonce_payload(private_initiator_init_t *this, message_t *request)
257 {
258 nonce_payload_t *nonce_payload;
259 randomizer_t *randomizer;
260
261 this->logger->log(this->logger, CONTROL|LEVEL1, "Building NONCE payload");
262
263 this->logger->log(this->logger, CONTROL|LEVEL2, "Get pseudo random bytes for NONCE");
264 randomizer = this->ike_sa->get_randomizer(this->ike_sa);
265
266 randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_SIZE, &(this->sent_nonce));
267
268 this->logger->log(this->logger, RAW|LEVEL2, "Initiator NONCE",&(this->sent_nonce));
269
270 nonce_payload = nonce_payload_create();
271
272 nonce_payload->set_nonce(nonce_payload, this->sent_nonce);
273
274 this->logger->log(this->logger, CONTROL|LEVEL2, "Add NONCE payload to message");
275 request->add_payload(request, (payload_t *) nonce_payload);
276 }
277
278 /**
279 * Implementation of state_t.process_message.
280 */
281 static status_t process_message(private_initiator_init_t *this, message_t *message)
282 {
283 this->logger->log(this->logger, ERROR, "In state INITIATOR_INIT no message is processed");
284 return FAILED;
285 }
286
287 /**
288 * Implementation of state_t.get_state.
289 */
290 static ike_sa_state_t get_state(private_initiator_init_t *this)
291 {
292 return INITIATOR_INIT;
293 }
294
295 /**
296 * Implementation of state_t.destroy.
297 */
298 static void destroy(private_initiator_init_t *this)
299 {
300 this->logger->log(this->logger, CONTROL | LEVEL3, "Going to destroy initiator_init_t state object");
301
302 /* destroy diffie hellman object */
303 if (this->diffie_hellman != NULL)
304 {
305 this->logger->log(this->logger, CONTROL | LEVEL3, "Destroy diffie_hellman_t object");
306 this->diffie_hellman->destroy(this->diffie_hellman);
307 }
308 if (this->sent_nonce.ptr != NULL)
309 {
310 this->logger->log(this->logger, CONTROL | LEVEL3, "Free memory of sent nonce");
311 allocator_free(this->sent_nonce.ptr);
312 }
313 allocator_free(this);
314 }
315
316 /**
317 * Implementation of private_initiator_init_t.destroy_after_state_change
318 */
319 static void destroy_after_state_change (private_initiator_init_t *this)
320 {
321 this->logger->log(this->logger, CONTROL | LEVEL3, "Going to destroy initiator_init_t state object");
322 allocator_free(this);
323 }
324
325 /*
326 * Described in header.
327 */
328 initiator_init_t *initiator_init_create(protected_ike_sa_t *ike_sa)
329 {
330 private_initiator_init_t *this = allocator_alloc_thing(private_initiator_init_t);
331
332 /* interface functions */
333 this->public.state_interface.process_message = (status_t (*) (state_t *,message_t *)) process_message;
334 this->public.state_interface.get_state = (ike_sa_state_t (*) (state_t *)) get_state;
335 this->public.state_interface.destroy = (void (*) (state_t *)) destroy;
336
337 /* public functions */
338 this->public.initiate_connection = (status_t (*)(initiator_init_t *, char *)) initiate_connection;
339 this->public.retry_initiate_connection = (status_t (*)(initiator_init_t *, int )) retry_initiate_connection;
340
341 /* private functions */
342 this->destroy_after_state_change = destroy_after_state_change;
343 this->build_nonce_payload = build_nonce_payload;
344 this->build_sa_payload = build_sa_payload;
345 this->build_ke_payload = build_ke_payload;
346
347 /* private data */
348 this->ike_sa = ike_sa;
349 this->logger = this->ike_sa->get_logger(this->ike_sa);
350 this->sent_nonce = CHUNK_INITIALIZER;
351 this->diffie_hellman = NULL;
352
353 return &(this->public);
354 }