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
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>.
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
22 #include "notify_payload.h"
25 #include <encoding/payloads/encodings.h>
26 #include <crypto/hashers/hasher.h>
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
,
32 "INVALID_MAJOR_VERSION");
33 ENUM_NEXT(notify_type_names
, INVALID_SYNTAX
, INVALID_SYNTAX
, INVALID_MAJOR_VERSION
,
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
,
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",
48 "INTERNAL_ADDRESS_FAILURE",
52 "UNACCEPTABLE_ADDRESSES",
53 "UNEXPECTED_NAT_DETECTED",
56 "CHILD_SA_NOT_FOUND");
57 ENUM_NEXT(notify_type_names
, ME_CONNECT_FAILED
, ME_CONNECT_FAILED
, CHILD_SA_NOT_FOUND
,
59 ENUM_NEXT(notify_type_names
, MS_NOTIFY_STATUS
, MS_NOTIFY_STATUS
, ME_CONNECT_FAILED
,
61 ENUM_NEXT(notify_type_names
, INITIAL_CONTACT
, IPSEC_REPLAY_COUNTER_SYNC
, MS_NOTIFY_STATUS
,
64 "ADDITIONAL_TS_POSSIBLE",
66 "NAT_DETECTION_SOURCE_IP",
67 "NAT_DETECTION_DESTINATION_IP",
70 "HTTP_CERT_LOOKUP_SUPPORTED",
72 "ESP_TFC_PADDING_NOT_SUPPORTED",
73 "NON_FIRST_FRAGMENTS_ALSO",
75 "ADDITIONAL_IP4_ADDRESS",
76 "ADDITIONAL_IP6_ADDRESS",
77 "NO_ADDITIONAL_ADDRESSES",
78 "UPDATE_SA_ADDRESSES",
82 "MULTIPLE_AUTH_SUPPORTED",
83 "ANOTHER_AUTH_FOLLOWS",
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
,
104 ENUM_NEXT(notify_type_names
, ME_MEDIATION
, ME_RESPONSE
, USE_BEET_MODE
,
112 ENUM_END(notify_type_names
, ME_RESPONSE
);
115 ENUM_BEGIN(notify_type_short_names
, UNSUPPORTED_CRITICAL_PAYLOAD
, UNSUPPORTED_CRITICAL_PAYLOAD
,
117 ENUM_NEXT(notify_type_short_names
, INVALID_IKE_SPI
, INVALID_MAJOR_VERSION
, UNSUPPORTED_CRITICAL_PAYLOAD
,
120 ENUM_NEXT(notify_type_short_names
, INVALID_SYNTAX
, INVALID_SYNTAX
, INVALID_MAJOR_VERSION
,
122 ENUM_NEXT(notify_type_short_names
, INVALID_MESSAGE_ID
, INVALID_MESSAGE_ID
, INVALID_SYNTAX
,
124 ENUM_NEXT(notify_type_short_names
, INVALID_SPI
, INVALID_SPI
, INVALID_MESSAGE_ID
,
126 ENUM_NEXT(notify_type_short_names
, NO_PROPOSAL_CHOSEN
, NO_PROPOSAL_CHOSEN
, INVALID_SPI
,
128 ENUM_NEXT(notify_type_short_names
, INVALID_KE_PAYLOAD
, INVALID_KE_PAYLOAD
, NO_PROPOSAL_CHOSEN
,
130 ENUM_NEXT(notify_type_short_names
, AUTHENTICATION_FAILED
, AUTHENTICATION_FAILED
, INVALID_KE_PAYLOAD
,
132 ENUM_NEXT(notify_type_short_names
, SINGLE_PAIR_REQUIRED
, CHILD_SA_NOT_FOUND
, AUTHENTICATION_FAILED
,
144 ENUM_NEXT(notify_type_short_names
, ME_CONNECT_FAILED
, ME_CONNECT_FAILED
, CHILD_SA_NOT_FOUND
,
146 ENUM_NEXT(notify_type_short_names
, MS_NOTIFY_STATUS
, MS_NOTIFY_STATUS
, ME_CONNECT_FAILED
,
148 ENUM_NEXT(notify_type_short_names
, INITIAL_CONTACT
, IPSEC_REPLAY_COUNTER_SYNC
, MS_NOTIFY_STATUS
,
189 ENUM_NEXT(notify_type_short_names
, USE_BEET_MODE
, USE_BEET_MODE
, IPSEC_REPLAY_COUNTER_SYNC
,
191 ENUM_NEXT(notify_type_short_names
, ME_MEDIATION
, ME_RESPONSE
, USE_BEET_MODE
,
199 ENUM_END(notify_type_short_names
, ME_RESPONSE
);
202 typedef struct private_notify_payload_t private_notify_payload_t
;
205 * Private data of an notify_payload_t object.
207 struct private_notify_payload_t
{
210 * Public notify_payload_t interface.
212 notify_payload_t
public;
217 u_int8_t next_payload
;
230 * Length of this payload.
232 u_int16_t payload_length
;
237 u_int8_t protocol_id
;
245 * Notify message type.
247 u_int16_t notify_type
;
250 * Security parameter index (spi).
257 chunk_t notification_data
;
261 * Encoding rules to parse or generate a IKEv2-Notify Payload.
263 * The defined offsets are the positions in a object of type
264 * private_notify_payload_t.
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
) }
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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
302 ~ Security Parameter Index (SPI) ~
304 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
306 ~ Notification Data ~
308 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
311 METHOD(payload_t
, verify
, status_t
,
312 private_notify_payload_t
*this)
314 bool bad_length
= FALSE
;
316 switch (this->protocol_id
)
324 DBG1(DBG_ENC
, "Unknown protocol (%d)", this->protocol_id
);
328 switch (this->notify_type
)
330 case INVALID_KE_PAYLOAD
:
332 if (this->notification_data
.len
!= 2)
338 case NAT_DETECTION_SOURCE_IP
:
339 case NAT_DETECTION_DESTINATION_IP
:
342 if (this->notification_data
.len
!= HASH_SIZE_SHA1
)
349 case INVALID_MAJOR_VERSION
:
350 case NO_PROPOSAL_CHOSEN
:
352 if (this->notification_data
.len
!= 0)
358 case ADDITIONAL_IP4_ADDRESS
:
360 if (this->notification_data
.len
!= 4)
366 case ADDITIONAL_IP6_ADDRESS
:
368 if (this->notification_data
.len
!= 16)
376 if (this->notification_data
.len
!= 4)
382 case IPCOMP_SUPPORTED
:
384 if (this->notification_data
.len
!= 3)
391 if (this->notification_data
.len
!= 8 &&
392 this->notification_data
.len
!= 12 &&
393 this->notification_data
.len
!= 24)
399 if (this->notification_data
.len
< 4 ||
400 this->notification_data
.len
> 16)
406 if (this->notification_data
.len
< 16 ||
407 this->notification_data
.len
> 32)
418 DBG1(DBG_ENC
, "invalid notify data length for %N (%d)",
419 notify_type_names
, this->notify_type
,
420 this->notification_data
.len
);
426 METHOD(payload_t
, get_encoding_rules
, void,
427 private_notify_payload_t
*this, encoding_rule_t
**rules
, size_t *rule_count
)
429 *rules
= notify_payload_encodings
;
430 *rule_count
= countof(notify_payload_encodings
);
433 METHOD(payload_t
, get_type
, payload_type_t
,
434 private_notify_payload_t
*this)
439 METHOD(payload_t
, get_next_type
, payload_type_t
,
440 private_notify_payload_t
*this)
442 return this->next_payload
;
445 METHOD(payload_t
, set_next_type
, void,
446 private_notify_payload_t
*this, payload_type_t type
)
448 this->next_payload
= type
;
452 * recompute the payloads length.
454 static void compute_length (private_notify_payload_t
*this)
456 size_t length
= NOTIFY_PAYLOAD_HEADER_LENGTH
;
458 if (this->notification_data
.ptr
!= NULL
)
460 length
+= this->notification_data
.len
;
462 if (this->spi
.ptr
!= NULL
)
464 length
+= this->spi
.len
;
466 this->payload_length
= length
;
469 METHOD(payload_t
, get_length
, size_t,
470 private_notify_payload_t
*this)
472 return this->payload_length
;
475 METHOD(notify_payload_t
, get_protocol_id
, u_int8_t
,
476 private_notify_payload_t
*this)
478 return this->protocol_id
;
481 METHOD(notify_payload_t
, set_protocol_id
, void,
482 private_notify_payload_t
*this, u_int8_t protocol_id
)
484 this->protocol_id
= protocol_id
;
487 METHOD(notify_payload_t
, get_notify_type
, notify_type_t
,
488 private_notify_payload_t
*this)
490 return this->notify_type
;
493 METHOD(notify_payload_t
, set_notify_type
, void,
494 private_notify_payload_t
*this, notify_type_t notify_type
)
496 this->notify_type
= notify_type
;
499 METHOD(notify_payload_t
, get_spi
, u_int32_t
,
500 private_notify_payload_t
*this)
502 switch (this->protocol_id
)
506 if (this->spi
.len
== 4)
508 return *((u_int32_t
*)this->spi
.ptr
);
516 METHOD(notify_payload_t
, set_spi
, void,
517 private_notify_payload_t
*this, u_int32_t spi
)
519 chunk_free(&this->spi
);
520 switch (this->protocol_id
)
524 this->spi
= chunk_alloc(4);
525 *((u_int32_t
*)this->spi
.ptr
) = spi
;
530 this->spi_size
= this->spi
.len
;
531 compute_length(this);
534 METHOD(notify_payload_t
, get_notification_data
, chunk_t
,
535 private_notify_payload_t
*this)
537 return this->notification_data
;
540 METHOD(notify_payload_t
, set_notification_data
, void,
541 private_notify_payload_t
*this, chunk_t data
)
543 free(this->notification_data
.ptr
);
544 this->notification_data
= chunk_clone(data
);
545 compute_length(this);
548 METHOD2(payload_t
, notify_payload_t
, destroy
, void,
549 private_notify_payload_t
*this)
551 free(this->notification_data
.ptr
);
557 * Described in header
559 notify_payload_t
*notify_payload_create()
561 private_notify_payload_t
*this;
565 .payload_interface
= {
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
,
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
,
580 .get_notification_data
= _get_notification_data
,
581 .set_notification_data
= _set_notification_data
,
584 .next_payload
= NO_PAYLOAD
,
585 .payload_length
= NOTIFY_PAYLOAD_HEADER_LENGTH
,
587 return &this->public;
591 * Described in header.
593 notify_payload_t
*notify_payload_create_from_protocol_and_type(
594 protocol_id_t protocol_id
, notify_type_t notify_type
)
596 notify_payload_t
*notify
= notify_payload_create();
598 notify
->set_notify_type(notify
, notify_type
);
599 notify
->set_protocol_id(notify
, protocol_id
);