Moving charon to libcharon.

This commit is contained in:
Tobias Brunner
2010-03-19 13:34:52 +01:00
parent 7c11d10eb8
commit 08c5572602
480 changed files with 0 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
charon
+234
View File
@@ -0,0 +1,234 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# copy-n-paste from Makefile.am
LOCAL_SRC_FILES := \
bus/bus.c bus/bus.h \
bus/listeners/listener.h \
bus/listeners/file_logger.c bus/listeners/file_logger.h \
bus/listeners/sys_logger.c bus/listeners/sys_logger.h \
config/backend_manager.c config/backend_manager.h config/backend.h \
config/child_cfg.c config/child_cfg.h \
config/ike_cfg.c config/ike_cfg.h \
config/peer_cfg.c config/peer_cfg.h \
config/proposal.c config/proposal.h \
config/auth_cfg.c config/auth_cfg.h \
control/controller.c control/controller.h \
daemon.c daemon.h \
encoding/generator.c encoding/generator.h \
encoding/message.c encoding/message.h \
encoding/parser.c encoding/parser.h \
encoding/payloads/auth_payload.c encoding/payloads/auth_payload.h \
encoding/payloads/cert_payload.c encoding/payloads/cert_payload.h \
encoding/payloads/certreq_payload.c encoding/payloads/certreq_payload.h \
encoding/payloads/configuration_attribute.c encoding/payloads/configuration_attribute.h \
encoding/payloads/cp_payload.c encoding/payloads/cp_payload.h \
encoding/payloads/delete_payload.c encoding/payloads/delete_payload.h \
encoding/payloads/eap_payload.c encoding/payloads/eap_payload.h \
encoding/payloads/encodings.c encoding/payloads/encodings.h \
encoding/payloads/encryption_payload.c encoding/payloads/encryption_payload.h \
encoding/payloads/id_payload.c encoding/payloads/id_payload.h \
encoding/payloads/ike_header.c encoding/payloads/ike_header.h \
encoding/payloads/ke_payload.c encoding/payloads/ke_payload.h \
encoding/payloads/nonce_payload.c encoding/payloads/nonce_payload.h \
encoding/payloads/notify_payload.c encoding/payloads/notify_payload.h \
encoding/payloads/payload.c encoding/payloads/payload.h \
encoding/payloads/proposal_substructure.c encoding/payloads/proposal_substructure.h \
encoding/payloads/sa_payload.c encoding/payloads/sa_payload.h \
encoding/payloads/traffic_selector_substructure.c encoding/payloads/traffic_selector_substructure.h \
encoding/payloads/transform_attribute.c encoding/payloads/transform_attribute.h \
encoding/payloads/transform_substructure.c encoding/payloads/transform_substructure.h \
encoding/payloads/ts_payload.c encoding/payloads/ts_payload.h \
encoding/payloads/unknown_payload.c encoding/payloads/unknown_payload.h \
encoding/payloads/vendor_id_payload.c encoding/payloads/vendor_id_payload.h \
kernel/kernel_interface.c kernel/kernel_interface.h \
kernel/kernel_ipsec.c kernel/kernel_ipsec.h \
kernel/kernel_net.h \
network/packet.c network/packet.h \
network/receiver.c network/receiver.h \
network/sender.c network/sender.h \
network/socket_manager.c network/socket_manager.h network/socket.h \
processing/jobs/job.h \
processing/jobs/acquire_job.c processing/jobs/acquire_job.h \
processing/jobs/callback_job.c processing/jobs/callback_job.h \
processing/jobs/delete_child_sa_job.c processing/jobs/delete_child_sa_job.h \
processing/jobs/delete_ike_sa_job.c processing/jobs/delete_ike_sa_job.h \
processing/jobs/migrate_job.c processing/jobs/migrate_job.h \
processing/jobs/process_message_job.c processing/jobs/process_message_job.h \
processing/jobs/rekey_child_sa_job.c processing/jobs/rekey_child_sa_job.h \
processing/jobs/rekey_ike_sa_job.c processing/jobs/rekey_ike_sa_job.h \
processing/jobs/retransmit_job.c processing/jobs/retransmit_job.h \
processing/jobs/send_dpd_job.c processing/jobs/send_dpd_job.h \
processing/jobs/send_keepalive_job.c processing/jobs/send_keepalive_job.h \
processing/jobs/roam_job.c processing/jobs/roam_job.h \
processing/jobs/update_sa_job.c processing/jobs/update_sa_job.h \
processing/jobs/inactivity_job.c processing/jobs/inactivity_job.h \
processing/scheduler.c processing/scheduler.h \
processing/processor.c processing/processor.h \
sa/authenticators/authenticator.c sa/authenticators/authenticator.h \
sa/authenticators/eap_authenticator.c sa/authenticators/eap_authenticator.h \
sa/authenticators/eap/eap_method.c sa/authenticators/eap/eap_method.h \
sa/authenticators/eap/eap_manager.c sa/authenticators/eap/eap_manager.h \
sa/authenticators/eap/sim_manager.c sa/authenticators/eap/sim_manager.h \
sa/authenticators/psk_authenticator.c sa/authenticators/psk_authenticator.h \
sa/authenticators/pubkey_authenticator.c sa/authenticators/pubkey_authenticator.h \
sa/child_sa.c sa/child_sa.h \
sa/ike_sa.c sa/ike_sa.h \
sa/ike_sa_id.c sa/ike_sa_id.h \
sa/ike_sa_manager.c sa/ike_sa_manager.h \
sa/task_manager.c sa/task_manager.h \
sa/keymat.c sa/keymat.h \
sa/trap_manager.c sa/trap_manager.h \
sa/tasks/child_create.c sa/tasks/child_create.h \
sa/tasks/child_delete.c sa/tasks/child_delete.h \
sa/tasks/child_rekey.c sa/tasks/child_rekey.h \
sa/tasks/ike_auth.c sa/tasks/ike_auth.h \
sa/tasks/ike_cert_pre.c sa/tasks/ike_cert_pre.h \
sa/tasks/ike_cert_post.c sa/tasks/ike_cert_post.h \
sa/tasks/ike_config.c sa/tasks/ike_config.h \
sa/tasks/ike_delete.c sa/tasks/ike_delete.h \
sa/tasks/ike_dpd.c sa/tasks/ike_dpd.h \
sa/tasks/ike_init.c sa/tasks/ike_init.h \
sa/tasks/ike_natd.c sa/tasks/ike_natd.h \
sa/tasks/ike_mobike.c sa/tasks/ike_mobike.h \
sa/tasks/ike_rekey.c sa/tasks/ike_rekey.h \
sa/tasks/ike_reauth.c sa/tasks/ike_reauth.h \
sa/tasks/ike_auth_lifetime.c sa/tasks/ike_auth_lifetime.h \
sa/tasks/ike_vendor.c sa/tasks/ike_vendor.h \
sa/tasks/task.c sa/tasks/task.h \
credentials/credential_manager.c credentials/credential_manager.h \
credentials/sets/auth_cfg_wrapper.c credentials/sets/auth_cfg_wrapper.h \
credentials/sets/ocsp_response_wrapper.c credentials/sets/ocsp_response_wrapper.h \
credentials/sets/cert_cache.c credentials/sets/cert_cache.h \
credentials/credential_set.h
# adding the plugin source files (copy-n-paste from Makefile.am)
LOCAL_SRC_FILES += $(call add_plugin, android, \
android_plugin.c android_plugin.h \
android_handler.c android_handler.h \
)
ifneq ($(call plugin_enabled, android)),)
LOCAL_SHARED_LIBRARIES += libcutils
endif
LOCAL_SRC_FILES += $(call add_plugin, attr, \
attr_plugin.h attr_plugin.c \
attr_provider.h attr_provider.c \
)
LOCAL_SRC_FILES += $(call add_plugin, eap-aka, \
eap_aka_plugin.h eap_aka_plugin.c \
eap_aka_peer.h eap_aka_peer.c \
eap_aka_server.h eap_aka_server.c \
)
LOCAL_SRC_FILES += $(call add_plugin, eap-aka-3gpp2, \
eap_aka_3gpp2_plugin.h eap_aka_3gpp2_plugin.c \
eap_aka_3gpp2_card.h eap_aka_3gpp2_card.c \
eap_aka_3gpp2_provider.h eap_aka_3gpp2_provider.c \
eap_aka_3gpp2_functions.h eap_aka_3gpp2_functions.c \
)
ifneq ($(call plugin_enabled, eap-aka-3gpp2)),)
LOCAL_C_INCLUDES += $(libgmp_PATH)
LOCAL_STATIC_LIBRARIES += libgmp
endif
LOCAL_SRC_FILES += $(call add_plugin, eap-gtc, \
eap_gtc_plugin.h eap_gtc_plugin.c eap_gtc.h eap_gtc.c \
)
LOCAL_SRC_FILES += $(call add_plugin, eap-identity, \
eap_identity_plugin.h eap_identity_plugin.c eap_identity.h eap_identity.c \
)
LOCAL_SRC_FILES += $(call add_plugin, eap-md5, \
eap_md5_plugin.h eap_md5_plugin.c eap_md5.h eap_md5.c \
)
LOCAL_SRC_FILES += $(call add_plugin, eap-mschapv2, \
eap_mschapv2_plugin.h eap_mschapv2_plugin.c \
eap_mschapv2.h eap_mschapv2.c \
)
LOCAL_SRC_FILES += $(call add_plugin, eap-sim, \
eap_sim_plugin.h eap_sim_plugin.c \
eap_sim_peer.h eap_sim_peer.c \
eap_sim_server.h eap_sim_server.c \
)
LOCAL_SRC_FILES += $(call add_plugin, eap-simaka-pseudonym, \
eap_simaka_pseudonym_plugin.h eap_simaka_pseudonym_plugin.c \
eap_simaka_pseudonym_card.h eap_simaka_pseudonym_card.c \
eap_simaka_pseudonym_provider.h eap_simaka_pseudonym_provider.c \
)
LOCAL_SRC_FILES += $(call add_plugin, eap-simaka-reauth, \
eap_simaka_reauth_plugin.h eap_simaka_reauth_plugin.c \
eap_simaka_reauth_card.h eap_simaka_reauth_card.c \
eap_simaka_reauth_provider.h eap_simaka_reauth_provider.c \
)
LOCAL_SRC_FILES += $(call add_plugin, eap-sim-file, \
eap_sim_file_plugin.h eap_sim_file_plugin.c \
eap_sim_file_card.h eap_sim_file_card.c \
eap_sim_file_provider.h eap_sim_file_provider.c \
eap_sim_file_triplets.h eap_sim_file_triplets.c \
)
# adding libakasim if either eap-aka or eap-sim is enabled
ifneq ($(or $(call plugin_enabled, eap-aka), $(call plugin_enabled, eap-sim)),)
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../libsimaka/
LOCAL_SRC_FILES += $(addprefix ../libsimaka/, \
simaka_message.h simaka_message.c \
simaka_crypto.h simaka_crypto.c \
)
endif
LOCAL_SRC_FILES += $(call add_plugin, kernel-netlink, \
kernel_netlink_plugin.h kernel_netlink_plugin.c \
kernel_netlink_ipsec.h kernel_netlink_ipsec.c kernel_netlink_net.h kernel_netlink_net.c \
kernel_netlink_shared.h kernel_netlink_shared.c \
)
LOCAL_SRC_FILES += $(call add_plugin, load-tester, \
load_tester_plugin.c load_tester_plugin.h \
load_tester_config.c load_tester_config.h \
load_tester_creds.c load_tester_creds.h \
load_tester_ipsec.c load_tester_ipsec.h \
load_tester_listener.c load_tester_listener.h \
load_tester_diffie_hellman.c load_tester_diffie_hellman.h \
)
LOCAL_SRC_FILES += $(call add_plugin, socket-default, \
socket_default_socket.h socket_default_socket.c \
socket_default_plugin.h socket_default_plugin.c \
)
LOCAL_SRC_FILES += $(call add_plugin, socket-dynamic, \
socket_dynamic_plugin.h socket_dynamic_plugin.c \
socket_dynamic_socket.h socket_dynamic_socket.c \
)
# build charon -----------------------------------------------------------------
LOCAL_C_INCLUDES += \
$(libvstr_PATH) \
$(strongswan_PATH)/src/include \
$(strongswan_PATH)/src/libstrongswan
LOCAL_CFLAGS := $(strongswan_CFLAGS)
# this is required to be able load the plugins
LOCAL_LDFLAGS := -Wl,--export-dynamic
LOCAL_MODULE := charon
LOCAL_ARM_MODE := arm
LOCAL_PRELINK_MODULE := false
LOCAL_SHARED_LIBRARIES += libstrongswan
include $(BUILD_EXECUTABLE)
+396
View File
@@ -0,0 +1,396 @@
ipsec_PROGRAMS = charon
charon_SOURCES = \
bus/bus.c bus/bus.h \
bus/listeners/listener.h \
bus/listeners/file_logger.c bus/listeners/file_logger.h \
bus/listeners/sys_logger.c bus/listeners/sys_logger.h \
config/backend_manager.c config/backend_manager.h config/backend.h \
config/child_cfg.c config/child_cfg.h \
config/ike_cfg.c config/ike_cfg.h \
config/peer_cfg.c config/peer_cfg.h \
config/proposal.c config/proposal.h \
config/auth_cfg.c config/auth_cfg.h \
control/controller.c control/controller.h \
daemon.c daemon.h \
encoding/generator.c encoding/generator.h \
encoding/message.c encoding/message.h \
encoding/parser.c encoding/parser.h \
encoding/payloads/auth_payload.c encoding/payloads/auth_payload.h \
encoding/payloads/cert_payload.c encoding/payloads/cert_payload.h \
encoding/payloads/certreq_payload.c encoding/payloads/certreq_payload.h \
encoding/payloads/configuration_attribute.c encoding/payloads/configuration_attribute.h \
encoding/payloads/cp_payload.c encoding/payloads/cp_payload.h \
encoding/payloads/delete_payload.c encoding/payloads/delete_payload.h \
encoding/payloads/eap_payload.c encoding/payloads/eap_payload.h \
encoding/payloads/encodings.c encoding/payloads/encodings.h \
encoding/payloads/encryption_payload.c encoding/payloads/encryption_payload.h \
encoding/payloads/id_payload.c encoding/payloads/id_payload.h \
encoding/payloads/ike_header.c encoding/payloads/ike_header.h \
encoding/payloads/ke_payload.c encoding/payloads/ke_payload.h \
encoding/payloads/nonce_payload.c encoding/payloads/nonce_payload.h \
encoding/payloads/notify_payload.c encoding/payloads/notify_payload.h \
encoding/payloads/payload.c encoding/payloads/payload.h \
encoding/payloads/proposal_substructure.c encoding/payloads/proposal_substructure.h \
encoding/payloads/sa_payload.c encoding/payloads/sa_payload.h \
encoding/payloads/traffic_selector_substructure.c encoding/payloads/traffic_selector_substructure.h \
encoding/payloads/transform_attribute.c encoding/payloads/transform_attribute.h \
encoding/payloads/transform_substructure.c encoding/payloads/transform_substructure.h \
encoding/payloads/ts_payload.c encoding/payloads/ts_payload.h \
encoding/payloads/unknown_payload.c encoding/payloads/unknown_payload.h \
encoding/payloads/vendor_id_payload.c encoding/payloads/vendor_id_payload.h \
kernel/kernel_interface.c kernel/kernel_interface.h \
kernel/kernel_ipsec.c kernel/kernel_ipsec.h \
kernel/kernel_net.h \
network/packet.c network/packet.h \
network/receiver.c network/receiver.h \
network/sender.c network/sender.h \
network/socket_manager.c network/socket_manager.h network/socket.h \
processing/jobs/job.h \
processing/jobs/acquire_job.c processing/jobs/acquire_job.h \
processing/jobs/callback_job.c processing/jobs/callback_job.h \
processing/jobs/delete_child_sa_job.c processing/jobs/delete_child_sa_job.h \
processing/jobs/delete_ike_sa_job.c processing/jobs/delete_ike_sa_job.h \
processing/jobs/migrate_job.c processing/jobs/migrate_job.h \
processing/jobs/process_message_job.c processing/jobs/process_message_job.h \
processing/jobs/rekey_child_sa_job.c processing/jobs/rekey_child_sa_job.h \
processing/jobs/rekey_ike_sa_job.c processing/jobs/rekey_ike_sa_job.h \
processing/jobs/retransmit_job.c processing/jobs/retransmit_job.h \
processing/jobs/send_dpd_job.c processing/jobs/send_dpd_job.h \
processing/jobs/send_keepalive_job.c processing/jobs/send_keepalive_job.h \
processing/jobs/roam_job.c processing/jobs/roam_job.h \
processing/jobs/update_sa_job.c processing/jobs/update_sa_job.h \
processing/jobs/inactivity_job.c processing/jobs/inactivity_job.h \
processing/scheduler.c processing/scheduler.h \
processing/processor.c processing/processor.h \
sa/authenticators/authenticator.c sa/authenticators/authenticator.h \
sa/authenticators/eap_authenticator.c sa/authenticators/eap_authenticator.h \
sa/authenticators/eap/eap_method.c sa/authenticators/eap/eap_method.h \
sa/authenticators/eap/eap_manager.c sa/authenticators/eap/eap_manager.h \
sa/authenticators/eap/sim_manager.c sa/authenticators/eap/sim_manager.h \
sa/authenticators/psk_authenticator.c sa/authenticators/psk_authenticator.h \
sa/authenticators/pubkey_authenticator.c sa/authenticators/pubkey_authenticator.h \
sa/child_sa.c sa/child_sa.h \
sa/ike_sa.c sa/ike_sa.h \
sa/ike_sa_id.c sa/ike_sa_id.h \
sa/ike_sa_manager.c sa/ike_sa_manager.h \
sa/task_manager.c sa/task_manager.h \
sa/keymat.c sa/keymat.h \
sa/trap_manager.c sa/trap_manager.h \
sa/tasks/child_create.c sa/tasks/child_create.h \
sa/tasks/child_delete.c sa/tasks/child_delete.h \
sa/tasks/child_rekey.c sa/tasks/child_rekey.h \
sa/tasks/ike_auth.c sa/tasks/ike_auth.h \
sa/tasks/ike_cert_pre.c sa/tasks/ike_cert_pre.h \
sa/tasks/ike_cert_post.c sa/tasks/ike_cert_post.h \
sa/tasks/ike_config.c sa/tasks/ike_config.h \
sa/tasks/ike_delete.c sa/tasks/ike_delete.h \
sa/tasks/ike_dpd.c sa/tasks/ike_dpd.h \
sa/tasks/ike_init.c sa/tasks/ike_init.h \
sa/tasks/ike_natd.c sa/tasks/ike_natd.h \
sa/tasks/ike_mobike.c sa/tasks/ike_mobike.h \
sa/tasks/ike_rekey.c sa/tasks/ike_rekey.h \
sa/tasks/ike_reauth.c sa/tasks/ike_reauth.h \
sa/tasks/ike_auth_lifetime.c sa/tasks/ike_auth_lifetime.h \
sa/tasks/ike_vendor.c sa/tasks/ike_vendor.h \
sa/tasks/task.c sa/tasks/task.h \
credentials/credential_manager.c credentials/credential_manager.h \
credentials/sets/auth_cfg_wrapper.c credentials/sets/auth_cfg_wrapper.h \
credentials/sets/ocsp_response_wrapper.c credentials/sets/ocsp_response_wrapper.h \
credentials/sets/cert_cache.c credentials/sets/cert_cache.h \
credentials/credential_set.h
INCLUDES = -I${linux_headers} -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon
AM_CFLAGS = -rdynamic \
-DIPSEC_DIR=\"${ipsecdir}\" \
-DIPSEC_PIDDIR=\"${piddir}\"
charon_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la -lm $(PTHREADLIB) $(DLLIB) $(SOCKLIB)
EXTRA_DIST = Android.mk
# compile options
#################
if USE_ME
charon_SOURCES += encoding/payloads/endpoint_notify.c encoding/payloads/endpoint_notify.h \
processing/jobs/initiate_mediation_job.c processing/jobs/initiate_mediation_job.h \
processing/jobs/mediation_job.c processing/jobs/mediation_job.h \
sa/connect_manager.c sa/connect_manager.h \
sa/mediation_manager.c sa/mediation_manager.h \
sa/tasks/ike_me.c sa/tasks/ike_me.h
endif
if USE_CAPABILITIES
charon_LDADD += -lcap
endif
if MONOLITHIC
lib_LTLIBRARIES = libcharon.la
charon_LDADD += $(top_builddir)/src/charon/libcharon.la
libcharon_la_SOURCES =
libcharon_la_LIBADD =
endif
# build optional plugins
########################
SUBDIRS =
PLUGINS = ${libstrongswan_plugins}
if USE_LOAD_TESTER
SUBDIRS += plugins/load_tester
PLUGINS += load-tester
if MONOLITHIC
libcharon_la_LIBADD += plugins/load_tester/libstrongswan-load-tester.la
endif
endif
if USE_KERNEL_PFKEY
SUBDIRS += plugins/kernel_pfkey
PLUGINS += kernel-pfkey
if MONOLITHIC
libcharon_la_LIBADD += plugins/kernel_pfkey/libstrongswan-kernel-pfkey.la
endif
endif
if USE_KERNEL_PFROUTE
SUBDIRS += plugins/kernel_pfroute
PLUGINS += kernel-pfroute
if MONOLITHIC
libcharon_la_LIBADD += plugins/kernel_pfroute/libstrongswan-kernel-pfroute.la
endif
endif
if USE_KERNEL_KLIPS
SUBDIRS += plugins/kernel_klips
PLUGINS += kernel-klips
if MONOLITHIC
libcharon_la_LIBADD += plugins/kernel_klips/libstrongswan-kernel-klips.la
endif
endif
if USE_KERNEL_NETLINK
SUBDIRS += plugins/kernel_netlink
PLUGINS += kernel-netlink
if MONOLITHIC
libcharon_la_LIBADD += plugins/kernel_netlink/libstrongswan-kernel-netlink.la
endif
endif
if USE_SOCKET_DEFAULT
SUBDIRS += plugins/socket_default
PLUGINS += socket-default
if MONOLITHIC
libcharon_la_LIBADD += plugins/socket_default/libstrongswan-socket-default.la
endif
endif
if USE_SOCKET_RAW
SUBDIRS += plugins/socket_raw
PLUGINS += socket-raw
if MONOLITHIC
libcharon_la_LIBADD += plugins/socket_raw/libstrongswan-socket-raw.la
endif
endif
if USE_SOCKET_DYNAMIC
SUBDIRS += plugins/socket_dynamic
PLUGINS += socket-dynamic
if MONOLITHIC
libcharon_la_LIBADD += plugins/socket_dynamic/libstrongswan-socket-dynamic.la
endif
endif
if USE_STROKE
SUBDIRS += plugins/stroke
PLUGINS += stroke
if MONOLITHIC
libcharon_la_LIBADD += plugins/stroke/libstrongswan-stroke.la
endif
endif
if USE_SMP
SUBDIRS += plugins/smp
PLUGINS += smp
if MONOLITHIC
libcharon_la_LIBADD += plugins/smp/libstrongswan-smp.la
endif
endif
if USE_SQL
SUBDIRS += plugins/sql
PLUGINS += sql
if MONOLITHIC
libcharon_la_LIBADD += plugins/sql/libstrongswan-sql.la
endif
endif
if USE_UPDOWN
SUBDIRS += plugins/updown
PLUGINS += updown
if MONOLITHIC
libcharon_la_LIBADD += plugins/updown/libstrongswan-updown.la
endif
endif
if USE_ATTR
SUBDIRS += plugins/attr
PLUGINS += attr
if MONOLITHIC
libcharon_la_LIBADD += plugins/attr/libstrongswan-attr.la
endif
endif
if USE_EAP_IDENTITY
SUBDIRS += plugins/eap_identity
PLUGINS += eap-identity
if MONOLITHIC
libcharon_la_LIBADD += plugins/eap_identity/libstrongswan-eap-identity.la
endif
endif
if USE_EAP_SIM
SUBDIRS += plugins/eap_sim
PLUGINS += eap-sim
if MONOLITHIC
libcharon_la_LIBADD += plugins/eap_sim/libstrongswan-eap-sim.la
endif
endif
if USE_EAP_SIM_FILE
SUBDIRS += plugins/eap_sim_file
PLUGINS += eap-sim-file
if MONOLITHIC
libcharon_la_LIBADD += plugins/eap_sim_file/libstrongswan-eap-sim-file.la
endif
endif
if USE_EAP_SIMAKA_PSEUDONYM
SUBDIRS += plugins/eap_simaka_pseudonym
PLUGINS += eap-simaka-pseudonym
if MONOLITHIC
libcharon_la_LIBADD += plugins/eap_simaka_pseudonym/libstrongswan-eap-simaka-pseudonym.la
endif
endif
if USE_EAP_SIMAKA_REAUTH
SUBDIRS += plugins/eap_simaka_reauth
PLUGINS += eap-simaka-reauth
if MONOLITHIC
libcharon_la_LIBADD += plugins/eap_simaka_reauth/libstrongswan-eap-simaka-reauth.la
endif
endif
if USE_EAP_AKA
SUBDIRS += plugins/eap_aka
PLUGINS += eap-aka
if MONOLITHIC
libcharon_la_LIBADD += plugins/eap_aka/libstrongswan-eap-aka.la
endif
endif
if USE_EAP_AKA_3GPP2
SUBDIRS += plugins/eap_aka_3gpp2
PLUGINS += eap-aka-3gpp2
if MONOLITHIC
libcharon_la_LIBADD += plugins/eap_aka_3gpp2/libstrongswan-eap-aka-3gpp2.la
endif
endif
if USE_SIMAKA
if MONOLITHIC
# otherwise this library is linked to both the eap_aka and the eap_sim plugin
libcharon_la_LIBADD += $(top_builddir)/src/libsimaka/libsimaka.la
endif
endif
if USE_EAP_MD5
SUBDIRS += plugins/eap_md5
PLUGINS += eap-md5
if MONOLITHIC
libcharon_la_LIBADD += plugins/eap_md5/libstrongswan-eap-md5.la
endif
endif
if USE_EAP_GTC
SUBDIRS += plugins/eap_gtc
PLUGINS += eap-gtc
if MONOLITHIC
libcharon_la_LIBADD += plugins/eap_gtc/libstrongswan-eap-gtc.la
endif
endif
if USE_EAP_MSCHAPV2
SUBDIRS += plugins/eap_mschapv2
PLUGINS += eap-mschapv2
if MONOLITHIC
libcharon_la_LIBADD += plugins/eap_mschapv2/libstrongswan-eap-mschapv2.la
endif
endif
if USE_EAP_RADIUS
SUBDIRS += plugins/eap_radius
PLUGINS += eap-radius
if MONOLITHIC
libcharon_la_LIBADD += plugins/eap_radius/libstrongswan-eap-radius.la
endif
endif
if USE_MEDSRV
SUBDIRS += plugins/medsrv
PLUGINS += medsrv
if MONOLITHIC
libcharon_la_LIBADD += plugins/medsrv/libstrongswan-medsrv.la
endif
endif
if USE_MEDCLI
SUBDIRS += plugins/medcli
PLUGINS += medcli
if MONOLITHIC
libcharon_la_LIBADD += plugins/medcli/libstrongswan-medcli.la
endif
endif
if USE_NM
SUBDIRS += plugins/nm
PLUGINS += nm
if MONOLITHIC
libcharon_la_LIBADD += plugins/nm/libstrongswan-nm.la
endif
endif
if USE_RESOLVE
SUBDIRS += plugins/resolve
PLUGINS += resolve
if MONOLITHIC
libcharon_la_LIBADD += plugins/resolve/libstrongswan-resolve.la
endif
endif
if USE_ANDROID
SUBDIRS += plugins/android
PLUGINS += android
if MONOLITHIC
libcharon_la_LIBADD += plugins/android/libstrongswan-android.la
endif
endif
if USE_UCI
SUBDIRS += plugins/uci
PLUGINS += uci
if MONOLITHIC
libcharon_la_LIBADD += plugins/uci/libstrongswan-uci.la
endif
endif
if USE_UNIT_TESTS
SUBDIRS += plugins/unit_tester
PLUGINS += unit-tester
if MONOLITHIC
libcharon_la_LIBADD += plugins/unit_tester/libstrongswan-unit-tester.la
endif
endif
AM_CFLAGS += -DPLUGINS=\""${PLUGINS}\""
+753
View File
@@ -0,0 +1,753 @@
/*
* Copyright (C) 2006 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "bus.h"
#include <stdint.h>
#include <daemon.h>
#include <threading/thread.h>
#include <threading/thread_value.h>
#include <threading/condvar.h>
#include <threading/mutex.h>
ENUM(debug_names, DBG_DMN, DBG_LIB,
"DMN",
"MGR",
"IKE",
"CHD",
"JOB",
"CFG",
"KNL",
"NET",
"ENC",
"LIB",
);
ENUM(debug_lower_names, DBG_DMN, DBG_LIB,
"dmn",
"mgr",
"ike",
"chd",
"job",
"cfg",
"knl",
"net",
"enc",
"lib",
);
typedef struct private_bus_t private_bus_t;
/**
* Private data of a bus_t object.
*/
struct private_bus_t {
/**
* Public part of a bus_t object.
*/
bus_t public;
/**
* List of registered listeners as entry_t's
*/
linked_list_t *listeners;
/**
* mutex to synchronize active listeners, recursively
*/
mutex_t *mutex;
/**
* Thread local storage the threads IKE_SA
*/
thread_value_t *thread_sa;
};
typedef struct entry_t entry_t;
/**
* a listener entry, either active or passive
*/
struct entry_t {
/**
* registered listener interface
*/
listener_t *listener;
/**
* is this a active listen() call with a blocking thread
*/
bool blocker;
/**
* are we currently calling this listener
*/
int calling;
/**
* condvar where active listeners wait
*/
condvar_t *condvar;
};
/**
* create a listener entry
*/
static entry_t *entry_create(listener_t *listener, bool blocker)
{
entry_t *this = malloc_thing(entry_t);
this->listener = listener;
this->blocker = blocker;
this->calling = 0;
this->condvar = condvar_create(CONDVAR_TYPE_DEFAULT);
return this;
}
/**
* destroy an entry_t
*/
static void entry_destroy(entry_t *entry)
{
entry->condvar->destroy(entry->condvar);
free(entry);
}
/**
* Implementation of bus_t.add_listener.
*/
static void add_listener(private_bus_t *this, listener_t *listener)
{
this->mutex->lock(this->mutex);
this->listeners->insert_last(this->listeners, entry_create(listener, FALSE));
this->mutex->unlock(this->mutex);
}
/**
* Implementation of bus_t.remove_listener.
*/
static void remove_listener(private_bus_t *this, listener_t *listener)
{
enumerator_t *enumerator;
entry_t *entry;
this->mutex->lock(this->mutex);
enumerator = this->listeners->create_enumerator(this->listeners);
while (enumerator->enumerate(enumerator, &entry))
{
if (entry->listener == listener)
{
this->listeners->remove_at(this->listeners, enumerator);
entry_destroy(entry);
break;
}
}
enumerator->destroy(enumerator);
this->mutex->unlock(this->mutex);
}
typedef struct cleanup_data_t cleanup_data_t;
/**
* data to remove a listener using thread_cleanup_t handler
*/
struct cleanup_data_t {
/** bus instance */
private_bus_t *this;
/** listener entry */
entry_t *entry;
};
/**
* thread_cleanup_t handler to remove a listener
*/
static void listener_cleanup(cleanup_data_t *data)
{
data->this->listeners->remove(data->this->listeners, data->entry, NULL);
entry_destroy(data->entry);
}
/**
* Implementation of bus_t.listen.
*/
static void listen_(private_bus_t *this, listener_t *listener, job_t *job)
{
bool old;
cleanup_data_t data;
data.this = this;
data.entry = entry_create(listener, TRUE);
this->mutex->lock(this->mutex);
this->listeners->insert_last(this->listeners, data.entry);
charon->processor->queue_job(charon->processor, job);
thread_cleanup_push((thread_cleanup_t)this->mutex->unlock, this->mutex);
thread_cleanup_push((thread_cleanup_t)listener_cleanup, &data);
old = thread_cancelability(TRUE);
while (data.entry->blocker)
{
data.entry->condvar->wait(data.entry->condvar, this->mutex);
}
thread_cancelability(old);
thread_cleanup_pop(FALSE);
/* unlock mutex */
thread_cleanup_pop(TRUE);
entry_destroy(data.entry);
}
/**
* Implementation of bus_t.set_sa.
*/
static void set_sa(private_bus_t *this, ike_sa_t *ike_sa)
{
this->thread_sa->set(this->thread_sa, ike_sa);
}
/**
* Implementation of bus_t.get_sa
*/
static ike_sa_t* get_sa(private_bus_t *this)
{
return this->thread_sa->get(this->thread_sa);
}
/**
* data associated to a signal, passed to callback
*/
typedef struct {
/** associated IKE_SA */
ike_sa_t *ike_sa;
/** invoking thread */
long thread;
/** debug group */
debug_t group;
/** debug level */
level_t level;
/** format string */
char *format;
/** argument list */
va_list args;
} log_data_t;
/**
* listener->log() invocation as a list remove callback
*/
static bool log_cb(entry_t *entry, log_data_t *data)
{
va_list args;
if (entry->calling || !entry->listener->log)
{ /* avoid recursive calls */
return FALSE;
}
entry->calling++;
va_copy(args, data->args);
if (!entry->listener->log(entry->listener, data->group, data->level,
data->thread, data->ike_sa, data->format, args))
{
if (entry->blocker)
{
entry->blocker = FALSE;
entry->condvar->signal(entry->condvar);
}
else
{
entry_destroy(entry);
}
va_end(args);
entry->calling--;
return TRUE;
}
va_end(args);
entry->calling--;
return FALSE;
}
/**
* Implementation of bus_t.vlog.
*/
static void vlog(private_bus_t *this, debug_t group, level_t level,
char* format, va_list args)
{
log_data_t data;
data.ike_sa = this->thread_sa->get(this->thread_sa);
data.thread = thread_current_id();
data.group = group;
data.level = level;
data.format = format;
va_copy(data.args, args);
this->mutex->lock(this->mutex);
/* We use the remove() method to invoke all listeners. This is cheap and
* does not require an allocation for this performance critical function. */
this->listeners->remove(this->listeners, &data, (void*)log_cb);
this->mutex->unlock(this->mutex);
va_end(data.args);
}
/**
* Implementation of bus_t.log.
*/
static void log_(private_bus_t *this, debug_t group, level_t level,
char* format, ...)
{
va_list args;
va_start(args, format);
vlog(this, group, level, format, args);
va_end(args);
}
/**
* unregister a listener
*/
static void unregister_listener(private_bus_t *this, entry_t *entry,
enumerator_t *enumerator)
{
if (entry->blocker)
{
entry->blocker = FALSE;
entry->condvar->signal(entry->condvar);
}
else
{
entry_destroy(entry);
}
this->listeners->remove_at(this->listeners, enumerator);
}
/**
* Implementation of bus_t.alert
*/
static void alert(private_bus_t *this, alert_t alert, ...)
{
enumerator_t *enumerator;
ike_sa_t *ike_sa;
entry_t *entry;
va_list args;
bool keep;
ike_sa = this->thread_sa->get(this->thread_sa);
this->mutex->lock(this->mutex);
enumerator = this->listeners->create_enumerator(this->listeners);
while (enumerator->enumerate(enumerator, &entry))
{
if (entry->calling || !entry->listener->alert)
{
continue;
}
entry->calling++;
va_start(args, alert);
keep = entry->listener->alert(entry->listener, ike_sa, alert, args);
va_end(args);
entry->calling--;
if (!keep)
{
unregister_listener(this, entry, enumerator);
}
}
enumerator->destroy(enumerator);
this->mutex->unlock(this->mutex);
}
/**
* Implementation of bus_t.ike_state_change
*/
static void ike_state_change(private_bus_t *this, ike_sa_t *ike_sa,
ike_sa_state_t state)
{
enumerator_t *enumerator;
entry_t *entry;
bool keep;
this->mutex->lock(this->mutex);
enumerator = this->listeners->create_enumerator(this->listeners);
while (enumerator->enumerate(enumerator, &entry))
{
if (entry->calling || !entry->listener->ike_state_change)
{
continue;
}
entry->calling++;
keep = entry->listener->ike_state_change(entry->listener, ike_sa, state);
entry->calling--;
if (!keep)
{
unregister_listener(this, entry, enumerator);
}
}
enumerator->destroy(enumerator);
this->mutex->unlock(this->mutex);
}
/**
* Implementation of bus_t.child_state_change
*/
static void child_state_change(private_bus_t *this, child_sa_t *child_sa,
child_sa_state_t state)
{
enumerator_t *enumerator;
ike_sa_t *ike_sa;
entry_t *entry;
bool keep;
ike_sa = this->thread_sa->get(this->thread_sa);
this->mutex->lock(this->mutex);
enumerator = this->listeners->create_enumerator(this->listeners);
while (enumerator->enumerate(enumerator, &entry))
{
if (entry->calling || !entry->listener->child_state_change)
{
continue;
}
entry->calling++;
keep = entry->listener->child_state_change(entry->listener, ike_sa,
child_sa, state);
entry->calling--;
if (!keep)
{
unregister_listener(this, entry, enumerator);
}
}
enumerator->destroy(enumerator);
this->mutex->unlock(this->mutex);
}
/**
* Implementation of bus_t.message
*/
static void message(private_bus_t *this, message_t *message, bool incoming)
{
enumerator_t *enumerator;
ike_sa_t *ike_sa;
entry_t *entry;
bool keep;
ike_sa = this->thread_sa->get(this->thread_sa);
this->mutex->lock(this->mutex);
enumerator = this->listeners->create_enumerator(this->listeners);
while (enumerator->enumerate(enumerator, &entry))
{
if (entry->calling || !entry->listener->message)
{
continue;
}
entry->calling++;
keep = entry->listener->message(entry->listener, ike_sa,
message, incoming);
entry->calling--;
if (!keep)
{
unregister_listener(this, entry, enumerator);
}
}
enumerator->destroy(enumerator);
this->mutex->unlock(this->mutex);
}
/**
* Implementation of bus_t.ike_keys
*/
static void ike_keys(private_bus_t *this, ike_sa_t *ike_sa,
diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r,
ike_sa_t *rekey)
{
enumerator_t *enumerator;
entry_t *entry;
bool keep;
this->mutex->lock(this->mutex);
enumerator = this->listeners->create_enumerator(this->listeners);
while (enumerator->enumerate(enumerator, &entry))
{
if (entry->calling || !entry->listener->ike_keys)
{
continue;
}
entry->calling++;
keep = entry->listener->ike_keys(entry->listener, ike_sa, dh,
nonce_i, nonce_r, rekey);
entry->calling--;
if (!keep)
{
unregister_listener(this, entry, enumerator);
}
}
enumerator->destroy(enumerator);
this->mutex->unlock(this->mutex);
}
/**
* Implementation of bus_t.child_keys
*/
static void child_keys(private_bus_t *this, child_sa_t *child_sa,
diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r)
{
enumerator_t *enumerator;
ike_sa_t *ike_sa;
entry_t *entry;
bool keep;
ike_sa = this->thread_sa->get(this->thread_sa);
this->mutex->lock(this->mutex);
enumerator = this->listeners->create_enumerator(this->listeners);
while (enumerator->enumerate(enumerator, &entry))
{
if (entry->calling || !entry->listener->child_keys)
{
continue;
}
entry->calling++;
keep = entry->listener->child_keys(entry->listener, ike_sa, child_sa,
dh, nonce_i, nonce_r);
entry->calling--;
if (!keep)
{
unregister_listener(this, entry, enumerator);
}
}
enumerator->destroy(enumerator);
this->mutex->unlock(this->mutex);
}
/**
* Implementation of bus_t.child_updown
*/
static void child_updown(private_bus_t *this, child_sa_t *child_sa, bool up)
{
enumerator_t *enumerator;
ike_sa_t *ike_sa;
entry_t *entry;
bool keep;
ike_sa = this->thread_sa->get(this->thread_sa);
this->mutex->lock(this->mutex);
enumerator = this->listeners->create_enumerator(this->listeners);
while (enumerator->enumerate(enumerator, &entry))
{
if (entry->calling || !entry->listener->child_updown)
{
continue;
}
entry->calling++;
keep = entry->listener->child_updown(entry->listener,
ike_sa, child_sa, up);
entry->calling--;
if (!keep)
{
unregister_listener(this, entry, enumerator);
}
}
enumerator->destroy(enumerator);
this->mutex->unlock(this->mutex);
}
/**
* Implementation of bus_t.child_rekey
*/
static void child_rekey(private_bus_t *this, child_sa_t *old, child_sa_t *new)
{
enumerator_t *enumerator;
ike_sa_t *ike_sa;
entry_t *entry;
bool keep;
ike_sa = this->thread_sa->get(this->thread_sa);
this->mutex->lock(this->mutex);
enumerator = this->listeners->create_enumerator(this->listeners);
while (enumerator->enumerate(enumerator, &entry))
{
if (entry->calling || !entry->listener->child_rekey)
{
continue;
}
entry->calling++;
keep = entry->listener->child_rekey(entry->listener, ike_sa, old, new);
entry->calling--;
if (!keep)
{
unregister_listener(this, entry, enumerator);
}
}
enumerator->destroy(enumerator);
this->mutex->unlock(this->mutex);
}
/**
* Implementation of bus_t.ike_updown
*/
static void ike_updown(private_bus_t *this, ike_sa_t *ike_sa, bool up)
{
enumerator_t *enumerator;
entry_t *entry;
bool keep;
this->mutex->lock(this->mutex);
enumerator = this->listeners->create_enumerator(this->listeners);
while (enumerator->enumerate(enumerator, &entry))
{
if (entry->calling || !entry->listener->ike_updown)
{
continue;
}
entry->calling++;
keep = entry->listener->ike_updown(entry->listener, ike_sa, up);
entry->calling--;
if (!keep)
{
unregister_listener(this, entry, enumerator);
}
}
enumerator->destroy(enumerator);
this->mutex->unlock(this->mutex);
/* a down event for IKE_SA implicitly downs all CHILD_SAs */
if (!up)
{
iterator_t *iterator;
child_sa_t *child_sa;
iterator = ike_sa->create_child_sa_iterator(ike_sa);
while (iterator->iterate(iterator, (void**)&child_sa))
{
child_updown(this, child_sa, FALSE);
}
iterator->destroy(iterator);
}
}
/**
* Implementation of bus_t.ike_rekey
*/
static void ike_rekey(private_bus_t *this, ike_sa_t *old, ike_sa_t *new)
{
enumerator_t *enumerator;
entry_t *entry;
bool keep;
this->mutex->lock(this->mutex);
enumerator = this->listeners->create_enumerator(this->listeners);
while (enumerator->enumerate(enumerator, &entry))
{
if (entry->calling || !entry->listener->ike_rekey)
{
continue;
}
entry->calling++;
keep = entry->listener->ike_rekey(entry->listener, old, new);
entry->calling--;
if (!keep)
{
unregister_listener(this, entry, enumerator);
}
}
enumerator->destroy(enumerator);
this->mutex->unlock(this->mutex);
}
/**
* Implementation of bus_t.authorize
*/
static bool authorize(private_bus_t *this, bool final)
{
enumerator_t *enumerator;
ike_sa_t *ike_sa;
entry_t *entry;
bool keep, success = TRUE;
ike_sa = this->thread_sa->get(this->thread_sa);
this->mutex->lock(this->mutex);
enumerator = this->listeners->create_enumerator(this->listeners);
while (enumerator->enumerate(enumerator, &entry))
{
if (entry->calling || !entry->listener->authorize)
{
continue;
}
entry->calling++;
keep = entry->listener->authorize(entry->listener, ike_sa,
final, &success);
entry->calling--;
if (!keep)
{
unregister_listener(this, entry, enumerator);
}
if (!success)
{
break;
}
}
enumerator->destroy(enumerator);
this->mutex->unlock(this->mutex);
return success;
}
/**
* Implementation of bus_t.destroy.
*/
static void destroy(private_bus_t *this)
{
this->thread_sa->destroy(this->thread_sa);
this->mutex->destroy(this->mutex);
this->listeners->destroy_function(this->listeners, (void*)entry_destroy);
free(this);
}
/*
* Described in header.
*/
bus_t *bus_create()
{
private_bus_t *this = malloc_thing(private_bus_t);
this->public.add_listener = (void(*)(bus_t*,listener_t*))add_listener;
this->public.remove_listener = (void(*)(bus_t*,listener_t*))remove_listener;
this->public.listen = (void(*)(bus_t*, listener_t *listener, job_t *job))listen_;
this->public.set_sa = (void(*)(bus_t*,ike_sa_t*))set_sa;
this->public.get_sa = (ike_sa_t*(*)(bus_t*))get_sa;
this->public.log = (void(*)(bus_t*,debug_t,level_t,char*,...))log_;
this->public.vlog = (void(*)(bus_t*,debug_t,level_t,char*,va_list))vlog;
this->public.alert = (void(*)(bus_t*, alert_t alert, ...))alert;
this->public.ike_state_change = (void(*)(bus_t*,ike_sa_t*,ike_sa_state_t))ike_state_change;
this->public.child_state_change = (void(*)(bus_t*,child_sa_t*,child_sa_state_t))child_state_change;
this->public.message = (void(*)(bus_t*, message_t *message, bool incoming))message;
this->public.ike_keys = (void(*)(bus_t*, ike_sa_t *ike_sa, diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r, ike_sa_t *rekey))ike_keys;
this->public.child_keys = (void(*)(bus_t*, child_sa_t *child_sa, diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r))child_keys;
this->public.ike_updown = (void(*)(bus_t*, ike_sa_t *ike_sa, bool up))ike_updown;
this->public.ike_rekey = (void(*)(bus_t*, ike_sa_t *old, ike_sa_t *new))ike_rekey;
this->public.child_updown = (void(*)(bus_t*, child_sa_t *child_sa, bool up))child_updown;
this->public.child_rekey = (void(*)(bus_t*, child_sa_t *old, child_sa_t *new))child_rekey;
this->public.authorize = (bool(*)(bus_t*, bool final))authorize;
this->public.destroy = (void(*)(bus_t*)) destroy;
this->listeners = linked_list_create();
this->mutex = mutex_create(MUTEX_TYPE_RECURSIVE);
this->thread_sa = thread_value_create(NULL);
return &this->public;
}
+338
View File
@@ -0,0 +1,338 @@
/*
* Copyright (C) 2006-2009 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup bus bus
* @{ @ingroup charon
*/
#ifndef BUS_H_
#define BUS_H_
typedef enum debug_t debug_t;
typedef enum level_t level_t;
typedef enum alert_t alert_t;
typedef struct bus_t bus_t;
#include <stdarg.h>
#include <sa/ike_sa.h>
#include <sa/child_sa.h>
#include <processing/jobs/job.h>
#include <bus/listeners/listener.h>
/**
* Debug message group.
*/
enum debug_t {
/** daemon main loop */
DBG_DMN,
/** IKE_SA_MANAGER */
DBG_MGR,
/** IKE_SA */
DBG_IKE,
/** CHILD_SA */
DBG_CHD,
/** job processing */
DBG_JOB,
/** configuration backends */
DBG_CFG,
/** kernel interface */
DBG_KNL,
/** networking/sockets */
DBG_NET,
/** message encoding/decoding */
DBG_ENC,
/** libstrongswan via logging hook */
DBG_LIB,
/** number of groups */
DBG_MAX,
/** pseudo group with all groups */
DBG_ANY = DBG_MAX,
};
/**
* short names of debug message group.
*/
extern enum_name_t *debug_names;
/**
* short names of debug message group, lower case.
*/
extern enum_name_t *debug_lower_names;
/**
* Debug levels used to control output verbosity.
*/
enum level_t {
/** absolutely silent */
LEVEL_SILENT = -1,
/** most important auditing logs */
LEVEL_AUDIT = 0,
/** control flow */
LEVEL_CTRL = 1,
/** diagnose problems */
LEVEL_DIAG = 2,
/** raw binary blobs */
LEVEL_RAW = 3,
/** including sensitive data (private keys) */
LEVEL_PRIVATE = 4,
};
#ifndef DEBUG_LEVEL
# define DEBUG_LEVEL 4
#endif /* DEBUG_LEVEL */
#if DEBUG_LEVEL >= 0
#define DBG0(group, format, ...) charon->bus->log(charon->bus, group, 0, format, ##__VA_ARGS__)
#endif /* DEBUG_LEVEL >= 0 */
#if DEBUG_LEVEL >= 1
#define DBG1(group, format, ...) charon->bus->log(charon->bus, group, 1, format, ##__VA_ARGS__)
#endif /* DEBUG_LEVEL >= 1 */
#if DEBUG_LEVEL >= 2
#define DBG2(group, format, ...) charon->bus->log(charon->bus, group, 2, format, ##__VA_ARGS__)
#endif /* DEBUG_LEVEL >= 2 */
#if DEBUG_LEVEL >= 3
#define DBG3(group, format, ...) charon->bus->log(charon->bus, group, 3, format, ##__VA_ARGS__)
#endif /* DEBUG_LEVEL >= 3 */
#if DEBUG_LEVEL >= 4
#define DBG4(group, format, ...) charon->bus->log(charon->bus, group, 4, format, ##__VA_ARGS__)
#endif /* DEBUG_LEVEL >= 4 */
#ifndef DBG0
# define DBG0(...) {}
#endif /* DBG0 */
#ifndef DBG1
# define DBG1(...) {}
#endif /* DBG1 */
#ifndef DBG2
# define DBG2(...) {}
#endif /* DBG2 */
#ifndef DBG3
# define DBG3(...) {}
#endif /* DBG3 */
#ifndef DBG4
# define DBG4(...) {}
#endif /* DBG4 */
/**
* Kind of alerts to raise.
*/
enum alert_t {
/* a RADIUS server did not respond, no additional arguments */
ALERT_RADIUS_NOT_RESPONDING,
/* a shutdown signal has been received, argument is a int with the signal */
ALERT_SHUTDOWN_SIGNAL,
};
/**
* The bus receives events and sends them to all registered listeners.
*
* Any events sent to are delivered to all registered listeners. Threads
* may wait actively to events using the blocking listen() call.
*/
struct bus_t {
/**
* Register a listener to the bus.
*
* A registered listener receives all events which are sent to the bus.
* The listener is passive; the thread which emitted the event
* processes the listener routine.
*
* @param listener listener to register.
*/
void (*add_listener) (bus_t *this, listener_t *listener);
/**
* Unregister a listener from the bus.
*
* @param listener listener to unregister.
*/
void (*remove_listener) (bus_t *this, listener_t *listener);
/**
* Register a listener and block the calling thread.
*
* This call registers a listener and blocks the calling thread until
* its listeners function returns FALSE. This allows to wait for certain
* events. The associated job is executed after the listener has been
* registered: This allows to listen on events we initiate with the job,
* without missing any events to job may fire.
*
* @param listener listener to register
* @param job job to execute asynchronously when registered, or NULL
*/
void (*listen)(bus_t *this, listener_t *listener, job_t *job);
/**
* Set the IKE_SA the calling thread is using.
*
* To associate an received log message to an IKE_SA without passing it as
* parameter each time, the thread registers the currenlty used IKE_SA
* during check-out. Before check-in, the thread unregisters the IKE_SA.
* This IKE_SA is stored per-thread, so each thread has its own IKE_SA
* registered.
*
* @param ike_sa ike_sa to register, or NULL to unregister
*/
void (*set_sa) (bus_t *this, ike_sa_t *ike_sa);
/**
* Get the IKE_SA the calling thread is currently using.
*
* If a thread currently does not know what IKE_SA it is processing,
* it can call get_sa() to look up the SA set during checkout via set_sa().
*
* @return registered ike_sa, NULL if none registered
*/
ike_sa_t* (*get_sa)(bus_t *this);
/**
* Send a log message to the bus.
*
* The signal specifies the type of the event occured. The format string
* specifies an additional informational or error message with a
* printf() like variable argument list.
* Use the DBG() macros.
*
* @param group debugging group
* @param level verbosity level of the signal
* @param format printf() style format string
* @param ... printf() style argument list
*/
void (*log)(bus_t *this, debug_t group, level_t level, char* format, ...);
/**
* Send a log message to the bus using va_list arguments.
*
* Same as bus_t.signal(), but uses va_list argument list.
*
* @param group kind of the signal (up, down, rekeyed, ...)
* @param level verbosity level of the signal
* @param format printf() style format string
* @param args va_list arguments
*/
void (*vlog)(bus_t *this, debug_t group, level_t level,
char* format, va_list args);
/**
* Raise an alert over the bus.
*
* @param alert kind of alert
* @param ... alert specific attributes
*/
void (*alert)(bus_t *this, alert_t alert, ...);
/**
* Send a IKE_SA state change event to the bus.
*
* @param ike_sa IKE_SA which changes its state
* @param state new state IKE_SA changes to
*/
void (*ike_state_change)(bus_t *this, ike_sa_t *ike_sa,
ike_sa_state_t state);
/**
* Send a CHILD_SA state change event to the bus.
*
* @param child_sa CHILD_SA which changes its state
* @param state new state CHILD_SA changes to
*/
void (*child_state_change)(bus_t *this, child_sa_t *child_sa,
child_sa_state_t state);
/**
* Message send/receive hook.
*
* @param message message to send/receive
* @param incoming TRUE for incoming messages, FALSE for outgoing
*/
void (*message)(bus_t *this, message_t *message, bool incoming);
/**
* IKE_SA authorization hook.
*
* @param final TRUE if this is the final invocation
* @return TRUE to establish IKE_SA, FALSE to send AUTH_FAILED
*/
bool (*authorize)(bus_t *this, bool final);
/**
* IKE_SA keymat hook.
*
* @param ike_sa IKE_SA this keymat belongs to
* @param dh diffie hellman shared secret
* @param nonce_i initiators nonce
* @param nonce_r responders nonce
* @param rekey IKE_SA we are rekeying, if any
*/
void (*ike_keys)(bus_t *this, ike_sa_t *ike_sa, diffie_hellman_t *dh,
chunk_t nonce_i, chunk_t nonce_r, ike_sa_t *rekey);
/**
* CHILD_SA keymat hook.
*
* @param child_sa CHILD_SA this keymat is used for
* @param dh diffie hellman shared secret
* @param nonce_i initiators nonce
* @param nonce_r responders nonce
*/
void (*child_keys)(bus_t *this, child_sa_t *child_sa, diffie_hellman_t *dh,
chunk_t nonce_i, chunk_t nonce_r);
/**
* IKE_SA up/down hook.
*
* @param ike_sa IKE_SA coming up/going down
* @param up TRUE for an up event, FALSE for a down event
*/
void (*ike_updown)(bus_t *this, ike_sa_t *ike_sa, bool up);
/**
* IKE_SA rekeying hook.
*
* @param old rekeyed and obsolete IKE_SA
* @param new new IKE_SA replacing old
*/
void (*ike_rekey)(bus_t *this, ike_sa_t *old, ike_sa_t *new);
/**
* CHILD_SA up/down hook.
*
* @param child_sa CHILD_SA coming up/going down
* @param up TRUE for an up event, FALSE for a down event
*/
void (*child_updown)(bus_t *this, child_sa_t *child_sa, bool up);
/**
* CHILD_SA rekeying hook.
*
* @param old rekeyed and obsolete CHILD_SA
* @param new new CHILD_SA replacing old
*/
void (*child_rekey)(bus_t *this, child_sa_t *old, child_sa_t *new);
/**
* Destroy the event bus.
*/
void (*destroy) (bus_t *this);
};
/**
* Create the event bus which forwards events to its listeners.
*
* @return event bus instance
*/
bus_t *bus_create();
#endif /** BUS_H_ @}*/
+125
View File
@@ -0,0 +1,125 @@
/*
* Copyright (C) 2006 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <stdio.h>
#include <string.h>
#include "file_logger.h"
typedef struct private_file_logger_t private_file_logger_t;
/**
* Private data of a file_logger_t object
*/
struct private_file_logger_t {
/**
* Public data.
*/
file_logger_t public;
/**
* output file
*/
FILE *out;
/**
* Maximum level to log, for each group
*/
level_t levels[DBG_MAX];
};
/**
* Implementation of bus_listener_t.log.
*/
static bool log_(private_file_logger_t *this, debug_t group, level_t level,
int thread, ike_sa_t* ike_sa, char *format, va_list args)
{
if (level <= this->levels[group])
{
char buffer[8192];
char *current = buffer, *next;
/* write in memory buffer first */
vsnprintf(buffer, sizeof(buffer), format, args);
/* prepend a prefix in front of every line */
while (current)
{
next = strchr(current, '\n');
if (next)
{
*(next++) = '\0';
}
fprintf(this->out, "%.2d[%N] %s\n",
thread, debug_names, group, current);
current = next;
}
}
/* always stay registered */
return TRUE;
}
/**
* Implementation of file_logger_t.set_level.
*/
static void set_level(private_file_logger_t *this, debug_t group, level_t level)
{
if (group < DBG_ANY)
{
this->levels[group] = level;
}
else
{
for (group = 0; group < DBG_MAX; group++)
{
this->levels[group] = level;
}
}
}
/**
* Implementation of file_logger_t.destroy.
*/
static void destroy(private_file_logger_t *this)
{
if (this->out != stdout && this->out != stderr)
{
fclose(this->out);
}
free(this);
}
/*
* Described in header.
*/
file_logger_t *file_logger_create(FILE *out)
{
private_file_logger_t *this = malloc_thing(private_file_logger_t);
/* public functions */
memset(&this->public.listener, 0, sizeof(listener_t));
this->public.listener.log = (bool(*)(listener_t*,debug_t,level_t,int,ike_sa_t*,char*,va_list))log_;
this->public.set_level = (void(*)(file_logger_t*,debug_t,level_t))set_level;
this->public.destroy = (void(*)(file_logger_t*))destroy;
/* private variables */
this->out = out;
set_level(this, DBG_ANY, LEVEL_SILENT);
return &this->public;
}
+60
View File
@@ -0,0 +1,60 @@
/*
* Copyright (C) 2006 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup file_logger file_logger
* @{ @ingroup listeners
*/
#ifndef FILE_LOGGER_H_
#define FILE_LOGGER_H_
#include <bus/listeners/listener.h>
typedef struct file_logger_t file_logger_t;
/**
* Logger to files which implements listener_t.
*/
struct file_logger_t {
/**
* Implements the listener_t interface.
*/
listener_t listener;
/**
* Set the loglevel for a debug group.
*
* @param group debug group to set
* @param level max level to log (0..4)
*/
void (*set_level) (file_logger_t *this, debug_t group, level_t level);
/**
* Destroys a file_logger_t object.
*/
void (*destroy) (file_logger_t *this);
};
/**
* Constructor to create a file_logger_t object.
*
* @param out FILE to write to
* @return file_logger_t object
*/
file_logger_t *file_logger_create(FILE *out);
#endif /** FILE_LOGGER_H_ @}*/
+178
View File
@@ -0,0 +1,178 @@
/*
* Copyright (C) 2009 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup listener listener
* @{ @ingroup listeners
*/
#ifndef LISTENER_H_
#define LISTENER_H_
typedef struct listener_t listener_t;
#include <bus/bus.h>
/**
* Listener interface, listens to events if registered to the bus.
*/
struct listener_t {
/**
* Log a debugging message.
*
* The implementing signal function returns TRUE to stay registered
* to the bus, or FALSE to unregister itself.
* Calling bus_t.log() inside of a registered listener is possible,
* but the bus does not invoke listeners recursively.
*
* @param group kind of the signal (up, down, rekeyed, ...)
* @param level verbosity level of the signal
* @param thread ID of the thread raised this signal
* @param ike_sa IKE_SA associated to the event
* @param format printf() style format string
* @param args vprintf() style va_list argument list
" @return TRUE to stay registered, FALSE to unregister
*/
bool (*log)(listener_t *this, debug_t group, level_t level, int thread,
ike_sa_t *ike_sa, char* format, va_list args);
/**
* Hook called if a critical alert is risen.
*
* @param ike_sa IKE_SA associated to the alert, if any
* @param alert kind of alert
* @param ... alert specific argument list
" @return TRUE to stay registered, FALSE to unregister
*/
bool (*alert)(listener_t *this, ike_sa_t *ike_sa,
alert_t alert, va_list args);
/**
* Handle state changes in an IKE_SA.
*
* @param ike_sa IKE_SA which changes its state
* @param state new IKE_SA state this IKE_SA changes to
* @return TRUE to stay registered, FALSE to unregister
*/
bool (*ike_state_change)(listener_t *this, ike_sa_t *ike_sa,
ike_sa_state_t state);
/**
* Handle state changes in a CHILD_SA.
*
* @param ike_sa IKE_SA containing the affected CHILD_SA
* @param child_sa CHILD_SA which changes its state
* @param state new CHILD_SA state this CHILD_SA changes to
* @return TRUE to stay registered, FALSE to unregister
*/
bool (*child_state_change)(listener_t *this, ike_sa_t *ike_sa,
child_sa_t *child_sa, child_sa_state_t state);
/**
* Hook called for received/sent messages of an IKE_SA.
*
* @param ike_sa IKE_SA sending/receving a message
* @param message message object
* @param incoming TRUE for incoming messages, FALSE for outgoing
* @return TRUE to stay registered, FALSE to unregister
*/
bool (*message)(listener_t *this, ike_sa_t *ike_sa, message_t *message,
bool incoming);
/**
* Hook called with IKE_SA key material.
*
* @param ike_sa IKE_SA this keymat belongs to
* @param dh diffie hellman shared secret
* @param nonce_i initiators nonce
* @param nonce_r responders nonce
* @param rekey IKE_SA we are rekeying, if any
* @return TRUE to stay registered, FALSE to unregister
*/
bool (*ike_keys)(listener_t *this, ike_sa_t *ike_sa, diffie_hellman_t *dh,
chunk_t nonce_i, chunk_t nonce_r, ike_sa_t *rekey);
/**
* Hook called with CHILD_SA key material.
*
* @param ike_sa IKE_SA the child sa belongs to
* @param child_sa CHILD_SA this keymat is used for
* @param dh diffie hellman shared secret
* @param nonce_i initiators nonce
* @param nonce_r responders nonce
* @return TRUE to stay registered, FALSE to unregister
*/
bool (*child_keys)(listener_t *this, ike_sa_t *ike_sa, child_sa_t *child_sa,
diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r);
/**
* Hook called if an IKE_SA gets up or down.
*
* @param ike_sa IKE_SA coming up/going down
* @param up TRUE for an up event, FALSE for a down event
* @return TRUE to stay registered, FALSE to unregister
*/
bool (*ike_updown)(listener_t *this, ike_sa_t *ike_sa, bool up);
/**
* Hook called when an IKE_SA gets rekeyed.
*
* @param old rekeyed IKE_SA getting obsolete
* @param new new IKE_SA replacing old
* @return TRUE to stay registered, FALSE to unregister
*/
bool (*ike_rekey)(listener_t *this, ike_sa_t *old, ike_sa_t *new);
/**
* Hook called when a CHILD_SA gets up or down.
*
* @param ike_sa IKE_SA containing the handled CHILD_SA
* @param child_sa CHILD_SA coming up/going down
* @param up TRUE for an up event, FALSE for a down event
* @return TRUE to stay registered, FALSE to unregister
*/
bool (*child_updown)(listener_t *this, ike_sa_t *ike_sa,
child_sa_t *child_sa, bool up);
/**
* Hook called when an CHILD_SA gets rekeyed.
*
* @param ike_sa IKE_SA containing the rekeyed CHILD_SA
* @param old rekeyed CHILD_SA getting obsolete
* @param new new CHILD_SA replacing old
* @return TRUE to stay registered, FALSE to unregister
*/
bool (*child_rekey)(listener_t *this, ike_sa_t *ike_sa,
child_sa_t *old, child_sa_t *new);
/**
* Hook called to invoke additional authorization rules.
*
* An authorization hook gets invoked several times: After each
* authentication round, the hook gets invoked with with final = FALSE.
* After authentication is complete and the peer configuration is selected,
* it is invoked again, but with final = TRUE.
*
* @param ike_sa IKE_SA to authorize
* @param final TRUE if this is the final hook invocation
* @param success set to TRUE to complete IKE_SA, FALSE abort
* @return TRUE to stay registered, FALSE to unregister
*/
bool (*authorize)(listener_t *this, ike_sa_t *ike_sa,
bool final, bool *success);
};
#endif /** LISTENER_H_ @}*/
+121
View File
@@ -0,0 +1,121 @@
/*
* Copyright (C) 2006 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <stdio.h>
#include <string.h>
#include "sys_logger.h"
typedef struct private_sys_logger_t private_sys_logger_t;
/**
* Private data of a sys_logger_t object
*/
struct private_sys_logger_t {
/**
* Public data.
*/
sys_logger_t public;
/**
* syslog facility to use
*/
int facility;
/**
* Maximum level to log, for each group
*/
level_t levels[DBG_MAX];
};
/**
* Implementation of listener_t.log.
*/
static bool log_(private_sys_logger_t *this, debug_t group, level_t level,
int thread, ike_sa_t* ike_sa, char *format, va_list args)
{
if (level <= this->levels[group])
{
char buffer[8192];
char *current = buffer, *next;
/* write in memory buffer first */
vsnprintf(buffer, sizeof(buffer), format, args);
/* do a syslog with every line */
while (current)
{
next = strchr(current, '\n');
if (next)
{
*(next++) = '\0';
}
syslog(this->facility|LOG_INFO, "%.2d[%N] %s\n",
thread, debug_names, group, current);
current = next;
}
}
/* always stay registered */
return TRUE;
}
/**
* Implementation of sys_logger_t.set_level.
*/
static void set_level(private_sys_logger_t *this, debug_t group, level_t level)
{
if (group < DBG_ANY)
{
this->levels[group] = level;
}
else
{
for (group = 0; group < DBG_MAX; group++)
{
this->levels[group] = level;
}
}
}
/**
* Implementation of sys_logger_t.destroy.
*/
static void destroy(private_sys_logger_t *this)
{
closelog();
free(this);
}
/*
* Described in header.
*/
sys_logger_t *sys_logger_create(int facility)
{
private_sys_logger_t *this = malloc_thing(private_sys_logger_t);
/* public functions */
memset(&this->public.listener, 0, sizeof(listener_t));
this->public.listener.log = (bool(*)(listener_t*,debug_t,level_t,int,ike_sa_t*,char*,va_list))log_;
this->public.set_level = (void(*)(sys_logger_t*,debug_t,level_t))set_level;
this->public.destroy = (void(*)(sys_logger_t*))destroy;
/* private variables */
this->facility = facility;
set_level(this, DBG_ANY, LEVEL_SILENT);
return &this->public;
}
+62
View File
@@ -0,0 +1,62 @@
/*
* Copyright (C) 2006 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup sys_logger sys_logger
* @{ @ingroup listeners
*/
#ifndef SYS_LOGGER_H_
#define SYS_LOGGER_H_
#include <syslog.h>
#include <bus/listeners/listener.h>
typedef struct sys_logger_t sys_logger_t;
/**
* Logger for syslog which implements listener_t.
*/
struct sys_logger_t {
/**
* Implements the listener_t interface.
*/
listener_t listener;
/**
* Set the loglevel for a debug group.
*
* @param group debug group to set
* @param level max level to log (0..4)
*/
void (*set_level) (sys_logger_t *this, debug_t group, level_t level);
/**
* Destroys a sys_logger_t object.
*/
void (*destroy) (sys_logger_t *this);
};
/**
* Constructor to create a sys_logger_t object.
*
* @param facility syslog facility to use
* @return sys_logger_t object
*/
sys_logger_t *sys_logger_create(int facility);
#endif /** SYS_LOGGER_H_ @}*/
+768
View File
@@ -0,0 +1,768 @@
/*
* Copyright (C) 2007-2009 Martin Willi
* Copyright (C) 2008 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "auth_cfg.h"
#include <daemon.h>
#include <utils/linked_list.h>
#include <utils/identification.h>
#include <credentials/certificates/certificate.h>
ENUM(auth_rule_names, AUTH_RULE_IDENTITY, AUTH_HELPER_SUBJECT_HASH_URL,
"RULE_IDENTITY",
"RULE_AUTH_CLASS",
"RULE_EAP_IDENTITY",
"RULE_EAP_TYPE",
"RULE_EAP_VENDOR",
"RULE_CA_CERT",
"RULE_IM_CERT",
"RULE_SUBJECT_CERT",
"RULE_CRL_VALIDATION",
"RULE_OCSP_VALIDATION",
"RULE_AC_GROUP",
"HELPER_IM_CERT",
"HELPER_SUBJECT_CERT",
"HELPER_IM_HASH_URL",
"HELPER_SUBJECT_HASH_URL",
);
typedef struct private_auth_cfg_t private_auth_cfg_t;
/**
* private data of item_set
*/
struct private_auth_cfg_t {
/**
* public functions
*/
auth_cfg_t public;
/**
* list of entry_t
*/
linked_list_t *entries;
};
typedef struct entry_t entry_t;
struct entry_t {
/** rule type */
auth_rule_t type;
/** associated value */
void *value;
};
/**
* enumerator for auth_cfg_t.create_enumerator()
*/
typedef struct {
/** implements enumerator_t */
enumerator_t public;
/** inner enumerator from linked_list_t */
enumerator_t *inner;
/** current entry */
entry_t *current;
} entry_enumerator_t;
/**
* enumerate function for item_enumerator_t
*/
static bool enumerate(entry_enumerator_t *this, auth_rule_t *type, void **value)
{
entry_t *entry;
if (this->inner->enumerate(this->inner, &entry))
{
this->current = entry;
*type = entry->type;
*value = entry->value;
return TRUE;
}
return FALSE;
}
/**
* destroy function for item_enumerator_t
*/
static void entry_enumerator_destroy(entry_enumerator_t *this)
{
this->inner->destroy(this->inner);
free(this);
}
/**
* Implementation of auth_cfg_t.create_enumerator.
*/
static enumerator_t* create_enumerator(private_auth_cfg_t *this)
{
entry_enumerator_t *enumerator;
enumerator = malloc_thing(entry_enumerator_t);
enumerator->inner = this->entries->create_enumerator(this->entries);
enumerator->public.enumerate = (void*)enumerate;
enumerator->public.destroy = (void*)entry_enumerator_destroy;
enumerator->current = NULL;
return &enumerator->public;
}
/**
* Destroy the value associated with an entry
*/
static void destroy_entry_value(entry_t *entry)
{
switch (entry->type)
{
case AUTH_RULE_IDENTITY:
case AUTH_RULE_EAP_IDENTITY:
case AUTH_RULE_AC_GROUP:
{
identification_t *id = (identification_t*)entry->value;
id->destroy(id);
break;
}
case AUTH_RULE_CA_CERT:
case AUTH_RULE_IM_CERT:
case AUTH_RULE_SUBJECT_CERT:
case AUTH_HELPER_IM_CERT:
case AUTH_HELPER_SUBJECT_CERT:
{
certificate_t *cert = (certificate_t*)entry->value;
cert->destroy(cert);
break;
}
case AUTH_HELPER_IM_HASH_URL:
case AUTH_HELPER_SUBJECT_HASH_URL:
{
free(entry->value);
break;
}
case AUTH_RULE_AUTH_CLASS:
case AUTH_RULE_EAP_TYPE:
case AUTH_RULE_EAP_VENDOR:
case AUTH_RULE_CRL_VALIDATION:
case AUTH_RULE_OCSP_VALIDATION:
break;
}
}
/**
* Implementation of auth_cfg_t.replace.
*/
static void replace(auth_cfg_t *this, entry_enumerator_t *enumerator,
auth_rule_t type, ...)
{
if (enumerator->current)
{
va_list args;
va_start(args, type);
destroy_entry_value(enumerator->current);
enumerator->current->type = type;
switch (type)
{
case AUTH_RULE_AUTH_CLASS:
case AUTH_RULE_EAP_TYPE:
case AUTH_RULE_EAP_VENDOR:
case AUTH_RULE_CRL_VALIDATION:
case AUTH_RULE_OCSP_VALIDATION:
/* integer type */
enumerator->current->value = (void*)(uintptr_t)va_arg(args, u_int);
break;
case AUTH_RULE_IDENTITY:
case AUTH_RULE_EAP_IDENTITY:
case AUTH_RULE_AC_GROUP:
case AUTH_RULE_CA_CERT:
case AUTH_RULE_IM_CERT:
case AUTH_RULE_SUBJECT_CERT:
case AUTH_HELPER_IM_CERT:
case AUTH_HELPER_SUBJECT_CERT:
case AUTH_HELPER_IM_HASH_URL:
case AUTH_HELPER_SUBJECT_HASH_URL:
/* pointer type */
enumerator->current->value = va_arg(args, void*);
break;
}
va_end(args);
}
}
/**
* Implementation of auth_cfg_t.get.
*/
static void* get(private_auth_cfg_t *this, auth_rule_t type)
{
enumerator_t *enumerator;
void *current_value, *best_value = NULL;
auth_rule_t current_type;
bool found = FALSE;
enumerator = create_enumerator(this);
while (enumerator->enumerate(enumerator, &current_type, &current_value))
{
if (type == current_type)
{
if (type == AUTH_RULE_CRL_VALIDATION ||
type == AUTH_RULE_OCSP_VALIDATION)
{ /* for CRL/OCSP validation, always get() the highest value */
if (!found || current_value > best_value)
{
best_value = current_value;
}
found = TRUE;
continue;
}
best_value = current_value;
found = TRUE;
break;
}
}
enumerator->destroy(enumerator);
if (found)
{
return best_value;
}
switch (type)
{
/* use some sane defaults if we don't find an entry */
case AUTH_RULE_AUTH_CLASS:
return (void*)AUTH_CLASS_ANY;
case AUTH_RULE_EAP_TYPE:
return (void*)EAP_NAK;
case AUTH_RULE_EAP_VENDOR:
return (void*)0;
case AUTH_RULE_CRL_VALIDATION:
case AUTH_RULE_OCSP_VALIDATION:
return (void*)VALIDATION_FAILED;
case AUTH_RULE_IDENTITY:
case AUTH_RULE_EAP_IDENTITY:
case AUTH_RULE_AC_GROUP:
case AUTH_RULE_CA_CERT:
case AUTH_RULE_IM_CERT:
case AUTH_RULE_SUBJECT_CERT:
case AUTH_HELPER_IM_CERT:
case AUTH_HELPER_SUBJECT_CERT:
case AUTH_HELPER_IM_HASH_URL:
case AUTH_HELPER_SUBJECT_HASH_URL:
default:
return NULL;
}
}
/**
* Implementation of auth_cfg_t.add.
*/
static void add(private_auth_cfg_t *this, auth_rule_t type, ...)
{
entry_t *entry = malloc_thing(entry_t);
va_list args;
va_start(args, type);
entry->type = type;
switch (type)
{
case AUTH_RULE_AUTH_CLASS:
case AUTH_RULE_EAP_TYPE:
case AUTH_RULE_EAP_VENDOR:
case AUTH_RULE_CRL_VALIDATION:
case AUTH_RULE_OCSP_VALIDATION:
/* integer type */
entry->value = (void*)(uintptr_t)va_arg(args, u_int);
break;
case AUTH_RULE_IDENTITY:
case AUTH_RULE_EAP_IDENTITY:
case AUTH_RULE_AC_GROUP:
case AUTH_RULE_CA_CERT:
case AUTH_RULE_IM_CERT:
case AUTH_RULE_SUBJECT_CERT:
case AUTH_HELPER_IM_CERT:
case AUTH_HELPER_SUBJECT_CERT:
case AUTH_HELPER_IM_HASH_URL:
case AUTH_HELPER_SUBJECT_HASH_URL:
/* pointer type */
entry->value = va_arg(args, void*);
break;
}
va_end(args);
this->entries->insert_last(this->entries, entry);
}
/**
* Implementation of auth_cfg_t.complies.
*/
static bool complies(private_auth_cfg_t *this, auth_cfg_t *constraints,
bool log_error)
{
enumerator_t *e1, *e2;
bool success = TRUE;
auth_rule_t t1, t2;
void *value;
e1 = constraints->create_enumerator(constraints);
while (e1->enumerate(e1, &t1, &value))
{
switch (t1)
{
case AUTH_RULE_CA_CERT:
case AUTH_RULE_IM_CERT:
{
certificate_t *c1, *c2;
c1 = (certificate_t*)value;
success = FALSE;
e2 = create_enumerator(this);
while (e2->enumerate(e2, &t2, &c2))
{
if ((t2 == AUTH_RULE_CA_CERT || t2 == AUTH_RULE_IM_CERT) &&
c1->equals(c1, c2))
{
success = TRUE;
}
}
e2->destroy(e2);
if (!success && log_error)
{
DBG1(DBG_CFG, "constraint check failed: peer not "
"authenticated by CA '%Y'.", c1->get_subject(c1));
}
break;
}
case AUTH_RULE_SUBJECT_CERT:
{
certificate_t *c1, *c2;
c1 = (certificate_t*)value;
c2 = get(this, AUTH_RULE_SUBJECT_CERT);
if (!c2 || !c1->equals(c1, c2))
{
success = FALSE;
if (log_error)
{
DBG1(DBG_CFG, "constraint check failed: peer not "
"authenticated with peer cert '%Y'.",
c1->get_subject(c1));
}
}
break;
}
case AUTH_RULE_CRL_VALIDATION:
case AUTH_RULE_OCSP_VALIDATION:
{
cert_validation_t validated, required;
required = (uintptr_t)value;
validated = (uintptr_t)get(this, t1);
switch (required)
{
case VALIDATION_FAILED:
/* no constraint */
break;
case VALIDATION_SKIPPED:
if (validated == VALIDATION_SKIPPED)
{
break;
}
/* FALL */
case VALIDATION_GOOD:
if (validated == VALIDATION_GOOD)
{
break;
}
/* FALL */
default:
success = FALSE;
if (log_error)
{
DBG1(DBG_CFG, "constraint check failed: %N is %N, "
"but requires at least %N", auth_rule_names,
t1, cert_validation_names, validated,
cert_validation_names, required);
}
break;
}
break;
}
case AUTH_RULE_IDENTITY:
case AUTH_RULE_EAP_IDENTITY:
{
identification_t *id1, *id2;
id1 = (identification_t*)value;
id2 = get(this, t1);
if (!id2 || !id2->matches(id2, id1))
{
success = FALSE;
if (log_error)
{
DBG1(DBG_CFG, "constraint check failed: %sidentity '%Y'"
" required ", t1 == AUTH_RULE_IDENTITY ? "" :
"EAP ", id1);
}
}
break;
}
case AUTH_RULE_AUTH_CLASS:
{
if ((uintptr_t)value != AUTH_CLASS_ANY &&
(uintptr_t)value != (uintptr_t)get(this, t1))
{
success = FALSE;
if (log_error)
{
DBG1(DBG_CFG, "constraint requires %N authentication, "
"but %N was used", auth_class_names, (uintptr_t)value,
auth_class_names, (uintptr_t)get(this, t1));
}
}
break;
}
case AUTH_RULE_EAP_TYPE:
{
if ((uintptr_t)value != (uintptr_t)get(this, t1))
{
success = FALSE;
if (log_error)
{
DBG1(DBG_CFG, "constraint requires %N, "
"but %N was used", eap_type_names, (uintptr_t)value,
eap_type_names, (uintptr_t)get(this, t1));
}
}
break;
}
case AUTH_RULE_EAP_VENDOR:
{
if ((uintptr_t)value != (uintptr_t)get(this, t1))
{
success = FALSE;
if (log_error)
{
DBG1(DBG_CFG, "constraint requires EAP vendor %d, "
"but %d was used", (uintptr_t)value,
(uintptr_t)get(this, t1));
}
}
break;
}
case AUTH_RULE_AC_GROUP:
{
success = FALSE;
if (log_error)
{
DBG1(DBG_CFG, "constraint check %N not implemented!",
auth_rule_names, t1);
}
break;
}
case AUTH_HELPER_IM_CERT:
case AUTH_HELPER_SUBJECT_CERT:
case AUTH_HELPER_IM_HASH_URL:
case AUTH_HELPER_SUBJECT_HASH_URL:
/* skip helpers */
continue;
}
if (!success)
{
break;
}
}
e1->destroy(e1);
return success;
}
/**
* Implementation of auth_cfg_t.merge.
*/
static void merge(private_auth_cfg_t *this, private_auth_cfg_t *other, bool copy)
{
if (!other)
{ /* nothing to merge */
return;
}
if (copy)
{
enumerator_t *enumerator;
auth_rule_t type;
void *value;
enumerator = create_enumerator(other);
while (enumerator->enumerate(enumerator, &type, &value))
{
switch (type)
{
case AUTH_RULE_CA_CERT:
case AUTH_RULE_IM_CERT:
case AUTH_RULE_SUBJECT_CERT:
case AUTH_HELPER_IM_CERT:
case AUTH_HELPER_SUBJECT_CERT:
{
certificate_t *cert = (certificate_t*)value;
add(this, type, cert->get_ref(cert));
break;
}
case AUTH_RULE_CRL_VALIDATION:
case AUTH_RULE_OCSP_VALIDATION:
case AUTH_RULE_AUTH_CLASS:
case AUTH_RULE_EAP_TYPE:
case AUTH_RULE_EAP_VENDOR:
{
add(this, type, (uintptr_t)value);
break;
}
case AUTH_RULE_IDENTITY:
case AUTH_RULE_EAP_IDENTITY:
case AUTH_RULE_AC_GROUP:
{
identification_t *id = (identification_t*)value;
add(this, type, id->clone(id));
break;
}
case AUTH_HELPER_IM_HASH_URL:
case AUTH_HELPER_SUBJECT_HASH_URL:
{
add(this, type, strdup((char*)value));
break;
}
}
}
enumerator->destroy(enumerator);
}
else
{
entry_t *entry;
while (other->entries->remove_first(other->entries,
(void**)&entry) == SUCCESS)
{
this->entries->insert_last(this->entries, entry);
}
}
}
/**
* Implementation of auth_cfg_t.equals.
*/
static bool equals(private_auth_cfg_t *this, private_auth_cfg_t *other)
{
enumerator_t *e1, *e2;
entry_t *i1, *i2;
bool equal = TRUE, found;
if (this->entries->get_count(this->entries) !=
other->entries->get_count(other->entries))
{
return FALSE;
}
e1 = this->entries->create_enumerator(this->entries);
while (e1->enumerate(e1, &i1))
{
found = FALSE;
e2 = other->entries->create_enumerator(other->entries);
while (e2->enumerate(e2, &i2))
{
if (i1->type == i2->type)
{
switch (i1->type)
{
case AUTH_RULE_AUTH_CLASS:
case AUTH_RULE_EAP_TYPE:
case AUTH_RULE_EAP_VENDOR:
case AUTH_RULE_CRL_VALIDATION:
case AUTH_RULE_OCSP_VALIDATION:
{
if (i1->value == i2->value)
{
found = TRUE;
break;
}
continue;
}
case AUTH_RULE_CA_CERT:
case AUTH_RULE_IM_CERT:
case AUTH_RULE_SUBJECT_CERT:
case AUTH_HELPER_IM_CERT:
case AUTH_HELPER_SUBJECT_CERT:
{
certificate_t *c1, *c2;
c1 = (certificate_t*)i1->value;
c2 = (certificate_t*)i2->value;
if (c1->equals(c1, c2))
{
found = TRUE;
break;
}
continue;
}
case AUTH_RULE_IDENTITY:
case AUTH_RULE_EAP_IDENTITY:
case AUTH_RULE_AC_GROUP:
{
identification_t *id1, *id2;
id1 = (identification_t*)i1->value;
id2 = (identification_t*)i2->value;
if (id1->equals(id1, id2))
{
found = TRUE;
break;
}
continue;
}
case AUTH_HELPER_IM_HASH_URL:
case AUTH_HELPER_SUBJECT_HASH_URL:
{
if (streq(i1->value, i2->value))
{
found = TRUE;
break;
}
continue;
}
}
break;
}
}
e2->destroy(e2);
if (!found)
{
equal = FALSE;
break;
}
}
e1->destroy(e1);
return equal;
}
/**
* Implementation of auth_cfg_t.purge
*/
static void purge(private_auth_cfg_t *this, bool keep_ca)
{
entry_t *entry;
linked_list_t *cas;
cas = linked_list_create();
while (this->entries->remove_last(this->entries, (void**)&entry) == SUCCESS)
{
if (keep_ca && entry->type == AUTH_RULE_CA_CERT)
{
cas->insert_first(cas, entry);
}
else
{
destroy_entry_value(entry);
free(entry);
}
}
while (cas->remove_last(cas, (void**)&entry) == SUCCESS)
{
this->entries->insert_first(this->entries, entry);
}
cas->destroy(cas);
}
/**
* Implementation of auth_cfg_t.clone
*/
static auth_cfg_t* clone_(private_auth_cfg_t *this)
{
enumerator_t *enumerator;
auth_cfg_t *clone;
entry_t *entry;
clone = auth_cfg_create();
enumerator = this->entries->create_enumerator(this->entries);
while (enumerator->enumerate(enumerator, &entry))
{
switch (entry->type)
{
case AUTH_RULE_IDENTITY:
case AUTH_RULE_EAP_IDENTITY:
case AUTH_RULE_AC_GROUP:
{
identification_t *id = (identification_t*)entry->value;
clone->add(clone, entry->type, id->clone(id));
break;
}
case AUTH_RULE_CA_CERT:
case AUTH_RULE_IM_CERT:
case AUTH_RULE_SUBJECT_CERT:
case AUTH_HELPER_IM_CERT:
case AUTH_HELPER_SUBJECT_CERT:
{
certificate_t *cert = (certificate_t*)entry->value;
clone->add(clone, entry->type, cert->get_ref(cert));
break;
}
case AUTH_HELPER_IM_HASH_URL:
case AUTH_HELPER_SUBJECT_HASH_URL:
{
clone->add(clone, entry->type, strdup(entry->value));
break;
}
case AUTH_RULE_AUTH_CLASS:
case AUTH_RULE_EAP_TYPE:
case AUTH_RULE_EAP_VENDOR:
case AUTH_RULE_CRL_VALIDATION:
case AUTH_RULE_OCSP_VALIDATION:
clone->add(clone, entry->type, (uintptr_t)entry->value);
break;
}
}
enumerator->destroy(enumerator);
return clone;
}
/**
* Implementation of auth_cfg_t.destroy
*/
static void destroy(private_auth_cfg_t *this)
{
purge(this, FALSE);
this->entries->destroy(this->entries);
free(this);
}
/*
* see header file
*/
auth_cfg_t *auth_cfg_create()
{
private_auth_cfg_t *this = malloc_thing(private_auth_cfg_t);
this->public.add = (void(*)(auth_cfg_t*, auth_rule_t type, ...))add;
this->public.get = (void*(*)(auth_cfg_t*, auth_rule_t type))get;
this->public.create_enumerator = (enumerator_t*(*)(auth_cfg_t*))create_enumerator;
this->public.replace = (void(*)(auth_cfg_t*,enumerator_t*,auth_rule_t,...))replace;
this->public.complies = (bool(*)(auth_cfg_t*, auth_cfg_t *,bool))complies;
this->public.merge = (void(*)(auth_cfg_t*, auth_cfg_t *other,bool))merge;
this->public.purge = (void(*)(auth_cfg_t*,bool))purge;
this->public.equals = (bool(*)(auth_cfg_t*, auth_cfg_t *other))equals;
this->public.clone = (auth_cfg_t*(*)(auth_cfg_t*))clone_;
this->public.destroy = (void(*)(auth_cfg_t*))destroy;
this->entries = linked_list_create();
return &this->public;
}
+201
View File
@@ -0,0 +1,201 @@
/*
* Copyright (C) 2007-2009 Martin Willi
* Copyright (C) 2008 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup auth_cfg auth_cfg
* @{ @ingroup config
*/
#ifndef AUTH_CFG_H_
#define AUTH_CFG_H_
#include <utils/enumerator.h>
typedef struct auth_cfg_t auth_cfg_t;
typedef enum auth_rule_t auth_rule_t;
/**
* Authentication config to use during authentication process.
*
* Each authentication config contains a set of rules. These rule-sets are used
* in two ways:
* - For configs specifying local authentication behavior, the rules define
* which authentication method in which way.
* - For configs specifying remote peer authentication, the rules define
* constraints the peer has to fullfill.
*
* Additionally to the rules, there is a set of helper items. These are used
* to transport credentials during the authentication process.
*/
enum auth_rule_t {
/** identity to use for IKEv2 authentication exchange, identification_t* */
AUTH_RULE_IDENTITY,
/** authentication class, auth_class_t */
AUTH_RULE_AUTH_CLASS,
/** EAP identity to use within EAP-Identity exchange, identification_t* */
AUTH_RULE_EAP_IDENTITY,
/** EAP type to propose for peer authentication, eap_type_t */
AUTH_RULE_EAP_TYPE,
/** EAP vendor for vendor specific type, u_int32_t */
AUTH_RULE_EAP_VENDOR,
/** certificate authority, certificate_t* */
AUTH_RULE_CA_CERT,
/** intermediate certificate in trustchain, certificate_t* */
AUTH_RULE_IM_CERT,
/** subject certificate, certificate_t* */
AUTH_RULE_SUBJECT_CERT,
/** result of a CRL validation, cert_validation_t */
AUTH_RULE_CRL_VALIDATION,
/** result of a OCSP validation, cert_validation_t */
AUTH_RULE_OCSP_VALIDATION,
/** subject is in attribute certificate group, identification_t* */
AUTH_RULE_AC_GROUP,
/** intermediate certificate, certificate_t* */
AUTH_HELPER_IM_CERT,
/** subject certificate, certificate_t* */
AUTH_HELPER_SUBJECT_CERT,
/** Hash and URL of a intermediate certificate, char* */
AUTH_HELPER_IM_HASH_URL,
/** Hash and URL of a end-entity certificate, char* */
AUTH_HELPER_SUBJECT_HASH_URL,
};
/**
* enum name for auth_rule_t.
*/
extern enum_name_t *auth_rule_names;
/**
* Authentication/Authorization round.
*
* RFC4739 defines multiple authentication rounds. This class defines such
* a round from a configuration perspective, either for the local or the remote
* peer. Local config are called "rulesets", as they define how we authenticate.
* Remote peer configs are called "constraits", they define what is needed to
* complete the authentication round successfully.
*
* @verbatim
[Repeat for each configuration]
+--------------------------------------------------+
| |
| |
| +----------+ IKE_AUTH +--------- + |
| | config | -----------> | | |
| | ruleset | | | |
| +----------+ [ <----------- ] | | |
| [ optional EAP ] | Peer | |
| +----------+ [ -----------> ] | | |
| | config | | | |
| | constr. | <----------- | | |
| +----------+ IKE_AUTH +--------- + |
| |
| |
+--------------------------------------------------+
@endverbatim
*
* Values for each items are either pointers (casted to void*) or short
* integers (use uintptr_t cast).
*/
struct auth_cfg_t {
/**
* Add an rule to the set.
*
* @param rule rule type
* @param ... associated value to rule
*/
void (*add)(auth_cfg_t *this, auth_rule_t rule, ...);
/**
* Get an rule value.
*
* @param rule rule type
* @return bool if item has been found
*/
void* (*get)(auth_cfg_t *this, auth_rule_t rule);
/**
* Create an enumerator over added rules.
*
* @return enumerator over (auth_rule_t, union{void*,uintpr_t})
*/
enumerator_t* (*create_enumerator)(auth_cfg_t *this);
/**
* Replace an rule at enumerator position.
*
* @param pos enumerator position position
* @param rule rule type
* @param ... associated value to rule
*/
void (*replace)(auth_cfg_t *this, enumerator_t *pos,
auth_rule_t rule, ...);
/**
* Check if a used config fulfills a set of configured constraints.
*
* @param constraints required authorization rules
* @param log_error wheter to log compliance errors
* @return TRUE if this complies with constraints
*/
bool (*complies)(auth_cfg_t *this, auth_cfg_t *constraints, bool log_error);
/**
* Merge items from other into this.
*
* @param other items to read for merge
* @param copy TRUE to copy items, FALSE to move them
*/
void (*merge)(auth_cfg_t *this, auth_cfg_t *other, bool copy);
/**
* Purge all rules in a config.
*
* @param keep_ca wheter to keep AUTH_RULE_CA_CERT entries
*/
void (*purge)(auth_cfg_t *this, bool keep_ca);
/**
* Check two configs for equality.
*
* @param other other config to compaire against this
* @return TRUE if auth infos identical
*/
bool (*equals)(auth_cfg_t *this, auth_cfg_t *other);
/**
* Clone a authentication config, including all rules.
*
* @return cloned configuration
*/
auth_cfg_t* (*clone)(auth_cfg_t *this);
/**
* Destroy a config with all associated rules/values.
*/
void (*destroy)(auth_cfg_t *this);
};
/**
* Create a authentication config.
*/
auth_cfg_t *auth_cfg_create();
#endif /** AUTH_CFG_H_ @}*/
+83
View File
@@ -0,0 +1,83 @@
/*
* Copyright (C) 2007-2008 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup backend backend
* @{ @ingroup config
*/
#ifndef BACKEND_H_
#define BACKEND_H_
typedef struct backend_t backend_t;
#include <library.h>
#include <config/ike_cfg.h>
#include <config/peer_cfg.h>
#include <utils/linked_list.h>
/**
* The interface for a configuration backend.
*
* A configuration backend is loaded into the backend_manager. It does the actual
* configuration lookup for the method it implements. See backend_manager_t for
* more information.
*/
struct backend_t {
/**
* Create an enumerator over all IKE configs matching two hosts.
*
* Hosts may be NULL to get all.
*
* There is no requirement for the backend to filter the configurations
* using the supplied hosts; but it may do so if it increases lookup times
* (e.g. include hosts in SQL query).
*
* @param me address of local host
* @param other address of remote host
* @return enumerator over ike_cfg_t's
*/
enumerator_t* (*create_ike_cfg_enumerator)(backend_t *this,
host_t *me, host_t *other);
/**
* Create an enumerator over all peer configs matching two identities.
*
* IDs may be NULL to get all.
*
* As configurations are looked up in the first authentication round (when
* multiple authentication), the backend implementation should compare
* the identities to the first auth_cfgs only.
* There is no requirement for the backend to filter the configurations
* using the supplied identities; but it may do so if it increases lookup
* times (e.g. include hosts in SQL query).
*
* @param me identity of ourself
* @param other identity of remote host
* @return enumerator over peer_cfg_t
*/
enumerator_t* (*create_peer_cfg_enumerator)(backend_t *this,
identification_t *me,
identification_t *other);
/**
* Get a peer_cfg identified by it's name, or a name of its children.
*
* @param name name of peer/child cfg
* @return matching peer_config, or NULL if none found
*/
peer_cfg_t *(*get_peer_cfg_by_name)(backend_t *this, char *name);
};
#endif /** BACKEND_H_ @}*/
+444
View File
@@ -0,0 +1,444 @@
/*
* Copyright (C) 2007-2009 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "backend_manager.h"
#include <sys/types.h>
#include <daemon.h>
#include <utils/linked_list.h>
#include <threading/rwlock.h>
typedef struct private_backend_manager_t private_backend_manager_t;
/**
* Private data of an backend_manager_t object.
*/
struct private_backend_manager_t {
/**
* Public part of backend_manager_t object.
*/
backend_manager_t public;
/**
* list of registered backends
*/
linked_list_t *backends;
/**
* rwlock for backends
*/
rwlock_t *lock;
};
/**
* match of an ike_cfg
*/
typedef enum ike_cfg_match_t {
MATCH_NONE = 0x00,
MATCH_ANY = 0x01,
MATCH_ME = 0x04,
MATCH_OTHER = 0x08,
} ike_cfg_match_t;
/**
* data to pass nested IKE enumerator
*/
typedef struct {
private_backend_manager_t *this;
host_t *me;
host_t *other;
} ike_data_t;
/**
* inner enumerator constructor for IKE cfgs
*/
static enumerator_t *ike_enum_create(backend_t *backend, ike_data_t *data)
{
return backend->create_ike_cfg_enumerator(backend, data->me, data->other);
}
/**
* get a match of a candidate ike_cfg for two hosts
*/
static ike_cfg_match_t get_ike_match(ike_cfg_t *cand, host_t *me, host_t *other)
{
host_t *me_cand, *other_cand;
ike_cfg_match_t match = MATCH_NONE;
if (me)
{
me_cand = host_create_from_dns(cand->get_my_addr(cand),
me->get_family(me), 0);
if (!me_cand)
{
return MATCH_NONE;
}
if (me_cand->ip_equals(me_cand, me))
{
match += MATCH_ME;
}
else if (me_cand->is_anyaddr(me_cand))
{
match += MATCH_ANY;
}
me_cand->destroy(me_cand);
}
else
{
match += MATCH_ANY;
}
if (other)
{
other_cand = host_create_from_dns(cand->get_other_addr(cand),
other->get_family(other), 0);
if (!other_cand)
{
return MATCH_NONE;
}
if (other_cand->ip_equals(other_cand, other))
{
match += MATCH_OTHER;
}
else if (other_cand->is_anyaddr(other_cand))
{
match += MATCH_ANY;
}
other_cand->destroy(other_cand);
}
else
{
match += MATCH_ANY;
}
return match;
}
/**
* implements backend_manager_t.get_ike_cfg.
*/
static ike_cfg_t *get_ike_cfg(private_backend_manager_t *this,
host_t *me, host_t *other)
{
ike_cfg_t *current, *found = NULL;
enumerator_t *enumerator;
ike_cfg_match_t match, best = MATCH_ANY;
ike_data_t *data;
data = malloc_thing(ike_data_t);
data->this = this;
data->me = me;
data->other = other;
DBG2(DBG_CFG, "looking for an ike config for %H...%H", me, other);
this->lock->read_lock(this->lock);
enumerator = enumerator_create_nested(
this->backends->create_enumerator(this->backends),
(void*)ike_enum_create, data, (void*)free);
while (enumerator->enumerate(enumerator, (void**)&current))
{
match = get_ike_match(current, me, other);
if (match)
{
DBG2(DBG_CFG, " candidate: %s...%s, prio %d",
current->get_my_addr(current),
current->get_other_addr(current), match);
if (match > best)
{
DESTROY_IF(found);
found = current;
found->get_ref(found);
best = match;
}
}
}
enumerator->destroy(enumerator);
this->lock->unlock(this->lock);
if (found)
{
DBG2(DBG_CFG, "found matching ike config: %s...%s with prio %d",
found->get_my_addr(found), found->get_other_addr(found), best);
}
return found;
}
/**
* Get the best ID match in one of the configs auth_cfg
*/
static id_match_t get_peer_match(identification_t *id,
peer_cfg_t *cfg, bool local)
{
enumerator_t *enumerator;
auth_cfg_t *auth;
identification_t *candidate;
id_match_t match = ID_MATCH_NONE;
if (!id)
{
return ID_MATCH_ANY;
}
/* compare first auth config only */
enumerator = cfg->create_auth_cfg_enumerator(cfg, local);
if (enumerator->enumerate(enumerator, &auth))
{
candidate = auth->get(auth, AUTH_RULE_IDENTITY);
if (candidate)
{
match = id->matches(id, candidate);
/* match vice-versa, as the proposed IDr might be ANY */
if (!match)
{
match = candidate->matches(candidate, id);
}
}
else
{
match = ID_MATCH_ANY;
}
}
enumerator->destroy(enumerator);
return match;
}
/**
* data to pass nested peer enumerator
*/
typedef struct {
rwlock_t *lock;
identification_t *me;
identification_t *other;
} peer_data_t;
/**
* list element to help sorting
*/
typedef struct {
id_match_t match_peer;
ike_cfg_match_t match_ike;
peer_cfg_t *cfg;
} match_entry_t;
/**
* inner enumerator constructor for peer cfgs
*/
static enumerator_t *peer_enum_create(backend_t *backend, peer_data_t *data)
{
return backend->create_peer_cfg_enumerator(backend, data->me, data->other);
}
/**
* unlock/cleanup peer enumerator
*/
static void peer_enum_destroy(peer_data_t *data)
{
data->lock->unlock(data->lock);
free(data);
}
/**
* convert enumerator value from match_entry to config
*/
static bool peer_enum_filter(linked_list_t *configs,
match_entry_t **in, peer_cfg_t **out)
{
*out = (*in)->cfg;
return TRUE;
}
/**
* Clean up temporary config list
*/
static void peer_enum_filter_destroy(linked_list_t *configs)
{
match_entry_t *entry;
while (configs->remove_last(configs, (void**)&entry) == SUCCESS)
{
entry->cfg->destroy(entry->cfg);
free(entry);
}
configs->destroy(configs);
}
/**
* Insert entry into match-sorted list, using helper
*/
static void insert_sorted(match_entry_t *entry, linked_list_t *list,
linked_list_t *helper)
{
match_entry_t *current;
while (list->remove_first(list, (void**)&current) == SUCCESS)
{
helper->insert_last(helper, current);
}
while (helper->remove_first(helper, (void**)&current) == SUCCESS)
{
if (entry && (
(entry->match_ike > current->match_ike &&
entry->match_peer >= current->match_peer) ||
(entry->match_ike >= current->match_ike &&
entry->match_peer > current->match_peer)))
{
list->insert_last(list, entry);
entry = NULL;
}
list->insert_last(list, current);
}
if (entry)
{
list->insert_last(list, entry);
}
}
/**
* Implements backend_manager_t.create_peer_cfg_enumerator.
*/
static enumerator_t *create_peer_cfg_enumerator(private_backend_manager_t *this,
host_t *me, host_t *other, identification_t *my_id,
identification_t *other_id)
{
enumerator_t *enumerator;
peer_data_t *data;
peer_cfg_t *cfg;
linked_list_t *configs, *helper;
data = malloc_thing(peer_data_t);
data->lock = this->lock;
data->me = my_id;
data->other = other_id;
/* create a sorted list with all matches */
this->lock->read_lock(this->lock);
enumerator = enumerator_create_nested(
this->backends->create_enumerator(this->backends),
(void*)peer_enum_create, data, (void*)peer_enum_destroy);
if (!me && !other && !my_id && !other_id)
{ /* shortcut if we are doing a "listall" */
return enumerator;
}
DBG1(DBG_CFG, "looking for peer configs matching %H[%Y]...%H[%Y]",
me, my_id, other, other_id);
configs = linked_list_create();
/* only once allocated helper list for sorting */
helper = linked_list_create();
while (enumerator->enumerate(enumerator, &cfg))
{
id_match_t match_peer_me, match_peer_other;
ike_cfg_match_t match_ike;
match_entry_t *entry;
match_peer_me = get_peer_match(my_id, cfg, TRUE);
match_peer_other = get_peer_match(other_id, cfg, FALSE);
match_ike = get_ike_match(cfg->get_ike_cfg(cfg), me, other);
if (match_peer_me && match_peer_other && match_ike)
{
DBG2(DBG_CFG, " candidate \"%s\", match: %d/%d/%d (me/other/ike)",
cfg->get_name(cfg), match_peer_me, match_peer_other, match_ike);
entry = malloc_thing(match_entry_t);
entry->match_peer = match_peer_me + match_peer_other;
entry->match_ike = match_ike;
entry->cfg = cfg->get_ref(cfg);
insert_sorted(entry, configs, helper);
}
}
enumerator->destroy(enumerator);
helper->destroy(helper);
return enumerator_create_filter(configs->create_enumerator(configs),
(void*)peer_enum_filter, configs,
(void*)peer_enum_filter_destroy);
}
/**
* implements backend_manager_t.get_peer_cfg_by_name.
*/
static peer_cfg_t *get_peer_cfg_by_name(private_backend_manager_t *this, char *name)
{
backend_t *backend;
peer_cfg_t *config = NULL;
enumerator_t *enumerator;
this->lock->read_lock(this->lock);
enumerator = this->backends->create_enumerator(this->backends);
while (config == NULL && enumerator->enumerate(enumerator, (void**)&backend))
{
config = backend->get_peer_cfg_by_name(backend, name);
}
enumerator->destroy(enumerator);
this->lock->unlock(this->lock);
return config;
}
/**
* Implementation of backend_manager_t.remove_backend.
*/
static void remove_backend(private_backend_manager_t *this, backend_t *backend)
{
this->lock->write_lock(this->lock);
this->backends->remove(this->backends, backend, NULL);
this->lock->unlock(this->lock);
}
/**
* Implementation of backend_manager_t.add_backend.
*/
static void add_backend(private_backend_manager_t *this, backend_t *backend)
{
this->lock->write_lock(this->lock);
this->backends->insert_last(this->backends, backend);
this->lock->unlock(this->lock);
}
/**
* Implementation of backend_manager_t.destroy.
*/
static void destroy(private_backend_manager_t *this)
{
this->backends->destroy(this->backends);
this->lock->destroy(this->lock);
free(this);
}
/*
* Described in header-file
*/
backend_manager_t *backend_manager_create()
{
private_backend_manager_t *this = malloc_thing(private_backend_manager_t);
this->public.get_ike_cfg = (ike_cfg_t* (*)(backend_manager_t*, host_t*, host_t*))get_ike_cfg;
this->public.get_peer_cfg_by_name = (peer_cfg_t* (*)(backend_manager_t*,char*))get_peer_cfg_by_name;
this->public.create_peer_cfg_enumerator = (enumerator_t* (*)(backend_manager_t*,host_t*,host_t*,identification_t*,identification_t*))create_peer_cfg_enumerator;
this->public.add_backend = (void(*)(backend_manager_t*, backend_t *backend))add_backend;
this->public.remove_backend = (void(*)(backend_manager_t*, backend_t *backend))remove_backend;
this->public.destroy = (void (*)(backend_manager_t*))destroy;
this->backends = linked_list_create();
this->lock = rwlock_create(RWLOCK_TYPE_DEFAULT);
return &this->public;
}
+114
View File
@@ -0,0 +1,114 @@
/*
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup backend_manager backend_manager
* @{ @ingroup config
*/
#ifndef BACKEND_MANAGER_H_
#define BACKEND_MANAGER_H_
typedef struct backend_manager_t backend_manager_t;
#include <library.h>
#include <utils/host.h>
#include <utils/identification.h>
#include <config/ike_cfg.h>
#include <config/peer_cfg.h>
#include <config/backend.h>
/**
* A loader and multiplexer to use multiple backends.
*
* Charon allows the use of multiple configuration backends simultaneously. To
* access all this backends by a single call, this class wraps multiple
* backends behind a single object.
* @verbatim
+---------+ +-----------+ +--------------+ |
| | | | +--------------+ | |
| daemon |----->| backend_- | +--------------+ |-+ <==|==> IPC
| core | | manager |---->| backends |-+ |
| |----->| | +--------------+ |
| | | | |
+---------+ +-----------+ |
@endverbatim
*/
struct backend_manager_t {
/**
* Get an ike_config identified by two hosts.
*
* @param my_host address of own host
* @param other_host address of remote host
* @return matching ike_config, or NULL if none found
*/
ike_cfg_t* (*get_ike_cfg)(backend_manager_t *this,
host_t *my_host, host_t *other_host);
/**
* Get a peer_config identified by it's name.
*
* @param name name of the peer_config
* @return matching peer_config, or NULL if none found
*/
peer_cfg_t* (*get_peer_cfg_by_name)(backend_manager_t *this, char *name);
/**
* Create an enumerator over all matching peer configs.
*
* Pass NULL as parameters to match any. The enumerator enumerates over
* peer_cfgs, ordered by priority (best match first).
*
* @param me local address
* @param other remote address
* @param my_id IDr in first authentication round
* @param other_id IDi in first authentication round
* @return enumerator over peer_cfg_t
*/
enumerator_t* (*create_peer_cfg_enumerator)(backend_manager_t *this,
host_t *me, host_t *other, identification_t *my_id,
identification_t *other_id);
/**
* Register a backend on the manager.
*
* @param backend backend to register
*/
void (*add_backend)(backend_manager_t *this, backend_t *backend);
/**
* Unregister a backend.
*
* @param backend backend to unregister
*/
void (*remove_backend)(backend_manager_t *this, backend_t *backend);
/**
* Destroys a backend_manager_t object.
*/
void (*destroy) (backend_manager_t *this);
};
/**
* Create an instance of the backend manager
*
* @return backend_manager instance
*/
backend_manager_t* backend_manager_create(void);
#endif /** BACKEND_MANAGER_H_ @}*/
+552
View File
@@ -0,0 +1,552 @@
/*
* Copyright (C) 2008-2009 Tobias Brunner
* Copyright (C) 2005-2007 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "child_cfg.h"
#include <daemon.h>
ENUM(action_names, ACTION_NONE, ACTION_RESTART,
"clear",
"hold",
"restart",
);
ENUM_BEGIN(ipcomp_transform_names, IPCOMP_NONE, IPCOMP_NONE,
"IPCOMP_NONE");
ENUM_NEXT(ipcomp_transform_names, IPCOMP_OUI, IPCOMP_LZJH, IPCOMP_NONE,
"IPCOMP_OUI",
"IPCOMP_DEFLATE",
"IPCOMP_LZS",
"IPCOMP_LZJH");
ENUM_END(ipcomp_transform_names, IPCOMP_LZJH);
typedef struct private_child_cfg_t private_child_cfg_t;
/**
* Private data of an child_cfg_t object
*/
struct private_child_cfg_t {
/**
* Public part
*/
child_cfg_t public;
/**
* Number of references hold by others to this child_cfg
*/
refcount_t refcount;
/**
* Name of the child_cfg, used to query it
*/
char *name;
/**
* list for all proposals
*/
linked_list_t *proposals;
/**
* list for traffic selectors for my site
*/
linked_list_t *my_ts;
/**
* list for traffic selectors for others site
*/
linked_list_t *other_ts;
/**
* updown script
*/
char *updown;
/**
* allow host access
*/
bool hostaccess;
/**
* Mode to propose for a initiated CHILD: tunnel/transport
*/
ipsec_mode_t mode;
/**
* action to take on DPD
*/
action_t dpd_action;
/**
* action to take on CHILD_SA close
*/
action_t close_action;
/**
* CHILD_SA lifetime config
*/
lifetime_cfg_t lifetime;
/**
* enable IPComp
*/
bool use_ipcomp;
/**
* Inactivity timeout
*/
u_int32_t inactivity;
/**
* set up IPsec transport SA in MIPv6 proxy mode
*/
bool proxy_mode;
/**
* enable installation and removal of kernel IPsec policies
*/
bool install_policy;
};
/**
* Implementation of child_cfg_t.get_name.
*/
static char *get_name(private_child_cfg_t *this)
{
return this->name;
}
/**
* Implementation of child_cfg_t.add_proposal.
*/
static void add_proposal(private_child_cfg_t *this, proposal_t *proposal)
{
this->proposals->insert_last(this->proposals, proposal);
}
/**
* Implementation of child_cfg_t.get_proposals.
*/
static linked_list_t* get_proposals(private_child_cfg_t *this, bool strip_dh)
{
enumerator_t *enumerator;
proposal_t *current;
linked_list_t *proposals = linked_list_create();
enumerator = this->proposals->create_enumerator(this->proposals);
while (enumerator->enumerate(enumerator, &current))
{
current = current->clone(current);
if (strip_dh)
{
current->strip_dh(current);
}
proposals->insert_last(proposals, current);
}
enumerator->destroy(enumerator);
return proposals;
}
/**
* Implementation of child_cfg_t.select_proposal.
*/
static proposal_t* select_proposal(private_child_cfg_t*this,
linked_list_t *proposals, bool strip_dh,
bool private)
{
enumerator_t *stored_enum, *supplied_enum;
proposal_t *stored, *supplied, *selected = NULL;
stored_enum = this->proposals->create_enumerator(this->proposals);
supplied_enum = proposals->create_enumerator(proposals);
/* compare all stored proposals with all supplied. Stored ones are preferred. */
while (stored_enum->enumerate(stored_enum, &stored))
{
stored = stored->clone(stored);
while (supplied_enum->enumerate(supplied_enum, &supplied))
{
if (strip_dh)
{
stored->strip_dh(stored);
}
selected = stored->select(stored, supplied, private);
if (selected)
{
DBG2(DBG_CFG, "received proposals: %#P", proposals);
DBG2(DBG_CFG, "configured proposals: %#P", this->proposals);
DBG2(DBG_CFG, "selected proposal: %P", selected);
break;
}
}
stored->destroy(stored);
if (selected)
{
break;
}
supplied_enum->destroy(supplied_enum);
supplied_enum = proposals->create_enumerator(proposals);
}
stored_enum->destroy(stored_enum);
supplied_enum->destroy(supplied_enum);
if (selected == NULL)
{
DBG1(DBG_CFG, "received proposals: %#P", proposals);
DBG1(DBG_CFG, "configured proposals: %#P", this->proposals);
}
return selected;
}
/**
* Implementation of child_cfg_t.add_traffic_selector.
*/
static void add_traffic_selector(private_child_cfg_t *this, bool local,
traffic_selector_t *ts)
{
if (local)
{
this->my_ts->insert_last(this->my_ts, ts);
}
else
{
this->other_ts->insert_last(this->other_ts, ts);
}
}
/**
* Implementation of child_cfg_t.get_traffic_selectors.
*/
static linked_list_t* get_traffic_selectors(private_child_cfg_t *this, bool local,
linked_list_t *supplied,
host_t *host)
{
enumerator_t *e1, *e2;
traffic_selector_t *ts1, *ts2, *selected;
linked_list_t *result = linked_list_create();
if (local)
{
e1 = this->my_ts->create_enumerator(this->my_ts);
}
else
{
e1 = this->other_ts->create_enumerator(this->other_ts);
}
/* no list supplied, just fetch the stored traffic selectors */
if (supplied == NULL)
{
DBG2(DBG_CFG, "proposing traffic selectors for %s:",
local ? "us" : "other");
while (e1->enumerate(e1, &ts1))
{
/* we make a copy of the TS, this allows us to update dynamic TS' */
selected = ts1->clone(ts1);
if (host)
{
selected->set_address(selected, host);
}
DBG2(DBG_CFG, " %R (derived from %R)", selected, ts1);
result->insert_last(result, selected);
}
e1->destroy(e1);
}
else
{
DBG2(DBG_CFG, "selecting traffic selectors for %s:",
local ? "us" : "other");
e2 = supplied->create_enumerator(supplied);
/* iterate over all stored selectors */
while (e1->enumerate(e1, &ts1))
{
/* we make a copy of the TS, as we have to update dynamic TS' */
ts1 = ts1->clone(ts1);
if (host)
{
ts1->set_address(ts1, host);
}
/* iterate over all supplied traffic selectors */
while (e2->enumerate(e2, &ts2))
{
selected = ts1->get_subset(ts1, ts2);
if (selected)
{
DBG2(DBG_CFG, " config: %R, received: %R => match: %R",
ts1, ts2, selected);
result->insert_last(result, selected);
}
else
{
DBG2(DBG_CFG, " config: %R, received: %R => no match",
ts1, ts2);
}
}
e2->destroy(e2);
e2 = supplied->create_enumerator(supplied);
ts1->destroy(ts1);
}
e1->destroy(e1);
e2->destroy(e2);
}
/* remove any redundant traffic selectors in the list */
e1 = result->create_enumerator(result);
e2 = result->create_enumerator(result);
while (e1->enumerate(e1, &ts1))
{
while (e2->enumerate(e2, &ts2))
{
if (ts1 != ts2)
{
if (ts2->is_contained_in(ts2, ts1))
{
result->remove_at(result, e2);
ts2->destroy(ts2);
e1->destroy(e1);
e1 = result->create_enumerator(result);
break;
}
if (ts1->is_contained_in(ts1, ts2))
{
result->remove_at(result, e1);
ts1->destroy(ts1);
e2->destroy(e2);
e2 = result->create_enumerator(result);
break;
}
}
}
}
e1->destroy(e1);
e2->destroy(e2);
return result;
}
/**
* Implementation of child_cfg_t.get_updown.
*/
static char* get_updown(private_child_cfg_t *this)
{
return this->updown;
}
/**
* Implementation of child_cfg_t.get_hostaccess.
*/
static bool get_hostaccess(private_child_cfg_t *this)
{
return this->hostaccess;
}
/**
* Applies jitter to the rekey value. Returns the new rekey value.
* Note: The distribution of random values is not perfect, but it
* should get the job done.
*/
static u_int64_t apply_jitter(u_int64_t rekey, u_int64_t jitter)
{
if (jitter == 0)
{
return rekey;
}
jitter = (jitter == UINT64_MAX) ? jitter : jitter + 1;
return rekey - jitter * (random() / (RAND_MAX + 1.0));
}
#define APPLY_JITTER(l) l.rekey = apply_jitter(l.rekey, l.jitter)
/**
* Implementation of child_cfg_t.get_lifetime.
*/
static lifetime_cfg_t *get_lifetime(private_child_cfg_t *this)
{
lifetime_cfg_t *lft = malloc_thing(lifetime_cfg_t);
memcpy(lft, &this->lifetime, sizeof(lifetime_cfg_t));
APPLY_JITTER(lft->time);
APPLY_JITTER(lft->bytes);
APPLY_JITTER(lft->packets);
return lft;
}
/**
* Implementation of child_cfg_t.get_mode.
*/
static ipsec_mode_t get_mode(private_child_cfg_t *this)
{
return this->mode;
}
/**
* Implementation of child_cfg_t.get_dpd_action.
*/
static action_t get_dpd_action(private_child_cfg_t *this)
{
return this->dpd_action;
}
/**
* Implementation of child_cfg_t.get_close_action.
*/
static action_t get_close_action(private_child_cfg_t *this)
{
return this->close_action;
}
/**
* Implementation of child_cfg_t.get_dh_group.
*/
static diffie_hellman_group_t get_dh_group(private_child_cfg_t *this)
{
enumerator_t *enumerator;
proposal_t *proposal;
u_int16_t dh_group = MODP_NONE;
enumerator = this->proposals->create_enumerator(this->proposals);
while (enumerator->enumerate(enumerator, &proposal))
{
if (proposal->get_algorithm(proposal, DIFFIE_HELLMAN_GROUP, &dh_group, NULL))
{
break;
}
}
enumerator->destroy(enumerator);
return dh_group;
}
/**
* Implementation of child_cfg_t.use_ipcomp.
*/
static bool use_ipcomp(private_child_cfg_t *this)
{
return this->use_ipcomp;
}
/**
* Implementation of child_cfg_t.get_inactivity.
*/
static u_int32_t get_inactivity(private_child_cfg_t *this)
{
return this->inactivity;
}
/**
* Implementation of child_cfg_t.set_mipv6_options.
*/
static void set_mipv6_options(private_child_cfg_t *this, bool proxy_mode,
bool install_policy)
{
this->proxy_mode = proxy_mode;
this->install_policy = install_policy;
}
/**
* Implementation of child_cfg_t.use_proxy_mode.
*/
static bool use_proxy_mode(private_child_cfg_t *this)
{
return this->proxy_mode;
}
/**
* Implementation of child_cfg_t.install_policy.
*/
static bool install_policy(private_child_cfg_t *this)
{
return this->install_policy;
}
/**
* Implementation of child_cfg_t.get_ref.
*/
static child_cfg_t* get_ref(private_child_cfg_t *this)
{
ref_get(&this->refcount);
return &this->public;
}
/**
* Implements child_cfg_t.destroy.
*/
static void destroy(private_child_cfg_t *this)
{
if (ref_put(&this->refcount))
{
this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy));
this->my_ts->destroy_offset(this->my_ts, offsetof(traffic_selector_t, destroy));
this->other_ts->destroy_offset(this->other_ts, offsetof(traffic_selector_t, destroy));
if (this->updown)
{
free(this->updown);
}
free(this->name);
free(this);
}
}
/*
* Described in header-file
*/
child_cfg_t *child_cfg_create(char *name, lifetime_cfg_t *lifetime,
char *updown, bool hostaccess,
ipsec_mode_t mode, action_t dpd_action,
action_t close_action, bool ipcomp,
u_int32_t inactivity)
{
private_child_cfg_t *this = malloc_thing(private_child_cfg_t);
this->public.get_name = (char* (*) (child_cfg_t*))get_name;
this->public.add_traffic_selector = (void (*)(child_cfg_t*,bool,traffic_selector_t*))add_traffic_selector;
this->public.get_traffic_selectors = (linked_list_t*(*)(child_cfg_t*,bool,linked_list_t*,host_t*))get_traffic_selectors;
this->public.add_proposal = (void (*) (child_cfg_t*,proposal_t*))add_proposal;
this->public.get_proposals = (linked_list_t* (*) (child_cfg_t*,bool))get_proposals;
this->public.select_proposal = (proposal_t* (*) (child_cfg_t*,linked_list_t*,bool,bool))select_proposal;
this->public.get_updown = (char* (*) (child_cfg_t*))get_updown;
this->public.get_hostaccess = (bool (*) (child_cfg_t*))get_hostaccess;
this->public.get_mode = (ipsec_mode_t (*) (child_cfg_t *))get_mode;
this->public.get_dpd_action = (action_t (*) (child_cfg_t *))get_dpd_action;
this->public.get_close_action = (action_t (*) (child_cfg_t *))get_close_action;
this->public.get_lifetime = (lifetime_cfg_t* (*) (child_cfg_t *))get_lifetime;
this->public.get_dh_group = (diffie_hellman_group_t(*)(child_cfg_t*)) get_dh_group;
this->public.set_mipv6_options = (void (*) (child_cfg_t*,bool,bool))set_mipv6_options;
this->public.use_ipcomp = (bool (*) (child_cfg_t *))use_ipcomp;
this->public.get_inactivity = (u_int32_t (*) (child_cfg_t *))get_inactivity;
this->public.use_proxy_mode = (bool (*) (child_cfg_t *))use_proxy_mode;
this->public.install_policy = (bool (*) (child_cfg_t *))install_policy;
this->public.get_ref = (child_cfg_t* (*) (child_cfg_t*))get_ref;
this->public.destroy = (void (*) (child_cfg_t*))destroy;
this->name = strdup(name);
this->updown = updown ? strdup(updown) : NULL;
this->hostaccess = hostaccess;
this->mode = mode;
this->dpd_action = dpd_action;
this->close_action = close_action;
this->use_ipcomp = ipcomp;
this->inactivity = inactivity;
this->proxy_mode = FALSE;
this->install_policy = TRUE;
this->refcount = 1;
this->proposals = linked_list_create();
this->my_ts = linked_list_create();
this->other_ts = linked_list_create();
memcpy(&this->lifetime, lifetime, sizeof(lifetime_cfg_t));
return &this->public;
}
+310
View File
@@ -0,0 +1,310 @@
/*
* Copyright (C) 2008-2009 Tobias Brunner
* Copyright (C) 2005-2007 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup child_cfg child_cfg
* @{ @ingroup config
*/
#ifndef CHILD_CFG_H_
#define CHILD_CFG_H_
typedef enum action_t action_t;
typedef enum ipcomp_transform_t ipcomp_transform_t;
typedef struct lifetime_cfg_t lifetime_cfg_t;
typedef struct child_cfg_t child_cfg_t;
#include <library.h>
#include <selectors/traffic_selector.h>
#include <config/proposal.h>
#include <kernel/kernel_ipsec.h>
/**
* Action to take when DPD detected/connection gets closed by peer.
*/
enum action_t {
/** No action */
ACTION_NONE,
/** Route config to reestablish on demand */
ACTION_ROUTE,
/** Restart config immediately */
ACTION_RESTART,
};
/**
* enum names for action_t.
*/
extern enum_name_t *action_names;
/**
* IPComp transform IDs, as in RFC 4306
*/
enum ipcomp_transform_t {
IPCOMP_NONE = 241,
IPCOMP_OUI = 1,
IPCOMP_DEFLATE = 2,
IPCOMP_LZS = 3,
IPCOMP_LZJH = 4,
};
/**
* enum strings for ipcomp_transform_t.
*/
extern enum_name_t *ipcomp_transform_names;
/**
* A lifetime_cfg_t defines the lifetime limits of a CHILD_SA.
*
* Set any of these values to 0 to ignore.
*/
struct lifetime_cfg_t {
struct {
/** Limit before the CHILD_SA gets invalid. */
u_int64_t life;
/** Limit before the CHILD_SA gets rekeyed. */
u_int64_t rekey;
/** The range of a random value subtracted from rekey. */
u_int64_t jitter;
} time, bytes, packets;
};
/**
* A child_cfg_t defines the config template for a CHILD_SA.
*
* After creation, proposals and traffic selectors may be added to the config.
* A child_cfg object is referenced multiple times, and is not thread save.
* Reading from the object is save, adding things is not allowed while other
* threads may access the object.
* A reference counter handles the number of references hold to this config.
*
* @see peer_cfg_t to get an overview over the configurations.
*/
struct child_cfg_t {
/**
* Get the name of the child_cfg.
*
* @return child_cfg's name
*/
char *(*get_name) (child_cfg_t *this);
/**
* Add a proposal to the list.
*
* The proposals are stored by priority, first added
* is the most prefered.
* After add, proposal is owned by child_cfg.
*
* @param proposal proposal to add
*/
void (*add_proposal) (child_cfg_t *this, proposal_t *proposal);
/**
* Get the list of proposals for the CHILD_SA.
*
* Resulting list and all of its proposals must be freed after use.
*
* @param strip_dh TRUE strip out diffie hellman groups
* @return list of proposals
*/
linked_list_t* (*get_proposals)(child_cfg_t *this, bool strip_dh);
/**
* Select a proposal from a supplied list.
*
* Returned propsal is newly created and must be destroyed after usage.
*
* @param proposals list from from wich proposals are selected
* @param strip_dh TRUE strip out diffie hellman groups
* @param private accept algorithms from a private range
* @return selected proposal, or NULL if nothing matches
*/
proposal_t* (*select_proposal)(child_cfg_t*this, linked_list_t *proposals,
bool strip_dh, bool private);
/**
* Add a traffic selector to the config.
*
* Use the "local" parameter to add it for the local or the remote side.
* After add, traffic selector is owned by child_cfg.
*
* @param local TRUE for local side, FALSE for remote
* @param ts traffic_selector to add
*/
void (*add_traffic_selector)(child_cfg_t *this, bool local,
traffic_selector_t *ts);
/**
* Get a list of traffic selectors to use for the CHILD_SA.
*
* The config contains two set of traffic selectors, one for the local
* side, one for the remote side.
* If a list with traffic selectors is supplied, these are used to narrow
* down the traffic selector list to the greatest common divisor.
* Some traffic selector may be "dymamic", meaning they are narrowed down
* to a specific address (host-to-host or virtual-IP setups). Use
* the "host" parameter to narrow such traffic selectors to that address.
* Resulted list and its traffic selectors must be destroyed after use.
*
* @param local TRUE for TS on local side, FALSE for remote
* @param supplied list with TS to select from, or NULL
* @param host address to use for narrowing "dynamic" TS', or NULL
* @return list containing the traffic selectors
*/
linked_list_t *(*get_traffic_selectors)(child_cfg_t *this, bool local,
linked_list_t *supplied,
host_t *host);
/**
* Get the updown script to run for the CHILD_SA.
*
* @return path to updown script
*/
char* (*get_updown)(child_cfg_t *this);
/**
* Should we allow access to the local host (gateway)?
*
* @return value of hostaccess flag
*/
bool (*get_hostaccess) (child_cfg_t *this);
/**
* Get the lifetime configuration of a CHILD_SA.
*
* The rekey limits automatically contain a jitter to avoid simultaneous
* rekeying. These values will change with each call to this function.
*
* @return lifetime_cfg_t (has to be freed)
*/
lifetime_cfg_t* (*get_lifetime) (child_cfg_t *this);
/**
* Get the mode to use for the CHILD_SA.
*
* The mode is either tunnel, transport or BEET. The peer must agree
* on the method, fallback is tunnel mode.
*
* @return ipsec mode
*/
ipsec_mode_t (*get_mode) (child_cfg_t *this);
/**
* Action to take on DPD.
*
* @return DPD action
*/
action_t (*get_dpd_action) (child_cfg_t *this);
/**
* Action to take if CHILD_SA gets closed.
*
* @return close action
*/
action_t (*get_close_action) (child_cfg_t *this);
/**
* Get the DH group to use for CHILD_SA setup.
*
* @return dh group to use
*/
diffie_hellman_group_t (*get_dh_group)(child_cfg_t *this);
/**
* Check whether IPComp should be used, if the other peer supports it.
*
* @return TRUE, if IPComp should be used
* FALSE, otherwise
*/
bool (*use_ipcomp)(child_cfg_t *this);
/**
* Get the inactivity timeout value.
*
* @return inactivity timeout in s
*/
u_int32_t (*get_inactivity)(child_cfg_t *this);
/**
* Sets two options needed for Mobile IPv6 interoperability
*
* @param proxy_mode use IPsec transport proxy mode (default FALSE)
* @param install_policy install IPsec kernel policies (default TRUE)
*/
void (*set_mipv6_options)(child_cfg_t *this, bool proxy_mode,
bool install_policy);
/**
* Check whether IPsec transport SA should be set up in proxy mode
*
* @return TRUE, if proxy mode should be used
* FALSE, otherwise
*/
bool (*use_proxy_mode)(child_cfg_t *this);
/**
* Check whether IPsec policies should be installed in the kernel
*
* @return TRUE, if IPsec kernel policies should be installed
* FALSE, otherwise
*/
bool (*install_policy)(child_cfg_t *this);
/**
* Increase the reference count.
*
* @return reference to this
*/
child_cfg_t* (*get_ref) (child_cfg_t *this);
/**
* Destroys the child_cfg object.
*
* Decrements the internal reference counter and
* destroys the child_cfg when it reaches zero.
*/
void (*destroy) (child_cfg_t *this);
};
/**
* Create a configuration template for CHILD_SA setup.
*
* The "name" string gets cloned.
*
* The lifetime_cfg_t object gets cloned.
* To prevent two peers to start rekeying at the same time, a jitter may be
* specified. Rekeying of an SA starts at (x.rekey - random(0, x.jitter)).
*
* After a call to create, a reference is obtained (refcount = 1).
*
* @param name name of the child_cfg
* @param lifetime lifetime_cfg_t for this child_cfg
* @param updown updown script to execute on up/down event
* @param hostaccess TRUE to allow access to the local host
* @param mode mode to propose for CHILD_SA, transport, tunnel or BEET
* @param dpd_action DPD action
* @param close_action close action
* @param ipcomp use IPComp, if peer supports it
* @param inactivity inactivity timeout in s before closing a CHILD_SA
* @return child_cfg_t object
*/
child_cfg_t *child_cfg_create(char *name, lifetime_cfg_t *lifetime,
char *updown, bool hostaccess,
ipsec_mode_t mode, action_t dpd_action,
action_t close_action, bool ipcomp,
u_int32_t inactivity);
#endif /** CHILD_CFG_H_ @}*/
+294
View File
@@ -0,0 +1,294 @@
/*
* Copyright (C) 2005-2007 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "ike_cfg.h"
#include <string.h>
#include <daemon.h>
typedef struct private_ike_cfg_t private_ike_cfg_t;
/**
* Private data of an ike_cfg_t object
*/
struct private_ike_cfg_t {
/**
* Public part
*/
ike_cfg_t public;
/**
* Number of references hold by others to this ike_cfg
*/
refcount_t refcount;
/**
* Address of local host
*/
char *me;
/**
* Address of remote host
*/
char *other;
/**
* our source port
*/
u_int16_t my_port;
/**
* destination port
*/
u_int16_t other_port;
/**
* should we send a certificate request?
*/
bool certreq;
/**
* enforce UDP encapsulation
*/
bool force_encap;
/**
* List of proposals to use
*/
linked_list_t *proposals;
};
METHOD(ike_cfg_t, send_certreq, bool,
private_ike_cfg_t *this)
{
return this->certreq;
}
METHOD(ike_cfg_t, force_encap_, bool,
private_ike_cfg_t *this)
{
return this->force_encap;
}
METHOD(ike_cfg_t, get_my_addr, char*,
private_ike_cfg_t *this)
{
return this->me;
}
METHOD(ike_cfg_t, get_other_addr, char*,
private_ike_cfg_t *this)
{
return this->other;
}
METHOD(ike_cfg_t, get_my_port, u_int16_t,
private_ike_cfg_t *this)
{
return this->my_port;
}
METHOD(ike_cfg_t, get_other_port, u_int16_t,
private_ike_cfg_t *this)
{
return this->other_port;
}
METHOD(ike_cfg_t, add_proposal, void,
private_ike_cfg_t *this, proposal_t *proposal)
{
this->proposals->insert_last(this->proposals, proposal);
}
METHOD(ike_cfg_t, get_proposals, linked_list_t*,
private_ike_cfg_t *this)
{
enumerator_t *enumerator;
proposal_t *current;
linked_list_t *proposals;
proposals = linked_list_create();
enumerator = this->proposals->create_enumerator(this->proposals);
while (enumerator->enumerate(enumerator, &current))
{
current = current->clone(current);
proposals->insert_last(proposals, current);
}
enumerator->destroy(enumerator);
return proposals;
}
METHOD(ike_cfg_t, select_proposal, proposal_t*,
private_ike_cfg_t *this, linked_list_t *proposals, bool private)
{
iterator_t *stored_iter, *supplied_iter;
proposal_t *stored, *supplied, *selected;
stored_iter = this->proposals->create_iterator(this->proposals, TRUE);
supplied_iter = proposals->create_iterator(proposals, TRUE);
/* compare all stored proposals with all supplied. Stored ones are preferred.*/
while (stored_iter->iterate(stored_iter, (void**)&stored))
{
supplied_iter->reset(supplied_iter);
while (supplied_iter->iterate(supplied_iter, (void**)&supplied))
{
selected = stored->select(stored, supplied, private);
if (selected)
{
/* they match, return */
stored_iter->destroy(stored_iter);
supplied_iter->destroy(supplied_iter);
DBG2(DBG_CFG, "received proposals: %#P", proposals);
DBG2(DBG_CFG, "configured proposals: %#P", this->proposals);
DBG2(DBG_CFG, "selected proposal: %P", selected);
return selected;
}
}
}
/* no proposal match :-(, will result in a NO_PROPOSAL_CHOSEN... */
stored_iter->destroy(stored_iter);
supplied_iter->destroy(supplied_iter);
DBG1(DBG_CFG, "received proposals: %#P", proposals);
DBG1(DBG_CFG, "configured proposals: %#P", this->proposals);
return NULL;
}
METHOD(ike_cfg_t, get_dh_group, diffie_hellman_group_t,
private_ike_cfg_t *this)
{
enumerator_t *enumerator;
proposal_t *proposal;
u_int16_t dh_group = MODP_NONE;
enumerator = this->proposals->create_enumerator(this->proposals);
while (enumerator->enumerate(enumerator, &proposal))
{
if (proposal->get_algorithm(proposal, DIFFIE_HELLMAN_GROUP, &dh_group, NULL))
{
break;
}
}
enumerator->destroy(enumerator);
return dh_group;
}
METHOD(ike_cfg_t, equals, bool,
private_ike_cfg_t *this, ike_cfg_t *other_public)
{
private_ike_cfg_t *other = (private_ike_cfg_t*)other_public;
enumerator_t *e1, *e2;
proposal_t *p1, *p2;
bool eq = TRUE;
if (this == other)
{
return TRUE;
}
if (this->public.equals != other->public.equals)
{
return FALSE;
}
if (this->proposals->get_count(this->proposals) !=
other->proposals->get_count(other->proposals))
{
return FALSE;
}
e1 = this->proposals->create_enumerator(this->proposals);
e2 = this->proposals->create_enumerator(this->proposals);
while (e1->enumerate(e1, &p1) && e2->enumerate(e2, &p2))
{
if (!p1->equals(p1, p2))
{
eq = FALSE;
break;
}
}
e1->destroy(e1);
e2->destroy(e2);
return (eq &&
this->certreq == other->certreq &&
this->force_encap == other->force_encap &&
streq(this->me, other->me) &&
streq(this->other, other->other) &&
this->my_port == other->my_port &&
this->other_port == other->other_port);
}
METHOD(ike_cfg_t, get_ref, ike_cfg_t*,
private_ike_cfg_t *this)
{
ref_get(&this->refcount);
return &this->public;
}
METHOD(ike_cfg_t, destroy, void,
private_ike_cfg_t *this)
{
if (ref_put(&this->refcount))
{
this->proposals->destroy_offset(this->proposals,
offsetof(proposal_t, destroy));
free(this->me);
free(this->other);
free(this);
}
}
/**
* Described in header.
*/
ike_cfg_t *ike_cfg_create(bool certreq, bool force_encap,
char *me, u_int16_t my_port, char *other, u_int16_t other_port)
{
private_ike_cfg_t *this;
INIT(this,
.public = {
.send_certreq = _send_certreq,
.force_encap = _force_encap_,
.get_my_addr = _get_my_addr,
.get_other_addr = _get_other_addr,
.get_my_port = _get_my_port,
.get_other_port = _get_other_port,
.add_proposal = _add_proposal,
.get_proposals = _get_proposals,
.select_proposal = _select_proposal,
.get_dh_group = _get_dh_group,
.equals = _equals,
.get_ref = _get_ref,
.destroy = _destroy,
},
.refcount = 1,
.certreq = certreq,
.force_encap = force_encap,
.me = strdup(me),
.other = strdup(other),
.my_port = my_port,
.other_port = other_port,
.proposals = linked_list_create(),
);
return &this->public;
}
+161
View File
@@ -0,0 +1,161 @@
/*
* Copyright (C) 2005-2007 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup ike_cfg ike_cfg
* @{ @ingroup config
*/
#ifndef IKE_CFG_H_
#define IKE_CFG_H_
typedef struct ike_cfg_t ike_cfg_t;
#include <library.h>
#include <utils/host.h>
#include <utils/linked_list.h>
#include <utils/identification.h>
#include <config/proposal.h>
#include <crypto/diffie_hellman.h>
/**
* An ike_cfg_t defines the rules to set up an IKE_SA.
*
* @see peer_cfg_t to get an overview over the configurations.
*/
struct ike_cfg_t {
/**
* Get own address.
*
* @return string of address/DNS name
*/
char* (*get_my_addr) (ike_cfg_t *this);
/**
* Get peers address.
*
* @return string of address/DNS name
*/
char* (*get_other_addr) (ike_cfg_t *this);
/**
* Get the port to use as our source port.
*
* @return source address port, host order
*/
u_int16_t (*get_my_port)(ike_cfg_t *this);
/**
* Get the port to use as destination port.
*
* @return destination address, host order
*/
u_int16_t (*get_other_port)(ike_cfg_t *this);
/**
* Adds a proposal to the list.
*
* The first added proposal has the highest priority, the last
* added the lowest.
*
* @param proposal proposal to add
*/
void (*add_proposal) (ike_cfg_t *this, proposal_t *proposal);
/**
* Returns a list of all supported proposals.
*
* Returned list and its proposals must be destroyed after use.
*
* @return list containing all the proposals
*/
linked_list_t* (*get_proposals) (ike_cfg_t *this);
/**
* Select a proposed from suggested proposals.
*
* Returned proposal must be destroyed after use.
*
* @param proposals list of proposals to select from
* @param private accept algorithms from a private range
* @return selected proposal, or NULL if none matches.
*/
proposal_t *(*select_proposal) (ike_cfg_t *this, linked_list_t *proposals,
bool private);
/**
* Should we send a certificate request in IKE_SA_INIT?
*
* @return certificate request sending policy
*/
bool (*send_certreq) (ike_cfg_t *this);
/**
* Enforce UDP encapsulation by faking NATD notifies?
*
* @return TRUE to enfoce UDP encapsulation
*/
bool (*force_encap) (ike_cfg_t *this);
/**
* Get the DH group to use for IKE_SA setup.
*
* @return dh group to use for initialization
*/
diffie_hellman_group_t (*get_dh_group)(ike_cfg_t *this);
/**
* Check if two IKE configs are equal.
*
* @param other other to check for equality
* @return TRUE if other equal to this
*/
bool (*equals)(ike_cfg_t *this, ike_cfg_t *other);
/**
* Increase reference count.
*
* @return reference to this
*/
ike_cfg_t* (*get_ref) (ike_cfg_t *this);
/**
* Destroys a ike_cfg_t object.
*
* Decrements the internal reference counter and
* destroys the ike_cfg when it reaches zero.
*/
void (*destroy) (ike_cfg_t *this);
};
/**
* Creates a ike_cfg_t object.
*
* Supplied hosts become owned by ike_cfg, the name gets cloned.
*
* @param certreq TRUE to send a certificate request
* @param force_encap enforce UDP encapsulation by faking NATD notify
* @param me address/DNS name of local peer
* @param my_port IKE port to use as source, 500 uses IKEv2 port floating
* @param other address/DNS name of remote peer
* @param other_port IKE port to use as dest, 500 uses IKEv2 port floating
* @return ike_cfg_t object.
*/
ike_cfg_t *ike_cfg_create(bool certreq, bool force_encap,
char *me, u_int16_t my_port, char *other, u_int16_t other_port);
#endif /** IKE_CFG_H_ @}*/
+699
View File
@@ -0,0 +1,699 @@
/*
* Copyright (C) 2007-2008 Tobias Brunner
* Copyright (C) 2005-2009 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <string.h>
#include "peer_cfg.h"
#include <daemon.h>
#include <threading/mutex.h>
#include <utils/linked_list.h>
#include <utils/identification.h>
ENUM(cert_policy_names, CERT_ALWAYS_SEND, CERT_NEVER_SEND,
"CERT_ALWAYS_SEND",
"CERT_SEND_IF_ASKED",
"CERT_NEVER_SEND",
);
ENUM(unique_policy_names, UNIQUE_NO, UNIQUE_KEEP,
"UNIQUE_NO",
"UNIQUE_REPLACE",
"UNIQUE_KEEP",
);
typedef struct private_peer_cfg_t private_peer_cfg_t;
/**
* Private data of an peer_cfg_t object
*/
struct private_peer_cfg_t {
/**
* Public part
*/
peer_cfg_t public;
/**
* Number of references hold by others to this peer_cfg
*/
refcount_t refcount;
/**
* Name of the peer_cfg, used to query it
*/
char *name;
/**
* IKE version to use for initiation
*/
u_int ike_version;
/**
* IKE config associated to this peer config
*/
ike_cfg_t *ike_cfg;
/**
* list of child configs associated to this peer config
*/
linked_list_t *child_cfgs;
/**
* mutex to lock access to list of child_cfgs
*/
mutex_t *mutex;
/**
* should we send a certificate
*/
cert_policy_t cert_policy;
/**
* uniqueness of an IKE_SA
*/
unique_policy_t unique;
/**
* number of tries after giving up if peer does not respond
*/
u_int32_t keyingtries;
/**
* enable support for MOBIKE
*/
bool use_mobike;
/**
* Time before starting rekeying
*/
u_int32_t rekey_time;
/**
* Time before starting reauthentication
*/
u_int32_t reauth_time;
/**
* Time, which specifies the range of a random value substracted from above.
*/
u_int32_t jitter_time;
/**
* Delay before deleting a rekeying/reauthenticating SA
*/
u_int32_t over_time;
/**
* DPD check intervall
*/
u_int32_t dpd;
/**
* virtual IP to use locally
*/
host_t *virtual_ip;
/**
* pool to acquire configuration attributes from
*/
char *pool;
/**
* local authentication configs (rulesets)
*/
linked_list_t *local_auth;
/**
* remote authentication configs (constraints)
*/
linked_list_t *remote_auth;
#ifdef ME
/**
* Is this a mediation connection?
*/
bool mediation;
/**
* Name of the mediation connection to mediate through
*/
peer_cfg_t *mediated_by;
/**
* ID of our peer at the mediation server (= leftid of the peer's conn with
* the mediation server)
*/
identification_t *peer_id;
#endif /* ME */
};
/**
* Implementation of peer_cfg_t.get_name
*/
static char *get_name(private_peer_cfg_t *this)
{
return this->name;
}
/**
* Implementation of peer_cfg_t.get_ike_version
*/
static u_int get_ike_version(private_peer_cfg_t *this)
{
return this->ike_version;
}
/**
* Implementation of peer_cfg_t.get_ike_cfg
*/
static ike_cfg_t* get_ike_cfg(private_peer_cfg_t *this)
{
return this->ike_cfg;
}
/**
* Implementation of peer_cfg_t.add_child_cfg.
*/
static void add_child_cfg(private_peer_cfg_t *this, child_cfg_t *child_cfg)
{
this->mutex->lock(this->mutex);
this->child_cfgs->insert_last(this->child_cfgs, child_cfg);
this->mutex->unlock(this->mutex);
}
/**
* child_cfg enumerator
*/
typedef struct {
enumerator_t public;
enumerator_t *wrapped;
mutex_t *mutex;
} child_cfg_enumerator_t;
/**
* Implementation of peer_cfg_t.remove_child_cfg.
*/
static void remove_child_cfg(private_peer_cfg_t *this,
child_cfg_enumerator_t *enumerator)
{
this->child_cfgs->remove_at(this->child_cfgs, enumerator->wrapped);
}
/**
* Implementation of child_cfg_enumerator_t.destroy
*/
static void child_cfg_enumerator_destroy(child_cfg_enumerator_t *this)
{
this->mutex->unlock(this->mutex);
this->wrapped->destroy(this->wrapped);
free(this);
}
/**
* Implementation of child_cfg_enumerator_t.enumerate
*/
static bool child_cfg_enumerate(child_cfg_enumerator_t *this, child_cfg_t **chd)
{
return this->wrapped->enumerate(this->wrapped, chd);
}
/**
* Implementation of peer_cfg_t.create_child_cfg_enumerator.
*/
static enumerator_t* create_child_cfg_enumerator(private_peer_cfg_t *this)
{
child_cfg_enumerator_t *enumerator = malloc_thing(child_cfg_enumerator_t);
enumerator->public.enumerate = (void*)child_cfg_enumerate;
enumerator->public.destroy = (void*)child_cfg_enumerator_destroy;
enumerator->mutex = this->mutex;
enumerator->wrapped = this->child_cfgs->create_enumerator(this->child_cfgs);
this->mutex->lock(this->mutex);
return &enumerator->public;
}
/**
* Check how good a list of TS matches a given child config
*/
static int get_ts_match(child_cfg_t *cfg, bool local,
linked_list_t *sup_list, host_t *host)
{
linked_list_t *cfg_list;
enumerator_t *sup_enum, *cfg_enum;
traffic_selector_t *sup_ts, *cfg_ts;
int match = 0, round;
/* fetch configured TS list, narrowing dynamic TS */
cfg_list = cfg->get_traffic_selectors(cfg, local, NULL, host);
/* use a round counter to rate leading TS with higher priority */
round = sup_list->get_count(sup_list);
sup_enum = sup_list->create_enumerator(sup_list);
while (sup_enum->enumerate(sup_enum, &sup_ts))
{
cfg_enum = cfg_list->create_enumerator(cfg_list);
while (cfg_enum->enumerate(cfg_enum, &cfg_ts))
{
if (cfg_ts->equals(cfg_ts, sup_ts))
{ /* equality is honored better than matches */
match += round * 5;
}
else if (cfg_ts->is_contained_in(cfg_ts, sup_ts) ||
sup_ts->is_contained_in(sup_ts, cfg_ts))
{
match += round * 1;
}
}
cfg_enum->destroy(cfg_enum);
round--;
}
sup_enum->destroy(sup_enum);
cfg_list->destroy_offset(cfg_list, offsetof(traffic_selector_t, destroy));
return match;
}
/**
* Implementation of peer_cfg_t.select_child_cfg
*/
static child_cfg_t* select_child_cfg(private_peer_cfg_t *this,
linked_list_t *my_ts,
linked_list_t *other_ts,
host_t *my_host, host_t *other_host)
{
child_cfg_t *current, *found = NULL;
enumerator_t *enumerator;
int best = 0;
DBG2(DBG_CFG, "looking for a child config for %#R=== %#R", my_ts, other_ts);
enumerator = create_child_cfg_enumerator(this);
while (enumerator->enumerate(enumerator, &current))
{
int my_prio, other_prio;
my_prio = get_ts_match(current, TRUE, my_ts, my_host);
other_prio = get_ts_match(current, FALSE, other_ts, other_host);
if (my_prio && other_prio)
{
DBG2(DBG_CFG, " candidate \"%s\" with prio %d+%d",
current->get_name(current), my_prio, other_prio);
if (my_prio + other_prio > best)
{
best = my_prio + other_prio;
DESTROY_IF(found);
found = current->get_ref(current);
}
}
}
enumerator->destroy(enumerator);
if (found)
{
DBG2(DBG_CFG, "found matching child config \"%s\" with prio %d",
found->get_name(found), best);
}
return found;
}
/**
* Implementation of peer_cfg_t.get_cert_policy.
*/
static cert_policy_t get_cert_policy(private_peer_cfg_t *this)
{
return this->cert_policy;
}
/**
* Implementation of peer_cfg_t.get_unique_policy.
*/
static unique_policy_t get_unique_policy(private_peer_cfg_t *this)
{
return this->unique;
}
/**
* Implementation of peer_cfg_t.get_keyingtries.
*/
static u_int32_t get_keyingtries(private_peer_cfg_t *this)
{
return this->keyingtries;
}
/**
* Implementation of peer_cfg_t.get_rekey_time.
*/
static u_int32_t get_rekey_time(private_peer_cfg_t *this)
{
if (this->rekey_time == 0)
{
return 0;
}
if (this->jitter_time == 0)
{
return this->rekey_time;
}
return this->rekey_time - (random() % this->jitter_time);
}
/**
* Implementation of peer_cfg_t.get_reauth_time.
*/
static u_int32_t get_reauth_time(private_peer_cfg_t *this)
{
if (this->reauth_time == 0)
{
return 0;
}
if (this->jitter_time == 0)
{
return this->reauth_time;
}
return this->reauth_time - (random() % this->jitter_time);
}
/**
* Implementation of peer_cfg_t.get_over_time.
*/
static u_int32_t get_over_time(private_peer_cfg_t *this)
{
return this->over_time;
}
/**
* Implementation of peer_cfg_t.use_mobike.
*/
static bool use_mobike(private_peer_cfg_t *this)
{
return this->use_mobike;
}
/**
* Implements peer_cfg_t.get_dpd
*/
static u_int32_t get_dpd(private_peer_cfg_t *this)
{
return this->dpd;
}
/**
* Implementation of peer_cfg_t.get_virtual_ip.
*/
static host_t* get_virtual_ip(private_peer_cfg_t *this)
{
return this->virtual_ip;
}
/**
* Implementation of peer_cfg_t.get_pool.
*/
static char* get_pool(private_peer_cfg_t *this)
{
return this->pool;
}
/**
* Implementation of peer_cfg_t.add_auth_cfg
*/
static void add_auth_cfg(private_peer_cfg_t *this,
auth_cfg_t *cfg, bool local)
{
if (local)
{
this->local_auth->insert_last(this->local_auth, cfg);
}
else
{
this->remote_auth->insert_last(this->remote_auth, cfg);
}
}
/**
* Implementation of peer_cfg_t.create_auth_cfg_enumerator
*/
static enumerator_t* create_auth_cfg_enumerator(private_peer_cfg_t *this,
bool local)
{
if (local)
{
return this->local_auth->create_enumerator(this->local_auth);
}
return this->remote_auth->create_enumerator(this->remote_auth);
}
#ifdef ME
/**
* Implementation of peer_cfg_t.is_mediation.
*/
static bool is_mediation(private_peer_cfg_t *this)
{
return this->mediation;
}
/**
* Implementation of peer_cfg_t.get_mediated_by.
*/
static peer_cfg_t* get_mediated_by(private_peer_cfg_t *this)
{
return this->mediated_by;
}
/**
* Implementation of peer_cfg_t.get_peer_id.
*/
static identification_t* get_peer_id(private_peer_cfg_t *this)
{
return this->peer_id;
}
#endif /* ME */
/**
* check auth configs for equality
*/
static bool auth_cfg_equal(private_peer_cfg_t *this, private_peer_cfg_t *other)
{
enumerator_t *e1, *e2;
auth_cfg_t *cfg1, *cfg2;
bool equal = TRUE;
if (this->local_auth->get_count(this->local_auth) !=
other->local_auth->get_count(other->local_auth))
{
return FALSE;
}
if (this->remote_auth->get_count(this->remote_auth) !=
other->remote_auth->get_count(other->remote_auth))
{
return FALSE;
}
e1 = this->local_auth->create_enumerator(this->local_auth);
e2 = other->local_auth->create_enumerator(other->local_auth);
while (e1->enumerate(e1, &cfg1) && e2->enumerate(e2, &cfg2))
{
if (!cfg1->equals(cfg1, cfg2))
{
equal = FALSE;
break;
}
}
e1->destroy(e1);
e2->destroy(e2);
if (!equal)
{
return FALSE;
}
e1 = this->remote_auth->create_enumerator(this->remote_auth);
e2 = other->remote_auth->create_enumerator(other->remote_auth);
while (e1->enumerate(e1, &cfg1) && e2->enumerate(e2, &cfg2))
{
if (!cfg1->equals(cfg1, cfg2))
{
equal = FALSE;
break;
}
}
e1->destroy(e1);
e2->destroy(e2);
return equal;
}
/**
* Implementation of peer_cfg_t.equals.
*/
static bool equals(private_peer_cfg_t *this, private_peer_cfg_t *other)
{
if (this == other)
{
return TRUE;
}
if (this->public.equals != other->public.equals)
{
return FALSE;
}
return (
this->ike_version == other->ike_version &&
this->cert_policy == other->cert_policy &&
this->unique == other->unique &&
this->keyingtries == other->keyingtries &&
this->use_mobike == other->use_mobike &&
this->rekey_time == other->rekey_time &&
this->reauth_time == other->reauth_time &&
this->jitter_time == other->jitter_time &&
this->over_time == other->over_time &&
this->dpd == other->dpd &&
(this->virtual_ip == other->virtual_ip ||
(this->virtual_ip && other->virtual_ip &&
this->virtual_ip->equals(this->virtual_ip, other->virtual_ip))) &&
(this->pool == other->pool ||
(this->pool && other->pool && streq(this->pool, other->pool))) &&
auth_cfg_equal(this, other)
#ifdef ME
&& this->mediation == other->mediation &&
this->mediated_by == other->mediated_by &&
(this->peer_id == other->peer_id ||
(this->peer_id && other->peer_id &&
this->peer_id->equals(this->peer_id, other->peer_id)))
#endif /* ME */
);
}
/**
* Implements peer_cfg_t.get_ref.
*/
static peer_cfg_t* get_ref(private_peer_cfg_t *this)
{
ref_get(&this->refcount);
return &this->public;
}
/**
* Implements peer_cfg_t.destroy.
*/
static void destroy(private_peer_cfg_t *this)
{
if (ref_put(&this->refcount))
{
this->ike_cfg->destroy(this->ike_cfg);
this->child_cfgs->destroy_offset(this->child_cfgs,
offsetof(child_cfg_t, destroy));
DESTROY_IF(this->virtual_ip);
this->local_auth->destroy_offset(this->local_auth,
offsetof(auth_cfg_t, destroy));
this->remote_auth->destroy_offset(this->remote_auth,
offsetof(auth_cfg_t, destroy));
#ifdef ME
DESTROY_IF(this->mediated_by);
DESTROY_IF(this->peer_id);
#endif /* ME */
this->mutex->destroy(this->mutex);
free(this->name);
free(this->pool);
free(this);
}
}
/*
* Described in header-file
*/
peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg,
cert_policy_t cert_policy, unique_policy_t unique,
u_int32_t keyingtries, u_int32_t rekey_time,
u_int32_t reauth_time, u_int32_t jitter_time,
u_int32_t over_time, bool mobike, u_int32_t dpd,
host_t *virtual_ip, char *pool,
bool mediation, peer_cfg_t *mediated_by,
identification_t *peer_id)
{
private_peer_cfg_t *this = malloc_thing(private_peer_cfg_t);
/* public functions */
this->public.get_name = (char* (*) (peer_cfg_t *))get_name;
this->public.get_ike_version = (u_int(*) (peer_cfg_t *))get_ike_version;
this->public.get_ike_cfg = (ike_cfg_t* (*) (peer_cfg_t *))get_ike_cfg;
this->public.add_child_cfg = (void (*) (peer_cfg_t *, child_cfg_t*))add_child_cfg;
this->public.remove_child_cfg = (void(*)(peer_cfg_t*, enumerator_t*))remove_child_cfg;
this->public.create_child_cfg_enumerator = (enumerator_t* (*) (peer_cfg_t *))create_child_cfg_enumerator;
this->public.select_child_cfg = (child_cfg_t* (*) (peer_cfg_t *,linked_list_t*,linked_list_t*,host_t*,host_t*))select_child_cfg;
this->public.get_cert_policy = (cert_policy_t (*) (peer_cfg_t *))get_cert_policy;
this->public.get_unique_policy = (unique_policy_t (*) (peer_cfg_t *))get_unique_policy;
this->public.get_keyingtries = (u_int32_t (*) (peer_cfg_t *))get_keyingtries;
this->public.get_rekey_time = (u_int32_t(*)(peer_cfg_t*))get_rekey_time;
this->public.get_reauth_time = (u_int32_t(*)(peer_cfg_t*))get_reauth_time;
this->public.get_over_time = (u_int32_t(*)(peer_cfg_t*))get_over_time;
this->public.use_mobike = (bool (*) (peer_cfg_t *))use_mobike;
this->public.get_dpd = (u_int32_t (*) (peer_cfg_t *))get_dpd;
this->public.get_virtual_ip = (host_t* (*) (peer_cfg_t *))get_virtual_ip;
this->public.get_pool = (char*(*)(peer_cfg_t*))get_pool;
this->public.add_auth_cfg = (void(*)(peer_cfg_t*, auth_cfg_t *cfg, bool local))add_auth_cfg;
this->public.create_auth_cfg_enumerator = (enumerator_t*(*)(peer_cfg_t*, bool local))create_auth_cfg_enumerator;
this->public.equals = (bool(*)(peer_cfg_t*, peer_cfg_t *other))equals;
this->public.get_ref = (peer_cfg_t*(*)(peer_cfg_t *))get_ref;
this->public.destroy = (void(*)(peer_cfg_t *))destroy;
#ifdef ME
this->public.is_mediation = (bool (*) (peer_cfg_t *))is_mediation;
this->public.get_mediated_by = (peer_cfg_t* (*) (peer_cfg_t *))get_mediated_by;
this->public.get_peer_id = (identification_t* (*) (peer_cfg_t *))get_peer_id;
#endif /* ME */
/* apply init values */
this->name = strdup(name);
this->ike_version = ike_version;
this->ike_cfg = ike_cfg;
this->child_cfgs = linked_list_create();
this->mutex = mutex_create(MUTEX_TYPE_DEFAULT);
this->cert_policy = cert_policy;
this->unique = unique;
this->keyingtries = keyingtries;
this->rekey_time = rekey_time;
this->reauth_time = reauth_time;
if (rekey_time && jitter_time > rekey_time)
{
jitter_time = rekey_time;
}
if (reauth_time && jitter_time > reauth_time)
{
jitter_time = reauth_time;
}
this->jitter_time = jitter_time;
this->over_time = over_time;
this->use_mobike = mobike;
this->dpd = dpd;
this->virtual_ip = virtual_ip;
this->pool = pool ? strdup(pool) : NULL;
this->local_auth = linked_list_create();
this->remote_auth = linked_list_create();
this->refcount = 1;
#ifdef ME
this->mediation = mediation;
this->mediated_by = mediated_by;
this->peer_id = peer_id;
#else /* ME */
DESTROY_IF(mediated_by);
DESTROY_IF(peer_id);
#endif /* ME */
return &this->public;
}
+358
View File
@@ -0,0 +1,358 @@
/*
* Copyright (C) 2007-2008 Tobias Brunner
* Copyright (C) 2005-2009 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup peer_cfg peer_cfg
* @{ @ingroup config
*/
#ifndef PEER_CFG_H_
#define PEER_CFG_H_
typedef enum cert_policy_t cert_policy_t;
typedef enum unique_policy_t unique_policy_t;
typedef struct peer_cfg_t peer_cfg_t;
#include <library.h>
#include <utils/identification.h>
#include <utils/enumerator.h>
#include <selectors/traffic_selector.h>
#include <config/proposal.h>
#include <config/ike_cfg.h>
#include <config/child_cfg.h>
#include <sa/authenticators/authenticator.h>
#include <sa/authenticators/eap/eap_method.h>
#include <config/auth_cfg.h>
/**
* Certificate sending policy. This is also used for certificate
* requests when using this definition for the other peer. If
* it is CERT_NEVER_SEND, a certreq is omitted, otherwise its
* included.
*
* @warning These definitions must be the same as in pluto/starter,
* as they are sent over the stroke socket.
*/
enum cert_policy_t {
/** always send certificates, even when not requested */
CERT_ALWAYS_SEND = 0,
/** send certificate upon cert request */
CERT_SEND_IF_ASKED = 1,
/** never send a certificate, even when requested */
CERT_NEVER_SEND = 2,
};
/**
* enum strings for cert_policy_t
*/
extern enum_name_t *cert_policy_names;
/**
* Uniqueness of an IKE_SA, used to drop multiple connections with one peer.
*/
enum unique_policy_t {
/** do not check for client uniqueness */
UNIQUE_NO,
/** replace unique IKE_SAs if new ones get established */
UNIQUE_REPLACE,
/** keep existing IKE_SAs, close the new ones on connection attept */
UNIQUE_KEEP,
};
/**
* enum strings for unique_policy_t
*/
extern enum_name_t *unique_policy_names;
/**
* Configuration of a peer, specified by IDs.
*
* The peer config defines a connection between two given IDs. It contains
* exactly one ike_cfg_t, which is use for initiation. Additionally, it contains
* multiple child_cfg_t defining which CHILD_SAs are allowed for this peer.
* @verbatim
+-------------------+ +---------------+
+---------------+ | peer_cfg | +---------------+ |
| ike_cfg | +-------------------+ | child_cfg | |
+---------------+ | - ids | +---------------+ |
| - hosts | 1 1 | - cas | 1 n | - proposals | |
| - proposals |<-----| - auth info |----->| - traffic sel | |
| - ... | | - dpd config | | - ... |-+
+---------------+ | - ... | +---------------+
+-------------------+
| 1 0 |
| |
v n n V
+-------------------+ +-------------------+
+-------------------+ | +-------------------+ |
| auth_cfg | | | auth_cfg | |
+-------------------+ | +-------------------+ |
| - local rules |-+ | - remote constr. |-+
+-------------------+ +-------------------+
@endverbatim
*
* Each peer_cfg has two lists of authentication config attached. Local
* authentication configs define how to authenticate ourself against the remote
* peer. Each config is enforced using the multiple authentication extension
* (RFC4739).
* The remote authentication configs are handled as constraints. The peer has
* to fullfill each of these rules (using multiple authentication, in any order)
* to gain access to the configuration.
*/
struct peer_cfg_t {
/**
* Get the name of the peer_cfg.
*
* Returned object is not getting cloned.
*
* @return peer_cfg's name
*/
char* (*get_name) (peer_cfg_t *this);
/**
* Get the IKE version to use for initiating.
*
* @return IKE major version
*/
u_int (*get_ike_version)(peer_cfg_t *this);
/**
* Get the IKE config to use for initiaton.
*
* @return the IKE config to use
*/
ike_cfg_t* (*get_ike_cfg) (peer_cfg_t *this);
/**
* Attach a CHILD config.
*
* @param child_cfg CHILD config to add
*/
void (*add_child_cfg) (peer_cfg_t *this, child_cfg_t *child_cfg);
/**
* Detach a CHILD config, pointed to by an enumerator.
*
* @param enumerator enumerator indicating element position
*/
void (*remove_child_cfg)(peer_cfg_t *this, enumerator_t *enumerator);
/**
* Create an enumerator for all attached CHILD configs.
*
* @return an enumerator over all CHILD configs.
*/
enumerator_t* (*create_child_cfg_enumerator) (peer_cfg_t *this);
/**
* Select a CHILD config from traffic selectors.
*
* @param my_ts TS for local side
* @param other_ts TS for remote side
* @param my_host host to narrow down dynamic TS for local side
* @param other_host host to narrow down dynamic TS for remote side
* @return selected CHILD config, or NULL if no match found
*/
child_cfg_t* (*select_child_cfg) (peer_cfg_t *this, linked_list_t *my_ts,
linked_list_t *other_ts, host_t *my_host,
host_t *other_host);
/**
* Add an authentication config to the peer configuration.
*
* @param config config to add
* @param local TRUE for local rules, FALSE for remote constraints
*/
void (*add_auth_cfg)(peer_cfg_t *this, auth_cfg_t *cfg, bool local);
/**
* Create an enumerator over registered authentication configs.
*
* @param local TRUE for local rules, FALSE for remote constraints
* @return enumerator over auth_cfg_t*
*/
enumerator_t* (*create_auth_cfg_enumerator)(peer_cfg_t *this, bool local);
/**
* Should be sent a certificate for this connection?
*
* @return certificate sending policy
*/
cert_policy_t (*get_cert_policy) (peer_cfg_t *this);
/**
* How to handle uniqueness of IKE_SAs?
*
* @return unique policy
*/
unique_policy_t (*get_unique_policy) (peer_cfg_t *this);
/**
* Get the max number of retries after timeout.
*
* @return max number retries
*/
u_int32_t (*get_keyingtries) (peer_cfg_t *this);
/**
* Get a time to start rekeying (is randomized with jitter).
*
* @return time in s when to start rekeying, 0 disables rekeying
*/
u_int32_t (*get_rekey_time)(peer_cfg_t *this);
/**
* Get a time to start reauthentication (is randomized with jitter).
*
* @return time in s when to start reauthentication, 0 disables it
*/
u_int32_t (*get_reauth_time)(peer_cfg_t *this);
/**
* Get the timeout of a rekeying/reauthenticating SA.
*
* @return timeout in s
*/
u_int32_t (*get_over_time)(peer_cfg_t *this);
/**
* Use MOBIKE (RFC4555) if peer supports it?
*
* @return TRUE to enable MOBIKE support
*/
bool (*use_mobike) (peer_cfg_t *this);
/**
* Get the DPD check interval.
*
* @return dpd_delay in seconds
*/
u_int32_t (*get_dpd) (peer_cfg_t *this);
/**
* Get a virtual IP for the local peer.
*
* If no virtual IP should be used, NULL is returned. %any means to request
* a virtual IP using configuration payloads. A specific address is also
* used for a request and may be changed by the server.
*
* @param suggestion NULL, %any or specific
* @return virtual IP, %any or NULL
*/
host_t* (*get_virtual_ip) (peer_cfg_t *this);
/**
* Get the name of the pool to acquire configuration attributes from.
*
* @return pool name, NULL if none defined
*/
char* (*get_pool)(peer_cfg_t *this);
#ifdef ME
/**
* Is this a mediation connection?
*
* @return TRUE, if this is a mediation connection
*/
bool (*is_mediation) (peer_cfg_t *this);
/**
* Get peer_cfg of the connection this one is mediated through.
*
* @return the peer_cfg of the mediation connection
*/
peer_cfg_t* (*get_mediated_by) (peer_cfg_t *this);
/**
* Get the id of the other peer at the mediation server.
*
* This is the leftid of the peer's connection with the mediation server.
*
* If it is not configured, it is assumed to be the same as the right id
* of this connection.
*
* @return the id of the other peer
*/
identification_t* (*get_peer_id) (peer_cfg_t *this);
#endif /* ME */
/**
* Check if two peer configurations are equal.
*
* This method does not compare associated ike/child_cfg.
*
* @param other candidate to check for equality against this
* @return TRUE if peer_cfg and ike_cfg are equal
*/
bool (*equals)(peer_cfg_t *this, peer_cfg_t *other);
/**
* Increase reference count.
*
* @return reference to this
*/
peer_cfg_t* (*get_ref) (peer_cfg_t *this);
/**
* Destroys the peer_cfg object.
*
* Decrements the internal reference counter and
* destroys the peer_cfg when it reaches zero.
*/
void (*destroy) (peer_cfg_t *this);
};
/**
* Create a configuration object for IKE_AUTH and later.
*
* name-string gets cloned, ID's not.
* Virtual IPs are used if they are != NULL. A %any host means the virtual
* IP should be obtained from the other peer.
* Lifetimes are in seconds. To prevent to peers to start rekeying at the
* same time, a jitter may be specified. Rekeying of an SA starts at
* (rekeylifetime - random(0, jitter)).
*
* @param name name of the peer_cfg
* @param ike_version which IKE version we sould use for this peer
* @param ike_cfg IKE config to use when acting as initiator
* @param cert_policy should we send a certificate payload?
* @param unique uniqueness of an IKE_SA
* @param keyingtries how many keying tries should be done before giving up
* @param rekey_time timeout before starting rekeying
* @param reauth_time timeout before starting reauthentication
* @param jitter_time timerange to randomly substract from rekey/reauth time
* @param over_time maximum overtime before closing a rekeying/reauth SA
* @param mobike use MOBIKE (RFC4555) if peer supports it
* @param dpd DPD check interval, 0 to disable
* @param virtual_ip virtual IP for local host, or NULL
* @param pool pool name to get configuration attributes from, or NULL
* @param mediation TRUE if this is a mediation connection
* @param mediated_by peer_cfg_t of the mediation connection to mediate through
* @param peer_id ID that identifies our peer at the mediation server
* @return peer_cfg_t object
*/
peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg,
cert_policy_t cert_policy, unique_policy_t unique,
u_int32_t keyingtries, u_int32_t rekey_time,
u_int32_t reauth_time, u_int32_t jitter_time,
u_int32_t over_time, bool mobike, u_int32_t dpd,
host_t *virtual_ip, char *pool,
bool mediation, peer_cfg_t *mediated_by,
identification_t *peer_id);
#endif /** PEER_CFG_H_ @}*/
+946
View File
@@ -0,0 +1,946 @@
/*
* Copyright (C) 2008-2009 Tobias Brunner
* Copyright (C) 2006 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <string.h>
#include "proposal.h"
#include <daemon.h>
#include <utils/linked_list.h>
#include <utils/identification.h>
#include <utils/lexparser.h>
#include <crypto/transform.h>
#include <crypto/prfs/prf.h>
#include <crypto/crypters/crypter.h>
#include <crypto/signers/signer.h>
#include <crypto/proposal/proposal_keywords.h>
ENUM(protocol_id_names, PROTO_NONE, PROTO_ESP,
"PROTO_NONE",
"IKE",
"AH",
"ESP",
);
ENUM(extended_sequence_numbers_names, NO_EXT_SEQ_NUMBERS, EXT_SEQ_NUMBERS,
"NO_EXT_SEQ",
"EXT_SEQ",
);
typedef struct private_proposal_t private_proposal_t;
typedef struct algorithm_t algorithm_t;
/**
* Private data of an proposal_t object
*/
struct private_proposal_t {
/**
* Public part
*/
proposal_t public;
/**
* protocol (ESP or AH)
*/
protocol_id_t protocol;
/**
* priority ordered list of encryption algorithms
*/
linked_list_t *encryption_algos;
/**
* priority ordered list of integrity algorithms
*/
linked_list_t *integrity_algos;
/**
* priority ordered list of pseudo random functions
*/
linked_list_t *prf_algos;
/**
* priority ordered list of dh groups
*/
linked_list_t *dh_groups;
/**
* priority ordered list of extended sequence number flags
*/
linked_list_t *esns;
/**
* senders SPI
*/
u_int64_t spi;
};
/**
* Struct used to store different kinds of algorithms.
*/
struct algorithm_t {
/**
* Value from an encryption_algorithm_t/integrity_algorithm_t/...
*/
u_int16_t algorithm;
/**
* the associated key size in bits, or zero if not needed
*/
u_int16_t key_size;
};
/**
* Add algorithm/keysize to a algorithm list
*/
static void add_algo(linked_list_t *list, u_int16_t algo, u_int16_t key_size)
{
algorithm_t *algo_key;
algo_key = malloc_thing(algorithm_t);
algo_key->algorithm = algo;
algo_key->key_size = key_size;
list->insert_last(list, (void*)algo_key);
}
/**
* Implements proposal_t.add_algorithm
*/
static void add_algorithm(private_proposal_t *this, transform_type_t type,
u_int16_t algo, u_int16_t key_size)
{
switch (type)
{
case ENCRYPTION_ALGORITHM:
add_algo(this->encryption_algos, algo, key_size);
break;
case INTEGRITY_ALGORITHM:
add_algo(this->integrity_algos, algo, key_size);
break;
case PSEUDO_RANDOM_FUNCTION:
add_algo(this->prf_algos, algo, key_size);
break;
case DIFFIE_HELLMAN_GROUP:
add_algo(this->dh_groups, algo, 0);
break;
case EXTENDED_SEQUENCE_NUMBERS:
add_algo(this->esns, algo, 0);
break;
default:
break;
}
}
/**
* filter function for peer configs
*/
static bool alg_filter(void *null, algorithm_t **in, u_int16_t *alg,
void **unused, u_int16_t *key_size)
{
algorithm_t *algo = *in;
*alg = algo->algorithm;
if (key_size)
{
*key_size = algo->key_size;
}
return TRUE;
}
/**
* Implements proposal_t.create_enumerator.
*/
static enumerator_t *create_enumerator(private_proposal_t *this,
transform_type_t type)
{
linked_list_t *list;
switch (type)
{
case ENCRYPTION_ALGORITHM:
list = this->encryption_algos;
break;
case INTEGRITY_ALGORITHM:
list = this->integrity_algos;
break;
case PSEUDO_RANDOM_FUNCTION:
list = this->prf_algos;
break;
case DIFFIE_HELLMAN_GROUP:
list = this->dh_groups;
break;
case EXTENDED_SEQUENCE_NUMBERS:
list = this->esns;
break;
default:
return NULL;
}
return enumerator_create_filter(list->create_enumerator(list),
(void*)alg_filter, NULL, NULL);
}
/**
* Implements proposal_t.get_algorithm.
*/
static bool get_algorithm(private_proposal_t *this, transform_type_t type,
u_int16_t *alg, u_int16_t *key_size)
{
enumerator_t *enumerator;
bool found = FALSE;
enumerator = create_enumerator(this, type);
if (enumerator->enumerate(enumerator, alg, key_size))
{
found = TRUE;
}
enumerator->destroy(enumerator);
return found;
}
/**
* Implements proposal_t.has_dh_group
*/
static bool has_dh_group(private_proposal_t *this, diffie_hellman_group_t group)
{
bool result = FALSE;
if (this->dh_groups->get_count(this->dh_groups))
{
algorithm_t *current;
enumerator_t *enumerator;
enumerator = this->dh_groups->create_enumerator(this->dh_groups);
while (enumerator->enumerate(enumerator, (void**)&current))
{
if (current->algorithm == group)
{
result = TRUE;
break;
}
}
enumerator->destroy(enumerator);
}
else if (group == MODP_NONE)
{
result = TRUE;
}
return result;
}
/**
* Implementation of proposal_t.strip_dh.
*/
static void strip_dh(private_proposal_t *this)
{
algorithm_t *alg;
while (this->dh_groups->remove_last(this->dh_groups, (void**)&alg) == SUCCESS)
{
free(alg);
}
}
/**
* Returns true if the given alg is an authenticated encryption algorithm
*/
static bool is_authenticated_encryption(u_int16_t alg)
{
switch(alg)
{
case ENCR_AES_CCM_ICV8:
case ENCR_AES_CCM_ICV12:
case ENCR_AES_CCM_ICV16:
case ENCR_AES_GCM_ICV8:
case ENCR_AES_GCM_ICV12:
case ENCR_AES_GCM_ICV16:
case ENCR_CAMELLIA_CCM_ICV8:
case ENCR_CAMELLIA_CCM_ICV12:
case ENCR_CAMELLIA_CCM_ICV16:
case ENCR_NULL_AUTH_AES_GMAC:
return TRUE;
}
return FALSE;
}
/**
* Find a matching alg/keysize in two linked lists
*/
static bool select_algo(linked_list_t *first, linked_list_t *second, bool priv,
bool *add, u_int16_t *alg, size_t *key_size)
{
enumerator_t *e1, *e2;
algorithm_t *alg1, *alg2;
/* if in both are zero algorithms specified, we HAVE a match */
if (first->get_count(first) == 0 && second->get_count(second) == 0)
{
*add = FALSE;
return TRUE;
}
e1 = first->create_enumerator(first);
e2 = second->create_enumerator(second);
/* compare algs, order of algs in "first" is preferred */
while (e1->enumerate(e1, &alg1))
{
e2->destroy(e2);
e2 = second->create_enumerator(second);
while (e2->enumerate(e2, &alg2))
{
if (alg1->algorithm == alg2->algorithm &&
alg1->key_size == alg2->key_size)
{
if (!priv && alg1->algorithm >= 1024)
{
/* accept private use algorithms only if requested */
DBG1(DBG_CFG, "an algorithm from private space would match, "
"but peer implementation is unknown, skipped");
continue;
}
/* ok, we have an algorithm */
*alg = alg1->algorithm;
*key_size = alg1->key_size;
*add = TRUE;
e1->destroy(e1);
e2->destroy(e2);
return TRUE;
}
}
}
/* no match in all comparisons */
e1->destroy(e1);
e2->destroy(e2);
return FALSE;
}
/**
* Implements proposal_t.select.
*/
static proposal_t *select_proposal(private_proposal_t *this,
private_proposal_t *other, bool private)
{
proposal_t *selected;
u_int16_t algo;
size_t key_size;
bool add;
DBG2(DBG_CFG, "selecting proposal:");
/* check protocol */
if (this->protocol != other->protocol)
{
DBG2(DBG_CFG, " protocol mismatch, skipping");
return NULL;
}
selected = proposal_create(this->protocol);
/* select encryption algorithm */
if (select_algo(this->encryption_algos, other->encryption_algos, private,
&add, &algo, &key_size))
{
if (add)
{
selected->add_algorithm(selected, ENCRYPTION_ALGORITHM,
algo, key_size);
}
}
else
{
selected->destroy(selected);
DBG2(DBG_CFG, " no acceptable %N found",
transform_type_names, ENCRYPTION_ALGORITHM);
return NULL;
}
/* select integrity algorithm */
if (!is_authenticated_encryption(algo))
{
if (select_algo(this->integrity_algos, other->integrity_algos, private,
&add, &algo, &key_size))
{
if (add)
{
selected->add_algorithm(selected, INTEGRITY_ALGORITHM,
algo, key_size);
}
}
else
{
selected->destroy(selected);
DBG2(DBG_CFG, " no acceptable %N found",
transform_type_names, INTEGRITY_ALGORITHM);
return NULL;
}
}
/* select prf algorithm */
if (select_algo(this->prf_algos, other->prf_algos, private,
&add, &algo, &key_size))
{
if (add)
{
selected->add_algorithm(selected, PSEUDO_RANDOM_FUNCTION,
algo, key_size);
}
}
else
{
selected->destroy(selected);
DBG2(DBG_CFG, " no acceptable %N found",
transform_type_names, PSEUDO_RANDOM_FUNCTION);
return NULL;
}
/* select a DH-group */
if (select_algo(this->dh_groups, other->dh_groups, private,
&add, &algo, &key_size))
{
if (add)
{
selected->add_algorithm(selected, DIFFIE_HELLMAN_GROUP, algo, 0);
}
}
else
{
selected->destroy(selected);
DBG2(DBG_CFG, " no acceptable %N found",
transform_type_names, DIFFIE_HELLMAN_GROUP);
return NULL;
}
/* select if we use ESNs (has no private use space) */
if (select_algo(this->esns, other->esns, TRUE, &add, &algo, &key_size))
{
if (add)
{
selected->add_algorithm(selected, EXTENDED_SEQUENCE_NUMBERS, algo, 0);
}
}
else
{
selected->destroy(selected);
DBG2(DBG_CFG, " no acceptable %N found",
transform_type_names, EXTENDED_SEQUENCE_NUMBERS);
return NULL;
}
DBG2(DBG_CFG, " proposal matches");
/* apply SPI from "other" */
selected->set_spi(selected, other->spi);
/* everything matched, return new proposal */
return selected;
}
/**
* Implements proposal_t.get_protocols.
*/
static protocol_id_t get_protocol(private_proposal_t *this)
{
return this->protocol;
}
/**
* Implements proposal_t.set_spi.
*/
static void set_spi(private_proposal_t *this, u_int64_t spi)
{
this->spi = spi;
}
/**
* Implements proposal_t.get_spi.
*/
static u_int64_t get_spi(private_proposal_t *this)
{
return this->spi;
}
/**
* Clone a algorithm list
*/
static void clone_algo_list(linked_list_t *list, linked_list_t *clone_list)
{
algorithm_t *algo, *clone_algo;
enumerator_t *enumerator;
enumerator = list->create_enumerator(list);
while (enumerator->enumerate(enumerator, &algo))
{
clone_algo = malloc_thing(algorithm_t);
memcpy(clone_algo, algo, sizeof(algorithm_t));
clone_list->insert_last(clone_list, (void*)clone_algo);
}
enumerator->destroy(enumerator);
}
/**
* check if an algorithm list equals
*/
static bool algo_list_equals(linked_list_t *l1, linked_list_t *l2)
{
enumerator_t *e1, *e2;
algorithm_t *alg1, *alg2;
bool equals = TRUE;
if (l1->get_count(l1) != l2->get_count(l2))
{
return FALSE;
}
e1 = l1->create_enumerator(l1);
e2 = l2->create_enumerator(l2);
while (e1->enumerate(e1, &alg1) && e2->enumerate(e2, &alg2))
{
if (alg1->algorithm != alg2->algorithm ||
alg1->key_size != alg2->key_size)
{
equals = FALSE;
break;
}
}
e1->destroy(e1);
e2->destroy(e2);
return equals;
}
/**
* Implementation of proposal_t.equals.
*/
static bool equals(private_proposal_t *this, private_proposal_t *other)
{
if (this == other)
{
return TRUE;
}
if (this->public.equals != other->public.equals)
{
return FALSE;
}
return (
algo_list_equals(this->encryption_algos, other->encryption_algos) &&
algo_list_equals(this->integrity_algos, other->integrity_algos) &&
algo_list_equals(this->prf_algos, other->prf_algos) &&
algo_list_equals(this->dh_groups, other->dh_groups) &&
algo_list_equals(this->esns, other->esns));
}
/**
* Implements proposal_t.clone
*/
static proposal_t *clone_(private_proposal_t *this)
{
private_proposal_t *clone = (private_proposal_t*)proposal_create(this->protocol);
clone_algo_list(this->encryption_algos, clone->encryption_algos);
clone_algo_list(this->integrity_algos, clone->integrity_algos);
clone_algo_list(this->prf_algos, clone->prf_algos);
clone_algo_list(this->dh_groups, clone->dh_groups);
clone_algo_list(this->esns, clone->esns);
clone->spi = this->spi;
return &clone->public;
}
/**
* Checks the proposal read from a string.
*/
static void check_proposal(private_proposal_t *this)
{
enumerator_t *e;
algorithm_t *alg;
bool all_aead = TRUE;
e = this->encryption_algos->create_enumerator(this->encryption_algos);
while (e->enumerate(e, &alg))
{
if (!is_authenticated_encryption(alg->algorithm))
{
all_aead = FALSE;
break;
}
}
e->destroy(e);
if (all_aead)
{
/* if all encryption algorithms in the proposal are authenticated encryption
* algorithms we MUST NOT propose any integrity algorithms */
while (this->integrity_algos->remove_last(this->integrity_algos,
(void**)&alg) == SUCCESS)
{
free(alg);
}
}
}
/**
* add a algorithm identified by a string to the proposal.
*/
static status_t add_string_algo(private_proposal_t *this, chunk_t alg)
{
const proposal_token_t *token = proposal_get_token(alg.ptr, alg.len);
if (token == NULL)
{
return FAILED;
}
add_algorithm(this, token->type, token->algorithm, token->keysize);
if (this->protocol == PROTO_IKE && token->type == INTEGRITY_ALGORITHM)
{
pseudo_random_function_t prf;
switch (token->algorithm)
{
case AUTH_HMAC_SHA1_96:
prf = PRF_HMAC_SHA1;
break;
case AUTH_HMAC_SHA2_256_128:
prf = PRF_HMAC_SHA2_256;
break;
case AUTH_HMAC_SHA2_384_192:
prf = PRF_HMAC_SHA2_384;
break;
case AUTH_HMAC_SHA2_512_256:
prf = PRF_HMAC_SHA2_512;
break;
case AUTH_HMAC_MD5_96:
prf = PRF_HMAC_MD5;
break;
case AUTH_AES_XCBC_96:
prf = PRF_AES128_XCBC;
break;
default:
prf = PRF_UNDEFINED;
}
if (prf != PRF_UNDEFINED)
{
add_algorithm(this, PSEUDO_RANDOM_FUNCTION, prf, 0);
}
}
return SUCCESS;
}
/**
* print all algorithms of a kind to buffer
*/
static int print_alg(private_proposal_t *this, char **dst, size_t *len,
u_int kind, void *names, bool *first)
{
enumerator_t *enumerator;
size_t written = 0;
u_int16_t alg, size;
enumerator = create_enumerator(this, kind);
while (enumerator->enumerate(enumerator, &alg, &size))
{
if (*first)
{
written += print_in_hook(*dst, *len, "%N", names, alg);
*first = FALSE;
}
else
{
written += print_in_hook(*dst, *len, "/%N", names, alg);
}
if (size)
{
written += print_in_hook(*dst, *len, "_%u", size);
}
}
enumerator->destroy(enumerator);
return written;
}
/**
* Described in header.
*/
int proposal_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec,
const void *const *args)
{
private_proposal_t *this = *((private_proposal_t**)(args[0]));
linked_list_t *list = *((linked_list_t**)(args[0]));
enumerator_t *enumerator;
size_t written = 0;
bool first = TRUE;
if (this == NULL)
{
return print_in_hook(dst, len, "(null)");
}
if (spec->hash)
{
enumerator = list->create_enumerator(list);
while (enumerator->enumerate(enumerator, &this))
{ /* call recursivly */
if (first)
{
written += print_in_hook(dst, len, "%P", this);
first = FALSE;
}
else
{
written += print_in_hook(dst, len, ", %P", this);
}
}
enumerator->destroy(enumerator);
return written;
}
written = print_in_hook(dst, len, "%N:", protocol_id_names, this->protocol);
written += print_alg(this, &dst, &len, ENCRYPTION_ALGORITHM,
encryption_algorithm_names, &first);
written += print_alg(this, &dst, &len, INTEGRITY_ALGORITHM,
integrity_algorithm_names, &first);
written += print_alg(this, &dst, &len, PSEUDO_RANDOM_FUNCTION,
pseudo_random_function_names, &first);
written += print_alg(this, &dst, &len, DIFFIE_HELLMAN_GROUP,
diffie_hellman_group_names, &first);
written += print_alg(this, &dst, &len, EXTENDED_SEQUENCE_NUMBERS,
extended_sequence_numbers_names, &first);
return written;
}
/**
* Implements proposal_t.destroy.
*/
static void destroy(private_proposal_t *this)
{
this->encryption_algos->destroy_function(this->encryption_algos, free);
this->integrity_algos->destroy_function(this->integrity_algos, free);
this->prf_algos->destroy_function(this->prf_algos, free);
this->dh_groups->destroy_function(this->dh_groups, free);
this->esns->destroy_function(this->esns, free);
free(this);
}
/*
* Describtion in header-file
*/
proposal_t *proposal_create(protocol_id_t protocol)
{
private_proposal_t *this = malloc_thing(private_proposal_t);
this->public.add_algorithm = (void (*)(proposal_t*,transform_type_t,u_int16_t,u_int16_t))add_algorithm;
this->public.create_enumerator = (enumerator_t* (*)(proposal_t*,transform_type_t))create_enumerator;
this->public.get_algorithm = (bool (*)(proposal_t*,transform_type_t,u_int16_t*,u_int16_t*))get_algorithm;
this->public.has_dh_group = (bool (*)(proposal_t*,diffie_hellman_group_t))has_dh_group;
this->public.strip_dh = (void(*)(proposal_t*))strip_dh;
this->public.select = (proposal_t* (*)(proposal_t*,proposal_t*,bool))select_proposal;
this->public.get_protocol = (protocol_id_t(*)(proposal_t*))get_protocol;
this->public.set_spi = (void(*)(proposal_t*,u_int64_t))set_spi;
this->public.get_spi = (u_int64_t(*)(proposal_t*))get_spi;
this->public.equals = (bool(*)(proposal_t*, proposal_t *other))equals;
this->public.clone = (proposal_t*(*)(proposal_t*))clone_;
this->public.destroy = (void(*)(proposal_t*))destroy;
this->spi = 0;
this->protocol = protocol;
this->encryption_algos = linked_list_create();
this->integrity_algos = linked_list_create();
this->prf_algos = linked_list_create();
this->dh_groups = linked_list_create();
this->esns = linked_list_create();
return &this->public;
}
/**
* Add supported IKE algorithms to proposal
*/
static void proposal_add_supported_ike(private_proposal_t *this)
{
enumerator_t *enumerator;
encryption_algorithm_t encryption;
integrity_algorithm_t integrity;
pseudo_random_function_t prf;
diffie_hellman_group_t group;
enumerator = lib->crypto->create_crypter_enumerator(lib->crypto);
while (enumerator->enumerate(enumerator, &encryption))
{
switch (encryption)
{
case ENCR_AES_CBC:
/* we assume that we support all AES sizes */
add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 128);
add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 192);
add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256);
break;
case ENCR_3DES:
case ENCR_AES_CTR:
case ENCR_AES_CCM_ICV8:
case ENCR_AES_CCM_ICV12:
case ENCR_AES_CCM_ICV16:
case ENCR_AES_GCM_ICV8:
case ENCR_AES_GCM_ICV12:
case ENCR_AES_GCM_ICV16:
add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 0);
break;
case ENCR_DES:
/* no, thanks */
break;
default:
break;
}
}
enumerator->destroy(enumerator);
enumerator = lib->crypto->create_signer_enumerator(lib->crypto);
while (enumerator->enumerate(enumerator, &integrity))
{
switch (integrity)
{
case AUTH_HMAC_SHA1_96:
case AUTH_HMAC_SHA2_256_128:
case AUTH_HMAC_SHA2_384_192:
case AUTH_HMAC_SHA2_512_256:
case AUTH_HMAC_MD5_96:
case AUTH_AES_XCBC_96:
add_algorithm(this, INTEGRITY_ALGORITHM, integrity, 0);
break;
default:
break;
}
}
enumerator->destroy(enumerator);
enumerator = lib->crypto->create_prf_enumerator(lib->crypto);
while (enumerator->enumerate(enumerator, &prf))
{
switch (prf)
{
case PRF_HMAC_SHA1:
case PRF_HMAC_SHA2_256:
case PRF_HMAC_SHA2_384:
case PRF_HMAC_SHA2_512:
case PRF_HMAC_MD5:
case PRF_AES128_XCBC:
add_algorithm(this, PSEUDO_RANDOM_FUNCTION, prf, 0);
break;
default:
break;
}
}
enumerator->destroy(enumerator);
enumerator = lib->crypto->create_dh_enumerator(lib->crypto);
while (enumerator->enumerate(enumerator, &group))
{
switch (group)
{
case MODP_NULL:
/* only for testing purposes */
break;
case MODP_768_BIT:
/* weak */
break;
case MODP_1024_BIT:
case MODP_1536_BIT:
case MODP_2048_BIT:
case MODP_4096_BIT:
case MODP_8192_BIT:
case ECP_256_BIT:
case ECP_384_BIT:
case ECP_521_BIT:
case ECP_192_BIT:
case ECP_224_BIT:
add_algorithm(this, DIFFIE_HELLMAN_GROUP, group, 0);
break;
default:
break;
}
}
enumerator->destroy(enumerator);
}
/*
* Describtion in header-file
*/
proposal_t *proposal_create_default(protocol_id_t protocol)
{
private_proposal_t *this = (private_proposal_t*)proposal_create(protocol);
switch (protocol)
{
case PROTO_IKE:
proposal_add_supported_ike(this);
break;
case PROTO_ESP:
add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 128);
add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 192);
add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 256);
add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_3DES, 0);
add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_BLOWFISH, 256);
add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0);
add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_AES_XCBC_96, 0);
add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0);
add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0);
break;
case PROTO_AH:
add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0);
add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_AES_XCBC_96, 0);
add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0);
add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0);
break;
default:
break;
}
return &this->public;
}
/*
* Describtion in header-file
*/
proposal_t *proposal_create_from_string(protocol_id_t protocol, const char *algs)
{
private_proposal_t *this = (private_proposal_t*)proposal_create(protocol);
chunk_t string = {(void*)algs, strlen(algs)};
chunk_t alg;
status_t status = SUCCESS;
eat_whitespace(&string);
if (string.len < 1)
{
destroy(this);
return NULL;
}
/* get all tokens, separated by '-' */
while (extract_token(&alg, '-', &string))
{
status |= add_string_algo(this, alg);
}
if (string.len)
{
status |= add_string_algo(this, string);
}
if (status != SUCCESS)
{
destroy(this);
return NULL;
}
check_proposal(this);
if (protocol == PROTO_AH || protocol == PROTO_ESP)
{
add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0);
}
return &this->public;
}
+226
View File
@@ -0,0 +1,226 @@
/*
* Copyright (C) 2006 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup proposal proposal
* @{ @ingroup config
*/
#ifndef PROPOSAL_H_
#define PROPOSAL_H_
typedef enum protocol_id_t protocol_id_t;
typedef enum extended_sequence_numbers_t extended_sequence_numbers_t;
typedef struct proposal_t proposal_t;
#include <library.h>
#include <utils/identification.h>
#include <utils/linked_list.h>
#include <utils/host.h>
#include <crypto/transform.h>
#include <crypto/crypters/crypter.h>
#include <crypto/signers/signer.h>
#include <crypto/diffie_hellman.h>
#include <selectors/traffic_selector.h>
/**
* Protocol ID of a proposal.
*/
enum protocol_id_t {
PROTO_NONE = 0,
PROTO_IKE = 1,
PROTO_AH = 2,
PROTO_ESP = 3,
};
/**
* enum names for protocol_id_t
*/
extern enum_name_t *protocol_id_names;
/**
* Extended sequence numbers, as in IKEv2 RFC 3.3.2.
*/
enum extended_sequence_numbers_t {
NO_EXT_SEQ_NUMBERS = 0,
EXT_SEQ_NUMBERS = 1
};
/**
* enum strings for extended_sequence_numbers_t.
*/
extern enum_name_t *extended_sequence_numbers_names;
/**
* Stores a set of algorithms used for an SA.
*
* A proposal stores algorithms for a specific
* protocol. It can store algorithms for one protocol.
* Proposals with multiple protocols are not supported,
* as it's not specified in RFC4301 anymore.
*/
struct proposal_t {
/**
* Add an algorithm to the proposal.
*
* The algorithms are stored by priority, first added
* is the most preferred.
* Key size is only needed for encryption algorithms
* with variable key size (such as AES). Must be set
* to zero if key size is not specified.
* The alg parameter accepts encryption_algorithm_t,
* integrity_algorithm_t, dh_group_number_t and
* extended_sequence_numbers_t.
*
* @param type kind of algorithm
* @param alg identifier for algorithm
* @param key_size key size to use
*/
void (*add_algorithm) (proposal_t *this, transform_type_t type,
u_int16_t alg, u_int16_t key_size);
/**
* Get an enumerator over algorithms for a specifc algo type.
*
* @param type kind of algorithm
* @return enumerator over u_int16_t alg, u_int16_t key_size
*/
enumerator_t *(*create_enumerator) (proposal_t *this, transform_type_t type);
/**
* Get the algorithm for a type to use.
*
* If there are multiple algorithms, only the first is returned.
*
* @param type kind of algorithm
* @param alg pointer which receives algorithm
* @param key_size pointer which receives the key size
* @return TRUE if algorithm of this kind available
*/
bool (*get_algorithm) (proposal_t *this, transform_type_t type,
u_int16_t *alg, u_int16_t *key_size);
/**
* Check if the proposal has a specific DH group.
*
* @param group group to check for
* @return TRUE if algorithm included
*/
bool (*has_dh_group) (proposal_t *this, diffie_hellman_group_t group);
/**
* Strip DH groups from proposal to use it without PFS.
*/
void (*strip_dh)(proposal_t *this);
/**
* Compare two proposal, and select a matching subset.
*
* If the proposals are for the same protocols (AH/ESP), they are
* compared. If they have at least one algorithm of each type
* in common, a resulting proposal of this kind is created.
*
* @param other proposal to compair agains
* @param private accepts algorithms allocated in a private range
* @return selected proposal, NULL if proposals don't match
*/
proposal_t *(*select) (proposal_t *this, proposal_t *other, bool private);
/**
* Get the protocol ID of the proposal.
*
* @return protocol of the proposal
*/
protocol_id_t (*get_protocol) (proposal_t *this);
/**
* Get the SPI of the proposal.
*
* @return spi for proto
*/
u_int64_t (*get_spi) (proposal_t *this);
/**
* Set the SPI of the proposal.
*
* @param spi spi to set for proto
*/
void (*set_spi) (proposal_t *this, u_int64_t spi);
/**
* Check for the eqality of two proposals.
*
* @param other other proposal to check for equality
* @return TRUE if other equal to this
*/
bool (*equals)(proposal_t *this, proposal_t *other);
/**
* Clone a proposal.
*
* @return clone of proposal
*/
proposal_t *(*clone) (proposal_t *this);
/**
* Destroys the proposal object.
*/
void (*destroy) (proposal_t *this);
};
/**
* Create a child proposal for AH, ESP or IKE.
*
* @param protocol protocol, such as PROTO_ESP
* @return proposal_t object
*/
proposal_t *proposal_create(protocol_id_t protocol);
/**
* Create a default proposal if nothing further specified.
*
* @param protocol protocol, such as PROTO_ESP
* @return proposal_t object
*/
proposal_t *proposal_create_default(protocol_id_t protocol);
/**
* Create a proposal from a string identifying the algorithms.
*
* The string is in the same form as a in the ipsec.conf file.
* E.g.: aes128-sha2_256-modp2048
* 3des-md5
* An additional '!' at the end of the string forces this proposal,
* without it the peer may choose another algorithm we support.
*
* @param protocol protocol, such as PROTO_ESP
* @param algs algorithms as string
* @return proposal_t object
*/
proposal_t *proposal_create_from_string(protocol_id_t protocol, const char *algs);
/**
* printf hook function for proposal_t.
*
* Arguments are:
* proposal_t *proposal
* With the #-specifier, arguments are:
* linked_list_t *list containing proposal_t*
*/
int proposal_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec,
const void *const *args);
#endif /** PROPOSAL_H_ @}*/
+455
View File
@@ -0,0 +1,455 @@
/*
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "controller.h"
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <dlfcn.h>
#include <daemon.h>
#include <library.h>
typedef struct private_controller_t private_controller_t;
typedef struct interface_listener_t interface_listener_t;
/**
* Private data of an stroke_t object.
*/
struct private_controller_t {
/**
* Public part of stroke_t object.
*/
controller_t public;
};
/**
* helper struct to map listener callbacks to interface callbacks
*/
struct interface_listener_t {
/**
* public bus listener interface
*/
listener_t public;
/**
* status of the operation, return to method callers
*/
status_t status;
/**
* interface callback (listener gets redirected to here)
*/
controller_cb_t callback;
/**
* user parameter to pass to callback
*/
void *param;
/**
* child configuration, used for initiate
*/
child_cfg_t *child_cfg;
/**
* peer configuration, used for initiate
*/
peer_cfg_t *peer_cfg;
/**
* IKE_SA to handle
*/
ike_sa_t *ike_sa;
/**
* CHILD_SA to handle
*/
child_sa_t *child_sa;
/**
* unique ID, used for various methods
*/
u_int32_t id;
};
typedef struct interface_job_t interface_job_t;
/**
* job for asynchronous listen operations
*/
struct interface_job_t {
/**
* job interface
*/
job_t public;
/**
* associated listener
*/
interface_listener_t listener;
};
/**
* listener log function
*/
static bool listener_log(interface_listener_t *this, debug_t group,
level_t level, int thread, ike_sa_t *ike_sa,
char* format, va_list args)
{
if (this->ike_sa == ike_sa)
{
if (!this->callback(this->param, group, level, ike_sa, format, args))
{
return FALSE;
}
}
return TRUE;
}
/**
* Implementation of listener_t.ike_state_change
*/
static bool listener_ike_state(interface_listener_t *this, ike_sa_t *ike_sa,
ike_sa_state_t state)
{
if (this->ike_sa == ike_sa)
{
switch (state)
{
#ifdef ME
case IKE_ESTABLISHED:
{ /* mediation connections are complete without CHILD_SA */
peer_cfg_t *peer_cfg = ike_sa->get_peer_cfg(ike_sa);
if (peer_cfg->is_mediation(peer_cfg))
{
this->status = SUCCESS;
return FALSE;
}
break;
}
#endif /* ME */
case IKE_DESTROYING:
if (ike_sa->get_state(ike_sa) == IKE_DELETING)
{ /* proper termination */
this->status = SUCCESS;
}
return FALSE;
default:
break;
}
}
return TRUE;
}
/**
* Implementation of listener_t.child_state_change
*/
static bool listener_child_state(interface_listener_t *this, ike_sa_t *ike_sa,
child_sa_t *child_sa, child_sa_state_t state)
{
if (this->ike_sa == ike_sa)
{
switch (state)
{
case CHILD_INSTALLED:
this->status = SUCCESS;
return FALSE;
case CHILD_DESTROYING:
switch (child_sa->get_state(child_sa))
{
case CHILD_DELETING:
/* proper delete */
this->status = SUCCESS;
break;
default:
break;
}
return FALSE;
default:
break;
}
}
return TRUE;
}
/**
* cleanup job if job is never executed
*/
static void recheckin(interface_job_t *job)
{
if (job->listener.ike_sa)
{
charon->ike_sa_manager->checkin(charon->ike_sa_manager,
job->listener.ike_sa);
}
}
/**
* Implementation of controller_t.create_ike_sa_iterator.
*/
static enumerator_t* create_ike_sa_enumerator(controller_t *this)
{
return charon->ike_sa_manager->create_enumerator(charon->ike_sa_manager);
}
/**
* execute function for initiate
*/
static status_t initiate_execute(interface_job_t *job)
{
ike_sa_t *ike_sa;
interface_listener_t *listener = &job->listener;
peer_cfg_t *peer_cfg = listener->peer_cfg;
ike_sa = charon->ike_sa_manager->checkout_by_config(charon->ike_sa_manager,
peer_cfg);
listener->ike_sa = ike_sa;
if (ike_sa->get_peer_cfg(ike_sa) == NULL)
{
ike_sa->set_peer_cfg(ike_sa, peer_cfg);
}
peer_cfg->destroy(peer_cfg);
if (ike_sa->initiate(ike_sa, listener->child_cfg, 0, NULL, NULL) == SUCCESS)
{
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
return SUCCESS;
}
charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
return FAILED;
}
/**
* Implementation of controller_t.initiate.
*/
static status_t initiate(private_controller_t *this,
peer_cfg_t *peer_cfg, child_cfg_t *child_cfg,
controller_cb_t callback, void *param)
{
interface_job_t job = {
.listener = {
.public = {
.log = (void*)listener_log,
.ike_state_change = (void*)listener_ike_state,
.child_state_change = (void*)listener_child_state,
},
.callback = callback,
.param = param,
.status = FAILED,
.child_cfg = child_cfg,
.peer_cfg = peer_cfg,
},
.public = {
.execute = (void*)initiate_execute,
.destroy = (void*)recheckin,
},
};
if (callback == NULL)
{
return initiate_execute(&job);
}
charon->bus->listen(charon->bus, &job.listener.public, (job_t*)&job);
return job.listener.status;
}
/**
* execute function for terminate_ike
*/
static status_t terminate_ike_execute(interface_job_t *job)
{
interface_listener_t *listener = &job->listener;
ike_sa_t *ike_sa = listener->ike_sa;
charon->bus->set_sa(charon->bus, ike_sa);
if (ike_sa->delete(ike_sa) != DESTROY_ME)
{
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
/* delete failed */
return FAILED;
}
charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
return SUCCESS;
}
/**
* Implementation of controller_t.terminate_ike.
*/
static status_t terminate_ike(controller_t *this, u_int32_t unique_id,
controller_cb_t callback, void *param)
{
ike_sa_t *ike_sa;
interface_job_t job = {
.listener = {
.public = {
.log = (void*)listener_log,
.ike_state_change = (void*)listener_ike_state,
.child_state_change = (void*)listener_child_state,
},
.callback = callback,
.param = param,
.status = FAILED,
.id = unique_id,
},
.public = {
.execute = (void*)terminate_ike_execute,
.destroy = (void*)recheckin,
},
};
ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
unique_id, FALSE);
if (ike_sa == NULL)
{
DBG1(DBG_IKE, "unable to terminate IKE_SA: ID %d not found", unique_id);
return NOT_FOUND;
}
job.listener.ike_sa = ike_sa;
if (callback == NULL)
{
return terminate_ike_execute(&job);
}
charon->bus->listen(charon->bus, &job.listener.public, (job_t*)&job);
return job.listener.status;
}
/**
* execute function for terminate_child
*/
static status_t terminate_child_execute(interface_job_t *job)
{
interface_listener_t *listener = &job->listener;
ike_sa_t *ike_sa = listener->ike_sa;
child_sa_t *child_sa = listener->child_sa;
charon->bus->set_sa(charon->bus, ike_sa);
if (ike_sa->delete_child_sa(ike_sa, child_sa->get_protocol(child_sa),
child_sa->get_spi(child_sa, TRUE)) != DESTROY_ME)
{
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
return SUCCESS;
}
charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
return FAILED;
}
/**
* Implementation of controller_t.terminate_child.
*/
static status_t terminate_child(controller_t *this, u_int32_t reqid,
controller_cb_t callback, void *param)
{
ike_sa_t *ike_sa;
child_sa_t *child_sa;
iterator_t *iterator;
interface_job_t job = {
.listener = {
.public = {
.log = (void*)listener_log,
.ike_state_change = (void*)listener_ike_state,
.child_state_change = (void*)listener_child_state,
},
.callback = callback,
.param = param,
.status = FAILED,
.id = reqid,
},
.public = {
.execute = (void*)terminate_child_execute,
.destroy = (void*)recheckin,
},
};
ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
reqid, TRUE);
if (ike_sa == NULL)
{
DBG1(DBG_IKE, "unable to terminate, CHILD_SA with ID %d not found",
reqid);
return NOT_FOUND;
}
job.listener.ike_sa = ike_sa;
iterator = ike_sa->create_child_sa_iterator(ike_sa);
while (iterator->iterate(iterator, (void**)&child_sa))
{
if (child_sa->get_state(child_sa) != CHILD_ROUTED &&
child_sa->get_reqid(child_sa) == reqid)
{
break;
}
child_sa = NULL;
}
iterator->destroy(iterator);
if (child_sa == NULL)
{
DBG1(DBG_IKE, "unable to terminate, established "
"CHILD_SA with ID %d not found", reqid);
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
return NOT_FOUND;
}
job.listener.child_sa = child_sa;
if (callback == NULL)
{
return terminate_child_execute(&job);
}
charon->bus->listen(charon->bus, &job.listener.public, (job_t*)&job);
return job.listener.status;
}
/**
* See header
*/
bool controller_cb_empty(void *param, debug_t group, level_t level,
ike_sa_t *ike_sa, char *format, va_list args)
{
return TRUE;
}
/**
* Implementation of stroke_t.destroy.
*/
static void destroy(private_controller_t *this)
{
free(this);
}
/*
* Described in header-file
*/
controller_t *controller_create(void)
{
private_controller_t *this = malloc_thing(private_controller_t);
this->public.create_ike_sa_enumerator = (enumerator_t*(*)(controller_t*))create_ike_sa_enumerator;
this->public.initiate = (status_t(*)(controller_t*,peer_cfg_t*,child_cfg_t*,controller_cb_t,void*))initiate;
this->public.terminate_ike = (status_t(*)(controller_t*,u_int32_t,controller_cb_t, void*))terminate_ike;
this->public.terminate_child = (status_t(*)(controller_t*,u_int32_t,controller_cb_t, void *param))terminate_child;
this->public.destroy = (void (*)(controller_t*))destroy;
return &this->public;
}
+140
View File
@@ -0,0 +1,140 @@
/*
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup controller_i controller
* @{ @ingroup control
*/
#ifndef CONTROLLER_H_
#define CONTROLLER_H_
#include <bus/bus.h>
/**
* callback to log things triggered by controller.
*
* @param param echoed parameter supplied when function invoked
* @param group debugging group
* @param level verbosity level if log
* @param ike_sa associated IKE_SA, if any
* @param format printf like format string
* @param args list of arguments to use for format
* @return FALSE to return from invoked function
*/
typedef bool(*controller_cb_t)(void* param, debug_t group, level_t level,
ike_sa_t* ike_sa, char* format, va_list args);
/**
* Empty callback function for controller_t functions.
*
* If you want to do a synchronous call, but don't need a callback, pass
* this function to the controllers methods.
*/
bool controller_cb_empty(void *param, debug_t group, level_t level,
ike_sa_t *ike_sa, char *format, va_list args);
typedef struct controller_t controller_t;
/**
* The controller provides a simple interface to run actions.
*
* The controller starts actions by creating jobs. It then tries to
* evaluate the result of the operation by listening on the bus.
*
* Passing NULL as callback to the managers function calls them asynchronously.
* If a callback is specified, they are called synchronously. There is a default
* callback "controller_cb_empty" if you wan't to call a function
* synchronously, but don't need a callback.
*/
struct controller_t {
/**
* Create an enumerator for all IKE_SAs.
*
* The enumerator blocks the IKE_SA manager until it gets destroyed. Do
* not call another interface/manager method while the iterator is alive.
*
* @return enumerator, locks IKE_SA manager until destroyed
*/
enumerator_t* (*create_ike_sa_enumerator)(controller_t *this);
/**
* Initiate a CHILD_SA, and if required, an IKE_SA.
*
* The initiate() function is synchronous and thus blocks until the
* IKE_SA is established or failed. Because of this, the initiate() function
* contains a thread cancellation point.
*
* @param peer_cfg peer_cfg to use for IKE_SA setup
* @param child_cfg child_cfg to set up CHILD_SA from
* @param cb logging callback
* @param param parameter to include in each call of cb
* @return
* - SUCCESS, if CHILD_SA established
* - FAILED, if setup failed
* - NEED_MORE, if callback returned FALSE
*/
status_t (*initiate)(controller_t *this,
peer_cfg_t *peer_cfg, child_cfg_t *child_cfg,
controller_cb_t callback, void *param);
/**
* Terminate an IKE_SA and all of its CHILD_SAs.
*
* The terminate() function is synchronous and thus blocks until the
* IKE_SA is properly deleted, or the delete timed out.
* The terminate() function contains a thread cancellation point.
*
* @param unique_id unique id of the IKE_SA to terminate.
* @param cb logging callback
* @param param parameter to include in each call of cb
* @return
* - SUCCESS, if CHILD_SA terminated
* - NOT_FOUND, if no such CHILD_SA found
* - NEED_MORE, if callback returned FALSE
*/
status_t (*terminate_ike)(controller_t *this, u_int32_t unique_id,
controller_cb_t callback, void *param);
/**
* Terminate a CHILD_SA.
*
* @param reqid reqid of the CHILD_SA to terminate
* @param cb logging callback
* @param param parameter to include in each call of cb
* @return
* - SUCCESS, if CHILD_SA terminated
* - NOT_FOUND, if no such CHILD_SA found
* - NEED_MORE, if callback returned FALSE
*/
status_t (*terminate_child)(controller_t *this, u_int32_t reqid,
controller_cb_t callback, void *param);
/**
* Destroy a controller_t instance.
*/
void (*destroy) (controller_t *this);
};
/**
* Creates a controller instance.
*
* @return controller_t object
*/
controller_t *controller_create(void);
#endif /** CONTROLLER_H_ @}*/
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,203 @@
/*
* Copyright (C) 2007-2009 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup credential_manager credential_manager
* @{ @ingroup ccredentials
*/
#ifndef CREDENTIAL_MANAGER_H_
#define CREDENTIAL_MANAGER_H_
#include <utils/identification.h>
#include <utils/enumerator.h>
#include <config/auth_cfg.h>
#include <credentials/credential_set.h>
#include <credentials/keys/private_key.h>
#include <credentials/keys/shared_key.h>
#include <credentials/certificates/certificate.h>
typedef struct credential_manager_t credential_manager_t;
/**
* Manages credentials using credential_sets.
*
* The credential manager is the entry point of the credential framework. It
* uses so called "sets" to access credentials in a modular fashion, these
* are implemented through the credential_set_t interface.
* The manager additionally does trust chain verification and trust status
* chaching. A set may call the managers methods if it needs credentials itself,
* the manager uses recursive locking.
*
* @verbatim
+-------+ +----------------+
| A | | | +------------------+
| u | -----> | | ------> | +------------------+
| t | | credential- | | | +------------------+
| h | -----> | manager | ------> +--| | credential- | => IPC
| e | | | +--| sets |
| n | +--> | | ------> +------------------+
| t | | | | |
| i | | | | |
| c | | +----------------+ |
| a | | |
| t | +----------------------------------------------+
| o | may be recursive
| r |
+-------+
@endverbatim
*
* The credential manager uses rwlocks for performance reasons, credential
* sets must be fully thread save.
*/
struct credential_manager_t {
/**
* Create an enumerator over all certificates.
*
* @param cert kind of certificate
* @param key kind of key in certificate
* @param id subject this certificate belongs to
* @param trusted TRUE to list trusted certificates only
* @return enumerator over the certificates
*/
enumerator_t *(*create_cert_enumerator)(credential_manager_t *this,
certificate_type_t cert, key_type_t key,
identification_t *id, bool trusted);
/**
* Create an enumerator over all shared keys.
*
* The enumerator enumerates over:
* shared_key_t*, id_match_t me, id_match_t other
* But must accepts values for the id_matches.
*
* @param type kind of requested shared key
* @param first first subject between key is shared
* @param second second subject between key is shared
* @return enumerator over shared keys
*/
enumerator_t *(*create_shared_enumerator)(credential_manager_t *this,
shared_key_type_t type,
identification_t *first, identification_t *second);
/**
* Create an enumerator over all Certificate Distribution Points.
*
* @param type kind of certificate the point distributes
* @param id identification of the distributed certificate
* @return enumerator of CDPs as char*
*/
enumerator_t *(*create_cdp_enumerator)(credential_manager_t *this,
certificate_type_t type, identification_t *id);
/**
* Get a trusted or untrusted certificate.
*
* @param cert kind of certificate
* @param key kind of key in certificate
* @param id subject this certificate belongs to
* @param trusted TRUE to get a trusted certificate only
* @return certificate, if found, NULL otherwise
*/
certificate_t *(*get_cert)(credential_manager_t *this,
certificate_type_t cert, key_type_t key,
identification_t *id, bool trusted);
/**
* Get the best matching shared key for two IDs.
*
* @param type kind of requested shared key
* @param me own identity
* @param other peers identity
* @return shared_key_t, NULL if none found
*/
shared_key_t *(*get_shared)(credential_manager_t *this, shared_key_type_t type,
identification_t *me, identification_t *other);
/**
* Get a private key to create a signature.
*
* The get_private() method gets a secret private key identified by either
* the keyid itself or an id the key belongs to.
* The auth parameter contains additional information, such as receipients
* trusted CA certs. Auth gets filled with subject and CA certificates
* needed to validate a created signature.
*
* @param type type of the key to get
* @param id identification the key belongs to
* @param auth auth config, including trusted CA certificates
* @return private_key_t, NULL if none found
*/
private_key_t* (*get_private)(credential_manager_t *this, key_type_t type,
identification_t *id, auth_cfg_t *auth);
/**
* Create an enumerator over trusted public keys.
*
* This method gets a an enumerator over trusted public keys to verify a
* signature created by id. The auth parameter contains additional
* authentication infos, e.g. peer and intermediate certificates.
* The resulting enumerator enumerates over public_key_t *, auth_cfg_t *,
* where the auth config helper contains rules for constraint checks.
*
* @param type type of the key to get
* @param id owner of the key, signer of the signature
* @param auth authentication infos
* @return enumerator
*/
enumerator_t* (*create_public_enumerator)(credential_manager_t *this,
key_type_t type, identification_t *id, auth_cfg_t *auth);
/**
* Cache a certificate by invoking cache_cert() on all registerd sets.
*
* @param cert certificate to cache
*/
void (*cache_cert)(credential_manager_t *this, certificate_t *cert);
/**
* Flush the certificate cache.
*
* Only the managers local cache is flushed, but not the sets cache filled
* by the cache_cert() method.
*
* @param type type of certificate to flush, or CERT_ANY
*/
void (*flush_cache)(credential_manager_t *this, certificate_type_t type);
/**
* Register a credential set to the manager.
*
* @param set set to register
*/
void (*add_set)(credential_manager_t *this, credential_set_t *set);
/**
* Unregister a credential set from the manager.
*
* @param set set to unregister
*/
void (*remove_set)(credential_manager_t *this, credential_set_t *set);
/**
* Destroy a credential_manager instance.
*/
void (*destroy)(credential_manager_t *this);
};
/**
* Create a credential_manager instance.
*/
credential_manager_t *credential_manager_create();
#endif /** CREDENTIAL_MANAGER_H_ @}*/
+108
View File
@@ -0,0 +1,108 @@
/*
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup credential_set credential_set
* @{ @ingroup ccredentials
*/
#ifndef CREDENTIAL_SET_H_
#define CREDENTIAL_SET_H_
#include <credentials/keys/public_key.h>
#include <credentials/keys/shared_key.h>
#include <credentials/certificates/certificate.h>
typedef struct credential_set_t credential_set_t;
/**
* A set of credentials.
*
* Contains private keys, shared keys and different kinds of certificates.
* Enumerators are used because queries might return multiple matches.
* Filter parameters restrict enumeration over specific items only.
* See credential_manager_t for an overview of the credential framework.
*
* A credential set enumerator may not block the credential set, i.e. multiple
* threads must be able to hold multiple enumerators, as the credential manager
* is higly parallelized. The best way to achieve this is by using shared
* read locks for the enumerators only. Otherwiese deadlocks will occur.
* The writing cache_cert() routine is called by the manager only if no
* enumerator is alive, so it is save to use a write lock there.
*/
struct credential_set_t {
/**
* Create an enumerator over private keys (private_key_t).
*
* The id is either a key identifier of the requested key, or an identity
* of the key owner.
*
* @param type type of requested private key
* @param id key identifier/owner
* @return enumerator over private_key_t's.
*/
enumerator_t *(*create_private_enumerator)(credential_set_t *this,
key_type_t type, identification_t *id);
/**
* Create an enumerator over certificates (certificate_t).
*
* @param cert kind of certificate
* @param key kind of key in certificate
* @param id identity (subject) this certificate belongs to
* @param trusted whether the certificate must be trustworthy
* @return enumerator as described above
*/
enumerator_t *(*create_cert_enumerator)(credential_set_t *this,
certificate_type_t cert, key_type_t key,
identification_t *id, bool trusted);
/**
* Create an enumerator over shared keys (shared_key_t).
*
* The enumerator enumerates over:
* shared_key_t*, id_match_t me, id_match_t other
* But must accept NULL values for the id_matches.
*
* @param type kind of requested shared key
* @param me own identity
* @param other other identity who owns that secret
* @return enumerator as described above
*/
enumerator_t *(*create_shared_enumerator)(credential_set_t *this,
shared_key_type_t type,
identification_t *me, identification_t *other);
/**
* Create an enumerator over certificate distribution points.
*
* @param type type of the certificate to get a CDP
* @param id identification of the distributed certificate
* @return an enumerator over CDPs as char*
*/
enumerator_t *(*create_cdp_enumerator)(credential_set_t *this,
certificate_type_t type, identification_t *id);
/**
* Cache a certificate in the credential set.
*
* The caching policy is implementation dependent, the sets may cache the
* certificate in-memory, persistent on disk or not at all.
*
* @param cert certificate to cache
*/
void (*cache_cert)(credential_set_t *this, certificate_t *cert);
};
#endif /** CREDENTIAL_SET_H_ @}*/
@@ -0,0 +1,223 @@
/*
* Copyright (C) 2008-2009 Martin Willi
* Copyright (C) 2008 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <daemon.h>
#include "auth_cfg_wrapper.h"
typedef struct private_auth_cfg_wrapper_t private_auth_cfg_wrapper_t;
/**
* private data of auth_cfg_wrapper
*/
struct private_auth_cfg_wrapper_t {
/**
* public functions
*/
auth_cfg_wrapper_t public;
/**
* wrapped auth info
*/
auth_cfg_t *auth;
};
/**
* enumerator for auth_cfg_wrapper_t.create_cert_enumerator()
*/
typedef struct {
/** implements enumerator_t */
enumerator_t public;
/** inner enumerator from auth_cfg */
enumerator_t *inner;
/** wrapped auth round */
auth_cfg_t *auth;
/** enumerated cert type */
certificate_type_t cert;
/** enumerated key type */
key_type_t key;
/** enumerated id */
identification_t *id;
} wrapper_enumerator_t;
/**
* Tries to fetch a certificate that was supplied as "Hash and URL"
* (replaces rule type and value in place).
*/
static bool fetch_cert(wrapper_enumerator_t *enumerator,
auth_rule_t *rule, void **value)
{
char *url = (char*)*value;
if (!url)
{
/* fetching the certificate previously failed */
return FALSE;
}
chunk_t data;
certificate_t *cert;
DBG1(DBG_CFG, " fetching certificate from '%s' ...", url);
if (lib->fetcher->fetch(lib->fetcher, url, &data, FETCH_END) != SUCCESS)
{
DBG1(DBG_CFG, " fetching certificate failed");
/* we set the item to NULL, so we can skip it */
enumerator->auth->replace(enumerator->auth, enumerator->inner,
*rule, NULL);
return FALSE;
}
cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
BUILD_BLOB_ASN1_DER, data, BUILD_END);
free(data.ptr);
if (!cert)
{
DBG1(DBG_CFG, " parsing fetched certificate failed");
/* we set the item to NULL, so we can skip it */
enumerator->auth->replace(enumerator->auth, enumerator->inner,
*rule, NULL);
return FALSE;
}
DBG1(DBG_CFG, " fetched certificate \"%Y\"", cert->get_subject(cert));
charon->credentials->cache_cert(charon->credentials, cert);
if (*rule == AUTH_HELPER_IM_HASH_URL)
{
*rule = AUTH_HELPER_IM_CERT;
}
else
{
*rule = AUTH_HELPER_SUBJECT_CERT;
}
*value = cert;
enumerator->auth->replace(enumerator->auth, enumerator->inner,
*rule, cert->get_ref(cert));
return TRUE;
}
/**
* enumerate function for wrapper_enumerator_t
*/
static bool enumerate(wrapper_enumerator_t *this, certificate_t **cert)
{
auth_rule_t rule;
certificate_t *current;
public_key_t *public;
while (this->inner->enumerate(this->inner, &rule, &current))
{
if (rule == AUTH_HELPER_IM_HASH_URL ||
rule == AUTH_HELPER_SUBJECT_HASH_URL)
{ /* on-demand fetching of hash and url certificates */
if (!fetch_cert(this, &rule, (void**)&current))
{
continue;
}
}
else if (rule != AUTH_HELPER_SUBJECT_CERT &&
rule != AUTH_HELPER_IM_CERT)
{ /* handle only HELPER certificates */
continue;
}
if (this->cert != CERT_ANY && this->cert != current->get_type(current))
{ /* CERT type requested, but does not match */
continue;
}
public = current->get_public_key(current);
if (this->key != KEY_ANY && !public)
{ /* key type requested, but no public key */
DESTROY_IF(public);
continue;
}
if (this->key != KEY_ANY && public && this->key != public->get_type(public))
{ /* key type requested, but public key has another type */
DESTROY_IF(public);
continue;
}
DESTROY_IF(public);
if (this->id && !current->has_subject(current, this->id))
{ /* subject requested, but does not match */
continue;
}
*cert = current;
return TRUE;
}
return FALSE;
}
/**
* destroy function for wrapper_enumerator_t
*/
static void wrapper_enumerator_destroy(wrapper_enumerator_t *this)
{
this->inner->destroy(this->inner);
free(this);
}
/**
* implementation of auth_cfg_wrapper_t.set.create_cert_enumerator
*/
static enumerator_t *create_enumerator(private_auth_cfg_wrapper_t *this,
certificate_type_t cert, key_type_t key,
identification_t *id, bool trusted)
{
wrapper_enumerator_t *enumerator;
if (trusted)
{
return NULL;
}
enumerator = malloc_thing(wrapper_enumerator_t);
enumerator->auth = this->auth;
enumerator->cert = cert;
enumerator->key = key;
enumerator->id = id;
enumerator->inner = this->auth->create_enumerator(this->auth);
enumerator->public.enumerate = (void*)enumerate;
enumerator->public.destroy = (void*)wrapper_enumerator_destroy;
return &enumerator->public;
}
/**
* Implementation of auth_cfg_wrapper_t.destroy
*/
static void destroy(private_auth_cfg_wrapper_t *this)
{
free(this);
}
/*
* see header file
*/
auth_cfg_wrapper_t *auth_cfg_wrapper_create(auth_cfg_t *auth)
{
private_auth_cfg_wrapper_t *this = malloc_thing(private_auth_cfg_wrapper_t);
this->public.set.create_private_enumerator = (void*)return_null;
this->public.set.create_cert_enumerator = (void*)create_enumerator;
this->public.set.create_shared_enumerator = (void*)return_null;
this->public.set.create_cdp_enumerator = (void*)return_null;
this->public.set.cache_cert = (void*)nop;
this->public.destroy = (void(*)(auth_cfg_wrapper_t*))destroy;
this->auth = auth;
return &this->public;
}
@@ -0,0 +1,53 @@
/*
* Copyright (C) 2008-2009 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup auth_cfg_wrapper auth_cfg_wrapper
* @{ @ingroup sets
*/
#ifndef AUTH_CFG_WRAPPER_H_
#define AUTH_CFG_WRAPPER_H_
#include <config/auth_cfg.h>
#include <credentials/credential_set.h>
typedef struct auth_cfg_wrapper_t auth_cfg_wrapper_t;
/**
* A wrapper around auth_cfg_t to handle it as a credential set.
*/
struct auth_cfg_wrapper_t {
/**
* implements credential_set_t
*/
credential_set_t set;
/**
* Destroy a auth_cfg_wrapper instance.
*/
void (*destroy)(auth_cfg_wrapper_t *this);
};
/**
* Create a auth_cfg_wrapper instance.
*
* @param auth the wrapped auth info
* @return wrapper around auth
*/
auth_cfg_wrapper_t *auth_cfg_wrapper_create(auth_cfg_t *auth);
#endif /** AUTH_CFG_WRAPPER_H_ @}*/
+390
View File
@@ -0,0 +1,390 @@
/*
* Copyright (C) 2008 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "cert_cache.h"
#include <time.h>
#include <sched.h>
#include <daemon.h>
#include <threading/rwlock.h>
#include <utils/linked_list.h>
/** cache size, a power of 2 for fast modulo */
#define CACHE_SIZE 32
/** attempts to acquire a cache lock */
#define REPLACE_TRIES 5
typedef struct private_cert_cache_t private_cert_cache_t;
typedef struct relation_t relation_t;
/**
* A trusted relation between subject and issuer
*/
struct relation_t {
/**
* subject of this relation
*/
certificate_t *subject;
/**
* issuer of this relation
*/
certificate_t *issuer;
/**
* Cache hits
*/
u_int hits;
/**
* Lock for this relation
*/
rwlock_t *lock;
};
/**
* private data of cert_cache
*/
struct private_cert_cache_t {
/**
* public functions
*/
cert_cache_t public;
/**
* array of trusted subject-issuer relations
*/
relation_t relations[CACHE_SIZE];
};
/**
* Cache relation in a free slot/replace an other
*/
static void cache(private_cert_cache_t *this,
certificate_t *subject, certificate_t *issuer)
{
relation_t *rel;
int i, offset, try;
u_int total_hits = 0;
/* check for a unused relation slot first */
for (i = 0; i < CACHE_SIZE; i++)
{
rel = &this->relations[i];
if (!rel->subject && rel->lock->try_write_lock(rel->lock))
{
/* double-check having lock */
if (!rel->subject)
{
rel->subject = subject->get_ref(subject);
rel->issuer = issuer->get_ref(issuer);
return rel->lock->unlock(rel->lock);
}
rel->lock->unlock(rel->lock);
}
total_hits += rel->hits;
}
/* run several attempts to replace a random slot, never block. */
for (try = 0; try < REPLACE_TRIES; try++)
{
/* replace a random relation */
offset = random();
for (i = 0; i < CACHE_SIZE; i++)
{
rel = &this->relations[(i + offset) % CACHE_SIZE];
if (rel->hits > total_hits / CACHE_SIZE)
{ /* skip often used slots */
continue;
}
if (rel->lock->try_write_lock(rel->lock))
{
if (rel->subject)
{
rel->subject->destroy(rel->subject);
rel->issuer->destroy(rel->issuer);
}
rel->subject = subject->get_ref(subject);
rel->issuer = issuer->get_ref(issuer);
rel->hits = 0;
return rel->lock->unlock(rel->lock);
}
}
/* give other threads a chance to release locks */
sched_yield();
}
}
/**
* Implementation of cert_cache_t.issued_by.
*/
static bool issued_by(private_cert_cache_t *this,
certificate_t *subject, certificate_t *issuer)
{
relation_t *found = NULL, *current;
int i;
for (i = 0; i < CACHE_SIZE; i++)
{
current = &this->relations[i];
current->lock->read_lock(current->lock);
if (current->subject)
{
/* check for equal issuer */
if (issuer->equals(issuer, current->issuer))
{
/* reuse issuer instance in cache() */
issuer = current->issuer;
if (subject->equals(subject, current->subject))
{
/* write hit counter is not locked, but not critical */
current->hits++;
found = current;
}
}
}
current->lock->unlock(current->lock);
if (found)
{
return TRUE;
}
}
/* no cache hit, check and cache signature */
if (subject->issued_by(subject, issuer))
{
cache(this, subject, issuer);
return TRUE;
}
return FALSE;
}
/**
* certificate enumerator implemenation
*/
typedef struct {
/** implements enumerator_t interface */
enumerator_t public;
/** type of requested certificate */
certificate_type_t cert;
/** type of requested key */
key_type_t key;
/** ID to get a cert for */
identification_t *id;
/** cache */
relation_t *relations;
/** current position in array cache */
int index;
/** currently locked relation */
int locked;
} cert_enumerator_t;
/**
* filter function for certs enumerator
*/
static bool cert_enumerate(cert_enumerator_t *this, certificate_t **out)
{
public_key_t *public;
relation_t *rel;
if (this->locked >= 0)
{
rel = &this->relations[this->locked];
rel->lock->unlock(rel->lock);
this->locked = -1;
}
while (++this->index < CACHE_SIZE)
{
rel = &this->relations[this->index];
rel->lock->read_lock(rel->lock);
this->locked = this->index;
if (rel->subject)
{
/* CRL lookup is done using issuer/authkeyidentifier */
if (this->key == KEY_ANY && this->id &&
(this->cert == CERT_ANY || this->cert == CERT_X509_CRL) &&
rel->subject->get_type(rel->subject) == CERT_X509_CRL &&
rel->subject->has_issuer(rel->subject, this->id))
{
*out = rel->subject;
return TRUE;
}
if ((this->cert == CERT_ANY ||
rel->subject->get_type(rel->subject) == this->cert) &&
(!this->id || rel->subject->has_subject(rel->subject, this->id)))
{
if (this->key == KEY_ANY)
{
*out = rel->subject;
return TRUE;
}
public = rel->subject->get_public_key(rel->subject);
if (public)
{
if (public->get_type(public) == this->key)
{
public->destroy(public);
*out = rel->subject;
return TRUE;
}
public->destroy(public);
}
}
}
this->locked = -1;
rel->lock->unlock(rel->lock);
}
return FALSE;
}
/**
* clean up enumeration data
*/
static void cert_enumerator_destroy(cert_enumerator_t *this)
{
relation_t *rel;
if (this->locked >= 0)
{
rel = &this->relations[this->locked];
rel->lock->unlock(rel->lock);
}
free(this);
}
/**
* implementation of credential_set_t.create_cert_enumerator
*/
static enumerator_t *create_enumerator(private_cert_cache_t *this,
certificate_type_t cert, key_type_t key,
identification_t *id, bool trusted)
{
cert_enumerator_t *enumerator;
if (trusted)
{
return NULL;
}
enumerator = malloc_thing(cert_enumerator_t);
enumerator->public.enumerate = (void*)cert_enumerate;
enumerator->public.destroy = (void*)cert_enumerator_destroy;
enumerator->cert = cert;
enumerator->key = key;
enumerator->id = id;
enumerator->relations = this->relations;
enumerator->index = -1;
enumerator->locked = -1;
return &enumerator->public;
}
/**
* Implementation of cert_cache_t.flush.
*/
static void flush(private_cert_cache_t *this, certificate_type_t type)
{
relation_t *rel;
int i;
for (i = 0; i < CACHE_SIZE; i++)
{
rel = &this->relations[i];
if (!rel->subject)
{
continue;
}
/* check with cheap read lock first */
if (type != CERT_ANY)
{
rel->lock->read_lock(rel->lock);
if (!rel->subject || type != rel->subject->get_type(rel->subject))
{
rel->lock->unlock(rel->lock);
continue;
}
rel->lock->unlock(rel->lock);
}
/* double check in write lock */
rel->lock->write_lock(rel->lock);
if (rel->subject)
{
if (type == CERT_ANY || type == rel->subject->get_type(rel->subject))
{
rel->subject->destroy(rel->subject);
rel->issuer->destroy(rel->issuer);
rel->subject = NULL;
rel->issuer = NULL;
rel->hits = 0;
}
}
rel->lock->unlock(rel->lock);
}
}
/**
* Implementation of cert_cache_t.destroy
*/
static void destroy(private_cert_cache_t *this)
{
relation_t *rel;
int i;
for (i = 0; i < CACHE_SIZE; i++)
{
rel = &this->relations[i];
if (rel->subject)
{
rel->subject->destroy(rel->subject);
rel->issuer->destroy(rel->issuer);
}
rel->lock->destroy(rel->lock);
}
free(this);
}
/*
* see header file
*/
cert_cache_t *cert_cache_create()
{
private_cert_cache_t *this;
int i;
this = malloc_thing(private_cert_cache_t);
this->public.set.create_private_enumerator = (void*)return_null;
this->public.set.create_cert_enumerator = (void*)create_enumerator;
this->public.set.create_shared_enumerator = (void*)return_null;
this->public.set.create_cdp_enumerator = (void*)return_null;
this->public.set.cache_cert = (void*)nop;
this->public.issued_by = (bool(*)(cert_cache_t*, certificate_t *subject, certificate_t *issuer))issued_by;
this->public.flush = (void(*)(cert_cache_t*, certificate_type_t type))flush;
this->public.destroy = (void(*)(cert_cache_t*))destroy;
for (i = 0; i < CACHE_SIZE; i++)
{
this->relations[i].subject = NULL;
this->relations[i].issuer = NULL;
this->relations[i].hits = 0;
this->relations[i].lock = rwlock_create(RWLOCK_TYPE_DEFAULT);
}
return &this->public;
}
@@ -0,0 +1,71 @@
/*
* Copyright (C) 2008 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup cert_cache cert_cache
* @{ @ingroup sets
*/
#ifndef CERT_CACHE_H_
#define CERT_CACHE_H_
#include <credentials/credential_set.h>
typedef struct cert_cache_t cert_cache_t;
/**
* Certificate signature verification and certificate cache.
*
* This cache serves all certificates seen in its issued_by method
* and serves them as untrusted through the credential set interface. Further,
* it caches valid subject-issuer relationships to speed up the issued_by
* method.
*/
struct cert_cache_t {
/**
* Implements credential_set_t.
*/
credential_set_t set;
/**
* Caching wrapper around certificate_t.issued_by.
*
* @param subject certificate to verify
* @param issuer issuing certificate to verify subject
* @return TRUE if subject issued by issuer
*/
bool (*issued_by)(cert_cache_t *this,
certificate_t *subject, certificate_t *issuer);
/**
* Flush the certificate cache.
*
* @param type type of certificate to flush, or CERT_ANY
*/
void (*flush)(cert_cache_t *this, certificate_type_t type);
/**
* Destroy a cert_cache instance.
*/
void (*destroy)(cert_cache_t *this);
};
/**
* Create a cert_cache instance.
*/
cert_cache_t *cert_cache_create();
#endif /** CERT_CACHE_H_ @}*/
@@ -0,0 +1,147 @@
/*
* Copyright (C) 2008 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "ocsp_response_wrapper.h"
typedef struct private_ocsp_response_wrapper_t private_ocsp_response_wrapper_t;
/**
* private data of ocsp_response_wrapper
*/
struct private_ocsp_response_wrapper_t {
/**
* public functions
*/
ocsp_response_wrapper_t public;
/**
* wrapped OCSP response
*/
ocsp_response_t *response;
};
/**
* enumerator for ocsp_response_wrapper_t.create_cert_enumerator()
*/
typedef struct {
/** implements enumerator_t */
enumerator_t public;
/** enumerator over ocsp response */
enumerator_t *inner;
/** type of cert */
certificate_type_t cert;
/** type of key */
key_type_t key;
/** filtering identity */
identification_t *id;
} wrapper_enumerator_t;
/**
* enumerate function wrapper_enumerator_t
*/
static bool enumerate(wrapper_enumerator_t *this, certificate_t **cert)
{
certificate_t *current;
public_key_t *public;
while (this->inner->enumerate(this->inner, &current))
{
if (this->cert != CERT_ANY && this->cert != current->get_type(current))
{ /* CERT type requested, but does not match */
continue;
}
public = current->get_public_key(current);
if (this->key != KEY_ANY && !public)
{ /* key type requested, but no public key */
DESTROY_IF(public);
continue;
}
if (this->key != KEY_ANY && public && this->key != public->get_type(public))
{ /* key type requested, but public key has another type */
DESTROY_IF(public);
continue;
}
DESTROY_IF(public);
if (this->id && !current->has_subject(current, this->id))
{ /* subject requested, but does not match */
continue;
}
*cert = current;
return TRUE;
}
return FALSE;
}
/**
* destroy function for wrapper_enumerator_t
*/
static void enumerator_destroy(wrapper_enumerator_t *this)
{
this->inner->destroy(this->inner);
free(this);
}
/**
* implementation of ocsp_response_wrapper_t.set.create_cert_enumerator
*/
static enumerator_t *create_enumerator(private_ocsp_response_wrapper_t *this,
certificate_type_t cert, key_type_t key,
identification_t *id, bool trusted)
{
wrapper_enumerator_t *enumerator;
if (trusted)
{
return NULL;
}
enumerator = malloc_thing(wrapper_enumerator_t);
enumerator->cert = cert;
enumerator->key = key;
enumerator->id = id;
enumerator->inner = this->response->create_cert_enumerator(this->response);
enumerator->public.enumerate = (void*)enumerate;
enumerator->public.destroy = (void*)enumerator_destroy;
return &enumerator->public;
}
/**
* Implementation of ocsp_response_wrapper_t.destroy
*/
static void destroy(private_ocsp_response_wrapper_t *this)
{
free(this);
}
/*
* see header file
*/
ocsp_response_wrapper_t *ocsp_response_wrapper_create(ocsp_response_t *response)
{
private_ocsp_response_wrapper_t *this = malloc_thing(private_ocsp_response_wrapper_t);
this->public.set.create_private_enumerator = (void*)return_null;
this->public.set.create_cert_enumerator = (void*)create_enumerator;
this->public.set.create_shared_enumerator = (void*)return_null;
this->public.set.create_cdp_enumerator = (void*)return_null;
this->public.set.cache_cert = (void*)nop;
this->public.destroy = (void(*)(ocsp_response_wrapper_t*))destroy;
this->response = response;
return &this->public;
}
@@ -0,0 +1,53 @@
/*
* Copyright (C) 2008 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup ocsp_response_wrapper ocsp_response_wrapper
* @{ @ingroup sets
*/
#ifndef OCSP_RESPONSE_WRAPPER_H_
#define OCSP_RESPONSE_WRAPPER_H_
#include <credentials/credential_set.h>
#include <credentials/certificates/ocsp_response.h>
typedef struct ocsp_response_wrapper_t ocsp_response_wrapper_t;
/**
* A wrapper around ocsp_response_t to handle it like a credential set.
*/
struct ocsp_response_wrapper_t {
/**
* implements credential_set_t
*/
credential_set_t set;
/**
* Destroy a ocsp_response_wrapper instance.
*/
void (*destroy)(ocsp_response_wrapper_t *this);
};
/**
* Create a ocsp_response_wrapper instance.
*
* @param response the wrapped OCSP response
* @return wrapper around response
*/
ocsp_response_wrapper_t *ocsp_response_wrapper_create(ocsp_response_t *response);
#endif /** OCSP_RESPONSE_WRAPPER_H_ @}*/
+789
View File
@@ -0,0 +1,789 @@
/*
* Copyright (C) 2006-2009 Tobias Brunner
* Copyright (C) 2005-2009 Martin Willi
* Copyright (C) 2006 Daniel Roethlisberger
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <stdio.h>
#ifdef HAVE_PRCTL
#include <sys/prctl.h>
#endif
#define _POSIX_PTHREAD_SEMANTICS /* for two param sigwait on OpenSolaris */
#include <signal.h>
#undef _POSIX_PTHREAD_SEMANTICS
#include <pthread.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <time.h>
#include <string.h>
#include <getopt.h>
#include <errno.h>
#include <pwd.h>
#include <grp.h>
#ifdef CAPABILITIES
#include <sys/capability.h>
#endif /* CAPABILITIES */
#include "daemon.h"
#include <library.h>
#include <utils/backtrace.h>
#include <threading/thread.h>
#include <selectors/traffic_selector.h>
#include <config/proposal.h>
#ifndef LOG_AUTHPRIV /* not defined on OpenSolaris */
#define LOG_AUTHPRIV LOG_AUTH
#endif
typedef struct private_daemon_t private_daemon_t;
/**
* Private additions to daemon_t, contains threads and internal functions.
*/
struct private_daemon_t {
/**
* Public members of daemon_t.
*/
daemon_t public;
/**
* Signal set used for signal handling.
*/
sigset_t signal_set;
#ifdef CAPABILITIES
/**
* capabilities to keep
*/
cap_t caps;
#endif /* CAPABILITIES */
};
/**
* One and only instance of the daemon.
*/
daemon_t *charon;
/**
* hook in library for debugging messages
*/
extern void (*dbg) (int level, char *fmt, ...);
/**
* Logging hook for library logs, spreads debug message over bus
*/
static void dbg_bus(int level, char *fmt, ...)
{
va_list args;
va_start(args, fmt);
charon->bus->vlog(charon->bus, DBG_LIB, level, fmt, args);
va_end(args);
}
/**
* Logging hook for library logs, using stderr output
*/
static void dbg_stderr(int level, char *fmt, ...)
{
va_list args;
if (level <= 1)
{
va_start(args, fmt);
fprintf(stderr, "00[LIB] ");
vfprintf(stderr, fmt, args);
fprintf(stderr, "\n");
va_end(args);
}
}
/**
* Run the daemon and handle unix signals
*/
static void run(private_daemon_t *this)
{
sigset_t set;
/* handle SIGINT, SIGHUP ans SIGTERM in this handler */
sigemptyset(&set);
sigaddset(&set, SIGINT);
sigaddset(&set, SIGHUP);
sigaddset(&set, SIGTERM);
sigprocmask(SIG_BLOCK, &set, NULL);
while (TRUE)
{
int sig;
int error;
error = sigwait(&set, &sig);
if (error)
{
DBG1(DBG_DMN, "error %d while waiting for a signal", error);
return;
}
switch (sig)
{
case SIGHUP:
{
DBG1(DBG_DMN, "signal of type SIGHUP received. Ignored");
break;
}
case SIGINT:
{
DBG1(DBG_DMN, "signal of type SIGINT received. Shutting down");
charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig);
return;
}
case SIGTERM:
{
DBG1(DBG_DMN, "signal of type SIGTERM received. Shutting down");
charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig);
return;
}
default:
{
DBG1(DBG_DMN, "unknown signal %d received. Ignored", sig);
break;
}
}
}
}
/**
* Clean up all daemon resources
*/
static void destroy(private_daemon_t *this)
{
/* terminate all idle threads */
if (this->public.processor)
{
this->public.processor->set_threads(this->public.processor, 0);
}
/* close all IKE_SAs */
if (this->public.ike_sa_manager)
{
this->public.ike_sa_manager->flush(this->public.ike_sa_manager);
}
DESTROY_IF(this->public.receiver);
/* unload plugins to release threads */
lib->plugins->unload(lib->plugins);
#ifdef CAPABILITIES
cap_free(this->caps);
#endif /* CAPABILITIES */
DESTROY_IF(this->public.traps);
DESTROY_IF(this->public.ike_sa_manager);
DESTROY_IF(this->public.kernel_interface);
DESTROY_IF(this->public.scheduler);
DESTROY_IF(this->public.controller);
DESTROY_IF(this->public.eap);
DESTROY_IF(this->public.sim);
#ifdef ME
DESTROY_IF(this->public.connect_manager);
DESTROY_IF(this->public.mediation_manager);
#endif /* ME */
DESTROY_IF(this->public.backends);
DESTROY_IF(this->public.credentials);
DESTROY_IF(this->public.sender);
DESTROY_IF(this->public.socket);
/* wait until all threads are gone */
DESTROY_IF(this->public.processor);
/* rehook library logging, shutdown logging */
dbg = dbg_stderr;
DESTROY_IF(this->public.bus);
this->public.file_loggers->destroy_offset(this->public.file_loggers,
offsetof(file_logger_t, destroy));
this->public.sys_loggers->destroy_offset(this->public.sys_loggers,
offsetof(sys_logger_t, destroy));
free(this);
}
/**
* drop daemon capabilities
*/
static bool drop_capabilities(private_daemon_t *this)
{
#ifdef HAVE_PRCTL
prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
#endif
if (setgid(charon->gid) != 0)
{
DBG1(DBG_DMN, "change to unprivileged group failed");
return FALSE;
}
if (setuid(charon->uid) != 0)
{
DBG1(DBG_DMN, "change to unprivileged user failed");
return FALSE;
}
#ifdef CAPABILITIES
if (cap_set_proc(this->caps) != 0)
{
DBG1(DBG_DMN, "unable to drop daemon capabilities");
return FALSE;
}
#endif /* CAPABILITIES */
return TRUE;
}
/**
* Implementation of daemon_t.keep_cap
*/
static void keep_cap(private_daemon_t *this, u_int cap)
{
#ifdef CAPABILITIES
cap_set_flag(this->caps, CAP_EFFECTIVE, 1, &cap, CAP_SET);
cap_set_flag(this->caps, CAP_INHERITABLE, 1, &cap, CAP_SET);
cap_set_flag(this->caps, CAP_PERMITTED, 1, &cap, CAP_SET);
#endif /* CAPABILITIES */
}
/**
* lookup UID and GID
*/
static bool lookup_uid_gid(private_daemon_t *this)
{
#ifdef IPSEC_USER
{
char buf[1024];
struct passwd passwd, *pwp;
if (getpwnam_r(IPSEC_USER, &passwd, buf, sizeof(buf), &pwp) != 0 ||
pwp == NULL)
{
DBG1(DBG_DMN, "resolving user '"IPSEC_USER"' failed");
return FALSE;
}
charon->uid = pwp->pw_uid;
}
#endif
#ifdef IPSEC_GROUP
{
char buf[1024];
struct group group, *grp;
if (getgrnam_r(IPSEC_GROUP, &group, buf, sizeof(buf), &grp) != 0 ||
grp == NULL)
{
DBG1(DBG_DMN, "resolving group '"IPSEC_GROUP"' failed");
return FALSE;
}
charon->gid = grp->gr_gid;
}
#endif
return TRUE;
}
/**
* Log loaded plugins
*/
static void print_plugins()
{
char buf[512], *plugin;
int len = 0;
enumerator_t *enumerator;
buf[0] = '\0';
enumerator = lib->plugins->create_plugin_enumerator(lib->plugins);
while (len < sizeof(buf) && enumerator->enumerate(enumerator, &plugin))
{
len += snprintf(&buf[len], sizeof(buf)-len, "%s ", plugin);
}
enumerator->destroy(enumerator);
DBG1(DBG_DMN, "loaded plugins: %s", buf);
}
/**
* Initialize logging
*/
static void initialize_loggers(private_daemon_t *this, bool use_stderr,
level_t levels[])
{
sys_logger_t *sys_logger;
file_logger_t *file_logger;
enumerator_t *enumerator;
char *facility, *filename;
int loggers_defined = 0;
debug_t group;
level_t def;
bool append;
FILE *file;
/* setup sysloggers */
enumerator = lib->settings->create_section_enumerator(lib->settings,
"charon.syslog");
while (enumerator->enumerate(enumerator, &facility))
{
loggers_defined++;
if (streq(facility, "daemon"))
{
sys_logger = sys_logger_create(LOG_DAEMON);
}
else if (streq(facility, "auth"))
{
sys_logger = sys_logger_create(LOG_AUTHPRIV);
}
else
{
continue;
}
def = lib->settings->get_int(lib->settings,
"charon.syslog.%s.default", 1, facility);
for (group = 0; group < DBG_MAX; group++)
{
sys_logger->set_level(sys_logger, group,
lib->settings->get_int(lib->settings,
"charon.syslog.%s.%N", def,
facility, debug_lower_names, group));
}
this->public.sys_loggers->insert_last(this->public.sys_loggers,
sys_logger);
this->public.bus->add_listener(this->public.bus, &sys_logger->listener);
}
enumerator->destroy(enumerator);
/* and file loggers */
enumerator = lib->settings->create_section_enumerator(lib->settings,
"charon.filelog");
while (enumerator->enumerate(enumerator, &filename))
{
loggers_defined++;
if (streq(filename, "stderr"))
{
file = stderr;
}
else if (streq(filename, "stdout"))
{
file = stdout;
}
else
{
append = lib->settings->get_bool(lib->settings,
"charon.filelog.%s.append", TRUE, filename);
file = fopen(filename, append ? "a" : "w");
if (file == NULL)
{
DBG1(DBG_DMN, "opening file %s for logging failed: %s",
filename, strerror(errno));
continue;
}
}
file_logger = file_logger_create(file);
def = lib->settings->get_int(lib->settings,
"charon.filelog.%s.default", 1, filename);
for (group = 0; group < DBG_MAX; group++)
{
file_logger->set_level(file_logger, group,
lib->settings->get_int(lib->settings,
"charon.filelog.%s.%N", def,
filename, debug_lower_names, group));
}
this->public.file_loggers->insert_last(this->public.file_loggers,
file_logger);
this->public.bus->add_listener(this->public.bus, &file_logger->listener);
}
enumerator->destroy(enumerator);
/* set up legacy style default loggers provided via command-line */
if (!loggers_defined)
{
/* set up default stdout file_logger */
file_logger = file_logger_create(stdout);
this->public.bus->add_listener(this->public.bus, &file_logger->listener);
this->public.file_loggers->insert_last(this->public.file_loggers,
file_logger);
/* set up default daemon sys_logger */
sys_logger = sys_logger_create(LOG_DAEMON);
this->public.bus->add_listener(this->public.bus, &sys_logger->listener);
this->public.sys_loggers->insert_last(this->public.sys_loggers,
sys_logger);
for (group = 0; group < DBG_MAX; group++)
{
sys_logger->set_level(sys_logger, group, levels[group]);
if (use_stderr)
{
file_logger->set_level(file_logger, group, levels[group]);
}
}
/* set up default auth sys_logger */
sys_logger = sys_logger_create(LOG_AUTHPRIV);
this->public.bus->add_listener(this->public.bus, &sys_logger->listener);
this->public.sys_loggers->insert_last(this->public.sys_loggers,
sys_logger);
sys_logger->set_level(sys_logger, DBG_ANY, LEVEL_AUDIT);
}
}
/**
* Initialize the daemon
*/
static bool initialize(private_daemon_t *this, bool syslog, level_t levels[])
{
/* for uncritical pseudo random numbers */
srandom(time(NULL) + getpid());
/* setup bus and it's listeners first to enable log output */
this->public.bus = bus_create();
/* set up hook to log dbg message in library via charons message bus */
dbg = dbg_bus;
initialize_loggers(this, !syslog, levels);
DBG1(DBG_DMN, "Starting IKEv2 charon daemon (strongSwan "VERSION")");
if (lib->integrity)
{
DBG1(DBG_DMN, "integrity tests enabled:");
DBG1(DBG_DMN, "lib 'libstrongswan': passed file and segment integrity tests");
DBG1(DBG_DMN, "daemon 'charon': passed file integrity test");
}
/* load secrets, ca certificates and crls */
this->public.processor = processor_create();
this->public.scheduler = scheduler_create();
this->public.credentials = credential_manager_create();
this->public.controller = controller_create();
this->public.eap = eap_manager_create();
this->public.sim = sim_manager_create();
this->public.backends = backend_manager_create();
this->public.kernel_interface = kernel_interface_create();
this->public.socket = socket_manager_create();
this->public.traps = trap_manager_create();
/* load plugins, further infrastructure may need it */
if (!lib->plugins->load(lib->plugins, NULL,
lib->settings->get_str(lib->settings, "charon.load", PLUGINS)))
{
return FALSE;
}
print_plugins();
this->public.ike_sa_manager = ike_sa_manager_create();
if (this->public.ike_sa_manager == NULL)
{
return FALSE;
}
this->public.sender = sender_create();
this->public.receiver = receiver_create();
if (this->public.receiver == NULL)
{
return FALSE;
}
#ifdef ME
this->public.connect_manager = connect_manager_create();
if (this->public.connect_manager == NULL)
{
return FALSE;
}
this->public.mediation_manager = mediation_manager_create();
#endif /* ME */
return TRUE;
}
/**
* Handle SIGSEGV/SIGILL signals raised by threads
*/
static void segv_handler(int signal)
{
backtrace_t *backtrace;
DBG1(DBG_DMN, "thread %u received %d", thread_current_id(), signal);
backtrace = backtrace_create(2);
backtrace->log(backtrace, stderr);
backtrace->destroy(backtrace);
DBG1(DBG_DMN, "killing ourself, received critical signal");
abort();
}
/**
* Create the daemon.
*/
private_daemon_t *daemon_create(void)
{
struct sigaction action;
private_daemon_t *this = malloc_thing(private_daemon_t);
/* assign methods */
this->public.keep_cap = (void(*)(daemon_t*, u_int cap))keep_cap;
/* NULL members for clean destruction */
this->public.socket = NULL;
this->public.ike_sa_manager = NULL;
this->public.traps = NULL;
this->public.credentials = NULL;
this->public.backends = NULL;
this->public.sender= NULL;
this->public.receiver = NULL;
this->public.scheduler = NULL;
this->public.kernel_interface = NULL;
this->public.processor = NULL;
this->public.controller = NULL;
this->public.eap = NULL;
this->public.sim = NULL;
this->public.bus = NULL;
this->public.file_loggers = linked_list_create();
this->public.sys_loggers = linked_list_create();
#ifdef ME
this->public.connect_manager = NULL;
this->public.mediation_manager = NULL;
#endif /* ME */
this->public.uid = 0;
this->public.gid = 0;
#ifdef CAPABILITIES
this->caps = cap_init();
keep_cap(this, CAP_NET_ADMIN);
if (lib->leak_detective)
{
keep_cap(this, CAP_SYS_NICE);
}
#endif /* CAPABILITIES */
/* add handler for SEGV and ILL,
* INT, TERM and HUP are handled by sigwait() in run() */
action.sa_handler = segv_handler;
action.sa_flags = 0;
sigemptyset(&action.sa_mask);
sigaddset(&action.sa_mask, SIGINT);
sigaddset(&action.sa_mask, SIGTERM);
sigaddset(&action.sa_mask, SIGHUP);
sigaction(SIGSEGV, &action, NULL);
sigaction(SIGILL, &action, NULL);
sigaction(SIGBUS, &action, NULL);
action.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &action, NULL);
pthread_sigmask(SIG_SETMASK, &action.sa_mask, NULL);
return this;
}
/**
* Check/create PID file, return TRUE if already running
*/
static bool check_pidfile()
{
struct stat stb;
FILE *file;
if (stat(PID_FILE, &stb) == 0)
{
file = fopen(PID_FILE, "r");
if (file)
{
char buf[64];
pid_t pid = 0;
memset(buf, 0, sizeof(buf));
if (fread(buf, 1, sizeof(buf), file))
{
pid = atoi(buf);
}
fclose(file);
if (pid && kill(pid, 0) == 0)
{ /* such a process is running */
return TRUE;
}
}
DBG1(DBG_DMN, "removing pidfile '"PID_FILE"', process not running");
unlink(PID_FILE);
}
/* create new pidfile */
file = fopen(PID_FILE, "w");
if (file)
{
fprintf(file, "%d\n", getpid());
ignore_result(fchown(fileno(file), charon->uid, charon->gid));
fclose(file);
}
return FALSE;
}
/**
* print command line usage and exit
*/
static void usage(const char *msg)
{
if (msg != NULL && *msg != '\0')
{
fprintf(stderr, "%s\n", msg);
}
fprintf(stderr, "Usage: charon\n"
" [--help]\n"
" [--version]\n"
" [--use-syslog]\n"
" [--debug-<type> <level>]\n"
" <type>: log context type (dmn|mgr|ike|chd|job|cfg|knl|net|enc|lib)\n"
" <level>: log verbosity (-1 = silent, 0 = audit, 1 = control,\n"
" 2 = controlmore, 3 = raw, 4 = private)\n"
"\n"
);
exit(msg == NULL? 0 : 1);
}
/**
* Main function, manages the daemon.
*/
int main(int argc, char *argv[])
{
bool use_syslog = FALSE;
private_daemon_t *private_charon;
level_t levels[DBG_MAX];
int group;
/* logging for library during initialization, as we have no bus yet */
dbg = dbg_stderr;
/* initialize library */
if (!library_init(NULL))
{
library_deinit();
exit(SS_RC_LIBSTRONGSWAN_INTEGRITY);
}
if (lib->integrity &&
!lib->integrity->check_file(lib->integrity, "charon", argv[0]))
{
dbg_stderr(1, "integrity check of charon failed");
library_deinit();
exit(SS_RC_DAEMON_INTEGRITY);
}
lib->printf_hook->add_handler(lib->printf_hook, 'R',
traffic_selector_printf_hook,
PRINTF_HOOK_ARGTYPE_POINTER,
PRINTF_HOOK_ARGTYPE_END);
lib->printf_hook->add_handler(lib->printf_hook, 'P',
proposal_printf_hook,
PRINTF_HOOK_ARGTYPE_POINTER,
PRINTF_HOOK_ARGTYPE_END);
private_charon = daemon_create();
charon = (daemon_t*)private_charon;
/* use CTRL loglevel for default */
for (group = 0; group < DBG_MAX; group++)
{
levels[group] = LEVEL_CTRL;
}
/* handle arguments */
for (;;)
{
struct option long_opts[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'v' },
{ "use-syslog", no_argument, NULL, 'l' },
/* TODO: handle "debug-all" */
{ "debug-dmn", required_argument, &group, DBG_DMN },
{ "debug-mgr", required_argument, &group, DBG_MGR },
{ "debug-ike", required_argument, &group, DBG_IKE },
{ "debug-chd", required_argument, &group, DBG_CHD },
{ "debug-job", required_argument, &group, DBG_JOB },
{ "debug-cfg", required_argument, &group, DBG_CFG },
{ "debug-knl", required_argument, &group, DBG_KNL },
{ "debug-net", required_argument, &group, DBG_NET },
{ "debug-enc", required_argument, &group, DBG_ENC },
{ "debug-lib", required_argument, &group, DBG_LIB },
{ 0,0,0,0 }
};
int c = getopt_long(argc, argv, "", long_opts, NULL);
switch (c)
{
case EOF:
break;
case 'h':
usage(NULL);
break;
case 'v':
printf("Linux strongSwan %s\n", VERSION);
exit(0);
case 'l':
use_syslog = TRUE;
continue;
case 0:
/* option is in group */
levels[group] = atoi(optarg);
continue;
default:
usage("");
break;
}
break;
}
if (!lookup_uid_gid(private_charon))
{
DBG1(DBG_DMN, "invalid uid/gid - aborting charon");
destroy(private_charon);
library_deinit();
exit(SS_RC_INITIALIZATION_FAILED);
}
/* initialize daemon */
if (!initialize(private_charon, use_syslog, levels))
{
DBG1(DBG_DMN, "initialization failed - aborting charon");
destroy(private_charon);
library_deinit();
exit(SS_RC_INITIALIZATION_FAILED);
}
if (check_pidfile())
{
DBG1(DBG_DMN, "charon already running (\""PID_FILE"\" exists)");
destroy(private_charon);
library_deinit();
exit(-1);
}
if (!drop_capabilities(private_charon))
{
DBG1(DBG_DMN, "capability dropping failed - aborting charon");
destroy(private_charon);
library_deinit();
exit(SS_RC_INITIALIZATION_FAILED);
}
/* start the engine, go multithreaded */
charon->processor->set_threads(charon->processor,
lib->settings->get_int(lib->settings, "charon.threads",
DEFAULT_THREADS));
/* run daemon */
run(private_charon);
/* normal termination, cleanup and exit */
destroy(private_charon);
unlink(PID_FILE);
library_deinit();
return 0;
}
+319
View File
@@ -0,0 +1,319 @@
/*
* Copyright (C) 2006-2007 Tobias Brunner
* Copyright (C) 2005-2009 Martin Willi
* Copyright (C) 2006 Daniel Roethlisberger
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup charon charon
*
* @defgroup bus bus
* @ingroup charon
*
* @defgroup listeners listeners
* @ingroup bus
*
* @defgroup config config
* @ingroup charon
*
* @defgroup attributes attributes
* @ingroup config
*
* @defgroup control control
* @ingroup charon
*
* @defgroup ccredentials credentials
* @ingroup charon
*
* @defgroup sets sets
* @ingroup ccredentials
*
* @defgroup encoding encoding
* @ingroup charon
*
* @defgroup payloads payloads
* @ingroup encoding
*
* @defgroup kernel kernel
* @ingroup charon
*
* @defgroup network network
* @ingroup charon
*
* @defgroup cplugins plugins
* @ingroup charon
*
* @defgroup processing processing
* @ingroup charon
*
* @defgroup jobs jobs
* @ingroup processing
*
* @defgroup sa sa
* @ingroup charon
*
* @defgroup authenticators authenticators
* @ingroup sa
*
* @defgroup eap eap
* @ingroup authenticators
*
* @defgroup tasks tasks
* @ingroup sa
*
* @addtogroup charon
* @{
*
* IKEv2 keying daemon.
*
* All IKEv2 stuff is handled in charon. It uses a newer and more flexible
* architecture than pluto. Charon uses a thread-pool (called processor),
* which allows parallel execution SA-management. All threads originate
* from the processor. Work is delegated to the processor by queueing jobs
* to it.
@verbatim
+---------------------------------+ +----------------------------+
| controller | | config |
+---------------------------------+ +----------------------------+
| | | ^ ^ ^
V V V | | |
+----------+ +-----------+ +------+ +----------+ +----+
| receiver | | | | | +------+ | CHILD_SA | | K |
+---+------+ | Scheduler | | IKE- | | IKE- |--+----------+ | e |
| | | | SA |--| SA | | CHILD_SA | | r |
+------+---+ +-----------+ | | +------+ +----------+ | n |
<->| socket | | | Man- | | e |
+------+---+ +-----------+ | ager | +------+ +----------+ | l |
| | | | | | IKE- |--| CHILD_SA | | - |
+---+------+ | Processor |---| |--| SA | +----------+ | I |
| sender | | | | | +------+ | f |
+----------+ +-----------+ +------+ +----+
| | | | | |
V V V V V V
+---------------------------------+ +----------------------------+
| Bus | | credentials |
+---------------------------------+ +----------------------------+
@endverbatim
* The scheduler is responsible to execute timed events. Jobs may be queued to
* the scheduler to get executed at a defined time (e.g. rekeying). The
* scheduler does not execute the jobs itself, it queues them to the processor.
*
* The IKE_SA manager managers all IKE_SA. It further handles the
* synchronization:
* Each IKE_SA must be checked out strictly and checked in again after use. The
* manager guarantees that only one thread may check out a single IKE_SA. This
* allows us to write the (complex) IKE_SAs routines non-threadsave.
* The IKE_SA contain the state and the logic of each IKE_SA and handle the
* messages.
*
* The CHILD_SA contains state about a IPsec security association and manages
* them. An IKE_SA may have multiple CHILD_SAs. Communication to the kernel
* takes place here through the kernel interface.
*
* The kernel interface installs IPsec security associations, policies, routes
* and virtual addresses. It further provides methods to enumerate interfaces
* and may notify the daemon about state changes at lower layers.
*
* The bus receives signals from the different threads and relays them to
* interested listeners. Debugging signals, but also important state changes or
* error messages are sent over the bus.
* Its listeners are not only for logging, but also to track the state of an
* IKE_SA.
*
* The controller, credential_manager, bus and backend_manager (config) are
* places where a plugin ca register itself to privide information or observe
* and control the daemon.
*/
#ifndef DAEMON_H_
#define DAEMON_H_
typedef struct daemon_t daemon_t;
#include <network/sender.h>
#include <network/receiver.h>
#include <network/socket_manager.h>
#include <processing/scheduler.h>
#include <processing/processor.h>
#include <kernel/kernel_interface.h>
#include <control/controller.h>
#include <bus/bus.h>
#include <bus/listeners/file_logger.h>
#include <bus/listeners/sys_logger.h>
#include <sa/ike_sa_manager.h>
#include <sa/trap_manager.h>
#include <config/backend_manager.h>
#include <credentials/credential_manager.h>
#include <sa/authenticators/eap/eap_manager.h>
#include <sa/authenticators/eap/sim_manager.h>
#ifdef ME
#include <sa/connect_manager.h>
#include <sa/mediation_manager.h>
#endif /* ME */
/**
* Name of the daemon.
*/
#define DAEMON_NAME "charon"
/**
* Number of threads in the thread pool, if not specified in config.
*/
#define DEFAULT_THREADS 16
/**
* UDP Port on which the daemon will listen for incoming traffic.
*/
#define IKEV2_UDP_PORT 500
/**
* UDP Port to which the daemon will float to if NAT is detected.
*/
#define IKEV2_NATT_PORT 4500
/**
* PID file, in which charon stores its process id
*/
#define PID_FILE IPSEC_PIDDIR "/charon.pid"
/**
* Main class of daemon, contains some globals.
*/
struct daemon_t {
/**
* Socket manager instance
*/
socket_manager_t *socket;
/**
* A ike_sa_manager_t instance.
*/
ike_sa_manager_t *ike_sa_manager;
/**
* Manager for triggering policies, called traps
*/
trap_manager_t *traps;
/**
* Manager for the different configuration backends.
*/
backend_manager_t *backends;
/**
* Manager for the credential backends
*/
credential_manager_t *credentials;
/**
* The Sender-Thread.
*/
sender_t *sender;
/**
* The Receiver-Thread.
*/
receiver_t *receiver;
/**
* The Scheduler-Thread.
*/
scheduler_t *scheduler;
/**
* Job processing using a thread pool.
*/
processor_t *processor;
/**
* The signaling bus.
*/
bus_t *bus;
/**
* A list of installed file_logger_t's
*/
linked_list_t *file_loggers;
/**
* A list of installed sys_logger_t's
*/
linked_list_t *sys_loggers;
/**
* Kernel Interface to communicate with kernel
*/
kernel_interface_t *kernel_interface;
/**
* Controller to control the daemon
*/
controller_t *controller;
/**
* EAP manager to maintain registered EAP methods
*/
eap_manager_t *eap;
/**
* SIM manager to maintain (U)SIM cards/providers
*/
sim_manager_t *sim;
#ifdef ME
/**
* Connect manager
*/
connect_manager_t *connect_manager;
/**
* Mediation manager
*/
mediation_manager_t *mediation_manager;
#endif /* ME */
/**
* User ID the daemon will user after initialization
*/
uid_t uid;
/**
* Group ID the daemon will use after initialization
*/
gid_t gid;
/**
* Do not drop a given capability after initialization.
*
* Some plugins might need additional capabilites. They tell the daemon
* during plugin initialization which one they need, the daemon won't
* drop these.
*/
void (*keep_cap)(daemon_t *this, u_int cap);
};
/**
* The one and only instance of the daemon.
*/
extern daemon_t *charon;
#endif /** DAEMON_H_ @}*/
+12
View File
@@ -0,0 +1,12 @@
#!/bin/bash
CMD=`tempfile`
LOG="debug.log"
ipsec start --nofork 2>&1 > $LOG &
sleep 1
echo >> $LOG
echo >> $LOG
echo >> $LOG
echo "c" > $CMD
gdb -batch /usr/local/libexec/ipsec/charon `cat /var/run/charon.pid ` -x $CMD 2>&1 >> $LOG
ipsec stop
rm $CMD
+888
View File
@@ -0,0 +1,888 @@
/*
* Copyright (C) 2005-2009 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <stdio.h>
#include "generator.h"
#include <library.h>
#include <daemon.h>
#include <utils/linked_list.h>
#include <encoding/payloads/payload.h>
#include <encoding/payloads/proposal_substructure.h>
#include <encoding/payloads/transform_substructure.h>
#include <encoding/payloads/sa_payload.h>
#include <encoding/payloads/ke_payload.h>
#include <encoding/payloads/notify_payload.h>
#include <encoding/payloads/nonce_payload.h>
#include <encoding/payloads/id_payload.h>
#include <encoding/payloads/auth_payload.h>
#include <encoding/payloads/cert_payload.h>
#include <encoding/payloads/certreq_payload.h>
#include <encoding/payloads/ts_payload.h>
#include <encoding/payloads/delete_payload.h>
#include <encoding/payloads/vendor_id_payload.h>
#include <encoding/payloads/cp_payload.h>
#include <encoding/payloads/configuration_attribute.h>
#include <encoding/payloads/eap_payload.h>
typedef struct private_generator_t private_generator_t;
/**
* Private part of a generator_t object.
*/
struct private_generator_t {
/**
* Public part of a generator_t object.
*/
generator_t public;
/**
* Buffer used to generate the data into.
*/
u_int8_t *buffer;
/**
* Current write position in buffer (one byte aligned).
*/
u_int8_t *out_position;
/**
* Position of last byte in buffer.
*/
u_int8_t *roof_position;
/**
* Current bit writing to in current byte (between 0 and 7).
*/
u_int8_t current_bit;
/**
* Associated data struct to read informations from.
*/
void *data_struct;
/*
* Last payload length position offset in the buffer.
*/
u_int32_t last_payload_length_position_offset;
/**
* Offset of the header length field in the buffer.
*/
u_int32_t header_length_position_offset;
/**
* Last SPI size.
*/
u_int8_t last_spi_size;
/**
* Attribute format of the last generated transform attribute.
*
* Used to check if a variable value field is used or not for
* the transform attribute value.
*/
bool attribute_format;
/**
* Depending on the value of attribute_format this field is used
* to hold the length of the transform attribute in bytes.
*/
u_int16_t attribute_length;
};
/**
* Get size of current buffer in bytes.
*/
static int get_size(private_generator_t *this)
{
return this->roof_position - this->buffer;
}
/**
* Get free space of current buffer in bytes.
*/
static int get_space(private_generator_t *this)
{
return this->roof_position - this->out_position;
}
/**
* Get length of data in buffer (in bytes).
*/
static int get_length(private_generator_t *this)
{
return this->out_position - this->buffer;
}
/**
* Get current offset in buffer (in bytes).
*/
static u_int32_t get_offset(private_generator_t *this)
{
return this->out_position - this->buffer;
}
/**
* Makes sure enough space is available in buffer to store amount of bits.
*/
static void make_space_available(private_generator_t *this, int bits)
{
while ((get_space(this) * 8 - this->current_bit) < bits)
{
int old_buffer_size, new_buffer_size, out_position_offset;
old_buffer_size = get_size(this);
new_buffer_size = old_buffer_size + GENERATOR_DATA_BUFFER_INCREASE_VALUE;
out_position_offset = this->out_position - this->buffer;
DBG2(DBG_ENC, "increasing gen buffer from %d to %d byte",
old_buffer_size, new_buffer_size);
this->buffer = realloc(this->buffer,new_buffer_size);
this->out_position = (this->buffer + out_position_offset);
this->roof_position = (this->buffer + new_buffer_size);
}
}
/**
* Writes a specific amount of byte into the buffer.
*/
static void write_bytes_to_buffer(private_generator_t *this, void *bytes,
int number_of_bytes)
{
int i;
u_int8_t *read_position = (u_int8_t *)bytes;
make_space_available(this, number_of_bytes * 8);
for (i = 0; i < number_of_bytes; i++)
{
*(this->out_position) = *(read_position);
read_position++;
this->out_position++;
}
}
/**
* Writes a specific amount of byte into the buffer at a specific offset.
*/
static void write_bytes_to_buffer_at_offset(private_generator_t *this,
void *bytes, int number_of_bytes, u_int32_t offset)
{
int i;
u_int8_t *read_position = (u_int8_t *)bytes;
u_int8_t *write_position;
u_int32_t free_space_after_offset = get_size(this) - offset;
/* check first if enough space for new data is available */
if (number_of_bytes > free_space_after_offset)
{
make_space_available(this,
(number_of_bytes - free_space_after_offset) * 8);
}
write_position = this->buffer + offset;
for (i = 0; i < number_of_bytes; i++)
{
*write_position = *read_position;
read_position++;
write_position++;
}
}
/**
* Generates a U_INT-Field type and writes it to buffer.
*/
static void generate_u_int_type(private_generator_t *this,
encoding_type_t int_type,u_int32_t offset)
{
int number_of_bits = 0;
/* find out number of bits of each U_INT type to check for enough space */
switch (int_type)
{
case U_INT_4:
number_of_bits = 4;
break;
case TS_TYPE:
case U_INT_8:
number_of_bits = 8;
break;
case U_INT_16:
case CONFIGURATION_ATTRIBUTE_LENGTH:
number_of_bits = 16;
break;
case U_INT_32:
number_of_bits = 32;
break;
case ATTRIBUTE_TYPE:
number_of_bits = 15;
break;
case IKE_SPI:
number_of_bits = 64;
break;
default:
DBG1(DBG_ENC, "U_INT Type %N is not supported",
encoding_type_names, int_type);
return;
}
if ((number_of_bits % 8) == 0 && this->current_bit != 0)
{
DBG1(DBG_ENC, "U_INT Type %N is not 8 Bit aligned",
encoding_type_names, int_type);
return;
}
make_space_available(this, number_of_bits);
switch (int_type)
{
case U_INT_4:
{
u_int8_t high, low;
if (this->current_bit == 0)
{
/* high of current byte in buffer has to be set to the new value*/
high = *((u_int8_t *)(this->data_struct + offset)) << 4;
/* low in buffer is not changed */
low = *(this->out_position) & 0x0F;
/* high is set, low_val is not changed */
*(this->out_position) = high | low;
DBG3(DBG_ENC, " => %d", *(this->out_position));
/* write position is not changed, just bit position is moved */
this->current_bit = 4;
}
else if (this->current_bit == 4)
{
/* high in buffer is not changed */
high = *(this->out_position) & 0xF0;
/* low of current byte in buffer has to be set to the new value*/
low = *((u_int8_t *)(this->data_struct + offset)) & 0x0F;
*(this->out_position) = high | low;
DBG3(DBG_ENC, " => %d", *(this->out_position));
this->out_position++;
this->current_bit = 0;
}
else
{
DBG1(DBG_ENC, "U_INT_4 Type is not 4 Bit aligned");
/* 4 Bit integers must have a 4 bit alignment */
return;
}
break;
}
case TS_TYPE:
case U_INT_8:
{
/* 8 bit values are written as they are */
*this->out_position = *((u_int8_t *)(this->data_struct + offset));
DBG3(DBG_ENC, " => %d", *(this->out_position));
this->out_position++;
break;
}
case ATTRIBUTE_TYPE:
{
u_int8_t attribute_format_flag;
u_int16_t val;
/* attribute type must not change first bit of current byte */
if (this->current_bit != 1)
{
DBG1(DBG_ENC, "ATTRIBUTE FORMAT flag is not set");
return;
}
attribute_format_flag = *(this->out_position) & 0x80;
/* get attribute type value as 16 bit integer*/
val = *((u_int16_t*)(this->data_struct + offset));
/* unset most significant bit */
val &= 0x7FFF;
if (attribute_format_flag)
{
val |= 0x8000;
}
val = htons(val);
DBG3(DBG_ENC, " => %d", val);
/* write bytes to buffer (set bit is overwritten) */
write_bytes_to_buffer(this, &val, sizeof(u_int16_t));
this->current_bit = 0;
break;
}
case U_INT_16:
case CONFIGURATION_ATTRIBUTE_LENGTH:
{
u_int16_t val = htons(*((u_int16_t*)(this->data_struct + offset)));
DBG3(DBG_ENC, " => %b", &val, sizeof(u_int16_t));
write_bytes_to_buffer(this, &val, sizeof(u_int16_t));
break;
}
case U_INT_32:
{
u_int32_t val = htonl(*((u_int32_t*)(this->data_struct + offset)));
DBG3(DBG_ENC, " => %b", &val, sizeof(u_int32_t));
write_bytes_to_buffer(this, &val, sizeof(u_int32_t));
break;
}
case IKE_SPI:
{
/* 64 bit are written as-is, no host order conversion */
write_bytes_to_buffer(this, this->data_struct + offset,
sizeof(u_int64_t));
DBG3(DBG_ENC, " => %b", this->data_struct + offset,
sizeof(u_int64_t));
break;
}
default:
{
DBG1(DBG_ENC, "U_INT Type %N is not supported",
encoding_type_names, int_type);
return;
}
}
}
/**
* Generate a reserved bit or byte
*/
static void generate_reserved_field(private_generator_t *this, int bits)
{
/* only one bit or 8 bit fields are supported */
if (bits != 1 && bits != 8)
{
DBG1(DBG_ENC, "reserved field of %d bits cannot be generated", bits);
return ;
}
make_space_available(this, bits);
if (bits == 1)
{
u_int8_t reserved_bit = ~(1 << (7 - this->current_bit));
*(this->out_position) = *(this->out_position) & reserved_bit;
if (this->current_bit == 0)
{
/* memory must be zero */
*(this->out_position) = 0x00;
}
this->current_bit++;
if (this->current_bit >= 8)
{
this->current_bit = this->current_bit % 8;
this->out_position++;
}
}
else
{
if (this->current_bit > 0)
{
DBG1(DBG_ENC, "reserved field cannot be written cause "
"alignement of current bit is %d", this->current_bit);
return;
}
*(this->out_position) = 0x00;
this->out_position++;
}
}
/**
* Generate a FLAG filed
*/
static void generate_flag(private_generator_t *this, u_int32_t offset)
{
u_int8_t flag_value;
u_int8_t flag;
flag_value = (*((bool *) (this->data_struct + offset))) ? 1 : 0;
/* get flag position */
flag = (flag_value << (7 - this->current_bit));
/* make sure one bit is available in buffer */
make_space_available(this, 1);
if (this->current_bit == 0)
{
/* memory must be zero */
*(this->out_position) = 0x00;
}
*(this->out_position) = *(this->out_position) | flag;
DBG3(DBG_ENC, " => %d", *this->out_position);
this->current_bit++;
if (this->current_bit >= 8)
{
this->current_bit = this->current_bit % 8;
this->out_position++;
}
}
/**
* Generates a bytestream from a chunk_t.
*/
static void generate_from_chunk(private_generator_t *this, u_int32_t offset)
{
chunk_t *value;
if (this->current_bit != 0)
{
DBG1(DBG_ENC, "can not generate a chunk at Bitpos %d", this->current_bit);
return ;
}
value = (chunk_t *)(this->data_struct + offset);
DBG3(DBG_ENC, " => %B", value);
write_bytes_to_buffer(this, value->ptr, value->len);
}
/**
* Implementation of private_generator_t.write_to_chunk.
*/
static void write_to_chunk(private_generator_t *this,chunk_t *data)
{
int data_length = get_length(this);
u_int32_t header_length_field = data_length;
/* write length into header length field */
if (this->header_length_position_offset > 0)
{
u_int32_t val = htonl(header_length_field);
write_bytes_to_buffer_at_offset(this, &val, sizeof(u_int32_t),
this->header_length_position_offset);
}
if (this->current_bit > 0)
{
data_length++;
}
*data = chunk_alloc(data_length);
memcpy(data->ptr, this->buffer, data_length);
DBG3(DBG_ENC, "generated data of this generator %B", data);
}
/**
* Implementation of private_generator_t.generate_payload.
*/
static void generate_payload (private_generator_t *this,payload_t *payload)
{
int i, offset_start;
size_t rule_count;
encoding_rule_t *rules;
payload_type_t payload_type;
this->data_struct = payload;
payload_type = payload->get_type(payload);
/* spi size has to get reseted */
this->last_spi_size = 0;
offset_start = this->out_position - this->buffer;
DBG2(DBG_ENC, "generating payload of type %N",
payload_type_names, payload_type);
/* each payload has its own encoding rules */
payload->get_encoding_rules(payload, &rules, &rule_count);
for (i = 0; i < rule_count;i++)
{
DBG2(DBG_ENC, " generating rule %d %N",
i, encoding_type_names, rules[i].type);
switch (rules[i].type)
{
case U_INT_4:
case U_INT_8:
case U_INT_16:
case U_INT_32:
case IKE_SPI:
case TS_TYPE:
case ATTRIBUTE_TYPE:
case CONFIGURATION_ATTRIBUTE_LENGTH:
{
generate_u_int_type(this, rules[i].type, rules[i].offset);
break;
}
case RESERVED_BIT:
{
generate_reserved_field(this, 1);
break;
}
case RESERVED_BYTE:
{
generate_reserved_field(this, 8);
break;
}
case FLAG:
{
generate_flag(this, rules[i].offset);
break;
}
case PAYLOAD_LENGTH:
{
this->last_payload_length_position_offset = get_offset(this);
generate_u_int_type(this, U_INT_16,rules[i].offset);
break;
}
case HEADER_LENGTH:
{
this->header_length_position_offset = get_offset(this);
generate_u_int_type(this ,U_INT_32, rules[i].offset);
break;
}
case SPI_SIZE:
generate_u_int_type(this, U_INT_8, rules[i].offset);
this->last_spi_size = *((u_int8_t *)(this->data_struct +
rules[i].offset));
break;
case ADDRESS:
{
generate_from_chunk(this, rules[i].offset);
break;
}
case SPI:
{
generate_from_chunk(this, rules[i].offset);
break;
}
case KEY_EXCHANGE_DATA:
case NOTIFICATION_DATA:
case NONCE_DATA:
case ID_DATA:
case AUTH_DATA:
case CERT_DATA:
case CERTREQ_DATA:
case SPIS:
case CONFIGURATION_ATTRIBUTE_VALUE:
case VID_DATA:
case EAP_DATA:
{
u_int32_t payload_length_position_offset;
u_int16_t length_of_payload;
u_int16_t header_length = 0;
u_int16_t length_in_network_order;
switch(rules[i].type)
{
case KEY_EXCHANGE_DATA:
header_length = KE_PAYLOAD_HEADER_LENGTH;
break;
case NOTIFICATION_DATA:
header_length = NOTIFY_PAYLOAD_HEADER_LENGTH +
this->last_spi_size;
break;
case NONCE_DATA:
header_length = NONCE_PAYLOAD_HEADER_LENGTH;
break;
case ID_DATA:
header_length = ID_PAYLOAD_HEADER_LENGTH;
break;
case AUTH_DATA:
header_length = AUTH_PAYLOAD_HEADER_LENGTH;
break;
case CERT_DATA:
header_length = CERT_PAYLOAD_HEADER_LENGTH;
break;
case CERTREQ_DATA:
header_length = CERTREQ_PAYLOAD_HEADER_LENGTH;
break;
case SPIS:
header_length = DELETE_PAYLOAD_HEADER_LENGTH;
break;
case VID_DATA:
header_length = VENDOR_ID_PAYLOAD_HEADER_LENGTH;
break;
case CONFIGURATION_ATTRIBUTE_VALUE:
header_length = CONFIGURATION_ATTRIBUTE_HEADER_LENGTH;
break;
case EAP_DATA:
header_length = EAP_PAYLOAD_HEADER_LENGTH;
break;
default:
break;
}
generate_from_chunk(this, rules[i].offset);
payload_length_position_offset =
this->last_payload_length_position_offset;
length_of_payload = header_length +
((chunk_t *)(this->data_struct + rules[i].offset))->len;
length_in_network_order = htons(length_of_payload);
write_bytes_to_buffer_at_offset(this, &length_in_network_order,
sizeof(u_int16_t), payload_length_position_offset);
break;
}
case PROPOSALS:
{
u_int32_t payload_length_position_offset =
this->last_payload_length_position_offset;
/* Length of SA_PAYLOAD is calculated */
u_int16_t length_of_sa_payload = SA_PAYLOAD_HEADER_LENGTH;
u_int16_t int16_val;
linked_list_t *proposals = *((linked_list_t **)
(this->data_struct + rules[i].offset));
iterator_t *iterator;
payload_t *current_proposal;
iterator = proposals->create_iterator(proposals,TRUE);
while (iterator->iterate(iterator, (void**)&current_proposal))
{
u_int32_t before_generate_position_offset;
u_int32_t after_generate_position_offset;
before_generate_position_offset = get_offset(this);
generate_payload(this, current_proposal);
after_generate_position_offset = get_offset(this);
length_of_sa_payload += (after_generate_position_offset -
before_generate_position_offset);
}
iterator->destroy(iterator);
int16_val = htons(length_of_sa_payload);
write_bytes_to_buffer_at_offset(this, &int16_val,
sizeof(u_int16_t),payload_length_position_offset);
break;
}
case TRANSFORMS:
{
u_int32_t payload_length_position_offset =
this->last_payload_length_position_offset;
u_int16_t length_of_proposal =
PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH + this->last_spi_size;
u_int16_t int16_val;
linked_list_t *transforms = *((linked_list_t **)
(this->data_struct + rules[i].offset));
iterator_t *iterator;
payload_t *current_transform;
iterator = transforms->create_iterator(transforms,TRUE);
while (iterator->iterate(iterator, (void**)&current_transform))
{
u_int32_t before_generate_position_offset;
u_int32_t after_generate_position_offset;
before_generate_position_offset = get_offset(this);
generate_payload(this, current_transform);
after_generate_position_offset = get_offset(this);
length_of_proposal += (after_generate_position_offset -
before_generate_position_offset);
}
iterator->destroy(iterator);
int16_val = htons(length_of_proposal);
write_bytes_to_buffer_at_offset(this, &int16_val,
sizeof(u_int16_t), payload_length_position_offset);
break;
}
case TRANSFORM_ATTRIBUTES:
{
u_int32_t transform_length_position_offset =
this->last_payload_length_position_offset;
u_int16_t length_of_transform =
TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH;
u_int16_t int16_val;
linked_list_t *transform_attributes =*((linked_list_t **)
(this->data_struct + rules[i].offset));
iterator_t *iterator;
payload_t *current_attribute;
iterator = transform_attributes->create_iterator(
transform_attributes, TRUE);
while (iterator->iterate(iterator, (void**)&current_attribute))
{
u_int32_t before_generate_position_offset;
u_int32_t after_generate_position_offset;
before_generate_position_offset = get_offset(this);
generate_payload(this, current_attribute);
after_generate_position_offset = get_offset(this);
length_of_transform += (after_generate_position_offset -
before_generate_position_offset);
}
iterator->destroy(iterator);
int16_val = htons(length_of_transform);
write_bytes_to_buffer_at_offset(this, &int16_val,
sizeof(u_int16_t),transform_length_position_offset);
break;
}
case CONFIGURATION_ATTRIBUTES:
{
u_int32_t configurations_length_position_offset =
this->last_payload_length_position_offset;
u_int16_t length_of_configurations = CP_PAYLOAD_HEADER_LENGTH;
u_int16_t int16_val;
linked_list_t *configuration_attributes = *((linked_list_t **)
(this->data_struct + rules[i].offset));
iterator_t *iterator;
payload_t *current_attribute;
iterator = configuration_attributes->create_iterator(
configuration_attributes,TRUE);
while (iterator->iterate(iterator, (void**)&current_attribute))
{
u_int32_t before_generate_position_offset;
u_int32_t after_generate_position_offset;
before_generate_position_offset = get_offset(this);
generate_payload(this, current_attribute);
after_generate_position_offset = get_offset(this);
length_of_configurations += after_generate_position_offset -
before_generate_position_offset;
}
iterator->destroy(iterator);
int16_val = htons(length_of_configurations);
write_bytes_to_buffer_at_offset(this, &int16_val,
sizeof(u_int16_t),configurations_length_position_offset);
break;
}
case ATTRIBUTE_FORMAT:
{
generate_flag(this, rules[i].offset);
/* Attribute format is a flag which is stored in context*/
this->attribute_format =
*((bool *)(this->data_struct + rules[i].offset));
break;
}
case ATTRIBUTE_LENGTH_OR_VALUE:
{
if (this->attribute_format == FALSE)
{
generate_u_int_type(this, U_INT_16, rules[i].offset);
/* this field hold the length of the attribute */
this->attribute_length =
*((u_int16_t *)(this->data_struct + rules[i].offset));
}
else
{
generate_u_int_type(this, U_INT_16, rules[i].offset);
}
break;
}
case ATTRIBUTE_VALUE:
{
if (this->attribute_format == FALSE)
{
DBG2(DBG_ENC, "attribute value has not fixed size");
/* the attribute value is generated */
generate_from_chunk(this, rules[i].offset);
}
break;
}
case TRAFFIC_SELECTORS:
{
u_int32_t payload_length_position_offset =
this->last_payload_length_position_offset;
u_int16_t length_of_ts_payload = TS_PAYLOAD_HEADER_LENGTH;
u_int16_t int16_val;
linked_list_t *traffic_selectors = *((linked_list_t **)
(this->data_struct + rules[i].offset));
iterator_t *iterator;
payload_t *current_tss;
iterator = traffic_selectors->create_iterator(
traffic_selectors,TRUE);
while (iterator->iterate(iterator, (void **)&current_tss))
{
u_int32_t before_generate_position_offset;
u_int32_t after_generate_position_offset;
before_generate_position_offset = get_offset(this);
generate_payload(this, current_tss);
after_generate_position_offset = get_offset(this);
length_of_ts_payload += (after_generate_position_offset -
before_generate_position_offset);
}
iterator->destroy(iterator);
int16_val = htons(length_of_ts_payload);
write_bytes_to_buffer_at_offset(this, &int16_val,
sizeof(u_int16_t),payload_length_position_offset);
break;
}
case ENCRYPTED_DATA:
{
generate_from_chunk(this, rules[i].offset);
break;
}
default:
DBG1(DBG_ENC, "field type %N is not supported",
encoding_type_names, rules[i].type);
return;
}
}
DBG2(DBG_ENC, "generating %N payload finished",
payload_type_names, payload_type);
DBG3(DBG_ENC, "generated data for this payload %b",
this->buffer + offset_start,
this->out_position - this->buffer - offset_start);
}
/**
* Implementation of generator_t.destroy.
*/
static status_t destroy(private_generator_t *this)
{
free(this->buffer);
free(this);
return SUCCESS;
}
/*
* Described in header
*/
generator_t *generator_create()
{
private_generator_t *this;
this = malloc_thing(private_generator_t);
/* initiate public functions */
this->public.generate_payload = (void(*)(generator_t*, payload_t *))generate_payload;
this->public.destroy = (void(*)(generator_t*)) destroy;
this->public.write_to_chunk = (void (*) (generator_t *,chunk_t *))write_to_chunk;
/* allocate memory for buffer */
this->buffer = malloc(GENERATOR_DATA_BUFFER_SIZE);
/* initiate private variables */
this->out_position = this->buffer;
this->roof_position = this->buffer + GENERATOR_DATA_BUFFER_SIZE;
this->data_struct = NULL;
this->current_bit = 0;
this->last_payload_length_position_offset = 0;
this->header_length_position_offset = 0;
this->attribute_format = FALSE;
this->attribute_length = 0;
return &(this->public);
}
+85
View File
@@ -0,0 +1,85 @@
/*
* Copyright (C) 2005-2009 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup generator generator
* @{ @ingroup encoding
*/
#ifndef GENERATOR_H_
#define GENERATOR_H_
typedef struct generator_t generator_t;
#include <library.h>
#include <encoding/payloads/encodings.h>
#include <encoding/payloads/payload.h>
/**
* Generating is done in a data buffer.
* This is the start size of this buffer in bytes.
*/
#define GENERATOR_DATA_BUFFER_SIZE 500
/**
* Number of bytes to increase the buffer, if it is too small.
*/
#define GENERATOR_DATA_BUFFER_INCREASE_VALUE 500
/**
* A generator_t class used to generate IKEv2 payloads.
*
* After creation, multiple payloads can be generated with the generate_payload
* method. The generated bytes are appended. After all payloads are added,
* the write_to_chunk method writes out all generated data since
* the creation of the generator. After that, the generator must be destroyed.
* The generater uses a set of encoding rules, which it can get from
* the supplied payload. With this rules, the generater can generate
* the payload and all substructures automatically.
*/
struct generator_t {
/**
* Generates a specific payload from given payload object.
*
* Remember: Header and substructures are also handled as payloads.
*
* @param payload interface payload_t implementing object
*/
void (*generate_payload) (generator_t *this,payload_t *payload);
/**
* Writes all generated data of the generator to a chunk.
*
* @param data chunk to write the data to
*/
void (*write_to_chunk) (generator_t *this,chunk_t *data);
/**
* Destroys a generator_t object.
*/
void (*destroy) (generator_t *this);
};
/**
* Constructor to create a generator.
*
* @return generator_t object.
*/
generator_t *generator_create(void);
#endif /** GENERATOR_H_ @}*/
File diff suppressed because it is too large Load Diff
+359
View File
@@ -0,0 +1,359 @@
/*
* Copyright (C) 2006-2007 Tobias Brunner
* Copyright (C) 2005-2009 Martin Willi
* Copyright (C) 2006 Daniel Roethlisberger
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup message message
* @{ @ingroup encoding
*/
#ifndef MESSAGE_H_
#define MESSAGE_H_
typedef struct message_t message_t;
#include <library.h>
#include <sa/ike_sa_id.h>
#include <network/packet.h>
#include <encoding/payloads/ike_header.h>
#include <encoding/payloads/notify_payload.h>
#include <utils/linked_list.h>
#include <crypto/crypters/crypter.h>
#include <crypto/signers/signer.h>
/**
* This class is used to represent an IKEv2-Message.
*
* The message handles parsing and generation of payloads
* via parser_t/generator_t. Encryption is done transparently
* via the encryption_payload_t. A set of rules for messages
* and payloads does check parsed messages.
*/
struct message_t {
/**
* Sets the IKE major version of the message.
*
* @param major_version major version to set
*/
void (*set_major_version) (message_t *this,u_int8_t major_version);
/**
* Gets the IKE major version of the message.
*
* @return major version of the message
*/
u_int8_t (*get_major_version) (message_t *this);
/**
* Sets the IKE minor version of the message.
*
* @param minor_version minor version to set
*/
void (*set_minor_version) (message_t *this,u_int8_t minor_version);
/**
* Gets the IKE minor version of the message.
*
* @return minor version of the message
*/
u_int8_t (*get_minor_version) (message_t *this);
/**
* Sets the Message ID of the message.
*
* @param message_id message_id to set
*/
void (*set_message_id) (message_t *this,u_int32_t message_id);
/**
* Gets the Message ID of the message.
*
* @return message_id type of the message
*/
u_int32_t (*get_message_id) (message_t *this);
/**
* Gets the initiator SPI of the message.
*
* @return initiator spi of the message
*/
u_int64_t (*get_initiator_spi) (message_t *this);
/**
* Gets the responder SPI of the message.
*
* @return responder spi of the message
*/
u_int64_t (*get_responder_spi) (message_t *this);
/**
* Sets the IKE_SA ID of the message.
*
* ike_sa_id gets cloned.
*
* @param ike_sa_id ike_sa_id to set
*/
void (*set_ike_sa_id) (message_t *this, ike_sa_id_t * ike_sa_id);
/**
* Gets the IKE_SA ID of the message.
*
* The ike_sa_id points to the message internal id, do not modify.
*
* @return ike_sa_id of message
*/
ike_sa_id_t *(*get_ike_sa_id) (message_t *this);
/**
* Sets the exchange type of the message.
*
* @param exchange_type exchange_type to set
*/
void (*set_exchange_type) (message_t *this,exchange_type_t exchange_type);
/**
* Gets the exchange type of the message.
*
* @return exchange type of the message
*/
exchange_type_t (*get_exchange_type) (message_t *this);
/**
* Gets the payload type of the first payload.
*
* @return payload type of the first payload
*/
payload_type_t (*get_first_payload_type) (message_t *this);
/**
* Sets the request flag.
*
* @param request TRUE if message is a request, FALSE if it is a reply
*/
void (*set_request) (message_t *this, bool request);
/**
* Gets request flag.
*
* @return TRUE if message is a request, FALSE if it is a reply
*/
bool (*get_request) (message_t *this);
/**
* Append a payload to the message.
*
* If the payload must be encrypted is not specified here. Encryption
* of payloads is evaluated via internal rules for the messages and
* is done before generation. The order of payloads may change, since
* all payloads to encrypt are added to the encryption payload, which is
* always the last one.
*
* @param payload payload to append
*/
void (*add_payload) (message_t *this, payload_t *payload);
/**
* Build a notify payload and add it to the message.
*
* This is a helper method to create notify messages or add
* notify payload to messages. The flush parameter specifies if existing
* payloads should get removed before appending the notify.
*
* @param flush TRUE to remove existing payloads
* @param type type of the notify
* @param data a chunk of data to add to the notify, gets cloned
*/
void (*add_notify) (message_t *this, bool flush, notify_type_t type,
chunk_t data);
/**
* Parses header of message.
*
* Begins parisng of a message created via message_create_from_packet().
* The parsing context is stored, so a subsequent call to parse_body()
* will continue the parsing process.
*
* @return
* - SUCCESS if header could be parsed
* - PARSE_ERROR if corrupted/invalid data found
* - FAILED if consistence check of header failed
*/
status_t (*parse_header) (message_t *this);
/**
* Parses body of message.
*
* The body gets not only parsed, but rather it gets verified.
* All payloads are verified if they are allowed to exist in the message
* of this type and if their own structure is ok.
* If there are encrypted payloads, they get decrypted via the supplied
* crypter. Also the message integrity gets verified with the supplied
* signer.
* Crypter/signer can be omitted (by passing NULL) when no encryption
* payload is expected.
*
* @param crypter crypter to decrypt encryption payloads
* @param signer signer to verifiy a message with an encryption payload
* @return
* - SUCCESS if parsing successful
* - NOT_SUPPORTED if ciritcal unknown payloads found
* - NOT_SUPPORTED if message type is not supported!
* - PARSE_ERROR if message parsing failed
* - VERIFY_ERROR if message verification failed (bad syntax)
* - FAILED if integrity check failed
* - INVALID_STATE if crypter/signer not supplied, but needed
*/
status_t (*parse_body) (message_t *this, crypter_t *crypter, signer_t *signer);
/**
* Generates the UDP packet of specific message.
*
* Payloads which must be encrypted are generated first and added to
* an encryption payload. This encryption payload will get encrypted via
* the supplied crypter. Then all other payloads and the header get generated.
* After that, the checksum is added to the encryption payload over the full
* message.
* Crypter/signer can be omitted (by passing NULL) when no encryption
* payload is expected.
* Generation is only done once, multiple calls will just return a packet copy.
*
* @param crypter crypter to use when a payload must be encrypted
* @param signer signer to build a mac
* @param packet copy of generated packet
* @return
* - SUCCESS if packet could be generated
* - INVALID_STATE if exchange type is currently not set
* - NOT_FOUND if no rules found for message generation
* - INVALID_STATE if crypter/signer not supplied but needed.
*/
status_t (*generate) (message_t *this, crypter_t *crypter, signer_t *signer, packet_t **packet);
/**
* Gets the source host informations.
*
* @warning Returned host_t object is not getting cloned,
* do not destroy nor modify.
*
* @return host_t object representing source host
*/
host_t * (*get_source) (message_t *this);
/**
* Sets the source host informations.
*
* @warning host_t object is not getting cloned and gets destroyed by
* message_t.destroy or next call of message_t.set_source.
*
* @param host host_t object representing source host
*/
void (*set_source) (message_t *this, host_t *host);
/**
* Gets the destination host informations.
*
* @warning Returned host_t object is not getting cloned,
* do not destroy nor modify.
*
* @return host_t object representing destination host
*/
host_t * (*get_destination) (message_t *this);
/**
* Sets the destination host informations.
*
* @warning host_t object is not getting cloned and gets destroyed by
* message_t.destroy or next call of message_t.set_destination.
*
* @param host host_t object representing destination host
*/
void (*set_destination) (message_t *this, host_t *host);
/**
* Create an enumerator over all payloads.
*
* @return enumerator over payload_t
*/
enumerator_t * (*create_payload_enumerator) (message_t *this);
/**
* Find a payload of a specific type.
*
* Returns the first occurance.
*
* @param type type of the payload to find
* @return payload, or NULL if no such payload found
*/
payload_t* (*get_payload) (message_t *this, payload_type_t type);
/**
* Get the first notify payload of a specific type.
*
* @param type type of notification payload
* @return notify payload, NULL if no such notify found
*/
notify_payload_t* (*get_notify)(message_t *this, notify_type_t type);
/**
* Returns a clone of the internal stored packet_t object.
*
* @return packet_t object as clone of internal one
*/
packet_t * (*get_packet) (message_t *this);
/**
* Returns a clone of the internal stored packet_t data.
*
* @return clone of the internal stored packet_t data.
*/
chunk_t (*get_packet_data) (message_t *this);
/**
* Destroys a message and all including objects.
*/
void (*destroy) (message_t *this);
};
/**
* Creates an message_t object from a incoming UDP Packet.
*
* @warning the given packet_t object is not copied and gets
* destroyed in message_t's destroy call.
*
* - exchange_type is set to NOT_SET
* - original_initiator is set to TRUE
* - is_request is set to TRUE
* Call message_t.parse_header afterwards.
*
* @param packet packet_t object which is assigned to message
* @return message_t object
*/
message_t * message_create_from_packet(packet_t *packet);
/**
* Creates an empty message_t object.
*
* - exchange_type is set to NOT_SET
* - original_initiator is set to TRUE
* - is_request is set to TRUE
*
* @return message_t object
*/
message_t * message_create(void);
#endif /** MESSAGE_H_ @}*/
+862
View File
@@ -0,0 +1,862 @@
/*
* Copyright (C) 2005-2009 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <stdlib.h>
#include <arpa/inet.h>
#include <string.h>
#include "parser.h"
#include <library.h>
#include <daemon.h>
#include <utils/linked_list.h>
#include <encoding/payloads/encodings.h>
#include <encoding/payloads/payload.h>
#include <encoding/payloads/sa_payload.h>
#include <encoding/payloads/proposal_substructure.h>
#include <encoding/payloads/transform_substructure.h>
#include <encoding/payloads/transform_attribute.h>
#include <encoding/payloads/ke_payload.h>
#include <encoding/payloads/nonce_payload.h>
#include <encoding/payloads/id_payload.h>
#include <encoding/payloads/notify_payload.h>
#include <encoding/payloads/encryption_payload.h>
#include <encoding/payloads/auth_payload.h>
#include <encoding/payloads/cert_payload.h>
#include <encoding/payloads/certreq_payload.h>
#include <encoding/payloads/ts_payload.h>
#include <encoding/payloads/delete_payload.h>
#include <encoding/payloads/vendor_id_payload.h>
#include <encoding/payloads/cp_payload.h>
#include <encoding/payloads/configuration_attribute.h>
#include <encoding/payloads/eap_payload.h>
#include <encoding/payloads/unknown_payload.h>
typedef struct private_parser_t private_parser_t;
/**
* Private data stored in a context.
*
* Contains pointers and counters to store current state.
*/
struct private_parser_t {
/**
* Public members, see parser_t.
*/
parser_t public;
/**
* Current bit for reading in input data.
*/
u_int8_t bit_pos;
/**
* Current byte for reading in input data.
*/
u_int8_t *byte_pos;
/**
* Input data to parse.
*/
u_int8_t *input;
/**
* Roof of input, used for length-checking.
*/
u_int8_t *input_roof;
/**
* Set of encoding rules for this parsing session.
*/
encoding_rule_t *rules;
};
/**
* Forward declaration
*/
static status_t parse_payload(private_parser_t *this,
payload_type_t payload_type, payload_t **payload);
/**
* Log invalid length error
*/
static bool short_input(private_parser_t *this, int number)
{
DBG1(DBG_ENC, " not enough input to parse rule %d %N",
number, encoding_type_names, this->rules[number].type);
return FALSE;
}
/**
* Log unaligned rules
*/
static bool bad_bitpos(private_parser_t *this, int number)
{
DBG1(DBG_ENC, " found rule %d %N on bitpos %d",
number, encoding_type_names, this->rules[number].type, this->bit_pos);
return FALSE;
}
/**
* Parse a 4-Bit unsigned integer from the current parsing position.
*/
static bool parse_uint4(private_parser_t *this, int rule_number,
u_int8_t *output_pos)
{
if (this->byte_pos + sizeof(u_int8_t) > this->input_roof)
{
return short_input(this, rule_number);
}
switch (this->bit_pos)
{
case 0:
if (output_pos)
{
*output_pos = *(this->byte_pos) >> 4;
}
this->bit_pos = 4;
break;
case 4:
if (output_pos)
{
*output_pos = *(this->byte_pos) & 0x0F;
}
this->bit_pos = 0;
this->byte_pos++;
break;
default:
return bad_bitpos(this, rule_number);
}
if (output_pos)
{
DBG3(DBG_ENC, " => %d", *output_pos);
}
return TRUE;
}
/**
* Parse a 8-Bit unsigned integer from the current parsing position.
*/
static bool parse_uint8(private_parser_t *this, int rule_number,
u_int8_t *output_pos)
{
if (this->byte_pos + sizeof(u_int8_t) > this->input_roof)
{
return short_input(this, rule_number);
}
if (this->bit_pos)
{
return bad_bitpos(this, rule_number);
}
if (output_pos)
{
*output_pos = *(this->byte_pos);
DBG3(DBG_ENC, " => %d", *output_pos);
}
this->byte_pos++;
return TRUE;
}
/**
* Parse a 15-Bit unsigned integer from the current parsing position.
*/
static bool parse_uint15(private_parser_t *this, int rule_number,
u_int16_t *output_pos)
{
if (this->byte_pos + sizeof(u_int16_t) > this->input_roof)
{
return short_input(this, rule_number);
}
if (this->bit_pos != 1)
{
return bad_bitpos(this, rule_number);
}
if (output_pos)
{
memcpy(output_pos, this->byte_pos, sizeof(u_int16_t));
*output_pos = ntohs(*output_pos) & ~0x8000;
DBG3(DBG_ENC, " => %d", *output_pos);
}
this->byte_pos += sizeof(u_int16_t);
this->bit_pos = 0;
return TRUE;
}
/**
* Parse a 16-Bit unsigned integer from the current parsing position.
*/
static bool parse_uint16(private_parser_t *this, int rule_number,
u_int16_t *output_pos)
{
if (this->byte_pos + sizeof(u_int16_t) > this->input_roof)
{
return short_input(this, rule_number);
}
if (this->bit_pos)
{
return bad_bitpos(this, rule_number);
}
if (output_pos)
{
memcpy(output_pos, this->byte_pos, sizeof(u_int16_t));
*output_pos = ntohs(*output_pos);
DBG3(DBG_ENC, " => %d", *output_pos);
}
this->byte_pos += sizeof(u_int16_t);
return TRUE;
}
/**
* Parse a 32-Bit unsigned integer from the current parsing position.
*/
static bool parse_uint32(private_parser_t *this, int rule_number,
u_int32_t *output_pos)
{
if (this->byte_pos + sizeof(u_int32_t) > this->input_roof)
{
return short_input(this, rule_number);
}
if (this->bit_pos)
{
return bad_bitpos(this, rule_number);
}
if (output_pos)
{
memcpy(output_pos, this->byte_pos, sizeof(u_int32_t));
*output_pos = ntohl(*output_pos);
DBG3(DBG_ENC, " => %d", *output_pos);
}
this->byte_pos += sizeof(u_int32_t);
return TRUE;
}
/**
* Parse a given amount of bytes and writes them to a specific location
*/
static bool parse_bytes(private_parser_t *this, int rule_number,
u_int8_t *output_pos, int bytes)
{
if (this->byte_pos + bytes > this->input_roof)
{
return short_input(this, rule_number);
}
if (this->bit_pos)
{
return bad_bitpos(this, rule_number);
}
if (output_pos)
{
memcpy(output_pos, this->byte_pos, bytes);
DBG3(DBG_ENC, " => %b", output_pos, bytes);
}
this->byte_pos += bytes;
return TRUE;
}
/**
* Parse a single Bit from the current parsing position
*/
static bool parse_bit(private_parser_t *this, int rule_number,
bool *output_pos)
{
if (this->byte_pos + sizeof(u_int8_t) > this->input_roof)
{
return short_input(this, rule_number);
}
if (output_pos)
{
u_int8_t mask;
mask = 0x01 << (7 - this->bit_pos);
*output_pos = *this->byte_pos & mask;
if (*output_pos)
{ /* set to a "clean", comparable true */
*output_pos = TRUE;
}
DBG3(DBG_ENC, " => %d", *output_pos);
}
this->bit_pos = (this->bit_pos + 1) % 8;
if (this->bit_pos == 0)
{
this->byte_pos++;
}
return TRUE;
}
/**
* Parse substructures in a list.
*/
static bool parse_list(private_parser_t *this, int rule_number,
linked_list_t **output_pos, payload_type_t payload_type, int length)
{
linked_list_t *list = *output_pos;
if (length < 0)
{
return short_input(this, rule_number);
}
if (this->bit_pos)
{
return bad_bitpos(this, rule_number);
}
while (length > 0)
{
u_int8_t *pos_before = this->byte_pos;
payload_t *payload;
DBG2(DBG_ENC, " %d bytes left, parsing recursively %N",
length, payload_type_names, payload_type);
if (parse_payload(this, payload_type, &payload) != SUCCESS)
{
DBG1(DBG_ENC, " parsing of a %N substructure failed",
payload_type_names, payload_type);
return FALSE;
}
list->insert_last(list, payload);
length -= this->byte_pos - pos_before;
}
if (length != 0)
{ /* must yield exactly to zero */
DBG1(DBG_ENC, " length of %N substructure list invalid",
payload_type_names, payload_type);
return FALSE;
}
*output_pos = list;
return TRUE;
}
/**
* Parse data from current parsing position in a chunk.
*/
static bool parse_chunk(private_parser_t *this, int rule_number,
chunk_t *output_pos, int length)
{
if (this->byte_pos + length > this->input_roof)
{
return short_input(this, rule_number);
}
if (this->bit_pos)
{
return bad_bitpos(this, rule_number);
}
if (output_pos)
{
*output_pos = chunk_alloc(length);
memcpy(output_pos->ptr, this->byte_pos, length);
DBG3(DBG_ENC, " => %b", output_pos->ptr, length);
}
this->byte_pos += length;
return TRUE;
}
/**
* Implementation of parser_t.parse_payload.
*/
static status_t parse_payload(private_parser_t *this,
payload_type_t payload_type, payload_t **payload)
{
payload_t *pld;
void *output;
size_t rule_count;
int payload_length = 0, spi_size = 0, attribute_length = 0;
u_int16_t ts_type = 0;
bool attribute_format = FALSE;
int rule_number;
encoding_rule_t *rule;
/* create instance of the payload to parse */
pld = payload_create(payload_type);
DBG2(DBG_ENC, "parsing %N payload, %d bytes left",
payload_type_names, payload_type, this->input_roof - this->byte_pos);
DBG3(DBG_ENC, "parsing payload from %b",
this->byte_pos, this->input_roof - this->byte_pos);
if (pld->get_type(pld) == UNKNOWN_PAYLOAD)
{
DBG1(DBG_ENC, " payload type %d is unknown, handling as %N",
payload_type, payload_type_names, UNKNOWN_PAYLOAD);
}
/* base pointer for output, avoids casting in every rule */
output = pld;
/* parse the payload with its own rulse */
pld->get_encoding_rules(pld, &this->rules, &rule_count);
for (rule_number = 0; rule_number < rule_count; rule_number++)
{
rule = &(this->rules[rule_number]);
DBG2(DBG_ENC, " parsing rule %d %N",
rule_number, encoding_type_names, rule->type);
switch (rule->type)
{
case U_INT_4:
{
if (!parse_uint4(this, rule_number, output + rule->offset))
{
pld->destroy(pld);
return PARSE_ERROR;
}
break;
}
case U_INT_8:
{
if (!parse_uint8(this, rule_number, output + rule->offset))
{
pld->destroy(pld);
return PARSE_ERROR;
}
break;
}
case U_INT_16:
{
if (!parse_uint16(this, rule_number, output + rule->offset))
{
pld->destroy(pld);
return PARSE_ERROR;
}
break;
}
case U_INT_32:
{
if (!parse_uint32(this, rule_number, output + rule->offset))
{
pld->destroy(pld);
return PARSE_ERROR;
}
break;
}
case IKE_SPI:
{
if (!parse_bytes(this, rule_number, output + rule->offset, 8))
{
pld->destroy(pld);
return PARSE_ERROR;
}
break;
}
case RESERVED_BIT:
{
if (!parse_bit(this, rule_number, NULL))
{
pld->destroy(pld);
return PARSE_ERROR;
}
break;
}
case RESERVED_BYTE:
{
if (!parse_uint8(this, rule_number, NULL))
{
pld->destroy(pld);
return PARSE_ERROR;
}
break;
}
case FLAG:
{
if (!parse_bit(this, rule_number, output + rule->offset))
{
pld->destroy(pld);
return PARSE_ERROR;
}
break;
}
case PAYLOAD_LENGTH:
{
if (!parse_uint16(this, rule_number, output + rule->offset))
{
pld->destroy(pld);
return PARSE_ERROR;
}
/* parsed u_int16 should be aligned */
payload_length = *(u_int16_t*)(output + rule->offset);
if (payload_length < UNKNOWN_PAYLOAD_HEADER_LENGTH)
{
pld->destroy(pld);
return PARSE_ERROR;
}
break;
}
case HEADER_LENGTH:
{
if (!parse_uint32(this, rule_number, output + rule->offset))
{
pld->destroy(pld);
return PARSE_ERROR;
}
break;
}
case SPI_SIZE:
{
if (!parse_uint8(this, rule_number, output + rule->offset))
{
pld->destroy(pld);
return PARSE_ERROR;
}
spi_size = *(u_int8_t*)(output + rule->offset);
break;
}
case SPI:
{
if (!parse_chunk(this, rule_number, output + rule->offset,
spi_size))
{
pld->destroy(pld);
return PARSE_ERROR;
}
break;
}
case PROPOSALS:
{
if (payload_length < SA_PAYLOAD_HEADER_LENGTH ||
!parse_list(this, rule_number, output + rule->offset,
PROPOSAL_SUBSTRUCTURE,
payload_length - SA_PAYLOAD_HEADER_LENGTH))
{
pld->destroy(pld);
return PARSE_ERROR;
}
break;
}
case TRANSFORMS:
{
if (payload_length <
spi_size + PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH ||
!parse_list(this, rule_number, output + rule->offset,
TRANSFORM_SUBSTRUCTURE, payload_length - spi_size -
PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH))
{
pld->destroy(pld);
return PARSE_ERROR;
}
break;
}
case TRANSFORM_ATTRIBUTES:
{
if (payload_length < TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH ||
!parse_list(this, rule_number, output + rule->offset,
TRANSFORM_ATTRIBUTE,
payload_length - TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH))
{
pld->destroy(pld);
return PARSE_ERROR;
}
break;
}
case CONFIGURATION_ATTRIBUTES:
{
if (payload_length < CP_PAYLOAD_HEADER_LENGTH ||
!parse_list(this, rule_number, output + rule->offset,
CONFIGURATION_ATTRIBUTE,
payload_length - CP_PAYLOAD_HEADER_LENGTH))
{
pld->destroy(pld);
return PARSE_ERROR;
}
break;
}
case ATTRIBUTE_FORMAT:
{
if (!parse_bit(this, rule_number, output + rule->offset))
{
pld->destroy(pld);
return PARSE_ERROR;
}
attribute_format = *(bool*)(output + rule->offset);
break;
}
case ATTRIBUTE_TYPE:
{
if (!parse_uint15(this, rule_number, output + rule->offset))
{
pld->destroy(pld);
return PARSE_ERROR;
}
break;
}
case CONFIGURATION_ATTRIBUTE_LENGTH:
{
if (!parse_uint16(this, rule_number, output + rule->offset))
{
pld->destroy(pld);
return PARSE_ERROR;
}
attribute_length = *(u_int16_t*)(output + rule->offset);
break;
}
case ATTRIBUTE_LENGTH_OR_VALUE:
{
if (!parse_uint16(this, rule_number, output + rule->offset))
{
pld->destroy(pld);
return PARSE_ERROR;
}
attribute_length = *(u_int16_t*)(output + rule->offset);
break;
}
case ATTRIBUTE_VALUE:
{
if (attribute_format == FALSE &&
!parse_chunk(this, rule_number, output + rule->offset,
attribute_length))
{
pld->destroy(pld);
return PARSE_ERROR;
}
break;
}
case NONCE_DATA:
{
if (payload_length < NONCE_PAYLOAD_HEADER_LENGTH ||
!parse_chunk(this, rule_number, output + rule->offset,
payload_length - NONCE_PAYLOAD_HEADER_LENGTH))
{
pld->destroy(pld);
return PARSE_ERROR;
}
break;
}
case ID_DATA:
{
if (payload_length < ID_PAYLOAD_HEADER_LENGTH ||
!parse_chunk(this, rule_number, output + rule->offset,
payload_length - ID_PAYLOAD_HEADER_LENGTH))
{
pld->destroy(pld);
return PARSE_ERROR;
}
break;
}
case AUTH_DATA:
{
if (payload_length < AUTH_PAYLOAD_HEADER_LENGTH ||
!parse_chunk(this, rule_number, output + rule->offset,
payload_length - AUTH_PAYLOAD_HEADER_LENGTH))
{
pld->destroy(pld);
return PARSE_ERROR;
}
break;
}
case CERT_DATA:
{
if (payload_length < CERT_PAYLOAD_HEADER_LENGTH ||
!parse_chunk(this, rule_number, output + rule->offset,
payload_length - CERT_PAYLOAD_HEADER_LENGTH))
{
pld->destroy(pld);
return PARSE_ERROR;
}
break;
}
case CERTREQ_DATA:
{
if (payload_length < CERTREQ_PAYLOAD_HEADER_LENGTH ||
!parse_chunk(this, rule_number, output + rule->offset,
payload_length - CERTREQ_PAYLOAD_HEADER_LENGTH))
{
pld->destroy(pld);
return PARSE_ERROR;
}
break;
}
case EAP_DATA:
{
if (payload_length < EAP_PAYLOAD_HEADER_LENGTH ||
!parse_chunk(this, rule_number, output + rule->offset,
payload_length - EAP_PAYLOAD_HEADER_LENGTH))
{
pld->destroy(pld);
return PARSE_ERROR;
}
break;
}
case SPIS:
{
if (payload_length < DELETE_PAYLOAD_HEADER_LENGTH ||
!parse_chunk(this, rule_number, output + rule->offset,
payload_length - DELETE_PAYLOAD_HEADER_LENGTH))
{
pld->destroy(pld);
return PARSE_ERROR;
}
break;
}
case VID_DATA:
{
if (payload_length < VENDOR_ID_PAYLOAD_HEADER_LENGTH ||
!parse_chunk(this, rule_number, output + rule->offset,
payload_length - VENDOR_ID_PAYLOAD_HEADER_LENGTH))
{
pld->destroy(pld);
return PARSE_ERROR;
}
break;
}
case CONFIGURATION_ATTRIBUTE_VALUE:
{
if (!parse_chunk(this, rule_number, output + rule->offset,
attribute_length))
{
pld->destroy(pld);
return PARSE_ERROR;
}
break;
}
case KEY_EXCHANGE_DATA:
{
if (payload_length < KE_PAYLOAD_HEADER_LENGTH ||
!parse_chunk(this, rule_number, output + rule->offset,
payload_length - KE_PAYLOAD_HEADER_LENGTH))
{
pld->destroy(pld);
return PARSE_ERROR;
}
break;
}
case NOTIFICATION_DATA:
{
if (payload_length < NOTIFY_PAYLOAD_HEADER_LENGTH + spi_size ||
!parse_chunk(this, rule_number, output + rule->offset,
payload_length - NOTIFY_PAYLOAD_HEADER_LENGTH - spi_size))
{
pld->destroy(pld);
return PARSE_ERROR;
}
break;
}
case ENCRYPTED_DATA:
{
if (payload_length < ENCRYPTION_PAYLOAD_HEADER_LENGTH ||
!parse_chunk(this, rule_number, output + rule->offset,
payload_length - ENCRYPTION_PAYLOAD_HEADER_LENGTH))
{
pld->destroy(pld);
return PARSE_ERROR;
}
break;
}
case TS_TYPE:
{
if (!parse_uint8(this, rule_number, output + rule->offset))
{
pld->destroy(pld);
return PARSE_ERROR;
}
ts_type = *(u_int8_t*)(output + rule->offset);
break;
}
case ADDRESS:
{
int address_length = (ts_type == TS_IPV4_ADDR_RANGE) ? 4 : 16;
if (!parse_chunk(this, rule_number, output + rule->offset,
address_length))
{
pld->destroy(pld);
return PARSE_ERROR;
}
break;
}
case TRAFFIC_SELECTORS:
{
if (payload_length < TS_PAYLOAD_HEADER_LENGTH ||
!parse_list(this, rule_number, output + rule->offset,
TRAFFIC_SELECTOR_SUBSTRUCTURE,
payload_length - TS_PAYLOAD_HEADER_LENGTH))
{
pld->destroy(pld);
return PARSE_ERROR;
}
break;
}
case UNKNOWN_DATA:
{
if (payload_length < UNKNOWN_PAYLOAD_HEADER_LENGTH ||
!parse_chunk(this, rule_number, output + rule->offset,
payload_length - UNKNOWN_PAYLOAD_HEADER_LENGTH))
{
pld->destroy(pld);
return PARSE_ERROR;
}
break;
}
default:
{
DBG1(DBG_ENC, " no rule to parse rule %d %N",
rule_number, encoding_type_names, rule->type);
pld->destroy(pld);
return PARSE_ERROR;
}
}
/* process next rulue */
rule++;
}
*payload = pld;
DBG2(DBG_ENC, "parsing %N payload finished",
payload_type_names, payload_type);
return SUCCESS;
}
/**
* Implementation of parser_t.get_remaining_byte_count.
*/
static int get_remaining_byte_count (private_parser_t *this)
{
return this->input_roof - this->byte_pos;
}
/**
* Implementation of parser_t.reset_context.
*/
static void reset_context (private_parser_t *this)
{
this->byte_pos = this->input;
this->bit_pos = 0;
}
/**
* Implementation of parser_t.destroy.
*/
static void destroy(private_parser_t *this)
{
free(this);
}
/*
* Described in header.
*/
parser_t *parser_create(chunk_t data)
{
private_parser_t *this = malloc_thing(private_parser_t);
this->public.parse_payload = (status_t(*)(parser_t*,payload_type_t,payload_t**))parse_payload;
this->public.reset_context = (void(*)(parser_t*)) reset_context;
this->public.get_remaining_byte_count = (int (*) (parser_t *))get_remaining_byte_count;
this->public.destroy = (void(*)(parser_t*)) destroy;
this->input = data.ptr;
this->byte_pos = data.ptr;
this->bit_pos = 0;
this->input_roof = data.ptr + data.len;
return &this->public;
}
+79
View File
@@ -0,0 +1,79 @@
/*
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup parser parser
* @{ @ingroup encoding
*/
#ifndef PARSER_H_
#define PARSER_H_
typedef struct parser_t parser_t;
#include <library.h>
#include <encoding/payloads/encodings.h>
#include <encoding/payloads/payload.h>
/**
* A parser_t class to parse IKEv2 payloads.
*
* A parser is used for parsing one chunk of data. Multiple
* payloads can be parsed out of the chunk using parse_payload.
* The parser remains the state until destroyed.
*/
struct parser_t {
/**
* Parses the next payload.
*
* @warning Caller is responsible for freeing allocated payload.
*
* Rules for parsing are described in the payload definition.
*
* @param payload_type payload type to parse
* @param payload pointer where parsed payload was allocated
* @return
* - SUCCESSFUL if succeeded,
* - PARSE_ERROR if corrupted/invalid data found
*/
status_t (*parse_payload) (parser_t *this, payload_type_t payload_type, payload_t **payload);
/**
* Gets the remaining byte count which is not currently parsed.
*/
int (*get_remaining_byte_count) (parser_t *this);
/**
* Resets the current parser context.
*/
void (*reset_context) (parser_t *this);
/**
* Destroys a parser_t object.
*/
void (*destroy) (parser_t *this);
};
/**
* Constructor to create a parser_t object.
*
* @param data chunk of data to parse with this parser_t object
* @return parser_t object
*/
parser_t *parser_create(chunk_t data);
#endif /** PARSER_H_ @}*/
@@ -0,0 +1,259 @@
/*
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "auth_payload.h"
#include <encoding/payloads/encodings.h>
typedef struct private_auth_payload_t private_auth_payload_t;
/**
* Private data of an auth_payload_t object.
*
*/
struct private_auth_payload_t {
/**
* Public auth_payload_t interface.
*/
auth_payload_t public;
/**
* Next payload type.
*/
u_int8_t next_payload;
/**
* Critical flag.
*/
bool critical;
/**
* Length of this payload.
*/
u_int16_t payload_length;
/**
* Method of the AUTH Data.
*/
u_int8_t auth_method;
/**
* The contained auth data value.
*/
chunk_t auth_data;
};
/**
* Encoding rules to parse or generate a AUTH payload
*
* The defined offsets are the positions in a object of type
* private_auth_payload_t.
*/
encoding_rule_t auth_payload_encodings[] = {
/* 1 Byte next payload type, stored in the field next_payload */
{ U_INT_8, offsetof(private_auth_payload_t, next_payload) },
/* the critical bit */
{ FLAG, offsetof(private_auth_payload_t, critical) },
/* 7 Bit reserved bits, nowhere stored */
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
/* Length of the whole payload*/
{ PAYLOAD_LENGTH, offsetof(private_auth_payload_t, payload_length)},
/* 1 Byte AUTH type*/
{ U_INT_8, offsetof(private_auth_payload_t, auth_method) },
/* 3 reserved bytes */
{ RESERVED_BYTE, 0 },
{ RESERVED_BYTE, 0 },
{ RESERVED_BYTE, 0 },
/* some auth data bytes, length is defined in PAYLOAD_LENGTH */
{ AUTH_DATA, offsetof(private_auth_payload_t, auth_data) }
};
/*
1 2 3
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! Next Payload !C! RESERVED ! Payload Length !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! Auth Method ! RESERVED !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! !
~ Authentication Data ~
! !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
/**
* Implementation of payload_t.verify.
*/
static status_t verify(private_auth_payload_t *this)
{
if (this->auth_method == 0 ||
(this->auth_method >= 4 && this->auth_method <= 8) ||
(this->auth_method >= 12 && this->auth_method <= 200))
{
/* reserved IDs */
return FAILED;
}
return SUCCESS;
}
/**
* Implementation of auth_payload_t.get_encoding_rules.
*/
static void get_encoding_rules(private_auth_payload_t *this, encoding_rule_t **rules, size_t *rule_count)
{
*rules = auth_payload_encodings;
*rule_count = sizeof(auth_payload_encodings) / sizeof(encoding_rule_t);
}
/**
* Implementation of payload_t.get_type.
*/
static payload_type_t get_payload_type(private_auth_payload_t *this)
{
return AUTHENTICATION;
}
/**
* Implementation of payload_t.get_next_type.
*/
static payload_type_t get_next_type(private_auth_payload_t *this)
{
return (this->next_payload);
}
/**
* Implementation of payload_t.set_next_type.
*/
static void set_next_type(private_auth_payload_t *this,payload_type_t type)
{
this->next_payload = type;
}
/**
* Implementation of payload_t.get_length.
*/
static size_t get_length(private_auth_payload_t *this)
{
return this->payload_length;
}
/**
* Implementation of auth_payload_t.set_auth_method.
*/
static void set_auth_method (private_auth_payload_t *this, auth_method_t method)
{
this->auth_method = method;
}
/**
* Implementation of auth_payload_t.get_auth_method.
*/
static auth_method_t get_auth_method (private_auth_payload_t *this)
{
return (this->auth_method);
}
/**
* Implementation of auth_payload_t.set_data.
*/
static void set_data (private_auth_payload_t *this, chunk_t data)
{
if (this->auth_data.ptr != NULL)
{
chunk_free(&(this->auth_data));
}
this->auth_data.ptr = clalloc(data.ptr,data.len);
this->auth_data.len = data.len;
this->payload_length = AUTH_PAYLOAD_HEADER_LENGTH + this->auth_data.len;
}
/**
* Implementation of auth_payload_t.get_data.
*/
static chunk_t get_data (private_auth_payload_t *this)
{
return (this->auth_data);
}
/**
* Implementation of auth_payload_t.get_data_clone.
*/
static chunk_t get_data_clone (private_auth_payload_t *this)
{
chunk_t cloned_data;
if (this->auth_data.ptr == NULL)
{
return (this->auth_data);
}
cloned_data.ptr = clalloc(this->auth_data.ptr,this->auth_data.len);
cloned_data.len = this->auth_data.len;
return cloned_data;
}
/**
* Implementation of payload_t.destroy and auth_payload_t.destroy.
*/
static void destroy(private_auth_payload_t *this)
{
if (this->auth_data.ptr != NULL)
{
chunk_free(&(this->auth_data));
}
free(this);
}
/*
* Described in header
*/
auth_payload_t *auth_payload_create()
{
private_auth_payload_t *this = malloc_thing(private_auth_payload_t);
/* interface functions */
this->public.payload_interface.verify = (status_t (*) (payload_t *))verify;
this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules;
this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length;
this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type;
this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type;
this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_payload_type;
this->public.payload_interface.destroy = (void (*) (payload_t *))destroy;
/* public functions */
this->public.destroy = (void (*) (auth_payload_t *)) destroy;
this->public.set_auth_method = (void (*) (auth_payload_t *,auth_method_t)) set_auth_method;
this->public.get_auth_method = (auth_method_t (*) (auth_payload_t *)) get_auth_method;
this->public.set_data = (void (*) (auth_payload_t *,chunk_t)) set_data;
this->public.get_data_clone = (chunk_t (*) (auth_payload_t *)) get_data_clone;
this->public.get_data = (chunk_t (*) (auth_payload_t *)) get_data;
/* private variables */
this->critical = FALSE;
this->next_payload = NO_PAYLOAD;
this->payload_length =AUTH_PAYLOAD_HEADER_LENGTH;
this->auth_data = chunk_empty;
return (&(this->public));
}
@@ -0,0 +1,102 @@
/*
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup auth_payload auth_payload
* @{ @ingroup payloads
*/
#ifndef AUTH_PAYLOAD_H_
#define AUTH_PAYLOAD_H_
typedef struct auth_payload_t auth_payload_t;
#include <library.h>
#include <encoding/payloads/payload.h>
#include <sa/authenticators/authenticator.h>
/**
* Length of a auth payload without the auth data in bytes.
*/
#define AUTH_PAYLOAD_HEADER_LENGTH 8
/**
* Class representing an IKEv2 AUTH payload.
*
* The AUTH payload format is described in RFC section 3.8.
*/
struct auth_payload_t {
/**
* The payload_t interface.
*/
payload_t payload_interface;
/**
* Set the AUTH method.
*
* @param method auth_method_t to use
*/
void (*set_auth_method) (auth_payload_t *this, auth_method_t method);
/**
* Get the AUTH method.
*
* @return auth_method_t used
*/
auth_method_t (*get_auth_method) (auth_payload_t *this);
/**
* Set the AUTH data.
*
* Data gets cloned.
*
* @param data AUTH data as chunk_t
*/
void (*set_data) (auth_payload_t *this, chunk_t data);
/**
* Get the AUTH data.
*
* Returned data are a copy of the internal one.
*
* @return AUTH data as chunk_t
*/
chunk_t (*get_data_clone) (auth_payload_t *this);
/**
* Get the AUTH data.
*
* Returned data are NOT copied
*
* @return AUTH data as chunk_t
*/
chunk_t (*get_data) (auth_payload_t *this);
/**
* Destroys an auth_payload_t object.
*/
void (*destroy) (auth_payload_t *this);
};
/**
* Creates an empty auth_payload_t object.
*
* @return auth_payload_t object
*/
auth_payload_t *auth_payload_create(void);
#endif /** AUTH_PAYLOAD_H_ @}*/
@@ -0,0 +1,340 @@
/*
* Copyright (C) 2008 Tobias Brunner
* Copyright (C) 2005-2007 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <stddef.h>
#include <ctype.h>
#include <daemon.h>
#include "cert_payload.h"
ENUM(cert_encoding_names, ENC_PKCS7_WRAPPED_X509, ENC_OCSP_CONTENT,
"ENC_PKCS7_WRAPPED_X509",
"ENC_PGP",
"ENC_DNS_SIGNED_KEY",
"ENC_X509_SIGNATURE",
"ENC_X509_KEY_EXCHANGE",
"ENC_KERBEROS_TOKENS",
"ENC_CRL",
"ENC_ARL",
"ENC_SPKI",
"ENC_X509_ATTRIBUTE",
"ENC_RAW_RSA_KEY",
"ENC_X509_HASH_AND_URL",
"ENC_X509_HASH_AND_URL_BUNDLE",
"ENC_OCSP_CONTENT",
);
typedef struct private_cert_payload_t private_cert_payload_t;
/**
* Private data of an cert_payload_t object.
*
*/
struct private_cert_payload_t {
/**
* Public cert_payload_t interface.
*/
cert_payload_t public;
/**
* Next payload type.
*/
u_int8_t next_payload;
/**
* Critical flag.
*/
bool critical;
/**
* Length of this payload.
*/
u_int16_t payload_length;
/**
* Encoding of the CERT Data.
*/
u_int8_t encoding;
/**
* The contained cert data value.
*/
chunk_t data;
/**
* TRUE if the "Hash and URL" data is invalid
*/
bool invalid_hash_and_url;
};
/**
* Encoding rules to parse or generate a CERT payload
*
* The defined offsets are the positions in a object of type
* private_cert_payload_t.
*
*/
encoding_rule_t cert_payload_encodings[] = {
/* 1 Byte next payload type, stored in the field next_payload */
{ U_INT_8, offsetof(private_cert_payload_t, next_payload) },
/* the critical bit */
{ FLAG, offsetof(private_cert_payload_t, critical) },
/* 7 Bit reserved bits, nowhere stored */
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
/* Length of the whole payload*/
{ PAYLOAD_LENGTH, offsetof(private_cert_payload_t, payload_length)},
/* 1 Byte CERT type*/
{ U_INT_8, offsetof(private_cert_payload_t, encoding) },
/* some cert data bytes, length is defined in PAYLOAD_LENGTH */
{ CERT_DATA, offsetof(private_cert_payload_t, data) }
};
/*
1 2 3
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! Next Payload !C! RESERVED ! Payload Length !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! Cert Encoding ! !
+-+-+-+-+-+-+-+-+ !
~ Certificate Data ~
! !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
/**
* Implementation of payload_t.verify.
*/
static status_t verify(private_cert_payload_t *this)
{
if (this->encoding == ENC_X509_HASH_AND_URL ||
this->encoding == ENC_X509_HASH_AND_URL_BUNDLE)
{
/* coarse verification of "Hash and URL" encoded certificates */
if (this->data.len <= 20)
{
DBG1(DBG_ENC, "invalid payload length for hash-and-url (%d), ignore",
this->data.len);
this->invalid_hash_and_url = TRUE;
return SUCCESS;
}
int i = 20; /* skipping the hash */
for (; i < this->data.len; ++i)
{
if (this->data.ptr[i] == '\0')
{
/* null terminated, fine */
return SUCCESS;
}
else if (!isprint(this->data.ptr[i]))
{
DBG1(DBG_ENC, "non printable characters in url of hash-and-url"
" encoded certificate payload, ignore");
this->invalid_hash_and_url = TRUE;
return SUCCESS;
}
}
/* URL is not null terminated, correct that */
chunk_t data = chunk_alloc(this->data.len + 1);
memcpy(data.ptr, this->data.ptr, this->data.len);
data.ptr[this->data.len] = '\0';
chunk_free(&this->data);
this->data = data;
}
return SUCCESS;
}
/**
* Implementation of cert_payload_t.get_encoding_rules.
*/
static void get_encoding_rules(private_cert_payload_t *this,
encoding_rule_t **rules, size_t *rule_count)
{
*rules = cert_payload_encodings;
*rule_count = sizeof(cert_payload_encodings) / sizeof(encoding_rule_t);
}
/**
* Implementation of payload_t.get_type.
*/
static payload_type_t get_payload_type(private_cert_payload_t *this)
{
return CERTIFICATE;
}
/**
* Implementation of payload_t.get_next_type.
*/
static payload_type_t get_next_type(private_cert_payload_t *this)
{
return this->next_payload;
}
/**
* Implementation of payload_t.set_next_type.
*/
static void set_next_type(private_cert_payload_t *this,payload_type_t type)
{
this->next_payload = type;
}
/**
* Implementation of payload_t.get_length.
*/
static size_t get_length(private_cert_payload_t *this)
{
return this->payload_length;
}
/**
* Implementation of cert_payload_t.get_cert_encoding.
*/
static cert_encoding_t get_cert_encoding(private_cert_payload_t *this)
{
return this->encoding;
}
/**
* Implementation of cert_payload_t.get_cert.
*/
static certificate_t *get_cert(private_cert_payload_t *this)
{
if (this->encoding != ENC_X509_SIGNATURE)
{
return NULL;
}
return lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
BUILD_BLOB_ASN1_DER, this->data,
BUILD_END);
}
/**
* Implementation of cert_payload_t.get_hash.
*/
static chunk_t get_hash(private_cert_payload_t *this)
{
chunk_t hash = chunk_empty;
if ((this->encoding != ENC_X509_HASH_AND_URL &&
this->encoding != ENC_X509_HASH_AND_URL_BUNDLE) ||
this->invalid_hash_and_url)
{
return hash;
}
hash.ptr = this->data.ptr;
hash.len = 20;
return hash;
}
/**
* Implementation of cert_payload_t.get_url.
*/
static char *get_url(private_cert_payload_t *this)
{
if ((this->encoding != ENC_X509_HASH_AND_URL &&
this->encoding != ENC_X509_HASH_AND_URL_BUNDLE) ||
this->invalid_hash_and_url)
{
return NULL;
}
return (char*)this->data.ptr + 20;
}
/**
* Implementation of payload_t.destroy and cert_payload_t.destroy.
*/
static void destroy(private_cert_payload_t *this)
{
chunk_free(&this->data);
free(this);
}
/*
* Described in header
*/
cert_payload_t *cert_payload_create()
{
private_cert_payload_t *this = malloc_thing(private_cert_payload_t);
this->public.payload_interface.verify = (status_t (*) (payload_t*))verify;
this->public.payload_interface.get_encoding_rules = (void (*) (payload_t*,encoding_rule_t**, size_t*))get_encoding_rules;
this->public.payload_interface.get_length = (size_t (*) (payload_t*))get_length;
this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t*))get_next_type;
this->public.payload_interface.set_next_type = (void (*) (payload_t*,payload_type_t))set_next_type;
this->public.payload_interface.get_type = (payload_type_t (*) (payload_t*))get_payload_type;
this->public.payload_interface.destroy = (void (*) (payload_t*))destroy;
this->public.destroy = (void (*) (cert_payload_t*))destroy;
this->public.get_cert = (certificate_t* (*) (cert_payload_t*))get_cert;
this->public.get_cert_encoding = (cert_encoding_t (*) (cert_payload_t*))get_cert_encoding;
this->public.get_hash = (chunk_t (*) (cert_payload_t*))get_hash;
this->public.get_url = (char* (*) (cert_payload_t*))get_url;
this->critical = FALSE;
this->next_payload = NO_PAYLOAD;
this->payload_length = CERT_PAYLOAD_HEADER_LENGTH;
this->data = chunk_empty;
this->encoding = 0;
this->invalid_hash_and_url = FALSE;
return &this->public;
}
/*
* Described in header
*/
cert_payload_t *cert_payload_create_from_cert(certificate_t *cert)
{
private_cert_payload_t *this = (private_cert_payload_t*)cert_payload_create();
switch (cert->get_type(cert))
{
case CERT_X509:
this->encoding = ENC_X509_SIGNATURE;
break;
default:
DBG1(DBG_ENC, "embedding %N certificate in payload failed",
certificate_type_names, cert->get_type(cert));
free(this);
return NULL;
}
this->data = cert->get_encoding(cert);
this->payload_length = CERT_PAYLOAD_HEADER_LENGTH + this->data.len;
return &this->public;
}
/*
* Described in header
*/
cert_payload_t *cert_payload_create_from_hash_and_url(chunk_t hash, char *url)
{
private_cert_payload_t *this = (private_cert_payload_t*)cert_payload_create();
this->encoding = ENC_X509_HASH_AND_URL;
this->data = chunk_cat("cc", hash, chunk_create(url, strlen(url)));
this->payload_length = CERT_PAYLOAD_HEADER_LENGTH + this->data.len;
return &this->public;
}
@@ -0,0 +1,137 @@
/*
* Copyright (C) 2008 Tobias Brunner
* Copyright (C) 2005-2007 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup cert_payload cert_payload
* @{ @ingroup payloads
*/
#ifndef CERT_PAYLOAD_H_
#define CERT_PAYLOAD_H_
typedef struct cert_payload_t cert_payload_t;
typedef enum cert_encoding_t cert_encoding_t;
#include <library.h>
#include <credentials/certificates/certificate.h>
#include <encoding/payloads/payload.h>
/**
* Length of a cert payload without the cert data in bytes.
*/
#define CERT_PAYLOAD_HEADER_LENGTH 5
/**
* Certifcate encodings, as in RFC4306
*/
enum cert_encoding_t {
ENC_PKCS7_WRAPPED_X509 = 1,
ENC_PGP = 2,
ENC_DNS_SIGNED_KEY = 3,
ENC_X509_SIGNATURE = 4,
ENC_KERBEROS_TOKEN = 6,
ENC_CRL = 7,
ENC_ARL = 8,
ENC_SPKI = 9,
ENC_X509_ATTRIBUTE = 10,
ENC_RAW_RSA_KEY = 11,
ENC_X509_HASH_AND_URL = 12,
ENC_X509_HASH_AND_URL_BUNDLE = 13,
ENC_OCSP_CONTENT = 14, /* from RFC 4806 */
};
/**
* Enum names for cert_encoding_t
*/
extern enum_name_t *cert_encoding_names;
/**
* Class representing an IKEv2 CERT payload.
*
* The CERT payload format is described in RFC section 3.6.
*/
struct cert_payload_t {
/**
* The payload_t interface.
*/
payload_t payload_interface;
/**
* Get the playoads encoded certifcate.
*
* @return certifcate copy
*/
certificate_t *(*get_cert)(cert_payload_t *this);
/**
* Get the encoding of the certificate.
*
* @return encoding
*/
cert_encoding_t (*get_cert_encoding)(cert_payload_t *this);
/**
* Get the hash if this is a hash and URL encoded certificate.
*
* This function returns internal data, do not free.
*
* @return hash
*/
chunk_t (*get_hash)(cert_payload_t *this);
/**
* Get the URL if this is a hash and URL encoded certificate.
*
* This function returns internal data, do not free.
*
* @return url
*/
char *(*get_url)(cert_payload_t *this);
/**
* Destroys the cert_payload object.
*/
void (*destroy) (cert_payload_t *this);
};
/**
* Creates an empty certificate payload.
*
* @return cert_payload_t object
*/
cert_payload_t *cert_payload_create(void);
/**
* Creates a certificate payload with an embedded certificate.
*
* @param cert certificate to embed
* @return cert_payload_t object
*/
cert_payload_t *cert_payload_create_from_cert(certificate_t *cert);
/**
* Creates a certificate payload with hash and URL encoding of a certificate.
*
* @param hash hash of the DER encoded certificate (get's cloned)
* @param url the URL to locate the certificate (get's cloned)
* @return cert_payload_t object
*/
cert_payload_t *cert_payload_create_from_hash_and_url(chunk_t hash, char *url);
#endif /** CERT_PAYLOAD_H_ @}*/
@@ -0,0 +1,298 @@
/*
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <stddef.h>
#include <daemon.h>
#include <crypto/hashers/hasher.h>
#include <encoding/payloads/cert_payload.h>
#include "certreq_payload.h"
typedef struct private_certreq_payload_t private_certreq_payload_t;
/**
* Private data of an certreq_payload_t object.
*
*/
struct private_certreq_payload_t {
/**
* Public certreq_payload_t interface.
*/
certreq_payload_t public;
/**
* Next payload type.
*/
u_int8_t next_payload;
/**
* Critical flag.
*/
bool critical;
/**
* Length of this payload.
*/
u_int16_t payload_length;
/**
* Encoding of the CERT Data.
*/
u_int8_t encoding;
/**
* The contained certreq data value.
*/
chunk_t data;
};
/**
* Encoding rules to parse or generate a CERTREQ payload
*
* The defined offsets are the positions in a object of type
* private_certreq_payload_t.
*
*/
encoding_rule_t certreq_payload_encodings[] = {
/* 1 Byte next payload type, stored in the field next_payload */
{ U_INT_8, offsetof(private_certreq_payload_t, next_payload) },
/* the critical bit */
{ FLAG, offsetof(private_certreq_payload_t, critical) },
/* 7 Bit reserved bits, nowhere stored */
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
/* Length of the whole payload*/
{ PAYLOAD_LENGTH, offsetof(private_certreq_payload_t, payload_length) },
/* 1 Byte CERTREQ type*/
{ U_INT_8, offsetof(private_certreq_payload_t, encoding) },
/* some certreq data bytes, length is defined in PAYLOAD_LENGTH */
{ CERTREQ_DATA, offsetof(private_certreq_payload_t, data) }
};
/*
1 2 3
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! Next Payload !C! RESERVED ! Payload Length !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! Cert Encoding ! !
+-+-+-+-+-+-+-+-+ !
~ Certification Authority ~
! !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
/**
* Implementation of payload_t.verify.
*/
static status_t verify(private_certreq_payload_t *this)
{
if (this->encoding == ENC_X509_SIGNATURE)
{
if (this->data.len < HASH_SIZE_SHA1 ||
this->data.len % HASH_SIZE_SHA1)
{
DBG1(DBG_ENC, "invalid X509 hash length (%d) in certreq",
this->data.len);
return FAILED;
}
}
return SUCCESS;
}
/**
* Implementation of certreq_payload_t.get_encoding_rules.
*/
static void get_encoding_rules(private_certreq_payload_t *this, encoding_rule_t **rules, size_t *rule_count)
{
*rules = certreq_payload_encodings;
*rule_count = sizeof(certreq_payload_encodings) / sizeof(encoding_rule_t);
}
/**
* Implementation of payload_t.get_type.
*/
static payload_type_t get_payload_type(private_certreq_payload_t *this)
{
return CERTIFICATE_REQUEST;
}
/**
* Implementation of payload_t.get_next_type.
*/
static payload_type_t get_next_type(private_certreq_payload_t *this)
{
return (this->next_payload);
}
/**
* Implementation of payload_t.set_next_type.
*/
static void set_next_type(private_certreq_payload_t *this,payload_type_t type)
{
this->next_payload = type;
}
/**
* Implementation of payload_t.get_length.
*/
static size_t get_length(private_certreq_payload_t *this)
{
return this->payload_length;
}
/**
* Implementation of certreq_payload_t.add_keyid.
*/
static void add_keyid(private_certreq_payload_t *this, chunk_t keyid)
{
this->data = chunk_cat("mc", this->data, keyid);
this->payload_length += keyid.len;
}
typedef struct keyid_enumerator_t keyid_enumerator_t;
/**
* enumerator to enumerate keyids
*/
struct keyid_enumerator_t {
enumerator_t public;
chunk_t full;
u_char *pos;
};
/**
* enumerate function for keyid_enumerator
*/
static bool keyid_enumerate(keyid_enumerator_t *this, chunk_t *chunk)
{
if (this->pos == NULL)
{
this->pos = this->full.ptr;
}
else
{
this->pos += HASH_SIZE_SHA1;
if (this->pos > (this->full.ptr + this->full.len - HASH_SIZE_SHA1))
{
this->pos = NULL;
}
}
if (this->pos)
{
chunk->ptr = this->pos;
chunk->len = HASH_SIZE_SHA1;
return TRUE;
}
return FALSE;
}
/**
* Implementation of certreq_payload_t.create_keyid_enumerator.
*/
static enumerator_t* create_keyid_enumerator(private_certreq_payload_t *this)
{
keyid_enumerator_t *enumerator = malloc_thing(keyid_enumerator_t);
enumerator->public.enumerate = (void*)keyid_enumerate;
enumerator->public.destroy = (void*)free;
enumerator->full = this->data;
enumerator->pos = NULL;
return &enumerator->public;
}
/**
* Implementation of certreq_payload_t.get_cert_type.
*/
static certificate_type_t get_cert_type(private_certreq_payload_t *this)
{
switch (this->encoding)
{
case ENC_X509_SIGNATURE:
return CERT_X509;
default:
return CERT_ANY;
}
}
/**
* Implementation of payload_t.destroy and certreq_payload_t.destroy.
*/
static void destroy(private_certreq_payload_t *this)
{
chunk_free(&this->data);
free(this);
}
/*
* Described in header
*/
certreq_payload_t *certreq_payload_create()
{
private_certreq_payload_t *this = malloc_thing(private_certreq_payload_t);
/* interface functions */
this->public.payload_interface.verify = (status_t (*) (payload_t*))verify;
this->public.payload_interface.get_encoding_rules = (void (*) (payload_t*,encoding_rule_t**,size_t*))get_encoding_rules;
this->public.payload_interface.get_length = (size_t (*) (payload_t*))get_length;
this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t*))get_next_type;
this->public.payload_interface.set_next_type = (void (*) (payload_t*,payload_type_t))set_next_type;
this->public.payload_interface.get_type = (payload_type_t (*) (payload_t*))get_payload_type;
this->public.payload_interface.destroy = (void (*) (payload_t*))destroy;
/* public functions */
this->public.destroy = (void (*) (certreq_payload_t*)) destroy;
this->public.create_keyid_enumerator = (enumerator_t*(*)(certreq_payload_t*))create_keyid_enumerator;
this->public.get_cert_type = (certificate_type_t(*)(certreq_payload_t*))get_cert_type;
this->public.add_keyid = (void(*)(certreq_payload_t*, chunk_t keyid))add_keyid;
/* private variables */
this->critical = FALSE;
this->next_payload = NO_PAYLOAD;
this->payload_length = CERTREQ_PAYLOAD_HEADER_LENGTH;
this->data = chunk_empty;
this->encoding = 0;
return &this->public;
}
/*
* Described in header
*/
certreq_payload_t *certreq_payload_create_type(certificate_type_t type)
{
private_certreq_payload_t *this = (private_certreq_payload_t*)certreq_payload_create();
switch (type)
{
case CERT_X509:
this->encoding = ENC_X509_SIGNATURE;
break;
default:
DBG1(DBG_ENC, "certificate type %N not supported in requests",
certificate_type_names, type);
free(this);
return NULL;
}
return &this->public;
}
@@ -0,0 +1,90 @@
/*
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup certreq_payload certreq_payload
* @{ @ingroup payloads
*/
#ifndef CERTREQ_PAYLOAD_H_
#define CERTREQ_PAYLOAD_H_
typedef struct certreq_payload_t certreq_payload_t;
#include <library.h>
#include <encoding/payloads/payload.h>
#include <encoding/payloads/cert_payload.h>
/**
* Length of a CERTREQ payload without the CERTREQ data in bytes.
*/
#define CERTREQ_PAYLOAD_HEADER_LENGTH 5
/**
* Class representing an IKEv2 CERTREQ payload.
*
* The CERTREQ payload format is described in RFC section 3.7.
*/
struct certreq_payload_t {
/**
* The payload_t interface.
*/
payload_t payload_interface;
/**
* Create an enumerator over contained keyids.
*
* @return enumerator over chunk_t's.
*/
enumerator_t* (*create_keyid_enumerator)(certreq_payload_t *this);
/**
* Get the type of contained certificate keyids.
*
* @return certificate keyid type
*/
certificate_type_t (*get_cert_type)(certreq_payload_t *this);
/**
* Add a certificates keyid to the payload.
*
* @param keyid keyid of the trusted certifcate
* @return
*/
void (*add_keyid)(certreq_payload_t *this, chunk_t keyid);
/**
* Destroys an certreq_payload_t object.
*/
void (*destroy) (certreq_payload_t *this);
};
/**
* Creates an empty certreq_payload_t object.
*
* @return certreq payload
*/
certreq_payload_t *certreq_payload_create(void);
/**
* Creates an empty certreq_payload_t for a kind of certificates.
*
* @param type type of the added keyids
* @return certreq payload
*/
certreq_payload_t *certreq_payload_create_type(certificate_type_t type);
#endif /** CERTREQ_PAYLOAD_H_ @}*/
@@ -0,0 +1,264 @@
/*
* Copyright (C) 2005-2009 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <stddef.h>
#include "configuration_attribute.h"
#include <encoding/payloads/encodings.h>
#include <library.h>
#include <daemon.h>
typedef struct private_configuration_attribute_t private_configuration_attribute_t;
/**
* Private data of an configuration_attribute_t object.
*
*/
struct private_configuration_attribute_t {
/**
* Public configuration_attribute_t interface.
*/
configuration_attribute_t public;
/**
* Type of the attribute.
*/
u_int16_t type;
/**
* Length of the attribute.
*/
u_int16_t length;
/**
* Attribute value as chunk.
*/
chunk_t value;
};
/**
* Encoding rules to parse or generate a configuration attribute.
*
* The defined offsets are the positions in a object of type
* private_configuration_attribute_t.
*/
encoding_rule_t configuration_attribute_encodings[] = {
{ RESERVED_BIT, 0 },
/* type of the attribute as 15 bit unsigned integer */
{ ATTRIBUTE_TYPE, offsetof(private_configuration_attribute_t, type) },
/* Length of attribute value */
{ CONFIGURATION_ATTRIBUTE_LENGTH, offsetof(private_configuration_attribute_t, length) },
/* Value of attribute if attribute format flag is zero */
{ CONFIGURATION_ATTRIBUTE_VALUE, offsetof(private_configuration_attribute_t, value) }
};
/*
1 2 3
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
!R| Attribute Type ! Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
~ Value ~
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
/**
* Implementation of payload_t.verify.
*/
static status_t verify(private_configuration_attribute_t *this)
{
bool failed = FALSE;
if (this->length != this->value.len)
{
DBG1(DBG_ENC, "invalid attribute length");
return FAILED;
}
switch (this->type)
{
case INTERNAL_IP4_ADDRESS:
case INTERNAL_IP4_NETMASK:
case INTERNAL_IP4_DNS:
case INTERNAL_IP4_NBNS:
case INTERNAL_ADDRESS_EXPIRY:
case INTERNAL_IP4_DHCP:
if (this->length != 0 && this->length != 4)
{
failed = TRUE;
}
break;
case INTERNAL_IP4_SUBNET:
if (this->length != 0 && this->length != 8)
{
failed = TRUE;
}
break;
case INTERNAL_IP6_ADDRESS:
case INTERNAL_IP6_SUBNET:
if (this->length != 0 && this->length != 17)
{
failed = TRUE;
}
break;
case INTERNAL_IP6_DNS:
case INTERNAL_IP6_NBNS:
case INTERNAL_IP6_DHCP:
if (this->length != 0 && this->length != 16)
{
failed = TRUE;
}
break;
case SUPPORTED_ATTRIBUTES:
if (this->length % 2)
{
failed = TRUE;
}
break;
case APPLICATION_VERSION:
/* any length acceptable */
break;
default:
DBG1(DBG_ENC, "unknown attribute type %N",
configuration_attribute_type_names, this->type);
break;
}
if (failed)
{
DBG1(DBG_ENC, "invalid attribute length %d for %N",
this->length, configuration_attribute_type_names, this->type);
return FAILED;
}
return SUCCESS;
}
/**
* Implementation of payload_t.get_encoding_rules.
*/
static void get_encoding_rules(private_configuration_attribute_t *this,
encoding_rule_t **rules, size_t *rule_count)
{
*rules = configuration_attribute_encodings;
*rule_count = sizeof(configuration_attribute_encodings) / sizeof(encoding_rule_t);
}
/**
* Implementation of payload_t.get_type.
*/
static payload_type_t get_type(private_configuration_attribute_t *this)
{
return CONFIGURATION_ATTRIBUTE;
}
/**
* Implementation of payload_t.get_next_type.
*/
static payload_type_t get_next_type(private_configuration_attribute_t *this)
{
return NO_PAYLOAD;
}
/**
* Implementation of payload_t.set_next_type.
*/
static void set_next_type(private_configuration_attribute_t *this,
payload_type_t type)
{
}
/**
* Implementation of configuration_attribute_t.get_length.
*/
static size_t get_length(private_configuration_attribute_t *this)
{
return this->value.len + CONFIGURATION_ATTRIBUTE_HEADER_LENGTH;
}
/**
* Implementation of configuration_attribute_t.get_type.
*/
static configuration_attribute_type_t get_configuration_attribute_type(
private_configuration_attribute_t *this)
{
return this->type;
}
/**
* Implementation of configuration_attribute_t.get_value.
*/
static chunk_t get_value(private_configuration_attribute_t *this)
{
return this->value;
}
/**
* Implementation of configuration_attribute_t.destroy and payload_t.destroy.
*/
static void destroy(private_configuration_attribute_t *this)
{
free(this->value.ptr);
free(this);
}
/*
* Described in header.
*/
configuration_attribute_t *configuration_attribute_create()
{
private_configuration_attribute_t *this;
this = malloc_thing(private_configuration_attribute_t);
this->public.payload_interface.verify = (status_t(*)(payload_t *))verify;
this->public.payload_interface.get_encoding_rules = (void(*)(payload_t *, encoding_rule_t **, size_t *) )get_encoding_rules;
this->public.payload_interface.get_length = (size_t(*)(payload_t *))get_length;
this->public.payload_interface.get_next_type = (payload_type_t(*)(payload_t *))get_next_type;
this->public.payload_interface.set_next_type = (void(*)(payload_t *,payload_type_t))set_next_type;
this->public.payload_interface.get_type = (payload_type_t(*)(payload_t *))get_type;
this->public.payload_interface.destroy = (void(*)(payload_t*))destroy;
this->public.get_value = (chunk_t(*)(configuration_attribute_t *))get_value;
this->public.get_type = (configuration_attribute_type_t(*)(configuration_attribute_t *))get_configuration_attribute_type;
this->public.destroy = (void (*)(configuration_attribute_t*))destroy;
this->type = 0;
this->value = chunk_empty;
this->length = 0;
return &this->public;
}
/*
* Described in header.
*/
configuration_attribute_t *configuration_attribute_create_value(
configuration_attribute_type_t type, chunk_t value)
{
private_configuration_attribute_t *this;
this = (private_configuration_attribute_t*)configuration_attribute_create();
this->type = ((u_int16_t)type) & 0x7FFF;
this->value = chunk_clone(value);
this->length = value.len;
return &this->public;
}
@@ -0,0 +1,85 @@
/*
* Copyright (C) 2005-2009 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup configuration_attribute configuration_attribute
* @{ @ingroup payloads
*/
#ifndef CONFIGURATION_ATTRIBUTE_H_
#define CONFIGURATION_ATTRIBUTE_H_
typedef struct configuration_attribute_t configuration_attribute_t;
#include <library.h>
#include <attributes/attributes.h>
#include <encoding/payloads/payload.h>
/**
* Configuration attribute header length in bytes.
*/
#define CONFIGURATION_ATTRIBUTE_HEADER_LENGTH 4
/**
* Class representing an IKEv2-CONFIGURATION Attribute.
*
* The CONFIGURATION ATTRIBUTE format is described in RFC section 3.15.1.
*/
struct configuration_attribute_t {
/**
* Implements payload_t interface.
*/
payload_t payload_interface;
/**
* Get the type of the attribute.
*
* @return type of the configuration attribute
*/
configuration_attribute_type_t (*get_type)(configuration_attribute_t *this);
/**
* Returns the value of the attribute.
*
* @return chunk_t pointing to the internal value
*/
chunk_t (*get_value) (configuration_attribute_t *this);
/**
* Destroys an configuration_attribute_t object.
*/
void (*destroy) (configuration_attribute_t *this);
};
/**
* Creates an empty configuration attribute.
*
* @return created configuration attribute
*/
configuration_attribute_t *configuration_attribute_create();
/**
* Creates a configuration attribute with type and value.
*
* @param type type of configuration attribute
* @param value value, gets cloned
* @return created configuration attribute
*/
configuration_attribute_t *configuration_attribute_create_value(
configuration_attribute_type_t type, chunk_t value);
#endif /** CONFIGURATION_ATTRIBUTE_H_ @}*/
@@ -0,0 +1,273 @@
/*
* Copyright (C) 2005-2009 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <stddef.h>
#include "cp_payload.h"
#include <encoding/payloads/encodings.h>
#include <utils/linked_list.h>
ENUM(config_type_names, CFG_REQUEST, CFG_ACK,
"CFG_REQUEST",
"CFG_REPLY",
"CFG_SET",
"CFG_ACK",
);
typedef struct private_cp_payload_t private_cp_payload_t;
/**
* Private data of an cp_payload_t object.
*
*/
struct private_cp_payload_t {
/**
* Public cp_payload_t interface.
*/
cp_payload_t public;
/**
* Next payload type.
*/
u_int8_t next_payload;
/**
* Critical flag.
*/
bool critical;
/**
* Length of this payload.
*/
u_int16_t payload_length;
/**
* List of attributes, as configuration_attribute_t
*/
linked_list_t *attributes;
/**
* Config Type.
*/
u_int8_t type;
};
/**
* Encoding rules to parse or generate a IKEv2-CP Payload
*
* The defined offsets are the positions in a object of type
* private_cp_payload_t.
*
*/
encoding_rule_t cp_payload_encodings[] = {
/* 1 Byte next payload type, stored in the field next_payload */
{ U_INT_8, offsetof(private_cp_payload_t, next_payload) },
/* the critical bit */
{ FLAG, offsetof(private_cp_payload_t, critical) },
/* 7 Bit reserved bits, nowhere stored */
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
/* Length of the whole CP payload*/
{ PAYLOAD_LENGTH, offsetof(private_cp_payload_t, payload_length) },
/* Proposals are stored in a proposal substructure,
offset points to a linked_list_t pointer */
{ U_INT_8, offsetof(private_cp_payload_t, type) },
{ RESERVED_BYTE,0 },
{ RESERVED_BYTE,0 },
{ RESERVED_BYTE,0 },
{ CONFIGURATION_ATTRIBUTES, offsetof(private_cp_payload_t, attributes) }
};
/*
1 2 3
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! Next Payload !C! RESERVED ! Payload Length !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! CFG Type ! RESERVED !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! !
~ Configuration Attributes ~
! !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
/**
* Implementation of payload_t.verify.
*/
static status_t verify(private_cp_payload_t *this)
{
status_t status = SUCCESS;
enumerator_t *enumerator;
payload_t *attribute;
enumerator = this->attributes->create_enumerator(this->attributes);
while (enumerator->enumerate(enumerator, &attribute))
{
status = attribute->verify(attribute);
if (status != SUCCESS)
{
break;
}
}
enumerator->destroy(enumerator);
return status;
}
/**
* Implementation of payload_t.get_encoding_rules.
*/
static void get_encoding_rules(private_cp_payload_t *this,
encoding_rule_t **rules, size_t *rule_count)
{
*rules = cp_payload_encodings;
*rule_count = sizeof(cp_payload_encodings) / sizeof(encoding_rule_t);
}
/**
* Implementation of payload_t.get_type.
*/
static payload_type_t get_type(private_cp_payload_t *this)
{
return CONFIGURATION;
}
/**
* Implementation of payload_t.get_next_type.
*/
static payload_type_t get_next_type(private_cp_payload_t *this)
{
return this->next_payload;
}
/**
* Implementation of payload_t.set_next_type.
*/
static void set_next_type(private_cp_payload_t *this,payload_type_t type)
{
this->next_payload = type;
}
/**
* recompute the length of the payload.
*/
static void compute_length(private_cp_payload_t *this)
{
enumerator_t *enumerator;
payload_t *attribute;
this->payload_length = CP_PAYLOAD_HEADER_LENGTH;
enumerator = this->attributes->create_enumerator(this->attributes);
while (enumerator->enumerate(enumerator, &attribute))
{
this->payload_length += attribute->get_length(attribute);
}
enumerator->destroy(enumerator);
}
/**
* Implementation of payload_t.get_length.
*/
static size_t get_length(private_cp_payload_t *this)
{
return this->payload_length;
}
/**
* Implementation of cp_payload_t.create_attribute_enumerator.
*/
static enumerator_t *create_attribute_enumerator(private_cp_payload_t *this)
{
return this->attributes->create_enumerator(this->attributes);
}
/**
* Implementation of cp_payload_t.add_attribute.
*/
static void add_attribute(private_cp_payload_t *this,
configuration_attribute_t *attribute)
{
this->attributes->insert_last(this->attributes, attribute);
compute_length(this);
}
/**
* Implementation of cp_payload_t.get_type.
*/
static config_type_t get_config_type(private_cp_payload_t *this)
{
return this->type;
}
/**
* Implementation of payload_t.destroy and cp_payload_t.destroy.
*/
static void destroy(private_cp_payload_t *this)
{
this->attributes->destroy_offset(this->attributes,
offsetof(configuration_attribute_t, destroy));
free(this);
}
/*
* Described in header.
*/
cp_payload_t *cp_payload_create()
{
private_cp_payload_t *this = malloc_thing(private_cp_payload_t);
this->public.payload_interface.verify = (status_t (*) (payload_t *))verify;
this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules;
this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length;
this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type;
this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type;
this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_type;
this->public.payload_interface.destroy = (void (*) (payload_t *))destroy;
this->public.create_attribute_enumerator = (enumerator_t*(*)(cp_payload_t *))create_attribute_enumerator;
this->public.add_attribute = (void (*) (cp_payload_t *,configuration_attribute_t*))add_attribute;
this->public.get_type = (config_type_t (*) (cp_payload_t *))get_config_type;
this->public.destroy = (void (*)(cp_payload_t *))destroy;
/* set default values of the fields */
this->critical = FALSE;
this->next_payload = NO_PAYLOAD;
this->payload_length = CP_PAYLOAD_HEADER_LENGTH;
this->attributes = linked_list_create();
this->type = CFG_REQUEST;
return &this->public;
}
/*
* Described in header.
*/
cp_payload_t *cp_payload_create_type(config_type_t type)
{
private_cp_payload_t *this = (private_cp_payload_t*)cp_payload_create();
this->type = type;
return &this->public;
}
@@ -0,0 +1,108 @@
/*
* Copyright (C) 2005-2009 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup cp_payload cp_payload
* @{ @ingroup payloads
*/
#ifndef CP_PAYLOAD_H_
#define CP_PAYLOAD_H_
typedef enum config_type_t config_type_t;
typedef struct cp_payload_t cp_payload_t;
#include <library.h>
#include <encoding/payloads/payload.h>
#include <encoding/payloads/configuration_attribute.h>
#include <utils/enumerator.h>
/**
* CP_PAYLOAD length in bytes without any proposal substructure.
*/
#define CP_PAYLOAD_HEADER_LENGTH 8
/**
* Config Type of an Configuration Payload.
*/
enum config_type_t {
CFG_REQUEST = 1,
CFG_REPLY = 2,
CFG_SET = 3,
CFG_ACK = 4,
};
/**
* enum name for config_type_t.
*/
extern enum_name_t *config_type_names;
/**
* Class representing an IKEv2-CP Payload.
*
* The CP Payload format is described in RFC section 3.15.
*/
struct cp_payload_t {
/**
* The payload_t interface.
*/
payload_t payload_interface;
/**
* Creates an iterator of stored configuration_attribute_t objects.
*
* @return enumerator over configration_attribute_T
*/
enumerator_t *(*create_attribute_enumerator) (cp_payload_t *this);
/**
* Adds a configuration attribute to the configuration payload.
*
* @param attribute attribute to add
*/
void (*add_attribute)(cp_payload_t *this,
configuration_attribute_t *attribute);
/**
* Get the configuration payload type.
*
* @return type of configuration payload
*/
config_type_t (*get_type) (cp_payload_t *this);
/**
* Destroys an cp_payload_t object.
*/
void (*destroy) (cp_payload_t *this);
};
/**
* Creates an empty configuration payload
*
* @return empty configuration payload
*/
cp_payload_t *cp_payload_create();
/**
* Creates an cp_payload_t with type and value
*
* @param type type of configuration payload to create
* @return created configuration payload
*/
cp_payload_t *cp_payload_create_type(config_type_t config_type);
#endif /** CP_PAYLOAD_H_ @}*/
@@ -0,0 +1,292 @@
/*
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <stddef.h>
#include "delete_payload.h"
typedef struct private_delete_payload_t private_delete_payload_t;
/**
* Private data of an delete_payload_t object.
*
*/
struct private_delete_payload_t {
/**
* Public delete_payload_t interface.
*/
delete_payload_t public;
/**
* Next payload type.
*/
u_int8_t next_payload;
/**
* Critical flag.
*/
bool critical;
/**
* Length of this payload.
*/
u_int16_t payload_length;
/**
* Protocol ID.
*/
u_int8_t protocol_id;
/**
* SPI Size.
*/
u_int8_t spi_size;
/**
* Number of SPI's.
*/
u_int16_t spi_count;
/**
* The contained SPI's.
*/
chunk_t spis;
/**
* List containing u_int32_t spis
*/
linked_list_t *spi_list;
};
/**
* Encoding rules to parse or generate a DELETE payload
*
* The defined offsets are the positions in a object of type
* private_delete_payload_t.
*
*/
encoding_rule_t delete_payload_encodings[] = {
/* 1 Byte next payload type, stored in the field next_payload */
{ U_INT_8, offsetof(private_delete_payload_t, next_payload) },
/* the critical bit */
{ FLAG, offsetof(private_delete_payload_t, critical) },
/* 7 Bit reserved bits, nowhere stored */
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
/* Length of the whole payload*/
{ PAYLOAD_LENGTH, offsetof(private_delete_payload_t, payload_length)},
{ U_INT_8, offsetof(private_delete_payload_t, protocol_id) },
{ U_INT_8, offsetof(private_delete_payload_t, spi_size) },
{ U_INT_16, offsetof(private_delete_payload_t, spi_count) },
/* some delete data bytes, length is defined in PAYLOAD_LENGTH */
{ SPIS, offsetof(private_delete_payload_t, spis) }
};
/*
1 2 3
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! Next Payload !C! RESERVED ! Payload Length !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! Protocol ID ! SPI Size ! # of SPIs !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! !
~ Security Parameter Index(es) (SPI) ~
! !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
/**
* Implementation of payload_t.verify.
*/
static status_t verify(private_delete_payload_t *this)
{
switch (this->protocol_id)
{
case PROTO_AH:
case PROTO_ESP:
if (this->spi_size != 4)
{
return FAILED;
}
break;
case PROTO_IKE:
case 0:
/* IKE deletion has no spi assigned! */
if (this->spi_size != 0)
{
return FAILED;
}
break;
default:
return FAILED;
}
if (this->spis.len != (this->spi_count * this->spi_size))
{
return FAILED;
}
return SUCCESS;
}
/**
* Implementation of delete_payload_t.get_encoding_rules.
*/
static void get_encoding_rules(private_delete_payload_t *this, encoding_rule_t **rules, size_t *rule_count)
{
*rules = delete_payload_encodings;
*rule_count = sizeof(delete_payload_encodings) / sizeof(encoding_rule_t);
}
/**
* Implementation of payload_t.get_type.
*/
static payload_type_t get_payload_type(private_delete_payload_t *this)
{
return DELETE;
}
/**
* Implementation of payload_t.get_next_type.
*/
static payload_type_t get_next_type(private_delete_payload_t *this)
{
return (this->next_payload);
}
/**
* Implementation of payload_t.set_next_type.
*/
static void set_next_type(private_delete_payload_t *this,payload_type_t type)
{
this->next_payload = type;
}
/**
* Implementation of payload_t.get_length.
*/
static size_t get_length(private_delete_payload_t *this)
{
return this->payload_length;
}
/**
* Implementation of delete_payload_t.get_protocol_id.
*/
static protocol_id_t get_protocol_id (private_delete_payload_t *this)
{
return (this->protocol_id);
}
/**
* Implementation of delete_payload_t.add_spi.
*/
static void add_spi(private_delete_payload_t *this, u_int32_t spi)
{
/* only add SPIs if AH|ESP, ignore others */
if (this->protocol_id == PROTO_AH || this->protocol_id == PROTO_ESP)
{
this->spi_count += 1;
this->spis.len += this->spi_size;
this->spis.ptr = realloc(this->spis.ptr, this->spis.len);
*(u_int32_t*)(this->spis.ptr + (this->spis.len / this->spi_size - 1)) = spi;
if (this->spi_list)
{
/* reset SPI iterator list */
this->spi_list->destroy(this->spi_list);
this->spi_list = NULL;
}
}
}
/**
* Implementation of delete_payload_t.create_spi_iterator.
*/
static iterator_t* create_spi_iterator(private_delete_payload_t *this)
{
int i;
if (this->spi_list == NULL)
{
this->spi_list = linked_list_create();
/* only parse SPIs if AH|ESP */
if (this->protocol_id == PROTO_AH || this->protocol_id == PROTO_ESP)
{
for (i = 0; i < this->spi_count; i++)
{
this->spi_list->insert_last(this->spi_list, this->spis.ptr + i *
this->spi_size);
}
}
}
return this->spi_list->create_iterator(this->spi_list, TRUE);
}
/**
* Implementation of payload_t.destroy and delete_payload_t.destroy.
*/
static void destroy(private_delete_payload_t *this)
{
if (this->spis.ptr != NULL)
{
chunk_free(&this->spis);
}
if (this->spi_list)
{
this->spi_list->destroy(this->spi_list);
}
free(this);
}
/*
* Described in header
*/
delete_payload_t *delete_payload_create(protocol_id_t protocol_id)
{
private_delete_payload_t *this = malloc_thing(private_delete_payload_t);
/* interface functions */
this->public.payload_interface.verify = (status_t (*) (payload_t *))verify;
this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules;
this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length;
this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type;
this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type;
this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_payload_type;
this->public.payload_interface.destroy = (void (*) (payload_t *))destroy;
/* public functions */
this->public.destroy = (void (*) (delete_payload_t *)) destroy;
this->public.get_protocol_id = (protocol_id_t (*) (delete_payload_t *)) get_protocol_id;
this->public.add_spi = (void (*) (delete_payload_t *,u_int32_t))add_spi;
this->public.create_spi_iterator = (iterator_t* (*) (delete_payload_t *)) create_spi_iterator;
/* private variables */
this->critical = FALSE;
this->next_payload = NO_PAYLOAD;
this->payload_length = DELETE_PAYLOAD_HEADER_LENGTH;
this->protocol_id = protocol_id;
this->spi_size = protocol_id == PROTO_AH || protocol_id == PROTO_ESP ? 4 : 0;
this->spi_count = 0;
this->spis = chunk_empty;
this->spi_list = NULL;
return (&this->public);
}
@@ -0,0 +1,84 @@
/*
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup delete_payload delete_payload
* @{ @ingroup payloads
*/
#ifndef DELETE_PAYLOAD_H_
#define DELETE_PAYLOAD_H_
typedef struct delete_payload_t delete_payload_t;
#include <library.h>
#include <encoding/payloads/payload.h>
#include <encoding/payloads/proposal_substructure.h>
/**
* Length of a delete payload without the SPI in bytes.
*/
#define DELETE_PAYLOAD_HEADER_LENGTH 8
/**
* Class representing an IKEv2 DELETE payload.
*
* The DELETE payload format is described in RFC section 3.11.
*/
struct delete_payload_t {
/**
* The payload_t interface.
*/
payload_t payload_interface;
/**
* Get the protocol ID.
*
* @return protocol ID
*/
protocol_id_t (*get_protocol_id) (delete_payload_t *this);
/**
* Add an SPI to the list of deleted SAs.
*
* @param spi spi to add
*/
void (*add_spi) (delete_payload_t *this, u_int32_t spi);
/**
* Get an iterator over the SPIs.
*
* The iterate() function returns a pointer to a u_int32_t SPI.
*
* @return iterator over SPIs
*/
iterator_t *(*create_spi_iterator) (delete_payload_t *this);
/**
* Destroys an delete_payload_t object.
*/
void (*destroy) (delete_payload_t *this);
};
/**
* Creates an empty delete_payload_t object.
*
* @param protocol_id protocol, such as AH|ESP
* @return delete_payload_t object
*/
delete_payload_t *delete_payload_create(protocol_id_t protocol_id);
#endif /** DELETE_PAYLOAD_H_ @}*/
@@ -0,0 +1,302 @@
/*
* Copyright (C) 2005-2010 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <stddef.h>
#include "eap_payload.h"
#include <daemon.h>
typedef struct private_eap_payload_t private_eap_payload_t;
/**
* Private data of an eap_payload_t object.
*
*/
struct private_eap_payload_t {
/**
* Public eap_payload_t interface.
*/
eap_payload_t public;
/**
* Next payload type.
*/
u_int8_t next_payload;
/**
* Critical flag.
*/
bool critical;
/**
* Length of this payload.
*/
u_int16_t payload_length;
/**
* EAP message data, if available
*/
chunk_t data;
};
/**
* Encoding rules to parse or generate a EAP payload.
*
* The defined offsets are the positions in a object of type
* private_eap_payload_t.
*
*/
static encoding_rule_t eap_payload_encodings[] = {
/* 1 Byte next payload type, stored in the field next_payload */
{ U_INT_8, offsetof(private_eap_payload_t, next_payload) },
/* the critical bit */
{ FLAG, offsetof(private_eap_payload_t, critical) },
/* 7 Bit reserved bits, nowhere stored */
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
/* Length of the whole payload*/
{ PAYLOAD_LENGTH, offsetof(private_eap_payload_t, payload_length) },
/* chunt to data, starting at "code" */
{ EAP_DATA, offsetof(private_eap_payload_t, data) },
};
/*
1 2 3
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! Next Payload !C! RESERVED ! Payload Length !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! Code ! Identifier ! Length !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! Type ! Type_Data...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
*/
METHOD(payload_t, verify, status_t,
private_eap_payload_t *this)
{
u_int16_t length;
u_int8_t code;
if (this->data.len < 4)
{
DBG1(DBG_ENC, "EAP payloads EAP message too short (%d)", this->data.len);
return FAILED;
}
length = untoh16(this->data.ptr + 2);
if (this->data.len != length)
{
DBG1(DBG_ENC, "EAP payload length (%d) does not match contained "
"message length (%d)", this->data.len, length);
return FAILED;
}
code = this->data.ptr[0];
switch (code)
{
case EAP_REQUEST:
case EAP_RESPONSE:
{
if (this->data.len < 4)
{
DBG1(DBG_ENC, "EAP Request/Response does not have any data");
return FAILED;
}
break;
}
case EAP_SUCCESS:
case EAP_FAILURE:
{
if (this->data.len != 4)
{
DBG1(DBG_ENC, "EAP Success/Failure has data");
return FAILED;
}
break;
}
default:
return FAILED;
}
return SUCCESS;
}
METHOD(payload_t, get_encoding_rules, void,
private_eap_payload_t *this, encoding_rule_t **rules, size_t *rule_count)
{
*rules = eap_payload_encodings;
*rule_count = sizeof(eap_payload_encodings) / sizeof(encoding_rule_t);
}
METHOD(payload_t, get_payload_type, payload_type_t,
private_eap_payload_t *this)
{
return EXTENSIBLE_AUTHENTICATION;
}
METHOD(payload_t, get_next_type, payload_type_t,
private_eap_payload_t *this)
{
return (this->next_payload);
}
METHOD(payload_t, set_next_type, void,
private_eap_payload_t *this, payload_type_t type)
{
this->next_payload = type;
}
METHOD(payload_t, get_length, size_t,
private_eap_payload_t *this)
{
return this->payload_length;
}
METHOD(eap_payload_t, get_data, chunk_t,
private_eap_payload_t *this)
{
return this->data;
}
METHOD(eap_payload_t, set_data, void,
private_eap_payload_t *this, chunk_t data)
{
free(this->data.ptr);
this->data = chunk_clone(data);
this->payload_length = this->data.len + 4;
}
METHOD(eap_payload_t, get_code, eap_code_t,
private_eap_payload_t *this)
{
if (this->data.len > 0)
{
return this->data.ptr[0];
}
/* should not happen, as it is verified */
return 0;
}
METHOD(eap_payload_t, get_identifier, u_int8_t,
private_eap_payload_t *this)
{
if (this->data.len > 1)
{
return this->data.ptr[1];
}
/* should not happen, as it is verified */
return 0;
}
METHOD(eap_payload_t, get_type, eap_type_t,
private_eap_payload_t *this, u_int32_t *vendor)
{
eap_type_t type;
*vendor = 0;
if (this->data.len > 4)
{
type = this->data.ptr[4];
if (type != EAP_EXPANDED)
{
return type;
}
if (this->data.len >= 12)
{
*vendor = untoh32(this->data.ptr + 4) & 0x00FFFFFF;
return untoh32(this->data.ptr + 8);
}
}
return 0;
}
METHOD2(payload_t, eap_payload_t, destroy, void,
private_eap_payload_t *this)
{
chunk_free(&this->data);
free(this);
}
/*
* Described in header
*/
eap_payload_t *eap_payload_create()
{
private_eap_payload_t *this;
INIT(this,
.public = {
.payload_interface = {
.verify = _verify,
.get_encoding_rules = _get_encoding_rules,
.get_length = _get_length,
.get_next_type = _get_next_type,
.set_next_type = _set_next_type,
.get_type = _get_payload_type,
.destroy = _destroy,
},
.get_data = _get_data,
.set_data = _set_data,
.get_code = _get_code,
.get_identifier = _get_identifier,
.get_type = _get_type,
.destroy = _destroy,
},
.next_payload = NO_PAYLOAD,
.payload_length = EAP_PAYLOAD_HEADER_LENGTH,
);
return &this->public;
}
/*
* Described in header
*/
eap_payload_t *eap_payload_create_data(chunk_t data)
{
eap_payload_t *this = eap_payload_create();
this->set_data(this, data);
return this;
}
/*
* Described in header
*/
eap_payload_t *eap_payload_create_code(eap_code_t code, u_int8_t identifier)
{
chunk_t data;
data = chunk_from_chars(code, identifier, 0, 0);
htoun16(data.ptr + 2, data.len);
return eap_payload_create_data(data);
}
/*
* Described in header
*/
eap_payload_t *eap_payload_create_nak(u_int8_t identifier)
{
chunk_t data;
data = chunk_from_chars(EAP_RESPONSE, identifier, 0, 0, EAP_NAK);
htoun16(data.ptr + 2, data.len);
return eap_payload_create_data(data);
}
@@ -0,0 +1,129 @@
/*
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup eap_payload eap_payload
* @{ @ingroup payloads
*/
#ifndef EAP_PAYLOAD_H_
#define EAP_PAYLOAD_H_
typedef struct eap_payload_t eap_payload_t;
#include <library.h>
#include <encoding/payloads/payload.h>
#include <sa/authenticators/eap/eap_method.h>
/**
* Length of a EAP payload without the EAP Message in bytes.
*/
#define EAP_PAYLOAD_HEADER_LENGTH 4
/**
* Class representing an IKEv2 EAP payload.
*
* The EAP payload format is described in RFC section 3.16.
*/
struct eap_payload_t {
/**
* The payload_t interface.
*/
payload_t payload_interface;
/**
* Set the contained EAP data.
*
* This contains the FULL EAP message starting with "code".
* Chunk gets cloned.
*
* @param message EAP data
*/
void (*set_data) (eap_payload_t *this, chunk_t data);
/**
* Get the contained EAP data.
*
* This contains the FULL EAP message starting with "code".
*
* @return EAP data (pointer to internal data)
*/
chunk_t (*get_data) (eap_payload_t *this);
/**
* Get the EAP code.
*
* @return EAP message as chunk_t
*/
eap_code_t (*get_code) (eap_payload_t *this);
/**
* Get the EAP identifier.
*
* @return unique identifier
*/
u_int8_t (*get_identifier) (eap_payload_t *this);
/**
* Get the EAP method type.
*
* @param vendor pointer receiving vendor identifier
* @return EAP method type, vendor specific if vendor != 0
*/
eap_type_t (*get_type) (eap_payload_t *this, u_int32_t *vendor);
/**
* Destroys an eap_payload_t object.
*/
void (*destroy) (eap_payload_t *this);
};
/**
* Creates an empty eap_payload_t object.
*
* @return eap_payload_t object
*/
eap_payload_t *eap_payload_create(void);
/**
* Creates an eap_payload_t object with data.
*
* @return eap_payload_t object
*/
eap_payload_t *eap_payload_create_data(chunk_t data);
/**
* Creates an eap_payload_t object with a code.
*
* Could should be either EAP_SUCCESS/EAP_FAILURE, use
* constructor above otherwise.
*
* @param code EAP status code
* @param identifier EAP identifier to use in payload
* @return eap_payload_t object
*/
eap_payload_t *eap_payload_create_code(eap_code_t code, u_int8_t identifier);
/**
* Creates an eap_payload_t EAP_RESPONSE containing an EAP_NAK.
*
* @param identifier EAP identifier to use in payload
* @return eap_payload_t object
*/
eap_payload_t *eap_payload_create_nak(u_int8_t identifier);
#endif /** EAP_PAYLOAD_H_ @}*/
@@ -0,0 +1,58 @@
/*
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "encodings.h"
ENUM(encoding_type_names, U_INT_4, ENCRYPTED_DATA,
"U_INT_4",
"U_INT_8",
"U_INT_16",
"U_INT_32",
"RESERVED_BIT",
"RESERVED_BYTE",
"FLAG",
"PAYLOAD_LENGTH",
"HEADER_LENGTH",
"SPI_SIZE",
"SPI",
"KEY_EXCHANGE_DATA",
"NOTIFICATION_DATA",
"PROPOSALS",
"TRANSFORMS",
"TRANSFORM_ATTRIBUTES",
"CONFIGURATION_ATTRIBUTES",
"CONFIGURATION_ATTRIBUTE_VALUE",
"ATTRIBUTE_FORMAT",
"ATTRIBUTE_TYPE",
"ATTRIBUTE_LENGTH_OR_VALUE",
"CONFIGURATION_ATTRIBUTE_LENGTH",
"ATTRIBUTE_VALUE",
"TRAFFIC_SELECTORS",
"TS_TYPE",
"ADDRESS",
"NONCE_DATA",
"ID_DATA",
"AUTH_DATA",
"CERT_DATA",
"CERTREQ_DATA",
"EAP_DATA",
"SPIS",
"VID_DATA",
"UNKNOWN_DATA",
"IKE_SPI",
"ENCRYPTED_DATA",
);
+515
View File
@@ -0,0 +1,515 @@
/*
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup encodings encodings
* @{ @ingroup payloads
*/
#ifndef ENCODINGS_H_
#define ENCODINGS_H_
typedef enum encoding_type_t encoding_type_t;
typedef struct encoding_rule_t encoding_rule_t;
#include <library.h>
/**
* All different kinds of encoding types.
*
* Each field of an IKEv2-Message (in header or payload)
* which has to be parsed or generated differently has its own
* type defined here.
*
* Header is parsed like a payload and gets its one payload_id
* from PRIVATE USE space. Also the substructures
* of specific payload types get their own payload_id
* from PRIVATE_USE space. See IKEv2-Draft for more informations.
*/
enum encoding_type_t {
/**
* Representing a 4 Bit unsigned int value.
*
*
* When generating it must be changed from host to network order.
* The value is read from the associated data struct.
* The current write position is moved 4 bit forward afterwards.
*
* When parsing it must be changed from network to host order.
* The value is written to the associated data struct.
* The current read pointer is moved 4 bit forward afterwards.
*/
U_INT_4,
/**
* Representing a 8 Bit unsigned int value.
*
*
* When generating it must be changed from host to network order.
* The value is read from the associated data struct.
* The current write position is moved 8 bit forward afterwards.
*
* When parsing it must be changed from network to host order.
* The value is written to the associated data struct.
* The current read pointer is moved 8 bit forward afterwards.
*/
U_INT_8,
/**
* Representing a 16 Bit unsigned int value.
*
*
* When generating it must be changed from host to network order.
* The value is read from the associated data struct.
* The current write position is moved 16 bit forward afterwards.
*
* When parsing it must be changed from network to host order.
* The value is written to the associated data struct.
* The current read pointer is moved 16 bit forward afterwards.
*/
U_INT_16,
/**
* Representing a 32 Bit unsigned int value.
*
* When generating it must be changed from host to network order.
* The value is read from the associated data struct.
* The current write position is moved 32 bit forward afterwards.
*
* When parsing it must be changed from network to host order.
* The value is written to the associated data struct.
* The current read pointer is moved 32 bit forward afterwards.
*/
U_INT_32,
/**
* represents a RESERVED_BIT used in FLAG-Bytes.
*
* When generating, the next bit is set to zero and the current write
* position is moved one bit forward.
* No value is read from the associated data struct.
* The current write position is moved 1 bit forward afterwards.
*
* When parsing, the current read pointer is moved one bit forward.
* No value is written to the associated data struct.
* The current read pointer is moved 1 bit forward afterwards.
*/
RESERVED_BIT,
/**
* represents a RESERVED_BYTE.
*
* When generating, the next byte is set to zero and the current write
* position is moved one byte forward.
* No value is read from the associated data struct.
* The current write position is moved 1 byte forward afterwards.
*
* When parsing, the current read pointer is moved one byte forward.
* No value is written to the associated data struct.
* The current read pointer is moved 1 byte forward afterwards.
*/
RESERVED_BYTE,
/**
* Representing a 1 Bit flag.
*
* When generation, the next bit is set to 1 if the associated value
* in the data struct is TRUE, 0 otherwise. The current write position
* is moved 1 bit forward afterwards.
*
* When parsing, the next bit is read and stored in the associated data
* struct. 0 means FALSE, 1 means TRUE, The current read pointer
* is moved 1 bit forward afterwards
*/
FLAG,
/**
* Representating a length field of a payload.
*
* When generating it must be changed from host to network order.
* The value is read from the associated data struct.
* The current write position is moved 16 bit forward afterwards.
*
* When parsing it must be changed from network to host order.
* The value is written to the associated data struct.
* The current read pointer is moved 16 bit forward afterwards.
*/
PAYLOAD_LENGTH,
/**
* Representating a length field of a header.
*
* When generating it must be changed from host to network order.
* The value is read from the associated data struct.
* The current write position is moved 32 bit forward afterwards.
*
* When parsing it must be changed from network to host order.
* The value is written to the associated data struct.
* The current read pointer is moved 32 bit forward afterwards.
*/
HEADER_LENGTH,
/**
* Representating a spi size field.
*
* When generating it must be changed from host to network order.
* The value is read from the associated data struct.
* The current write position is moved 8 bit forward afterwards.
*
* When parsing it must be changed from network to host order.
* The value is written to the associated data struct.
* The current read pointer is moved 8 bit forward afterwards.
*/
SPI_SIZE,
/**
* Representating a spi field.
*
* When generating the content of the chunkt pointing to
* is written.
*
* When parsing SPI_SIZE bytes are read and written into the chunk pointing to.
*/
SPI,
/**
* Representating a Key Exchange Data field.
*
* When generating the content of the chunkt pointing to
* is written.
*
* When parsing (Payload Length - 8) bytes are read and written into the chunk pointing to.
*/
KEY_EXCHANGE_DATA,
/**
* Representating a Notification field.
*
* When generating the content of the chunkt pointing to
* is written.
*
* When parsing (Payload Length - spi size - 8) bytes are read and written into the chunk pointing to.
*/
NOTIFICATION_DATA,
/**
* Representating one or more proposal substructures.
*
* The offset points to a linked_list_t pointer.
*
* When generating the proposal_substructure_t objects are stored
* in the pointed linked_list.
*
* When parsing the parsed proposal_substructure_t objects have
* to be stored in the pointed linked_list.
*/
PROPOSALS,
/**
* Representating one or more transform substructures.
*
* The offset points to a linked_list_t pointer.
*
* When generating the transform_substructure_t objects are stored
* in the pointed linked_list.
*
* When parsing the parsed transform_substructure_t objects have
* to be stored in the pointed linked_list.
*/
TRANSFORMS,
/**
* Representating one or more Attributes of a transform substructure.
*
* The offset points to a linked_list_t pointer.
*
* When generating the transform_attribute_t objects are stored
* in the pointed linked_list.
*
* When parsing the parsed transform_attribute_t objects have
* to be stored in the pointed linked_list.
*/
TRANSFORM_ATTRIBUTES,
/**
* Representating one or more Attributes of a configuration payload.
*
* The offset points to a linked_list_t pointer.
*
* When generating the configuration_attribute_t objects are stored
* in the pointed linked_list.
*
* When parsing the parsed configuration_attribute_t objects have
* to be stored in the pointed linked_list.
*/
CONFIGURATION_ATTRIBUTES,
/**
*
* When generating the content of the chunkt pointing to
* is written.
*
* When parsing (Payload Length - 4) bytes are read and written into the chunk pointing to.
*/
CONFIGURATION_ATTRIBUTE_VALUE,
/**
* Representing a 1 Bit flag specifying the format of a transform attribute.
*
* When generation, the next bit is set to 1 if the associated value
* in the data struct is TRUE, 0 otherwise. The current write position
* is moved 1 bit forward afterwards.
*
* When parsing, the next bit is read and stored in the associated data
* struct. 0 means FALSE, 1 means TRUE, The current read pointer
* is moved 1 bit forward afterwards.
*/
ATTRIBUTE_FORMAT,
/**
* Representing a 15 Bit unsigned int value used as attribute type
* in an attribute transform.
*
*
* When generating it must be changed from host to network order.
* The value is read from the associated data struct.
* The current write position is moved 15 bit forward afterwards.
*
* When parsing it must be changed from network to host order.
* The value is written to the associated data struct.
* The current read pointer is moved 15 bit forward afterwards.
*/
ATTRIBUTE_TYPE,
/**
* Depending on the field of type ATTRIBUTE_FORMAT
* this field contains the length or the value of an transform attribute.
* Its stored in a 16 unsigned integer field.
*
* When generating it must be changed from host to network order.
* The value is read from the associated data struct.
* The current write position is moved 16 bit forward afterwards.
*
* When parsing it must be changed from network to host order.
* The value is written to the associated data struct.
* The current read pointer is moved 16 bit forward afterwards.
*/
ATTRIBUTE_LENGTH_OR_VALUE,
/**
* This field contains the length or the value of an configuration attribute.
* Its stored in a 16 unsigned integer field.
*
* When generating it must be changed from host to network order.
* The value is read from the associated data struct.
* The current write position is moved 16 bit forward afterwards.
*
* When parsing it must be changed from network to host order.
* The value is written to the associated data struct.
* The current read pointer is moved 16 bit forward afterwards.
*/
CONFIGURATION_ATTRIBUTE_LENGTH,
/**
* Depending on the field of type ATTRIBUTE_FORMAT
* this field is available or missing and so parsed/generated
* or not parsed/not generated.
*
* When generating the content of the chunkt pointing to
* is written.
*
* When parsing SPI_SIZE bytes are read and written into the chunk pointing to.
*/
ATTRIBUTE_VALUE,
/**
* Representating one or more Traffic selectors of a TS payload.
*
* The offset points to a linked_list_t pointer.
*
* When generating the traffic_selector_substructure_t objects are stored
* in the pointed linked_list.
*
* When parsing the parsed traffic_selector_substructure_t objects have
* to be stored in the pointed linked_list.
*/
TRAFFIC_SELECTORS,
/**
* Representating a Traffic selector type field.
*
* When generating it must be changed from host to network order.
* The value is read from the associated data struct.
* The current write position is moved 16 bit forward afterwards.
*
* When parsing it must be changed from network to host order.
* The value is written to the associated data struct.
* The current read pointer is moved 16 bit forward afterwards.
*/
TS_TYPE,
/**
* Representating an address field in a traffic selector.
*
* Depending on the last field of type TS_TYPE
* this field is either 4 or 16 byte long.
*
* When generating the content of the chunkt pointing to
* is written.
*
* When parsing 4 or 16 bytes are read and written into the chunk pointing to.
*/
ADDRESS,
/**
* Representating a Nonce Data field.
*
* When generating the content of the chunkt pointing to
* is written.
*
* When parsing (Payload Length - 4) bytes are read and written into the chunk pointing to.
*/
NONCE_DATA,
/**
* Representating a ID Data field.
*
* When generating the content of the chunkt pointing to
* is written.
*
* When parsing (Payload Length - 8) bytes are read and written into the chunk pointing to.
*/
ID_DATA,
/**
* Representating a AUTH Data field.
*
* When generating the content of the chunkt pointing to
* is written.
*
* When parsing (Payload Length - 8) bytes are read and written into the chunk pointing to.
*/
AUTH_DATA,
/**
* Representating a CERT Data field.
*
* When generating the content of the chunkt pointing to
* is written.
*
* When parsing (Payload Length - 5) bytes are read and written into the chunk pointing to.
*/
CERT_DATA,
/**
* Representating a CERTREQ Data field.
*
* When generating the content of the chunkt pointing to
* is written.
*
* When parsing (Payload Length - 5) bytes are read and written into the chunk pointing to.
*/
CERTREQ_DATA,
/**
* Representating an EAP message field.
*
* When generating the content of the chunkt pointing to
* is written.
*
* When parsing (Payload Length - 4) bytes are read and written into the chunk pointing to.
*/
EAP_DATA,
/**
* Representating the SPIS field in a DELETE payload.
*
* When generating the content of the chunkt pointing to
* is written.
*
* When parsing (Payload Length - 8) bytes are read and written into the chunk pointing to.
*/
SPIS,
/**
* Representating the VID DATA field in a VENDOR ID payload.
*
* When generating the content of the chunkt pointing to
* is written.
*
* When parsing (Payload Length - 4) bytes are read and written into the chunk pointing to.
*/
VID_DATA,
/**
* Representating the DATA of an unknown payload.
*
* When generating the content of the chunkt pointing to
* is written.
*
* When parsing (Payload Length - 4) bytes are read and written into the chunk pointing to.
*/
UNKNOWN_DATA,
/**
* Representating an IKE_SPI field in an IKEv2 Header.
*
* When generating the value of the u_int64_t pointing to
* is written (host and networ order is not changed).
*
* When parsing 8 bytes are read and written into the u_int64_t pointing to.
*/
IKE_SPI,
/**
* Representing the encrypted data body of a encryption payload.
*/
ENCRYPTED_DATA,
};
/**
* enum name for encoding_type_t
*/
extern enum_name_t *encoding_type_names;
/**
* Rule how to en-/decode a payload field.
*
* An encoding rule is a mapping of a specific encoding type to
* a location in the data struct where the current field is stored to
* or read from.
* This rules are used by parser and generator.
*/
struct encoding_rule_t {
/**
* Encoding type.
*/
encoding_type_t type;
/**
* Offset in the data struct.
*
* When parsing, data are written to this offset of the
* data struct.
*
* When generating, data are read from this offset in the
* data struct.
*/
u_int32_t offset;
};
#endif /** ENCODINGS_H_ @}*/
@@ -0,0 +1,619 @@
/*
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <stddef.h>
#include <string.h>
#include "encryption_payload.h"
#include <daemon.h>
#include <encoding/payloads/encodings.h>
#include <utils/linked_list.h>
#include <encoding/generator.h>
#include <encoding/parser.h>
#include <utils/iterator.h>
#include <crypto/signers/signer.h>
typedef struct private_encryption_payload_t private_encryption_payload_t;
/**
* Private data of an encryption_payload_t' Object.
*
*/
struct private_encryption_payload_t {
/**
* Public encryption_payload_t interface.
*/
encryption_payload_t public;
/**
* There is no next payload for an encryption payload,
* since encryption payload MUST be the last one.
* next_payload means here the first payload of the
* contained, encrypted payload.
*/
u_int8_t next_payload;
/**
* Critical flag.
*/
bool critical;
/**
* Length of this payload
*/
u_int16_t payload_length;
/**
* Chunk containing the iv, data, padding,
* and (an eventually not calculated) signature.
*/
chunk_t encrypted;
/**
* Chunk containing the data in decrypted (unpadded) form.
*/
chunk_t decrypted;
/**
* Signer set by set_signer.
*/
signer_t *signer;
/**
* Crypter, supplied by encrypt/decrypt
*/
crypter_t *crypter;
/**
* Contained payloads of this encrpytion_payload.
*/
linked_list_t *payloads;
};
/**
* Encoding rules to parse or generate a IKEv2-Encryption Payload.
*
* The defined offsets are the positions in a object of type
* private_encryption_payload_t.
*
*/
encoding_rule_t encryption_payload_encodings[] = {
/* 1 Byte next payload type, stored in the field next_payload */
{ U_INT_8, offsetof(private_encryption_payload_t, next_payload) },
/* the critical bit */
{ FLAG, offsetof(private_encryption_payload_t, critical) },
/* 7 Bit reserved bits, nowhere stored */
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
/* Length of the whole encryption payload*/
{ PAYLOAD_LENGTH, offsetof(private_encryption_payload_t, payload_length) },
/* encrypted data, stored in a chunk. contains iv, data, padding */
{ ENCRYPTED_DATA, offsetof(private_encryption_payload_t, encrypted) },
};
/*
1 2 3
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! Next Payload !C! RESERVED ! Payload Length !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! Initialization Vector !
! (length is block size for encryption algorithm) !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! Encrypted IKE Payloads !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! ! Padding (0-255 octets) !
+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
! ! Pad Length !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
~ Integrity Checksum Data ~
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
/**
* Implementation of payload_t.verify.
*/
static status_t verify(private_encryption_payload_t *this)
{
return SUCCESS;
}
/**
* Implementation of payload_t.get_encoding_rules.
*/
static void get_encoding_rules(private_encryption_payload_t *this, encoding_rule_t **rules, size_t *rule_count)
{
*rules = encryption_payload_encodings;
*rule_count = sizeof(encryption_payload_encodings) / sizeof(encoding_rule_t);
}
/**
* Implementation of payload_t.get_type.
*/
static payload_type_t get_type(private_encryption_payload_t *this)
{
return ENCRYPTED;
}
/**
* Implementation of payload_t.get_next_type.
*/
static payload_type_t get_next_type(private_encryption_payload_t *this)
{
/* returns first contained payload here */
return (this->next_payload);
}
/**
* Implementation of payload_t.set_next_type.
*/
static void set_next_type(private_encryption_payload_t *this, payload_type_t type)
{
/* set next type is not allowed, since this payload MUST be the last one
* and so nothing is done in here*/
}
/**
* (re-)compute the lenght of the whole payload
*/
static void compute_length(private_encryption_payload_t *this)
{
iterator_t *iterator;
payload_t *current_payload;
size_t block_size, length = 0;
iterator = this->payloads->create_iterator(this->payloads, TRUE);
/* count payload length */
while (iterator->iterate(iterator, (void **) &current_payload))
{
length += current_payload->get_length(current_payload);
}
iterator->destroy(iterator);
if (this->crypter && this->signer)
{
/* append one byte for padding length */
length++;
/* append padding */
block_size = this->crypter->get_block_size(this->crypter);
length += block_size - length % block_size;
/* add iv */
length += block_size;
/* add signature */
length += this->signer->get_block_size(this->signer);
}
length += ENCRYPTION_PAYLOAD_HEADER_LENGTH;
this->payload_length = length;
}
/**
* Implementation of payload_t.get_length.
*/
static size_t get_length(private_encryption_payload_t *this)
{
compute_length(this);
return this->payload_length;
}
/**
* Implementation of payload_t.create_payload_iterator.
*/
static iterator_t *create_payload_iterator (private_encryption_payload_t *this, bool forward)
{
return (this->payloads->create_iterator(this->payloads, forward));
}
/**
* Implementation of payload_t.add_payload.
*/
static void add_payload(private_encryption_payload_t *this, payload_t *payload)
{
payload_t *last_payload;
if (this->payloads->get_count(this->payloads) > 0)
{
this->payloads->get_last(this->payloads,(void **) &last_payload);
last_payload->set_next_type(last_payload, payload->get_type(payload));
}
else
{
this->next_payload = payload->get_type(payload);
}
payload->set_next_type(payload, NO_PAYLOAD);
this->payloads->insert_last(this->payloads, (void*)payload);
compute_length(this);
}
/**
* Implementation of encryption_payload_t.remove_first_payload.
*/
static status_t remove_first_payload(private_encryption_payload_t *this, payload_t **payload)
{
return this->payloads->remove_first(this->payloads, (void**)payload);
}
/**
* Implementation of encryption_payload_t.get_payload_count.
*/
static size_t get_payload_count(private_encryption_payload_t *this)
{
return this->payloads->get_count(this->payloads);
}
/**
* Generate payload before encryption.
*/
static void generate(private_encryption_payload_t *this)
{
payload_t *current_payload, *next_payload;
generator_t *generator;
iterator_t *iterator;
/* recalculate length before generating */
compute_length(this);
/* create iterator */
iterator = this->payloads->create_iterator(this->payloads, TRUE);
/* get first payload */
if (iterator->iterate(iterator, (void**)&current_payload))
{
this->next_payload = current_payload->get_type(current_payload);
}
else
{
/* no paylads? */
DBG2(DBG_ENC, "generating contained payloads, but none available");
free(this->decrypted.ptr);
this->decrypted = chunk_empty;
iterator->destroy(iterator);
return;
}
generator = generator_create();
/* build all payload, except last */
while(iterator->iterate(iterator, (void**)&next_payload))
{
current_payload->set_next_type(current_payload, next_payload->get_type(next_payload));
generator->generate_payload(generator, current_payload);
current_payload = next_payload;
}
iterator->destroy(iterator);
/* build last payload */
current_payload->set_next_type(current_payload, NO_PAYLOAD);
generator->generate_payload(generator, current_payload);
/* free already generated data */
free(this->decrypted.ptr);
generator->write_to_chunk(generator, &(this->decrypted));
generator->destroy(generator);
DBG2(DBG_ENC, "successfully generated content in encryption payload");
}
/**
* Implementation of encryption_payload_t.encrypt.
*/
static status_t encrypt(private_encryption_payload_t *this)
{
chunk_t iv, padding, to_crypt, result;
rng_t *rng;
size_t block_size;
if (this->signer == NULL || this->crypter == NULL)
{
DBG1(DBG_ENC, "could not encrypt, signer/crypter not set");
return INVALID_STATE;
}
/* for random data in iv and padding */
rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
if (!rng)
{
DBG1(DBG_ENC, "could not encrypt, no RNG found");
return FAILED;
}
/* build payload chunk */
generate(this);
DBG2(DBG_ENC, "encrypting payloads");
DBG3(DBG_ENC, "data to encrypt %B", &this->decrypted);
/* build padding */
block_size = this->crypter->get_block_size(this->crypter);
padding.len = block_size - ((this->decrypted.len + 1) % block_size);
rng->allocate_bytes(rng, padding.len, &padding);
/* concatenate payload data, padding, padding len */
to_crypt.len = this->decrypted.len + padding.len + 1;
to_crypt.ptr = malloc(to_crypt.len);
memcpy(to_crypt.ptr, this->decrypted.ptr, this->decrypted.len);
memcpy(to_crypt.ptr + this->decrypted.len, padding.ptr, padding.len);
*(to_crypt.ptr + to_crypt.len - 1) = padding.len;
/* build iv */
iv.len = block_size;
rng->allocate_bytes(rng, iv.len, &iv);
rng->destroy(rng);
DBG3(DBG_ENC, "data before encryption with padding %B", &to_crypt);
/* encrypt to_crypt chunk */
free(this->encrypted.ptr);
this->crypter->encrypt(this->crypter, to_crypt, iv, &result);
free(padding.ptr);
free(to_crypt.ptr);
DBG3(DBG_ENC, "data after encryption %B", &result);
/* build encrypted result with iv and signature */
this->encrypted.len = iv.len + result.len + this->signer->get_block_size(this->signer);
free(this->encrypted.ptr);
this->encrypted.ptr = malloc(this->encrypted.len);
/* fill in result, signature is left out */
memcpy(this->encrypted.ptr, iv.ptr, iv.len);
memcpy(this->encrypted.ptr + iv.len, result.ptr, result.len);
free(result.ptr);
free(iv.ptr);
DBG3(DBG_ENC, "data after encryption with IV and (invalid) signature %B",
&this->encrypted);
return SUCCESS;
}
/**
* Parse the payloads after decryption.
*/
static status_t parse(private_encryption_payload_t *this)
{
parser_t *parser;
status_t status;
payload_type_t current_payload_type;
/* build a parser on the decrypted data */
parser = parser_create(this->decrypted);
current_payload_type = this->next_payload;
/* parse all payloads */
while (current_payload_type != NO_PAYLOAD)
{
payload_t *current_payload;
status = parser->parse_payload(parser, current_payload_type, (payload_t**)&current_payload);
if (status != SUCCESS)
{
parser->destroy(parser);
return PARSE_ERROR;
}
status = current_payload->verify(current_payload);
if (status != SUCCESS)
{
DBG1(DBG_ENC, "%N verification failed",
payload_type_names, current_payload->get_type(current_payload));
current_payload->destroy(current_payload);
parser->destroy(parser);
return VERIFY_ERROR;
}
/* get next payload type */
current_payload_type = current_payload->get_next_type(current_payload);
this->payloads->insert_last(this->payloads,current_payload);
}
parser->destroy(parser);
DBG2(DBG_ENC, "succesfully parsed content of encryption payload");
return SUCCESS;
}
/**
* Implementation of encryption_payload_t.encrypt.
*/
static status_t decrypt(private_encryption_payload_t *this)
{
chunk_t iv, concatenated;
u_int8_t padding_length;
DBG2(DBG_ENC, "decrypting encryption payload");
DBG3(DBG_ENC, "data before decryption with IV and (invalid) signature %B",
&this->encrypted);
if (this->signer == NULL || this->crypter == NULL)
{
DBG1(DBG_ENC, "could not decrypt, no crypter/signer set");
return INVALID_STATE;
}
/* get IV */
iv.len = this->crypter->get_block_size(this->crypter);
iv.ptr = this->encrypted.ptr;
/* point concatenated to data + padding + padding_length*/
concatenated.ptr = this->encrypted.ptr + iv.len;
concatenated.len = this->encrypted.len - iv.len -
this->signer->get_block_size(this->signer);
/* concatenated must be a multiple of block_size of crypter */
if (concatenated.len < iv.len || concatenated.len % iv.len)
{
DBG1(DBG_ENC, "could not decrypt, invalid input");
return FAILED;
}
/* free previus data, if any */
free(this->decrypted.ptr);
DBG3(DBG_ENC, "data before decryption %B", &concatenated);
this->crypter->decrypt(this->crypter, concatenated, iv, &this->decrypted);
DBG3(DBG_ENC, "data after decryption with padding %B", &this->decrypted);
/* get padding length, sits just bevore signature */
padding_length = *(this->decrypted.ptr + this->decrypted.len - 1);
/* add one byte to the padding length, since the padding_length field is
* not included */
padding_length++;
/* check size again */
if (padding_length > concatenated.len || padding_length > this->decrypted.len)
{
DBG1(DBG_ENC, "decryption failed, invalid padding length found. Invalid key?");
/* decryption failed :-/ */
return FAILED;
}
this->decrypted.len -= padding_length;
/* free padding */
this->decrypted.ptr = realloc(this->decrypted.ptr, this->decrypted.len);
DBG3(DBG_ENC, "data after decryption without padding %B", &this->decrypted);
DBG2(DBG_ENC, "decryption successful, trying to parse content");
return parse(this);
}
/**
* Implementation of encryption_payload_t.set_transforms.
*/
static void set_transforms(private_encryption_payload_t *this, crypter_t* crypter, signer_t* signer)
{
this->signer = signer;
this->crypter = crypter;
}
/**
* Implementation of encryption_payload_t.build_signature.
*/
static status_t build_signature(private_encryption_payload_t *this, chunk_t data)
{
chunk_t data_without_sig = data;
chunk_t sig;
if (this->signer == NULL)
{
DBG1(DBG_ENC, "unable to build signature, no signer set");
return INVALID_STATE;
}
sig.len = this->signer->get_block_size(this->signer);
data_without_sig.len -= sig.len;
sig.ptr = data.ptr + data_without_sig.len;
DBG2(DBG_ENC, "building signature");
this->signer->get_signature(this->signer, data_without_sig, sig.ptr);
return SUCCESS;
}
/**
* Implementation of encryption_payload_t.verify_signature.
*/
static status_t verify_signature(private_encryption_payload_t *this, chunk_t data)
{
chunk_t sig, data_without_sig;
bool valid;
if (this->signer == NULL)
{
DBG1(DBG_ENC, "unable to verify signature, no signer set");
return INVALID_STATE;
}
/* find signature in data chunk */
sig.len = this->signer->get_block_size(this->signer);
if (data.len <= sig.len)
{
DBG1(DBG_ENC, "unable to verify signature, invalid input");
return FAILED;
}
sig.ptr = data.ptr + data.len - sig.len;
/* verify it */
data_without_sig.len = data.len - sig.len;
data_without_sig.ptr = data.ptr;
valid = this->signer->verify_signature(this->signer, data_without_sig, sig);
if (!valid)
{
DBG1(DBG_ENC, "signature verification failed");
return FAILED;
}
DBG2(DBG_ENC, "signature verification successful");
return SUCCESS;
}
/**
* Implementation of payload_t.destroy.
*/
static void destroy(private_encryption_payload_t *this)
{
this->payloads->destroy_offset(this->payloads, offsetof(payload_t, destroy));
free(this->encrypted.ptr);
free(this->decrypted.ptr);
free(this);
}
/*
* Described in header
*/
encryption_payload_t *encryption_payload_create()
{
private_encryption_payload_t *this = malloc_thing(private_encryption_payload_t);
/* payload_t interface functions */
this->public.payload_interface.verify = (status_t (*) (payload_t *))verify;
this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules;
this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length;
this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type;
this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type;
this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_type;
this->public.payload_interface.destroy = (void (*) (payload_t *))destroy;
/* public functions */
this->public.create_payload_iterator = (iterator_t * (*) (encryption_payload_t *,bool)) create_payload_iterator;
this->public.add_payload = (void (*) (encryption_payload_t *,payload_t *)) add_payload;
this->public.remove_first_payload = (status_t (*)(encryption_payload_t*, payload_t **)) remove_first_payload;
this->public.get_payload_count = (size_t (*)(encryption_payload_t*)) get_payload_count;
this->public.encrypt = (status_t (*) (encryption_payload_t *)) encrypt;
this->public.decrypt = (status_t (*) (encryption_payload_t *)) decrypt;
this->public.set_transforms = (void (*) (encryption_payload_t*,crypter_t*,signer_t*)) set_transforms;
this->public.build_signature = (status_t (*) (encryption_payload_t*, chunk_t)) build_signature;
this->public.verify_signature = (status_t (*) (encryption_payload_t*, chunk_t)) verify_signature;
this->public.destroy = (void (*) (encryption_payload_t *)) destroy;
/* set default values of the fields */
this->critical = FALSE;
this->next_payload = NO_PAYLOAD;
this->payload_length = ENCRYPTION_PAYLOAD_HEADER_LENGTH;
this->encrypted = chunk_empty;
this->decrypted = chunk_empty;
this->signer = NULL;
this->crypter = NULL;
this->payloads = linked_list_create();
return (&(this->public));
}
@@ -0,0 +1,173 @@
/*
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup encryption_payload encryption_payload
* @{ @ingroup payloads
*/
#ifndef ENCRYPTION_PAYLOAD_H_
#define ENCRYPTION_PAYLOAD_H_
typedef struct encryption_payload_t encryption_payload_t;
#include <library.h>
#include <crypto/crypters/crypter.h>
#include <crypto/signers/signer.h>
#include <encoding/payloads/payload.h>
#include <utils/linked_list.h>
/**
* Encrpytion payload length in bytes without IV and following data.
*/
#define ENCRYPTION_PAYLOAD_HEADER_LENGTH 4
/**
* The encryption payload as described in RFC section 3.14.
*
* Before any crypt/decrypt/sign/verify operation can occur,
* the transforms must be set. After that, a parsed encryption payload
* can be decrypted, which also will parse the contained payloads.
* Encryption is done the same way, added payloads will get generated
* and then encrypted.
* For signature building, there is the FULL packet needed. Meaning it
* must be builded after generation of all payloads and the encryption
* of the encryption payload.
* Signature verificatin is done before decryption.
*/
struct encryption_payload_t {
/**
* Implements payload_t interface.
*/
payload_t payload_interface;
/**
* Creates an iterator for all contained payloads.
*
* iterator_t object has to get destroyed by the caller.
*
* @param forward iterator direction (TRUE: front to end)
* return created iterator_t object
*/
iterator_t *(*create_payload_iterator) (encryption_payload_t *this, bool forward);
/**
* Adds a payload to this encryption payload.
*
* @param payload payload_t object to add
*/
void (*add_payload) (encryption_payload_t *this, payload_t *payload);
/**
* Reove the last payload in the contained payload list.
*
* @param payload removed payload
* @return
* - SUCCESS, or
* - NOT_FOUND if list empty
*/
status_t (*remove_first_payload) (encryption_payload_t *this, payload_t **payload);
/**
* Get the number of payloads.
*
* @return number of contained payloads
*/
size_t (*get_payload_count) (encryption_payload_t *this);
/**
* Set transforms to use.
*
* To decryption, encryption, signature building and verifying,
* the payload needs a crypter and a signer object.
*
* @warning Do NOT call this function again after encryption, since
* the signer must be the same while encrypting and signature building!
*
* @param crypter crypter_t to use for data de-/encryption
* @param signer signer_t to use for data signing/verifying
*/
void (*set_transforms) (encryption_payload_t *this, crypter_t *crypter, signer_t *signer);
/**
* Generate and encrypt contained payloads.
*
* This function generates the content for added payloads
* and encrypts them. Signature is not built, since we need
* additional data (the full message).
*
* @return SUCCESS, or INVALID_STATE if transforms not set
*/
status_t (*encrypt) (encryption_payload_t *this);
/**
* Decrypt and parse contained payloads.
*
* This function decrypts the contained data. After,
* the payloads are parsed internally and are accessible
* via the iterator.
*
* @return
* - SUCCESS, or
* - INVALID_STATE if transforms not set, or
* - FAILED if data is invalid
*/
status_t (*decrypt) (encryption_payload_t *this);
/**
* Build the signature.
*
* The signature is built over the FULL message, so the header
* and every payload (inclusive this one) must already be generated.
* The generated message is supplied via the data paramater.
*
* @param data chunk contains the already generated message
* @return
* - SUCCESS, or
* - INVALID_STATE if transforms not set
*/
status_t (*build_signature) (encryption_payload_t *this, chunk_t data);
/**
* Verify the signature.
*
* Since the signature is built over the full message, we need
* this data to do the verification. The message data
* is supplied via the data argument.
*
* @param data chunk contains the message
* @return
* - SUCCESS, or
* - FAILED if signature invalid, or
* - INVALID_STATE if transforms not set
*/
status_t (*verify_signature) (encryption_payload_t *this, chunk_t data);
/**
* Destroys an encryption_payload_t object.
*/
void (*destroy) (encryption_payload_t *this);
};
/**
* Creates an empty encryption_payload_t object.
*
* @return encryption_payload_t object
*/
encryption_payload_t *encryption_payload_create(void);
#endif /** ENCRYPTION_PAYLOAD_H_ @}*/
@@ -0,0 +1,422 @@
/*
* Copyright (C) 2007 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "endpoint_notify.h"
#include <math.h>
#include <daemon.h>
typedef struct private_endpoint_notify_t private_endpoint_notify_t;
/**
* Private data of an notify_payload_t object.
*/
struct private_endpoint_notify_t {
/**
* Public endpoint_notify_t interface.
*/
endpoint_notify_t public;
/**
* Priority
*/
u_int32_t priority;
/**
* Family
*/
me_endpoint_family_t family;
/**
* Endpoint type
*/
me_endpoint_type_t type;
/**
* Endpoint
*/
host_t *endpoint;
/**
* Base (used for server reflexive endpoints)
*/
host_t *base;
};
/* Notification data:
1 2 3
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! Priority !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! Family ! Type ! Port !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! IP Address (variable) !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
ENUM(me_endpoint_type_names, HOST, RELAYED,
"HOST",
"PEER_REFLEXIVE",
"SERVER_REFLEXIVE",
"RELAYED"
);
/**
* Helper functions to parse integer values
*/
static status_t parse_uint8(u_int8_t **cur, u_int8_t *top, u_int8_t *val)
{
if (*cur + sizeof(u_int8_t) > top)
{
return FAILED;
}
*val = *(u_int8_t*)*cur;
*cur += sizeof(u_int8_t);
return SUCCESS;
}
static status_t parse_uint16(u_int8_t **cur, u_int8_t *top, u_int16_t *val)
{
if (*cur + sizeof(u_int16_t) > top)
{
return FAILED;
}
*val = ntohs(*(u_int16_t*)*cur);
*cur += sizeof(u_int16_t);
return SUCCESS;
}
static status_t parse_uint32(u_int8_t **cur, u_int8_t *top, u_int32_t *val)
{
if (*cur + sizeof(u_int32_t) > top)
{
return FAILED;
}
*val = ntohl(*(u_int32_t*)*cur);
*cur += sizeof(u_int32_t);
return SUCCESS;
}
/**
* Parses the notification data of a ME_ENDPOINT notify
*/
static status_t parse_notification_data(private_endpoint_notify_t *this, chunk_t data)
{
u_int8_t family, type, addr_family;
u_int16_t port;
chunk_t addr;
u_int8_t *cur = data.ptr;
u_int8_t *top = data.ptr + data.len;
DBG3(DBG_IKE, "me_endpoint_data %B", &data);
if (parse_uint32(&cur, top, &this->priority) != SUCCESS)
{
DBG1(DBG_IKE, "failed to parse ME_ENDPOINT: invalid priority");
return FAILED;
}
if (parse_uint8(&cur, top, &family) != SUCCESS || family >= MAX_FAMILY)
{
DBG1(DBG_IKE, "failed to parse ME_ENDPOINT: invalid family");
return FAILED;
}
this->family = (me_endpoint_family_t)family;
if (parse_uint8(&cur, top, &type) != SUCCESS ||
type == NO_TYPE || type >= MAX_TYPE)
{
DBG1(DBG_IKE, "failed to parse ME_ENDPOINT: invalid type");
return FAILED;
}
this->type = (me_endpoint_type_t)type;
addr_family = AF_INET;
addr.len = 4;
switch(this->family)
{
case IPv6:
addr_family = AF_INET6;
addr.len = 16;
/* fall-through */
case IPv4:
if (parse_uint16(&cur, top, &port) != SUCCESS)
{
DBG1(DBG_IKE, "failed to parse ME_ENDPOINT: invalid port");
return FAILED;
}
if (cur + addr.len > top)
{
DBG1(DBG_IKE, "failed to parse ME_ENDPOINT: invalid IP address");
return FAILED;
}
addr.ptr = cur;
this->endpoint = host_create_from_chunk(addr_family, addr, port);
break;
case NO_FAMILY:
default:
this->endpoint = NULL;
break;
}
return SUCCESS;
}
/**
* Generates the notification data of a ME_ENDPOINT notify
*/
static chunk_t build_notification_data(private_endpoint_notify_t *this)
{
chunk_t prio_chunk, family_chunk, type_chunk, port_chunk, addr_chunk;
chunk_t data;
u_int32_t prio;
u_int16_t port;
u_int8_t family, type;
prio = htonl(this->priority);
prio_chunk = chunk_from_thing(prio);
family = this->family;
family_chunk = chunk_from_thing(family);
type = this->type;
type_chunk = chunk_from_thing(type);
if (this->endpoint)
{
port = htons(this->endpoint->get_port(this->endpoint));
addr_chunk = this->endpoint->get_address(this->endpoint);
}
else
{
port = 0;
addr_chunk = chunk_empty;
}
port_chunk = chunk_from_thing(port);
/* data = prio | family | type | port | addr */
data = chunk_cat("ccccc", prio_chunk, family_chunk, type_chunk,
port_chunk, addr_chunk);
DBG3(DBG_IKE, "me_endpoint_data %B", &data);
return data;
}
/**
* Implementation of endpoint_notify_t.build_notify
*/
static notify_payload_t *build_notify(private_endpoint_notify_t *this)
{
chunk_t data;
notify_payload_t *notify;
notify = notify_payload_create();
notify->set_notify_type(notify, ME_ENDPOINT);
data = build_notification_data(this);
notify->set_notification_data(notify, data);
chunk_free(&data);
return notify;
}
/**
* Implementation of endpoint_notify_t.get_priority.
*/
static u_int32_t get_priority(private_endpoint_notify_t *this)
{
return this->priority;
}
/**
* Implementation of endpoint_notify_t.set_priority.
*/
static void set_priority(private_endpoint_notify_t *this, u_int32_t priority)
{
this->priority = priority;
}
/**
* Implementation of endpoint_notify_t.get_type.
*/
static me_endpoint_type_t get_type(private_endpoint_notify_t *this)
{
return this->type;
}
/**
* Implementation of endpoint_notify_t.get_family.
*/
static me_endpoint_family_t get_family(private_endpoint_notify_t *this)
{
return this->family;
}
/**
* Implementation of endpoint_notify_t.get_host.
*/
static host_t *get_host(private_endpoint_notify_t *this)
{
return this->endpoint;
}
/**
* Implementation of endpoint_notify_t.get_base.
*/
static host_t *get_base(private_endpoint_notify_t *this)
{
return (!this->base) ? this->endpoint : this->base;
}
/**
* Implementation of endpoint_notify_t.clone.
*/
static endpoint_notify_t *_clone(private_endpoint_notify_t *this)
{
private_endpoint_notify_t *clone = (private_endpoint_notify_t*)endpoint_notify_create();
clone->priority = this->priority;
clone->type = this->type;
clone->family = this->family;
if (this->endpoint)
{
clone->endpoint = this->endpoint->clone(this->endpoint);
}
if (this->base)
{
clone->base = this->base->clone(this->base);
}
return &clone->public;
}
/**
* Implementation of endpoint_notify_t.destroy.
*/
static status_t destroy(private_endpoint_notify_t *this)
{
DESTROY_IF(this->endpoint);
DESTROY_IF(this->base);
free(this);
return SUCCESS;
}
/*
* Described in header
*/
endpoint_notify_t *endpoint_notify_create()
{
private_endpoint_notify_t *this = malloc_thing(private_endpoint_notify_t);
/* public functions */
this->public.get_priority = (u_int32_t (*) (endpoint_notify_t *)) get_priority;
this->public.set_priority = (void (*) (endpoint_notify_t *, u_int32_t)) set_priority;
this->public.get_type = (me_endpoint_type_t (*) (endpoint_notify_t *)) get_type;
this->public.get_family = (me_endpoint_family_t (*) (endpoint_notify_t *)) get_family;
this->public.get_host = (host_t *(*) (endpoint_notify_t *)) get_host;
this->public.get_base = (host_t *(*) (endpoint_notify_t *)) get_base;
this->public.build_notify = (notify_payload_t *(*) (endpoint_notify_t *)) build_notify;
this->public.clone = (endpoint_notify_t *(*) (endpoint_notify_t *)) _clone;
this->public.destroy = (void (*) (endpoint_notify_t *)) destroy;
/* set default values of the fields */
this->priority = 0;
this->family = NO_FAMILY;
this->type = NO_TYPE;
this->endpoint = NULL;
this->base = NULL;
return &this->public;
}
/**
* Described in header
*/
endpoint_notify_t *endpoint_notify_create_from_host(me_endpoint_type_t type, host_t *host, host_t *base)
{
private_endpoint_notify_t *this = (private_endpoint_notify_t*)endpoint_notify_create();
this->type = type;
switch(type)
{
case HOST:
this->priority = pow(2, 16) * ME_PRIO_HOST;
break;
case PEER_REFLEXIVE:
this->priority = pow(2, 16) * ME_PRIO_PEER;
break;
case SERVER_REFLEXIVE:
this->priority = pow(2, 16) * ME_PRIO_SERVER;
break;
case RELAYED:
default:
this->priority = pow(2, 16) * ME_PRIO_RELAY;
break;
}
/* FIXME: if there is more than one ip address we should vary this priority */
this->priority += 65535;
if (!host)
{
return &this->public;
}
switch(host->get_family(host))
{
case AF_INET:
this->family = IPv4;
break;
case AF_INET6:
this->family = IPv6;
break;
default:
/* unsupported family type, we do not set the host
* (family is set to NO_FAMILY) */
return &this->public;
}
this->endpoint = host->clone(host);
if (base)
{
this->base = base->clone(base);
}
return &this->public;
}
/**
* Described in header
*/
endpoint_notify_t *endpoint_notify_create_from_payload(notify_payload_t *notify)
{
if (notify->get_notify_type(notify) != ME_ENDPOINT)
{
return NULL;
}
private_endpoint_notify_t *this = (private_endpoint_notify_t*)endpoint_notify_create();
chunk_t data = notify->get_notification_data(notify);
if (parse_notification_data(this, data) != SUCCESS)
{
destroy(this);
return NULL;
}
return &this->public;
}
@@ -0,0 +1,173 @@
/*
* Copyright (C) 2007 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup endpoint_notify endpoint_notify
* @{ @ingroup payloads
*/
#ifndef ENDPOINT_NOTIFY_H_
#define ENDPOINT_NOTIFY_H_
#define ME_PRIO_HOST 255
#define ME_PRIO_PEER 128
#define ME_PRIO_SERVER 64
#define ME_PRIO_RELAY 0
typedef enum me_endpoint_family_t me_endpoint_family_t;
typedef enum me_endpoint_type_t me_endpoint_type_t;
typedef struct endpoint_notify_t endpoint_notify_t;
#include <encoding/payloads/notify_payload.h>
/**
* ME endpoint families.
*/
enum me_endpoint_family_t {
NO_FAMILY = 0,
IPv4 = 1,
IPv6 = 2,
MAX_FAMILY = 3
};
/**
* ME endpoint types.
*/
enum me_endpoint_type_t {
NO_TYPE = 0,
HOST = 1,
PEER_REFLEXIVE = 2,
SERVER_REFLEXIVE = 3,
RELAYED = 4,
MAX_TYPE = 5
};
/**
* enum name for me_endpoint_type_t.
*/
extern enum_name_t *me_endpoint_type_names;
/**
* Class representing a ME_ENDPOINT Notify payload. In fact it's not
* the notify per se, but the notification data of that notify that is
* handled with this class.
*/
struct endpoint_notify_t {
/**
* Returns the priority of this endpoint.
*
* @return priority
*/
u_int32_t (*get_priority) (endpoint_notify_t *this);
/**
* Sets the priority of this endpoint.
*
* @param priority priority
*/
void (*set_priority) (endpoint_notify_t *this, u_int32_t priority);
/**
* Returns the endpoint type of this endpoint.
*
* @return endpoint type
*/
me_endpoint_type_t (*get_type) (endpoint_notify_t *this);
/**
* Returns the endpoint family of this endpoint.
*
* @return endpoint family
*/
me_endpoint_family_t (*get_family) (endpoint_notify_t *this);
/**
* Returns the host of this endpoint.
*
* @return host
*/
host_t *(*get_host) (endpoint_notify_t *this);
/**
* Returns the base of this endpoint.
*
* If this is not a SERVER_REFLEXIVE endpoint, the returned host is the same
* as the one returned by get_host.
*
* @return host
*/
host_t *(*get_base) (endpoint_notify_t *this);
/**
* Generates a notification payload from this endpoint.
*
* @return built notify_payload_t
*/
notify_payload_t *(*build_notify) (endpoint_notify_t *this);
/**
* Clones an endpoint_notify_t object.
*
* @return cloned object
*/
endpoint_notify_t *(*clone) (endpoint_notify_t *this);
/**
* Destroys an endpoint_notify_t object.
*/
void (*destroy) (endpoint_notify_t *this);
};
/**
* Creates an empty endpoint_notify_t object.
*
* @return created endpoint_notify_t object
*/
endpoint_notify_t *endpoint_notify_create(void);
/**
* Creates an endpoint_notify_t object from a host.
*
* @param type the endpoint type
* @param host host to base the notify on (gets cloned)
* @param base base of the endpoint, applies only to reflexive endpoints (gets cloned)
* @return created endpoint_notify_t object
*/
endpoint_notify_t *endpoint_notify_create_from_host(me_endpoint_type_t type,
host_t *host, host_t *base);
/**
* Creates an endpoint_notify_t object from a notify payload.
*
* @param notify the notify payload
* @return - created endpoint_notify_t object
* - NULL if invalid payload
*/
endpoint_notify_t *endpoint_notify_create_from_payload(notify_payload_t *notify);
#endif /** ENDPOINT_NOTIFY_H_ @}*/
@@ -0,0 +1,293 @@
/*
* Copyright (C) 2007 Tobias Brunner
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
*
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <stddef.h>
#include "id_payload.h"
#include <daemon.h>
#include <encoding/payloads/encodings.h>
typedef struct private_id_payload_t private_id_payload_t;
/**
* Private data of an id_payload_t object.
*
*/
struct private_id_payload_t {
/**
* Public id_payload_t interface.
*/
id_payload_t public;
/**
* one of ID_INITIATOR, ID_RESPONDER
*/
payload_type_t payload_type;
/**
* Next payload type.
*/
u_int8_t next_payload;
/**
* Critical flag.
*/
bool critical;
/**
* Length of this payload.
*/
u_int16_t payload_length;
/**
* Type of the ID Data.
*/
u_int8_t id_type;
/**
* The contained id data value.
*/
chunk_t id_data;
};
/**
* Encoding rules to parse or generate a ID payload
*
* The defined offsets are the positions in a object of type
* private_id_payload_t.
*
*/
encoding_rule_t id_payload_encodings[] = {
/* 1 Byte next payload type, stored in the field next_payload */
{ U_INT_8, offsetof(private_id_payload_t, next_payload) },
/* the critical bit */
{ FLAG, offsetof(private_id_payload_t, critical) },
/* 7 Bit reserved bits, nowhere stored */
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
/* Length of the whole payload*/
{ PAYLOAD_LENGTH, offsetof(private_id_payload_t, payload_length) },
/* 1 Byte ID type*/
{ U_INT_8, offsetof(private_id_payload_t, id_type) },
/* 3 reserved bytes */
{ RESERVED_BYTE, 0 },
{ RESERVED_BYTE, 0 },
{ RESERVED_BYTE, 0 },
/* some id data bytes, length is defined in PAYLOAD_LENGTH */
{ ID_DATA, offsetof(private_id_payload_t, id_data) }
};
/*
1 2 3
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! Next Payload !C! RESERVED ! Payload Length !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! ID Type ! RESERVED |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! !
~ Identification Data ~
! !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
/**
* Implementation of payload_t.verify.
*/
static status_t verify(private_id_payload_t *this)
{
if ((this->id_type == 0) ||
(this->id_type == 4) ||
((this->id_type >= 6) && (this->id_type <= 8)) ||
((this->id_type >= 12) && (this->id_type <= 200)))
{
/* reserved IDs */
DBG1(DBG_ENC, "received ID with reserved type %d", this->id_type);
return FAILED;
}
return SUCCESS;
}
/**
* Implementation of id_payload_t.get_encoding_rules.
*/
static void get_encoding_rules(private_id_payload_t *this, encoding_rule_t **rules, size_t *rule_count)
{
*rules = id_payload_encodings;
*rule_count = sizeof(id_payload_encodings) / sizeof(encoding_rule_t);
}
/**
* Implementation of payload_t.get_type.
*/
static payload_type_t get_payload_type(private_id_payload_t *this)
{
return this->payload_type;
}
/**
* Implementation of payload_t.get_next_type.
*/
static payload_type_t get_next_type(private_id_payload_t *this)
{
return this->next_payload;
}
/**
* Implementation of payload_t.set_next_type.
*/
static void set_next_type(private_id_payload_t *this,payload_type_t type)
{
this->next_payload = type;
}
/**
* Implementation of payload_t.get_length.
*/
static size_t get_length(private_id_payload_t *this)
{
return this->payload_length;
}
/**
* Implementation of id_payload_t.set_type.
*/
static void set_id_type (private_id_payload_t *this, id_type_t type)
{
this->id_type = type;
}
/**
* Implementation of id_payload_t.get_id_type.
*/
static id_type_t get_id_type (private_id_payload_t *this)
{
return (this->id_type);
}
/**
* Implementation of id_payload_t.set_data.
*/
static void set_data (private_id_payload_t *this, chunk_t data)
{
if (this->id_data.ptr != NULL)
{
chunk_free(&(this->id_data));
}
this->id_data.ptr = clalloc(data.ptr,data.len);
this->id_data.len = data.len;
this->payload_length = ID_PAYLOAD_HEADER_LENGTH + this->id_data.len;
}
/**
* Implementation of id_payload_t.get_data_clone.
*/
static chunk_t get_data (private_id_payload_t *this)
{
return (this->id_data);
}
/**
* Implementation of id_payload_t.get_data_clone.
*/
static chunk_t get_data_clone (private_id_payload_t *this)
{
chunk_t cloned_data;
if (this->id_data.ptr == NULL)
{
return (this->id_data);
}
cloned_data.ptr = clalloc(this->id_data.ptr,this->id_data.len);
cloned_data.len = this->id_data.len;
return cloned_data;
}
/**
* Implementation of id_payload_t.get_identification.
*/
static identification_t *get_identification (private_id_payload_t *this)
{
return identification_create_from_encoding(this->id_type,this->id_data);
}
/**
* Implementation of payload_t.destroy and id_payload_t.destroy.
*/
static void destroy(private_id_payload_t *this)
{
if (this->id_data.ptr != NULL)
{
chunk_free(&(this->id_data));
}
free(this);
}
/*
* Described in header.
*/
id_payload_t *id_payload_create(payload_type_t payload_type)
{
private_id_payload_t *this = malloc_thing(private_id_payload_t);
/* interface functions */
this->public.payload_interface.verify = (status_t (*) (payload_t *))verify;
this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules;
this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length;
this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type;
this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type;
this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_payload_type;
this->public.payload_interface.destroy = (void (*) (payload_t *))destroy;
/* public functions */
this->public.destroy = (void (*) (id_payload_t *)) destroy;
this->public.set_id_type = (void (*) (id_payload_t *,id_type_t)) set_id_type;
this->public.get_id_type = (id_type_t (*) (id_payload_t *)) get_id_type;
this->public.set_data = (void (*) (id_payload_t *,chunk_t)) set_data;
this->public.get_data = (chunk_t (*) (id_payload_t *)) get_data;
this->public.get_data_clone = (chunk_t (*) (id_payload_t *)) get_data_clone;
this->public.get_identification = (identification_t * (*) (id_payload_t *this)) get_identification;
/* private variables */
this->critical = FALSE;
this->next_payload = NO_PAYLOAD;
this->payload_length =ID_PAYLOAD_HEADER_LENGTH;
this->id_data = chunk_empty;
this->payload_type = payload_type;
return (&(this->public));
}
/*
* Described in header.
*/
id_payload_t *id_payload_create_from_identification(payload_type_t payload_type, identification_t *identification)
{
id_payload_t *this= id_payload_create(payload_type);
this->set_data(this,identification->get_encoding(identification));
this->set_id_type(this,identification->get_type(identification));
return this;
}
@@ -0,0 +1,122 @@
/*
* Copyright (C) 2007 Tobias Brunner
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup id_payload id_payload
* @{ @ingroup payloads
*/
#ifndef ID_PAYLOAD_H_
#define ID_PAYLOAD_H_
typedef struct id_payload_t id_payload_t;
#include <library.h>
#include <utils/identification.h>
#include <encoding/payloads/payload.h>
/**
* Length of a id payload without the data in bytes.
*/
#define ID_PAYLOAD_HEADER_LENGTH 8
/**
* Object representing an IKEv2 ID payload.
*
* The ID payload format is described in RFC section 3.5.
*/
struct id_payload_t {
/**
* The payload_t interface.
*/
payload_t payload_interface;
/**
* Set the ID type.
*
* @param type Type of ID
*/
void (*set_id_type) (id_payload_t *this, id_type_t type);
/**
* Get the ID type.
*
* @return type of the ID
*/
id_type_t (*get_id_type) (id_payload_t *this);
/**
* Set the ID data.
*
* Data are getting cloned.
*
* @param data ID data as chunk_t
*/
void (*set_data) (id_payload_t *this, chunk_t data);
/**
* Get the ID data.
*
* Returned data are a copy of the internal one
*
* @return ID data as chunk_t
*/
chunk_t (*get_data_clone) (id_payload_t *this);
/**
* Get the ID data.
*
* Returned data are NOT copied.
*
* @return ID data as chunk_t
*/
chunk_t (*get_data) (id_payload_t *this);
/**
* Creates an identification object of this id payload.
*
* Returned object has to get destroyed by the caller.
*
* @return identification_t object
*/
identification_t *(*get_identification) (id_payload_t *this);
/**
* Destroys an id_payload_t object.
*/
void (*destroy) (id_payload_t *this);
};
/**
* Creates an empty id_payload_t object.
*
* @param payload_type one of ID_INITIATOR, ID_RESPONDER
* @return id_payload_t object
*/
id_payload_t *id_payload_create(payload_type_t payload_type);
/**
* Creates an id_payload_t from an existing identification_t object.
*
* @param payload_type one of ID_INITIATOR, ID_RESPONDER
* @param identification identification_t object
* @return id_payload_t object
*/
id_payload_t *id_payload_create_from_identification(payload_type_t payload_type,
identification_t *identification);
#endif /** ID_PAYLOAD_H_ @}*/
@@ -0,0 +1,415 @@
/*
* Copyright (C) 2007 Tobias Brunner
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/* offsetof macro */
#include <stddef.h>
#include "ike_header.h"
#include <encoding/payloads/encodings.h>
typedef struct private_ike_header_t private_ike_header_t;
/**
* Private data of an ike_header_t object.
*/
struct private_ike_header_t {
/**
* Public interface.
*/
ike_header_t public;
/**
* SPI of the initiator.
*/
u_int64_t initiator_spi;
/**
* SPI of the responder.
*/
u_int64_t responder_spi;
/**
* Next payload type.
*/
u_int8_t next_payload;
/**
* IKE major version.
*/
u_int8_t maj_version;
/**
* IKE minor version.
*/
u_int8_t min_version;
/**
* Exchange type .
*/
u_int8_t exchange_type;
/**
* Flags of the Message.
*/
struct {
/**
* Sender is initiator of the associated IKE_SA_INIT-Exchange.
*/
bool initiator;
/**
* Is protocol supporting higher version?
*/
bool version;
/**
* TRUE, if this is a response, FALSE if its a Request.
*/
bool response;
} flags;
/**
* Associated Message-ID.
*/
u_int32_t message_id;
/**
* Length of the whole IKEv2-Message (header and all payloads).
*/
u_int32_t length;
};
ENUM_BEGIN(exchange_type_names, EXCHANGE_TYPE_UNDEFINED, EXCHANGE_TYPE_UNDEFINED,
"EXCHANGE_TYPE_UNDEFINED");
ENUM_NEXT(exchange_type_names, IKE_SA_INIT, INFORMATIONAL, EXCHANGE_TYPE_UNDEFINED,
"IKE_SA_INIT",
"IKE_AUTH",
"CREATE_CHILD_SA",
"INFORMATIONAL");
#ifdef ME
ENUM_NEXT(exchange_type_names, ME_CONNECT, ME_CONNECT, INFORMATIONAL,
"ME_CONNECT");
ENUM_END(exchange_type_names, ME_CONNECT);
#else
ENUM_END(exchange_type_names, INFORMATIONAL);
#endif /* ME */
/**
* Encoding rules to parse or generate a IKEv2-Header.
*
* The defined offsets are the positions in a object of type
* ike_header_t.
*/
encoding_rule_t ike_header_encodings[] = {
/* 8 Byte SPI, stored in the field initiator_spi */
{ IKE_SPI, offsetof(private_ike_header_t, initiator_spi) },
/* 8 Byte SPI, stored in the field responder_spi */
{ IKE_SPI, offsetof(private_ike_header_t, responder_spi) },
/* 1 Byte next payload type, stored in the field next_payload */
{ U_INT_8, offsetof(private_ike_header_t, next_payload) },
/* 4 Bit major version, stored in the field maj_version */
{ U_INT_4, offsetof(private_ike_header_t, maj_version) },
/* 4 Bit minor version, stored in the field min_version */
{ U_INT_4, offsetof(private_ike_header_t, min_version) },
/* 8 Bit for the exchange type */
{ U_INT_8, offsetof(private_ike_header_t, exchange_type) },
/* 2 Bit reserved bits, nowhere stored */
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
/* 3 Bit flags, stored in the fields response, version and initiator */
{ FLAG, offsetof(private_ike_header_t, flags.response) },
{ FLAG, offsetof(private_ike_header_t, flags.version) },
{ FLAG, offsetof(private_ike_header_t, flags.initiator) },
/* 3 Bit reserved bits, nowhere stored */
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
/* 4 Byte message id, stored in the field message_id */
{ U_INT_32, offsetof(private_ike_header_t, message_id) },
/* 4 Byte length fied, stored in the field length */
{ HEADER_LENGTH, offsetof(private_ike_header_t, length) }
};
/* 1 2 3
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! IKE_SA Initiator's SPI !
! !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! IKE_SA Responder's SPI !
! !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! Next Payload ! MjVer ! MnVer ! Exchange Type ! Flags !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! Message ID !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! Length !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
/**
* Implementation of payload_t.verify.
*/
static status_t verify(private_ike_header_t *this)
{
if ((this->exchange_type < IKE_SA_INIT) ||
((this->exchange_type > INFORMATIONAL)
#ifdef ME
&& (this->exchange_type != ME_CONNECT)
#endif /* ME */
))
{
/* unsupported exchange type */
return FAILED;
}
if (this->initiator_spi == 0
#ifdef ME
/* we allow zero spi for INFORMATIONAL exchanges,
* to allow connectivity checks */
&& this->exchange_type != INFORMATIONAL
#endif /* ME */
)
{
/* initiator spi not set */
return FAILED;
}
/* verification of version is not done in here */
return SUCCESS;
}
/**
* Implementation of payload_t.set_next_type.
*/
static void set_next_type(payload_t *this,payload_type_t type)
{
((private_ike_header_t *)this)->next_payload = type;
}
/**
* Implementation of ike_header_t.get_initiator_spi.
*/
static u_int64_t get_initiator_spi(private_ike_header_t *this)
{
return this->initiator_spi;
}
/**
* Implementation of ike_header_t.set_initiator_spi.
*/
static void set_initiator_spi(private_ike_header_t *this, u_int64_t initiator_spi)
{
this->initiator_spi = initiator_spi;
}
/**
* Implementation of ike_header_t.get_responder_spi.
*/
static u_int64_t get_responder_spi(private_ike_header_t *this)
{
return this->responder_spi;
}
/**
* Implementation of ike_header_t.set_responder_spi.
*/
static void set_responder_spi(private_ike_header_t *this, u_int64_t responder_spi)
{
this->responder_spi = responder_spi;
}
/**
* Implementation of ike_header_t.get_maj_version.
*/
static u_int8_t get_maj_version(private_ike_header_t *this)
{
return this->maj_version;
}
/**
* Implementation of ike_header_t.get_min_version.
*/
static u_int8_t get_min_version(private_ike_header_t *this)
{
return this->min_version;
}
/**
* Implementation of ike_header_t.get_response_flag.
*/
static bool get_response_flag(private_ike_header_t *this)
{
return this->flags.response;
}
/**
* Implementation of ike_header_t.set_response_flag.
*/
static void set_response_flag(private_ike_header_t *this, bool response)
{
this->flags.response = response;
}
/**
* Implementation of ike_header_t.get_version_flag.
*/
static bool get_version_flag(private_ike_header_t *this)
{
return this->flags.version;
}
/**
* Implementation of ike_header_t.get_initiator_flag.
*/
static bool get_initiator_flag(private_ike_header_t *this)
{
return this->flags.initiator;
}
/**
* Implementation of ike_header_t.set_initiator_flag.
*/
static void set_initiator_flag(private_ike_header_t *this, bool initiator)
{
this->flags.initiator = initiator;
}
/**
* Implementation of ike_header_t.get_exchange_type.
*/
static u_int8_t get_exchange_type(private_ike_header_t *this)
{
return this->exchange_type;
}
/**
* Implementation of ike_header_t.set_exchange_type.
*/
static void set_exchange_type(private_ike_header_t *this, u_int8_t exchange_type)
{
this->exchange_type = exchange_type;
}
/**
* Implements ike_header_t's get_message_id function.
* See #ike_header_t.get_message_id for description.
*/
static u_int32_t get_message_id(private_ike_header_t *this)
{
return this->message_id;
}
/**
* Implementation of ike_header_t.set_message_id.
*/
static void set_message_id(private_ike_header_t *this, u_int32_t message_id)
{
this->message_id = message_id;
}
/**
* Implementation of ike_header_t.destroy and payload_t.destroy.
*/
static void destroy(ike_header_t *this)
{
free(this);
}
/**
* Implementation of payload_t.get_encoding_rules.
*/
static void get_encoding_rules(payload_t *this, encoding_rule_t **rules, size_t *rule_count)
{
*rules = ike_header_encodings;
*rule_count = sizeof(ike_header_encodings) / sizeof(encoding_rule_t);
}
/**
* Implementation of payload_t.get_type.
*/
static payload_type_t get_type(payload_t *this)
{
return HEADER;
}
/**
* Implementation of payload_t.get_next_type.
*/
static payload_type_t get_next_type(payload_t *this)
{
return (((private_ike_header_t*)this)->next_payload);
}
/**
* Implementation of payload_t.get_length.
*/
static size_t get_length(payload_t *this)
{
return (((private_ike_header_t*)this)->length);
}
/*
* Described in header.
*/
ike_header_t *ike_header_create()
{
private_ike_header_t *this = malloc_thing(private_ike_header_t);
this->public.payload_interface.verify = (status_t (*) (payload_t *))verify;
this->public.payload_interface.get_encoding_rules = get_encoding_rules;
this->public.payload_interface.get_length = get_length;
this->public.payload_interface.get_next_type = get_next_type;
this->public.payload_interface.set_next_type = set_next_type;
this->public.payload_interface.get_type = get_type;
this->public.payload_interface.destroy = (void (*) (payload_t *))destroy;
this->public.destroy = destroy;
this->public.get_initiator_spi = (u_int64_t (*) (ike_header_t*))get_initiator_spi;
this->public.set_initiator_spi = (void (*) (ike_header_t*,u_int64_t))set_initiator_spi;
this->public.get_responder_spi = (u_int64_t (*) (ike_header_t*))get_responder_spi;
this->public.set_responder_spi = (void (*) (ike_header_t *,u_int64_t))set_responder_spi;
this->public.get_maj_version = (u_int8_t (*) (ike_header_t*))get_maj_version;
this->public.get_min_version = (u_int8_t (*) (ike_header_t*))get_min_version;
this->public.get_response_flag = (bool (*) (ike_header_t*))get_response_flag;
this->public.set_response_flag = (void (*) (ike_header_t*,bool))set_response_flag;
this->public.get_version_flag = (bool (*) (ike_header_t*))get_version_flag;
this->public.get_initiator_flag = (bool (*) (ike_header_t*))get_initiator_flag;
this->public.set_initiator_flag = (void (*) (ike_header_t*,bool))set_initiator_flag;
this->public.get_exchange_type = (u_int8_t (*) (ike_header_t*))get_exchange_type;
this->public.set_exchange_type = (void (*) (ike_header_t*,u_int8_t))set_exchange_type;
this->public.get_message_id = (u_int32_t (*) (ike_header_t*))get_message_id;
this->public.set_message_id = (void (*) (ike_header_t*,u_int32_t))set_message_id;
/* set default values of the fields */
this->initiator_spi = 0;
this->responder_spi = 0;
this->next_payload = 0;
this->maj_version = IKE_MAJOR_VERSION;
this->min_version = IKE_MINOR_VERSION;
this->exchange_type = EXCHANGE_TYPE_UNDEFINED;
this->flags.initiator = TRUE;
this->flags.version = HIGHER_VERSION_SUPPORTED_FLAG;
this->flags.response = FALSE;
this->message_id = 0;
this->length = IKE_HEADER_LENGTH;
return (ike_header_t*)this;
}
@@ -0,0 +1,227 @@
/*
* Copyright (C) 2007 Tobias Brunner
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup ike_header ike_header
* @{ @ingroup payloads
*/
#ifndef IKE_HEADER_H_
#define IKE_HEADER_H_
typedef enum exchange_type_t exchange_type_t;
typedef struct ike_header_t ike_header_t;
#include <library.h>
#include <encoding/payloads/payload.h>
/**
* Major Version of IKEv2.
*/
#define IKE_MAJOR_VERSION 2
/**
* Minor Version of IKEv2.
*/
#define IKE_MINOR_VERSION 0
/**
* Flag in IKEv2-Header. Always 0.
*/
#define HIGHER_VERSION_SUPPORTED_FLAG 0
/**
* Length of IKE Header in Bytes.
*/
#define IKE_HEADER_LENGTH 28
/**
* Different types of IKE-Exchanges.
*
* See RFC for different types.
*/
enum exchange_type_t{
/**
* EXCHANGE_TYPE_UNDEFINED. In private space, since not a official message type.
*/
EXCHANGE_TYPE_UNDEFINED = 255,
/**
* IKE_SA_INIT.
*/
IKE_SA_INIT = 34,
/**
* IKE_AUTH.
*/
IKE_AUTH = 35,
/**
* CREATE_CHILD_SA.
*/
CREATE_CHILD_SA = 36,
/**
* INFORMATIONAL.
*/
INFORMATIONAL = 37,
#ifdef ME
/**
* ME_CONNECT
*/
ME_CONNECT = 240
#endif /* ME */
};
/**
* enum name for exchange_type_t
*/
extern enum_name_t *exchange_type_names;
/**
* An object of this type represents an IKEv2 header and is used to
* generate and parse IKEv2 headers.
*
* The header format of an IKEv2-Message is compatible to the
* ISAKMP-Header format to allow implementations supporting
* both versions of the IKE-protocol.
*/
struct ike_header_t {
/**
* The payload_t interface.
*/
payload_t payload_interface;
/**
* Get the initiator spi.
*
* @return initiator_spi
*/
u_int64_t (*get_initiator_spi) (ike_header_t *this);
/**
* Set the initiator spi.
*
* @param initiator_spi initiator_spi
*/
void (*set_initiator_spi) (ike_header_t *this, u_int64_t initiator_spi);
/**
* Get the responder spi.
*
* @return responder_spi
*/
u_int64_t (*get_responder_spi) (ike_header_t *this);
/**
* Set the responder spi.
*
* @param responder_spi responder_spi
*/
void (*set_responder_spi) (ike_header_t *this, u_int64_t responder_spi);
/**
* Get the major version.
*
* @return major version
*/
u_int8_t (*get_maj_version) (ike_header_t *this);
/**
* Get the minor version.
*
* @return minor version
*/
u_int8_t (*get_min_version) (ike_header_t *this);
/**
* Get the response flag.
*
* @return response flag
*/
bool (*get_response_flag) (ike_header_t *this);
/**
* Set the response flag-
*
* @param response response flag
*/
void (*set_response_flag) (ike_header_t *this, bool response);
/**
* Get "higher version supported"-flag.
*
* @return version flag
*/
bool (*get_version_flag) (ike_header_t *this);
/**
* Get the initiator flag.
*
* @return initiator flag
*/
bool (*get_initiator_flag) (ike_header_t *this);
/**
* Set the initiator flag.
*
* @param initiator initiator flag
*/
void (*set_initiator_flag) (ike_header_t *this, bool initiator);
/**
* Get the exchange type.
*
* @return exchange type
*/
u_int8_t (*get_exchange_type) (ike_header_t *this);
/**
* Set the exchange type.
*
* @param exchange_type exchange type
*/
void (*set_exchange_type) (ike_header_t *this, u_int8_t exchange_type);
/**
* Get the message id.
*
* @return message id
*/
u_int32_t (*get_message_id) (ike_header_t *this);
/**
* Set the message id.
*
* @param initiator_spi message id
*/
void (*set_message_id) (ike_header_t *this, u_int32_t message_id);
/**
* Destroys a ike_header_t object.
*/
void (*destroy) (ike_header_t *this);
};
/**
* Create an ike_header_t object
*
* @return ike_header_t object
*/
ike_header_t *ike_header_create(void);
#endif /** IKE_HEADER_H_ @}*/
@@ -0,0 +1,270 @@
/*
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <stddef.h>
#include "ke_payload.h"
#include <encoding/payloads/encodings.h>
typedef struct private_ke_payload_t private_ke_payload_t;
/**
* Private data of an ke_payload_t object.
*
*/
struct private_ke_payload_t {
/**
* Public ke_payload_t interface.
*/
ke_payload_t public;
/**
* Next payload type.
*/
u_int8_t next_payload;
/**
* Critical flag.
*/
bool critical;
/**
* Length of this payload.
*/
u_int16_t payload_length;
/**
* DH Group Number.
*/
u_int16_t dh_group_number;
/**
* Key Exchange Data of this KE payload.
*/
chunk_t key_exchange_data;
};
/**
* Encoding rules to parse or generate a IKEv2-KE Payload.
*
* The defined offsets are the positions in a object of type
* private_ke_payload_t.
*
*/
encoding_rule_t ke_payload_encodings[] = {
/* 1 Byte next payload type, stored in the field next_payload */
{ U_INT_8, offsetof(private_ke_payload_t, next_payload) },
/* the critical bit */
{ FLAG, offsetof(private_ke_payload_t, critical) },
/* 7 Bit reserved bits, nowhere stored */
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
/* Length of the whole payload*/
{ PAYLOAD_LENGTH, offsetof(private_ke_payload_t, payload_length) },
/* DH Group number as 16 bit field*/
{ U_INT_16, offsetof(private_ke_payload_t, dh_group_number) },
{ RESERVED_BYTE, 0 },
{ RESERVED_BYTE, 0 },
/* Key Exchange Data is from variable size */
{ KEY_EXCHANGE_DATA, offsetof(private_ke_payload_t, key_exchange_data)}
};
/*
1 2 3
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! Next Payload !C! RESERVED ! Payload Length !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! DH Group # ! RESERVED !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! !
~ Key Exchange Data ~
! !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
/**
* Implementation of payload_t.verify.
*/
static status_t verify(private_ke_payload_t *this)
{
/* dh group is not verified in here */
return SUCCESS;
}
/**
* Implementation of payload_t.destroy.
*/
static void destroy(private_ke_payload_t *this)
{
if (this->key_exchange_data.ptr != NULL)
{
free(this->key_exchange_data.ptr);
}
free(this);
}
/**
* Implementation of payload_t.get_encoding_rules.
*/
static void get_encoding_rules(private_ke_payload_t *this, encoding_rule_t **rules, size_t *rule_count)
{
*rules = ke_payload_encodings;
*rule_count = sizeof(ke_payload_encodings) / sizeof(encoding_rule_t);
}
/**
* Implementation of payload_t.get_type.
*/
static payload_type_t get_type(private_ke_payload_t *this)
{
return KEY_EXCHANGE;
}
/**
* Implementation of payload_t.get_next_type.
*/
static payload_type_t get_next_type(private_ke_payload_t *this)
{
return (this->next_payload);
}
/**
* Implementation of payload_t.set_next_type.
*/
static void set_next_type(private_ke_payload_t *this,payload_type_t type)
{
this->next_payload = type;
}
/**
* recompute the length of the payload.
*/
static void compute_length(private_ke_payload_t *this)
{
size_t length = KE_PAYLOAD_HEADER_LENGTH;
if (this->key_exchange_data.ptr != NULL)
{
length += this->key_exchange_data.len;
}
this->payload_length = length;
}
/**
* Implementation of payload_t.get_length.
*/
static size_t get_length(private_ke_payload_t *this)
{
compute_length(this);
return this->payload_length;
}
/**
* Implementation of ke_payload_t.get_key_exchange_data.
*/
static chunk_t get_key_exchange_data(private_ke_payload_t *this)
{
return (this->key_exchange_data);
}
/**
* Implementation of ke_payload_t.set_key_exchange_data.
*/
static void set_key_exchange_data(private_ke_payload_t *this, chunk_t key_exchange_data)
{
/* destroy existing data first */
if (this->key_exchange_data.ptr != NULL)
{
/* free existing value */
free(this->key_exchange_data.ptr);
this->key_exchange_data.ptr = NULL;
this->key_exchange_data.len = 0;
}
this->key_exchange_data = chunk_clone(key_exchange_data);
compute_length(this);
}
/**
* Implementation of ke_payload_t.get_dh_group_number.
*/
static diffie_hellman_group_t get_dh_group_number(private_ke_payload_t *this)
{
return this->dh_group_number;
}
/**
* Implementation of ke_payload_t.set_dh_group_number.
*/
static void set_dh_group_number(private_ke_payload_t *this, diffie_hellman_group_t dh_group_number)
{
this->dh_group_number = dh_group_number;
}
/*
* Described in header
*/
ke_payload_t *ke_payload_create()
{
private_ke_payload_t *this = malloc_thing(private_ke_payload_t);
/* interface functions */
this->public.payload_interface.verify = (status_t (*) (payload_t *))verify;
this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules;
this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length;
this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type;
this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type;
this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_type;
this->public.payload_interface.destroy = (void (*) (payload_t *))destroy;
/* public functions */
this->public.get_key_exchange_data = (chunk_t (*) (ke_payload_t *)) get_key_exchange_data;
this->public.set_key_exchange_data = (void (*) (ke_payload_t *,chunk_t)) set_key_exchange_data;
this->public.get_dh_group_number = (diffie_hellman_group_t (*) (ke_payload_t *)) get_dh_group_number;
this->public.set_dh_group_number =(void (*) (ke_payload_t *,diffie_hellman_group_t)) set_dh_group_number;
this->public.destroy = (void (*) (ke_payload_t *)) destroy;
/* set default values of the fields */
this->critical = FALSE;
this->next_payload = NO_PAYLOAD;
this->payload_length = KE_PAYLOAD_HEADER_LENGTH;
this->key_exchange_data = chunk_empty;
this->dh_group_number = MODP_NONE;
return &this->public;
}
/*
* Described in header
*/
ke_payload_t *ke_payload_create_from_diffie_hellman(diffie_hellman_t *dh)
{
private_ke_payload_t *this = (private_ke_payload_t*)ke_payload_create();
dh->get_my_public_value(dh, &this->key_exchange_data);
this->dh_group_number = dh->get_dh_group(dh);
compute_length(this);
return &this->public;
}
@@ -0,0 +1,104 @@
/*
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup ke_payload ke_payload
* @{ @ingroup payloads
*/
#ifndef KE_PAYLOAD_H_
#define KE_PAYLOAD_H_
typedef struct ke_payload_t ke_payload_t;
#include <library.h>
#include <encoding/payloads/payload.h>
#include <encoding/payloads/transform_substructure.h>
#include <utils/linked_list.h>
#include <crypto/diffie_hellman.h>
/**
* KE payload length in bytes without any key exchange data.
*/
#define KE_PAYLOAD_HEADER_LENGTH 8
/**
* Class representing an IKEv2-KE Payload.
*
* The KE Payload format is described in RFC section 3.4.
*/
struct ke_payload_t {
/**
* The payload_t interface.
*/
payload_t payload_interface;
/**
* Returns the currently set key exchange data of this KE payload.
*
* @warning Returned data are not copied.
*
* @return chunk_t pointing to the value
*/
chunk_t (*get_key_exchange_data) (ke_payload_t *this);
/**
* Sets the key exchange data of this KE payload.
*
* Value is getting copied.
*
* @param key_exchange_data chunk_t pointing to the value to set
*/
void (*set_key_exchange_data) (ke_payload_t *this, chunk_t key_exchange_data);
/**
* Gets the Diffie-Hellman Group Number of this KE payload.
*
* @return DH Group Number of this payload
*/
diffie_hellman_group_t (*get_dh_group_number) (ke_payload_t *this);
/**
* Sets the Diffie-Hellman Group Number of this KE payload.
*
* @param dh_group_number DH Group to set
*/
void (*set_dh_group_number) (ke_payload_t *this,
diffie_hellman_group_t dh_group_number);
/**
* Destroys an ke_payload_t object.
*/
void (*destroy) (ke_payload_t *this);
};
/**
* Creates an empty ke_payload_t object
*
* @return ke_payload_t object
*/
ke_payload_t *ke_payload_create(void);
/**
* Creates a ke_payload_t from a diffie_hellman_t
*
* @param diffie_hellman diffie hellman object containing group and key
* @return ke_payload_t object
*/
ke_payload_t *ke_payload_create_from_diffie_hellman(
diffie_hellman_t *diffie_hellman);
#endif /** KE_PAYLOAD_H_ @}*/
@@ -0,0 +1,225 @@
/*
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/* offsetof macro */
#include <stddef.h>
#include "nonce_payload.h"
#include <encoding/payloads/encodings.h>
typedef struct private_nonce_payload_t private_nonce_payload_t;
/**
* Private data of an nonce_payload_t object.
*
*/
struct private_nonce_payload_t {
/**
* Public nonce_payload_t interface.
*/
nonce_payload_t public;
/**
* Next payload type.
*/
u_int8_t next_payload;
/**
* Critical flag.
*/
bool critical;
/**
* Length of this payload.
*/
u_int16_t payload_length;
/**
* The contained nonce value.
*/
chunk_t nonce;
};
/**
* Encoding rules to parse or generate a nonce payload
*
* The defined offsets are the positions in a object of type
* private_nonce_payload_t.
*
*/
encoding_rule_t nonce_payload_encodings[] = {
/* 1 Byte next payload type, stored in the field next_payload */
{ U_INT_8, offsetof(private_nonce_payload_t, next_payload) },
/* the critical bit */
{ FLAG, offsetof(private_nonce_payload_t, critical) },
/* 7 Bit reserved bits, nowhere stored */
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
/* Length of the whole nonce payload*/
{ PAYLOAD_LENGTH, offsetof(private_nonce_payload_t, payload_length) },
/* some nonce bytes, lenth is defined in PAYLOAD_LENGTH */
{ NONCE_DATA, offsetof(private_nonce_payload_t, nonce) }
};
/* 1 2 3
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! Next Payload !C! RESERVED ! Payload Length !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! !
~ Nonce Data ~
! !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
/**
* Implementation of payload_t.verify.
*/
static status_t verify(private_nonce_payload_t *this)
{
if ((this->nonce.len < 16) || ((this->nonce.len > 256)))
{
/* nonce length is wrong */
return FAILED;
}
return SUCCESS;
}
/**
* Implementation of nonce_payload_t.set_nonce.
*/
static status_t set_nonce(private_nonce_payload_t *this, chunk_t nonce)
{
this->nonce.ptr = clalloc(nonce.ptr, nonce.len);
this->nonce.len = nonce.len;
this->payload_length = NONCE_PAYLOAD_HEADER_LENGTH + nonce.len;
return SUCCESS;
}
/**
* Implementation of nonce_payload_t.get_nonce.
*/
static chunk_t get_nonce(private_nonce_payload_t *this)
{
chunk_t nonce;
nonce.ptr = clalloc(this->nonce.ptr,this->nonce.len);
nonce.len = this->nonce.len;
return nonce;
}
/**
* Implementation of nonce_payload_t.get_encoding_rules.
*/
static void get_encoding_rules(private_nonce_payload_t *this, encoding_rule_t **rules, size_t *rule_count)
{
*rules = nonce_payload_encodings;
*rule_count = sizeof(nonce_payload_encodings) / sizeof(encoding_rule_t);
}
/**
* Implementation of payload_t.get_type.
*/
static payload_type_t get_type(private_nonce_payload_t *this)
{
return NONCE;
}
/**
* Implementation of payload_t.get_next_type.
*/
static payload_type_t get_next_type(private_nonce_payload_t *this)
{
return (this->next_payload);
}
/**
* Implementation of payload_t.set_next_type.
*/
static void set_next_type(private_nonce_payload_t *this,payload_type_t type)
{
this->next_payload = type;
}
/**
* recompute the length of the payload.
*/
static void compute_length(private_nonce_payload_t *this)
{
this->payload_length = NONCE_PAYLOAD_HEADER_LENGTH + this->nonce.len;
}
/**
* Implementation of payload_t.get_length.
*/
static size_t get_length(private_nonce_payload_t *this)
{
compute_length(this);
return this->payload_length;
}
/**
* Implementation of payload_t.destroy and nonce_payload_t.destroy.
*/
static void destroy(private_nonce_payload_t *this)
{
if (this->nonce.ptr != NULL)
{
free(this->nonce.ptr);
}
free(this);
}
/*
* Described in header
*/
nonce_payload_t *nonce_payload_create()
{
private_nonce_payload_t *this = malloc_thing(private_nonce_payload_t);
/* interface functions */
this->public.payload_interface.verify = (status_t (*) (payload_t *))verify;
this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules;
this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length;
this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type;
this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type;
this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_type;
this->public.payload_interface.destroy = (void (*) (payload_t *))destroy;
/* public functions */
this->public.destroy = (void (*) (nonce_payload_t *)) destroy;
this->public.set_nonce = (void (*) (nonce_payload_t *,chunk_t)) set_nonce;
this->public.get_nonce = (chunk_t (*) (nonce_payload_t *)) get_nonce;
/* private variables */
this->critical = FALSE;
this->next_payload = NO_PAYLOAD;
this->payload_length = NONCE_PAYLOAD_HEADER_LENGTH;
this->nonce.ptr = NULL;
this->nonce.len = 0;
return (&(this->public));
}
@@ -0,0 +1,78 @@
/*
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup nonce_payload nonce_payload
* @{ @ingroup payloads
*/
#ifndef NONCE_PAYLOAD_H_
#define NONCE_PAYLOAD_H_
typedef struct nonce_payload_t nonce_payload_t;
#include <library.h>
#include <encoding/payloads/payload.h>
/**
* Nonce size in bytes for nonces sending to other peer.
*/
#define NONCE_SIZE 32
/**
* Length of a nonce payload without a nonce in bytes.
*/
#define NONCE_PAYLOAD_HEADER_LENGTH 4
/**
* Object representing an IKEv2 Nonce payload.
*
* The Nonce payload format is described in RFC section 3.3.
*/
struct nonce_payload_t {
/**
* The payload_t interface.
*/
payload_t payload_interface;
/**
* Set the nonce value.
*
* @param nonce chunk containing the nonce, will be cloned
*/
void (*set_nonce) (nonce_payload_t *this, chunk_t nonce);
/**
* Get the nonce value.
*
* @return a chunk containing the cloned nonce
*/
chunk_t (*get_nonce) (nonce_payload_t *this);
/**
* Destroys an nonce_payload_t object.
*/
void (*destroy) (nonce_payload_t *this);
};
/**
* Creates an empty nonce_payload_t object
*
* @return nonce_payload_t object
*/
nonce_payload_t *nonce_payload_create(void);
#endif /** NONCE_PAYLOAD_H_ @}*/
@@ -0,0 +1,617 @@
/*
* Copyright (C) 2006-2008 Tobias Brunner
* Copyright (C) 2006 Daniel Roethlisberger
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <stddef.h>
#include "notify_payload.h"
#include <daemon.h>
#include <encoding/payloads/encodings.h>
#include <crypto/hashers/hasher.h>
ENUM_BEGIN(notify_type_names, UNSUPPORTED_CRITICAL_PAYLOAD, UNSUPPORTED_CRITICAL_PAYLOAD,
"UNSUPPORTED_CRITICAL_PAYLOAD");
ENUM_NEXT(notify_type_names, INVALID_IKE_SPI, INVALID_MAJOR_VERSION, UNSUPPORTED_CRITICAL_PAYLOAD,
"INVALID_IKE_SPI",
"INVALID_MAJOR_VERSION");
ENUM_NEXT(notify_type_names, INVALID_SYNTAX, INVALID_SYNTAX, INVALID_MAJOR_VERSION,
"INVALID_SYNTAX");
ENUM_NEXT(notify_type_names, INVALID_MESSAGE_ID, INVALID_MESSAGE_ID, INVALID_SYNTAX,
"INVALID_MESSAGE_ID");
ENUM_NEXT(notify_type_names, INVALID_SPI, INVALID_SPI, INVALID_MESSAGE_ID,
"INVALID_SPI");
ENUM_NEXT(notify_type_names, NO_PROPOSAL_CHOSEN, NO_PROPOSAL_CHOSEN, INVALID_SPI,
"NO_PROPOSAL_CHOSEN");
ENUM_NEXT(notify_type_names, INVALID_KE_PAYLOAD, INVALID_KE_PAYLOAD, NO_PROPOSAL_CHOSEN,
"INVALID_KE_PAYLOAD");
ENUM_NEXT(notify_type_names, AUTHENTICATION_FAILED, AUTHENTICATION_FAILED, INVALID_KE_PAYLOAD,
"AUTHENTICATION_FAILED");
ENUM_NEXT(notify_type_names, SINGLE_PAIR_REQUIRED, USE_ASSIGNED_HoA, AUTHENTICATION_FAILED,
"SINGLE_PAIR_REQUIRED",
"NO_ADDITIONAL_SAS",
"INTERNAL_ADDRESS_FAILURE",
"FAILED_CP_REQUIRED",
"TS_UNACCEPTABLE",
"INVALID_SELECTORS",
"UNACCEPTABLE_ADDRESSES",
"UNEXPECTED_NAT_DETECTED",
"USE_ASSIGNED_HoA");
ENUM_NEXT(notify_type_names, ME_CONNECT_FAILED, ME_CONNECT_FAILED, USE_ASSIGNED_HoA,
"ME_CONNECT_FAILED");
ENUM_NEXT(notify_type_names, INITIAL_CONTACT, LINK_ID, ME_CONNECT_FAILED,
"INITIAL_CONTACT",
"SET_WINDOW_SIZE",
"ADDITIONAL_TS_POSSIBLE",
"IPCOMP_SUPPORTED",
"NAT_DETECTION_SOURCE_IP",
"NAT_DETECTION_DESTINATION_IP",
"COOKIE",
"USE_TRANSPORT_MODE",
"HTTP_CERT_LOOKUP_SUPPORTED",
"REKEY_SA",
"ESP_TFC_PADDING_NOT_SUPPORTED",
"NON_FIRST_FRAGMENTS_ALSO",
"MOBIKE_SUPPORTED",
"ADDITIONAL_IP4_ADDRESS",
"ADDITIONAL_IP6_ADDRESS",
"NO_ADDITIONAL_ADDRESSES",
"UPDATE_SA_ADDRESSES",
"COOKIE2",
"NO_NATS_ALLOWED",
"AUTH_LIFETIME",
"MULTIPLE_AUTH_SUPPORTED",
"ANOTHER_AUTH_FOLLOWS",
"REDIRECT_SUPPORTED",
"REDIRECT",
"REDIRECTED_FROM",
"TICKET_LT_OPAQUE",
"TICKET_REQUEST",
"TICKET_ACK",
"TICKET_NACK",
"TICKET_OPAQUE",
"LINK_ID");
ENUM_NEXT(notify_type_names, EAP_ONLY_AUTHENTICATION, EAP_ONLY_AUTHENTICATION, LINK_ID,
"EAP_ONLY_AUTHENTICATION");
ENUM_NEXT(notify_type_names, USE_BEET_MODE, USE_BEET_MODE, EAP_ONLY_AUTHENTICATION,
"USE_BEET_MODE");
ENUM_NEXT(notify_type_names, ME_MEDIATION, ME_RESPONSE, USE_BEET_MODE,
"ME_MEDIATION",
"ME_ENDPOINT",
"ME_CALLBACK",
"ME_CONNECTID",
"ME_CONNECTKEY",
"ME_CONNECTAUTH",
"ME_RESPONSE");
ENUM_END(notify_type_names, ME_RESPONSE);
ENUM_BEGIN(notify_type_short_names, UNSUPPORTED_CRITICAL_PAYLOAD, UNSUPPORTED_CRITICAL_PAYLOAD,
"CRIT");
ENUM_NEXT(notify_type_short_names, INVALID_IKE_SPI, INVALID_MAJOR_VERSION, UNSUPPORTED_CRITICAL_PAYLOAD,
"INVAL_IKE_SPI",
"INVAL_MAJOR");
ENUM_NEXT(notify_type_short_names, INVALID_SYNTAX, INVALID_SYNTAX, INVALID_MAJOR_VERSION,
"INVAL_SYN");
ENUM_NEXT(notify_type_short_names, INVALID_MESSAGE_ID, INVALID_MESSAGE_ID, INVALID_SYNTAX,
"INVAL_MID");
ENUM_NEXT(notify_type_short_names, INVALID_SPI, INVALID_SPI, INVALID_MESSAGE_ID,
"INVAL_SPI");
ENUM_NEXT(notify_type_short_names, NO_PROPOSAL_CHOSEN, NO_PROPOSAL_CHOSEN, INVALID_SPI,
"NO_PROP");
ENUM_NEXT(notify_type_short_names, INVALID_KE_PAYLOAD, INVALID_KE_PAYLOAD, NO_PROPOSAL_CHOSEN,
"INVAL_KE");
ENUM_NEXT(notify_type_short_names, AUTHENTICATION_FAILED, AUTHENTICATION_FAILED, INVALID_KE_PAYLOAD,
"AUTH_FAILED");
ENUM_NEXT(notify_type_short_names, SINGLE_PAIR_REQUIRED, USE_ASSIGNED_HoA, AUTHENTICATION_FAILED,
"SINGLE_PAIR",
"NO_ADD_SAS",
"INT_ADDR_FAIL",
"FAIL_CP_REQ",
"TS_UNACCEPT",
"INVAL_SEL",
"UNACCEPT_ADDR",
"UNEXPECT_NAT",
"ASSIGNED_HoA");
ENUM_NEXT(notify_type_short_names, ME_CONNECT_FAILED, ME_CONNECT_FAILED, USE_ASSIGNED_HoA,
"ME_CONN_FAIL");
ENUM_NEXT(notify_type_short_names, INITIAL_CONTACT, LINK_ID, ME_CONNECT_FAILED,
"INIT_CONTACT",
"SET_WINSIZE",
"ADD_TS_POSS",
"IPCOMP_SUPP",
"NATD_S_IP",
"NATD_D_IP",
"COOKIE",
"USE_TRANSP",
"HTTP_CERT_LOOK",
"REKEY_SA",
"ESP_TFC_PAD_N",
"NON_FIRST_FRAG",
"MOBIKE_SUP",
"ADD_4_ADDR",
"ADD_6_ADDR",
"NO_ADD_ADDR",
"UPD_SA_ADDR",
"COOKIE2",
"NO_NATS",
"AUTH_LFT",
"MULT_AUTH",
"AUTH_FOLLOWS",
"REDIR_SUP",
"REDIR",
"REDIR_FROM",
"TKT_LT_OPAK",
"TKT_REQ",
"TKT_ACK",
"TKT_NACK",
"TKT_OPAK",
"LINK_ID");
ENUM_NEXT(notify_type_short_names, EAP_ONLY_AUTHENTICATION, EAP_ONLY_AUTHENTICATION, LINK_ID,
"EAP_ONLY");
ENUM_NEXT(notify_type_short_names, USE_BEET_MODE, USE_BEET_MODE, EAP_ONLY_AUTHENTICATION,
"BEET_MODE");
ENUM_NEXT(notify_type_short_names, ME_MEDIATION, ME_RESPONSE, USE_BEET_MODE,
"ME_MED",
"ME_EP",
"ME_CB",
"ME_CID",
"ME_CKEY",
"ME_CAUTH",
"ME_R");
ENUM_END(notify_type_short_names, ME_RESPONSE);
typedef struct private_notify_payload_t private_notify_payload_t;
/**
* Private data of an notify_payload_t object.
*
*/
struct private_notify_payload_t {
/**
* Public notify_payload_t interface.
*/
notify_payload_t public;
/**
* Next payload type.
*/
u_int8_t next_payload;
/**
* Critical flag.
*/
bool critical;
/**
* Length of this payload.
*/
u_int16_t payload_length;
/**
* Protocol id.
*/
u_int8_t protocol_id;
/**
* Spi size.
*/
u_int8_t spi_size;
/**
* Notify message type.
*/
u_int16_t notify_type;
/**
* Security parameter index (spi).
*/
chunk_t spi;
/**
* Notification data.
*/
chunk_t notification_data;
};
/**
* Encoding rules to parse or generate a IKEv2-Notify Payload.
*
* The defined offsets are the positions in a object of type
* private_notify_payload_t.
*
*/
encoding_rule_t notify_payload_encodings[] = {
/* 1 Byte next payload type, stored in the field next_payload */
{ U_INT_8, offsetof(private_notify_payload_t, next_payload) },
/* the critical bit */
{ FLAG, offsetof(private_notify_payload_t, critical) },
/* 7 Bit reserved bits, nowhere stored */
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
/* Length of the whole payload*/
{ PAYLOAD_LENGTH, offsetof(private_notify_payload_t, payload_length) },
/* Protocol ID as 8 bit field*/
{ U_INT_8, offsetof(private_notify_payload_t, protocol_id) },
/* SPI Size as 8 bit field*/
{ SPI_SIZE, offsetof(private_notify_payload_t, spi_size) },
/* Notify message type as 16 bit field*/
{ U_INT_16, offsetof(private_notify_payload_t, notify_type) },
/* SPI as variable length field*/
{ SPI, offsetof(private_notify_payload_t, spi) },
/* Key Exchange Data is from variable size */
{ NOTIFICATION_DATA, offsetof(private_notify_payload_t, notification_data) }
};
/*
1 2 3
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! Next Payload !C! RESERVED ! Payload Length !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! Protocol ID ! SPI Size ! Notify Message Type !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! !
~ Security Parameter Index (SPI) ~
! !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! !
~ Notification Data ~
! !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
/**
* Implementation of payload_t.verify.
*/
static status_t verify(private_notify_payload_t *this)
{
bool bad_length = FALSE;
switch (this->protocol_id)
{
case PROTO_NONE:
case PROTO_IKE:
case PROTO_AH:
case PROTO_ESP:
break;
default:
DBG1(DBG_ENC, "Unknown protocol (%d)", this->protocol_id);
return FAILED;
}
switch (this->notify_type)
{
case INVALID_KE_PAYLOAD:
{
if (this->notification_data.len != 2)
{
bad_length = TRUE;
}
break;
}
case NAT_DETECTION_SOURCE_IP:
case NAT_DETECTION_DESTINATION_IP:
case ME_CONNECTAUTH:
{
if (this->notification_data.len != HASH_SIZE_SHA1)
{
bad_length = TRUE;
}
break;
}
case INVALID_SYNTAX:
case INVALID_MAJOR_VERSION:
case NO_PROPOSAL_CHOSEN:
{
if (this->notification_data.len != 0)
{
bad_length = TRUE;
}
break;
}
case ADDITIONAL_IP4_ADDRESS:
{
if (this->notification_data.len != 4)
{
bad_length = TRUE;
}
break;
}
case ADDITIONAL_IP6_ADDRESS:
{
if (this->notification_data.len != 16)
{
bad_length = TRUE;
}
break;
}
case AUTH_LIFETIME:
{
if (this->notification_data.len != 4)
{
bad_length = TRUE;
}
break;
}
case IPCOMP_SUPPORTED:
{
if (this->notification_data.len != 3)
{
bad_length = TRUE;
}
break;
}
case ME_ENDPOINT:
if (this->notification_data.len != 8 &&
this->notification_data.len != 12 &&
this->notification_data.len != 24)
{
bad_length = TRUE;
}
break;
case ME_CONNECTID:
if (this->notification_data.len < 4 ||
this->notification_data.len > 16)
{
bad_length = TRUE;
}
break;
case ME_CONNECTKEY:
if (this->notification_data.len < 16 ||
this->notification_data.len > 32)
{
bad_length = TRUE;
}
break;
default:
/* TODO: verify */
break;
}
if (bad_length)
{
DBG1(DBG_ENC, "invalid notify data length for %N (%d)",
notify_type_names, this->notify_type,
this->notification_data.len);
return FAILED;
}
return SUCCESS;
}
/**
* Implementation of payload_t.get_encoding_rules.
*/
static void get_encoding_rules(private_notify_payload_t *this, encoding_rule_t **rules, size_t *rule_count)
{
*rules = notify_payload_encodings;
*rule_count = sizeof(notify_payload_encodings) / sizeof(encoding_rule_t);
}
/**
* Implementation of payload_t.get_type.
*/
static payload_type_t get_type(private_notify_payload_t *this)
{
return NOTIFY;
}
/**
* Implementation of payload_t.get_next_type.
*/
static payload_type_t get_next_type(private_notify_payload_t *this)
{
return (this->next_payload);
}
/**
* Implementation of payload_t.set_next_type.
*/
static void set_next_type(private_notify_payload_t *this,payload_type_t type)
{
this->next_payload = type;
}
/**
* recompute the payloads length.
*/
static void compute_length (private_notify_payload_t *this)
{
size_t length = NOTIFY_PAYLOAD_HEADER_LENGTH;
if (this->notification_data.ptr != NULL)
{
length += this->notification_data.len;
}
if (this->spi.ptr != NULL)
{
length += this->spi.len;
}
this->payload_length = length;
}
/**
* Implementation of payload_t.get_length.
*/
static size_t get_length(private_notify_payload_t *this)
{
compute_length(this);
return this->payload_length;
}
/**
* Implementation of notify_payload_t.get_protocol_id.
*/
static u_int8_t get_protocol_id(private_notify_payload_t *this)
{
return this->protocol_id;
}
/**
* Implementation of notify_payload_t.set_protocol_id.
*/
static void set_protocol_id(private_notify_payload_t *this, u_int8_t protocol_id)
{
this->protocol_id = protocol_id;
}
/**
* Implementation of notify_payload_t.get_notify_type.
*/
static notify_type_t get_notify_type(private_notify_payload_t *this)
{
return this->notify_type;
}
/**
* Implementation of notify_payload_t.set_notify_type.
*/
static void set_notify_type(private_notify_payload_t *this, u_int16_t notify_type)
{
this->notify_type = notify_type;
}
/**
* Implementation of notify_payload_t.get_spi.
*/
static u_int32_t get_spi(private_notify_payload_t *this)
{
switch (this->protocol_id)
{
case PROTO_AH:
case PROTO_ESP:
if (this->spi.len == 4)
{
return *((u_int32_t*)this->spi.ptr);
}
default:
break;
}
return 0;
}
/**
* Implementation of notify_payload_t.set_spi.
*/
static void set_spi(private_notify_payload_t *this, u_int32_t spi)
{
chunk_free(&this->spi);
switch (this->protocol_id)
{
case PROTO_AH:
case PROTO_ESP:
this->spi = chunk_alloc(4);
*((u_int32_t*)this->spi.ptr) = spi;
break;
default:
break;
}
this->spi_size = this->spi.len;
compute_length(this);
}
/**
* Implementation of notify_payload_t.get_notification_data.
*/
static chunk_t get_notification_data(private_notify_payload_t *this)
{
return (this->notification_data);
}
/**
* Implementation of notify_payload_t.set_notification_data.
*/
static status_t set_notification_data(private_notify_payload_t *this, chunk_t notification_data)
{
chunk_free(&this->notification_data);
if (notification_data.len > 0)
{
this->notification_data = chunk_clone(notification_data);
}
compute_length(this);
return SUCCESS;
}
/**
* Implementation of notify_payload_t.destroy and notify_payload_t.destroy.
*/
static status_t destroy(private_notify_payload_t *this)
{
chunk_free(&this->notification_data);
chunk_free(&this->spi);
free(this);
return SUCCESS;
}
/*
* Described in header
*/
notify_payload_t *notify_payload_create()
{
private_notify_payload_t *this = malloc_thing(private_notify_payload_t);
/* interface functions */
this->public.payload_interface.verify = (status_t (*) (payload_t *))verify;
this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules;
this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length;
this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type;
this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type;
this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_type;
this->public.payload_interface.destroy = (void (*) (payload_t *))destroy;
/* public functions */
this->public.get_protocol_id = (u_int8_t (*) (notify_payload_t *)) get_protocol_id;
this->public.set_protocol_id = (void (*) (notify_payload_t *,u_int8_t)) set_protocol_id;
this->public.get_notify_type = (notify_type_t (*) (notify_payload_t *)) get_notify_type;
this->public.set_notify_type = (void (*) (notify_payload_t *,notify_type_t)) set_notify_type;
this->public.get_spi = (u_int32_t (*) (notify_payload_t *)) get_spi;
this->public.set_spi = (void (*) (notify_payload_t *,u_int32_t)) set_spi;
this->public.get_notification_data = (chunk_t (*) (notify_payload_t *)) get_notification_data;
this->public.set_notification_data = (void (*) (notify_payload_t *,chunk_t)) set_notification_data;
this->public.destroy = (void (*) (notify_payload_t *)) destroy;
/* set default values of the fields */
this->critical = FALSE;
this->next_payload = NO_PAYLOAD;
this->payload_length = NOTIFY_PAYLOAD_HEADER_LENGTH;
this->protocol_id = 0;
this->notify_type = 0;
this->spi.ptr = NULL;
this->spi.len = 0;
this->spi_size = 0;
this->notification_data.ptr = NULL;
this->notification_data.len = 0;
return &this->public;
}
/*
* Described in header.
*/
notify_payload_t *notify_payload_create_from_protocol_and_type(protocol_id_t protocol_id, notify_type_t notify_type)
{
notify_payload_t *notify = notify_payload_create();
notify->set_notify_type(notify,notify_type);
notify->set_protocol_id(notify,protocol_id);
return notify;
}
@@ -0,0 +1,232 @@
/*
* Copyright (C) 2006-2008 Tobias Brunner
* Copyright (C) 2006 Daniel Roethlisberger
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup notify_payload notify_payload
* @{ @ingroup payloads
*/
#ifndef NOTIFY_PAYLOAD_H_
#define NOTIFY_PAYLOAD_H_
typedef enum notify_type_t notify_type_t;
typedef struct notify_payload_t notify_payload_t;
#include <library.h>
#include <encoding/payloads/payload.h>
#include <encoding/payloads/proposal_substructure.h>
#include <utils/linked_list.h>
/**
* Notify payload length in bytes without any spi and notification data.
*/
#define NOTIFY_PAYLOAD_HEADER_LENGTH 8
/**
* Notify message types.
*
* See IKEv2 RFC 3.10.1.
*/
enum notify_type_t {
/* notify error messages */
UNSUPPORTED_CRITICAL_PAYLOAD = 1,
INVALID_IKE_SPI = 4,
INVALID_MAJOR_VERSION = 5,
INVALID_SYNTAX = 7,
INVALID_MESSAGE_ID = 9,
INVALID_SPI = 11,
NO_PROPOSAL_CHOSEN = 14,
INVALID_KE_PAYLOAD = 17,
AUTHENTICATION_FAILED = 24,
SINGLE_PAIR_REQUIRED = 34,
NO_ADDITIONAL_SAS = 35,
INTERNAL_ADDRESS_FAILURE = 36,
FAILED_CP_REQUIRED = 37,
TS_UNACCEPTABLE = 38,
INVALID_SELECTORS = 39,
/* mobile extension, RFC 4555 */
UNACCEPTABLE_ADDRESSES = 40,
UNEXPECTED_NAT_DETECTED = 41,
/* mobile IPv6 bootstrapping, RFC 5026 */
USE_ASSIGNED_HoA = 42,
/* IKE-ME, private use */
ME_CONNECT_FAILED = 8192,
/* notify status messages */
INITIAL_CONTACT = 16384,
SET_WINDOW_SIZE = 16385,
ADDITIONAL_TS_POSSIBLE = 16386,
IPCOMP_SUPPORTED = 16387,
NAT_DETECTION_SOURCE_IP = 16388,
NAT_DETECTION_DESTINATION_IP = 16389,
COOKIE = 16390,
USE_TRANSPORT_MODE = 16391,
HTTP_CERT_LOOKUP_SUPPORTED = 16392,
REKEY_SA = 16393,
ESP_TFC_PADDING_NOT_SUPPORTED = 16394,
NON_FIRST_FRAGMENTS_ALSO = 16395,
/* mobike extension, RFC4555 */
MOBIKE_SUPPORTED = 16396,
ADDITIONAL_IP4_ADDRESS = 16397,
ADDITIONAL_IP6_ADDRESS = 16398,
NO_ADDITIONAL_ADDRESSES = 16399,
UPDATE_SA_ADDRESSES = 16400,
COOKIE2 = 16401,
NO_NATS_ALLOWED = 16402,
/* repeated authentication extension, RFC4478 */
AUTH_LIFETIME = 16403,
/* multiple authentication exchanges, RFC 4739 */
MULTIPLE_AUTH_SUPPORTED = 16404,
ANOTHER_AUTH_FOLLOWS = 16405,
/* redirect mechanism, RFC 5685 */
REDIRECT_SUPPORTED = 16406,
REDIRECT = 16407,
REDIRECTED_FROM = 16408,
/* draft-ietf-ipsecme-ikev2-resumption, assigned by IANA */
TICKET_LT_OPAQUE = 16409,
TICKET_REQUEST = 16410,
TICKET_ACK = 16411,
TICKET_NACK = 16412,
TICKET_OPAQUE = 16413,
LINK_ID = 16414,
/* draft-eronen-ipsec-ikev2-eap-auth, not assigned by IANA yet */
EAP_ONLY_AUTHENTICATION = 40960,
/* BEET mode, not even a draft yet. private use */
USE_BEET_MODE = 40961,
/* IKE-ME, private use */
ME_MEDIATION = 40962,
ME_ENDPOINT = 40963,
ME_CALLBACK = 40964,
ME_CONNECTID = 40965,
ME_CONNECTKEY = 40966,
ME_CONNECTAUTH = 40967,
ME_RESPONSE = 40968
};
/**
* enum name for notify_type_t.
*/
extern enum_name_t *notify_type_names;
/**
* enum name for notify_type_t (shorter strings).
*/
extern enum_name_t *notify_type_short_names;
/**
* Class representing an IKEv2-Notify Payload.
*
* The Notify Payload format is described in Draft section 3.10.
*/
struct notify_payload_t {
/**
* The payload_t interface.
*/
payload_t payload_interface;
/**
* Gets the protocol id of this payload.
*
* @return protocol id of this payload
*/
u_int8_t (*get_protocol_id) (notify_payload_t *this);
/**
* Sets the protocol id of this payload.
*
* @param protocol_id protocol id to set
*/
void (*set_protocol_id) (notify_payload_t *this, u_int8_t protocol_id);
/**
* Gets the notify message type of this payload.
*
* @return notify message type of this payload
*/
notify_type_t (*get_notify_type) (notify_payload_t *this);
/**
* Sets notify message type of this payload.
*
* @param type notify message type to set
*/
void (*set_notify_type) (notify_payload_t *this, notify_type_t type);
/**
* Returns the currently set spi of this payload.
*
* This is only valid for notifys with protocol AH|ESP
*
* @return SPI value
*/
u_int32_t (*get_spi) (notify_payload_t *this);
/**
* Sets the spi of this payload.
*
* This is only valid for notifys with protocol AH|ESP
*
* @param spi SPI value
*/
void (*set_spi) (notify_payload_t *this, u_int32_t spi);
/**
* Returns the currently set notification data of payload.
*
* Returned data are not copied.
*
* @return chunk_t pointing to the value
*/
chunk_t (*get_notification_data) (notify_payload_t *this);
/**
* Sets the notification data of this payload.
*
* @warning Value is getting copied.
*
* @param notification_data chunk_t pointing to the value to set
*/
void (*set_notification_data) (notify_payload_t *this,
chunk_t notification_data);
/**
* Destroys an notify_payload_t object.
*/
void (*destroy) (notify_payload_t *this);
};
/**
* Creates an empty notify_payload_t object
*
* @return created notify_payload_t object
*/
notify_payload_t *notify_payload_create(void);
/**
* Creates an notify_payload_t object of specific type for specific protocol id.
*
* @param protocol_id protocol id (IKE, AH or ESP)
* @param type notify type (see notify_type_t)
* @return notify_payload_t object
*/
notify_payload_t *notify_payload_create_from_protocol_and_type(
protocol_id_t protocol_id, notify_type_t type);
#endif /** NOTIFY_PAYLOAD_H_ @}*/
+184
View File
@@ -0,0 +1,184 @@
/*
* Copyright (C) 2007 Tobias Brunner
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "payload.h"
#include <encoding/payloads/ike_header.h>
#include <encoding/payloads/sa_payload.h>
#include <encoding/payloads/nonce_payload.h>
#include <encoding/payloads/id_payload.h>
#include <encoding/payloads/ke_payload.h>
#include <encoding/payloads/notify_payload.h>
#include <encoding/payloads/auth_payload.h>
#include <encoding/payloads/cert_payload.h>
#include <encoding/payloads/certreq_payload.h>
#include <encoding/payloads/encryption_payload.h>
#include <encoding/payloads/ts_payload.h>
#include <encoding/payloads/delete_payload.h>
#include <encoding/payloads/vendor_id_payload.h>
#include <encoding/payloads/cp_payload.h>
#include <encoding/payloads/configuration_attribute.h>
#include <encoding/payloads/eap_payload.h>
#include <encoding/payloads/unknown_payload.h>
ENUM_BEGIN(payload_type_names, NO_PAYLOAD, NO_PAYLOAD,
"NO_PAYLOAD");
ENUM_NEXT(payload_type_names, SECURITY_ASSOCIATION, EXTENSIBLE_AUTHENTICATION, NO_PAYLOAD,
"SECURITY_ASSOCIATION",
"KEY_EXCHANGE",
"ID_INITIATOR",
"ID_RESPONDER",
"CERTIFICATE",
"CERTIFICATE_REQUEST",
"AUTHENTICATION",
"NONCE",
"NOTIFY",
"DELETE",
"VENDOR_ID",
"TRAFFIC_SELECTOR_INITIATOR",
"TRAFFIC_SELECTOR_RESPONDER",
"ENCRYPTED",
"CONFIGURATION",
"EXTENSIBLE_AUTHENTICATION");
#ifdef ME
ENUM_NEXT(payload_type_names, ID_PEER, ID_PEER, EXTENSIBLE_AUTHENTICATION,
"ID_PEER");
ENUM_NEXT(payload_type_names, HEADER, UNKNOWN_PAYLOAD, ID_PEER,
"HEADER",
"PROPOSAL_SUBSTRUCTURE",
"TRANSFORM_SUBSTRUCTURE",
"TRANSFORM_ATTRIBUTE",
"TRAFFIC_SELECTOR_SUBSTRUCTURE",
"CONFIGURATION_ATTRIBUTE",
"UNKNOWN_PAYLOAD");
#else
ENUM_NEXT(payload_type_names, HEADER, UNKNOWN_PAYLOAD, EXTENSIBLE_AUTHENTICATION,
"HEADER",
"PROPOSAL_SUBSTRUCTURE",
"TRANSFORM_SUBSTRUCTURE",
"TRANSFORM_ATTRIBUTE",
"TRAFFIC_SELECTOR_SUBSTRUCTURE",
"CONFIGURATION_ATTRIBUTE",
"UNKNOWN_PAYLOAD");
#endif /* ME */
ENUM_END(payload_type_names, UNKNOWN_PAYLOAD);
/* short forms of payload names */
ENUM_BEGIN(payload_type_short_names, NO_PAYLOAD, NO_PAYLOAD,
"--");
ENUM_NEXT(payload_type_short_names, SECURITY_ASSOCIATION, EXTENSIBLE_AUTHENTICATION, NO_PAYLOAD,
"SA",
"KE",
"IDi",
"IDr",
"CERT",
"CERTREQ",
"AUTH",
"No",
"N",
"D",
"V",
"TSi",
"TSr",
"E",
"CP",
"EAP");
#ifdef ME
ENUM_NEXT(payload_type_short_names, ID_PEER, ID_PEER, EXTENSIBLE_AUTHENTICATION,
"IDp");
ENUM_NEXT(payload_type_short_names, HEADER, UNKNOWN_PAYLOAD, ID_PEER,
"HDR",
"PROP",
"TRANS",
"TRANSATTR",
"TSSUB",
"CPATTR",
"??");
#else
ENUM_NEXT(payload_type_short_names, HEADER, UNKNOWN_PAYLOAD, EXTENSIBLE_AUTHENTICATION,
"HDR",
"PROP",
"TRANS",
"TRANSATTR",
"TSSUB",
"CPATTR",
"??");
#endif /* ME */
ENUM_END(payload_type_short_names, UNKNOWN_PAYLOAD);
/*
* see header
*/
payload_t *payload_create(payload_type_t type)
{
switch (type)
{
case HEADER:
return (payload_t*)ike_header_create();
case SECURITY_ASSOCIATION:
return (payload_t*)sa_payload_create();
case PROPOSAL_SUBSTRUCTURE:
return (payload_t*)proposal_substructure_create();
case TRANSFORM_SUBSTRUCTURE:
return (payload_t*)transform_substructure_create();
case TRANSFORM_ATTRIBUTE:
return (payload_t*)transform_attribute_create();
case NONCE:
return (payload_t*)nonce_payload_create();
case ID_INITIATOR:
return (payload_t*)id_payload_create(ID_INITIATOR);
case ID_RESPONDER:
return (payload_t*)id_payload_create(ID_RESPONDER);
#ifdef ME
case ID_PEER:
return (payload_t*)id_payload_create(ID_PEER);
#endif /* ME */
case AUTHENTICATION:
return (payload_t*)auth_payload_create();
case CERTIFICATE:
return (payload_t*)cert_payload_create();
case CERTIFICATE_REQUEST:
return (payload_t*)certreq_payload_create();
case TRAFFIC_SELECTOR_SUBSTRUCTURE:
return (payload_t*)traffic_selector_substructure_create();
case TRAFFIC_SELECTOR_INITIATOR:
return (payload_t*)ts_payload_create(TRUE);
case TRAFFIC_SELECTOR_RESPONDER:
return (payload_t*)ts_payload_create(FALSE);
case KEY_EXCHANGE:
return (payload_t*)ke_payload_create();
case NOTIFY:
return (payload_t*)notify_payload_create();
case DELETE:
return (payload_t*)delete_payload_create(0);
case VENDOR_ID:
return (payload_t*)vendor_id_payload_create();
case CONFIGURATION:
return (payload_t*)cp_payload_create();
case CONFIGURATION_ATTRIBUTE:
return (payload_t*)configuration_attribute_create();
case EXTENSIBLE_AUTHENTICATION:
return (payload_t*)eap_payload_create();
case ENCRYPTED:
return (payload_t*)encryption_payload_create();
default:
return (payload_t*)unknown_payload_create();
}
}
+272
View File
@@ -0,0 +1,272 @@
/*
* Copyright (C) 2007 Tobias Brunner
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup payload payload
* @{ @ingroup payloads
*/
#ifndef PAYLOAD_H_
#define PAYLOAD_H_
typedef enum payload_type_t payload_type_t;
typedef struct payload_t payload_t;
#include <library.h>
#include <encoding/payloads/encodings.h>
/**
* Payload-Types of a IKEv2-Message.
*
* Header and substructures are also defined as
* payload types with values from PRIVATE USE space.
*/
enum payload_type_t{
/**
* End of payload list in next_payload
*/
NO_PAYLOAD = 0,
/**
* The security association (SA) payload containing proposals.
*/
SECURITY_ASSOCIATION = 33,
/**
* The key exchange (KE) payload containing diffie-hellman values.
*/
KEY_EXCHANGE = 34,
/**
* Identification for the original initiator (IDi).
*/
ID_INITIATOR = 35,
/**
* Identification for the original responder (IDr).
*/
ID_RESPONDER = 36,
/**
* Certificate payload with certificates (CERT).
*/
CERTIFICATE = 37,
/**
* Certificate request payload (CERTREQ).
*/
CERTIFICATE_REQUEST = 38,
/**
* Authentication payload contains auth data (AUTH).
*/
AUTHENTICATION = 39,
/**
* Nonces, for initator and responder (Ni, Nr, N)
*/
NONCE = 40,
/**
* Notify paylaod (N).
*/
NOTIFY = 41,
/**
* Delete payload (D)
*/
DELETE = 42,
/**
* Vendor id paylpoad (V).
*/
VENDOR_ID = 43,
/**
* Traffic selector for the original initiator (TSi).
*/
TRAFFIC_SELECTOR_INITIATOR = 44,
/**
* Traffic selector for the original responser (TSr).
*/
TRAFFIC_SELECTOR_RESPONDER = 45,
/**
* Encryption payload, contains other payloads (E).
*/
ENCRYPTED = 46,
/**
* Configuration payload (CP).
*/
CONFIGURATION = 47,
/**
* Extensible authentication payload (EAP).
*/
EXTENSIBLE_AUTHENTICATION = 48,
#ifdef ME
/**
* Identification payload for peers has a value from
* the PRIVATE USE space.
*/
ID_PEER = 128,
#endif /* ME */
/**
* Header has a value of PRIVATE USE space.
*
* This payload type is not sent over wire and just
* used internally to handle IKEv2-Header like a payload.
*/
HEADER = 140,
/**
* PROPOSAL_SUBSTRUCTURE has a value of PRIVATE USE space.
*
* This payload type is not sent over wire and just
* used internally to handle a proposal substructure like a payload.
*/
PROPOSAL_SUBSTRUCTURE = 141,
/**
* TRANSFORM_SUBSTRUCTURE has a value of PRIVATE USE space.
*
* This payload type is not sent over wire and just
* used internally to handle a transform substructure like a payload.
*/
TRANSFORM_SUBSTRUCTURE = 142,
/**
* TRANSFORM_ATTRIBUTE has a value of PRIVATE USE space.
*
* This payload type is not sent over wire and just
* used internally to handle a transform attribute like a payload.
*/
TRANSFORM_ATTRIBUTE = 143,
/**
* TRAFFIC_SELECTOR_SUBSTRUCTURE has a value of PRIVATE USE space.
*
* This payload type is not sent over wire and just
* used internally to handle a transform selector like a payload.
*/
TRAFFIC_SELECTOR_SUBSTRUCTURE = 144,
/**
* CONFIGURATION_ATTRIBUTE has a value of PRIVATE USE space.
*
* This payload type is not sent over wire and just
* used internally to handle a transform attribute like a payload.
*/
CONFIGURATION_ATTRIBUTE = 145,
/**
* A unknown payload has a value of PRIVATE USE space.
*
* This payload type is not sent over wire and just
* used internally to handle a unknown payload.
*/
UNKNOWN_PAYLOAD = 146,
};
/**
* enum names for payload_type_t.
*/
extern enum_name_t *payload_type_names;
/**
* enum names for payload_type_t in a short form.
*/
extern enum_name_t *payload_type_short_names;
/**
* Generic interface for all payload types (incl.header and substructures).
*
* To handle all kinds of payloads on a generic way, this interface must
* be implemented by every payload. This allows parser_t/generator_t a simple
* handling of all payloads.
*/
struct payload_t {
/**
* Get encoding rules for this payload.
*
* @param rules location to store pointer of first rule
* @param rule_count location to store number of rules
*/
void (*get_encoding_rules) (payload_t *this, encoding_rule_t **rules, size_t *rule_count);
/**
* Get type of payload.
*
* @return type of this payload
*/
payload_type_t (*get_type) (payload_t *this);
/**
* Get type of next payload or NO_PAYLOAD (0) if this is the last one.
*
* @return type of next payload
*/
payload_type_t (*get_next_type) (payload_t *this);
/**
* Set type of next payload.
*
* @param type type of next payload
*/
void (*set_next_type) (payload_t *this,payload_type_t type);
/**
* Get length of payload.
*
* @return length of this payload
*/
size_t (*get_length) (payload_t *this);
/**
* Verifies payload structure and makes consistence check.
*
* @return SUCCESS, FAILED if consistence not given
*/
status_t (*verify) (payload_t *this);
/**
* Destroys a payload and all included substructures.
*/
void (*destroy) (payload_t *this);
};
/**
* Create an empty payload.
*
* Useful for the parser, who wants a generic constructor for all payloads.
* It supports all payload_t methods. If a payload type is not known,
* an unknwon_paylod is created with the chunk of data in it.
*
* @param type type of the payload to create
* @return payload_t object
*/
payload_t *payload_create(payload_type_t type);
#endif /** PAYLOAD_H_ @}*/
@@ -0,0 +1,598 @@
/*
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <stddef.h>
#include "proposal_substructure.h"
#include <encoding/payloads/encodings.h>
#include <encoding/payloads/transform_substructure.h>
#include <library.h>
#include <utils/linked_list.h>
#include <daemon.h>
/**
* IKEv1 Value for a proposal payload.
*/
#define PROPOSAL_TYPE_VALUE 2
typedef struct private_proposal_substructure_t private_proposal_substructure_t;
/**
* Private data of an proposal_substructure_t object.
*
*/
struct private_proposal_substructure_t {
/**
* Public proposal_substructure_t interface.
*/
proposal_substructure_t public;
/**
* Next payload type.
*/
u_int8_t next_payload;
/**
* Length of this payload.
*/
u_int16_t proposal_length;
/**
* Proposal number.
*/
u_int8_t proposal_number;
/**
* Protocol ID.
*/
u_int8_t protocol_id;
/**
* SPI size of the following SPI.
*/
u_int8_t spi_size;
/**
* Number of transforms.
*/
u_int8_t transforms_count;
/**
* SPI is stored as chunk.
*/
chunk_t spi;
/**
* Transforms are stored in a linked_list_t.
*/
linked_list_t * transforms;
};
/**
* Encoding rules to parse or generate a Proposal substructure.
*
* The defined offsets are the positions in a object of type
* private_proposal_substructure_t.
*/
encoding_rule_t proposal_substructure_encodings[] = {
/* 1 Byte next payload type, stored in the field next_payload */
{ U_INT_8, offsetof(private_proposal_substructure_t, next_payload) },
/* Reserved Byte is skipped */
{ RESERVED_BYTE, 0 },
/* Length of the whole proposal substructure payload*/
{ PAYLOAD_LENGTH, offsetof(private_proposal_substructure_t, proposal_length) },
/* proposal number is a number of 8 bit */
{ U_INT_8, offsetof(private_proposal_substructure_t, proposal_number) },
/* protocol ID is a number of 8 bit */
{ U_INT_8, offsetof(private_proposal_substructure_t, protocol_id) },
/* SPI Size has its own type */
{ SPI_SIZE, offsetof(private_proposal_substructure_t, spi_size) },
/* Number of transforms is a number of 8 bit */
{ U_INT_8, offsetof(private_proposal_substructure_t, transforms_count) },
/* SPI is a chunk of variable size*/
{ SPI, offsetof(private_proposal_substructure_t, spi) },
/* Transforms are stored in a transform substructure,
offset points to a linked_list_t pointer */
{ TRANSFORMS, offsetof(private_proposal_substructure_t, transforms) }
};
/*
1 2 3
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 0 (last) or 2 ! RESERVED ! Proposal Length !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! Proposal # ! Protocol ID ! SPI Size !# of Transforms!
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
~ SPI (variable) ~
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! !
~ <Transforms> ~
! !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
/**
* Implementation of payload_t.verify.
*/
static status_t verify(private_proposal_substructure_t *this)
{
status_t status = SUCCESS;
iterator_t *iterator;
payload_t *current_transform;
if ((this->next_payload != NO_PAYLOAD) && (this->next_payload != 2))
{
/* must be 0 or 2 */
DBG1(DBG_ENC, "inconsistent next payload");
return FAILED;
}
if (this->transforms_count != this->transforms->get_count(this->transforms))
{
/* must be the same! */
DBG1(DBG_ENC, "transform count invalid");
return FAILED;
}
switch (this->protocol_id)
{
case PROTO_AH:
case PROTO_ESP:
if (this->spi.len != 4)
{
DBG1(DBG_ENC, "invalid SPI length in %N proposal",
protocol_id_names, this->protocol_id);
return FAILED;
}
break;
case PROTO_IKE:
if (this->spi.len != 0 && this->spi.len != 8)
{
DBG1(DBG_ENC, "invalid SPI length in IKE proposal");
return FAILED;
}
break;
default:
DBG1(DBG_ENC, "invalid proposal protocol (%d)", this->protocol_id);
return FAILED;
}
if ((this->protocol_id == 0) || (this->protocol_id >= 4))
{
/* reserved are not supported */
DBG1(DBG_ENC, "invalid protocol");
return FAILED;
}
iterator = this->transforms->create_iterator(this->transforms,TRUE);
while(iterator->iterate(iterator, (void**)&current_transform))
{
status = current_transform->verify(current_transform);
if (status != SUCCESS)
{
DBG1(DBG_ENC, "TRANSFORM_SUBSTRUCTURE verification failed");
break;
}
}
iterator->destroy(iterator);
/* proposal number is checked in SA payload */
return status;
}
/**
* Implementation of payload_t.get_encoding_rules.
*/
static void get_encoding_rules(private_proposal_substructure_t *this, encoding_rule_t **rules, size_t *rule_count)
{
*rules = proposal_substructure_encodings;
*rule_count = sizeof(proposal_substructure_encodings) / sizeof(encoding_rule_t);
}
/**
* Implementation of payload_t.get_type.
*/
static payload_type_t get_type(private_proposal_substructure_t *this)
{
return PROPOSAL_SUBSTRUCTURE;
}
/**
* Implementation of payload_t.get_next_type.
*/
static payload_type_t get_next_type(private_proposal_substructure_t *this)
{
return (this->next_payload);
}
/**
* Implementation of payload_t.set_next_type.
*/
static void set_next_type(private_proposal_substructure_t *this,payload_type_t type)
{
}
/**
* (re-)compute the length of the payload.
*/
static void compute_length(private_proposal_substructure_t *this)
{
iterator_t *iterator;
payload_t *current_transform;
size_t transforms_count = 0;
size_t length = PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH;
iterator = this->transforms->create_iterator(this->transforms,TRUE);
while (iterator->iterate(iterator, (void**)&current_transform))
{
length += current_transform->get_length(current_transform);
transforms_count++;
}
iterator->destroy(iterator);
length += this->spi.len;
this->transforms_count = transforms_count;
this->proposal_length = length;
}
/**
* Implementation of payload_t.get_length.
*/
static size_t get_length(private_proposal_substructure_t *this)
{
compute_length(this);
return this->proposal_length;
}
/**
* Implementation of proposal_substructure_t.create_transform_substructure_iterator.
*/
static iterator_t *create_transform_substructure_iterator (private_proposal_substructure_t *this,bool forward)
{
return (this->transforms->create_iterator(this->transforms,forward));
}
/**
* Implementation of proposal_substructure_t.add_transform_substructure.
*/
static void add_transform_substructure (private_proposal_substructure_t *this,transform_substructure_t *transform)
{
status_t status;
if (this->transforms->get_count(this->transforms) > 0)
{
transform_substructure_t *last_transform;
status = this->transforms->get_last(this->transforms,(void **) &last_transform);
/* last transform is now not anymore last one */
last_transform->set_is_last_transform(last_transform,FALSE);
}
transform->set_is_last_transform(transform,TRUE);
this->transforms->insert_last(this->transforms,(void *) transform);
compute_length(this);
}
/**
* Implementation of proposal_substructure_t.proposal_substructure_t.
*/
static void set_is_last_proposal (private_proposal_substructure_t *this, bool is_last)
{
this->next_payload = (is_last) ? 0: PROPOSAL_TYPE_VALUE;
}
/**
* Implementation of proposal_substructure_t.set_proposal_number.
*/
static void set_proposal_number(private_proposal_substructure_t *this,u_int8_t proposal_number)
{
this->proposal_number = proposal_number;
}
/**
* Implementation of proposal_substructure_t.get_proposal_number.
*/
static u_int8_t get_proposal_number (private_proposal_substructure_t *this)
{
return (this->proposal_number);
}
/**
* Implementation of proposal_substructure_t.set_protocol_id.
*/
static void set_protocol_id(private_proposal_substructure_t *this,u_int8_t protocol_id)
{
this->protocol_id = protocol_id;
}
/**
* Implementation of proposal_substructure_t.get_protocol_id.
*/
static u_int8_t get_protocol_id(private_proposal_substructure_t *this)
{
return (this->protocol_id);
}
/**
* Implementation of proposal_substructure_t.set_spi.
*/
static void set_spi(private_proposal_substructure_t *this, chunk_t spi)
{
/* first delete already set spi value */
if (this->spi.ptr != NULL)
{
free(this->spi.ptr);
this->spi.ptr = NULL;
this->spi.len = 0;
compute_length(this);
}
this->spi.ptr = clalloc(spi.ptr,spi.len);
this->spi.len = spi.len;
this->spi_size = spi.len;
compute_length(this);
}
/**
* Implementation of proposal_substructure_t.get_spi.
*/
static chunk_t get_spi(private_proposal_substructure_t *this)
{
chunk_t spi;
spi.ptr = this->spi.ptr;
spi.len = this->spi.len;
return spi;
}
/**
* Implementation of proposal_substructure_t.get_transform_count.
*/
static size_t get_transform_count (private_proposal_substructure_t *this)
{
return this->transforms->get_count(this->transforms);
}
/**
* Implementation of proposal_substructure_t.get_spi_size.
*/
static size_t get_spi_size (private_proposal_substructure_t *this)
{
return this->spi.len;
}
/**
* Implementation of proposal_substructure_t.get_proposal.
*/
proposal_t* get_proposal(private_proposal_substructure_t *this)
{
iterator_t *iterator;
transform_substructure_t *transform;
proposal_t *proposal;
u_int64_t spi;
proposal = proposal_create(this->protocol_id);
iterator = this->transforms->create_iterator(this->transforms, TRUE);
while (iterator->iterate(iterator, (void**)&transform))
{
transform_type_t transform_type;
u_int16_t transform_id;
u_int16_t key_length = 0;
transform_type = transform->get_transform_type(transform);
transform_id = transform->get_transform_id(transform);
transform->get_key_length(transform, &key_length);
proposal->add_algorithm(proposal, transform_type, transform_id, key_length);
}
iterator->destroy(iterator);
switch (this->spi.len)
{
case 4:
spi = *((u_int32_t*)this->spi.ptr);
break;
case 8:
spi = *((u_int64_t*)this->spi.ptr);
break;
default:
spi = 0;
}
proposal->set_spi(proposal, spi);
return proposal;
}
/**
* Implementation of proposal_substructure_t.clone.
*/
static private_proposal_substructure_t* clone_(private_proposal_substructure_t *this)
{
private_proposal_substructure_t *clone;
iterator_t *transforms;
transform_substructure_t *current_transform;
clone = (private_proposal_substructure_t *) proposal_substructure_create();
clone->next_payload = this->next_payload;
clone->proposal_number = this->proposal_number;
clone->protocol_id = this->protocol_id;
clone->spi_size = this->spi_size;
if (this->spi.ptr != NULL)
{
clone->spi.ptr = clalloc(this->spi.ptr,this->spi.len);
clone->spi.len = this->spi.len;
}
transforms = this->transforms->create_iterator(this->transforms,FALSE);
while (transforms->iterate(transforms, (void**)&current_transform))
{
current_transform = current_transform->clone(current_transform);
clone->public.add_transform_substructure(&clone->public, current_transform);
}
transforms->destroy(transforms);
return clone;
}
/**
* Implements payload_t's and proposal_substructure_t's destroy function.
* See #payload_s.destroy or proposal_substructure_s.destroy for description.
*/
static void destroy(private_proposal_substructure_t *this)
{
this->transforms->destroy_offset(this->transforms,
offsetof(transform_substructure_t, destroy));
chunk_free(&this->spi);
free(this);
}
/*
* Described in header.
*/
proposal_substructure_t *proposal_substructure_create()
{
private_proposal_substructure_t *this = malloc_thing(private_proposal_substructure_t);
/* interface functions */
this->public.payload_interface.verify = (status_t (*) (payload_t *))verify;
this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules;
this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length;
this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type;
this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type;
this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_type;
this->public.payload_interface.destroy = (void (*) (payload_t *))destroy;
/* public functions */
this->public.create_transform_substructure_iterator = (iterator_t* (*) (proposal_substructure_t *,bool)) create_transform_substructure_iterator;
this->public.add_transform_substructure = (void (*) (proposal_substructure_t *,transform_substructure_t *)) add_transform_substructure;
this->public.set_proposal_number = (void (*) (proposal_substructure_t *,u_int8_t))set_proposal_number;
this->public.get_proposal_number = (u_int8_t (*) (proposal_substructure_t *)) get_proposal_number;
this->public.set_protocol_id = (void (*) (proposal_substructure_t *,u_int8_t))set_protocol_id;
this->public.get_protocol_id = (u_int8_t (*) (proposal_substructure_t *)) get_protocol_id;
this->public.set_is_last_proposal = (void (*) (proposal_substructure_t *,bool)) set_is_last_proposal;
this->public.get_proposal = (proposal_t* (*) (proposal_substructure_t*))get_proposal;
this->public.set_spi = (void (*) (proposal_substructure_t *,chunk_t))set_spi;
this->public.get_spi = (chunk_t (*) (proposal_substructure_t *)) get_spi;
this->public.get_transform_count = (size_t (*) (proposal_substructure_t *)) get_transform_count;
this->public.get_spi_size = (size_t (*) (proposal_substructure_t *)) get_spi_size;
this->public.clone = (proposal_substructure_t * (*) (proposal_substructure_t *)) clone_;
this->public.destroy = (void (*) (proposal_substructure_t *)) destroy;
/* set default values of the fields */
this->next_payload = NO_PAYLOAD;
this->proposal_length = 0;
this->proposal_number = 0;
this->protocol_id = 0;
this->transforms_count = 0;
this->spi_size = 0;
this->spi.ptr = NULL;
this->spi.len = 0;
this->transforms = linked_list_create();
return (&(this->public));
}
/*
* Described in header.
*/
proposal_substructure_t *proposal_substructure_create_from_proposal(proposal_t *proposal)
{
transform_substructure_t *transform;
private_proposal_substructure_t *this;
u_int16_t alg, key_size;
enumerator_t *enumerator;
this = (private_proposal_substructure_t*)proposal_substructure_create();
/* encryption algorithm is only availble in ESP */
enumerator = proposal->create_enumerator(proposal, ENCRYPTION_ALGORITHM);
while (enumerator->enumerate(enumerator, &alg, &key_size))
{
transform = transform_substructure_create_type(ENCRYPTION_ALGORITHM,
alg, key_size);
add_transform_substructure(this, transform);
}
enumerator->destroy(enumerator);
/* integrity algorithms */
enumerator = proposal->create_enumerator(proposal, INTEGRITY_ALGORITHM);
while (enumerator->enumerate(enumerator, &alg, &key_size))
{
transform = transform_substructure_create_type(INTEGRITY_ALGORITHM,
alg, key_size);
add_transform_substructure(this, transform);
}
enumerator->destroy(enumerator);
/* prf algorithms */
enumerator = proposal->create_enumerator(proposal, PSEUDO_RANDOM_FUNCTION);
while (enumerator->enumerate(enumerator, &alg, &key_size))
{
transform = transform_substructure_create_type(PSEUDO_RANDOM_FUNCTION,
alg, key_size);
add_transform_substructure(this, transform);
}
enumerator->destroy(enumerator);
/* dh groups */
enumerator = proposal->create_enumerator(proposal, DIFFIE_HELLMAN_GROUP);
while (enumerator->enumerate(enumerator, &alg, NULL))
{
transform = transform_substructure_create_type(DIFFIE_HELLMAN_GROUP,
alg, 0);
add_transform_substructure(this, transform);
}
enumerator->destroy(enumerator);
/* extended sequence numbers */
enumerator = proposal->create_enumerator(proposal, EXTENDED_SEQUENCE_NUMBERS);
while (enumerator->enumerate(enumerator, &alg, NULL))
{
transform = transform_substructure_create_type(EXTENDED_SEQUENCE_NUMBERS,
alg, 0);
add_transform_substructure(this, transform);
}
enumerator->destroy(enumerator);
/* add SPI, if necessary */
switch (proposal->get_protocol(proposal))
{
case PROTO_AH:
case PROTO_ESP:
this->spi_size = this->spi.len = 4;
this->spi.ptr = malloc(this->spi_size);
*((u_int32_t*)this->spi.ptr) = proposal->get_spi(proposal);
break;
case PROTO_IKE:
if (proposal->get_spi(proposal))
{ /* IKE only uses SPIS when rekeying, but on initial setup */
this->spi_size = this->spi.len = 8;
this->spi.ptr = malloc(this->spi_size);
*((u_int64_t*)this->spi.ptr) = proposal->get_spi(proposal);
}
break;
default:
break;
}
this->proposal_number = 0;
this->protocol_id = proposal->get_protocol(proposal);
return &this->public;
}
@@ -0,0 +1,173 @@
/*
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup proposal_substructure proposal_substructure
* @{ @ingroup payloads
*/
#ifndef PROPOSAL_SUBSTRUCTURE_H_
#define PROPOSAL_SUBSTRUCTURE_H_
typedef struct proposal_substructure_t proposal_substructure_t;
#include <library.h>
#include <encoding/payloads/payload.h>
#include <encoding/payloads/transform_substructure.h>
#include <config/proposal.h>
#include <utils/linked_list.h>
/**
* Length of the proposal substructure header (without spi).
*/
#define PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH 8
/**
* Class representing an IKEv2-PROPOSAL SUBSTRUCTURE.
*
* The PROPOSAL SUBSTRUCTURE format is described in RFC section 3.3.1.
*/
struct proposal_substructure_t {
/**
* The payload_t interface.
*/
payload_t payload_interface;
/**
* Creates an iterator of stored transform_substructure_t objects.
*
* @param forward iterator direction (TRUE: front to end)
* @return created iterator_t object
*/
iterator_t *(*create_transform_substructure_iterator) (
proposal_substructure_t *this, bool forward);
/**
* Adds a transform_substructure_t object to this object.
*
* @param transform transform_substructure_t object to add
*/
void (*add_transform_substructure) (proposal_substructure_t *this,
transform_substructure_t *transform);
/**
* Sets the proposal number of current proposal.
*
* @param id proposal number to set
*/
void (*set_proposal_number) (proposal_substructure_t *this,
u_int8_t proposal_number);
/**
* get proposal number of current proposal.
*
* @return proposal number of current proposal substructure.
*/
u_int8_t (*get_proposal_number) (proposal_substructure_t *this);
/**
* get the number of transforms in current proposal.
*
* @return transform count in current proposal
*/
size_t (*get_transform_count) (proposal_substructure_t *this);
/**
* get size of the set spi in bytes.
*
* @return size of the spi in bytes
*/
size_t (*get_spi_size) (proposal_substructure_t *this);
/**
* Sets the protocol id of current proposal.
*
* @param id protocol id to set
*/
void (*set_protocol_id) (proposal_substructure_t *this,
u_int8_t protocol_id);
/**
* get protocol id of current proposal.
*
* @return protocol id of current proposal substructure.
*/
u_int8_t (*get_protocol_id) (proposal_substructure_t *this);
/**
* Sets the next_payload field of this substructure
*
* If this is the last proposal, next payload field is set to 0,
* otherwise to 2
*
* @param is_last When TRUE, next payload field is set to 0, otherwise to 2
*/
void (*set_is_last_proposal) (proposal_substructure_t *this, bool is_last);
/**
* Returns the currently set SPI of this proposal.
*
* @return chunk_t pointing to the value
*/
chunk_t (*get_spi) (proposal_substructure_t *this);
/**
* Sets the SPI of the current proposal.
*
* @warning SPI is getting copied
*
* @param spi chunk_t pointing to the value to set
*/
void (*set_spi) (proposal_substructure_t *this, chunk_t spi);
/**
* Get a proposal_t from the propsal_substructure_t.
*
* @return proposal_t
*/
proposal_t * (*get_proposal) (proposal_substructure_t *this);
/**
* Clones an proposal_substructure_t object.
*
* @return cloned object
*/
proposal_substructure_t* (*clone) (proposal_substructure_t *this);
/**
* Destroys an proposal_substructure_t object.
*/
void (*destroy) (proposal_substructure_t *this);
};
/**
* Creates an empty proposal_substructure_t object
*
* @return proposal_substructure_t object
*/
proposal_substructure_t *proposal_substructure_create(void);
/**
* Creates a proposal_substructure_t from a proposal_t.
*
* @param proposal proposal to build a substruct out of it
* @return proposal_substructure_t object
*/
proposal_substructure_t *proposal_substructure_create_from_proposal(
proposal_t *proposal);
#endif /** PROPOSAL_SUBSTRUCTURE_H_ @}*/
@@ -0,0 +1,368 @@
/*
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <stddef.h>
#include "sa_payload.h"
#include <encoding/payloads/encodings.h>
#include <utils/linked_list.h>
#include <daemon.h>
typedef struct private_sa_payload_t private_sa_payload_t;
/**
* Private data of an sa_payload_t object.
*
*/
struct private_sa_payload_t {
/**
* Public sa_payload_t interface.
*/
sa_payload_t public;
/**
* Next payload type.
*/
u_int8_t next_payload;
/**
* Critical flag.
*/
bool critical;
/**
* Length of this payload.
*/
u_int16_t payload_length;
/**
* Proposals in this payload are stored in a linked_list_t.
*/
linked_list_t * proposals;
};
/**
* Encoding rules to parse or generate a IKEv2-SA Payload
*
* The defined offsets are the positions in a object of type
* private_sa_payload_t.
*
*/
encoding_rule_t sa_payload_encodings[] = {
/* 1 Byte next payload type, stored in the field next_payload */
{ U_INT_8, offsetof(private_sa_payload_t, next_payload) },
/* the critical bit */
{ FLAG, offsetof(private_sa_payload_t, critical) },
/* 7 Bit reserved bits, nowhere stored */
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
/* Length of the whole SA payload*/
{ PAYLOAD_LENGTH, offsetof(private_sa_payload_t, payload_length) },
/* Proposals are stored in a proposal substructure,
offset points to a linked_list_t pointer */
{ PROPOSALS, offsetof(private_sa_payload_t, proposals) }
};
/*
1 2 3
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! Next Payload !C! RESERVED ! Payload Length !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! !
~ <Proposals> ~
! !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
/**
* Implementation of payload_t.verify.
*/
static status_t verify(private_sa_payload_t *this)
{
int expected_number = 1, current_number;
status_t status = SUCCESS;
iterator_t *iterator;
proposal_substructure_t *current_proposal;
bool first = TRUE;
/* check proposal numbering */
iterator = this->proposals->create_iterator(this->proposals,TRUE);
while(iterator->iterate(iterator, (void**)&current_proposal))
{
current_number = current_proposal->get_proposal_number(current_proposal);
if (current_number < expected_number)
{
if (current_number != (expected_number + 1))
{
DBG1(DBG_ENC, "proposal number is %d, expected %d or %d",
current_number, expected_number, expected_number + 1);
status = FAILED;
break;
}
}
else if (current_number < expected_number)
{
/* must not be smaller then proceeding one */
DBG1(DBG_ENC, "proposal number smaller than that of previous proposal");
status = FAILED;
break;
}
status = current_proposal->payload_interface.verify(&(current_proposal->payload_interface));
if (status != SUCCESS)
{
DBG1(DBG_ENC, "PROPOSAL_SUBSTRUCTURE verification failed");
break;
}
first = FALSE;
expected_number = current_number;
}
iterator->destroy(iterator);
return status;
}
/**
* Implementation of payload_t.destroy and sa_payload_t.destroy.
*/
static status_t destroy(private_sa_payload_t *this)
{
this->proposals->destroy_offset(this->proposals,
offsetof(proposal_substructure_t, destroy));
free(this);
return SUCCESS;
}
/**
* Implementation of payload_t.get_encoding_rules.
*/
static void get_encoding_rules(private_sa_payload_t *this, encoding_rule_t **rules, size_t *rule_count)
{
*rules = sa_payload_encodings;
*rule_count = sizeof(sa_payload_encodings) / sizeof(encoding_rule_t);
}
/**
* Implementation of payload_t.get_type.
*/
static payload_type_t get_type(private_sa_payload_t *this)
{
return SECURITY_ASSOCIATION;
}
/**
* Implementation of payload_t.get_next_type.
*/
static payload_type_t get_next_type(private_sa_payload_t *this)
{
return (this->next_payload);
}
/**
* Implementation of payload_t.set_next_type.
*/
static void set_next_type(private_sa_payload_t *this,payload_type_t type)
{
this->next_payload = type;
}
/**
* recompute length of the payload.
*/
static void compute_length (private_sa_payload_t *this)
{
iterator_t *iterator;
payload_t *current_proposal;
size_t length = SA_PAYLOAD_HEADER_LENGTH;
iterator = this->proposals->create_iterator(this->proposals,TRUE);
while (iterator->iterate(iterator, (void **)&current_proposal))
{
length += current_proposal->get_length(current_proposal);
}
iterator->destroy(iterator);
this->payload_length = length;
}
/**
* Implementation of payload_t.get_length.
*/
static size_t get_length(private_sa_payload_t *this)
{
compute_length(this);
return this->payload_length;
}
/**
* Implementation of sa_payload_t.create_proposal_substructure_iterator.
*/
static iterator_t *create_proposal_substructure_iterator (private_sa_payload_t *this,bool forward)
{
return this->proposals->create_iterator(this->proposals,forward);
}
/**
* Implementation of sa_payload_t.add_proposal_substructure.
*/
static void add_proposal_substructure(private_sa_payload_t *this,proposal_substructure_t *proposal)
{
status_t status;
u_int proposal_count = this->proposals->get_count(this->proposals);
if (proposal_count > 0)
{
proposal_substructure_t *last_proposal;
status = this->proposals->get_last(this->proposals,(void **) &last_proposal);
/* last transform is now not anymore last one */
last_proposal->set_is_last_proposal(last_proposal, FALSE);
}
proposal->set_is_last_proposal(proposal, TRUE);
proposal->set_proposal_number(proposal, proposal_count + 1);
this->proposals->insert_last(this->proposals,(void *) proposal);
compute_length(this);
}
/**
* Implementation of sa_payload_t.add_proposal.
*/
static void add_proposal(private_sa_payload_t *this, proposal_t *proposal)
{
proposal_substructure_t *substructure;
substructure = proposal_substructure_create_from_proposal(proposal);
add_proposal_substructure(this, substructure);
}
/**
* Implementation of sa_payload_t.get_proposals.
*/
static linked_list_t *get_proposals(private_sa_payload_t *this)
{
int struct_number = 0;
int ignore_struct_number = 0;
iterator_t *iterator;
proposal_substructure_t *proposal_struct;
linked_list_t *proposal_list;
/* this list will hold our proposals */
proposal_list = linked_list_create();
/* we do not support proposals split up to two proposal substructures, as
* AH+ESP bundles are not supported in RFC4301 anymore.
* To handle such structures safely, we just skip proposals with multiple
* protocols.
*/
iterator = this->proposals->create_iterator(this->proposals, TRUE);
while (iterator->iterate(iterator, (void **)&proposal_struct))
{
proposal_t *proposal;
/* check if a proposal has a single protocol */
if (proposal_struct->get_proposal_number(proposal_struct) == struct_number)
{
if (ignore_struct_number < struct_number)
{
/* remova an already added, if first of series */
proposal_list->remove_last(proposal_list, (void**)&proposal);
proposal->destroy(proposal);
ignore_struct_number = struct_number;
}
continue;
}
struct_number++;
proposal = proposal_struct->get_proposal(proposal_struct);
if (proposal)
{
proposal_list->insert_last(proposal_list, proposal);
}
}
iterator->destroy(iterator);
return proposal_list;
}
/*
* Described in header.
*/
sa_payload_t *sa_payload_create()
{
private_sa_payload_t *this = malloc_thing(private_sa_payload_t);
/* public interface */
this->public.payload_interface.verify = (status_t (*) (payload_t *))verify;
this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules;
this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length;
this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type;
this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type;
this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_type;
this->public.payload_interface.destroy = (void (*) (payload_t *))destroy;
/* public functions */
this->public.create_proposal_substructure_iterator = (iterator_t* (*) (sa_payload_t *,bool)) create_proposal_substructure_iterator;
this->public.add_proposal_substructure = (void (*) (sa_payload_t *,proposal_substructure_t *)) add_proposal_substructure;
this->public.add_proposal = (void (*) (sa_payload_t*,proposal_t*))add_proposal;
this->public.get_proposals = (linked_list_t* (*) (sa_payload_t *)) get_proposals;
this->public.destroy = (void (*) (sa_payload_t *)) destroy;
/* set default values of the fields */
this->critical = FALSE;
this->next_payload = NO_PAYLOAD;
this->payload_length = SA_PAYLOAD_HEADER_LENGTH;
this->proposals = linked_list_create();
return &this->public;
}
/*
* Described in header.
*/
sa_payload_t *sa_payload_create_from_proposal_list(linked_list_t *proposals)
{
iterator_t *iterator;
proposal_t *proposal;
sa_payload_t *sa_payload = sa_payload_create();
/* add every payload from the list */
iterator = proposals->create_iterator(proposals, TRUE);
while (iterator->iterate(iterator, (void**)&proposal))
{
add_proposal((private_sa_payload_t*)sa_payload, proposal);
}
iterator->destroy(iterator);
return sa_payload;
}
/*
* Described in header.
*/
sa_payload_t *sa_payload_create_from_proposal(proposal_t *proposal)
{
sa_payload_t *sa_payload = sa_payload_create();
add_proposal((private_sa_payload_t*)sa_payload, proposal);
return sa_payload;
}
@@ -0,0 +1,115 @@
/*
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup sa_payload sa_payload
* @{ @ingroup payloads
*/
#ifndef SA_PAYLOAD_H_
#define SA_PAYLOAD_H_
typedef struct sa_payload_t sa_payload_t;
#include <library.h>
#include <encoding/payloads/payload.h>
#include <encoding/payloads/proposal_substructure.h>
#include <utils/linked_list.h>
/**
* SA_PAYLOAD length in bytes without any proposal substructure.
*/
#define SA_PAYLOAD_HEADER_LENGTH 4
/**
* Class representing an IKEv2-SA Payload.
*
* The SA Payload format is described in RFC section 3.3.
*/
struct sa_payload_t {
/**
* The payload_t interface.
*/
payload_t payload_interface;
/**
* Creates an iterator of stored proposal_substructure_t objects.
*
* When deleting an proposal using this iterator,
* the length of this transform substructure has to be refreshed
* by calling get_length()!
*
* @param forward iterator direction (TRUE: front to end)
* @return created iterator_t object
*/
iterator_t *(*create_proposal_substructure_iterator) (sa_payload_t *this,
bool forward);
/**
* Adds a proposal_substructure_t object to this object.
*
* @param proposal proposal_substructure_t object to add
*/
void (*add_proposal_substructure) (sa_payload_t *this,
proposal_substructure_t *proposal);
/**
* Gets the proposals in this payload as a list.
*
* @return a list containing proposal_t s
*/
linked_list_t *(*get_proposals) (sa_payload_t *this);
/**
* Add a child proposal (AH/ESP) to the payload.
*
* @param proposal child proposal to add to the payload
*/
void (*add_proposal) (sa_payload_t *this, proposal_t *proposal);
/**
* Destroys an sa_payload_t object.
*/
void (*destroy) (sa_payload_t *this);
};
/**
* Creates an empty sa_payload_t object
*
* @return created sa_payload_t object
*/
sa_payload_t *sa_payload_create(void);
/**
* Creates a sa_payload_t object from a list of proposals.
*
* @param proposals list of proposals to build the payload from
* @return sa_payload_t object
*/
sa_payload_t *sa_payload_create_from_proposal_list(linked_list_t *proposals);
/**
* Creates a sa_payload_t object from a single proposal.
*
* This is only for convenience. Use sa_payload_create_from_proposal_list
* if you want to add more than one proposal.
*
* @param proposal proposal from which the payload should be built.
* @return sa_payload_t object
*/
sa_payload_t *sa_payload_create_from_proposal(proposal_t *proposal);
#endif /** SA_PAYLOAD_H_ @}*/
@@ -0,0 +1,276 @@
/*
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "traffic_selector_substructure.h"
#include <encoding/payloads/encodings.h>
#include <utils/linked_list.h>
typedef struct private_traffic_selector_substructure_t private_traffic_selector_substructure_t;
/**
* Private data of an traffic_selector_substructure_t object.
*
*/
struct private_traffic_selector_substructure_t {
/**
* Public traffic_selector_substructure_t interface.
*/
traffic_selector_substructure_t public;
/**
* Type of traffic selector.
*/
u_int8_t ts_type;
/**
* IP Protocol ID.
*/
u_int8_t ip_protocol_id;
/**
* Length of this payload.
*/
u_int16_t payload_length;
/**
* Start port number.
*/
u_int16_t start_port;
/**
* End port number.
*/
u_int16_t end_port;
/**
* Starting address.
*/
chunk_t starting_address;
/**
* Ending address.
*/
chunk_t ending_address;
};
/**
* Encoding rules to parse or generate a TS payload
*
* The defined offsets are the positions in a object of type
* private_traffic_selector_substructure_t.
*
*/
encoding_rule_t traffic_selector_substructure_encodings[] = {
/* 1 Byte next ts type*/
{ TS_TYPE, offsetof(private_traffic_selector_substructure_t, ts_type) },
/* 1 Byte IP protocol id*/
{ U_INT_8, offsetof(private_traffic_selector_substructure_t, ip_protocol_id) },
/* Length of the whole payload*/
{ PAYLOAD_LENGTH, offsetof(private_traffic_selector_substructure_t, payload_length) },
/* 2 Byte start port*/
{ U_INT_16, offsetof(private_traffic_selector_substructure_t, start_port) },
/* 2 Byte end port*/
{ U_INT_16, offsetof(private_traffic_selector_substructure_t, end_port) },
/* starting address is either 4 or 16 byte */
{ ADDRESS, offsetof(private_traffic_selector_substructure_t, starting_address) },
/* ending address is either 4 or 16 byte */
{ ADDRESS, offsetof(private_traffic_selector_substructure_t, ending_address) }
};
/*
1 2 3
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! TS Type !IP Protocol ID*| Selector Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Start Port* | End Port* |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! !
~ Starting Address* ~
! !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! !
~ Ending Address* ~
! !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
/**
* Implementation of payload_t.verify.
*/
static status_t verify(private_traffic_selector_substructure_t *this)
{
if (this->start_port > this->end_port)
{
return FAILED;
}
switch (this->ts_type)
{
case TS_IPV4_ADDR_RANGE:
{
if ((this->starting_address.len != 4) ||
(this->ending_address.len != 4))
{
/* ipv4 address must be 4 bytes long */
return FAILED;
}
break;
}
case TS_IPV6_ADDR_RANGE:
{
if ((this->starting_address.len != 16) ||
(this->ending_address.len != 16))
{
/* ipv6 address must be 16 bytes long */
return FAILED;
}
break;
}
default:
{
/* not supported ts type */
return FAILED;
}
}
return SUCCESS;
}
/**
* Implementation of traffic_selector_substructure_t.get_encoding_rules.
*/
static void get_encoding_rules(private_traffic_selector_substructure_t *this, encoding_rule_t **rules, size_t *rule_count)
{
*rules = traffic_selector_substructure_encodings;
*rule_count = sizeof(traffic_selector_substructure_encodings) / sizeof(encoding_rule_t);
}
/**
* Implementation of payload_t.get_type.
*/
static payload_type_t get_payload_type(private_traffic_selector_substructure_t *this)
{
return TRAFFIC_SELECTOR_SUBSTRUCTURE;
}
/**
* Implementation of payload_t.get_next_type.
*/
static payload_type_t get_next_type(private_traffic_selector_substructure_t *this)
{
return 0;
}
/**
* Implementation of payload_t.set_next_type.
*/
static void set_next_type(private_traffic_selector_substructure_t *this,payload_type_t type)
{
}
/**
* Implementation of payload_t.get_length.
*/
static size_t get_length(private_traffic_selector_substructure_t *this)
{
return this->payload_length;
}
/**
* Implementation of traffic_selector_substructure_t.get_traffic_selector.
*/
static traffic_selector_t *get_traffic_selector(private_traffic_selector_substructure_t *this)
{
traffic_selector_t *ts;
ts = traffic_selector_create_from_bytes(this->ip_protocol_id, this->ts_type,
this->starting_address, this->start_port,
this->ending_address, this->end_port);
return ts;
}
/**
* recompute length field of the payload
*/
void compute_length(private_traffic_selector_substructure_t *this)
{
this->payload_length = TRAFFIC_SELECTOR_HEADER_LENGTH +
this->ending_address.len + this->starting_address.len;
}
/**
* Implementation of payload_t.destroy and traffic_selector_substructure_t.destroy.
*/
static void destroy(private_traffic_selector_substructure_t *this)
{
free(this->starting_address.ptr);
free(this->ending_address.ptr);
free(this);
}
/*
* Described in header
*/
traffic_selector_substructure_t *traffic_selector_substructure_create()
{
private_traffic_selector_substructure_t *this = malloc_thing(private_traffic_selector_substructure_t);
/* interface functions */
this->public.payload_interface.verify = (status_t (*) (payload_t *))verify;
this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules;
this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length;
this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type;
this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type;
this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_payload_type;
this->public.payload_interface.destroy = (void (*) (payload_t *))destroy;
/* public functions */
this->public.get_traffic_selector = (traffic_selector_t* (*)(traffic_selector_substructure_t*))get_traffic_selector;
this->public.destroy = (void (*) (traffic_selector_substructure_t *)) destroy;
/* private variables */
this->payload_length = TRAFFIC_SELECTOR_HEADER_LENGTH;
this->start_port = 0;
this->end_port = 0;
this->starting_address = chunk_empty;
this->ending_address = chunk_empty;
this->ip_protocol_id = 0;
/* must be set to be valid */
this->ts_type = TS_IPV4_ADDR_RANGE;
return (&(this->public));
}
/*
* Described in header
*/
traffic_selector_substructure_t *traffic_selector_substructure_create_from_traffic_selector(traffic_selector_t *traffic_selector)
{
private_traffic_selector_substructure_t *this = (private_traffic_selector_substructure_t*)traffic_selector_substructure_create();
this->ts_type = traffic_selector->get_type(traffic_selector);
this->ip_protocol_id = traffic_selector->get_protocol(traffic_selector);
this->start_port = traffic_selector->get_from_port(traffic_selector);
this->end_port = traffic_selector->get_to_port(traffic_selector);
this->starting_address = chunk_clone(traffic_selector->get_from_address(traffic_selector));
this->ending_address = chunk_clone(traffic_selector->get_to_address(traffic_selector));
compute_length(this);
return &(this->public);
}
@@ -0,0 +1,151 @@
/*
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup traffic_selector_substructure traffic_selector_substructure
* @{ @ingroup payloads
*/
#ifndef TRAFFIC_SELECTOR_SUBSTRUCTURE_H_
#define TRAFFIC_SELECTOR_SUBSTRUCTURE_H_
typedef struct traffic_selector_substructure_t traffic_selector_substructure_t;
#include <library.h>
#include <utils/host.h>
#include <selectors/traffic_selector.h>
#include <encoding/payloads/payload.h>
/**
* Length of a TRAFFIC SELECTOR SUBSTRUCTURE without start and end address.
*/
#define TRAFFIC_SELECTOR_HEADER_LENGTH 8
/**
* Class representing an IKEv2 TRAFFIC SELECTOR.
*
* The TRAFFIC SELECTOR format is described in RFC section 3.13.1.
*/
struct traffic_selector_substructure_t {
/**
* The payload_t interface.
*/
payload_t payload_interface;
/**
* Get the type of Traffic selector.
*
* @return type of traffic selector
*
*/
ts_type_t (*get_ts_type) (traffic_selector_substructure_t *this);
/**
* Set the type of Traffic selector.
*
* @param ts_type type of traffic selector
*/
void (*set_ts_type) (traffic_selector_substructure_t *this,
ts_type_t ts_type);
/**
* Get the IP protocol ID of Traffic selector.
*
* @return type of traffic selector
*
*/
u_int8_t (*get_protocol_id) (traffic_selector_substructure_t *this);
/**
* Set the IP protocol ID of Traffic selector
*
* @param protocol_id protocol ID of traffic selector
*/
void (*set_protocol_id) (traffic_selector_substructure_t *this,
u_int8_t protocol_id);
/**
* Get the start port and address as host_t object.
*
* Returned host_t object has to get destroyed by the caller.
*
* @return start host as host_t object
*
*/
host_t *(*get_start_host) (traffic_selector_substructure_t *this);
/**
* Set the start port and address as host_t object.
*
* @param start_host start host as host_t object
*/
void (*set_start_host) (traffic_selector_substructure_t *this,
host_t *start_host);
/**
* Get the end port and address as host_t object.
*
* Returned host_t object has to get destroyed by the caller.
*
* @return end host as host_t object
*
*/
host_t *(*get_end_host) (traffic_selector_substructure_t *this);
/**
* Set the end port and address as host_t object.
*
* @param end_host end host as host_t object
*/
void (*set_end_host) (traffic_selector_substructure_t *this,
host_t *end_host);
/**
* Get a traffic_selector_t from this substructure.
*
* @warning traffic_selector_t must be destroyed after usage.
*
* @return contained traffic_selector_t
*/
traffic_selector_t *(*get_traffic_selector) (
traffic_selector_substructure_t *this);
/**
* Destroys an traffic_selector_substructure_t object.
*/
void (*destroy) (traffic_selector_substructure_t *this);
};
/**
* Creates an empty traffic_selector_substructure_t object.
*
* TS type is set to default TS_IPV4_ADDR_RANGE!
*
* @return traffic_selector_substructure_t object
*/
traffic_selector_substructure_t *traffic_selector_substructure_create(void);
/**
* Creates an initialized traffif selector substructure using
* the values from a traffic_selector_t.
*
* @param traffic_selector traffic_selector_t to use for initialization
* @return traffic_selector_substructure_t object
*/
traffic_selector_substructure_t *traffic_selector_substructure_create_from_traffic_selector(
traffic_selector_t *traffic_selector);
#endif /** TRAFFIC_SELECTOR_SUBSTRUCTURE_H_ @}*/
@@ -0,0 +1,325 @@
/*
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <string.h>
#include <stddef.h>
#include "transform_attribute.h"
#include <encoding/payloads/encodings.h>
#include <library.h>
typedef struct private_transform_attribute_t private_transform_attribute_t;
/**
* Private data of an transform_attribute_t object.
*
*/
struct private_transform_attribute_t {
/**
* Public transform_attribute_t interface.
*/
transform_attribute_t public;
/**
* Attribute Format Flag.
*
* - TRUE means value is stored in attribute_length_or_value
* - FALSE means value is stored in attribute_value
*/
bool attribute_format;
/**
* Type of the attribute.
*/
u_int16_t attribute_type;
/**
* Attribute Length if attribute_format is 0, attribute Value otherwise.
*/
u_int16_t attribute_length_or_value;
/**
* Attribute value as chunk if attribute_format is 0 (FALSE).
*/
chunk_t attribute_value;
};
ENUM_BEGIN(transform_attribute_type_name, ATTRIBUTE_UNDEFINED, ATTRIBUTE_UNDEFINED,
"ATTRIBUTE_UNDEFINED");
ENUM_NEXT(transform_attribute_type_name, KEY_LENGTH, KEY_LENGTH, ATTRIBUTE_UNDEFINED,
"KEY_LENGTH");
ENUM_END(transform_attribute_type_name, KEY_LENGTH);
/**
* Encoding rules to parse or generate a Transform attribute.
*
* The defined offsets are the positions in a object of type
* private_transform_attribute_t.
*
*/
encoding_rule_t transform_attribute_encodings[] = {
/* Flag defining the format of this payload */
{ ATTRIBUTE_FORMAT, offsetof(private_transform_attribute_t, attribute_format) },
/* type of the attribute as 15 bit unsigned integer */
{ ATTRIBUTE_TYPE, offsetof(private_transform_attribute_t, attribute_type) },
/* Length or value, depending on the attribute format flag */
{ ATTRIBUTE_LENGTH_OR_VALUE, offsetof(private_transform_attribute_t, attribute_length_or_value) },
/* Value of attribute if attribute format flag is zero */
{ ATTRIBUTE_VALUE, offsetof(private_transform_attribute_t, attribute_value) }
};
/*
1 2 3
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
!A! Attribute Type ! AF=0 Attribute Length !
!F! ! AF=1 Attribute Value !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! AF=0 Attribute Value !
! AF=1 Not Transmitted !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
/**
* Implementation of payload_t.verify.
*/
static status_t verify(private_transform_attribute_t *this)
{
if (this->attribute_type != KEY_LENGTH)
{
return FAILED;
}
return SUCCESS;
}
/**
* Implementation of payload_t.get_encoding_rules.
*/
static void get_encoding_rules(private_transform_attribute_t *this, encoding_rule_t **rules, size_t *rule_count)
{
*rules = transform_attribute_encodings;
*rule_count = sizeof(transform_attribute_encodings) / sizeof(encoding_rule_t);
}
/**
* Implementation of payload_t.get_type.
*/
static payload_type_t get_type(private_transform_attribute_t *this)
{
return TRANSFORM_ATTRIBUTE;
}
/**
* Implementation of payload_t.get_next_type.
*/
static payload_type_t get_next_type(private_transform_attribute_t *this)
{
return (NO_PAYLOAD);
}
/**
* Implementation of payload_t.set_next_type.
*/
static void set_next_type(private_transform_attribute_t *this,payload_type_t type)
{
}
/**
* Implementation of transform_attribute_t.get_length.
*/
static size_t get_length(private_transform_attribute_t *this)
{
if (this->attribute_format == TRUE)
{
/*Attribute size is only 4 byte */
return 4;
}
return (this->attribute_length_or_value + 4);
}
/**
* Implementation of transform_attribute_t.set_value_chunk.
*/
static void set_value_chunk(private_transform_attribute_t *this, chunk_t value)
{
if (this->attribute_value.ptr != NULL)
{
/* free existing value */
free(this->attribute_value.ptr);
this->attribute_value.ptr = NULL;
this->attribute_value.len = 0;
}
if (value.len > 2)
{
this->attribute_value.ptr = clalloc(value.ptr,value.len);
this->attribute_value.len = value.len;
this->attribute_length_or_value = value.len;
/* attribute has not a fixed length */
this->attribute_format = FALSE;
}
else
{
memcpy(&(this->attribute_length_or_value),value.ptr,value.len);
}
}
/**
* Implementation of transform_attribute_t.set_value.
*/
static void set_value(private_transform_attribute_t *this, u_int16_t value)
{
if (this->attribute_value.ptr != NULL)
{
/* free existing value */
free(this->attribute_value.ptr);
this->attribute_value.ptr = NULL;
this->attribute_value.len = 0;
}
this->attribute_length_or_value = value;
}
/**
* Implementation of transform_attribute_t.get_value_chunk.
*/
static chunk_t get_value_chunk (private_transform_attribute_t *this)
{
chunk_t value;
if (this->attribute_format == FALSE)
{
value.ptr = this->attribute_value.ptr;
value.len = this->attribute_value.len;
}
else
{
value.ptr = (void *) &(this->attribute_length_or_value);
value.len = 2;
}
return value;
}
/**
* Implementation of transform_attribute_t.get_value.
*/
static u_int16_t get_value (private_transform_attribute_t *this)
{
return this->attribute_length_or_value;
}
/**
* Implementation of transform_attribute_t.set_attribute_type.
*/
static void set_attribute_type (private_transform_attribute_t *this, u_int16_t type)
{
this->attribute_type = type & 0x7FFF;
}
/**
* Implementation of transform_attribute_t.get_attribute_type.
*/
static u_int16_t get_attribute_type (private_transform_attribute_t *this)
{
return this->attribute_type;
}
/**
* Implementation of transform_attribute_t.clone.
*/
static transform_attribute_t * _clone(private_transform_attribute_t *this)
{
private_transform_attribute_t *new_clone;
new_clone = (private_transform_attribute_t *) transform_attribute_create();
new_clone->attribute_format = this->attribute_format;
new_clone->attribute_type = this->attribute_type;
new_clone->attribute_length_or_value = this->attribute_length_or_value;
if (!new_clone->attribute_format)
{
new_clone->attribute_value.ptr = clalloc(this->attribute_value.ptr,this->attribute_value.len);
new_clone->attribute_value.len = this->attribute_value.len;
}
return (transform_attribute_t *) new_clone;
}
/**
* Implementation of transform_attribute_t.destroy and payload_t.destroy.
*/
static void destroy(private_transform_attribute_t *this)
{
if (this->attribute_value.ptr != NULL)
{
free(this->attribute_value.ptr);
}
free(this);
}
/*
* Described in header.
*/
transform_attribute_t *transform_attribute_create()
{
private_transform_attribute_t *this = malloc_thing(private_transform_attribute_t);
/* payload interface */
this->public.payload_interface.verify = (status_t (*) (payload_t *))verify;
this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules;
this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length;
this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type;
this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type;
this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_type;
this->public.payload_interface.destroy = (void (*) (payload_t *))destroy;
/* public functions */
this->public.set_value_chunk = (void (*) (transform_attribute_t *,chunk_t)) set_value_chunk;
this->public.set_value = (void (*) (transform_attribute_t *,u_int16_t)) set_value;
this->public.get_value_chunk = (chunk_t (*) (transform_attribute_t *)) get_value_chunk;
this->public.get_value = (u_int16_t (*) (transform_attribute_t *)) get_value;
this->public.set_attribute_type = (void (*) (transform_attribute_t *,u_int16_t type)) set_attribute_type;
this->public.get_attribute_type = (u_int16_t (*) (transform_attribute_t *)) get_attribute_type;
this->public.clone = (transform_attribute_t * (*) (transform_attribute_t *)) _clone;
this->public.destroy = (void (*) (transform_attribute_t *)) destroy;
/* set default values of the fields */
this->attribute_format = TRUE;
this->attribute_type = 0;
this->attribute_length_or_value = 0;
this->attribute_value.ptr = NULL;
this->attribute_value.len = 0;
return (&(this->public));
}
/*
* Described in header.
*/
transform_attribute_t *transform_attribute_create_key_length(u_int16_t key_length)
{
transform_attribute_t *attribute = transform_attribute_create();
attribute->set_attribute_type(attribute,KEY_LENGTH);
attribute->set_value(attribute,key_length);
return attribute;
}
@@ -0,0 +1,132 @@
/*
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup transform_attribute transform_attribute
* @{ @ingroup payloads
*/
#ifndef TRANSFORM_ATTRIBUTE_H_
#define TRANSFORM_ATTRIBUTE_H_
typedef enum transform_attribute_type_t transform_attribute_type_t;
typedef struct transform_attribute_t transform_attribute_t;
#include <library.h>
#include <encoding/payloads/payload.h>
/**
* Type of the attribute, as in IKEv2 RFC 3.3.5.
*/
enum transform_attribute_type_t {
ATTRIBUTE_UNDEFINED = 16384,
KEY_LENGTH = 14
};
/**
* enum name for transform_attribute_type_t.
*/
extern enum_name_t *transform_attribute_type_names;
/**
* Class representing an IKEv2- TRANSFORM Attribute.
*
* The TRANSFORM ATTRIBUTE format is described in RFC section 3.3.5.
*/
struct transform_attribute_t {
/**
* The payload_t interface.
*/
payload_t payload_interface;
/**
* Returns the currently set value of the attribute.
*
* Returned data are not copied.
*
* @return chunk_t pointing to the value
*/
chunk_t (*get_value_chunk) (transform_attribute_t *this);
/**
* Returns the currently set value of the attribute.
*
* Returned data are not copied.
*
* @return value
*/
u_int16_t (*get_value) (transform_attribute_t *this);
/**
* Sets the value of the attribute.
*
* Value is getting copied.
*
* @param value chunk_t pointing to the value to set
*/
void (*set_value_chunk) (transform_attribute_t *this, chunk_t value);
/**
* Sets the value of the attribute.
*
* @param value value to set
*/
void (*set_value) (transform_attribute_t *this, u_int16_t value);
/**
* Sets the type of the attribute.
*
* @param type type to set (most significant bit is set to zero)
*/
void (*set_attribute_type) (transform_attribute_t *this, u_int16_t type);
/**
* get the type of the attribute.
*
* @return type of the value
*/
u_int16_t (*get_attribute_type) (transform_attribute_t *this);
/**
* Clones an transform_attribute_t object.
*
* @return cloned transform_attribute_t object
*/
transform_attribute_t * (*clone) (transform_attribute_t *this);
/**
* Destroys an transform_attribute_t object.
*/
void (*destroy) (transform_attribute_t *this);
};
/**
* Creates an empty transform_attribute_t object.
*
* @return transform_attribute_t object
*/
transform_attribute_t *transform_attribute_create(void);
/**
* Creates an transform_attribute_t of type KEY_LENGTH.
*
* @param key_length key length in bytes
* @return transform_attribute_t object
*/
transform_attribute_t *transform_attribute_create_key_length(u_int16_t key_length);
#endif /** TRANSFORM_ATTRIBUTE_H_ @}*/
@@ -0,0 +1,402 @@
/*
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <stddef.h>
#include "transform_substructure.h"
#include <encoding/payloads/transform_attribute.h>
#include <encoding/payloads/encodings.h>
#include <library.h>
#include <utils/linked_list.h>
#include <daemon.h>
typedef struct private_transform_substructure_t private_transform_substructure_t;
/**
* Private data of an transform_substructure_t object.
*
*/
struct private_transform_substructure_t {
/**
* Public transform_substructure_t interface.
*/
transform_substructure_t public;
/**
* Next payload type.
*/
u_int8_t next_payload;
/**
* Length of this payload.
*/
u_int16_t transform_length;
/**
* Type of the transform.
*/
u_int8_t transform_type;
/**
* Transform ID.
*/
u_int16_t transform_id;
/**
* Transforms Attributes are stored in a linked_list_t.
*/
linked_list_t *attributes;
};
/**
* Encoding rules to parse or generate a Transform substructure.
*
* The defined offsets are the positions in a object of type
* private_transform_substructure_t.
*
*/
encoding_rule_t transform_substructure_encodings[] = {
/* 1 Byte next payload type, stored in the field next_payload */
{ U_INT_8, offsetof(private_transform_substructure_t, next_payload) },
/* Reserved Byte is skipped */
{ RESERVED_BYTE, 0 },
/* Length of the whole transform substructure*/
{ PAYLOAD_LENGTH, offsetof(private_transform_substructure_t, transform_length) },
/* transform type is a number of 8 bit */
{ U_INT_8, offsetof(private_transform_substructure_t, transform_type) },
/* Reserved Byte is skipped */
{ RESERVED_BYTE, 0 },
/* tranform ID is a number of 8 bit */
{ U_INT_16, offsetof(private_transform_substructure_t, transform_id) },
/* Attributes are stored in a transform attribute,
offset points to a linked_list_t pointer */
{ TRANSFORM_ATTRIBUTES, offsetof(private_transform_substructure_t, attributes) }
};
/*
1 2 3
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 0 (last) or 3 ! RESERVED ! Transform Length !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
!Transform Type ! RESERVED ! Transform ID !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! !
~ Transform Attributes ~
! !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
/**
* Implementation of payload_t.verify.
*/
static status_t verify(private_transform_substructure_t *this)
{
status_t status = SUCCESS;
iterator_t *iterator;
payload_t *current_attributes;
if ((this->next_payload != NO_PAYLOAD) && (this->next_payload != 3))
{
/* must be 0 or 3 */
DBG1(DBG_ENC, "inconsistent next payload");
return FAILED;
}
switch (this->transform_type)
{
case ENCRYPTION_ALGORITHM:
case PSEUDO_RANDOM_FUNCTION:
case INTEGRITY_ALGORITHM:
case DIFFIE_HELLMAN_GROUP:
case EXTENDED_SEQUENCE_NUMBERS:
/* we don't check transform ID, we want to reply
* cleanly with NO_PROPOSAL_CHOSEN or so if we don't support it */
break;
default:
{
DBG1(DBG_ENC, "invalid transform type: %d", this->transform_type);
return FAILED;
}
}
iterator = this->attributes->create_iterator(this->attributes,TRUE);
while(iterator->iterate(iterator, (void**)&current_attributes))
{
status = current_attributes->verify(current_attributes);
if (status != SUCCESS)
{
DBG1(DBG_ENC, "TRANSFORM_ATTRIBUTE verification failed");
}
}
iterator->destroy(iterator);
/* proposal number is checked in SA payload */
return status;
}
/**
* Implementation of payload_t.get_encoding_rules.
*/
static void get_encoding_rules(private_transform_substructure_t *this, encoding_rule_t **rules, size_t *rule_count)
{
*rules = transform_substructure_encodings;
*rule_count = sizeof(transform_substructure_encodings) / sizeof(encoding_rule_t);
}
/**
* Implementation of payload_t.get_type.
*/
static payload_type_t get_type(private_transform_substructure_t *this)
{
return TRANSFORM_SUBSTRUCTURE;
}
/**
* Implementation of payload_t.get_next_type.
*/
static payload_type_t get_next_type(private_transform_substructure_t *this)
{
return (this->next_payload);
}
/**
* recompute the length of the payload.
*/
static void compute_length (private_transform_substructure_t *this)
{
iterator_t *iterator;
payload_t *current_attribute;
size_t length = TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH;
iterator = this->attributes->create_iterator(this->attributes,TRUE);
while (iterator->iterate(iterator, (void**)&current_attribute))
{
length += current_attribute->get_length(current_attribute);
}
iterator->destroy(iterator);
this->transform_length = length;
}
/**
* Implementation of payload_t.get_length.
*/
static size_t get_length(private_transform_substructure_t *this)
{
compute_length(this);
return this->transform_length;
}
/**
* Implementation of transform_substructure_t.create_transform_attribute_iterator.
*/
static iterator_t *create_transform_attribute_iterator (private_transform_substructure_t *this,bool forward)
{
return this->attributes->create_iterator(this->attributes,forward);
}
/**
* Implementation of transform_substructure_t.add_transform_attribute.
*/
static void add_transform_attribute (private_transform_substructure_t *this,transform_attribute_t *attribute)
{
this->attributes->insert_last(this->attributes,(void *) attribute);
compute_length(this);
}
/**
* Implementation of transform_substructure_t.set_is_last_transform.
*/
static void set_is_last_transform (private_transform_substructure_t *this, bool is_last)
{
this->next_payload = (is_last) ? 0: TRANSFORM_TYPE_VALUE;
}
/**
* Implementation of transform_substructure_t.get_is_last_transform.
*/
static bool get_is_last_transform (private_transform_substructure_t *this)
{
return ((this->next_payload == TRANSFORM_TYPE_VALUE) ? FALSE : TRUE);
}
/**
* Implementation of payload_t.set_next_type.
*/
static void set_next_type(private_transform_substructure_t *this,payload_type_t type)
{
}
/**
* Implementation of transform_substructure_t.set_transform_type.
*/
static void set_transform_type (private_transform_substructure_t *this,u_int8_t type)
{
this->transform_type = type;
}
/**
* Implementation of transform_substructure_t.get_transform_type.
*/
static u_int8_t get_transform_type (private_transform_substructure_t *this)
{
return this->transform_type;
}
/**
* Implementation of transform_substructure_t.set_transform_id.
*/
static void set_transform_id (private_transform_substructure_t *this,u_int16_t id)
{
this->transform_id = id;
}
/**
* Implementation of transform_substructure_t.get_transform_id.
*/
static u_int16_t get_transform_id (private_transform_substructure_t *this)
{
return this->transform_id;
}
/**
* Implementation of transform_substructure_t.clone.
*/
static transform_substructure_t *clone_(private_transform_substructure_t *this)
{
private_transform_substructure_t *clone;
iterator_t *attributes;
transform_attribute_t *current_attribute;
clone = (private_transform_substructure_t *) transform_substructure_create();
clone->next_payload = this->next_payload;
clone->transform_type = this->transform_type;
clone->transform_id = this->transform_id;
attributes = this->attributes->create_iterator(this->attributes, FALSE);
while (attributes->iterate(attributes, (void**)&current_attribute))
{
current_attribute = current_attribute->clone(current_attribute);
clone->public.add_transform_attribute(&clone->public, current_attribute);
}
attributes->destroy(attributes);
return &clone->public;
}
/**
* Implementation of transform_substructure_t.get_key_length.
*/
static status_t get_key_length(private_transform_substructure_t *this, u_int16_t *key_length)
{
iterator_t *attributes;
transform_attribute_t *current_attribute;
attributes = this->attributes->create_iterator(this->attributes, TRUE);
while (attributes->iterate(attributes, (void**)&current_attribute))
{
if (current_attribute->get_attribute_type(current_attribute) == KEY_LENGTH)
{
*key_length = current_attribute->get_value(current_attribute);
attributes->destroy(attributes);
return SUCCESS;
}
}
attributes->destroy(attributes);
return FAILED;
}
/**
* Implementation of transform_substructure_t.destroy and payload_t.destroy.
*/
static void destroy(private_transform_substructure_t *this)
{
this->attributes->destroy_offset(this->attributes,
offsetof(transform_attribute_t, destroy));
free(this);
}
/*
* Described in header.
*/
transform_substructure_t *transform_substructure_create()
{
private_transform_substructure_t *this = malloc_thing(private_transform_substructure_t);
/* payload interface */
this->public.payload_interface.verify = (status_t (*) (payload_t *))verify;
this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules;
this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length;
this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type;
this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type;
this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_type;
this->public.payload_interface.destroy = (void (*) (payload_t *))destroy;
/* public functions */
this->public.create_transform_attribute_iterator = (iterator_t * (*) (transform_substructure_t *,bool)) create_transform_attribute_iterator;
this->public.add_transform_attribute = (void (*) (transform_substructure_t *,transform_attribute_t *)) add_transform_attribute;
this->public.set_is_last_transform = (void (*) (transform_substructure_t *,bool)) set_is_last_transform;
this->public.get_is_last_transform = (bool (*) (transform_substructure_t *)) get_is_last_transform;
this->public.set_transform_type = (void (*) (transform_substructure_t *,u_int8_t)) set_transform_type;
this->public.get_transform_type = (u_int8_t (*) (transform_substructure_t *)) get_transform_type;
this->public.set_transform_id = (void (*) (transform_substructure_t *,u_int16_t)) set_transform_id;
this->public.get_transform_id = (u_int16_t (*) (transform_substructure_t *)) get_transform_id;
this->public.get_key_length = (status_t (*) (transform_substructure_t *,u_int16_t *)) get_key_length;
this->public.clone = (transform_substructure_t* (*) (transform_substructure_t *)) clone_;
this->public.destroy = (void (*) (transform_substructure_t *)) destroy;
/* set default values of the fields */
this->next_payload = NO_PAYLOAD;
this->transform_length = TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH;
this->transform_id = 0;
this->transform_type = 0;
this->attributes = linked_list_create();
return (&(this->public));
}
/*
* Described in header
*/
transform_substructure_t *transform_substructure_create_type(
transform_type_t transform_type,
u_int16_t transform_id, u_int16_t key_length)
{
transform_substructure_t *transform = transform_substructure_create();
transform->set_transform_type(transform,transform_type);
transform->set_transform_id(transform,transform_id);
if (key_length)
{
transform_attribute_t *attribute;
attribute = transform_attribute_create_key_length(key_length);
transform->add_transform_attribute(transform, attribute);
}
return transform;
}
@@ -0,0 +1,174 @@
/*
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup transform_substructure transform_substructure
* @{ @ingroup payloads
*/
#ifndef TRANSFORM_SUBSTRUCTURE_H_
#define TRANSFORM_SUBSTRUCTURE_H_
typedef struct transform_substructure_t transform_substructure_t;
#include <library.h>
#include <encoding/payloads/payload.h>
#include <encoding/payloads/transform_attribute.h>
#include <utils/linked_list.h>
#include <crypto/diffie_hellman.h>
#include <crypto/signers/signer.h>
#include <crypto/prfs/prf.h>
#include <crypto/crypters/crypter.h>
#include <config/proposal.h>
/**
* IKEv1 Value for a transform payload.
*/
#define TRANSFORM_TYPE_VALUE 3
/**
* Length of the transform substructure header in bytes.
*/
#define TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH 8
/**
* Class representing an IKEv2- TRANSFORM SUBSTRUCTURE.
*
* The TRANSFORM SUBSTRUCTURE format is described in RFC section 3.3.2.
*/
struct transform_substructure_t {
/**
* The payload_t interface.
*/
payload_t payload_interface;
/**
* Creates an iterator of stored transform_attribute_t objects.
*
* When deleting an transform attribute using this iterator,
* the length of this transform substructure has to be refreshed
* by calling get_length().
*
* @param forward iterator direction (TRUE: front to end)
* @return created iterator_t object.
*/
iterator_t * (*create_transform_attribute_iterator) (
transform_substructure_t *this, bool forward);
/**
* Adds a transform_attribute_t object to this object.
*
* @param proposal transform_attribute_t object to add
*/
void (*add_transform_attribute) (transform_substructure_t *this,
transform_attribute_t *attribute);
/**
* Sets the next_payload field of this substructure
*
* If this is the last transform, next payload field is set to 0,
* otherwise to 3
*
* @param is_last When TRUE, next payload field is set to 0, otherwise to 3
*/
void (*set_is_last_transform) (transform_substructure_t *this, bool is_last);
/**
* Checks if this is the last transform.
*
* @return TRUE if this is the last Transform, FALSE otherwise
*/
bool (*get_is_last_transform) (transform_substructure_t *this);
/**
* Sets transform type of the current transform substructure.
*
* @param type type value to set
*/
void (*set_transform_type) (transform_substructure_t *this, u_int8_t type);
/**
* get transform type of the current transform.
*
* @return Transform type of current transform substructure.
*/
u_int8_t (*get_transform_type) (transform_substructure_t *this);
/**
* Sets transform id of the current transform substructure.
*
* @param id transform id to set
*/
void (*set_transform_id) (transform_substructure_t *this, u_int16_t id);
/**
* get transform id of the current transform.
*
* @return Transform id of current transform substructure.
*/
u_int16_t (*get_transform_id) (transform_substructure_t *this);
/**
* get transform id of the current transform.
*
* @param key_length The key length is written to this location
* @return
* - SUCCESS if a key length attribute is contained
* - FAILED if no key length attribute is part of this
* transform or key length uses more then 16 bit!
*/
status_t (*get_key_length) (transform_substructure_t *this,
u_int16_t *key_length);
/**
* Clones an transform_substructure_t object.
*
* @return cloned transform_substructure_t object
*/
transform_substructure_t* (*clone) (transform_substructure_t *this);
/**
* Destroys an transform_substructure_t object.
*/
void (*destroy) (transform_substructure_t *this);
};
/**
* Creates an empty transform_substructure_t object.
*
* @return created transform_substructure_t object
*/
transform_substructure_t *transform_substructure_create(void);
/**
* Creates an empty transform_substructure_t object.
*
* The key length is used for the transport types ENCRYPTION_ALGORITHM,
* PSEUDO_RANDOM_FUNCTION, INTEGRITY_ALGORITHM. For all
* other transport types the key_length parameter is not used
*
* @param transform_type type of transform to create
* @param transform_id transform id specifying the specific algorithm of a transform type
* @param key_length Key length for key lenght attribute
* @return transform_substructure_t object
*/
transform_substructure_t *transform_substructure_create_type(
transform_type_t transform_type, u_int16_t transform_id,
u_int16_t key_length);
#endif /** TRANSFORM_SUBSTRUCTURE_H_ @}*/
@@ -0,0 +1,334 @@
/*
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <stddef.h>
#include "ts_payload.h"
#include <encoding/payloads/encodings.h>
#include <utils/linked_list.h>
typedef struct private_ts_payload_t private_ts_payload_t;
/**
* Private data of an ts_payload_t object.
*
*/
struct private_ts_payload_t {
/**
* Public ts_payload_t interface.
*/
ts_payload_t public;
/**
* TRUE if this TS payload is of type TSi, FALSE for TSr.
*/
bool is_initiator;
/**
* Next payload type.
*/
u_int8_t next_payload;
/**
* Critical flag.
*/
bool critical;
/**
* Length of this payload.
*/
u_int16_t payload_length;
/**
* Number of traffic selectors
*/
u_int8_t number_of_traffic_selectors;
/**
* Contains the traffic selectors of type traffic_selector_substructure_t.
*/
linked_list_t *traffic_selectors;
};
/**
* Encoding rules to parse or generate a TS payload
*
* The defined offsets are the positions in a object of type
* private_ts_payload_t.
*
*/
encoding_rule_t ts_payload_encodings[] = {
/* 1 Byte next payload type, stored in the field next_payload */
{ U_INT_8, offsetof(private_ts_payload_t, next_payload) },
/* the critical bit */
{ FLAG, offsetof(private_ts_payload_t, critical) },
/* 7 Bit reserved bits, nowhere stored */
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
/* Length of the whole payload*/
{ PAYLOAD_LENGTH, offsetof(private_ts_payload_t, payload_length)},
/* 1 Byte TS type*/
{ U_INT_8, offsetof(private_ts_payload_t, number_of_traffic_selectors) },
/* 3 reserved bytes */
{ RESERVED_BYTE, 0 },
{ RESERVED_BYTE, 0 },
{ RESERVED_BYTE, 0 },
/* some ts data bytes, length is defined in PAYLOAD_LENGTH */
{ TRAFFIC_SELECTORS, offsetof(private_ts_payload_t, traffic_selectors) }
};
/*
1 2 3
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! Next Payload !C! RESERVED ! Payload Length !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! Number of TSs ! RESERVED !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! !
~ <Traffic Selectors> ~
! !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
/**
* Implementation of payload_t.verify.
*/
static status_t verify(private_ts_payload_t *this)
{
iterator_t *iterator;
payload_t *current_traffic_selector;
status_t status = SUCCESS;
if (this->number_of_traffic_selectors != (this->traffic_selectors->get_count(this->traffic_selectors)))
{
/* must be the same */
return FAILED;
}
iterator = this->traffic_selectors->create_iterator(this->traffic_selectors,TRUE);
while(iterator->iterate(iterator, (void**)&current_traffic_selector))
{
status = current_traffic_selector->verify(current_traffic_selector);
if (status != SUCCESS)
{
break;
}
}
iterator->destroy(iterator);
return status;
}
/**
* Implementation of ts_payload_t.get_encoding_rules.
*/
static void get_encoding_rules(private_ts_payload_t *this, encoding_rule_t **rules, size_t *rule_count)
{
*rules = ts_payload_encodings;
*rule_count = sizeof(ts_payload_encodings) / sizeof(encoding_rule_t);
}
/**
* Implementation of payload_t.get_type.
*/
static payload_type_t get_payload_type(private_ts_payload_t *this)
{
if (this->is_initiator)
{
return TRAFFIC_SELECTOR_INITIATOR;
}
else
{
return TRAFFIC_SELECTOR_RESPONDER;
}
}
/**
* Implementation of payload_t.get_next_type.
*/
static payload_type_t get_next_type(private_ts_payload_t *this)
{
return (this->next_payload);
}
/**
* Implementation of payload_t.set_next_type.
*/
static void set_next_type(private_ts_payload_t *this,payload_type_t type)
{
this->next_payload = type;
}
/**
* recompute the length of the payload.
*/
static void compute_length (private_ts_payload_t *this)
{
iterator_t *iterator;
size_t ts_count = 0;
size_t length = TS_PAYLOAD_HEADER_LENGTH;
payload_t *current_traffic_selector;
iterator = this->traffic_selectors->create_iterator(this->traffic_selectors,TRUE);
while (iterator->iterate(iterator, (void**)&current_traffic_selector))
{
length += current_traffic_selector->get_length(current_traffic_selector);
ts_count++;
}
iterator->destroy(iterator);
this->number_of_traffic_selectors= ts_count;
this->payload_length = length;
}
/**
* Implementation of payload_t.get_length.
*/
static size_t get_length(private_ts_payload_t *this)
{
compute_length(this);
return this->payload_length;
}
/**
* Implementation of ts_payload_t.get_initiator.
*/
static bool get_initiator (private_ts_payload_t *this)
{
return (this->is_initiator);
}
/**
* Implementation of ts_payload_t.set_initiator.
*/
static void set_initiator (private_ts_payload_t *this,bool is_initiator)
{
this->is_initiator = is_initiator;
}
/**
* Implementation of ts_payload_t.add_traffic_selector_substructure.
*/
static void add_traffic_selector_substructure (private_ts_payload_t *this,traffic_selector_substructure_t *traffic_selector)
{
this->traffic_selectors->insert_last(this->traffic_selectors,traffic_selector);
this->number_of_traffic_selectors = this->traffic_selectors->get_count(this->traffic_selectors);
}
/**
* Implementation of ts_payload_t.create_traffic_selector_substructure_iterator.
*/
static iterator_t * create_traffic_selector_substructure_iterator (private_ts_payload_t *this, bool forward)
{
return this->traffic_selectors->create_iterator(this->traffic_selectors,forward);
}
/**
* Implementation of ts_payload_t.get_traffic_selectors.
*/
static linked_list_t *get_traffic_selectors(private_ts_payload_t *this)
{
traffic_selector_t *ts;
iterator_t *iterator;
traffic_selector_substructure_t *ts_substructure;
linked_list_t *ts_list = linked_list_create();
iterator = this->traffic_selectors->create_iterator(this->traffic_selectors, TRUE);
while (iterator->iterate(iterator, (void**)&ts_substructure))
{
ts = ts_substructure->get_traffic_selector(ts_substructure);
ts_list->insert_last(ts_list, (void*)ts);
}
iterator->destroy(iterator);
return ts_list;
}
/**
* Implementation of payload_t.destroy and ts_payload_t.destroy.
*/
static void destroy(private_ts_payload_t *this)
{
this->traffic_selectors->destroy_offset(this->traffic_selectors,
offsetof(payload_t, destroy));
free(this);
}
/*
* Described in header
*/
ts_payload_t *ts_payload_create(bool is_initiator)
{
private_ts_payload_t *this = malloc_thing(private_ts_payload_t);
/* interface functions */
this->public.payload_interface.verify = (status_t (*) (payload_t *))verify;
this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules;
this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length;
this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type;
this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type;
this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_payload_type;
this->public.payload_interface.destroy = (void (*) (payload_t *))destroy;
/* public functions */
this->public.destroy = (void (*) (ts_payload_t *)) destroy;
this->public.get_initiator = (bool (*) (ts_payload_t *)) get_initiator;
this->public.set_initiator = (void (*) (ts_payload_t *,bool)) set_initiator;
this->public.add_traffic_selector_substructure = (void (*) (ts_payload_t *,traffic_selector_substructure_t *)) add_traffic_selector_substructure;
this->public.create_traffic_selector_substructure_iterator = (iterator_t* (*) (ts_payload_t *,bool)) create_traffic_selector_substructure_iterator;
this->public.get_traffic_selectors = (linked_list_t *(*) (ts_payload_t *)) get_traffic_selectors;
/* private variables */
this->critical = FALSE;
this->next_payload = NO_PAYLOAD;
this->payload_length =TS_PAYLOAD_HEADER_LENGTH;
this->is_initiator = is_initiator;
this->number_of_traffic_selectors = 0;
this->traffic_selectors = linked_list_create();
return &(this->public);
}
/*
* Described in header
*/
ts_payload_t *ts_payload_create_from_traffic_selectors(bool is_initiator, linked_list_t *traffic_selectors)
{
iterator_t *iterator;
traffic_selector_t *ts;
traffic_selector_substructure_t *ts_substructure;
private_ts_payload_t *this;
this = (private_ts_payload_t*)ts_payload_create(is_initiator);
iterator = traffic_selectors->create_iterator(traffic_selectors, TRUE);
while (iterator->iterate(iterator, (void**)&ts))
{
ts_substructure = traffic_selector_substructure_create_from_traffic_selector(ts);
this->public.add_traffic_selector_substructure(&(this->public), ts_substructure);
}
iterator->destroy(iterator);
return &(this->public);
}
@@ -0,0 +1,127 @@
/*
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup ts_payload ts_payload
* @{ @ingroup payloads
*/
#ifndef TS_PAYLOAD_H_
#define TS_PAYLOAD_H_
typedef struct ts_payload_t ts_payload_t;
#include <library.h>
#include <utils/linked_list.h>
#include <selectors/traffic_selector.h>
#include <encoding/payloads/payload.h>
#include <encoding/payloads/traffic_selector_substructure.h>
/**
* Length of a TS payload without the Traffic selectors.
*/
#define TS_PAYLOAD_HEADER_LENGTH 8
/**
* Class representing an IKEv2 TS payload.
*
* The TS payload format is described in RFC section 3.13.
*/
struct ts_payload_t {
/**
* The payload_t interface.
*/
payload_t payload_interface;
/**
* Get the type of TSpayload (TSi or TSr).
*
* @return
* - TRUE if this payload is of type TSi
* - FALSE if this payload is of type TSr
*/
bool (*get_initiator) (ts_payload_t *this);
/**
* Set the type of TS payload (TSi or TSr).
*
* @param is_initiator
* - TRUE if this payload is of type TSi
* - FALSE if this payload is of type TSr
*/
void (*set_initiator) (ts_payload_t *this,bool is_initiator);
/**
* Adds a traffic_selector_substructure_t object to this object.
*
* @param traffic_selector traffic_selector_substructure_t object to add
*/
void (*add_traffic_selector_substructure) (ts_payload_t *this,
traffic_selector_substructure_t *traffic_selector);
/**
* Creates an iterator of stored traffic_selector_substructure_t objects.
*
* When removing an traffic_selector_substructure_t object
* using this iterator, the length of this payload
* has to get refreshed by calling payload_t.get_length!
*
* @param forward iterator direction (TRUE: front to end)
* @return created iterator_t object
*/
iterator_t *(*create_traffic_selector_substructure_iterator) (
ts_payload_t *this, bool forward);
/**
* Get a list of nested traffic selectors as traffic_selector_t.
*
* Resulting list and its traffic selectors must be destroyed after usage
*
* @return list of traffic selectors
*/
linked_list_t *(*get_traffic_selectors) (ts_payload_t *this);
/**
* Destroys an ts_payload_t object.
*/
void (*destroy) (ts_payload_t *this);
};
/**
* Creates an empty ts_payload_t object.
*
* @param is_initiator
* - TRUE if this payload is of type TSi
* - FALSE if this payload is of type TSr
* @return ts_payload_t object
*/
ts_payload_t *ts_payload_create(bool is_initiator);
/**
* Creates ts_payload with a list of traffic_selector_t
*
* @param is_initiator
* - TRUE if this payload is of type TSi
* - FALSE if this payload is of type TSr
* @param traffic_selectors list of traffic selectors to include
* @return ts_payload_t object
*/
ts_payload_t *ts_payload_create_from_traffic_selectors(bool is_initiator,
linked_list_t *traffic_selectors);
#endif /** TS_PAYLOAD_H_ @}*/
@@ -0,0 +1,201 @@
/*
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <stddef.h>
#include "unknown_payload.h"
typedef struct private_unknown_payload_t private_unknown_payload_t;
/**
* Private data of an unknown_payload_t object.
*/
struct private_unknown_payload_t {
/**
* Public unknown_payload_t interface.
*/
unknown_payload_t public;
/**
* Next payload type.
*/
u_int8_t next_payload;
/**
* Critical flag.
*/
bool critical;
/**
* Length of this payload.
*/
u_int16_t payload_length;
/**
* The contained data.
*/
chunk_t data;
};
/**
* Encoding rules to parse an payload which is not further specified.
*
* The defined offsets are the positions in a object of type
* private_unknown_payload_t.
*
*/
encoding_rule_t unknown_payload_encodings[] = {
/* 1 Byte next payload type, stored in the field next_payload */
{ U_INT_8, offsetof(private_unknown_payload_t, next_payload)},
/* the critical bit */
{ FLAG, offsetof(private_unknown_payload_t, critical) },
/* 7 Bit reserved bits, nowhere stored */
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
/* Length of the whole payload*/
{ PAYLOAD_LENGTH, offsetof(private_unknown_payload_t, payload_length)},
/* some unknown data bytes, length is defined in PAYLOAD_LENGTH */
{ UNKNOWN_DATA, offsetof(private_unknown_payload_t, data) }
};
/*
1 2 3
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! Next Payload !C! RESERVED ! Payload Length !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! !
~ Data of any type ~
! !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
/**
* Implementation of payload_t.verify.
*/
static status_t verify(private_unknown_payload_t *this)
{
/* can't do any checks, so we assume its good */
return SUCCESS;
}
/**
* Implementation of payload_t.get_encoding_rules.
*/
static void get_encoding_rules(private_unknown_payload_t *this, encoding_rule_t **rules, size_t *rule_count)
{
*rules = unknown_payload_encodings;
*rule_count = sizeof(unknown_payload_encodings) / sizeof(encoding_rule_t);
}
/**
* Implementation of payload_t.get_type.
*/
static payload_type_t get_payload_type(private_unknown_payload_t *this)
{
return UNKNOWN_PAYLOAD;
}
/**
* Implementation of payload_t.get_next_type.
*/
static payload_type_t get_next_type(private_unknown_payload_t *this)
{
return (this->next_payload);
}
/**
* Implementation of payload_t.set_next_type.
*/
static void set_next_type(private_unknown_payload_t *this,payload_type_t type)
{
this->next_payload = type;
}
/**
* Implementation of payload_t.get_length.
*/
static size_t get_length(private_unknown_payload_t *this)
{
return this->payload_length;
}
/**
* Implementation of unknown_payload_t.get_data.
*/
static bool is_critical(private_unknown_payload_t *this)
{
return this->critical;
}
/**
* Implementation of unknown_payload_t.get_data.
*/
static chunk_t get_data (private_unknown_payload_t *this)
{
return (this->data);
}
/**
* Implementation of payload_t.destroy and unknown_payload_t.destroy.
*/
static void destroy(private_unknown_payload_t *this)
{
if (this->data.ptr != NULL)
{
chunk_free(&(this->data));
}
free(this);
}
/*
* Described in header
*/
unknown_payload_t *unknown_payload_create()
{
private_unknown_payload_t *this = malloc_thing(private_unknown_payload_t);
/* interface functions */
this->public.payload_interface.verify = (status_t (*) (payload_t *))verify;
this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules;
this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length;
this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type;
this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type;
this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_payload_type;
this->public.payload_interface.destroy = (void (*) (payload_t *))destroy;
/* public functions */
this->public.destroy = (void (*) (unknown_payload_t *)) destroy;
this->public.is_critical = (bool (*) (unknown_payload_t *)) is_critical;
this->public.get_data = (chunk_t (*) (unknown_payload_t *)) get_data;
/* private variables */
this->critical = FALSE;
this->next_payload = NO_PAYLOAD;
this->payload_length = UNKNOWN_PAYLOAD_HEADER_LENGTH;
this->data = chunk_empty;
return (&(this->public));
}
@@ -0,0 +1,79 @@
/*
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup unknown_payload unknown_payload
* @{ @ingroup payloads
*/
#ifndef UNKNOWN_PAYLOAD_H_
#define UNKNOWN_PAYLOAD_H_
typedef struct unknown_payload_t unknown_payload_t;
#include <library.h>
#include <encoding/payloads/payload.h>
/**
* Header length of the unknown payload.
*/
#define UNKNOWN_PAYLOAD_HEADER_LENGTH 4
/**
* Payload which can't be processed further.
*
* When the parser finds an unknown payload, he builds an instance of
* this class. This allows further processing of this payload, such as
* a check for the critical bit in the header.
*/
struct unknown_payload_t {
/**
* The payload_t interface.
*/
payload_t payload_interface;
/**
* Get the raw data of this payload, without
* the generic payload header.
*
* Returned data are NOT copied and must not be freed.
*
* @return data as chunk_t
*/
chunk_t (*get_data) (unknown_payload_t *this);
/**
* Get the critical flag.
*
* @return TRUE if payload is critical, FALSE if not
*/
bool (*is_critical) (unknown_payload_t *this);
/**
* Destroys an unknown_payload_t object.
*/
void (*destroy) (unknown_payload_t *this);
};
/**
* Creates an empty unknown_payload_t object.
*
* @return unknown_payload_t object
*/
unknown_payload_t *unknown_payload_create(void);
#endif /** UNKNOWN_PAYLOAD_H_ @}*/
@@ -0,0 +1,195 @@
/*
* Copyright (C) 2005-2009 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <stddef.h>
#include "vendor_id_payload.h"
typedef struct private_vendor_id_payload_t private_vendor_id_payload_t;
/**
* Private data of an vendor_id_payload_t object.
*/
struct private_vendor_id_payload_t {
/**
* Public vendor_id_payload_t interface.
*/
vendor_id_payload_t public;
/**
* Next payload type.
*/
u_int8_t next_payload;
/**
* Critical flag.
*/
bool critical;
/**
* Length of this payload.
*/
u_int16_t payload_length;
/**
* The contained data.
*/
chunk_t data;
};
/**
* Encoding rules to parse or generate a VENDOR ID payload
*
* The defined offsets are the positions in a object of type
* private_vendor_id_payload_t.
*/
encoding_rule_t vendor_id_payload_encodings[] = {
/* 1 Byte next payload type, stored in the field next_payload */
{ U_INT_8, offsetof(private_vendor_id_payload_t, next_payload) },
/* the critical bit */
{ FLAG, offsetof(private_vendor_id_payload_t, critical) },
/* 7 Bit reserved bits, nowhere stored */
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
{ RESERVED_BIT, 0 },
/* Length of the whole payload*/
{ PAYLOAD_LENGTH, offsetof(private_vendor_id_payload_t, payload_length)},
/* some vendor_id data bytes, length is defined in PAYLOAD_LENGTH */
{ VID_DATA, offsetof(private_vendor_id_payload_t, data) }
};
/*
1 2 3
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! Next Payload !C! RESERVED ! Payload Length !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ !
~ VID Data ~
! !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
/**
* Implementation of payload_t.verify.
*/
static status_t verify(private_vendor_id_payload_t *this)
{
return SUCCESS;
}
/**
* Implementation of vendor_id_payload_t.get_encoding_rules.
*/
static void get_encoding_rules(private_vendor_id_payload_t *this,
encoding_rule_t **rules, size_t *rule_count)
{
*rules = vendor_id_payload_encodings;
*rule_count = sizeof(vendor_id_payload_encodings) / sizeof(encoding_rule_t);
}
/**
* Implementation of payload_t.get_type.
*/
static payload_type_t get_payload_type(private_vendor_id_payload_t *this)
{
return VENDOR_ID;
}
/**
* Implementation of payload_t.get_next_type.
*/
static payload_type_t get_next_type(private_vendor_id_payload_t *this)
{
return this->next_payload;
}
/**
* Implementation of payload_t.set_next_type.
*/
static void set_next_type(private_vendor_id_payload_t *this,payload_type_t type)
{
this->next_payload = type;
}
/**
* Implementation of payload_t.get_length.
*/
static size_t get_length(private_vendor_id_payload_t *this)
{
return this->payload_length;
}
/**
* Implementation of vendor_id_payload_t.get_data.
*/
static chunk_t get_data(private_vendor_id_payload_t *this)
{
return this->data;
}
/**
* Implementation of payload_t.destroy and vendor_id_payload_t.destroy.
*/
static void destroy(private_vendor_id_payload_t *this)
{
free(this->data.ptr);
free(this);
}
/*
* Described in header
*/
vendor_id_payload_t *vendor_id_payload_create()
{
private_vendor_id_payload_t *this = malloc_thing(private_vendor_id_payload_t);
this->public.payload_interface.verify = (status_t (*) (payload_t *))verify;
this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules;
this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length;
this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type;
this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type;
this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_payload_type;
this->public.payload_interface.destroy = (void (*) (payload_t *))destroy;
this->public.get_data = (chunk_t (*) (vendor_id_payload_t *)) get_data;
this->critical = FALSE;
this->next_payload = NO_PAYLOAD;
this->payload_length = VENDOR_ID_PAYLOAD_HEADER_LENGTH;
this->data = chunk_empty;
return &this->public;
}
/*
* Described in header
*/
vendor_id_payload_t *vendor_id_payload_create_data(chunk_t data)
{
private_vendor_id_payload_t *this;
this = (private_vendor_id_payload_t*)vendor_id_payload_create();
this->payload_length += data.len;
this->data = data;
return &this->public;
}
@@ -0,0 +1,70 @@
/*
* Copyright (C) 2005-2009 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup vendor_id_payload vendor_id_payload
* @{ @ingroup payloads
*/
#ifndef VENDOR_ID_PAYLOAD_H_
#define VENDOR_ID_PAYLOAD_H_
typedef struct vendor_id_payload_t vendor_id_payload_t;
#include <library.h>
#include <encoding/payloads/payload.h>
/**
* Length of a VENDOR ID payload without the VID data in bytes.
*/
#define VENDOR_ID_PAYLOAD_HEADER_LENGTH 4
/**
* Class representing an IKEv2 VENDOR ID payload.
*
* The VENDOR ID payload format is described in RFC section 3.12.
*/
struct vendor_id_payload_t {
/**
* The payload_t interface.
*/
payload_t payload_interface;
/**
* Get the VID data.
*
* @return VID data, pointing to an internal chunk_t
*/
chunk_t (*get_data)(vendor_id_payload_t *this);
};
/**
* Creates an empty Vendor ID payload.
*
* @return vendor ID payload
*/
vendor_id_payload_t *vendor_id_payload_create();
/**
* Creates a vendor ID payload using a chunk of data
*
* @param data data to use in vendor ID payload, gets owned by payload
* @return vendor ID payload
*/
vendor_id_payload_t *vendor_id_payload_create_data(chunk_t data);
#endif /** VENDOR_ID_PAYLOAD_H_ @}*/
+386
View File
@@ -0,0 +1,386 @@
/*
* Copyright (C) 2008-2009 Tobias Brunner
* Hochschule fuer Technik Rapperswil
* Copyright (C) 2010 Martin Willi
* Copyright (C) 2010 revosec AG
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "kernel_interface.h"
#include <daemon.h>
typedef struct private_kernel_interface_t private_kernel_interface_t;
/**
* Private data of a kernel_interface_t object.
*/
struct private_kernel_interface_t {
/**
* Public part of kernel_interface_t object.
*/
kernel_interface_t public;
/**
* ipsec interface
*/
kernel_ipsec_t *ipsec;
/**
* network interface
*/
kernel_net_t *net;
};
METHOD(kernel_interface_t, get_spi, status_t,
private_kernel_interface_t *this, host_t *src, host_t *dst,
protocol_id_t protocol, u_int32_t reqid, u_int32_t *spi)
{
if (!this->ipsec)
{
return NOT_SUPPORTED;
}
return this->ipsec->get_spi(this->ipsec, src, dst, protocol, reqid, spi);
}
METHOD(kernel_interface_t, get_cpi, status_t,
private_kernel_interface_t *this, host_t *src, host_t *dst,
u_int32_t reqid, u_int16_t *cpi)
{
if (!this->ipsec)
{
return NOT_SUPPORTED;
}
return this->ipsec->get_cpi(this->ipsec, src, dst, reqid, cpi);
}
METHOD(kernel_interface_t, add_sa, status_t,
private_kernel_interface_t *this, host_t *src, host_t *dst,
u_int32_t spi, protocol_id_t protocol, u_int32_t reqid,
lifetime_cfg_t *lifetime, u_int16_t enc_alg, chunk_t enc_key,
u_int16_t int_alg, chunk_t int_key, ipsec_mode_t mode, u_int16_t ipcomp,
u_int16_t cpi, bool encap, bool inbound, traffic_selector_t *src_ts,
traffic_selector_t *dst_ts)
{
if (!this->ipsec)
{
return NOT_SUPPORTED;
}
return this->ipsec->add_sa(this->ipsec, src, dst, spi, protocol, reqid,
lifetime, enc_alg, enc_key, int_alg, int_key, mode, ipcomp, cpi,
encap, inbound, src_ts, dst_ts);
}
METHOD(kernel_interface_t, update_sa, status_t,
private_kernel_interface_t *this, u_int32_t spi, protocol_id_t protocol,
u_int16_t cpi, host_t *src, host_t *dst, host_t *new_src, host_t *new_dst,
bool encap, bool new_encap)
{
if (!this->ipsec)
{
return NOT_SUPPORTED;
}
return this->ipsec->update_sa(this->ipsec, spi, protocol, cpi, src, dst,
new_src, new_dst, encap, new_encap);
}
METHOD(kernel_interface_t, query_sa, status_t,
private_kernel_interface_t *this, host_t *src, host_t *dst,
u_int32_t spi, protocol_id_t protocol, u_int64_t *bytes)
{
if (!this->ipsec)
{
return NOT_SUPPORTED;
}
return this->ipsec->query_sa(this->ipsec, src, dst, spi, protocol, bytes);
}
METHOD(kernel_interface_t, del_sa, status_t,
private_kernel_interface_t *this, host_t *src, host_t *dst, u_int32_t spi,
protocol_id_t protocol, u_int16_t cpi)
{
if (!this->ipsec)
{
return NOT_SUPPORTED;
}
return this->ipsec->del_sa(this->ipsec, src, dst, spi, protocol, cpi);
}
METHOD(kernel_interface_t, add_policy, status_t,
private_kernel_interface_t *this, host_t *src, host_t *dst,
traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
policy_dir_t direction, u_int32_t spi, protocol_id_t protocol,
u_int32_t reqid, ipsec_mode_t mode, u_int16_t ipcomp, u_int16_t cpi,
bool routed)
{
if (!this->ipsec)
{
return NOT_SUPPORTED;
}
return this->ipsec->add_policy(this->ipsec, src, dst, src_ts, dst_ts,
direction, spi, protocol, reqid, mode, ipcomp, cpi, routed);
}
METHOD(kernel_interface_t, query_policy, status_t,
private_kernel_interface_t *this, traffic_selector_t *src_ts,
traffic_selector_t *dst_ts, policy_dir_t direction, u_int32_t *use_time)
{
if (!this->ipsec)
{
return NOT_SUPPORTED;
}
return this->ipsec->query_policy(this->ipsec, src_ts, dst_ts,
direction, use_time);
}
METHOD(kernel_interface_t, del_policy, status_t,
private_kernel_interface_t *this, traffic_selector_t *src_ts,
traffic_selector_t *dst_ts, policy_dir_t direction, bool unrouted)
{
if (!this->ipsec)
{
return NOT_SUPPORTED;
}
return this->ipsec->del_policy(this->ipsec, src_ts, dst_ts,
direction, unrouted);
}
METHOD(kernel_interface_t, get_source_addr, host_t*,
private_kernel_interface_t *this, host_t *dest, host_t *src)
{
if (!this->net)
{
return NULL;
}
return this->net->get_source_addr(this->net, dest, src);
}
METHOD(kernel_interface_t, get_nexthop, host_t*,
private_kernel_interface_t *this, host_t *dest)
{
if (!this->net)
{
return NULL;
}
return this->net->get_nexthop(this->net, dest);
}
METHOD(kernel_interface_t, get_interface, char*,
private_kernel_interface_t *this, host_t *host)
{
if (!this->net)
{
return NULL;
}
return this->net->get_interface(this->net, host);
}
METHOD(kernel_interface_t, create_address_enumerator, enumerator_t*,
private_kernel_interface_t *this, bool include_down_ifaces,
bool include_virtual_ips)
{
if (!this->net)
{
return enumerator_create_empty();
}
return this->net->create_address_enumerator(this->net, include_down_ifaces,
include_virtual_ips);
}
METHOD(kernel_interface_t, add_ip, status_t,
private_kernel_interface_t *this, host_t *virtual_ip, host_t *iface_ip)
{
if (!this->net)
{
return NOT_SUPPORTED;
}
return this->net->add_ip(this->net, virtual_ip, iface_ip);
}
METHOD(kernel_interface_t, del_ip, status_t,
private_kernel_interface_t *this, host_t *virtual_ip)
{
if (!this->net)
{
return NOT_SUPPORTED;
}
return this->net->del_ip(this->net, virtual_ip);
}
METHOD(kernel_interface_t, add_route, status_t,
private_kernel_interface_t *this, chunk_t dst_net,
u_int8_t prefixlen, host_t *gateway, host_t *src_ip, char *if_name)
{
if (!this->net)
{
return NOT_SUPPORTED;
}
return this->net->add_route(this->net, dst_net, prefixlen, gateway,
src_ip, if_name);
}
METHOD(kernel_interface_t, del_route, status_t,
private_kernel_interface_t *this, chunk_t dst_net,
u_int8_t prefixlen, host_t *gateway, host_t *src_ip, char *if_name)
{
if (!this->net)
{
return NOT_SUPPORTED;
}
return this->net->del_route(this->net, dst_net, prefixlen, gateway,
src_ip, if_name);
}
METHOD(kernel_interface_t, bypass_socket, bool,
private_kernel_interface_t *this, int fd, int family)
{
if (!this->ipsec)
{
return FALSE;
}
return this->ipsec->bypass_socket(this->ipsec, fd, family);
}
METHOD(kernel_interface_t, get_address_by_ts, status_t,
private_kernel_interface_t *this, traffic_selector_t *ts, host_t **ip)
{
enumerator_t *addrs;
host_t *host;
int family;
bool found = FALSE;
DBG2(DBG_KNL, "getting a local address in traffic selector %R", ts);
/* if we have a family which includes localhost, we do not
* search for an IP, we use the default */
family = ts->get_type(ts) == TS_IPV4_ADDR_RANGE ? AF_INET : AF_INET6;
if (family == AF_INET)
{
host = host_create_from_string("127.0.0.1", 0);
}
else
{
host = host_create_from_string("::1", 0);
}
if (ts->includes(ts, host))
{
*ip = host_create_any(family);
host->destroy(host);
DBG2(DBG_KNL, "using host %H", *ip);
return SUCCESS;
}
host->destroy(host);
addrs = create_address_enumerator(this, TRUE, TRUE);
while (addrs->enumerate(addrs, (void**)&host))
{
if (ts->includes(ts, host))
{
found = TRUE;
*ip = host->clone(host);
break;
}
}
addrs->destroy(addrs);
if (!found)
{
DBG1(DBG_KNL, "no local address found in traffic selector %R", ts);
return FAILED;
}
DBG2(DBG_KNL, "using host %H", *ip);
return SUCCESS;
}
METHOD(kernel_interface_t, add_ipsec_interface, void,
private_kernel_interface_t *this, kernel_ipsec_constructor_t constructor)
{
if (!this->ipsec)
{
this->ipsec = constructor();
}
}
METHOD(kernel_interface_t, remove_ipsec_interface, void,
private_kernel_interface_t *this, kernel_ipsec_constructor_t constructor)
{
/* TODO: replace if interface currently in use */
}
METHOD(kernel_interface_t, add_net_interface, void,
private_kernel_interface_t *this, kernel_net_constructor_t constructor)
{
if (!this->net)
{
this->net = constructor();
}
}
METHOD(kernel_interface_t, remove_net_interface, void,
private_kernel_interface_t *this, kernel_net_constructor_t constructor)
{
/* TODO: replace if interface currently in use */
}
METHOD(kernel_interface_t, destroy, void,
private_kernel_interface_t *this)
{
DESTROY_IF(this->ipsec);
DESTROY_IF(this->net);
free(this);
}
/*
* Described in header-file
*/
kernel_interface_t *kernel_interface_create()
{
private_kernel_interface_t *this;
INIT(this,
.public = {
.get_spi = _get_spi,
.get_cpi = _get_cpi,
.add_sa = _add_sa,
.update_sa = _update_sa,
.query_sa = _query_sa,
.del_sa = _del_sa,
.add_policy = _add_policy,
.query_policy = _query_policy,
.del_policy = _del_policy,
.get_source_addr = _get_source_addr,
.get_nexthop = _get_nexthop,
.get_interface = _get_interface,
.create_address_enumerator = _create_address_enumerator,
.add_ip = _add_ip,
.del_ip = _del_ip,
.add_route = _add_route,
.del_route = _del_route,
.bypass_socket = _bypass_socket,
.get_address_by_ts = _get_address_by_ts,
.add_ipsec_interface = _add_ipsec_interface,
.remove_ipsec_interface = _remove_ipsec_interface,
.add_net_interface = _add_net_interface,
.remove_net_interface = _remove_net_interface,
.destroy = _destroy,
},
);
return &this->public;
}
+398
View File
@@ -0,0 +1,398 @@
/*
* Copyright (C) 2006-2009 Tobias Brunner
* Copyright (C) 2006 Daniel Roethlisberger
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup kernel_interface kernel_interface
* @{ @ingroup kernel
*/
#ifndef KERNEL_INTERFACE_H_
#define KERNEL_INTERFACE_H_
typedef struct kernel_interface_t kernel_interface_t;
#include <utils/host.h>
#include <crypto/prf_plus.h>
#include <encoding/payloads/proposal_substructure.h>
#include <kernel/kernel_ipsec.h>
#include <kernel/kernel_net.h>
/**
* Constructor function for ipsec kernel interface
*/
typedef kernel_ipsec_t* (*kernel_ipsec_constructor_t)(void);
/**
* Constructor function for network kernel interface
*/
typedef kernel_net_t* (*kernel_net_constructor_t)(void);
/**
* Manager and wrapper for different kernel interfaces.
*
* The kernel interface handles the communication with the kernel
* for SA and policy management and interface and IP address management.
*/
struct kernel_interface_t {
/**
* Get a SPI from the kernel.
*
* @param src source address of SA
* @param dst destination address of SA
* @param protocol protocol for SA (ESP/AH)
* @param reqid unique ID for this SA
* @param spi allocated spi
* @return SUCCESS if operation completed
*/
status_t (*get_spi)(kernel_interface_t *this, host_t *src, host_t *dst,
protocol_id_t protocol, u_int32_t reqid, u_int32_t *spi);
/**
* Get a Compression Parameter Index (CPI) from the kernel.
*
* @param src source address of SA
* @param dst destination address of SA
* @param reqid unique ID for the corresponding SA
* @param cpi allocated cpi
* @return SUCCESS if operation completed
*/
status_t (*get_cpi)(kernel_interface_t *this, host_t *src, host_t *dst,
u_int32_t reqid, u_int16_t *cpi);
/**
* Add an SA to the SAD.
*
* add_sa() may update an already allocated
* SPI (via get_spi). In this case, the replace
* flag must be set.
* This function does install a single SA for a
* single protocol in one direction.
*
* @param src source address for this SA
* @param dst destination address for this SA
* @param spi SPI allocated by us or remote peer
* @param protocol protocol for this SA (ESP/AH)
* @param reqid unique ID for this SA
* @param lifetime lifetime_cfg_t for this SA
* @param enc_alg Algorithm to use for encryption (ESP only)
* @param enc_key key to use for encryption
* @param int_alg Algorithm to use for integrity protection
* @param int_key key to use for integrity protection
* @param mode mode of the SA (tunnel, transport)
* @param ipcomp IPComp transform to use
* @param cpi CPI for IPComp
* @param encap enable UDP encapsulation for NAT traversal
* @param inbound TRUE if this is an inbound SA
* @param src_ts traffic selector with BEET source address
* @param dst_ts traffic selector with BEET destination address
* @return SUCCESS if operation completed
*/
status_t (*add_sa) (kernel_interface_t *this,
host_t *src, host_t *dst, u_int32_t spi,
protocol_id_t protocol, u_int32_t reqid,
lifetime_cfg_t *lifetime,
u_int16_t enc_alg, chunk_t enc_key,
u_int16_t int_alg, chunk_t int_key,
ipsec_mode_t mode, u_int16_t ipcomp, u_int16_t cpi,
bool encap, bool inbound,
traffic_selector_t *src_ts, traffic_selector_t *dst_ts);
/**
* Update the hosts on an installed SA.
*
* We cannot directly update the destination address as the kernel
* requires the spi, the protocol AND the destination address (and family)
* to identify SAs. Therefore if the destination address changed we
* create a new SA and delete the old one.
*
* @param spi SPI of the SA
* @param protocol protocol for this SA (ESP/AH)
* @param cpi CPI for IPComp, 0 if no IPComp is used
* @param src current source address
* @param dst current destination address
* @param new_src new source address
* @param new_dst new destination address
* @param encap current use of UDP encapsulation
* @param new_encap new use of UDP encapsulation
* @return SUCCESS if operation completed, NOT_SUPPORTED if
* the kernel interface can't update the SA
*/
status_t (*update_sa)(kernel_interface_t *this,
u_int32_t spi, protocol_id_t protocol, u_int16_t cpi,
host_t *src, host_t *dst,
host_t *new_src, host_t *new_dst,
bool encap, bool new_encap);
/**
* Query the number of bytes processed by an SA from the SAD.
*
* @param src source address for this SA
* @param dst destination address for this SA
* @param spi SPI allocated by us or remote peer
* @param protocol protocol for this SA (ESP/AH)
* @param[out] bytes the number of bytes processed by SA
* @return SUCCESS if operation completed
*/
status_t (*query_sa) (kernel_interface_t *this, host_t *src, host_t *dst,
u_int32_t spi, protocol_id_t protocol, u_int64_t *bytes);
/**
* Delete a previously installed SA from the SAD.
*
* @param src source address for this SA
* @param dst destination address for this SA
* @param spi SPI allocated by us or remote peer
* @param protocol protocol for this SA (ESP/AH)
* @param cpi CPI for IPComp or 0
* @return SUCCESS if operation completed
*/
status_t (*del_sa) (kernel_interface_t *this, host_t *src, host_t *dst,
u_int32_t spi, protocol_id_t protocol, u_int16_t cpi);
/**
* Add a policy to the SPD.
*
* A policy is always associated to an SA. Traffic which matches a
* policy is handled by the SA with the same reqid.
*
* @param src source address of SA
* @param dst dest address of SA
* @param src_ts traffic selector to match traffic source
* @param dst_ts traffic selector to match traffic dest
* @param direction direction of traffic, POLICY_IN, POLICY_OUT, POLICY_FWD
* @param spi SPI of SA
* @param protocol protocol to use to protect traffic (AH/ESP)
* @param reqid unique ID of an SA to use to enforce policy
* @param mode mode of SA (tunnel, transport)
* @param ipcomp the IPComp transform used
* @param cpi CPI for IPComp
* @param routed TRUE, if this policy is routed in the kernel
* @return SUCCESS if operation completed
*/
status_t (*add_policy) (kernel_interface_t *this,
host_t *src, host_t *dst,
traffic_selector_t *src_ts,
traffic_selector_t *dst_ts,
policy_dir_t direction, u_int32_t spi,
protocol_id_t protocol, u_int32_t reqid,
ipsec_mode_t mode, u_int16_t ipcomp, u_int16_t cpi,
bool routed);
/**
* Query the use time of a policy.
*
* The use time of a policy is the time the policy was used
* for the last time.
*
* @param src_ts traffic selector to match traffic source
* @param dst_ts traffic selector to match traffic dest
* @param direction direction of traffic, POLICY_IN, POLICY_OUT, POLICY_FWD
* @param[out] use_time the time of this SA's last use
* @return SUCCESS if operation completed
*/
status_t (*query_policy) (kernel_interface_t *this,
traffic_selector_t *src_ts,
traffic_selector_t *dst_ts,
policy_dir_t direction, u_int32_t *use_time);
/**
* Remove a policy from the SPD.
*
* The kernel interface implements reference counting for policies.
* If the same policy is installed multiple times (in the case of rekeying),
* the reference counter is increased. del_policy() decreases the ref counter
* and removes the policy only when no more references are available.
*
* @param src_ts traffic selector to match traffic source
* @param dst_ts traffic selector to match traffic dest
* @param direction direction of traffic, POLICY_IN, POLICY_OUT, POLICY_FWD
* @param unrouted TRUE, if this policy is unrouted from the kernel
* @return SUCCESS if operation completed
*/
status_t (*del_policy) (kernel_interface_t *this,
traffic_selector_t *src_ts,
traffic_selector_t *dst_ts,
policy_dir_t direction,
bool unrouted);
/**
* Get our outgoing source address for a destination.
*
* Does a route lookup to get the source address used to reach dest.
* The returned host is allocated and must be destroyed.
* An optional src address can be used to check if a route is available
* for given source to dest.
*
* @param dest target destination address
* @param src source address to check, or NULL
* @return outgoing source address, NULL if unreachable
*/
host_t* (*get_source_addr)(kernel_interface_t *this,
host_t *dest, host_t *src);
/**
* Get the next hop for a destination.
*
* Does a route lookup to get the next hop used to reach dest.
* The returned host is allocated and must be destroyed.
*
* @param dest target destination address
* @return next hop address, NULL if unreachable
*/
host_t* (*get_nexthop)(kernel_interface_t *this, host_t *dest);
/**
* Get the interface name of a local address.
*
* @param host address to get interface name from
* @return allocated interface name, or NULL if not found
*/
char* (*get_interface) (kernel_interface_t *this, host_t *host);
/**
* Creates an enumerator over all local addresses.
*
* This function blocks an internal cached address list until the
* enumerator gets destroyed.
* The hosts are read-only, do not modify of free.
*
* @param include_down_ifaces TRUE to enumerate addresses from down interfaces
* @param include_virtual_ips TRUE to enumerate virtual ip addresses
* @return enumerator over host_t's
*/
enumerator_t *(*create_address_enumerator) (kernel_interface_t *this,
bool include_down_ifaces, bool include_virtual_ips);
/**
* Add a virtual IP to an interface.
*
* Virtual IPs are attached to an interface. If an IP is added multiple
* times, the IP is refcounted and not removed until del_ip() was called
* as many times as add_ip().
* The virtual IP is attached to the interface where the iface_ip is found.
*
* @param virtual_ip virtual ip address to assign
* @param iface_ip IP of an interface to attach virtual IP
* @return SUCCESS if operation completed
*/
status_t (*add_ip) (kernel_interface_t *this, host_t *virtual_ip,
host_t *iface_ip);
/**
* Remove a virtual IP from an interface.
*
* The kernel interface uses refcounting, see add_ip().
*
* @param virtual_ip virtual ip address to assign
* @return SUCCESS if operation completed
*/
status_t (*del_ip) (kernel_interface_t *this, host_t *virtual_ip);
/**
* Add a route.
*
* @param dst_net destination net
* @param prefixlen destination net prefix length
* @param gateway gateway for this route
* @param src_ip sourc ip of the route
* @param if_name name of the interface the route is bound to
* @return SUCCESS if operation completed
* ALREADY_DONE if the route already exists
*/
status_t (*add_route) (kernel_interface_t *this, chunk_t dst_net, u_int8_t prefixlen,
host_t *gateway, host_t *src_ip, char *if_name);
/**
* Delete a route.
*
* @param dst_net destination net
* @param prefixlen destination net prefix length
* @param gateway gateway for this route
* @param src_ip sourc ip of the route
* @param if_name name of the interface the route is bound to
* @return SUCCESS if operation completed
*/
status_t (*del_route) (kernel_interface_t *this, chunk_t dst_net, u_int8_t prefixlen,
host_t *gateway, host_t *src_ip, char *if_name);
/**
* Set up a bypass policy for a given socket.
*
* @param fd socket file descriptor to setup policy for
* @param family protocol family of the socket
* @return TRUE of policy set up successfully
*/
bool (*bypass_socket)(kernel_interface_t *this, int fd, int family);
/**
* manager methods
*/
/**
* Tries to find an ip address of a local interface that is included in the
* supplied traffic selector.
*
* @param ts traffic selector
* @param ip returned ip (has to be destroyed)
* @return SUCCESS if address found
*/
status_t (*get_address_by_ts) (kernel_interface_t *this,
traffic_selector_t *ts, host_t **ip);
/**
* Register an ipsec kernel interface constructor on the manager.
*
* @param create constructor to register
*/
void (*add_ipsec_interface)(kernel_interface_t *this, kernel_ipsec_constructor_t create);
/**
* Unregister an ipsec kernel interface constructor.
*
* @param create constructor to unregister
*/
void (*remove_ipsec_interface)(kernel_interface_t *this, kernel_ipsec_constructor_t create);
/**
* Register a network kernel interface constructor on the manager.
*
* @param create constructor to register
*/
void (*add_net_interface)(kernel_interface_t *this, kernel_net_constructor_t create);
/**
* Unregister a network kernel interface constructor.
*
* @param create constructor to unregister
*/
void (*remove_net_interface)(kernel_interface_t *this, kernel_net_constructor_t create);
/**
* Destroys a kernel_interface_manager_t object.
*/
void (*destroy) (kernel_interface_t *this);
};
/**
* Creates an object of type kernel_interface_t.
*/
kernel_interface_t *kernel_interface_create(void);
#endif /** KERNEL_INTERFACE_H_ @}*/
+29
View File
@@ -0,0 +1,29 @@
/*
* Copyright (C) 2008 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "kernel_ipsec.h"
ENUM(ipsec_mode_names, MODE_TRANSPORT, MODE_BEET,
"TRANSPORT",
"TUNNEL",
"BEET",
);
ENUM(policy_dir_names, POLICY_IN, POLICY_FWD,
"in",
"out",
"fwd"
);
+282
View File
@@ -0,0 +1,282 @@
/*
* Copyright (C) 2006-2009 Tobias Brunner
* Copyright (C) 2006 Daniel Roethlisberger
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup kernel_ipsec kernel_ipsec
* @{ @ingroup kernel
*/
#ifndef KERNEL_IPSEC_H_
#define KERNEL_IPSEC_H_
typedef enum ipsec_mode_t ipsec_mode_t;
typedef enum policy_dir_t policy_dir_t;
typedef struct kernel_ipsec_t kernel_ipsec_t;
#include <utils/host.h>
#include <crypto/prf_plus.h>
#include <config/proposal.h>
#include <config/child_cfg.h>
/**
* Mode of a CHILD_SA.
*/
enum ipsec_mode_t {
/** transport mode, no inner address */
MODE_TRANSPORT = 1,
/** tunnel mode, inner and outer addresses */
MODE_TUNNEL,
/** BEET mode, tunnel mode but fixed, bound inner addresses */
MODE_BEET,
};
/**
* enum names for ipsec_mode_t.
*/
extern enum_name_t *ipsec_mode_names;
/**
* Direction of a policy. These are equal to those
* defined in xfrm.h, but we want to stay implementation
* neutral here.
*/
enum policy_dir_t {
/** Policy for inbound traffic */
POLICY_IN = 0,
/** Policy for outbound traffic */
POLICY_OUT = 1,
/** Policy for forwarded traffic */
POLICY_FWD = 2,
};
/**
* enum names for policy_dir_t.
*/
extern enum_name_t *policy_dir_names;
/**
* Interface to the ipsec subsystem of the kernel.
*
* The kernel ipsec interface handles the communication with the kernel
* for SA and policy management. It allows setup of these, and provides
* further the handling of kernel events.
* Policy information are cached in the interface. This is necessary to do
* reference counting. The Linux kernel does not allow the same policy
* installed twice, but we need this as CHILD_SA exist multiple times
* when rekeying. Thats why we do reference counting of policies.
*/
struct kernel_ipsec_t {
/**
* Get a SPI from the kernel.
*
* @param src source address of SA
* @param dst destination address of SA
* @param protocol protocol for SA (ESP/AH)
* @param reqid unique ID for this SA
* @param spi allocated spi
* @return SUCCESS if operation completed
*/
status_t (*get_spi)(kernel_ipsec_t *this, host_t *src, host_t *dst,
protocol_id_t protocol, u_int32_t reqid, u_int32_t *spi);
/**
* Get a Compression Parameter Index (CPI) from the kernel.
*
* @param src source address of SA
* @param dst destination address of SA
* @param reqid unique ID for the corresponding SA
* @param cpi allocated cpi
* @return SUCCESS if operation completed
*/
status_t (*get_cpi)(kernel_ipsec_t *this, host_t *src, host_t *dst,
u_int32_t reqid, u_int16_t *cpi);
/**
* Add an SA to the SAD.
*
* add_sa() may update an already allocated
* SPI (via get_spi). In this case, the replace
* flag must be set.
* This function does install a single SA for a
* single protocol in one direction.
*
* @param src source address for this SA
* @param dst destination address for this SA
* @param spi SPI allocated by us or remote peer
* @param protocol protocol for this SA (ESP/AH)
* @param reqid unique ID for this SA
* @param lifetime lifetime_cfg_t for this SA
* @param enc_alg Algorithm to use for encryption (ESP only)
* @param enc_key key to use for encryption
* @param int_alg Algorithm to use for integrity protection
* @param int_key key to use for integrity protection
* @param mode mode of the SA (tunnel, transport)
* @param ipcomp IPComp transform to use
* @param cpi CPI for IPComp
* @param encap enable UDP encapsulation for NAT traversal
* @param inbound TRUE if this is an inbound SA
* @param src_ts traffic selector with BEET source address
* @param dst_ts traffic selector with BEET destination address
* @return SUCCESS if operation completed
*/
status_t (*add_sa) (kernel_ipsec_t *this,
host_t *src, host_t *dst, u_int32_t spi,
protocol_id_t protocol, u_int32_t reqid,
lifetime_cfg_t *lifetime,
u_int16_t enc_alg, chunk_t enc_key,
u_int16_t int_alg, chunk_t int_key,
ipsec_mode_t mode, u_int16_t ipcomp, u_int16_t cpi,
bool encap, bool inbound,
traffic_selector_t *src_ts, traffic_selector_t *dst_ts);
/**
* Update the hosts on an installed SA.
*
* We cannot directly update the destination address as the kernel
* requires the spi, the protocol AND the destination address (and family)
* to identify SAs. Therefore if the destination address changed we
* create a new SA and delete the old one.
*
* @param spi SPI of the SA
* @param protocol protocol for this SA (ESP/AH)
* @param cpi CPI for IPComp, 0 if no IPComp is used
* @param src current source address
* @param dst current destination address
* @param new_src new source address
* @param new_dst new destination address
* @param encap current use of UDP encapsulation
* @param new_encap new use of UDP encapsulation
* @return SUCCESS if operation completed, NOT_SUPPORTED if
* the kernel interface can't update the SA
*/
status_t (*update_sa)(kernel_ipsec_t *this,
u_int32_t spi, protocol_id_t protocol, u_int16_t cpi,
host_t *src, host_t *dst,
host_t *new_src, host_t *new_dst,
bool encap, bool new_encap);
/**
* Query the number of bytes processed by an SA from the SAD.
*
* @param src source address for this SA
* @param dst destination address for this SA
* @param spi SPI allocated by us or remote peer
* @param protocol protocol for this SA (ESP/AH)
* @param[out] bytes the number of bytes processed by SA
* @return SUCCESS if operation completed
*/
status_t (*query_sa) (kernel_ipsec_t *this, host_t *src, host_t *dst,
u_int32_t spi, protocol_id_t protocol, u_int64_t *bytes);
/**
* Delete a previusly installed SA from the SAD.
*
* @param src source address for this SA
* @param dst destination address for this SA
* @param spi SPI allocated by us or remote peer
* @param protocol protocol for this SA (ESP/AH)
* @param cpi CPI for IPComp or 0
* @return SUCCESS if operation completed
*/
status_t (*del_sa) (kernel_ipsec_t *this, host_t *src, host_t *dst,
u_int32_t spi, protocol_id_t protocol, u_int16_t cpi);
/**
* Add a policy to the SPD.
*
* A policy is always associated to an SA. Traffic which matches a
* policy is handled by the SA with the same reqid.
*
* @param src source address of SA
* @param dst dest address of SA
* @param src_ts traffic selector to match traffic source
* @param dst_ts traffic selector to match traffic dest
* @param direction direction of traffic, POLICY_IN, POLICY_OUT, POLICY_FWD
* @param spi SPI of SA
* @param protocol protocol to use to protect traffic (AH/ESP)
* @param reqid unique ID of an SA to use to enforce policy
* @param mode mode of SA (tunnel, transport)
* @param ipcomp the IPComp transform used
* @param cpi CPI for IPComp
* @param routed TRUE, if this policy is routed in the kernel
* @return SUCCESS if operation completed
*/
status_t (*add_policy) (kernel_ipsec_t *this,
host_t *src, host_t *dst,
traffic_selector_t *src_ts,
traffic_selector_t *dst_ts,
policy_dir_t direction, u_int32_t spi,
protocol_id_t protocol, u_int32_t reqid,
ipsec_mode_t mode, u_int16_t ipcomp, u_int16_t cpi,
bool routed);
/**
* Query the use time of a policy.
*
* The use time of a policy is the time the policy was used for the last
* time. It is not the system time, but a monotonic timestamp as returned
* by time_monotonic.
*
* @param src_ts traffic selector to match traffic source
* @param dst_ts traffic selector to match traffic dest
* @param direction direction of traffic, POLICY_IN, POLICY_OUT, POLICY_FWD
* @param[out] use_time the monotonic timestamp of this SA's last use
* @return SUCCESS if operation completed
*/
status_t (*query_policy) (kernel_ipsec_t *this,
traffic_selector_t *src_ts,
traffic_selector_t *dst_ts,
policy_dir_t direction, u_int32_t *use_time);
/**
* Remove a policy from the SPD.
*
* The kernel interface implements reference counting for policies.
* If the same policy is installed multiple times (in the case of rekeying),
* the reference counter is increased. del_policy() decreases the ref counter
* and removes the policy only when no more references are available.
*
* @param src_ts traffic selector to match traffic source
* @param dst_ts traffic selector to match traffic dest
* @param direction direction of traffic, POLICY_IN, POLICY_OUT, POLICY_FWD
* @param unrouted TRUE, if this policy is unrouted from the kernel
* @return SUCCESS if operation completed
*/
status_t (*del_policy) (kernel_ipsec_t *this,
traffic_selector_t *src_ts,
traffic_selector_t *dst_ts,
policy_dir_t direction,
bool unrouted);
/**
* Install a bypass policy for the given socket.
*
* @param fd socket file descriptor to setup policy for
* @param family protocol family of the socket
* @return TRUE of policy set up successfully
*/
bool (*bypass_socket)(kernel_ipsec_t *this, int fd, int family);
/**
* Destroy the implementation.
*/
void (*destroy) (kernel_ipsec_t *this);
};
#endif /** KERNEL_IPSEC_H_ @}*/
+143
View File
@@ -0,0 +1,143 @@
/*
* Copyright (C) 2008 Tobias Brunner
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup kernel_net kernel_net
* @{ @ingroup kernel
*/
#ifndef KERNEL_NET_H_
#define KERNEL_NET_H_
typedef struct kernel_net_t kernel_net_t;
#include <utils/enumerator.h>
#include <utils/host.h>
/**
* Interface to the network subsystem of the kernel.
*
* The kernel network interface handles the communication with the kernel
* for interface and IP address management.
*/
struct kernel_net_t {
/**
* Get our outgoing source address for a destination.
*
* Does a route lookup to get the source address used to reach dest.
* The returned host is allocated and must be destroyed.
* An optional src address can be used to check if a route is available
* for given source to dest.
*
* @param dest target destination address
* @param src source address to check, or NULL
* @return outgoing source address, NULL if unreachable
*/
host_t* (*get_source_addr)(kernel_net_t *this, host_t *dest, host_t *src);
/**
* Get the next hop for a destination.
*
* Does a route lookup to get the next hop used to reach dest.
* The returned host is allocated and must be destroyed.
*
* @param dest target destination address
* @return next hop address, NULL if unreachable
*/
host_t* (*get_nexthop)(kernel_net_t *this, host_t *dest);
/**
* Get the interface name of a local address.
*
* @param host address to get interface name from
* @return allocated interface name, or NULL if not found
*/
char* (*get_interface) (kernel_net_t *this, host_t *host);
/**
* Creates an enumerator over all local addresses.
*
* This function blocks an internal cached address list until the
* enumerator gets destroyed.
* The hosts are read-only, do not modify of free.
*
* @param include_down_ifaces TRUE to enumerate addresses from down interfaces
* @param include_virtual_ips TRUE to enumerate virtual ip addresses
* @return enumerator over host_t's
*/
enumerator_t *(*create_address_enumerator) (kernel_net_t *this,
bool include_down_ifaces, bool include_virtual_ips);
/**
* Add a virtual IP to an interface.
*
* Virtual IPs are attached to an interface. If an IP is added multiple
* times, the IP is refcounted and not removed until del_ip() was called
* as many times as add_ip().
* The virtual IP is attached to the interface where the iface_ip is found.
*
* @param virtual_ip virtual ip address to assign
* @param iface_ip IP of an interface to attach virtual IP
* @return SUCCESS if operation completed
*/
status_t (*add_ip) (kernel_net_t *this, host_t *virtual_ip,
host_t *iface_ip);
/**
* Remove a virtual IP from an interface.
*
* The kernel interface uses refcounting, see add_ip().
*
* @param virtual_ip virtual ip address to assign
* @return SUCCESS if operation completed
*/
status_t (*del_ip) (kernel_net_t *this, host_t *virtual_ip);
/**
* Add a route.
*
* @param dst_net destination net
* @param prefixlen destination net prefix length
* @param gateway gateway for this route
* @param src_ip sourc ip of the route
* @param if_name name of the interface the route is bound to
* @return SUCCESS if operation completed
* ALREADY_DONE if the route already exists
*/
status_t (*add_route) (kernel_net_t *this, chunk_t dst_net, u_int8_t prefixlen,
host_t *gateway, host_t *src_ip, char *if_name);
/**
* Delete a route.
*
* @param dst_net destination net
* @param prefixlen destination net prefix length
* @param gateway gateway for this route
* @param src_ip sourc ip of the route
* @param if_name name of the interface the route is bound to
* @return SUCCESS if operation completed
*/
status_t (*del_route) (kernel_net_t *this, chunk_t dst_net, u_int8_t prefixlen,
host_t *gateway, host_t *src_ip, char *if_name);
/**
* Destroy the implementation.
*/
void (*destroy) (kernel_net_t *this);
};
#endif /** KERNEL_NET_H_ @}*/
+138
View File
@@ -0,0 +1,138 @@
/*
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "packet.h"
typedef struct private_packet_t private_packet_t;
/**
* Private data of an packet_t object.
*/
struct private_packet_t {
/**
* Public part of a packet_t object.
*/
packet_t public;
/**
* source address
*/
host_t *source;
/**
* destination address
*/
host_t *destination;
/**
* message data
*/
chunk_t data;
};
METHOD(packet_t, set_source, void,
private_packet_t *this, host_t *source)
{
DESTROY_IF(this->source);
this->source = source;
}
METHOD(packet_t, set_destination, void,
private_packet_t *this, host_t *destination)
{
DESTROY_IF(this->destination);
this->destination = destination;
}
METHOD(packet_t, get_source, host_t*,
private_packet_t *this)
{
return this->source;
}
METHOD(packet_t, get_destination, host_t*,
private_packet_t *this)
{
return this->destination;
}
METHOD(packet_t, get_data, chunk_t,
private_packet_t *this)
{
return this->data;
}
METHOD(packet_t, set_data, void,
private_packet_t *this, chunk_t data)
{
free(this->data.ptr);
this->data = data;
}
METHOD(packet_t, destroy, void,
private_packet_t *this)
{
DESTROY_IF(this->source);
DESTROY_IF(this->destination);
free(this->data.ptr);
free(this);
}
METHOD(packet_t, clone_, packet_t*,
private_packet_t *this)
{
packet_t *other;
other = packet_create();
if (this->destination != NULL)
{
other->set_destination(other, this->destination->clone(this->destination));
}
if (this->source != NULL)
{
other->set_source(other, this->source->clone(this->source));
}
if (this->data.ptr != NULL)
{
other->set_data(other, chunk_clone(this->data));
}
return other;
}
/*
* Documented in header
*/
packet_t *packet_create(void)
{
private_packet_t *this;
INIT(this,
.public = {
.set_data = _set_data,
.get_data = _get_data,
.set_source = _set_source,
.get_source = _get_source,
.set_destination = _set_destination,
.get_destination = _get_destination,
.clone = _clone_,
.destroy = _destroy,
},
);
return &this->public;
}
+115
View File
@@ -0,0 +1,115 @@
/*
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup packet packet
* @{ @ingroup network
*/
#ifndef PACKET_H_
#define PACKET_H_
typedef struct packet_t packet_t;
#include <library.h>
#include <utils/host.h>
/**
* Abstraction of an UDP-Packet, contains data, sender and receiver.
*/
struct packet_t {
/**
* Set the source address.
*
* Set host_t is now owned by packet_t, it will destroy
* it if necessary.
*
* @param source address to set as source
*/
void (*set_source) (packet_t *packet, host_t *source);
/**
* Set the destination address.
*
* Set host_t is now owned by packet_t, it will destroy
* it if necessary.
*
* @param source address to set as destination
*/
void (*set_destination) (packet_t *packet, host_t *destination);
/**
* Get the source address.
*
* Set host_t is still owned by packet_t, clone it
* if needed.
*
* @return source address
*/
host_t *(*get_source) (packet_t *packet);
/**
* Get the destination address.
*
* Set host_t is still owned by packet_t, clone it
* if needed.
*
* @return destination address
*/
host_t *(*get_destination) (packet_t *packet);
/**
* Get the data from the packet.
*
* The data pointed by the chunk is still owned
* by the packet. Clone it if needed.
*
* @return chunk containing the data
*/
chunk_t (*get_data) (packet_t *packet);
/**
* Set the data in the packet.
*
* Supplied chunk data is now owned by the
* packet. It will free it.
*
* @param data chunk with data to set
*/
void (*set_data) (packet_t *packet, chunk_t data);
/**
* Clones a packet_t object.
*
* @param clone clone of the packet
*/
packet_t* (*clone) (packet_t *packet);
/**
* Destroy the packet, freeing contained data.
*/
void (*destroy) (packet_t *packet);
};
/**
* create an empty packet
*
* @return packet_t object
*/
packet_t *packet_create(void);
#endif /** PACKET_H_ @}*/
+402
View File
@@ -0,0 +1,402 @@
/*
* Copyright (C) 2008 Tobias Brunner
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <stdlib.h>
#include <unistd.h>
#include "receiver.h"
#include <daemon.h>
#include <network/socket.h>
#include <network/packet.h>
#include <processing/jobs/job.h>
#include <processing/jobs/process_message_job.h>
#include <processing/jobs/callback_job.h>
#include <crypto/hashers/hasher.h>
/** lifetime of a cookie, in seconds */
#define COOKIE_LIFETIME 10
/** how many times to reuse the secret */
#define COOKIE_REUSE 10000
/** default value for private_receiver_t.cookie_threshold */
#define COOKIE_THRESHOLD_DEFAULT 10
/** default value for private_receiver_t.block_threshold */
#define BLOCK_THRESHOLD_DEFAULT 5
/** length of the secret to use for cookie calculation */
#define SECRET_LENGTH 16
typedef struct private_receiver_t private_receiver_t;
/**
* Private data of a receiver_t object.
*/
struct private_receiver_t {
/**
* Public part of a receiver_t object.
*/
receiver_t public;
/**
* Threads job receiving packets
*/
callback_job_t *job;
/**
* current secret to use for cookie calculation
*/
char secret[SECRET_LENGTH];
/**
* previous secret used to verify older cookies
*/
char secret_old[SECRET_LENGTH];
/**
* how many times we have used "secret" so far
*/
u_int32_t secret_used;
/**
* time we did the cookie switch
*/
u_int32_t secret_switch;
/**
* time offset to use, hides our system time
*/
u_int32_t secret_offset;
/**
* the RNG to use for secret generation
*/
rng_t *rng;
/**
* hasher to use for cookie calculation
*/
hasher_t *hasher;
/**
* require cookies after this many half open IKE_SAs
*/
u_int32_t cookie_threshold;
/**
* how many half open IKE_SAs per peer before blocking
*/
u_int32_t block_threshold;
/**
* Delay for receiving incoming packets, to simulate larger RTT
*/
u_int receive_delay;
};
/**
* send a notify back to the sender
*/
static void send_notify(message_t *request, notify_type_t type, chunk_t data)
{
if (request->get_request(request) &&
request->get_exchange_type(request) == IKE_SA_INIT)
{
message_t *response;
host_t *src, *dst;
packet_t *packet;
ike_sa_id_t *ike_sa_id;
response = message_create();
dst = request->get_source(request);
src = request->get_destination(request);
response->set_source(response, src->clone(src));
response->set_destination(response, dst->clone(dst));
response->set_exchange_type(response, request->get_exchange_type(request));
response->set_request(response, FALSE);
response->set_message_id(response, 0);
ike_sa_id = request->get_ike_sa_id(request);
ike_sa_id->switch_initiator(ike_sa_id);
response->set_ike_sa_id(response, ike_sa_id);
response->add_notify(response, FALSE, type, data);
if (response->generate(response, NULL, NULL, &packet) == SUCCESS)
{
charon->sender->send(charon->sender, packet);
response->destroy(response);
}
}
}
/**
* build a cookie
*/
static chunk_t cookie_build(private_receiver_t *this, message_t *message,
u_int32_t t, chunk_t secret)
{
u_int64_t spi = message->get_initiator_spi(message);
host_t *ip = message->get_source(message);
chunk_t input, hash;
/* COOKIE = t | sha1( IPi | SPIi | t | secret ) */
input = chunk_cata("cccc", ip->get_address(ip), chunk_from_thing(spi),
chunk_from_thing(t), secret);
hash = chunk_alloca(this->hasher->get_hash_size(this->hasher));
this->hasher->get_hash(this->hasher, input, hash.ptr);
return chunk_cat("cc", chunk_from_thing(t), hash);
}
/**
* verify a received cookie
*/
static bool cookie_verify(private_receiver_t *this, message_t *message,
chunk_t cookie)
{
u_int32_t t, now;
chunk_t reference;
chunk_t secret;
now = time_monotonic(NULL);
t = *(u_int32_t*)cookie.ptr;
if (cookie.len != sizeof(u_int32_t) +
this->hasher->get_hash_size(this->hasher) ||
t < now - this->secret_offset - COOKIE_LIFETIME)
{
DBG2(DBG_NET, "received cookie lifetime expired, rejecting");
return FALSE;
}
/* check if cookie is derived from old_secret */
if (t + this->secret_offset > this->secret_switch)
{
secret = chunk_from_thing(this->secret);
}
else
{
secret = chunk_from_thing(this->secret_old);
}
/* compare own calculation against received */
reference = cookie_build(this, message, t, secret);
if (chunk_equals(reference, cookie))
{
chunk_free(&reference);
return TRUE;
}
chunk_free(&reference);
return FALSE;
}
/**
* check if cookies are required, and if so, a valid cookie is included
*/
static bool cookie_required(private_receiver_t *this, message_t *message)
{
bool failed = FALSE;
if (charon->ike_sa_manager->get_half_open_count(charon->ike_sa_manager,
NULL) >= this->cookie_threshold)
{
/* check for a cookie. We don't use our parser here and do it
* quick and dirty for performance reasons.
* we assume the cookie is the first payload (which is a MUST), and
* the cookie's SPI length is zero. */
packet_t *packet = message->get_packet(message);
chunk_t data = packet->get_data(packet);
if (data.len <
IKE_HEADER_LENGTH + NOTIFY_PAYLOAD_HEADER_LENGTH +
sizeof(u_int32_t) + this->hasher->get_hash_size(this->hasher) ||
*(data.ptr + 16) != NOTIFY ||
*(u_int16_t*)(data.ptr + IKE_HEADER_LENGTH + 6) != htons(COOKIE))
{
/* no cookie found */
failed = TRUE;
}
else
{
data.ptr += IKE_HEADER_LENGTH + NOTIFY_PAYLOAD_HEADER_LENGTH;
data.len = sizeof(u_int32_t) + this->hasher->get_hash_size(this->hasher);
if (!cookie_verify(this, message, data))
{
DBG2(DBG_NET, "found cookie, but content invalid");
failed = TRUE;
}
}
packet->destroy(packet);
}
return failed;
}
/**
* check if peer has to many half open IKE_SAs
*/
static bool peer_to_aggressive(private_receiver_t *this, message_t *message)
{
if (charon->ike_sa_manager->get_half_open_count(charon->ike_sa_manager,
message->get_source(message)) >= this->block_threshold)
{
return TRUE;
}
return FALSE;
}
/**
* Job callback to receive packets
*/
static job_requeue_t receive_packets(private_receiver_t *this)
{
packet_t *packet;
message_t *message;
job_t *job;
/* read in a packet */
if (charon->socket->receive(charon->socket, &packet) != SUCCESS)
{
DBG2(DBG_NET, "receiving from socket failed!");
return JOB_REQUEUE_FAIR;
}
/* parse message header */
message = message_create_from_packet(packet);
if (message->parse_header(message) != SUCCESS)
{
DBG1(DBG_NET, "received invalid IKE header from %H - ignored",
packet->get_source(packet));
message->destroy(message);
return JOB_REQUEUE_DIRECT;
}
/* check IKE major version */
if (message->get_major_version(message) != IKE_MAJOR_VERSION)
{
DBG1(DBG_NET, "received unsupported IKE version %d.%d from %H, "
"sending INVALID_MAJOR_VERSION", message->get_major_version(message),
message->get_minor_version(message), packet->get_source(packet));
send_notify(message, INVALID_MAJOR_VERSION, chunk_empty);
message->destroy(message);
return JOB_REQUEUE_DIRECT;
}
if (message->get_request(message) &&
message->get_exchange_type(message) == IKE_SA_INIT)
{
/* check for cookies */
if (this->cookie_threshold && cookie_required(this, message))
{
u_int32_t now = time_monotonic(NULL);
chunk_t cookie = cookie_build(this, message, now - this->secret_offset,
chunk_from_thing(this->secret));
DBG2(DBG_NET, "received packet from: %#H to %#H",
message->get_source(message),
message->get_destination(message));
DBG2(DBG_NET, "sending COOKIE notify to %H",
message->get_source(message));
send_notify(message, COOKIE, cookie);
chunk_free(&cookie);
if (++this->secret_used > COOKIE_REUSE)
{
/* create new cookie */
DBG1(DBG_NET, "generating new cookie secret after %d uses",
this->secret_used);
memcpy(this->secret_old, this->secret, SECRET_LENGTH);
this->rng->get_bytes(this->rng, SECRET_LENGTH, this->secret);
this->secret_switch = now;
this->secret_used = 0;
}
message->destroy(message);
return JOB_REQUEUE_DIRECT;
}
/* check if peer has not too many IKE_SAs half open */
if (this->block_threshold && peer_to_aggressive(this, message))
{
DBG1(DBG_NET, "ignoring IKE_SA setup from %H, "
"peer too aggressive", message->get_source(message));
message->destroy(message);
return JOB_REQUEUE_DIRECT;
}
}
job = (job_t*)process_message_job_create(message);
if (this->receive_delay)
{
charon->scheduler->schedule_job_ms(charon->scheduler,
job, this->receive_delay);
}
else
{
charon->processor->queue_job(charon->processor, job);
}
return JOB_REQUEUE_DIRECT;
}
METHOD(receiver_t, destroy, void,
private_receiver_t *this)
{
this->job->cancel(this->job);
this->rng->destroy(this->rng);
this->hasher->destroy(this->hasher);
free(this);
}
/*
* Described in header.
*/
receiver_t *receiver_create()
{
private_receiver_t *this;
u_int32_t now = time_monotonic(NULL);
INIT(this,
.public.destroy = _destroy,
.secret_switch = now,
.secret_offset = random() % now,
);
if (lib->settings->get_bool(lib->settings, "charon.dos_protection", TRUE))
{
this->cookie_threshold = lib->settings->get_int(lib->settings,
"charon.cookie_threshold", COOKIE_THRESHOLD_DEFAULT);
this->block_threshold = lib->settings->get_int(lib->settings,
"charon.block_threshold", BLOCK_THRESHOLD_DEFAULT);
}
this->receive_delay = lib->settings->get_int(lib->settings,
"charon.receive_delay", 0);
this->hasher = lib->crypto->create_hasher(lib->crypto, HASH_PREFERRED);
if (this->hasher == NULL)
{
DBG1(DBG_NET, "creating cookie hasher failed, no hashers supported");
free(this);
return NULL;
}
this->rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG);
if (this->rng == NULL)
{
DBG1(DBG_NET, "creating cookie RNG failed, no RNG supported");
this->hasher->destroy(this->hasher);
free(this);
return NULL;
}
this->rng->get_bytes(this->rng, SECRET_LENGTH, this->secret);
memcpy(this->secret_old, this->secret, SECRET_LENGTH);
this->job = callback_job_create((callback_job_cb_t)receive_packets,
this, NULL, NULL);
charon->processor->queue_job(charon->processor, (job_t*)this->job);
return &this->public;
}
+70
View File
@@ -0,0 +1,70 @@
/*
* Copyright (C) 2005-2007 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup receiver receiver
* @{ @ingroup network
*/
#ifndef RECEIVER_H_
#define RECEIVER_H_
typedef struct receiver_t receiver_t;
#include <library.h>
#include <utils/host.h>
/**
* Receives packets from the socket and adds them to the job queue.
*
* The receiver starts a thread, wich reads on the blocking socket. A received
* packet is preparsed and a process_message_job is queued in the job queue.
*
* To endure DoS attacks, cookies are enabled when to many IKE_SAs are half
* open. The calculation of cookies is slightly different from the proposed
* method in RFC4306. We do not include a nonce, because we think the advantage
* we gain does not justify the overhead to parse the whole message.
* Instead of VersionIdOfSecret, we include a timestamp. This allows us to
* find out wich key was used for cookie creation. Further, we can set a
* lifetime for the cookie, which allows us to reuse the secret for a longer
* time.
* COOKIE = time | sha1( IPi | SPIi | time | secret )
*
* The secret is changed after a certain amount of cookies sent. The old
* secret is stored to allow a clean migration between secret changes.
*
* Further, the number of half-initiated IKE_SAs is limited per peer. This
* mades it impossible for a peer to flood the server with its real IP address.
*/
struct receiver_t {
/**
* Destroys a receiver_t object.
*/
void (*destroy) (receiver_t *receiver);
};
/**
* Create a receiver_t object.
*
* The receiver thread will start working, get data
* from the socket and add those packets to the job queue.
*
* @return receiver_t object, NULL if initialization fails
*/
receiver_t * receiver_create(void);
#endif /** RECEIVER_H_ @}*/

Some files were not shown because too many files have changed in this diff Show More