]>
Commit | Line | Data |
---|---|---|
c7dd2a7b MW |
1 | /** |
2 | * @file initiator_init.c | |
3 | * | |
8c7824fb | 4 | * @brief Implementation of initiator_init_t. |
c7dd2a7b MW |
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 | ||
0e96f7d8 | 26 | #include <daemon.h> |
c7dd2a7b MW |
27 | #include <sa/states/state.h> |
28 | #include <sa/states/ike_sa_init_requested.h> | |
29 | #include <utils/allocator.h> | |
5534ee84 | 30 | #include <queues/jobs/retransmit_request_job.h> |
c7dd2a7b MW |
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 | ||
5796aa16 MW |
37 | typedef struct private_initiator_init_t private_initiator_init_t; |
38 | ||
c7dd2a7b | 39 | /** |
8c7824fb | 40 | * Private data of a initiator_init_t object.. |
c7dd2a7b MW |
41 | * |
42 | */ | |
5796aa16 | 43 | struct private_initiator_init_t { |
c7dd2a7b MW |
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_t. | |
57 | */ | |
58 | diffie_hellman_t *diffie_hellman; | |
59 | ||
60 | /** | |
61 | * DH group number. | |
62 | */ | |
63 | u_int16_t dh_group_number; | |
64 | ||
65 | /** | |
66 | * DH group priority used to get dh_group_number from configuration manager. | |
67 | * This priority is passed to the next state of type ike_sa_init_requested_t. | |
68 | */ | |
69 | u_int16_t dh_group_priority; | |
70 | ||
71 | /** | |
72 | * Sent nonce. | |
73 | * This nonce is passed to the next state of type ike_sa_init_requested_t. | |
74 | */ | |
75 | chunk_t sent_nonce; | |
c7dd2a7b MW |
76 | |
77 | /** | |
78 | * Logger used to log :-) | |
79 | * | |
80 | * Is logger of ike_sa! | |
81 | */ | |
82 | logger_t *logger; | |
83 | ||
84 | /** | |
85 | * Builds the IKE_SA_INIT request message. | |
86 | * | |
87 | * @param this calling object | |
88 | * @param message the created message will be stored at this location | |
c7dd2a7b | 89 | */ |
d048df5c | 90 | void (*build_ike_sa_init_request) (private_initiator_init_t *this, message_t **message); |
c7dd2a7b MW |
91 | |
92 | /** | |
93 | * Builds the SA payload for this state. | |
94 | * | |
95 | * @param this calling object | |
96 | * @param payload The generated SA payload object of type ke_payload_t is | |
97 | * stored at this location. | |
c7dd2a7b | 98 | */ |
d048df5c | 99 | void (*build_sa_payload) (private_initiator_init_t *this, payload_t **payload); |
c7dd2a7b MW |
100 | |
101 | /** | |
102 | * Builds the KE payload for this state. | |
103 | * | |
104 | * @param this calling object | |
105 | * @param payload The generated KE payload object of type ke_payload_t is | |
106 | * stored at this location. | |
c7dd2a7b | 107 | */ |
d048df5c MW |
108 | void (*build_ke_payload) (private_initiator_init_t *this, payload_t **payload); |
109 | ||
c7dd2a7b MW |
110 | /** |
111 | * Builds the NONCE payload for this state. | |
112 | * | |
113 | * @param this calling object | |
114 | * @param payload The generated NONCE payload object of type ke_payload_t is | |
115 | * stored at this location. | |
c7dd2a7b | 116 | */ |
d048df5c | 117 | void (*build_nonce_payload) (private_initiator_init_t *this, payload_t **payload); |
c7dd2a7b MW |
118 | |
119 | /** | |
f6ba78c3 JH |
120 | * Destroy function called internally of this class after state change to state |
121 | * IKE_SA_INIT_REQUESTED succeeded. | |
c7dd2a7b MW |
122 | * |
123 | * This destroy function does not destroy objects which were passed to the new state. | |
124 | * | |
125 | * @param this calling object | |
c7dd2a7b | 126 | */ |
d048df5c | 127 | void (*destroy_after_state_change) (private_initiator_init_t *this); |
c7dd2a7b MW |
128 | }; |
129 | ||
130 | /** | |
2848a7ba | 131 | * Implementation of initiator_init_t.initiate_connection. |
c7dd2a7b | 132 | */ |
aad398a7 | 133 | static status_t initiate_connection (private_initiator_init_t *this, char *name) |
c7dd2a7b | 134 | { |
8c7824fb | 135 | init_config_t *init_config; |
8c7824fb | 136 | sa_config_t *sa_config; |
d048df5c | 137 | status_t status; |
8d68033e | 138 | |
aad398a7 | 139 | |
c7dd2a7b MW |
140 | this->logger->log(this->logger, CONTROL, "Initializing connection %s",name); |
141 | ||
a9428251 | 142 | status = charon->configuration_manager->get_init_config_for_name(charon->configuration_manager,name,&init_config); |
c7dd2a7b MW |
143 | if (status != SUCCESS) |
144 | { | |
a9428251 | 145 | this->logger->log(this->logger, ERROR | MORE, "Could not retrieve INIT configuration informations for %s",name); |
ae3012a0 | 146 | return DELETE_ME; |
c7dd2a7b MW |
147 | } |
148 | ||
a9428251 JH |
149 | this->ike_sa->set_init_config(this->ike_sa,init_config); |
150 | ||
1b3f92d2 JH |
151 | status = charon->configuration_manager->get_sa_config_for_name(charon->configuration_manager,name,&sa_config); |
152 | ||
153 | if (status != SUCCESS) | |
154 | { | |
155 | this->logger->log(this->logger, ERROR | MORE, "Could not retrieve SA configuration informations for %s",name); | |
ae3012a0 | 156 | return DELETE_ME; |
1b3f92d2 JH |
157 | } |
158 | ||
1b3f92d2 JH |
159 | this->ike_sa->set_sa_config(this->ike_sa,sa_config); |
160 | ||
2848a7ba | 161 | /* host informations are read from configuration */ |
a9428251 JH |
162 | this->ike_sa->set_other_host(this->ike_sa,init_config->get_other_host_clone(init_config)); |
163 | this->ike_sa->set_my_host(this->ike_sa,init_config->get_my_host_clone(init_config)); | |
164 | ||
165 | this->dh_group_number = init_config->get_dh_group_number(init_config,this->dh_group_priority); | |
166 | if (this->dh_group_number == MODP_UNDEFINED) | |
d048df5c | 167 | { |
f6ba78c3 | 168 | this->logger->log(this->logger, ERROR | MORE, "Diffie hellman group could not be retrieved with priority %d", this->dh_group_priority); |
ae3012a0 | 169 | return DELETE_ME; |
c7dd2a7b | 170 | } |
0e96f7d8 | 171 | |
2848a7ba JH |
172 | /* next step is done in retry_initiate_connection */ |
173 | return this->public.retry_initiate_connection(&(this->public),this->dh_group_priority); | |
174 | } | |
175 | ||
176 | /** | |
177 | * Implementation of initiator_init_t.retry_initiate_connection. | |
178 | */ | |
179 | status_t retry_initiate_connection (private_initiator_init_t *this, int dh_group_priority) | |
180 | { | |
181 | ike_sa_init_requested_t *next_state; | |
8d68033e | 182 | chunk_t ike_sa_init_request_data; |
2848a7ba JH |
183 | init_config_t *init_config; |
184 | randomizer_t *randomizer; | |
8d68033e | 185 | ike_sa_id_t *ike_sa_id; |
2848a7ba | 186 | message_t *message; |
2848a7ba | 187 | status_t status; |
8d68033e | 188 | |
ae3012a0 JH |
189 | |
190 | this->dh_group_priority = dh_group_priority; | |
2848a7ba JH |
191 | |
192 | init_config = this->ike_sa->get_init_config(this->ike_sa); | |
c7dd2a7b | 193 | |
ae3012a0 JH |
194 | ike_sa_id = this->ike_sa->public.get_id(&(this->ike_sa->public)); |
195 | ike_sa_id->set_responder_spi(ike_sa_id,0); | |
196 | ||
2848a7ba JH |
197 | this->dh_group_number = init_config->get_dh_group_number(init_config,dh_group_priority); |
198 | if (this->dh_group_number == MODP_UNDEFINED) | |
c7dd2a7b | 199 | { |
ae3012a0 JH |
200 | this->logger->log(this->logger, ERROR | MORE, "Diffie hellman group could not be retrieved with priority %d", dh_group_priority); |
201 | return DELETE_ME; | |
c7dd2a7b | 202 | } |
2848a7ba JH |
203 | |
204 | this->diffie_hellman = diffie_hellman_create(this->dh_group_number); | |
c7dd2a7b | 205 | |
d048df5c | 206 | this->logger->log(this->logger, CONTROL|MOST, "Get pseudo random bytes for nonce"); |
aad398a7 | 207 | randomizer = this->ike_sa->get_randomizer(this->ike_sa); |
5534ee84 JH |
208 | |
209 | allocator_free_chunk(&(this->sent_nonce)); | |
210 | ||
d048df5c MW |
211 | randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_SIZE, &(this->sent_nonce)); |
212 | ||
213 | this->logger->log(this->logger, RAW|MOST, "Nonce",&(this->sent_nonce)); | |
214 | ||
215 | this->build_ike_sa_init_request (this,&message); | |
c7dd2a7b | 216 | |
5534ee84 JH |
217 | /* message can now be sent (must not be destroyed) */ |
218 | status = this->ike_sa->send_request(this->ike_sa, message); | |
c7dd2a7b MW |
219 | if (status != SUCCESS) |
220 | { | |
5534ee84 | 221 | this->logger->log(this->logger, ERROR, "Could not send request message"); |
c7dd2a7b | 222 | message->destroy(message); |
ae3012a0 | 223 | return DELETE_ME; |
c7dd2a7b | 224 | } |
8d68033e JH |
225 | |
226 | message = this->ike_sa->get_last_requested_message(this->ike_sa); | |
227 | ||
228 | ike_sa_init_request_data = message->get_packet_data(message); | |
c7dd2a7b MW |
229 | |
230 | /* state can now be changed */ | |
b2410480 | 231 | this->logger->log(this->logger, CONTROL|MOST, "Create next state object"); |
8d68033e | 232 | next_state = ike_sa_init_requested_create(this->ike_sa, this->dh_group_priority, this->diffie_hellman, this->sent_nonce,ike_sa_init_request_data); |
c7dd2a7b | 233 | |
aad398a7 JH |
234 | /* state can now be changed */ |
235 | this->ike_sa->set_new_state(this->ike_sa,(state_t *) next_state); | |
c7dd2a7b | 236 | |
c7dd2a7b | 237 | /* state has NOW changed :-) */ |
d048df5c | 238 | this->logger->log(this->logger, CONTROL|MORE, "Changed state of IKE_SA from %s to %s", mapping_find(ike_sa_state_m,INITIATOR_INIT),mapping_find(ike_sa_state_m,IKE_SA_INIT_REQUESTED) ); |
5534ee84 | 239 | |
b2410480 | 240 | this->logger->log(this->logger, CONTROL|MOST, "Destroy old sate object"); |
c7dd2a7b | 241 | this->destroy_after_state_change(this); |
c7dd2a7b MW |
242 | return SUCCESS; |
243 | } | |
244 | ||
245 | /** | |
246 | * implements private_initiator_init_t.build_ike_sa_init_request | |
247 | */ | |
d048df5c | 248 | static void build_ike_sa_init_request (private_initiator_init_t *this, message_t **request) |
c7dd2a7b | 249 | { |
c7dd2a7b MW |
250 | payload_t *payload; |
251 | message_t *message; | |
252 | ||
253 | /* going to build message */ | |
d048df5c MW |
254 | this->logger->log(this->logger, CONTROL|MOST, "Going to build message"); |
255 | this->ike_sa->build_message(this->ike_sa, IKE_SA_INIT, TRUE, &message); | |
c7dd2a7b | 256 | |
d048df5c MW |
257 | /* build SA payload */ |
258 | this->build_sa_payload(this, &payload); | |
259 | this->logger->log(this->logger, CONTROL|MOST, "add SA payload to message"); | |
27e43205 | 260 | message->add_payload(message, payload); |
d048df5c | 261 | |
c7dd2a7b | 262 | /* build KE payload */ |
d048df5c MW |
263 | this->build_ke_payload(this, &payload); |
264 | this->logger->log(this->logger, CONTROL|MOST, "add KE payload to message"); | |
27e43205 | 265 | message->add_payload(message, payload); |
c7dd2a7b MW |
266 | |
267 | /* build Nonce payload */ | |
d048df5c MW |
268 | this->build_nonce_payload(this, &payload); |
269 | this->logger->log(this->logger, CONTROL|MOST, "add nonce payload to message"); | |
27e43205 | 270 | message->add_payload(message, payload); |
c7dd2a7b MW |
271 | |
272 | *request = message; | |
c7dd2a7b MW |
273 | } |
274 | ||
275 | /** | |
276 | * implements private_initiator_init_t.build_sa_payload | |
277 | */ | |
d048df5c | 278 | static void build_sa_payload(private_initiator_init_t *this, payload_t **payload) |
c7dd2a7b MW |
279 | { |
280 | sa_payload_t* sa_payload; | |
a9428251 JH |
281 | size_t proposal_count; |
282 | ike_proposal_t *proposals; | |
283 | init_config_t *init_config; | |
c7dd2a7b | 284 | |
c7dd2a7b | 285 | this->logger->log(this->logger, CONTROL|MORE, "building sa payload"); |
c7dd2a7b | 286 | |
a9428251 | 287 | init_config = this->ike_sa->get_init_config(this->ike_sa); |
c7dd2a7b | 288 | |
a9428251 | 289 | proposal_count = init_config->get_proposals(init_config,&proposals); |
c7dd2a7b | 290 | |
a9428251 JH |
291 | sa_payload = sa_payload_create_from_ike_proposals(proposals,proposal_count); |
292 | ||
293 | allocator_free(proposals); | |
c7dd2a7b | 294 | *payload = (payload_t *) sa_payload; |
c7dd2a7b MW |
295 | } |
296 | ||
297 | /** | |
298 | * implements private_initiator_init_t.build_ke_payload | |
299 | */ | |
d048df5c | 300 | static void build_ke_payload(private_initiator_init_t *this, payload_t **payload) |
c7dd2a7b MW |
301 | { |
302 | ke_payload_t *ke_payload; | |
303 | chunk_t key_data; | |
d048df5c | 304 | |
c7dd2a7b MW |
305 | this->logger->log(this->logger, CONTROL|MORE, "building ke payload"); |
306 | ||
d048df5c | 307 | this->diffie_hellman->get_my_public_value(this->diffie_hellman,&key_data); |
c7dd2a7b MW |
308 | |
309 | ke_payload = ke_payload_create(); | |
c7dd2a7b | 310 | ke_payload->set_dh_group_number(ke_payload, this->dh_group_number); |
d048df5c | 311 | ke_payload->set_key_exchange_data(ke_payload, key_data); |
c7dd2a7b | 312 | |
d048df5c | 313 | allocator_free_chunk(&key_data); |
c7dd2a7b | 314 | *payload = (payload_t *) ke_payload; |
c7dd2a7b MW |
315 | } |
316 | ||
317 | /** | |
318 | * implements private_initiator_init_t.build_nonce_payload | |
319 | */ | |
d048df5c | 320 | static void build_nonce_payload(private_initiator_init_t *this, payload_t **payload) |
c7dd2a7b MW |
321 | { |
322 | nonce_payload_t *nonce_payload; | |
c7dd2a7b MW |
323 | |
324 | this->logger->log(this->logger, CONTROL|MORE, "building nonce payload"); | |
c7dd2a7b | 325 | |
d048df5c | 326 | nonce_payload = nonce_payload_create(); |
c7dd2a7b | 327 | |
d048df5c | 328 | nonce_payload->set_nonce(nonce_payload, this->sent_nonce); |
c7dd2a7b | 329 | |
d048df5c | 330 | *payload = (payload_t *) nonce_payload; |
c7dd2a7b MW |
331 | } |
332 | ||
333 | /** | |
334 | * Implements state_t.get_state | |
335 | */ | |
ae3012a0 | 336 | static status_t process_message(private_initiator_init_t *this, message_t *message) |
c7dd2a7b | 337 | { |
c7dd2a7b MW |
338 | this->logger->log(this->logger, ERROR|MORE, "In state INITIATOR_INIT no message is processed"); |
339 | return FAILED; | |
340 | } | |
341 | ||
342 | /** | |
343 | * Implements state_t.get_state | |
344 | */ | |
345 | static ike_sa_state_t get_state(private_initiator_init_t *this) | |
346 | { | |
347 | return INITIATOR_INIT; | |
348 | } | |
349 | ||
350 | /** | |
351 | * Implements state_t.get_state | |
352 | */ | |
d048df5c | 353 | static void destroy(private_initiator_init_t *this) |
c7dd2a7b MW |
354 | { |
355 | this->logger->log(this->logger, CONTROL | MORE, "Going to destroy initiator_init_t state object"); | |
356 | ||
357 | /* destroy stored proposal */ | |
358 | this->logger->log(this->logger, CONTROL | MOST, "Destroy stored proposals"); | |
a9428251 | 359 | |
c7dd2a7b MW |
360 | /* destroy diffie hellman object */ |
361 | if (this->diffie_hellman != NULL) | |
362 | { | |
363 | this->logger->log(this->logger, CONTROL | MOST, "Destroy diffie_hellman_t object"); | |
364 | this->diffie_hellman->destroy(this->diffie_hellman); | |
365 | } | |
366 | if (this->sent_nonce.ptr != NULL) | |
367 | { | |
368 | this->logger->log(this->logger, CONTROL | MOST, "Free memory of sent nonce"); | |
369 | allocator_free(this->sent_nonce.ptr); | |
370 | } | |
c7dd2a7b | 371 | allocator_free(this); |
c7dd2a7b MW |
372 | } |
373 | ||
374 | /** | |
375 | * Implements private_initiator_init_t.destroy_after_state_change | |
376 | */ | |
d048df5c | 377 | static void destroy_after_state_change (private_initiator_init_t *this) |
c7dd2a7b MW |
378 | { |
379 | this->logger->log(this->logger, CONTROL | MORE, "Going to destroy initiator_init_t state object"); | |
380 | ||
381 | /* destroy stored proposal */ | |
382 | this->logger->log(this->logger, CONTROL | MOST, "Destroy stored proposals"); | |
c7dd2a7b | 383 | allocator_free(this); |
c7dd2a7b MW |
384 | } |
385 | ||
386 | /* | |
387 | * Described in header. | |
388 | */ | |
389 | initiator_init_t *initiator_init_create(protected_ike_sa_t *ike_sa) | |
390 | { | |
391 | private_initiator_init_t *this = allocator_alloc_thing(private_initiator_init_t); | |
c7dd2a7b MW |
392 | |
393 | /* interface functions */ | |
aad398a7 | 394 | this->public.state_interface.process_message = (status_t (*) (state_t *,message_t *)) process_message; |
c7dd2a7b | 395 | this->public.state_interface.get_state = (ike_sa_state_t (*) (state_t *)) get_state; |
d048df5c | 396 | this->public.state_interface.destroy = (void (*) (state_t *)) destroy; |
c7dd2a7b MW |
397 | |
398 | /* public functions */ | |
aad398a7 | 399 | this->public.initiate_connection = (status_t (*)(initiator_init_t *, char *)) initiate_connection; |
2848a7ba | 400 | this->public.retry_initiate_connection = (status_t (*)(initiator_init_t *, int )) retry_initiate_connection; |
c7dd2a7b MW |
401 | |
402 | /* private functions */ | |
403 | this->destroy_after_state_change = destroy_after_state_change; | |
404 | this->build_ike_sa_init_request = build_ike_sa_init_request; | |
405 | this->build_nonce_payload = build_nonce_payload; | |
406 | this->build_sa_payload = build_sa_payload; | |
407 | this->build_ke_payload = build_ke_payload; | |
408 | ||
409 | /* private data */ | |
410 | this->ike_sa = ike_sa; | |
411 | this->dh_group_priority = 1; | |
aad398a7 | 412 | this->logger = this->ike_sa->get_logger(this->ike_sa); |
c7dd2a7b | 413 | this->sent_nonce = CHUNK_INITIALIZER; |
d048df5c | 414 | |
c7dd2a7b MW |
415 | return &(this->public); |
416 | } |