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