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