fixed typo
[strongswan.git] / src / libcharon / encoding / payloads / notify_payload.c
1 /*
2 * Copyright (C) 2005-2010 Martin Willi
3 * Copyright (C) 2010 revosec AG
4 * Copyright (C) 2006-2008 Tobias Brunner
5 * Copyright (C) 2006 Daniel Roethlisberger
6 * Copyright (C) 2005 Jan Hutter
7 * Hochschule fuer Technik Rapperswil
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 * for more details.
18 */
19
20 #include <stddef.h>
21
22 #include "notify_payload.h"
23
24 #include <daemon.h>
25 #include <encoding/payloads/encodings.h>
26 #include <crypto/hashers/hasher.h>
27
28 ENUM_BEGIN(notify_type_names, UNSUPPORTED_CRITICAL_PAYLOAD, UNSUPPORTED_CRITICAL_PAYLOAD,
29 "UNSUPPORTED_CRITICAL_PAYLOAD");
30 ENUM_NEXT(notify_type_names, INVALID_IKE_SPI, INVALID_MAJOR_VERSION, UNSUPPORTED_CRITICAL_PAYLOAD,
31 "INVALID_IKE_SPI",
32 "INVALID_MAJOR_VERSION");
33 ENUM_NEXT(notify_type_names, INVALID_SYNTAX, INVALID_SYNTAX, INVALID_MAJOR_VERSION,
34 "INVALID_SYNTAX");
35 ENUM_NEXT(notify_type_names, INVALID_MESSAGE_ID, INVALID_MESSAGE_ID, INVALID_SYNTAX,
36 "INVALID_MESSAGE_ID");
37 ENUM_NEXT(notify_type_names, INVALID_SPI, INVALID_SPI, INVALID_MESSAGE_ID,
38 "INVALID_SPI");
39 ENUM_NEXT(notify_type_names, NO_PROPOSAL_CHOSEN, NO_PROPOSAL_CHOSEN, INVALID_SPI,
40 "NO_PROPOSAL_CHOSEN");
41 ENUM_NEXT(notify_type_names, INVALID_KE_PAYLOAD, INVALID_KE_PAYLOAD, NO_PROPOSAL_CHOSEN,
42 "INVALID_KE_PAYLOAD");
43 ENUM_NEXT(notify_type_names, AUTHENTICATION_FAILED, AUTHENTICATION_FAILED, INVALID_KE_PAYLOAD,
44 "AUTHENTICATION_FAILED");
45 ENUM_NEXT(notify_type_names, SINGLE_PAIR_REQUIRED, CHILD_SA_NOT_FOUND, AUTHENTICATION_FAILED,
46 "SINGLE_PAIR_REQUIRED",
47 "NO_ADDITIONAL_SAS",
48 "INTERNAL_ADDRESS_FAILURE",
49 "FAILED_CP_REQUIRED",
50 "TS_UNACCEPTABLE",
51 "INVALID_SELECTORS",
52 "UNACCEPTABLE_ADDRESSES",
53 "UNEXPECTED_NAT_DETECTED",
54 "USE_ASSIGNED_HoA",
55 "TEMPORARY_FAILURE",
56 "CHILD_SA_NOT_FOUND");
57 ENUM_NEXT(notify_type_names, ME_CONNECT_FAILED, ME_CONNECT_FAILED, CHILD_SA_NOT_FOUND,
58 "ME_CONNECT_FAILED");
59 ENUM_NEXT(notify_type_names, INITIAL_CONTACT, IPSEC_REPLAY_COUNTER_SYNC, ME_CONNECT_FAILED,
60 "INITIAL_CONTACT",
61 "SET_WINDOW_SIZE",
62 "ADDITIONAL_TS_POSSIBLE",
63 "IPCOMP_SUPPORTED",
64 "NAT_DETECTION_SOURCE_IP",
65 "NAT_DETECTION_DESTINATION_IP",
66 "COOKIE",
67 "USE_TRANSPORT_MODE",
68 "HTTP_CERT_LOOKUP_SUPPORTED",
69 "REKEY_SA",
70 "ESP_TFC_PADDING_NOT_SUPPORTED",
71 "NON_FIRST_FRAGMENTS_ALSO",
72 "MOBIKE_SUPPORTED",
73 "ADDITIONAL_IP4_ADDRESS",
74 "ADDITIONAL_IP6_ADDRESS",
75 "NO_ADDITIONAL_ADDRESSES",
76 "UPDATE_SA_ADDRESSES",
77 "COOKIE2",
78 "NO_NATS_ALLOWED",
79 "AUTH_LIFETIME",
80 "MULTIPLE_AUTH_SUPPORTED",
81 "ANOTHER_AUTH_FOLLOWS",
82 "REDIRECT_SUPPORTED",
83 "REDIRECT",
84 "REDIRECTED_FROM",
85 "TICKET_LT_OPAQUE",
86 "TICKET_REQUEST",
87 "TICKET_ACK",
88 "TICKET_NACK",
89 "TICKET_OPAQUE",
90 "LINK_ID",
91 "USE_WESP_MODE",
92 "ROHC_SUPPORTED",
93 "EAP_ONLY_AUTHENTICATION",
94 "CHILDLESS_IKEV2_SUPPORTED",
95 "QUICK_CRASH_DETECTION",
96 "IKEV2_MESSAGE_ID_SYNC_SUPPORTED",
97 "IKEV2_REPLAY_COUNTER_SYNC_SUPPORTED",
98 "IKEV2_MESSAGE_ID_SYNC",
99 "IPSEC_REPLAY_COUNTER_SYNC");
100 ENUM_NEXT(notify_type_names, USE_BEET_MODE, USE_BEET_MODE, IPSEC_REPLAY_COUNTER_SYNC,
101 "USE_BEET_MODE");
102 ENUM_NEXT(notify_type_names, ME_MEDIATION, ME_RESPONSE, USE_BEET_MODE,
103 "ME_MEDIATION",
104 "ME_ENDPOINT",
105 "ME_CALLBACK",
106 "ME_CONNECTID",
107 "ME_CONNECTKEY",
108 "ME_CONNECTAUTH",
109 "ME_RESPONSE");
110 ENUM_END(notify_type_names, ME_RESPONSE);
111
112
113 ENUM_BEGIN(notify_type_short_names, UNSUPPORTED_CRITICAL_PAYLOAD, UNSUPPORTED_CRITICAL_PAYLOAD,
114 "CRIT");
115 ENUM_NEXT(notify_type_short_names, INVALID_IKE_SPI, INVALID_MAJOR_VERSION, UNSUPPORTED_CRITICAL_PAYLOAD,
116 "INVAL_IKE_SPI",
117 "INVAL_MAJOR");
118 ENUM_NEXT(notify_type_short_names, INVALID_SYNTAX, INVALID_SYNTAX, INVALID_MAJOR_VERSION,
119 "INVAL_SYN");
120 ENUM_NEXT(notify_type_short_names, INVALID_MESSAGE_ID, INVALID_MESSAGE_ID, INVALID_SYNTAX,
121 "INVAL_MID");
122 ENUM_NEXT(notify_type_short_names, INVALID_SPI, INVALID_SPI, INVALID_MESSAGE_ID,
123 "INVAL_SPI");
124 ENUM_NEXT(notify_type_short_names, NO_PROPOSAL_CHOSEN, NO_PROPOSAL_CHOSEN, INVALID_SPI,
125 "NO_PROP");
126 ENUM_NEXT(notify_type_short_names, INVALID_KE_PAYLOAD, INVALID_KE_PAYLOAD, NO_PROPOSAL_CHOSEN,
127 "INVAL_KE");
128 ENUM_NEXT(notify_type_short_names, AUTHENTICATION_FAILED, AUTHENTICATION_FAILED, INVALID_KE_PAYLOAD,
129 "AUTH_FAILED");
130 ENUM_NEXT(notify_type_short_names, SINGLE_PAIR_REQUIRED, CHILD_SA_NOT_FOUND, AUTHENTICATION_FAILED,
131 "SINGLE_PAIR",
132 "NO_ADD_SAS",
133 "INT_ADDR_FAIL",
134 "FAIL_CP_REQ",
135 "TS_UNACCEPT",
136 "INVAL_SEL",
137 "UNACCEPT_ADDR",
138 "UNEXPECT_NAT",
139 "ASSIGNED_HoA",
140 "TEMP_FAIL",
141 "NO_CHILD_SA");
142 ENUM_NEXT(notify_type_short_names, ME_CONNECT_FAILED, ME_CONNECT_FAILED, CHILD_SA_NOT_FOUND,
143 "ME_CONN_FAIL");
144 ENUM_NEXT(notify_type_short_names, INITIAL_CONTACT, IPSEC_REPLAY_COUNTER_SYNC, ME_CONNECT_FAILED,
145 "INIT_CONTACT",
146 "SET_WINSIZE",
147 "ADD_TS_POSS",
148 "IPCOMP_SUP",
149 "NATD_S_IP",
150 "NATD_D_IP",
151 "COOKIE",
152 "USE_TRANSP",
153 "HTTP_CERT_LOOK",
154 "REKEY_SA",
155 "ESP_TFC_PAD_N",
156 "NON_FIRST_FRAG",
157 "MOBIKE_SUP",
158 "ADD_4_ADDR",
159 "ADD_6_ADDR",
160 "NO_ADD_ADDR",
161 "UPD_SA_ADDR",
162 "COOKIE2",
163 "NO_NATS",
164 "AUTH_LFT",
165 "MULT_AUTH",
166 "AUTH_FOLLOWS",
167 "REDIR_SUP",
168 "REDIR",
169 "REDIR_FROM",
170 "TKT_LT_OPAK",
171 "TKT_REQ",
172 "TKT_ACK",
173 "TKT_NACK",
174 "TKT_OPAK",
175 "LINK_ID",
176 "WESP_MODE",
177 "ROHC_SUP",
178 "EAP_ONLY",
179 "CHDLESS_SUP",
180 "CRASH_DET",
181 "MSG_ID_SYN_SUP",
182 "RPL_CTR_SYN_SUP",
183 "MSG_ID_SYN",
184 "RPL_CTR_SYN");
185 ENUM_NEXT(notify_type_short_names, USE_BEET_MODE, USE_BEET_MODE, IPSEC_REPLAY_COUNTER_SYNC,
186 "BEET_MODE");
187 ENUM_NEXT(notify_type_short_names, ME_MEDIATION, ME_RESPONSE, USE_BEET_MODE,
188 "ME_MED",
189 "ME_EP",
190 "ME_CB",
191 "ME_CID",
192 "ME_CKEY",
193 "ME_CAUTH",
194 "ME_R");
195 ENUM_END(notify_type_short_names, ME_RESPONSE);
196
197
198 typedef struct private_notify_payload_t private_notify_payload_t;
199
200 /**
201 * Private data of an notify_payload_t object.
202 */
203 struct private_notify_payload_t {
204
205 /**
206 * Public notify_payload_t interface.
207 */
208 notify_payload_t public;
209
210 /**
211 * Next payload type.
212 */
213 u_int8_t next_payload;
214
215 /**
216 * Critical flag.
217 */
218 bool critical;
219
220 /**
221 * reserved bits
222 */
223 bool reserved[7];
224
225 /**
226 * Length of this payload.
227 */
228 u_int16_t payload_length;
229
230 /**
231 * Protocol id.
232 */
233 u_int8_t protocol_id;
234
235 /**
236 * Spi size.
237 */
238 u_int8_t spi_size;
239
240 /**
241 * Notify message type.
242 */
243 u_int16_t notify_type;
244
245 /**
246 * Security parameter index (spi).
247 */
248 chunk_t spi;
249
250 /**
251 * Notification data.
252 */
253 chunk_t notification_data;
254 };
255
256 /**
257 * Encoding rules to parse or generate a IKEv2-Notify Payload.
258 *
259 * The defined offsets are the positions in a object of type
260 * private_notify_payload_t.
261 */
262 encoding_rule_t notify_payload_encodings[] = {
263 /* 1 Byte next payload type, stored in the field next_payload */
264 { U_INT_8, offsetof(private_notify_payload_t, next_payload) },
265 /* the critical bit */
266 { FLAG, offsetof(private_notify_payload_t, critical) },
267 /* 7 Bit reserved bits, nowhere stored */
268 { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[0]) },
269 { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[1]) },
270 { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[2]) },
271 { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[3]) },
272 { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[4]) },
273 { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[5]) },
274 { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[6]) },
275 /* Length of the whole payload*/
276 { PAYLOAD_LENGTH, offsetof(private_notify_payload_t, payload_length) },
277 /* Protocol ID as 8 bit field*/
278 { U_INT_8, offsetof(private_notify_payload_t, protocol_id) },
279 /* SPI Size as 8 bit field*/
280 { SPI_SIZE, offsetof(private_notify_payload_t, spi_size) },
281 /* Notify message type as 16 bit field*/
282 { U_INT_16, offsetof(private_notify_payload_t, notify_type) },
283 /* SPI as variable length field*/
284 { SPI, offsetof(private_notify_payload_t, spi) },
285 /* Key Exchange Data is from variable size */
286 { NOTIFICATION_DATA,offsetof(private_notify_payload_t, notification_data) }
287 };
288
289 /*
290 1 2 3
291 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
292 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
293 ! Next Payload !C! RESERVED ! Payload Length !
294 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
295 ! Protocol ID ! SPI Size ! Notify Message Type !
296 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
297 ! !
298 ~ Security Parameter Index (SPI) ~
299 ! !
300 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
301 ! !
302 ~ Notification Data ~
303 ! !
304 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
305 */
306
307 METHOD(payload_t, verify, status_t,
308 private_notify_payload_t *this)
309 {
310 bool bad_length = FALSE;
311
312 switch (this->protocol_id)
313 {
314 case PROTO_NONE:
315 case PROTO_IKE:
316 case PROTO_AH:
317 case PROTO_ESP:
318 break;
319 default:
320 DBG1(DBG_ENC, "Unknown protocol (%d)", this->protocol_id);
321 return FAILED;
322 }
323
324 switch (this->notify_type)
325 {
326 case INVALID_KE_PAYLOAD:
327 {
328 if (this->notification_data.len != 2)
329 {
330 bad_length = TRUE;
331 }
332 break;
333 }
334 case NAT_DETECTION_SOURCE_IP:
335 case NAT_DETECTION_DESTINATION_IP:
336 case ME_CONNECTAUTH:
337 {
338 if (this->notification_data.len != HASH_SIZE_SHA1)
339 {
340 bad_length = TRUE;
341 }
342 break;
343 }
344 case INVALID_SYNTAX:
345 case INVALID_MAJOR_VERSION:
346 case NO_PROPOSAL_CHOSEN:
347 {
348 if (this->notification_data.len != 0)
349 {
350 bad_length = TRUE;
351 }
352 break;
353 }
354 case ADDITIONAL_IP4_ADDRESS:
355 {
356 if (this->notification_data.len != 4)
357 {
358 bad_length = TRUE;
359 }
360 break;
361 }
362 case ADDITIONAL_IP6_ADDRESS:
363 {
364 if (this->notification_data.len != 16)
365 {
366 bad_length = TRUE;
367 }
368 break;
369 }
370 case AUTH_LIFETIME:
371 {
372 if (this->notification_data.len != 4)
373 {
374 bad_length = TRUE;
375 }
376 break;
377 }
378 case IPCOMP_SUPPORTED:
379 {
380 if (this->notification_data.len != 3)
381 {
382 bad_length = TRUE;
383 }
384 break;
385 }
386 case ME_ENDPOINT:
387 if (this->notification_data.len != 8 &&
388 this->notification_data.len != 12 &&
389 this->notification_data.len != 24)
390 {
391 bad_length = TRUE;
392 }
393 break;
394 case ME_CONNECTID:
395 if (this->notification_data.len < 4 ||
396 this->notification_data.len > 16)
397 {
398 bad_length = TRUE;
399 }
400 break;
401 case ME_CONNECTKEY:
402 if (this->notification_data.len < 16 ||
403 this->notification_data.len > 32)
404 {
405 bad_length = TRUE;
406 }
407 break;
408 default:
409 /* TODO: verify */
410 break;
411 }
412 if (bad_length)
413 {
414 DBG1(DBG_ENC, "invalid notify data length for %N (%d)",
415 notify_type_names, this->notify_type,
416 this->notification_data.len);
417 return FAILED;
418 }
419 return SUCCESS;
420 }
421
422 METHOD(payload_t, get_encoding_rules, void,
423 private_notify_payload_t *this, encoding_rule_t **rules, size_t *rule_count)
424 {
425 *rules = notify_payload_encodings;
426 *rule_count = countof(notify_payload_encodings);
427 }
428
429 METHOD(payload_t, get_type, payload_type_t,
430 private_notify_payload_t *this)
431 {
432 return NOTIFY;
433 }
434
435 METHOD(payload_t, get_next_type, payload_type_t,
436 private_notify_payload_t *this)
437 {
438 return this->next_payload;
439 }
440
441 METHOD(payload_t, set_next_type, void,
442 private_notify_payload_t *this, payload_type_t type)
443 {
444 this->next_payload = type;
445 }
446
447 /**
448 * recompute the payloads length.
449 */
450 static void compute_length (private_notify_payload_t *this)
451 {
452 size_t length = NOTIFY_PAYLOAD_HEADER_LENGTH;
453
454 if (this->notification_data.ptr != NULL)
455 {
456 length += this->notification_data.len;
457 }
458 if (this->spi.ptr != NULL)
459 {
460 length += this->spi.len;
461 }
462 this->payload_length = length;
463 }
464
465 METHOD(payload_t, get_length, size_t,
466 private_notify_payload_t *this)
467 {
468 return this->payload_length;
469 }
470
471 METHOD(notify_payload_t, get_protocol_id, u_int8_t,
472 private_notify_payload_t *this)
473 {
474 return this->protocol_id;
475 }
476
477 METHOD(notify_payload_t, set_protocol_id, void,
478 private_notify_payload_t *this, u_int8_t protocol_id)
479 {
480 this->protocol_id = protocol_id;
481 }
482
483 METHOD(notify_payload_t, get_notify_type, notify_type_t,
484 private_notify_payload_t *this)
485 {
486 return this->notify_type;
487 }
488
489 METHOD(notify_payload_t, set_notify_type, void,
490 private_notify_payload_t *this, notify_type_t notify_type)
491 {
492 this->notify_type = notify_type;
493 }
494
495 METHOD(notify_payload_t, get_spi, u_int32_t,
496 private_notify_payload_t *this)
497 {
498 switch (this->protocol_id)
499 {
500 case PROTO_AH:
501 case PROTO_ESP:
502 if (this->spi.len == 4)
503 {
504 return *((u_int32_t*)this->spi.ptr);
505 }
506 default:
507 break;
508 }
509 return 0;
510 }
511
512 METHOD(notify_payload_t, set_spi, void,
513 private_notify_payload_t *this, u_int32_t spi)
514 {
515 chunk_free(&this->spi);
516 switch (this->protocol_id)
517 {
518 case PROTO_AH:
519 case PROTO_ESP:
520 this->spi = chunk_alloc(4);
521 *((u_int32_t*)this->spi.ptr) = spi;
522 break;
523 default:
524 break;
525 }
526 this->spi_size = this->spi.len;
527 compute_length(this);
528 }
529
530 METHOD(notify_payload_t, get_notification_data, chunk_t,
531 private_notify_payload_t *this)
532 {
533 return this->notification_data;
534 }
535
536 METHOD(notify_payload_t, set_notification_data, void,
537 private_notify_payload_t *this, chunk_t data)
538 {
539 free(this->notification_data.ptr);
540 this->notification_data = chunk_clone(data);
541 compute_length(this);
542 }
543
544 METHOD2(payload_t, notify_payload_t, destroy, void,
545 private_notify_payload_t *this)
546 {
547 free(this->notification_data.ptr);
548 free(this->spi.ptr);
549 free(this);
550 }
551
552 /*
553 * Described in header
554 */
555 notify_payload_t *notify_payload_create()
556 {
557 private_notify_payload_t *this;
558
559 INIT(this,
560 .public = {
561 .payload_interface = {
562 .verify = _verify,
563 .get_encoding_rules = _get_encoding_rules,
564 .get_length = _get_length,
565 .get_next_type = _get_next_type,
566 .set_next_type = _set_next_type,
567 .get_type = _get_type,
568 .destroy = _destroy,
569 },
570 .get_protocol_id = _get_protocol_id,
571 .set_protocol_id = _set_protocol_id,
572 .get_notify_type = _get_notify_type,
573 .set_notify_type = _set_notify_type,
574 .get_spi = _get_spi,
575 .set_spi = _set_spi,
576 .get_notification_data = _get_notification_data,
577 .set_notification_data = _set_notification_data,
578 .destroy = _destroy,
579 },
580 .next_payload = NO_PAYLOAD,
581 .payload_length = NOTIFY_PAYLOAD_HEADER_LENGTH,
582 );
583 return &this->public;
584 }
585
586 /*
587 * Described in header.
588 */
589 notify_payload_t *notify_payload_create_from_protocol_and_type(
590 protocol_id_t protocol_id, notify_type_t notify_type)
591 {
592 notify_payload_t *notify = notify_payload_create();
593
594 notify->set_notify_type(notify, notify_type);
595 notify->set_protocol_id(notify, protocol_id);
596
597 return notify;
598 }