]> git.ipfire.org Git - thirdparty/strongswan.git/blob - src/libcharon/sa/ikev1/tasks/isakmp_natd.c
Add a return value to hasher_t.allocate_hash()
[thirdparty/strongswan.git] / src / libcharon / sa / ikev1 / tasks / isakmp_natd.c
1 /*
2 * Copyright (C) 2006-2011 Tobias Brunner,
3 * Copyright (C) 2006-2007 Martin Willi
4 * Copyright (C) 2006 Daniel Roethlisberger
5 * Hochschule fuer Technik Rapperswil
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 */
17
18 #include "isakmp_natd.h"
19
20 #include <string.h>
21
22 #include <hydra.h>
23 #include <daemon.h>
24 #include <sa/ikev1/keymat_v1.h>
25 #include <config/peer_cfg.h>
26 #include <crypto/hashers/hasher.h>
27 #include <encoding/payloads/hash_payload.h>
28
29 typedef struct private_isakmp_natd_t private_isakmp_natd_t;
30
31 /**
32 * Private members of a ike_natt_t task.
33 */
34 struct private_isakmp_natd_t {
35
36 /**
37 * Public interface.
38 */
39 isakmp_natd_t public;
40
41 /**
42 * Assigned IKE_SA.
43 */
44 ike_sa_t *ike_sa;
45
46 /**
47 * Are we the initiator?
48 */
49 bool initiator;
50
51 /**
52 * Keymat derivation (from SA)
53 */
54 keymat_v1_t *keymat;
55
56 /**
57 * Did we process any NAT detection payloads for a source address?
58 */
59 bool src_seen;
60
61 /**
62 * Did we process any NAT detection payloads for a destination address?
63 */
64 bool dst_seen;
65
66 /**
67 * Have we found a matching source address NAT hash?
68 */
69 bool src_matched;
70
71 /**
72 * Have we found a matching destination address NAT hash?
73 */
74 bool dst_matched;
75 };
76
77 /**
78 * Build NAT detection hash for a host.
79 */
80 static chunk_t generate_natd_hash(private_isakmp_natd_t *this,
81 ike_sa_id_t *ike_sa_id, host_t *host)
82 {
83 hasher_t *hasher;
84 chunk_t natd_chunk, natd_hash;
85 u_int64_t spi_i, spi_r;
86 u_int16_t port;
87
88 hasher = this->keymat->get_hasher(this->keymat);
89 if (!hasher)
90 {
91 DBG1(DBG_IKE, "no hasher available to build NAT-D payload");
92 return chunk_empty;
93 }
94
95 spi_i = ike_sa_id->get_initiator_spi(ike_sa_id);
96 spi_r = ike_sa_id->get_responder_spi(ike_sa_id);
97 port = htons(host->get_port(host));
98
99 /* natd_hash = HASH(CKY-I | CKY-R | IP | Port) */
100 natd_chunk = chunk_cata("cccc", chunk_from_thing(spi_i),
101 chunk_from_thing(spi_r), host->get_address(host),
102 chunk_from_thing(port));
103 if (!hasher->allocate_hash(hasher, natd_chunk, &natd_hash))
104 {
105 DBG1(DBG_IKE, "creating NAT-D payload hash failed");
106 return chunk_empty;
107 }
108 DBG3(DBG_IKE, "natd_chunk %B", &natd_chunk);
109 DBG3(DBG_IKE, "natd_hash %B", &natd_hash);
110
111 return natd_hash;
112 }
113
114 /**
115 * Build a faked NAT-D payload to enforce UDP encapsulation.
116 */
117 static chunk_t generate_natd_hash_faked(private_isakmp_natd_t *this)
118 {
119 hasher_t *hasher;
120 chunk_t chunk;
121 rng_t *rng;
122
123 hasher = this->keymat->get_hasher(this->keymat);
124 if (!hasher)
125 {
126 DBG1(DBG_IKE, "no hasher available to build NAT-D payload");
127 return chunk_empty;
128 }
129 rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
130 if (!rng ||
131 !rng->allocate_bytes(rng, hasher->get_hash_size(hasher), &chunk))
132 {
133 DBG1(DBG_IKE, "unable to get random bytes for NAT-D fake");
134 DESTROY_IF(rng);
135 return chunk_empty;
136 }
137 rng->destroy(rng);
138 return chunk;
139 }
140
141 /**
142 * Build a NAT-D payload.
143 */
144 static hash_payload_t *build_natd_payload(private_isakmp_natd_t *this, bool src,
145 host_t *host)
146 {
147 hash_payload_t *payload;
148 ike_cfg_t *config;
149 chunk_t hash;
150
151 config = this->ike_sa->get_ike_cfg(this->ike_sa);
152 if (src && config->force_encap(config))
153 {
154 hash = generate_natd_hash_faked(this);
155 }
156 else
157 {
158 ike_sa_id_t *ike_sa_id = this->ike_sa->get_id(this->ike_sa);
159 hash = generate_natd_hash(this, ike_sa_id, host);
160 }
161 if (!hash.len)
162 {
163 return NULL;
164 }
165 payload = hash_payload_create(NAT_D_V1);
166 payload->set_hash(payload, hash);
167 chunk_free(&hash);
168 return payload;
169 }
170
171 /**
172 * Add NAT-D payloads to the message.
173 */
174 static void add_natd_payloads(private_isakmp_natd_t *this, message_t *message)
175 {
176 hash_payload_t *payload;
177 host_t *host;
178
179 /* destination has to be added first */
180 host = message->get_destination(message);
181 payload = build_natd_payload(this, FALSE, host);
182 if (payload)
183 {
184 message->add_payload(message, (payload_t*)payload);
185 }
186
187 /* source is added second, compared with IKEv2 we always know the source,
188 * as these payloads are added in the second Phase 1 exchange or the
189 * response to the first */
190 host = message->get_source(message);
191 payload = build_natd_payload(this, TRUE, host);
192 if (payload)
193 {
194 message->add_payload(message, (payload_t*)payload);
195 }
196 }
197
198 /**
199 * Read NAT-D payloads from message and evaluate them.
200 */
201 static void process_payloads(private_isakmp_natd_t *this, message_t *message)
202 {
203 enumerator_t *enumerator;
204 payload_t *payload;
205 hash_payload_t *hash_payload;
206 chunk_t hash, src_hash, dst_hash;
207 ike_sa_id_t *ike_sa_id;
208 host_t *me, *other;
209 ike_cfg_t *config;
210
211 /* precompute hashes for incoming NAT-D comparison */
212 ike_sa_id = message->get_ike_sa_id(message);
213 me = message->get_destination(message);
214 other = message->get_source(message);
215 dst_hash = generate_natd_hash(this, ike_sa_id, me);
216 src_hash = generate_natd_hash(this, ike_sa_id, other);
217
218 DBG3(DBG_IKE, "precalculated src_hash %B", &src_hash);
219 DBG3(DBG_IKE, "precalculated dst_hash %B", &dst_hash);
220
221 enumerator = message->create_payload_enumerator(message);
222 while (enumerator->enumerate(enumerator, &payload))
223 {
224 if (payload->get_type(payload) != NAT_D_V1)
225 {
226 continue;
227 }
228 hash_payload = (hash_payload_t*)payload;
229 if (!this->dst_seen)
230 { /* the first NAT-D payload contains the destination hash */
231 this->dst_seen = TRUE;
232 hash = hash_payload->get_hash(hash_payload);
233 DBG3(DBG_IKE, "received dst_hash %B", &hash);
234 if (chunk_equals(hash, dst_hash))
235 {
236 this->dst_matched = TRUE;
237 }
238 continue;
239 }
240 /* the other NAT-D payloads contain source hashes */
241 this->src_seen = TRUE;
242 if (!this->src_matched)
243 {
244 hash = hash_payload->get_hash(hash_payload);
245 DBG3(DBG_IKE, "received src_hash %B", &hash);
246 if (chunk_equals(hash, src_hash))
247 {
248 this->src_matched = TRUE;
249 }
250 }
251 }
252 enumerator->destroy(enumerator);
253
254 chunk_free(&src_hash);
255 chunk_free(&dst_hash);
256
257 if (this->src_seen && this->dst_seen)
258 {
259 this->ike_sa->set_condition(this->ike_sa, COND_NAT_HERE,
260 !this->dst_matched);
261 this->ike_sa->set_condition(this->ike_sa, COND_NAT_THERE,
262 !this->src_matched);
263 config = this->ike_sa->get_ike_cfg(this->ike_sa);
264 if (this->dst_matched && this->src_matched &&
265 config->force_encap(config))
266 {
267 this->ike_sa->set_condition(this->ike_sa, COND_NAT_FAKE, TRUE);
268 }
269 }
270 }
271
272 METHOD(task_t, build_i, status_t,
273 private_isakmp_natd_t *this, message_t *message)
274 {
275 status_t result = NEED_MORE;
276
277 switch (message->get_exchange_type(message))
278 {
279 case AGGRESSIVE:
280 { /* add NAT-D payloads to the second request, already processed
281 * those by the responder contained in the first response */
282 result = SUCCESS;
283 /* fall */
284 }
285 case ID_PROT:
286 { /* add NAT-D payloads to the second request, need to process
287 * those by the responder contained in the second response */
288 if (message->get_payload(message, SECURITY_ASSOCIATION_V1))
289 { /* wait for the second exchange */
290 return NEED_MORE;
291 }
292 add_natd_payloads(this, message);
293 return result;
294 }
295 default:
296 break;
297 }
298 return SUCCESS;
299 }
300
301 METHOD(task_t, process_i, status_t,
302 private_isakmp_natd_t *this, message_t *message)
303 {
304 status_t result = NEED_MORE;
305
306 if (!this->ike_sa->supports_extension(this->ike_sa, EXT_NATT))
307 { /* we didn't receive VIDs inidcating support for NAT-T */
308 return SUCCESS;
309 }
310
311 switch (message->get_exchange_type(message))
312 {
313 case ID_PROT:
314 { /* process NAT-D payloads in the second response, added them in the
315 * second request already, so we're done afterwards */
316 if (message->get_payload(message, SECURITY_ASSOCIATION_V1))
317 { /* wait for the second exchange */
318 return NEED_MORE;
319 }
320 result = SUCCESS;
321 /* fall */
322 }
323 case AGGRESSIVE:
324 { /* process NAT-D payloads in the first response, add them in the
325 * following second request */
326 process_payloads(this, message);
327
328 if (this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY))
329 {
330 this->ike_sa->float_ports(this->ike_sa);
331 }
332 return result;
333 }
334 default:
335 break;
336 }
337 return SUCCESS;
338 }
339
340 METHOD(task_t, process_r, status_t,
341 private_isakmp_natd_t *this, message_t *message)
342 {
343 status_t result = NEED_MORE;
344
345 if (!this->ike_sa->supports_extension(this->ike_sa, EXT_NATT))
346 { /* we didn't receive VIDs indicating NAT-T support */
347 return SUCCESS;
348 }
349
350 switch (message->get_exchange_type(message))
351 {
352 case AGGRESSIVE:
353 { /* proccess NAT-D payloads in the second request, already added ours
354 * in the first response */
355 result = SUCCESS;
356 /* fall */
357 }
358 case ID_PROT:
359 { /* process NAT-D payloads in the second request, need to add ours
360 * to the second response */
361 if (message->get_payload(message, SECURITY_ASSOCIATION_V1))
362 { /* wait for the second exchange */
363 return NEED_MORE;
364 }
365 process_payloads(this, message);
366 return result;
367 }
368 default:
369 break;
370 }
371 return SUCCESS;
372 }
373
374 METHOD(task_t, build_r, status_t,
375 private_isakmp_natd_t *this, message_t *message)
376 {
377 switch (message->get_exchange_type(message))
378 {
379 case ID_PROT:
380 { /* add NAT-D payloads to second response, already processed those
381 * contained in the second request */
382 if (message->get_payload(message, SECURITY_ASSOCIATION_V1))
383 { /* wait for the second exchange */
384 return NEED_MORE;
385 }
386 add_natd_payloads(this, message);
387 return SUCCESS;
388 }
389 case AGGRESSIVE:
390 { /* add NAT-D payloads to the first response, process those contained
391 * in the following second request */
392 add_natd_payloads(this, message);
393 return NEED_MORE;
394 }
395 default:
396 break;
397 }
398 return SUCCESS;
399 }
400
401 METHOD(task_t, get_type, task_type_t,
402 private_isakmp_natd_t *this)
403 {
404 return TASK_ISAKMP_NATD;
405 }
406
407 METHOD(task_t, migrate, void,
408 private_isakmp_natd_t *this, ike_sa_t *ike_sa)
409 {
410 this->ike_sa = ike_sa;
411 this->keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa);
412 this->src_seen = FALSE;
413 this->dst_seen = FALSE;
414 this->src_matched = FALSE;
415 this->dst_matched = FALSE;
416 }
417
418 METHOD(task_t, destroy, void,
419 private_isakmp_natd_t *this)
420 {
421 free(this);
422 }
423
424 /*
425 * Described in header.
426 */
427 isakmp_natd_t *isakmp_natd_create(ike_sa_t *ike_sa, bool initiator)
428 {
429 private_isakmp_natd_t *this;
430
431 INIT(this,
432 .public = {
433 .task = {
434 .get_type = _get_type,
435 .migrate = _migrate,
436 .destroy = _destroy,
437 },
438 },
439 .ike_sa = ike_sa,
440 .keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa),
441 .initiator = initiator,
442 );
443
444 if (initiator)
445 {
446 this->public.task.build = _build_i;
447 this->public.task.process = _process_i;
448 }
449 else
450 {
451 this->public.task.build = _build_r;
452 this->public.task.process = _process_r;
453 }
454
455 return &this->public;
456 }