]>
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> | |
5534ee84 | 29 | #include <queues/jobs/retransmit_request_job.h> |
68621281 | 30 | #include <crypto/diffie_hellman.h> |
c7dd2a7b MW |
31 | #include <encoding/payloads/sa_payload.h> |
32 | #include <encoding/payloads/ke_payload.h> | |
33 | #include <encoding/payloads/nonce_payload.h> | |
34 | ||
35 | ||
5796aa16 MW |
36 | typedef struct private_initiator_init_t private_initiator_init_t; |
37 | ||
c7dd2a7b | 38 | /** |
8c7824fb | 39 | * Private data of a initiator_init_t object.. |
c7dd2a7b MW |
40 | * |
41 | */ | |
5796aa16 | 42 | struct private_initiator_init_t { |
c7dd2a7b MW |
43 | /** |
44 | * Methods of the state_t interface. | |
45 | */ | |
46 | initiator_init_t public; | |
47 | ||
48 | /** | |
49 | * Assigned IKE_SA. | |
50 | */ | |
51 | protected_ike_sa_t *ike_sa; | |
52 | ||
53 | /** | |
54 | * Diffie hellman object used to generate public DH value. | |
d94f63f6 | 55 | * This objet is passed to the next state of type IKE_SA_INIT_REQUESTED. |
c7dd2a7b MW |
56 | */ |
57 | diffie_hellman_t *diffie_hellman; | |
58 | ||
c7dd2a7b MW |
59 | /** |
60 | * Sent nonce. | |
d94f63f6 | 61 | * This nonce is passed to the next state of type IKE_SA_INIT_REQUESTED. |
c7dd2a7b MW |
62 | */ |
63 | chunk_t sent_nonce; | |
c7dd2a7b MW |
64 | |
65 | /** | |
d94f63f6 | 66 | * Assigned logger. |
c7dd2a7b MW |
67 | * |
68 | * Is logger of ike_sa! | |
69 | */ | |
70 | logger_t *logger; | |
71 | ||
c7dd2a7b MW |
72 | /** |
73 | * Builds the SA payload for this state. | |
74 | * | |
75 | * @param this calling object | |
d94f63f6 | 76 | * @param request message_t object to add the SA payload |
c7dd2a7b | 77 | */ |
d94f63f6 | 78 | void (*build_sa_payload) (private_initiator_init_t *this, message_t *request); |
c7dd2a7b MW |
79 | |
80 | /** | |
81 | * Builds the KE payload for this state. | |
82 | * | |
83 | * @param this calling object | |
d94f63f6 | 84 | * @param request message_t object to add the KE payload |
c7dd2a7b | 85 | */ |
d94f63f6 | 86 | void (*build_ke_payload) (private_initiator_init_t *this, message_t *request); |
d048df5c | 87 | |
c7dd2a7b MW |
88 | /** |
89 | * Builds the NONCE payload for this state. | |
90 | * | |
91 | * @param this calling object | |
d94f63f6 | 92 | * @param request message_t object to add the NONCE payload |
c7dd2a7b | 93 | */ |
68621281 | 94 | status_t (*build_nonce_payload) (private_initiator_init_t *this,message_t *request); |
c7dd2a7b MW |
95 | |
96 | /** | |
f6ba78c3 JH |
97 | * Destroy function called internally of this class after state change to state |
98 | * IKE_SA_INIT_REQUESTED succeeded. | |
c7dd2a7b MW |
99 | * |
100 | * This destroy function does not destroy objects which were passed to the new state. | |
101 | * | |
102 | * @param this calling object | |
c7dd2a7b | 103 | */ |
d048df5c | 104 | void (*destroy_after_state_change) (private_initiator_init_t *this); |
c7dd2a7b MW |
105 | }; |
106 | ||
107 | /** | |
2848a7ba | 108 | * Implementation of initiator_init_t.initiate_connection. |
c7dd2a7b | 109 | */ |
16b9a73c | 110 | static status_t initiate_connection (private_initiator_init_t *this, connection_t *connection) |
c7dd2a7b | 111 | { |
16b9a73c | 112 | policy_t *policy; |
ce461bbd | 113 | diffie_hellman_group_t dh_group; |
16b9a73c MW |
114 | host_t *my_host, *other_host; |
115 | identification_t *my_id, *other_id; | |
aad398a7 | 116 | |
16b9a73c MW |
117 | my_host = connection->get_my_host(connection); |
118 | other_host = connection->get_other_host(connection); | |
119 | my_id = connection->get_my_id(connection); | |
120 | other_id = connection->get_other_id(connection); | |
c7dd2a7b | 121 | |
16b9a73c MW |
122 | this->logger->log(this->logger, CONTROL, "Initiating connection between %s (%s) - %s (%s)", |
123 | my_id->get_string(my_id), my_host->get_address(my_host), | |
124 | other_id->get_string(other_id), other_host->get_address(other_host)); | |
125 | ||
126 | this->ike_sa->set_connection(this->ike_sa, connection); | |
127 | ||
128 | /* get policy */ | |
129 | policy = charon->policies->get_policy(charon->policies, my_id, other_id); | |
130 | if (policy == NULL) | |
ce461bbd | 131 | { |
16b9a73c MW |
132 | this->logger->log(this->logger, ERROR | LEVEL1, "Could not get a policy for '%s - %s', aborting", |
133 | my_id->get_string(my_id), other_id->get_string(other_id)); | |
ae3012a0 | 134 | return DELETE_ME; |
1b3f92d2 | 135 | } |
16b9a73c | 136 | this->ike_sa->set_policy(this->ike_sa,policy); |
a9428251 | 137 | |
ce461bbd | 138 | /* we must guess now a DH group. For that we choose our most preferred group */ |
16b9a73c | 139 | dh_group = connection->get_dh_group(connection); |
0e96f7d8 | 140 | |
2848a7ba | 141 | /* next step is done in retry_initiate_connection */ |
16b9a73c | 142 | return this->public.retry_initiate_connection(&this->public, dh_group); |
2848a7ba JH |
143 | } |
144 | ||
145 | /** | |
146 | * Implementation of initiator_init_t.retry_initiate_connection. | |
147 | */ | |
ce461bbd | 148 | status_t retry_initiate_connection (private_initiator_init_t *this, diffie_hellman_group_t dh_group) |
2848a7ba JH |
149 | { |
150 | ike_sa_init_requested_t *next_state; | |
8d68033e | 151 | chunk_t ike_sa_init_request_data; |
16b9a73c | 152 | connection_t *connection; |
8d68033e | 153 | ike_sa_id_t *ike_sa_id; |
2848a7ba | 154 | message_t *message; |
2848a7ba | 155 | status_t status; |
ae3012a0 | 156 | |
ce461bbd | 157 | if (dh_group == MODP_UNDEFINED) |
c7dd2a7b | 158 | { |
ce461bbd | 159 | this->logger->log(this->logger, AUDIT, "No DH group acceptable for initialization, Aborting"); |
ae3012a0 | 160 | return DELETE_ME; |
c7dd2a7b | 161 | } |
2848a7ba | 162 | |
16b9a73c | 163 | connection = this->ike_sa->get_connection(this->ike_sa); |
ce461bbd MW |
164 | this->diffie_hellman = diffie_hellman_create(dh_group); |
165 | ike_sa_id = this->ike_sa->public.get_id(&(this->ike_sa->public)); | |
166 | ike_sa_id->set_responder_spi(ike_sa_id,0); | |
c7dd2a7b | 167 | |
d94f63f6 | 168 | /* going to build message */ |
aee3eb52 | 169 | this->logger->log(this->logger, CONTROL|LEVEL2, "Going to build message"); |
d94f63f6 JH |
170 | this->ike_sa->build_message(this->ike_sa, IKE_SA_INIT, TRUE, &message); |
171 | ||
172 | /* build SA payload */ | |
173 | this->build_sa_payload(this, message); | |
5534ee84 | 174 | |
d94f63f6 JH |
175 | /* build KE payload */ |
176 | this->build_ke_payload(this, message); | |
5534ee84 | 177 | |
d94f63f6 | 178 | /* build Nonce payload */ |
68621281 MW |
179 | status = this->build_nonce_payload(this, message); |
180 | if (status != SUCCESS) | |
181 | { | |
182 | this->logger->log(this->logger, ERROR, "Building nonce payload failed. Aborting"); | |
183 | message->destroy(message); | |
184 | return DELETE_ME; | |
185 | } | |
186 | ||
5534ee84 JH |
187 | /* message can now be sent (must not be destroyed) */ |
188 | status = this->ike_sa->send_request(this->ike_sa, message); | |
c7dd2a7b MW |
189 | if (status != SUCCESS) |
190 | { | |
5346c894 | 191 | this->logger->log(this->logger, AUDIT, "Unable to initiate connection, could not send message. Aborting"); |
c7dd2a7b | 192 | message->destroy(message); |
ae3012a0 | 193 | return DELETE_ME; |
c7dd2a7b | 194 | } |
8d68033e JH |
195 | |
196 | message = this->ike_sa->get_last_requested_message(this->ike_sa); | |
197 | ||
198 | ike_sa_init_request_data = message->get_packet_data(message); | |
c7dd2a7b MW |
199 | |
200 | /* state can now be changed */ | |
aee3eb52 | 201 | this->logger->log(this->logger, CONTROL|LEVEL2, "Create next state object"); |
ce461bbd | 202 | next_state = ike_sa_init_requested_create(this->ike_sa, this->diffie_hellman, this->sent_nonce,ike_sa_init_request_data); |
aad398a7 | 203 | this->ike_sa->set_new_state(this->ike_sa,(state_t *) next_state); |
5534ee84 | 204 | |
aee3eb52 | 205 | this->logger->log(this->logger, CONTROL|LEVEL2, "Destroy old sate object"); |
c7dd2a7b | 206 | this->destroy_after_state_change(this); |
c7dd2a7b MW |
207 | return SUCCESS; |
208 | } | |
209 | ||
210 | /** | |
d94f63f6 | 211 | * Implementation of private_initiator_init_t.build_sa_payload. |
c7dd2a7b | 212 | */ |
d94f63f6 | 213 | static void build_sa_payload(private_initiator_init_t *this, message_t *request) |
c7dd2a7b MW |
214 | { |
215 | sa_payload_t* sa_payload; | |
ce461bbd | 216 | linked_list_t *proposal_list; |
16b9a73c | 217 | connection_t *connection; |
c7dd2a7b | 218 | |
aee3eb52 | 219 | this->logger->log(this->logger, CONTROL|LEVEL1, "Building SA payload"); |
c7dd2a7b | 220 | |
16b9a73c | 221 | connection = this->ike_sa->get_connection(this->ike_sa); |
c7dd2a7b | 222 | |
16b9a73c | 223 | proposal_list = connection->get_proposals(connection); |
c7dd2a7b | 224 | |
ce461bbd | 225 | sa_payload = sa_payload_create_from_proposal_list(proposal_list); |
d94f63f6 | 226 | |
aee3eb52 | 227 | this->logger->log(this->logger, CONTROL|LEVEL2, "Add SA payload to message"); |
d94f63f6 | 228 | request->add_payload(request, (payload_t *) sa_payload); |
c7dd2a7b MW |
229 | } |
230 | ||
231 | /** | |
d94f63f6 | 232 | * Implementation of private_initiator_init_t.build_ke_payload. |
c7dd2a7b | 233 | */ |
d94f63f6 | 234 | static void build_ke_payload(private_initiator_init_t *this, message_t *request) |
c7dd2a7b MW |
235 | { |
236 | ke_payload_t *ke_payload; | |
237 | chunk_t key_data; | |
ce461bbd | 238 | diffie_hellman_group_t dh_group; |
d048df5c | 239 | |
aee3eb52 | 240 | this->logger->log(this->logger, CONTROL|LEVEL1, "Building KE payload"); |
c7dd2a7b | 241 | |
d048df5c | 242 | this->diffie_hellman->get_my_public_value(this->diffie_hellman,&key_data); |
ce461bbd | 243 | dh_group = this->diffie_hellman->get_dh_group(this->diffie_hellman); |
c7dd2a7b MW |
244 | |
245 | ke_payload = ke_payload_create(); | |
ce461bbd | 246 | ke_payload->set_dh_group_number(ke_payload, dh_group); |
d048df5c | 247 | ke_payload->set_key_exchange_data(ke_payload, key_data); |
c7dd2a7b | 248 | |
5113680f | 249 | chunk_free(&key_data); |
d94f63f6 | 250 | |
aee3eb52 | 251 | this->logger->log(this->logger, CONTROL|LEVEL2, "Add KE payload to message"); |
d94f63f6 | 252 | request->add_payload(request, (payload_t *) ke_payload); |
c7dd2a7b MW |
253 | } |
254 | ||
255 | /** | |
d94f63f6 | 256 | * Implementation of private_initiator_init_t.build_nonce_payload. |
c7dd2a7b | 257 | */ |
68621281 | 258 | static status_t build_nonce_payload(private_initiator_init_t *this, message_t *request) |
c7dd2a7b MW |
259 | { |
260 | nonce_payload_t *nonce_payload; | |
d94f63f6 | 261 | randomizer_t *randomizer; |
68621281 | 262 | status_t status; |
d94f63f6 | 263 | |
aee3eb52 | 264 | this->logger->log(this->logger, CONTROL|LEVEL1, "Building NONCE payload"); |
d94f63f6 | 265 | |
aee3eb52 | 266 | this->logger->log(this->logger, CONTROL|LEVEL2, "Get pseudo random bytes for NONCE"); |
d94f63f6 | 267 | randomizer = this->ike_sa->get_randomizer(this->ike_sa); |
c7dd2a7b | 268 | |
68621281 MW |
269 | status = randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_SIZE, &(this->sent_nonce)); |
270 | if (status != SUCCESS) | |
271 | { | |
272 | return status; | |
273 | } | |
d94f63f6 | 274 | |
aee3eb52 | 275 | this->logger->log(this->logger, RAW|LEVEL2, "Initiator NONCE",&(this->sent_nonce)); |
c7dd2a7b | 276 | |
d048df5c | 277 | nonce_payload = nonce_payload_create(); |
c7dd2a7b | 278 | |
d048df5c | 279 | nonce_payload->set_nonce(nonce_payload, this->sent_nonce); |
c7dd2a7b | 280 | |
aee3eb52 | 281 | this->logger->log(this->logger, CONTROL|LEVEL2, "Add NONCE payload to message"); |
d94f63f6 | 282 | request->add_payload(request, (payload_t *) nonce_payload); |
68621281 | 283 | return SUCCESS; |
c7dd2a7b MW |
284 | } |
285 | ||
286 | /** | |
d94f63f6 | 287 | * Implementation of state_t.process_message. |
c7dd2a7b | 288 | */ |
ae3012a0 | 289 | static status_t process_message(private_initiator_init_t *this, message_t *message) |
c7dd2a7b | 290 | { |
b1953ccd | 291 | this->logger->log(this->logger, ERROR, "In state INITIATOR_INIT, no message is processed"); |
c7dd2a7b MW |
292 | return FAILED; |
293 | } | |
294 | ||
295 | /** | |
d94f63f6 | 296 | * Implementation of state_t.get_state. |
c7dd2a7b MW |
297 | */ |
298 | static ike_sa_state_t get_state(private_initiator_init_t *this) | |
299 | { | |
300 | return INITIATOR_INIT; | |
301 | } | |
302 | ||
303 | /** | |
d94f63f6 | 304 | * Implementation of state_t.destroy. |
c7dd2a7b | 305 | */ |
d048df5c | 306 | static void destroy(private_initiator_init_t *this) |
c7dd2a7b | 307 | { |
5346c894 | 308 | this->logger->log(this->logger, CONTROL | LEVEL3, "Going to destroy initiator_init_t state object"); |
c7dd2a7b | 309 | |
c7dd2a7b MW |
310 | /* destroy diffie hellman object */ |
311 | if (this->diffie_hellman != NULL) | |
312 | { | |
c7dd2a7b MW |
313 | this->diffie_hellman->destroy(this->diffie_hellman); |
314 | } | |
315 | if (this->sent_nonce.ptr != NULL) | |
316 | { | |
5113680f | 317 | free(this->sent_nonce.ptr); |
c7dd2a7b | 318 | } |
5113680f | 319 | free(this); |
c7dd2a7b MW |
320 | } |
321 | ||
322 | /** | |
d94f63f6 | 323 | * Implementation of private_initiator_init_t.destroy_after_state_change |
c7dd2a7b | 324 | */ |
d048df5c | 325 | static void destroy_after_state_change (private_initiator_init_t *this) |
c7dd2a7b | 326 | { |
5346c894 | 327 | this->logger->log(this->logger, CONTROL | LEVEL3, "Going to destroy initiator_init_t state object"); |
5113680f | 328 | free(this); |
c7dd2a7b MW |
329 | } |
330 | ||
331 | /* | |
332 | * Described in header. | |
333 | */ | |
334 | initiator_init_t *initiator_init_create(protected_ike_sa_t *ike_sa) | |
335 | { | |
5113680f | 336 | private_initiator_init_t *this = malloc_thing(private_initiator_init_t); |
c7dd2a7b MW |
337 | |
338 | /* interface functions */ | |
aad398a7 | 339 | this->public.state_interface.process_message = (status_t (*) (state_t *,message_t *)) process_message; |
c7dd2a7b | 340 | this->public.state_interface.get_state = (ike_sa_state_t (*) (state_t *)) get_state; |
d048df5c | 341 | this->public.state_interface.destroy = (void (*) (state_t *)) destroy; |
c7dd2a7b MW |
342 | |
343 | /* public functions */ | |
16b9a73c | 344 | this->public.initiate_connection = (status_t (*)(initiator_init_t *, connection_t*)) initiate_connection; |
2848a7ba | 345 | this->public.retry_initiate_connection = (status_t (*)(initiator_init_t *, int )) retry_initiate_connection; |
c7dd2a7b MW |
346 | |
347 | /* private functions */ | |
348 | this->destroy_after_state_change = destroy_after_state_change; | |
c7dd2a7b MW |
349 | this->build_nonce_payload = build_nonce_payload; |
350 | this->build_sa_payload = build_sa_payload; | |
351 | this->build_ke_payload = build_ke_payload; | |
352 | ||
353 | /* private data */ | |
354 | this->ike_sa = ike_sa; | |
5113680f | 355 | this->logger = logger_manager->get_logger(logger_manager, IKE_SA); |
c7dd2a7b | 356 | this->sent_nonce = CHUNK_INITIALIZER; |
d94f63f6 | 357 | this->diffie_hellman = NULL; |
d048df5c | 358 | |
c7dd2a7b MW |
359 | return &(this->public); |
360 | } |