[Pkg-swan-devel] [strongswan] 01/03: New upstream version 5.5.3

Yves-Alexis Perez corsac at moszumanska.debian.org
Thu Jun 1 20:17:05 UTC 2017


This is an automated email from the git hooks/post-receive script.

corsac pushed a commit to branch master
in repository strongswan.

commit 335b7e322c795d86705aab67d2ecf72f1c9c5614
Author: Yves-Alexis Perez <corsac at corsac.net>
Date:   Tue May 30 20:59:31 2017 +0200

    New upstream version 5.5.3
---
 Android.common.mk                                  |    2 +-
 Doxyfile.in                                        |    2 +-
 Makefile.am                                        |    4 +
 Makefile.in                                        |    9 +-
 NEWS                                               |   58 +
 README                                             | 1687 ++++---------
 conf/Makefile.in                                   |    2 +
 conf/options/charon.conf                           |   12 +
 conf/options/charon.opt                            |   17 +
 conf/plugins/attr-sql.conf                         |    4 +
 conf/plugins/attr-sql.opt                          |    4 +
 conf/plugins/kernel-netlink.opt                    |    6 +-
 conf/plugins/socket-default.conf                   |    3 +
 conf/plugins/socket-default.opt                    |    6 +
 conf/strongswan.conf.5.main                        |   31 +-
 conf/strongswan.conf.5.tail.in                     |   12 +-
 config.h.in                                        |    6 +
 configure                                          |  196 +-
 configure.ac                                       |   47 +-
 fuzz/Makefile.am                                   |   18 +
 {src/include => fuzz}/Makefile.in                  |   56 +-
 init/Makefile.in                                   |    2 +
 init/systemd-swanctl/Makefile.in                   |    2 +
 init/systemd/Makefile.in                           |    2 +
 man/Makefile.in                                    |    2 +
 man/ipsec.conf.5.in                                |   28 +-
 scripts/Makefile.in                                |    2 +
 src/Makefile.in                                    |    2 +
 src/_copyright/Makefile.in                         |    2 +
 src/_updown/Makefile.in                            |    2 +
 src/aikgen/Makefile.in                             |    2 +
 src/charon-cmd/Makefile.in                         |    2 +
 src/charon-nm/Makefile.in                          |    2 +
 src/charon-nm/charon-nm.c                          |    2 +-
 src/charon-nm/nm/nm_creds.c                        |   72 +-
 src/charon-nm/nm/nm_handler.c                      |   48 +-
 src/charon-nm/nm/nm_service.c                      |   66 +-
 src/charon-svc/Makefile.in                         |    2 +
 src/charon-systemd/Makefile.in                     |    2 +
 src/charon-tkm/Makefile.in                         |    2 +
 src/charon-tkm/src/tkm/tkm_kernel_sad.c            |   97 +-
 src/charon/Makefile.in                             |    2 +
 src/checksum/Makefile.in                           |    2 +
 src/conftest/Makefile.in                           |    2 +
 src/conftest/config.c                              |   21 +-
 src/dumm/Makefile.in                               |    2 +
 src/dumm/cowfs.c                                   |   13 +-
 src/dumm/dumm.c                                    |    9 +-
 src/include/Makefile.in                            |    2 +
 src/include/linux/xfrm.h                           |   11 +-
 src/ipsec/Makefile.in                              |    2 +
 src/ipsec/_ipsec.8                                 |    2 +-
 src/libcharon/Makefile.am                          |    9 +
 src/libcharon/Makefile.in                          |   22 +-
 src/libcharon/attributes/attribute_manager.c       |   25 +-
 src/libcharon/attributes/mem_pool.c                |   12 +-
 src/libcharon/bus/bus.c                            |   43 +-
 src/libcharon/config/backend_manager.c             |   30 +-
 src/libcharon/config/child_cfg.c                   |  100 +-
 src/libcharon/config/child_cfg.h                   |   82 +-
 src/libcharon/config/ike_cfg.c                     |    2 +-
 src/libcharon/config/ike_cfg.h                     |    8 +-
 src/libcharon/config/peer_cfg.c                    |   22 +-
 src/libcharon/config/proposal.c                    |   40 +-
 src/libcharon/daemon.c                             |   24 +-
 src/libcharon/encoding/message.c                   |    2 +-
 src/libcharon/encoding/payloads/certreq_payload.c  |    9 +-
 src/libcharon/encoding/payloads/delete_payload.c   |    9 +-
 src/libcharon/encoding/payloads/eap_payload.c      |    9 +-
 src/libcharon/kernel/kernel_interface.c            |    9 +-
 src/libcharon/kernel/kernel_ipsec.h                |    2 +
 src/libcharon/network/receiver.c                   |    6 +-
 src/libcharon/plugins/addrblock/Makefile.in        |    2 +
 .../plugins/addrblock/addrblock_validator.c        |    4 +-
 src/libcharon/plugins/android_dns/Makefile.in      |    2 +
 .../plugins/android_dns/android_dns_handler.c      |   12 +-
 src/libcharon/plugins/android_log/Makefile.am      |    1 +
 src/libcharon/plugins/android_log/Makefile.in      |    5 +-
 src/libcharon/plugins/attr/Makefile.in             |    2 +
 src/libcharon/plugins/attr/attr_provider.c         |   26 +-
 src/libcharon/plugins/attr_sql/Makefile.in         |    2 +
 src/libcharon/plugins/attr_sql/attr_sql_provider.c |   20 +-
 src/libcharon/plugins/bypass_lan/Makefile.in       |    2 +
 .../plugins/bypass_lan/bypass_lan_listener.c       |    7 +-
 src/libcharon/plugins/certexpire/Makefile.in       |    2 +
 src/libcharon/plugins/connmark/Makefile.in         |    2 +
 src/libcharon/plugins/coupling/Makefile.in         |    2 +
 src/libcharon/plugins/dhcp/Makefile.in             |    2 +
 src/libcharon/plugins/dhcp/dhcp_provider.c         |    3 +-
 src/libcharon/plugins/dhcp/dhcp_socket.c           |    3 +-
 src/libcharon/plugins/dhcp/dhcp_transaction.c      |   26 +-
 src/libcharon/plugins/dnscert/Makefile.in          |    2 +
 src/libcharon/plugins/dnscert/dnscert_cred.c       |    8 +-
 src/libcharon/plugins/duplicheck/Makefile.in       |    2 +
 src/libcharon/plugins/eap_aka/Makefile.in          |    2 +
 src/libcharon/plugins/eap_aka_3gpp2/Makefile.in    |    2 +
 src/libcharon/plugins/eap_dynamic/Makefile.in      |    2 +
 src/libcharon/plugins/eap_dynamic/eap_dynamic.c    |   12 +-
 src/libcharon/plugins/eap_gtc/Makefile.in          |    2 +
 src/libcharon/plugins/eap_identity/Makefile.in     |    2 +
 src/libcharon/plugins/eap_md5/Makefile.in          |    2 +
 src/libcharon/plugins/eap_mschapv2/Makefile.in     |    2 +
 src/libcharon/plugins/eap_peap/Makefile.in         |    2 +
 src/libcharon/plugins/eap_radius/Makefile.in       |    2 +
 .../plugins/eap_radius/eap_radius_provider.c       |   11 +-
 src/libcharon/plugins/eap_sim/Makefile.in          |    2 +
 src/libcharon/plugins/eap_sim_file/Makefile.in     |    2 +
 .../plugins/eap_sim_file/eap_sim_file_triplets.c   |   34 +-
 src/libcharon/plugins/eap_sim_pcsc/Makefile.in     |    2 +
 .../plugins/eap_simaka_pseudonym/Makefile.in       |    2 +
 .../plugins/eap_simaka_reauth/Makefile.in          |    2 +
 src/libcharon/plugins/eap_simaka_sql/Makefile.in   |    2 +
 .../plugins/eap_simaka_sql/eap_simaka_sql_card.c   |   11 +-
 src/libcharon/plugins/eap_tls/Makefile.in          |    2 +
 src/libcharon/plugins/eap_tnc/Makefile.in          |    2 +
 src/libcharon/plugins/eap_ttls/Makefile.in         |    2 +
 src/libcharon/plugins/error_notify/Makefile.in     |    2 +
 src/libcharon/plugins/ext_auth/Makefile.in         |    2 +
 src/libcharon/plugins/farp/Makefile.in             |    2 +
 src/libcharon/plugins/forecast/Makefile.in         |    2 +
 src/libcharon/plugins/forecast/forecast_listener.c |   30 +-
 src/libcharon/plugins/ha/Makefile.in               |    2 +
 src/libcharon/plugins/ha/ha_dispatcher.c           |   16 +-
 src/libcharon/plugins/ha/ha_message.c              |   11 +-
 src/libcharon/plugins/ha/ha_tunnel.c               |    9 +-
 src/libcharon/plugins/ipseckey/Makefile.in         |    2 +
 src/libcharon/plugins/ipseckey/ipseckey_cred.c     |    8 +-
 src/libcharon/plugins/kernel_iph/Makefile.in       |    2 +
 src/libcharon/plugins/kernel_iph/kernel_iph_net.c  |    8 +-
 src/libcharon/plugins/kernel_libipsec/Makefile.in  |    2 +
 .../kernel_libipsec/kernel_libipsec_ipsec.c        |   35 +-
 src/libcharon/plugins/kernel_netlink/Makefile.in   |    2 +
 .../plugins/kernel_netlink/kernel_netlink_ipsec.c  |  136 +-
 .../plugins/kernel_netlink/kernel_netlink_net.c    |  169 +-
 .../plugins/kernel_netlink/kernel_netlink_plugin.c |   23 +
 .../plugins/kernel_netlink/kernel_netlink_shared.c |    3 +-
 src/libcharon/plugins/kernel_pfkey/Makefile.in     |    2 +
 .../plugins/kernel_pfkey/kernel_pfkey_ipsec.c      |  119 +-
 src/libcharon/plugins/kernel_pfroute/Makefile.in   |    2 +
 .../plugins/kernel_pfroute/kernel_pfroute_net.c    |  123 +-
 src/libcharon/plugins/kernel_wfp/Makefile.in       |    2 +
 src/libcharon/plugins/led/Makefile.in              |    2 +
 src/libcharon/plugins/load_tester/Makefile.in      |    2 +
 .../plugins/load_tester/load_tester_creds.c        |   34 +-
 src/libcharon/plugins/lookip/Makefile.in           |    2 +
 src/libcharon/plugins/medcli/Makefile.in           |    2 +
 src/libcharon/plugins/medcli/medcli_config.c       |    8 +-
 src/libcharon/plugins/medcli/medcli_creds.c        |   16 +-
 src/libcharon/plugins/medcli/medcli_creds.h        |    2 +-
 src/libcharon/plugins/medcli/medcli_listener.h     |    2 +-
 src/libcharon/plugins/medsrv/Makefile.in           |    2 +
 src/libcharon/plugins/medsrv/medsrv_creds.c        |    9 +-
 src/libcharon/plugins/medsrv/medsrv_creds.h        |    2 +-
 src/libcharon/plugins/osx_attr/Makefile.in         |    2 +
 src/libcharon/plugins/osx_attr/osx_attr_handler.c  |   12 +-
 src/libcharon/plugins/p_cscf/Makefile.in           |    2 +
 src/libcharon/plugins/p_cscf/p_cscf_handler.c      |   23 +-
 src/libcharon/plugins/radattr/Makefile.in          |    2 +
 src/libcharon/plugins/resolve/Makefile.in          |    2 +
 src/libcharon/plugins/resolve/resolve_handler.c    |   12 +-
 src/libcharon/plugins/smp/Makefile.in              |    2 +
 src/libcharon/plugins/socket_default/Makefile.in   |    2 +
 .../plugins/socket_default/socket_default_socket.c |   55 +-
 src/libcharon/plugins/socket_dynamic/Makefile.in   |    2 +
 src/libcharon/plugins/socket_win/Makefile.in       |    2 +
 src/libcharon/plugins/sql/Makefile.in              |    2 +
 src/libcharon/plugins/sql/sql_config.c             |   79 +-
 src/libcharon/plugins/sql/sql_cred.c               |   35 +-
 src/libcharon/plugins/stroke/Makefile.in           |    2 +
 src/libcharon/plugins/stroke/stroke_attribute.c    |   76 +-
 src/libcharon/plugins/stroke/stroke_ca.c           |   49 +-
 src/libcharon/plugins/stroke/stroke_config.c       |   30 +-
 src/libcharon/plugins/stroke/stroke_handler.c      |   56 +-
 src/libcharon/plugins/stroke/stroke_list.c         |    5 +-
 src/libcharon/plugins/stroke/stroke_socket.c       |    1 +
 src/libcharon/plugins/systime_fix/Makefile.in      |    2 +
 src/libcharon/plugins/tnc_ifmap/Makefile.in        |    2 +
 .../plugins/tnc_ifmap/tnc_ifmap_soap_msg.c         |    9 +-
 src/libcharon/plugins/tnc_pdp/Makefile.in          |    2 +
 src/libcharon/plugins/uci/Makefile.in              |    2 +
 src/libcharon/plugins/uci/uci_config.c             |   16 +-
 src/libcharon/plugins/uci/uci_creds.c              |   10 +-
 src/libcharon/plugins/uci/uci_parser.c             |   17 +-
 src/libcharon/plugins/unity/Makefile.in            |    2 +
 src/libcharon/plugins/unity/unity_handler.c        |   39 +-
 src/libcharon/plugins/unity/unity_provider.c       |   10 +-
 src/libcharon/plugins/updown/Makefile.in           |    2 +
 src/libcharon/plugins/updown/updown_listener.c     |    2 +-
 src/libcharon/plugins/vici/Makefile.in             |    2 +
 src/libcharon/plugins/vici/README.md               |    3 +-
 src/libcharon/plugins/vici/perl/Makefile.in        |    2 +
 src/libcharon/plugins/vici/python/Makefile.in      |    2 +
 src/libcharon/plugins/vici/python/vici/protocol.py |    2 +-
 src/libcharon/plugins/vici/ruby/Makefile.in        |    4 +-
 src/libcharon/plugins/vici/suites/test_message.c   |   12 +-
 src/libcharon/plugins/vici/vici_attribute.c        |   26 +-
 src/libcharon/plugins/vici/vici_config.c           |  113 +-
 src/libcharon/plugins/vici/vici_cred.c             |   14 +-
 src/libcharon/plugins/vici/vici_message.c          |   10 +-
 src/libcharon/plugins/vici/vici_query.c            |    2 +-
 src/libcharon/plugins/whitelist/Makefile.in        |    2 +
 .../plugins/whitelist/whitelist_listener.c         |   21 +-
 src/libcharon/plugins/xauth_eap/Makefile.in        |    2 +
 src/libcharon/plugins/xauth_generic/Makefile.in    |    2 +
 src/libcharon/plugins/xauth_noauth/Makefile.in     |    2 +
 src/libcharon/plugins/xauth_pam/Makefile.in        |    2 +
 .../processing/jobs/delete_child_sa_job.c          |   69 +-
 .../processing/jobs/delete_child_sa_job.h          |   13 +-
 src/libcharon/sa/child_sa.c                        |  560 ++++-
 src/libcharon/sa/child_sa.h                        |  120 +-
 src/libcharon/sa/eap/eap_manager.c                 |   53 +-
 src/libcharon/sa/ike_sa.c                          |   57 +-
 src/libcharon/sa/ike_sa_manager.c                  |  121 +-
 src/libcharon/sa/ikev1/task_manager_v1.c           |   31 +-
 src/libcharon/sa/ikev1/tasks/quick_mode.c          |   37 +-
 src/libcharon/sa/ikev2/connect_manager.c           |  164 +-
 src/libcharon/sa/ikev2/task_manager_v2.c           |   47 +-
 src/libcharon/sa/ikev2/tasks/child_create.c        |   96 +-
 src/libcharon/sa/ikev2/tasks/child_delete.c        |  229 +-
 src/libcharon/sa/ikev2/tasks/child_rekey.c         |   16 +-
 src/libcharon/sa/shunt_manager.c                   |   22 +-
 src/libcharon/sa/task_manager.c                    |   32 +-
 src/libcharon/sa/task_manager.h                    |   16 +
 src/libcharon/sa/trap_manager.c                    |   72 +-
 src/libcharon/tests/Makefile.in                    |    2 +
 src/libcharon/tests/suites/test_child_rekey.c      |  617 +++--
 src/libcharon/tests/utils/exchange_test_asserts.c  |   57 +-
 src/libcharon/tests/utils/exchange_test_asserts.h  |   61 +-
 src/libcharon/tests/utils/mock_ipsec.c             |  179 +-
 src/libcharon/tests/utils/mock_ipsec.h             |   11 +-
 src/libcharon/tests/utils/sa_asserts.h             |   32 +-
 src/libfast/Makefile.in                            |    2 +
 src/libimcv/Makefile.in                            |    2 +
 src/libimcv/ietf/ietf_attr_installed_packages.c    |   26 +-
 src/libimcv/ietf/ietf_attr_op_status.c             |    4 +-
 src/libimcv/ietf/ietf_attr_port_filter.c           |   29 +-
 src/libimcv/imc/imc_os_info.c                      |   38 +-
 src/libimcv/imv/imv_agent.c                        |   32 +-
 src/libimcv/ita/ita_attr_settings.c                |   25 +-
 src/libimcv/plugins/imc_attestation/Makefile.in    |    2 +
 src/libimcv/plugins/imc_hcd/Makefile.in            |    2 +
 src/libimcv/plugins/imc_os/Makefile.in             |    2 +
 src/libimcv/plugins/imc_scanner/Makefile.in        |    2 +
 src/libimcv/plugins/imc_scanner/imc_scanner.c      |    2 +-
 src/libimcv/plugins/imc_swid/Makefile.in           |    2 +
 src/libimcv/plugins/imc_test/Makefile.in           |    2 +
 src/libimcv/plugins/imc_test/imc_test_state.h      |    4 +-
 src/libimcv/plugins/imv_attestation/Makefile.in    |    2 +
 .../imv_attestation/imv_attestation_state.c        |   32 +-
 src/libimcv/plugins/imv_hcd/Makefile.in            |    2 +
 src/libimcv/plugins/imv_os/Makefile.in             |    2 +
 src/libimcv/plugins/imv_scanner/Makefile.in        |    2 +
 src/libimcv/plugins/imv_swid/Makefile.in           |    2 +
 src/libimcv/plugins/imv_swid/imv_swid_rest.c       |   36 +-
 src/libimcv/plugins/imv_test/Makefile.in           |    2 +
 src/libimcv/plugins/imv_test/imv_test_agent.c      |    2 +
 src/libimcv/pts/pts_file_meas.c                    |   25 +-
 src/libimcv/pts/pts_pcr.c                          |   16 +-
 .../tcg/pts/tcg_pts_attr_req_func_comp_evid.c      |   28 +-
 .../tcg/pts/tcg_pts_attr_simple_comp_evid.c        |    4 +-
 src/libipsec/Makefile.in                           |    2 +
 src/libipsec/ipsec_sa_mgr.c                        |   91 +-
 src/libipsec/tests/Makefile.in                     |    2 +
 src/libpttls/Makefile.in                           |    2 +
 src/libpttls/sasl/sasl_mechanism.c                 |    8 +-
 src/libradius/Makefile.in                          |    2 +
 src/libradius/radius_message.c                     |   20 +-
 src/libsimaka/Makefile.in                          |    2 +
 src/libsimaka/simaka_message.c                     |   25 +-
 src/libstrongswan/Makefile.am                      |   10 +
 src/libstrongswan/Makefile.in                      |  450 ++--
 src/libstrongswan/asn1/asn1.c                      |   16 +-
 src/libstrongswan/asn1/asn1_parser.c               |   70 +-
 src/libstrongswan/asn1/asn1_parser.h               |   27 +-
 src/libstrongswan/collections/array.c              |    9 +-
 src/libstrongswan/collections/enumerator.c         |  368 +--
 src/libstrongswan/collections/enumerator.h         |   70 +-
 src/libstrongswan/collections/hashtable.c          |   10 +-
 src/libstrongswan/collections/linked_list.c        |   70 +-
 src/libstrongswan/collections/linked_list.h        |   56 +-
 src/libstrongswan/credentials/auth_cfg.c           |   21 +-
 src/libstrongswan/credentials/credential_factory.c |   26 +-
 src/libstrongswan/credentials/credential_manager.c |   54 +-
 src/libstrongswan/credentials/keys/public_key.c    |    9 +-
 .../credentials/sets/auth_cfg_wrapper.c            |   36 +-
 src/libstrongswan/credentials/sets/callback_cred.c |   10 +-
 src/libstrongswan/credentials/sets/cert_cache.c    |   38 +-
 src/libstrongswan/credentials/sets/mem_cred.c      |  230 +-
 src/libstrongswan/credentials/sets/mem_cred.h      |    2 +-
 .../credentials/sets/ocsp_response_wrapper.c       |   35 +-
 src/libstrongswan/crypto/crypto_factory.c          |  228 +-
 .../crypto/hashers/hash_algorithm_set.c            |   17 +-
 src/libstrongswan/library.c                        |   13 +
 src/libstrongswan/math/libnttfft/Makefile.in       |    2 +
 src/libstrongswan/math/libnttfft/tests/Makefile.in |    2 +
 src/libstrongswan/networking/tun_device.c          |   32 +-
 src/libstrongswan/plugins/acert/Makefile.in        |    2 +
 src/libstrongswan/plugins/aes/Makefile.in          |    2 +
 src/libstrongswan/plugins/aesni/Makefile.in        |    2 +
 src/libstrongswan/plugins/af_alg/Makefile.in       |    2 +
 src/libstrongswan/plugins/af_alg/af_alg_ops.c      |    4 +-
 src/libstrongswan/plugins/agent/Makefile.in        |    2 +
 src/libstrongswan/plugins/bliss/Makefile.in        |    2 +
 src/libstrongswan/plugins/bliss/tests/Makefile.in  |    2 +
 src/libstrongswan/plugins/blowfish/Makefile.in     |    2 +
 src/libstrongswan/plugins/ccm/Makefile.in          |    2 +
 src/libstrongswan/plugins/chapoly/Makefile.in      |    2 +
 src/libstrongswan/plugins/cmac/Makefile.in         |    2 +
 src/libstrongswan/plugins/constraints/Makefile.in  |    2 +
 src/libstrongswan/plugins/ctr/Makefile.in          |    2 +
 src/libstrongswan/plugins/curl/Makefile.in         |    2 +
 src/libstrongswan/plugins/curve25519/Makefile.in   |    2 +
 src/libstrongswan/plugins/des/Makefile.in          |    2 +
 src/libstrongswan/plugins/dnskey/Makefile.in       |    2 +
 src/libstrongswan/plugins/files/Makefile.in        |    2 +
 src/libstrongswan/plugins/fips_prf/Makefile.in     |    2 +
 src/libstrongswan/plugins/gcm/Makefile.in          |    2 +
 src/libstrongswan/plugins/gcrypt/Makefile.in       |    2 +
 src/libstrongswan/plugins/gmp/Makefile.in          |    2 +
 src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c |    7 +-
 src/libstrongswan/plugins/hmac/Makefile.in         |    2 +
 src/libstrongswan/plugins/keychain/Makefile.in     |    2 +
 src/libstrongswan/plugins/ldap/Makefile.in         |    2 +
 src/libstrongswan/plugins/md4/Makefile.in          |    2 +
 src/libstrongswan/plugins/md5/Makefile.in          |    2 +
 src/libstrongswan/plugins/mgf1/Makefile.in         |    2 +
 src/libstrongswan/plugins/mysql/Makefile.in        |    2 +
 src/libstrongswan/plugins/mysql/mysql_database.c   |   21 +-
 src/libstrongswan/plugins/newhope/Makefile.in      |    2 +
 .../plugins/newhope/tests/Makefile.in              |    2 +
 src/libstrongswan/plugins/nonce/Makefile.in        |    2 +
 src/libstrongswan/plugins/ntru/Makefile.in         |    2 +
 src/libstrongswan/plugins/openssl/Makefile.in      |    2 +
 src/libstrongswan/plugins/openssl/openssl_crl.c    |   11 +-
 src/libstrongswan/plugins/openssl/openssl_pkcs7.c  |   18 +-
 src/libstrongswan/plugins/padlock/Makefile.in      |    2 +
 src/libstrongswan/plugins/pem/Makefile.in          |    2 +
 src/libstrongswan/plugins/pem/pem_builder.c        |    6 +-
 src/libstrongswan/plugins/pgp/Makefile.in          |    2 +
 src/libstrongswan/plugins/pkcs1/Makefile.in        |    2 +
 src/libstrongswan/plugins/pkcs11/Makefile.in       |    2 +
 src/libstrongswan/plugins/pkcs11/pkcs11_creds.c    |   38 +-
 src/libstrongswan/plugins/pkcs11/pkcs11_library.c  |   22 +-
 src/libstrongswan/plugins/pkcs11/pkcs11_manager.c  |   10 +-
 src/libstrongswan/plugins/pkcs12/Makefile.in       |    2 +
 src/libstrongswan/plugins/pkcs7/Makefile.in        |    2 +
 .../plugins/pkcs7/pkcs7_signed_data.c              |    9 +-
 src/libstrongswan/plugins/pkcs8/Makefile.in        |    2 +
 src/libstrongswan/plugins/plugin_constructors.py   |   60 +
 src/libstrongswan/plugins/plugin_loader.c          |  203 +-
 src/libstrongswan/plugins/plugin_loader.h          |   10 +
 src/libstrongswan/plugins/pubkey/Makefile.in       |    2 +
 src/libstrongswan/plugins/random/Makefile.in       |    2 +
 src/libstrongswan/plugins/rc2/Makefile.in          |    2 +
 src/libstrongswan/plugins/rdrand/Makefile.in       |    2 +
 src/libstrongswan/plugins/revocation/Makefile.in   |    2 +
 src/libstrongswan/plugins/sha1/Makefile.in         |    2 +
 src/libstrongswan/plugins/sha2/Makefile.in         |    2 +
 src/libstrongswan/plugins/sha3/Makefile.in         |    2 +
 src/libstrongswan/plugins/soup/Makefile.in         |    2 +
 src/libstrongswan/plugins/sqlite/Makefile.in       |    2 +
 src/libstrongswan/plugins/sqlite/sqlite_database.c |   33 +-
 src/libstrongswan/plugins/sshkey/Makefile.in       |    2 +
 src/libstrongswan/plugins/test_vectors/Makefile.in |    2 +
 src/libstrongswan/plugins/unbound/Makefile.in      |    2 +
 src/libstrongswan/plugins/winhttp/Makefile.in      |    2 +
 src/libstrongswan/plugins/x509/Makefile.in         |    2 +
 src/libstrongswan/plugins/x509/x509_ac.c           |   44 +-
 src/libstrongswan/plugins/x509/x509_cert.c         |  309 ++-
 src/libstrongswan/plugins/x509/x509_crl.c          |   54 +-
 .../plugins/x509/x509_ocsp_response.c              |   54 +-
 src/libstrongswan/plugins/x509/x509_pkcs10.c       |   16 +-
 src/libstrongswan/plugins/xcbc/Makefile.in         |    2 +
 src/libstrongswan/processing/processor.c           |   13 +-
 src/libstrongswan/settings/settings.c              |   67 +-
 src/libstrongswan/tests/Makefile.in                |    2 +
 src/libstrongswan/tests/suites/test_asn1_parser.c  |  106 +-
 src/libstrongswan/tests/suites/test_enumerator.c   |   50 +-
 src/libstrongswan/tests/suites/test_linked_list.c  |  111 +-
 src/libstrongswan/tests/test_suite.h               |    2 +-
 src/libstrongswan/utils/backtrace.c                |    9 +-
 src/libstrongswan/utils/chunk.c                    |    2 +-
 src/libstrongswan/utils/identification.c           |   20 +-
 src/libstrongswan/utils/leak_detective.c           |    3 +
 src/libstrongswan/utils/utils.h                    |   48 +-
 src/libtls/Makefile.in                             |    2 +
 src/libtls/tests/Makefile.in                       |    2 +
 src/libtls/tls_crypto.c                            |   38 +-
 src/libtnccs/Makefile.am                           |    9 +
 src/libtnccs/Makefile.in                           |   22 +-
 src/libtnccs/plugins/tnc_imc/Makefile.in           |    2 +
 src/libtnccs/plugins/tnc_imv/Makefile.in           |    2 +
 .../plugins/tnc_imv/tnc_imv_recommendations.c      |   34 +-
 src/libtnccs/plugins/tnc_tnccs/Makefile.in         |    2 +
 src/libtnccs/plugins/tnccs_11/Makefile.in          |    2 +
 src/libtnccs/plugins/tnccs_11/tnccs_11_plugin.c    |    5 +-
 src/libtnccs/plugins/tnccs_20/Makefile.in          |    2 +
 src/libtnccs/plugins/tnccs_dynamic/Makefile.in     |    2 +
 src/libtnccs/tnc/tnc.c                             |    7 +
 src/libtncif/Makefile.in                           |    2 +
 src/libtpmtss/Makefile.am                          |    9 +
 src/libtpmtss/Makefile.in                          |   22 +-
 src/libtpmtss/plugins/tpm/Makefile.in              |    2 +
 src/libtpmtss/tpm_tss.c                            |    7 +
 src/manager/Makefile.in                            |    2 +
 src/manager/xml.c                                  |   10 +-
 src/medsrv/Makefile.in                             |    2 +
 src/pki/Makefile.in                                |    2 +
 src/pki/commands/issue.c                           |    1 +
 src/pki/commands/signcrl.c                         |   28 +-
 src/pki/man/Makefile.in                            |    2 +
 src/pool/Makefile.in                               |    2 +
 src/pt-tls-client/Makefile.in                      |    2 +
 src/scepclient/Makefile.in                         |    2 +
 src/starter/Makefile.in                            |    2 +
 src/starter/args.c                                 |    2 +
 src/starter/confread.h                             |    3 +
 src/starter/keywords.c                             |   33 +-
 src/starter/keywords.h                             |    1 +
 src/starter/keywords.txt                           |    1 +
 src/starter/parser/conf_parser.c                   |   55 +-
 src/starter/starterstroke.c                        |    1 +
 src/starter/tests/Makefile.in                      |    2 +
 src/stroke/Makefile.in                             |    2 +
 src/stroke/stroke_msg.h                            |    1 +
 src/swanctl/Makefile.in                            |    2 +
 src/swanctl/commands/load_creds.c                  |   19 +-
 src/swanctl/swanctl.conf                           |    9 +-
 src/swanctl/swanctl.conf.5.main                    |   38 +-
 src/swanctl/swanctl.opt                            |   31 +-
 testing/Makefile.in                                |    2 +
 testing/config/kernel/config-4.11                  | 2575 ++++++++++++++++++++
 testing/hosts/default/etc/ip6tables.rules          |    2 +-
 testing/hosts/default/etc/strongswan.conf.testing  |    7 +-
 testing/hosts/default/usr/local/bin/service        |   22 +
 testing/scripts/recipes/013_strongswan.mk          |    1 +
 testing/testing.conf                               |    4 +-
 .../tests/ikev2/rw-eap-aka-sql-rsa/description.txt |    9 +
 .../tests/ikev2/rw-eap-aka-sql-rsa/evaltest.dat    |   14 +
 .../rw-eap-aka-sql-rsa/hosts/carol/etc/ipsec.conf  |   21 +
 .../hosts/carol/etc/ipsec.d/data.sql               |    9 +
 .../hosts/carol/etc/ipsec.d/tables.sql             |   10 +
 .../hosts/carol/etc/ipsec.secrets                  |    1 +
 .../hosts/carol/etc/strongswan.conf                |   11 +
 .../rw-eap-aka-sql-rsa/hosts/moon/etc/ipsec.conf   |   23 +
 .../hosts/moon/etc/ipsec.d/data.sql                |    9 +
 .../hosts/moon/etc/ipsec.d/tables.sql              |   10 +
 .../hosts/moon/etc/strongswan.conf                 |   11 +
 .../tests/ikev2/rw-eap-aka-sql-rsa/posttest.dat    |    4 +
 testing/tests/ikev2/rw-eap-aka-sql-rsa/pretest.dat |    9 +
 testing/tests/ikev2/rw-eap-aka-sql-rsa/test.conf   |   21 +
 testing/tests/ikev2/two-certs/evaltest.dat         |    2 +-
 .../swanctl/rw-eap-aka-sql-rsa/description.txt     |    9 +
 .../tests/swanctl/rw-eap-aka-sql-rsa/evaltest.dat  |   10 +
 .../hosts/carol/etc/ipsec.d/data.sql               |    9 +
 .../hosts/carol/etc/ipsec.d/tables.sql             |   10 +
 .../hosts/carol/etc/strongswan.conf                |   19 +
 .../hosts/carol/etc/swanctl/swanctl.conf           |   26 +
 .../hosts/moon/etc/ipsec.d/data.sql                |    9 +
 .../hosts/moon/etc/ipsec.d/tables.sql              |   10 +
 .../hosts/moon/etc/strongswan.conf                 |   19 +
 .../hosts/moon/etc/swanctl/swanctl.conf            |   26 +
 .../tests/swanctl/rw-eap-aka-sql-rsa/posttest.dat  |    5 +
 .../tests/swanctl/rw-eap-aka-sql-rsa/pretest.dat   |   10 +
 testing/tests/swanctl/rw-eap-aka-sql-rsa/test.conf |   25 +
 .../swanctl/rw-eap-md5-id-rsa/description.txt      |    9 +
 .../tests/swanctl/rw-eap-md5-id-rsa/evaltest.dat   |   11 +
 .../hosts/carol/etc/strongswan.conf                |   14 +
 .../hosts/carol/etc/swanctl/swanctl.conf           |   34 +
 .../hosts/moon/etc/strongswan.conf                 |   14 +
 .../hosts/moon/etc/swanctl/swanctl.conf            |   40 +
 .../tests/swanctl/rw-eap-md5-id-rsa/posttest.dat   |    5 +
 .../tests/swanctl/rw-eap-md5-id-rsa/pretest.dat    |    8 +
 testing/tests/swanctl/rw-eap-md5-id-rsa/test.conf  |   25 +
 474 files changed, 10691 insertions(+), 4334 deletions(-)

diff --git a/Android.common.mk b/Android.common.mk
index 56e5fd8..1302123 100644
--- a/Android.common.mk
+++ b/Android.common.mk
@@ -26,5 +26,5 @@ add_plugin_subdirs = $(if $(call plugin_enabled,$(1)), \
               )
 
 # strongSwan version, replaced by top Makefile
-strongswan_VERSION := "5.5.2"
+strongswan_VERSION := "5.5.3"
 
diff --git a/Doxyfile.in b/Doxyfile.in
index 7608ffe..6c59d86 100644
--- a/Doxyfile.in
+++ b/Doxyfile.in
@@ -743,7 +743,7 @@ WARN_LOGFILE           =
 # spaces.
 # Note: If this tag is empty the current directory is searched.
 
-INPUT                  = @SRC_DIR@/src @SRC_DIR@/README.md
+INPUT                  = @SRC_DIR@/README.md @SRC_DIR@/README_LEGACY.md @SRC_DIR@/src
 
 # This tag can be used to specify the character encoding of the source files
 # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
diff --git a/Makefile.am b/Makefile.am
index a02c576..47e9e8c 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,5 +1,9 @@
 SUBDIRS = src man conf init testing
 
+if USE_FUZZING
+  SUBDIRS += fuzz
+endif
+
 if USE_SCRIPTS
   SUBDIRS += scripts
 endif
diff --git a/Makefile.in b/Makefile.in
index 521c253..07528a7 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -88,7 +88,8 @@ PRE_UNINSTALL = :
 POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
- at USE_SCRIPTS_TRUE@am__append_1 = scripts
+ at USE_FUZZING_TRUE@am__append_1 = fuzz
+ at USE_SCRIPTS_TRUE@am__append_2 = scripts
 subdir = .
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \
@@ -196,7 +197,7 @@ am__define_uniq_tagged_files = \
 ETAGS = etags
 CTAGS = ctags
 CSCOPE = cscope
-DIST_SUBDIRS = src man conf init testing scripts
+DIST_SUBDIRS = src man conf init testing fuzz scripts
 am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config.h.in \
 	$(top_srcdir)/src/dumm/ext/extconf.rb.in AUTHORS COPYING \
 	ChangeLog INSTALL NEWS README TODO compile config.guess \
@@ -386,6 +387,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -408,6 +410,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
@@ -472,7 +475,7 @@ tss2_LIBS = @tss2_LIBS@
 urandom_device = @urandom_device@
 xml_CFLAGS = @xml_CFLAGS@
 xml_LIBS = @xml_LIBS@
-SUBDIRS = src man conf init testing $(am__append_1)
+SUBDIRS = src man conf init testing $(am__append_1) $(am__append_2)
 @USE_SILENT_RULES_TRUE at AM_MAKEFLAGS = -s
 ACLOCAL_AMFLAGS = -I m4/config
 EXTRA_DIST = Doxyfile.in LICENSE Android.common.mk.in Android.common.mk Android.mk
diff --git a/NEWS b/NEWS
index aed5ee1d..98aefe7 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,61 @@
+strongswan-5.5.3
+----------------
+
+- Fixed a DoS vulnerability in the gmp plugin that was caused by insufficient
+  input validation when verifying RSA signatures.  More specifically,
+  mpz_powm_sec() has two requirements regarding the passed exponent and modulus
+  that the plugin did not enforce, if these are not met the calculation will
+  result in a floating point exception that crashes the whole process.
+  This vulnerability has been registered as CVE-2017-9022.
+
+- Fixed a DoS vulnerability in the x509 plugin that was caused because the ASN.1
+  parser didn't handle ASN.1 CHOICE types properly, which could result in an
+  infinite loop when parsing X.509 extensions that use such types.
+  This vulnerability has been registered as CVE-2017-9023.
+
+- The behavior during IKEv2 CHILD_SA rekeying has been changed in order to avoid
+  traffic loss. The responder now only installs the new inbound SA and delays
+  installing the outbound SA until it receives the DELETE for the replaced
+  CHILD_SA.  Similarly, the inbound SA of the replaced CHILD_SA is not removed
+  for a configurable amount of seconds (charon.delete_rekeyed_delay) after the
+  DELETE has been processed to reduce the chance of dropping delayed packets.
+
+- The code base has been ported to Apple's ARM64 iOS platform, whose calling
+  conventions for variadic and regular functions are different.  This means
+  assigning non-variadic functions to variadic function pointers does not work.
+  To avoid this issue the enumerator_t interface has been changed and the
+  signatures of the callback functions for enumerator_create_filter(), and the
+  invoke_function() and find_first() methods on linked_list_t have been changed.
+  The return type of find_first() also changed from status_t to bool.
+
+- Added support for fuzzing the certificate parser provided by the default
+  plugins (x509, pem, gmp etc.) on Google's OSS-Fuzz infrastructure. Several
+  issues found while fuzzing these plugins were fixed.
+
+- Two new options have been added to charon's retransmission settings:
+  retransmit_limit and retransmit_jitter.  The former adds an upper limit to the
+  calculated retransmission timeout, the latter randomly reduces it.
+
+- A bug in swanctl's --load-creds command was fixed that caused unencrypted
+  private keys to get unloaded if the command was called multiple times. The
+  load-key VICI command now returns the key ID of the loaded key on success.
+
+- The credential manager now enumerates local credential sets before global
+  ones. This means certificates supplied by the peer will now be preferred over
+  certificates with the same identity that may be locally stored (e.g. in the
+  certificate cache).
+
+- Added support for hardware offload of IPsec SAs as introduced by Linux 4.11
+  for hardware that supports this.
+
+- When building the libraries monolithically and statically the plugin
+  constructors are now hard-coded in each library so the plugin code is not
+  removed by the linker because it thinks none of their symbols are ever
+  referenced.
+
+- The pki tool loads the curve25519 plugin by default.
+
+
 strongswan-5.5.2
 ----------------
 
diff --git a/README b/README
index e344424..979b0eb 100644
--- a/README
+++ b/README
@@ -4,23 +4,26 @@
 
 strongSwan is an OpenSource IPsec-based VPN solution.
 
-This document is just a short introduction, for more detailed information
-consult the man pages and [**our wiki**](http://wiki.strongswan.org).
+This document is just a short introduction of the strongSwan **swanctl** command
+which uses the modern [**vici**](src/libcharon/plugins/vici/README.md) *Versatile
+IKE Configuration Interface*. The deprecated **ipsec** command using the legacy
+**stroke** configuration interface is described [**here**](README_LEGACY.md).
+For more detailed information consult the man pages and
+[**our wiki**](http://wiki.strongswan.org).
 
 
 ## Quickstart ##
 
-In the following examples we assume, for reasons of clarity, that **left**
-designates the **local** host and that **right** is the **remote** host.
-
 Certificates for users, hosts and gateways are issued by a fictitious
-strongSwan CA.  How to generate private keys and certificates using OpenSSL or
-the strongSwan PKI tool will be explained in one of the sections below.
-The CA certificate `strongswanCert.pem` must be present on all VPN endpoints
-in order to be able to authenticate the peers.
+strongSwan CA. In our example scenarios the CA certificate `strongswanCert.pem`
+must be present on all VPN endpoints in order to be able to authenticate the
+peers. For your particular VPN application you can either use certificates from
+any third-party CA or generate the needed private keys and certificates yourself
+with the strongSwan **pki** tool, the use of which will be explained in one of
+the sections following below.
 
 
-### Site-to-site case ###
+### Site-to-Site Case ###
 
 In this scenario two security gateways _moon_ and _sun_ will connect the
 two subnets _moon-net_ and _sun-net_ with each other through a VPN tunnel
@@ -31,46 +34,80 @@ set up between the two gateways:
 
 Configuration on gateway _moon_:
 
-    /etc/ipsec.d/cacerts/strongswanCert.pem
-
-    /etc/ipsec.d/certs/moonCert.pem
-
-    /etc/ipsec.secrets:
-
-        : RSA moonKey.pem "<optional passphrase>"
+    /etc/swanctl/x509ca/strongswanCert.pem
+    /etc/swanctl/x509/moonCert.pem
+    /etc/swanctl/priv/moonKey.pem
+
+    /etc/swanctl/swanctl.conf:
+
+        connections {
+            net-net {
+                remote_addrs = 192.168.0.2
+
+                local {
+                    auth = pubkey
+                    certs = moonCert.pem
+                }
+                remote {
+                    auth = pubkey
+                    id = "C=CH, O=strongSwan, CN=sun.strongswan.org"
+                }
+                children {
+                    net-net {
+                        local_ts  = 10.1.0.0/16
+                        remote_ts = 10.2.0.0/16
+                        start_action = trap
+                   }
+                }
+            }
+        }
 
-    /etc/ipsec.conf:
+Configuration on gateway _sun_:
 
-        conn net-net
-            leftsubnet=10.1.0.0/16
-            leftcert=moonCert.pem
-            right=192.168.0.2
-            rightsubnet=10.2.0.0/16
-            rightid="C=CH, O=strongSwan, CN=sun.strongswan.org"
-            auto=start
+    /etc/swanctl/x509ca/strongswanCert.pem
+    /etc/swanctl/x509/sunCert.pem
+    /etc/swanctl/priv/sunKey.pem
 
-Configuration on gateway _sun_:
+    /etc/swanctl/swanctl.conf:
 
-    /etc/ipsec.d/cacerts/strongswanCert.pem
+        connections {
+            net-net {
+                remote_addrs = 192.168.0.1
 
-    /etc/ipsec.d/certs/sunCert.pem
+                local {
+                    auth = pubkey
+                    certs = sunCert.pem
+                }
+                remote {
+                    auth = pubkey
+                    id = "C=CH, O=strongSwan, CN=moon.strongswan.org"
+                }
+                children {
+                    net-net {
+                        local_ts  = 10.2.0.0/16
+                        remote_ts = 10.1.0.0/16
+                        start_action = trap
+                   }
+                }
+            }
+        }
 
-    /etc/ipsec.secrets:
+The local and remote identities used in this scenario are the
+*subjectDistinguishedNames* contained in the end entity certificates.
+The certificates and private keys are loaded into the **charon** daemon with
+the command
 
-        : RSA sunKey.pem "<optional passphrase>"
+    swanctl --load-creds
 
-    /etc/ipsec.conf:
+whereas
 
-        conn net-net
-            leftsubnet=10.2.0.0/16
-            leftcert=sunCert.pem
-            right=192.168.0.1
-            rightsubnet=10.1.0.0/16
-            rightid="C=CH, O=strongSwan, CN=moon.strongswan.org"
-            auto=start
+    swanctl --load-conns
 
+loads the connections defined in `swanctl.conf`. With `start_action = trap` the
+IPsec connection is automatically set up with the first plaintext payload IP
+packet wanting to go through the tunnel.
 
-### Host-to-host case ###
+### Host-to-Host Case ###
 
 This is a setup between two single hosts which don't have a subnet behind
 them.  Although IPsec transport mode would be sufficient for host-to-host
@@ -79,44 +116,64 @@ connections we will use the default IPsec tunnel mode.
     | 192.168.0.1 | === | 192.168.0.2 |
          moon                sun
 
-Configuration on host _moon_:
-
-    /etc/ipsec.d/cacerts/strongswanCert.pem
-
-    /etc/ipsec.d/certs/moonCert.pem
-
-    /etc/ipsec.secrets:
-
-        : RSA moonKey.pem "<optional passphrase>"
-
-    /etc/ipsec.conf:
-
-        conn host-host
-            leftcert=moonCert.pem
-            right=192.168.0.2
-            rightid="C=CH, O=strongSwan, CN=sun.strongswan.org"
-            auto=start
+ Configuration on host _moon_:
+
+    /etc/swanctl/x509ca/strongswanCert.pem
+    /etc/swanctl/x509/moonCert.pem
+    /etc/swanctl/priv/moonKey.pem
+
+    /etc/swanctl/swanctl.conf:
+
+        connections {
+            host-host {
+                remote_addrs = 192.168.0.2
+
+                local {
+                    auth=pubkey
+                    certs = moonCert.pem
+                }
+                remote {
+                    auth = pubkey
+                    id = "C=CH, O=strongSwan, CN=sun.strongswan.org"
+                }
+                children {
+                    net-net {
+                        start_action = trap
+                    }
+                }
+            }
+        }
 
 Configuration on host _sun_:
 
-    /etc/ipsec.d/cacerts/strongswanCert.pem
+    /etc/swanctl/x509ca/strongswanCert.pem
+    /etc/swanctl/x509/sunCert.pem
+    /etc/swanctl/priv/sunKey.pem
 
-    /etc/ipsec.d/certs/sunCert.pem
+    /etc/swanctl/swanctl.conf:
 
-    /etc/ipsec.secrets:
+        connections {
+            host-host {
+                remote_addrs = 192.168.0.1
 
-        : RSA sunKey.pem "<optional passphrase>"
+                local {
+                    auth = pubkey
+                    certs = sunCert.pem
+                }
+                remote {
+                    auth = pubkey
+                    id = "C=CH, O=strongSwan, CN=moon.strongswan.org"
+                }
+                children {
+                    host-host {
+                        start_action = trap
+                   }
+                }
+            }
+        }
 
-    /etc/ipsec.conf:
 
-        conn host-host
-            leftcert=sunCert.pem
-            right=192.168.0.1
-            rightid="C=CH, O=strongSwan, CN=moon.strongswan.org"
-            auto=start
-
-
-### Roadwarrior case ###
+### Roadwarrior Case ###
 
 This is a very common case where a strongSwan gateway serves an arbitrary
 number of remote VPN clients usually having dynamic IP addresses.
@@ -126,43 +183,68 @@ number of remote VPN clients usually having dynamic IP addresses.
 
 Configuration on gateway _moon_:
 
-    /etc/ipsec.d/cacerts/strongswanCert.pem
-
-    /etc/ipsec.d/certs/moonCert.pem
-
-    /etc/ipsec.secrets:
-
-        : RSA moonKey.pem "<optional passphrase>"
-
-    /etc/ipsec.conf:
-
-        conn rw
-            leftsubnet=10.1.0.0/16
-            leftcert=moonCert.pem
-            right=%any
-            auto=add
+    /etc/swanctl/x509ca/strongswanCert.pem
+    /etc/swanctl/x509/moonCert.pem
+    /etc/swanctl/priv/moonKey.pem
+
+    /etc/swanctl/swanctl.conf:
+
+        connections {
+            rw {
+                local {
+                    auth = pubkey
+                    certs = moonCert.pem
+                    id = moon.strongswan.org
+                }
+                remote {
+                    auth = pubkey
+                }
+                children {
+                    net-net {
+                        local_ts  = 10.1.0.0/16
+                    }
+                }
+            }
+        }
 
 Configuration on roadwarrior _carol_:
 
-    /etc/ipsec.d/cacerts/strongswanCert.pem
-
-    /etc/ipsec.d/certs/carolCert.pem
-
-    /etc/ipsec.secrets:
-
-        : RSA carolKey.pem "<optional passphrase>"
-
-    /etc/ipsec.conf:
-
-        conn home
-            leftcert=carolCert.pem
-            right=192.168.0.1
-            rightsubnet=10.1.0.0/16
-            rightid="C=CH, O=strongSwan, CN=moon.strongswan.org"
-            auto=start
-
-
-### Roadwarrior case with virtual IP ###
+    /etc/swanctl/x509ca/strongswanCert.pem
+    /etc/swanctl/x509/carolCert.pem
+    /etc/swanctl/priv/carolKey.pem
+
+    /etc/swanctl/swanctl.conf:
+
+         connections {
+            home {
+                remote_addrs = moon.strongswan.org
+
+                local {
+                    auth = pubkey
+                    certs = carolCert.pem
+                    id = carol at strongswan.org
+                }
+                remote {
+                    auth = pubkey
+                    id = moon.strongswan.org
+                }
+                children {
+                    home {
+                        local_ts  = 10.1.0.0/16
+                        start_action = start
+                    }
+                }
+            }
+        }
+
+For `remote_addrs` the hostname `moon.strongswan.org` was chosen which will be
+resolved by DNS at runtime into the corresponding IP destination address.
+In this scenario the identity of the roadwarrior `carol` is the email address
+`carol at strongswan.org` which must be included as a *subjectAlternativeName* in
+the roadwarrior certificate `carolCert.pem`.
+
+
+### Roadwarrior Case with Virtual IP ###
 
 Roadwarriors usually have dynamic IP addresses assigned by the ISP they are
 currently attached to.  In order to simplify the routing from _moon-net_ back
@@ -173,1126 +255,439 @@ an inner IP address chosen from a pre-defined pool.
       moon-net          moon              carol       virtual IP
 
 In our example the virtual IP address is chosen from the address pool
-`10.3.0.0/16` which can be configured by adding the parameter
+`10.3.0.0/16` which can be configured by adding the section
 
-    rightsourceip=10.3.0.0/16
+    pools {
+        rw_pool {
+            addrs = 10.3.0.0/16
+        }
+    }
 
-to the gateway's `ipsec.conf`.  To request an IP address from this pool a
-roadwarrior can use IKEv1 mode config or IKEv2 configuration payloads.
-The configuration for both is the same
+to the gateway's `swanctl.conf` from where they are loaded into the **charon**
+daemon using the command
 
-    leftsourceip=%config
-
-Configuration on gateway _moon_:
+    swanctl --load-pools
 
-    /etc/ipsec.d/cacerts/strongswanCert.pem
+To request an IP address from this pool a roadwarrior can use IKEv1 mode config
+or IKEv2 configuration payloads. The configuration for both is the same
 
-    /etc/ipsec.d/certs/moonCert.pem
+    vips = 0.0.0.0
 
-    /etc/ipsec.secrets:
-
-        : RSA moonKey.pem "<optional passphrase>"
-
-    /etc/ipsec.conf:
+Configuration on gateway _moon_:
 
-        conn rw
-            leftsubnet=10.1.0.0/16
-            leftcert=moonCert.pem
-            right=%any
-            rightsourceip=10.3.0.0/16
-            auto=add
+    /etc/swanctl/x509ca/strongswanCert.pem
+    /etc/swanctl/x509/moonCert.pem
+    /etc/swanctl/rsa/moonKey.pem
+
+    /etc/swanctl/swanctl.conf:
+
+        connections {
+            rw {
+                pools = rw_pool
+
+                local {
+                    auth = pubkey
+                    certs = moonCert.pem
+                    id = moon.strongswan.org
+                }
+                remote {
+                    auth = pubkey
+                }
+                children {
+                    net-net {
+                        local_ts  = 10.1.0.0/16
+                    }
+                }
+            }
+        }
+
+        pools {
+            rw_pool {
+                addrs = 10.30.0.0/16
+            }
+        }
 
 Configuration on roadwarrior _carol_:
 
-    /etc/ipsec.d/cacerts/strongswanCert.pem
+    /etc/swanctl/x509ca/strongswanCert.pem
+    /etc/swanctl/x509/carolCert.pem
+    /etc/swanctl/priv/carolKey.pem
+
+    /etc/swanctl/swanctl.conf:
+
+         connections {
+            home {
+                remote_addrs = moon.strongswan.org
+                vips = 0.0.0.0
+
+                local {
+                    auth = pubkey
+                    certs = carolCert.pem
+                    id = carol at strongswan.org
+                }
+                remote {
+                    auth = pubkey
+                    id = moon.strongswan.org
+                }
+                children {
+                    home {
+                        local_ts  = 10.1.0.0/16
+                        start_action = start
+                    }
+                }
+            }
+        }
+
+
+### Roadwarrior Case with EAP Authentication ###
 
-    /etc/ipsec.d/certs/carolCert.pem
-
-    /etc/ipsec.secrets:
-
-        : RSA carolKey.pem "<optional passphrase>"
-
-    /etc/ipsec.conf:
-
-        conn home
-            leftsourceip=%config
-            leftcert=carolCert.pem
-            right=192.168.0.1
-            rightsubnet=10.1.0.0/16
-            rightid="C=CH, O=strongSwan, CN=moon.strongswan.org"
-            auto=start
-
-
-## Generating certificates and CRLs ##
+This is a very common case where a strongSwan gateway serves an arbitrary
+number of remote VPN clients which authenticate themselves via a password
+based *Extended Authentication Protocol* as e.g. *EAP-MD5* or *EAP-MSCHAPv2*.
 
-This section is not a full-blown tutorial on how to use OpenSSL or the
-strongSwan PKI tool.  It just lists a few points that are relevant if you want
-to generate your own certificates and CRLs for use with strongSwan.
+    10.1.0.0/16 -- | 192.168.0.1 | === | x.x.x.x |
+      moon-net          moon              carol
 
+Configuration on gateway _moon_:
 
-### Generating a CA certificate ###
+    /etc/swanctl/x509ca/strongswanCert.pem
+    /etc/swanctl/x509/moonCert.pem
+    /etc/swanctl/priv/moonKey.pem
+
+    /etc/swanctl/swanctl.conf:
+
+        connections {
+            rw {
+                local {
+                    auth = pubkey
+                    certs = moonCert.pem
+                    id = moon.strongswan.org
+                }
+                remote {
+                    auth = eap-md5
+                }
+                children {
+                    net-net {
+                        local_ts  = 10.1.0.0/16
+                    }
+                }
+                send_certreq = no
+            }
+        }
+
+The  `swanctl.conf` file additionally contains a `secrets` section defining all
+client credentials
+
+       secrets {
+           eap-carol {
+               id = carol at strongswan.org
+               secret = Ar3etTnp
+           }
+           eap-dave {
+               id = dave at strongswan.org
+               secret = W7R0g3do
+           }
+       }
 
-The OpenSSL statement
+Configuration on roadwarrior _carol_:
 
-    openssl req -x509 -days 1460 -newkey rsa:4096 \
-                -keyout strongswanKey.pem -out strongswanCert.pem
+    /etc/swanctl/x509ca/strongswanCert.pem
+
+    /etc/swanctl/swanctl.conf:
+
+         connections {
+            home {
+                remote_addrs = moon.strongswan.org
+
+                local {
+                    auth = eap
+                    id = carol at strongswan.org
+                }
+                remote {
+                    auth = pubkey
+                    id = moon.strongswan.org
+                }
+                children {
+                    home {
+                        local_ts  = 10.1.0.0/16
+                        start_action = start
+                    }
+                }
+            }
+        }
+
+       secrets {
+           eap-carol {
+               id = carol at strongswan.org
+               secret = Ar3etTnp
+           }
+       }
+
+
+### Roadwarrior Case with EAP Identity ###
+
+Often a client EAP identity is exchanged via EAP which differs from the
+external IKEv2 identity. In this example the IKEv2 identity defaults to
+the IPv4 address of the client.
 
-creates a 4096 bit RSA private key `strongswanKey.pem` and a self-signed CA
-certificate `strongswanCert.pem` with a validity of 4 years (1460 days).
+    10.1.0.0/16 -- | 192.168.0.1 | === | x.x.x.x |
+      moon-net          moon              carol
 
-    openssl x509 -in cert.pem -noout -text
+Configuration on gateway _moon_:
 
-lists the properties of  a X.509 certificate `cert.pem`. It allows you to verify
-whether the configuration defaults in `openssl.cnf` have been inserted
-correctly.
+    /etc/swanctl/x509ca/strongswanCert.pem
+    /etc/swanctl/x509/moonCert.pem
+    /etc/swanctl/priv/moonKey.pem
+
+    /etc/swanctl/swanctl.conf:
+
+        connections {
+            rw {
+                local {
+                    auth = pubkey
+                    certs = moonCert.pem
+                    id = moon.strongswan.org
+                }
+                remote {
+                    auth = eap-md5
+                    eap_id = %any
+                }
+                children {
+                    net-net {
+                        local_ts  = 10.1.0.0/16
+                    }
+                }
+                send_certreq = no
+            }
+        }
+
+       secrets {
+           eap-carol {
+               id = carol
+               secret = Ar3etTnp
+           }
+           eap-dave {
+               id = dave
+               secret = W7R0g3do
+           }
+       }
 
-If you prefer the CA certificate to be in binary DER format then the following
-command achieves this transformation:
+Configuration on roadwarrior _carol_:
 
-     openssl x509 -in strongswanCert.pem -outform DER -out strongswanCert.der
+    /etc/swanctl/x509ca/strongswanCert.pem
 
-The statements
+    /etc/swanctl/swanctl.conf:
 
-    ipsec pki --gen -s 4096 > strongswanKey.der
-    ipsec pki --self --ca --lifetime 1460 --in strongswanKey.der \
-              --dn "C=CH, O=strongSwan, CN=strongSwan Root CA" \
-              > strongswanCert.der
-    ipsec pki --print --in strongswanCert.der
+         connections {
+            home {
+                remote_addrs = moon.strongswan.org
 
-achieve about the same with the strongSwan PKI tool.  Unlike OpenSSL the tool
-stores keys and certificates in the binary DER format by default.
-The `--outform` option may be used to write PEM encoded files.
+                local {
+                    auth = eap
+                    eap_id = carol
+                }
+                remote {
+                    auth = pubkey
+                    id = moon.strongswan.org
+                }
+                children {
+                    home {
+                        local_ts  = 10.1.0.0/16
+                        start_action = start
+                    }
+                }
+            }
+        }
 
-The directory `/etc/ipsec.d/cacerts` contains all required CA certificates
-either in binary DER or in Base64 PEM format, irrespective of the file suffix
-the correct format will be determined.
+       secrets {
+           eap-carol {
+               id = carol
+               secret = Ar3etTnp
+           }
+       }
 
 
-### Generating a host or user certificate ###
+## Generating Certificates and CRLs ##
 
-The OpenSSL statement
+This section is not a full-blown tutorial on how to use the strongSwan **pki**
+tool. It just lists a few points that are relevant if you want to generate your
+own certificates and CRLs for use with strongSwan.
 
-     openssl req -newkey rsa:2048 -keyout hostKey.pem \
-                 -out hostReq.pem
 
-generates a 2048 bit RSA private key `hostKey.pem` and a certificate request
-`hostReq.pem` which has to be signed by the CA.
+### Generating a CA Certificate ###
 
-If you want to add a _subjectAltName_ field to the host certificate you must
-edit the OpenSSL configuration file `openssl.cnf` and add the following line in
-the `[ usr_cert ]` section:
+The pki statement
 
-     subjectAltName=DNS:moon.strongswan.org
+    pki --gen --type ed25519 --outform pem > strongswanKey.pem
 
-if you want to identify the host by its Fully Qualified Domain Name (FQDN), or
+generates an elliptic Edwards-Curve key with a cryptographic strength of 128
+bits. The corresponding public key is packed into a self-signed CA certificate
+with a lifetime of 10 years (3652 days)
 
-     subjectAltName=IP:192.168.0.1
+    pki --self --ca --lifetime 3652 --in strongswanKey.pem \
+               --dn "C=CH, O=strongSwan, CN=strongSwan Root CA" \
+               --outform pem > strongswanCert.pem
 
-if you want the ID to be of type _IPV4_ADDR_. Of course you could include both
-ID types with
+which can be listed with the command
 
-     subjectAltName=DNS:moon.strongswan.org,IP:192.168.0.1
+    pki --print --in strongswanCert.pem
 
-but the use of an IP address for the identification of a host should be
-discouraged anyway.
+    subject:  "C=CH, O=strongSwan, CN=strongSwan Root CA"
+    issuer:   "C=CH, O=strongSwan, CN=strongSwan Root CA"
+    validity:  not before May 18 08:32:06 2017, ok
+               not after  May 18 08:32:06 2027, ok (expires in 3651 days)
+    serial:    57:e0:6b:3a:9a:eb:c6:e0
+    flags:     CA CRLSign self-signed
+    subjkeyId: 2b:95:14:5b:c3:22:87:de:d1:42:91:88:63:b3:d5:c1:92:7a:0f:5d
+    pubkey:    ED25519 256 bits
+    keyid:     a7:e1:6a:3f:e7:6f:08:9d:89:ec:23:92:a9:a1:14:3c:78:a8:7a:f7
+    subjkey:   2b:95:14:5b:c3:22:87:de:d1:42:91:88:63:b3:d5:c1:92:7a:0f:5d
 
-For user certificates the appropriate ID type is _RFC822_ADDR_ which can be
-specified as
+If you prefer the CA private key and X.509 certificate to be in binary DER format
+then just omit the `--outform pem` option. The directory `/etc/swanctl/x509ca`
+contains all required CA certificates either in binary DER or in Base64 PEM
+format. Irrespective of the file suffix the correct format will be determined
+by strongSwan automagically.
 
-     subjectAltName=email:carol at strongswan.org
 
-or if the user's e-mail address is part of the subject's distinguished name
+### Generating a Host or User End Entity Certificate ###
 
-     subjectAltName=email:copy
+Again we are using the command
 
-Now the certificate request can be signed by the CA with the command
+    pki --gen --type ed25519 --outform pem > moonKey.pem
 
-     openssl ca -in hostReq.pem -days 730 -out hostCert.pem -notext
+to generate an Ed25519 private key for the host `moon`. Alternatively you could
+type
 
-If you omit the `-days` option then the `default_days` value (365 days)
-specified in `openssl.cnf` is used.  The `-notext` option avoids that a human
-readable listing of the certificate is prepended to the Base64 encoded
-certificate body.
+    pki --gen --type rsa --size 3072 > moonKey.der
 
-If you want to use the dynamic CRL fetching feature described in one of the
-following sections then you may include one or several _crlDistributionPoints_
-in your end certificates.  This can be done in the `[ usr_cert ]` section of the
-`openssl.cnf` configuration file:
+to generate a traditional 3072 bit RSA key and store it in binary DER format.
+As an alternative a **TPM 2.0** *Trusted Platform Module* available on every
+recent Intel platform could be used as a virtual smartcard to securely store an
+RSA or ECDSA private key. For details, refer to the TPM 2.0
+[HOWTO](https://wiki.strongswan.org/projects/strongswan/wiki/TpmPlugin).
 
-    crlDistributionPoints=@crl_dp
+In a next step the command
 
-    [ crl_dp ]
+    pki --req --type priv --in moonKey.pem \
+              --dn "C=CH, O=strongswan, CN=moon.strongswan.org \
+              --san moon.strongswan.org -- outform pem > moonReq.pem
 
-    URI.1="http://crl.strongswan.org/strongswan.crl"
-    URI.2="ldap://ldap.strongswan.org/cn=strongSwan Root CA, o=strongSwan,
-           c=CH?certificateRevocationList"
+creates a PKCS#10 certificate request that has to be signed by the CA.
+Through the [multiple] use of the `--san` parameter any number of desired
+*subjectAlternativeNames* can be added to the request. These can be of the
+form
 
-If you have only a single HTTP distribution point then the short form
+    --san sun.strongswan.org     # fully qualified host name
+    --san carol at strongswan.org   # RFC822 user email address
+    --san 192.168.0.1            # IPv4 address
+    --san fec0::1                # IPv6 address
 
-    crlDistributionPoints="URI:http://crl.strongswan.org/strongswan.crl"
+Based on the certificate request the CA issues a signed end entity certificate
+with the following command
 
-also works.
+    pki --issue --cacert strongswanCert.pem --cakey strongswanKey.pem \
+                --type pkcs10 --in moonReq.pem --serial 01 --lifetime 1826 \
+                --outform pem > moonCert.pem
 
-Again the statements
+If the `--serial` parameter with a hexadecimal argument is omitted then a random
+serial number is generated. Some third party VPN clients require that a VPN
+gateway certificate contains the *TLS Server Authentication* Extended Key Usage
+(EKU) flag which can be included with the following option
 
-    ipsec pki --gen > moonKey.der
-    ipsec pki --pub --in moonKey.der | ipsec pki --issue --lifetime 730 \
-              --cacert strongswanCert.der --cakey strongswanKey.der \
-              --dn "C=CH, O=strongSwan, CN=moon.strongswan.org" \
-              --san moon.strongswan.org --san 192.168.0.1 \
-              --crl http://crl.strongswan.org/strongswan.crl > moonCert.der
+    --flag serverAuth
 
-do something similar using the strongSwan PKI tool.
-
-Usually, a Windows or Mac OS X (or iOS) based VPN client needs its private key,
-its host or user certificate, and the CA certificate.  The most convenient way
+If you want to use the dynamic CRL fetching feature described in one of the
+following sections then you may include one or several *crlDistributionPoints*
+in your end entity certificates using the `--crl` parameter
+
+    --crl  http://crl.strongswan.org/strongswan.crl
+    --crl "ldap://ldap.strongswan.org/cn=strongSwan Root CA, o=strongSwan,c=CH?certificateRevocationList"
+
+The issued host certificate can be listed with
+
+    pki --print --in moonCert.pem
+
+    subject:  "C=CH, O=strongSwan, CN=moon.strongswan.org"
+    issuer:   "C=CH, O=strongSwan, CN=strongSwan Root CA"
+    validity:  not before May 19 10:28:19 2017, ok
+               not after  May 19 10:28:19 2022, ok (expires in 1825 days)
+    serial:    01
+    altNames:  moon.strongswan.org
+    flags:     serverAuth
+    CRL URIs:  http://crl.strongswan.org/strongswan.crl
+    authkeyId: 2b:95:14:5b:c3:22:87:de:d1:42:91:88:63:b3:d5:c1:92:7a:0f:5d
+    subjkeyId: 60:9d:de:30:a6:ca:b9:8e:87:bb:33:23:61:19:18:b8:c4:7e:23:8f
+    pubkey:    ED25519 256 bits
+    keyid:     39:1b:b3:c2:34:72:1a:01:08:40:ce:97:75:b8:be:ce:24:30:26:29
+    subjkey:   60:9d:de:30:a6:ca:b9:8e:87:bb:33:23:61:19:18:b8:c4:7e:23:8f
+
+Usually, a Windows, OSX, Android or iOS based VPN client needs its private key,
+its host or user certificate and the CA certificate.  The most convenient way
 to load this information is to put everything into a PKCS#12 container:
 
-     openssl pkcs12 -export -inkey carolKey.pem \
-                    -in carolCert.pem -name "carol" \
-                    -certfile strongswanCert.pem -caname "strongSwan Root CA" \
-                    -out carolCert.p12
+    openssl pkcs12 -export -inkey carolKey.pem \
+                   -in carolCert.pem -name "carol" \
+                   -certfile strongswanCert.pem -caname "strongSwan Root CA" \
+                   -out carolCert.p12
+
+The strongSwan **pki** tool currently is not able to create PKCS#12 containers
+so that **openssl** must be used.
 
 
 ### Generating a CRL ###
 
 An empty CRL that is signed by the CA can be generated with the command
 
-     openssl ca -gencrl -crldays 15 -out crl.pem
-
-If you omit the `-crldays` option then the `default_crl_days` value (30 days)
-specified in `openssl.cnf` is used.
-
-If you prefer the CRL to be in binary DER format then this conversion
-can be achieved with
-
-     openssl crl -in crl.pem -outform DER -out cert.crl
-
-The strongSwan PKI tool provides the `--signcrl` command to sign CRLs.
-
-The directory `/etc/ipsec.d/crls` contains all CRLs either in binary DER
-or in Base64 PEM format, irrespective of the file suffix the correct format
-will be determined.
-
-
-### Revoking a certificate ###
-
-A specific host certificate stored in the file `host.pem` is revoked with the
-command
-
-     openssl ca -revoke host.pem
-
-Next the CRL file must be updated
-
-     openssl ca -gencrl -crldays 60 -out crl.pem
-
-The content of the CRL file can be listed with the command
-
-     openssl crl -in crl.pem -noout -text
-
-in the case of a Base64 CRL, or alternatively for a CRL in DER format
-
-     openssl crl -inform DER -in cert.crl -noout -text
-
-Again the `--signcrl` command of the strongSwan PKI tool may also be used to
-create new CRLs containing additional certificates.
-
-
-## Configuring the connections - ipsec.conf ##
-
-### Configuring my side ###
-
-Usually the **local** side is the same for all connections.  Therefore it makes
-sense to put the definitions characterizing the strongSwan security gateway into
-the `conn %default` section of the configuration file `/etc/ipsec.conf`.  If we
-assume throughout this document that the strongSwan security gateway is **left**
-and the peer is **right** then we can write
-
-    conn %default
-         leftcert=moonCert.pem
-         # load connection definitions automatically
-         auto=add
-
-The X.509 certificate by which the strongSwan security gateway will authenticate
-itself by sending it in binary form to its peers as part of the Internet Key
-Exchange (IKE) is specified in the line
-
-     leftcert=moonCert.pem
-
-The certificate can either be stored in Base64 PEM-format or in the binary
-DER-format. Irrespective of the file suffix the correct format will be
-determined.  Therefore `leftcert=moonCert.der` or `leftcert=moonCert.cer`
-would also be valid alternatives.
-
-When using relative pathnames as in the examples above, the certificate files
-must be stored in in the directory `/etc/ipsec.d/certs`.  In order to
-distinguish strongSwan's own certificates from locally stored trusted peer
-certificates (see below for details), they could also be stored in a
-subdirectory below `/etc/ipsec.d/certs` as e.g. in
-
-    leftcert=mycerts/moonCert.pem
-
-Absolute pathnames are also possible as in
-
-    leftcert=/usr/ssl/certs/moonCert.pem
-
-As an ID for the VPN gateway we recommend the use of a Fully Qualified Domain
-Name (FQDN) of the form
-
-    conn rw
-         right=%any
-         leftid=moon.strongswan.org
-
-**Important**: When a FQDN identifier is used it must be explicitly included as
-a so called _subjectAltName_ of type _dnsName_ (`DNS:`) in the certificate
-indicated by `leftcert`.  For details on how to generate certificates with
-_subjectAltNames_, please refer to the sections above.
-
-If you don't want to mess with _subjectAltNames_, you can use the certificate's
-Distinguished Name (DN) instead, which is an identifier of type _DER_ASN1_DN_
-and which can be written e.g. in the LDAP-type format
-
-    conn rw
-         right=%any
-         leftid="C=CH, O=strongSwan, CN=moon.strongswan.org"
-
-Since the subject's DN is part of the certificate, the `leftid` does not have to
-be declared explicitly. Thus the entry
-
-    conn rw
-         right=%any
-
-automatically assumes the subject DN of `leftcert` to be the host ID.
-
-
-### Multiple certificates ###
-
-strongSwan supports multiple local host certificates and corresponding
-RSA private keys:
-
-    conn rw1
-         right=%any
-         rightid=peer1.domain1
-         leftcert=myCert1.pem
-         # leftid is DN of myCert1
-
-    conn rw2
-         right=%any
-         rightid=peer2.domain2
-         leftcert=myCert2.pem
-         # leftid is DN of myCert2
-
-When _peer1_ initiates a connection then strongSwan will send _myCert1_ and will
-sign with _myKey1_ defined in `/etc/ipsec.secrets` (see below) whereas
-_myCert2_ and _myKey2_ will be used in a connection setup started from _peer2_.
-
-
-### Configuring the peer side using CA certificates ###
-
-Now we can proceed to define our connections.  In many applications we might
-have dozens of road warriors connecting to a central strongSwan security
-gateway. The following most simple statement:
-
-    conn rw
-         right=%any
-
-defines the general roadwarrior case.  The line `right=%any` literally means
-that any IPsec peer is accepted, regardless of its current IP source address and
-its ID, as long as the peer presents a valid X.509 certificate signed by a CA
-the strongSwan security gateway puts explicit trust in.  Additionally, the
-signature during IKE gives proof that the peer is in possession of the private
-key matching the public key contained in the transmitted certificate.
-
-The ID by which a peer is identifying itself during IKE can by any of the ID
-types _IPV[46]_ADDR_, _FQDN_, _RFC822_ADDR_ or _DER_ASN1_DN_.  If one of the
-first three ID types is used, then the accompanying X.509 certificate of the
-peer must contain a matching _subjectAltName_ field of the type _ipAddress_
-(`IP:`), _dnsName_ (`DNS:`) or _rfc822Name_ (`email:`), respectively.  With the
-fourth type, _DER_ASN1_DN_, the identifier must completely match the subject
-field of the peer's certificate.  One of the two possible representations of a
-Distinguished Name (DN) is the LDAP-type format
-
-     rightid="C=CH, O=strongSwan IPsec, CN=sun.strongswan.org"
-
-Additional whitespace can be added everywhere as desired since it will be
-automatically eliminated by the parser.  An exception is the single whitespace
-between individual words, like e.g. in `strongSwan IPsec`, which is preserved.
-
-The Relative Distinguished Names (RDNs) can alternatively be separated by a
-slash `/` instead of a comma `,`
-
-     rightid="/C=CH/O=strongSwan IPsec/CN=sun.strongswan.org"
-
-This is the representation extracted from the certificate by the OpenSSL
-`-subject` command line option
-
-     openssl x509 -in sunCert.pem -noout -subject
-
-The following RDNs are supported by strongSwan
-
-| Name               | Description                      |
-|--------------------|----------------------------------|
-| DC                 | Domain Component                 |
-| C                  | Country                          |
-| ST                 | State or province                |
-| L                  | Locality or town                 |
-| O                  | Organization                     |
-| OU                 | Organizational Unit              |
-| CN                 | Common Name                      |
-| ND                 | NameDistinguisher, used with CN  |
-| N                  | Name                             |
-| G                  | Given name                       |
-| S                  | Surname                          |
-| I                  | Initials                         |
-| T                  | Personal title                   |
-| E                  | E-mail                           |
-| Email              | E-mail                           |
-| emailAddress       | E-mail                           |
-| SN                 | Serial number                    |
-| serialNumber       | Serial number                    |
-| D                  | Description                      |
-| ID                 | X.500 Unique Identifier          |
-| UID                | User ID                          |
-| TCGID              | [Siemens] Trust Center Global ID |
-| UN                 | Unstructured Name                |
-| unstructuredName   | Unstructured Name                |
-| UA                 | Unstructured Address             |
-| unstructuredAddress| Unstructured Address             |
-| EN                 | Employee Number                  |
-| employeeNumber     | Employee Number                  |
-| dnQualifier        | DN Qualifier                     |
-
-With the roadwarrior connection definition listed above, an IPsec SA for
-the strongSwan security gateway `moon.strongswan.org` itself can be established.
-If the roadwarriors should be able to reach e.g. the two subnets `10.1.0.0/24`
-and `10.1.3.0/24` behind the security gateway then the following connection
-definitions will make this possible
-
-    conn rw1
-         right=%any
-         leftsubnet=10.1.0.0/24
-
-    conn rw3
-         right=%any
-         leftsubnet=10.1.3.0/24
-
-For IKEv2 connections this can even be simplified by using
-
-    leftsubnet=10.1.0.0/24,10.1.3.0/24
-
-If not all peers in possession of a X.509 certificate signed by a specific
-certificate authority shall be given access to the Linux security gateway,
-then either a subset of them can be barred by listing the serial numbers of
-their certificates in a certificate revocation list (CRL) or as an alternative,
-access can be controlled by explicitly putting a roadwarrior entry for each
-eligible peer into `ipsec.conf`:
-
-    conn sun
-         right=%any
-         rightid=sun.strongswan.org
-
-    conn carol
-         right=%any
-         rightid=carol at strongswan.org
-
-    conn dave
-         right=%any
-         rightid="C=CH, O=strongSwan, CN=dave at strongswan.org"
-
-When the IP address of a peer is known to be stable, it can be specified as
-well.  This entry is mandatory when the strongSwan host wants to act as the
-initiator of an IPsec connection.
-
-    conn sun
-         right=192.168.0.2
-         rightid=sun.strongswan.org
-
-    conn carol
-         right=192.168.0.100
-         rightid=carol at strongswan.org
-
-    conn dave
-         right=192.168.0.200
-         rightid="C=CH, O=strongSwan, CN=dave at strongswan.org"
-
-    conn venus
-         right=192.168.0.50
-
-In the last example the ID types _FQDN_, _RFC822_ADDR_, _DER_ASN1_DN_ and
-_IPV4_ADDR_, respectively, were used.  Of course all connection definitions
-presented so far have included the lines in the `conn %defaults` section,
-comprising among other a `leftcert` entry.
-
-
-### Handling Virtual IPs and narrowing ###
-
-Often roadwarriors are behind NAT-boxes, which causes the inner IP source
-address of an IPsec tunnel to be different from the outer IP source address
-usually assigned dynamically by the ISP.  Whereas the varying outer IP address
-can be handled by the `right=%any` construct, the inner IP address or subnet
-must always be declared in a connection definition. Therefore for the three
-roadwarriors _rw1_ to _rw3_ connecting to a strongSwan security gateway the
-following entries are required in `/etc/ipsec.conf`:
-
-    conn rw1
-         right=%any
-         righsubnet=10.4.0.5/32
-
-    conn rw2
-         right=%any
-         rightsubnet=10.4.0.47/32
-
-    conn rw3
-         right=%any
-         rightsubnet=10.4.0.128/28
-
-Because the charon daemon uses narrowing (even for IKEv1) these three entries
-can be reduced to the single connection definition
-
-    conn rw
-         right=%any
-         rightsubnet=10.4.0.0/24
-
-Any host will be accepted (of course after successful authentication based on
-the peer's X.509 certificate only) if it declares a client subnet lying totally
-within the boundaries defined by the subnet definition (in our example
-`10.4.0.0/24`).
-
-This strongSwan feature can also be helpful with VPN clients getting a
-dynamically assigned inner IP from a DHCP server located on the NAT router box.
-
-Since the private IP address of roadwarriors will often not be known they are
-usually assigned virtual IPs from a predefined pool.  This also makes routing
-traffic back to the roadwarriors easier. For example, to assign each client an
-IP address from the `10.5.0.0/24` subnet `conn rw` can be defined as
-
-    conn rw
-         right=%any
-         rightsourceip=10.5.0.0/24
-
-
-### Protocol and Port Selectors ###
-
-strongSwan offers the possibility to restrict the protocol and optionally the
-ports in an IPsec SA using the `rightprotoport` and `leftprotoport` parameters.
-For IKEv2 multiple such restrictions can also be configured in
-`leftsubnet` and `rightsubnet`.
-
-Some examples:
-
-    conn icmp
-         right=%any
-         rightprotoport=icmp
-         leftid=moon.strongswan.org
-         leftprotoport=icmp
-
-    conn http
-         right=%any
-         rightprotoport=6
-         leftid=moon.strongswan.org
-         leftprotoport=6/80
-
-    conn l2tp
-         right=%any
-         # with port wildcard for interoperability with certain L2TP clients
-         rightprotoport=17/%any
-         leftid=moon.strongswan.org
-         leftprotoport=17/1701
-
-    conn dhcp
-         right=%any
-         rightprotoport=udp/bootpc
-         leftid=moon.strongswan.org
-         leftsubnet=0.0.0.0/0  #allows DHCP discovery broadcast
-         leftprotoport=udp/bootps
-
-Protocols and ports can be designated either by their numerical values
-or by their acronyms defined in `/etc/services`.
-
-Based on the protocol and port selectors appropriate policies will be set
-up, so that only the specified payload types will pass through the IPsec
-tunnel.
-
-
-### IPsec policies based on wildcards ###
-
-In large VPN-based remote access networks there is often a requirement that
-access to the various parts of an internal network must be granted selectively,
-e.g. depending on the group membership of the remote access user.  strongSwan
-makes this possible by applying wildcard filtering on the VPN user's
-distinguished name (_ID_DER_ASN1_DN_).
-
-Let's make a practical example:
-
-An organization has a sales department (_OU=Sales_) and a research group
-(_OU=Research_).  In the company intranet there are separate subnets for Sales
-(`10.0.0.0/24`) and Research (`10.0.1.0/24`) but both groups share a common web
-server (`10.0.2.100`).  The VPN clients use Virtual IP addresses that are either
-assigned statically or from a dynamic pool.  The sales and research departments
-use IP addresses from separate address pools (`10.1.0.0/24`) and
-(`10.1.1.0/24`), respectively.  An X.509 certificate is issued to each employee,
-containing in its subject distinguished name the country (_C=CH_), the company
-(_O=ACME_), the group membership (_OU=Sales_ or _OU=Research_) and the common
-name (e.g. _CN=Bart Simpson_).
-
-The IPsec policy defined above can now be enforced with the following three
-IPsec security associations:
-
-    conn sales
-         right=%any
-         rightid="C=CH, O=ACME, OU=Sales, CN=*"
-         rightsourceip=10.1.0.0/24       # Sales IP range
-         leftsubnet=10.0.0.0/24          # Sales subnet
-
-    conn research
-         right=%any
-         rightid="C=CH, O=ACME, OU=Research, CN=*"
-         rightsourceip=10.1.1.0/24       # Research IP range
-         leftsubnet=10.0.1.0/24          # Research subnet
-
-    conn web
-         right=%any
-         rightid="C=CH, O=ACME, OU=*, CN=*"
-         rightsubnet=10.1.0.0/23         # Remote access IP range
-         leftsubnet=10.0.2.100/32        # Web server
-         rightprotoport=tcp              # TCP protocol only
-         leftprotoport=tcp/http          # TCP port 80 only
-
-The `*` character is used as a wildcard in relative distinguished names (RDNs).
-In order to match a wildcard template, the _ID_DER_ASN1_DN_ of a peer must
-contain the same number of RDNs (selected from the list given earlier) appearing
-in the exact order defined by the template.
-
-    "C=CH, O=ACME, OU=Research, OU=Special Effects, CN=Bart Simpson"
-
-matches the templates
-
-    "C=CH, O=ACME, OU=Research, OU=*, CN=*"
-    "C=CH, O=ACME, OU=*, OU=Special Effects, CN=*"
-    "C=CH, O=ACME, OU=*, OU=*, CN=*"
-
-but not the template
-
-    "C=CH, O=ACME, OU=*, CN=*"
-
-which doesn't have the same number of RDNs.
-
-
-### IPsec policies based on CA certificates ###
-
-As an alternative to the wildcard based IPsec policies described above, access
-to specific client host and subnets can be controlled on the basis of the CA
-that issued the peer certificate
-
-    conn sales
-         right=%any
-         rightca="C=CH, O=ACME, OU=Sales, CN=Sales CA"
-         rightsourceip=10.1.0.0/24       # Sales IP range
-         leftsubnet=10.0.0.0/24          # Sales subnet
-
-    conn research
-         right=%any
-         rightca="C=CH, O=ACME, OU=Research, CN=Research CA"
-         rightsourceip=10.1.1.0/24       # Research IP range
-         leftsubnet=10.0.1.0/24          # Research subnet
-
-    conn web
-         right=%any
-         rightca="C=CH, O=ACME, CN=ACME Root CA"
-         rightsubnet=10.1.0.0/23         # Remote access IP range
-         leftsubnet=10.0.2.100/32        # Web server
-         rightprotoport=tcp              # TCP protocol only
-         leftprotoport=tcp/http          # TCP port 80 only
-
-In the example above, the connection _sales_ can be used by peers
-presenting certificates issued by the Sales CA, only.  In the same way,
-the use of the connection _research_ is restricted to owners of certificates
-issued by the Research CA.  The connection _web_ is open to both "Sales" and
-"Research" peers because the required _ACME Root CA_ is the issuer of the
-Research and Sales intermediate CAs.  If no `rightca` parameter is present
-then any valid certificate issued by one of the trusted CAs in
-`/etc/ipsec.d/cacerts` can be used by the peer.
-
-The `leftca` parameter usually doesn't have to be set explicitly because
-by default it is set to the issuer field of the certificate loaded via
-`leftcert`.  The statement
-
-     rightca=%same
-
-sets the CA requested from the peer to the CA used by the left side itself
-as e.g. in
-
-    conn sales
-         right=%any
-         rightca=%same
-         leftcert=mySalesCert.pem
-
-
-## Configuring certificates and CRLs ##
-
-
-### Installing the CA certificates ###
-
-X.509 certificates received by strongSwan during the IKE protocol are
-automatically authenticated by going up the trust chain until a self-signed
-root CA certificate is reached.  Usually host certificates are directly signed
-by a root CA, but strongSwan also supports multi-level hierarchies with
-intermediate CAs in between.  All CA certificates belonging to a trust chain
-must be copied in either binary DER or Base64 PEM format into the directory
-
-     /etc/ipsec.d/cacerts/
-
-
-### Installing optional certificate revocation lists (CRLs) ###
+    pki --signcrl --cacert strongswanCert.pem --cakey strongswanKey.pem \
+                  --lifetime 30 > strongswan.crl
 
-By copying a CA certificate into `/etc/ipsec.d/cacerts/`, automatically all user
-or host certificates issued by this CA are declared valid.  Unfortunately,
-private keys might get compromised inadvertently or intentionally, personal
-certificates of users leaving a company have to be blocked immediately, etc.
-To this purpose certificate revocation lists (CRLs) have been created.  CRLs
-contain the serial numbers of all user or host certificates that have been
-revoked due to various reasons.
+If you omit the `--lifetime` option then the default value of 15 days is used.
+CRLs can either be uploaded to a HTTP or LDAP server or put in binary DER or
+Base64 PEM format into the `/etc/swanctl/x509crl` directory from where they are
+loaded into the **charon** daemon with the command
 
-After successful verification of the X.509 trust chain, strongSwan searches its
-list of CRLs, either obtained by loading them from the `/etc/ipsec.d/crls/`
-directory, or fetching them dynamically from a HTTP or LDAP server, for the
-presence of a CRL issued by the CA that has signed the certificate.
+    swanctl --load-creds
 
-If the serial number of the certificate is found in the CRL then the public key
-contained in the certificate is declared invalid and the IKE SA will not be
-established.  If no CRL is found or if the deadline defined in the _nextUpdate_
-field of the CRL has been reached, a warning is issued but the public key will
-nevertheless be accepted (this behavior can be changed, see below).  CRLs must
-be stored either in binary DER or Base64 PEM format in the `crls` directory.
 
+### Revoking a Certificate ###
 
-### Dynamic update of certificates and CRLs ###
+A specific end entity certificate is revoked with the command
 
-strongSwan reads certificates and CRLs from their respective files during system
-startup and keeps them in memory.  X.509 certificates have a finite life span
-defined by their validity field.  Therefore it must be possible to replace CA or
-OCSP certificates kept in system memory without disturbing established IKE SAs.
-Certificate revocation lists should also be updated in the regular intervals
-indicated by the _nextUpdate_ field in the CRL body.  The following interactive
-commands allow the manual replacement of the various files:
+    pki --signcrl --cacert strongswanCert.pem --cakey strongswanKey.pem \
+                  --lifetime 30 --lastcrl strongswan.crl \
+                  --reason key-compromise --cert moonCert.pem > new.crl
 
+Instead of the certificate file (in our example moonCert.pem), the serial number
+of the certificate to be revoked can be indicated using the `--serial`
+parameter. The `pki --signcrl --help` command documents all possible revocation
+reasons but the `--reason` parameter can also be omitted. The content of the new
+CRL file can be listed with the command
 
-| Command                 | Action                                          |
-|-------------------------|-------------------------------------------------|
-| ipsec rereadaacerts     | reload all files in `/etc/ipsec.d/aacerts/`     |
-| ipsec rereadacerts      | reload all files in `/etc/ipsec.d/acerts/`      |
-| ipsec rereadcacerts     | reload all files in `/etc/ipsec.d/cacerts/`     |
-| ipsec rereadcrls        | reload all files in `/etc/ipsec.d/crls/`        |
-| ipsec rereadocspcerts   | reload all files in `/etc/ipsec.d/ocspcerts/`   |
-| ipsec rereadsecrets     | reload `/etc/ipsec.secrets` and configured keys |
-| ipsec rereadall         | all the commands above combined                 |
-| ipsec purgecerts        | purge all cached certificates                   |
-| ipsec purgecrl          | purge all cached CRLs                           |
-| ipsec purgeocsp         | purge the OCSP cache                            |
+    pki --print --type crl --in new.crl
 
+    issuer:   "C=CH, O=strongSwan, CN=strongSwan Root CA"
+    update:    this on May 19 11:13:01 2017, ok
+               next on Jun 18 11:13:01 2017, ok (expires in 29 days)
+    serial:    02
+    authKeyId: 2b:95:14:5b:c3:22:87:de:d1:42:91:88:63:b3:d5:c1:92:7a:0f:5d
+    1 revoked certificate:
+      01: May 19 11:13:01 2017, key compromise
 
-CRLs can also be automatically fetched from an HTTP or LDAP server by using
-the CRL distribution points contained in X.509 certificates.
 
+### Local Caching of CRLs ###
 
-### Local caching of CRLs ###
+The `strongswan.conf` option
 
-The `ipsec.conf` option
-
-    config setup
-         cachecrls=yes
+    charon {
+        cache_crls = yes
+    }
 
 activates the local caching of CRLs that were dynamically fetched from an
-HTTP or LDAP server.  Cached copies are stored in `/etc/ipsec.d/crls` using a
-unique filename formed from the issuer's _subjectKeyIdentifier_ and the
+HTTP or LDAP server.  Cached copies are stored in `/etc/swanctl/x509crl` using a
+unique filename formed from the issuer's *subjectKeyIdentifier* and the
 suffix `.crl`.
 
 With the cached copy the CRL is immediately available after startup.  When the
-local copy is about to expire it is automatically replaced with an updated CRL
-fetched from one of the defined CRL distribution points.
-
-
-### Online Certificate Status Protocol (OCSP) ###
-
-The _Online Certificate Status Protocol_ is defined by RFC 2560.  It can be
-used to query an OCSP server about the current status of an X.509 certificate
-and is often used as a more dynamic alternative to a static Certificate
-Revocation List (CRL).  Both the OCSP request sent by the client and the OCSP
-response messages returned by the server are transported via a standard
-TCP/HTTP connection.
-
-In the simplest OCSP setup, a default URI under which the OCSP server for a
-given CA can be accessed is defined in `ipsec.conf`:
-
-    ca strongswan
-         cacert=strongswanCert.pem
-         ocspuri=http://ocsp.strongswan.org:8880
-         auto=add
-
-The HTTP port can be freely chosen.
-
-OpenSSL implements an OCSP server that can be used in conjunction with an
-OpenSSL-based Public Key Infrastructure.  The OCSP server is started with the
-following command:
-
-    openssl ocsp -index index.txt -CA strongswanCert.pem -port 8880 \
-                 -rkey ocspKey.pem -rsigner ocspCert.pem \
-                 -resp_no_certs -nmin 60 -text
-
-The command consists of the parameters
-
-    -index   index.txt is a copy of the OpenSSL index file containing the list
-             of all issued certificates.  The certificate status in index.txt
-             is designated either by V for valid or R for revoked.  If a new
-             certificate is added or if a certificate is revoked using the
-             openssl ca command, the OCSP server must be restarted in order for
-             the changes in index.txt to take effect.
-
-    -CA      the CA certificate
-
-    -port    the HTTP port the OCSP server is listening on.
-
-    -rkey    the private key used to sign the OCSP response.  The use of the
-             sensitive CA private key is not recommended since this could
-             jeopardize the security of your production PKI if the OCSP
-             server is hacked.  It is much better to generate a special
-             RSA private key just for OCSP signing use instead.
-
-    -rsigner the certificate of the OCSP server containing a public key which
-             matches the private key defined by -rkey and which can be used by
-             the client to check the trustworthiness of the signed OCSP
-             response.
-
-    -resp_no_certs  With this option the OCSP signer certificate defined by
-                    -rsigner is not included in the OCSP response.
-
-    -nmin    the validity interval of an OCSP response given in minutes.
-
-    -text    this option activates a verbose logging output, showing the
-             contents of both the received OCSP request and sent OCSP response.
-
-
-The OCSP signer certificate can either be put into the default directory
-
-    /etc/ipsec.d/ocspcerts
-
-or alternatively strongSwan can receive it as part of the OCSP response from the
-remote OCSP server.  In order to verify that the server is indeed authorized by
-a CA to deal out certificate status information an extended key usage attribute
-must be included in the OCSP server certificate.  Just insert the parameter
-
-    extendedKeyUsage=OCSPSigner
-
-in the `[ usr_cert ]` section of your `openssl.cnf` configuration file before
-the CA signs the OCSP server certificate.
-
-For a given CA the corresponding _ca_ section in `ipsec.conf` (see below) allows
-to define the URI of a single OCSP server.  As an alternative an OCSP URI can be
-embedded into each host and user certificate by putting the line
-
-    authorityInfoAccess = OCSP;URI:http://ocsp.strongswan.org:8880
-
-into the `[ usr_cert ]` section of your `openssl.cnf` configuration file.
-If an OCSP _authorityInfoAccess_ extension is present in a certificate then this
-record overrides the default URI defined by the ca section.
-
-
-### CRL Policy ###
-
-By default strongSwan is quite tolerant concerning the handling of CRLs. It is
-not mandatory for a CRL to be present in `/etc/ipsec.d/crls` and if the
-expiration date defined by the _nextUpdate_ field of a CRL has been reached just
-a warning is issued but a peer certificate will always be accepted if it has not
-been revoked.
-
-If you want to enforce a stricter CRL policy then you can do this by setting
-the `strictcrlpolicy` option.  This is done in the `config setup` section
-of the `ipsec.conf` file:
-
-    config setup
-         strictcrlpolicy=yes
-          ...
-
-A certificate received from a peer will not be accepted if no corresponding
-CRL or OCSP response is available.  And if an IKE SA re-negotiation takes
-place after the _nextUpdate_ deadline has been reached, the peer certificate
-will be declared invalid and the cached public key will be deleted, causing
-the connection in question to fail.  Therefore if you are going to use the
-`strictcrlpolicy=yes` option, make sure that the CRLs will always be updated
-in time.  Otherwise a total standstill might ensue.
-
-As mentioned earlier the default setting is `strictcrlpolicy=no`.
-
-
-### Configuring the peer side using locally stored certificates ###
-
-If you don't want to use trust chains based on CA certificates as proposed above
-you can alternatively import trusted peer certificates directly.
-
-With the `conn %default` section defined above and the use of the `rightcert`
-keyword for the peer side, the connection definitions presented earlier can
-alternatively be written as
-
-    conn sun
-          right=%any
-          rightid=sun.strongswan.org
-          rightcert=sunCert.cer
-
-     conn carol
-          right=192.168.0.100
-          rightcert=carolCert.der
-
-If the peer certificates are loaded locally then there is no need to send any
-certificates to the other end via the IKE protocol.  Especially if self-signed
-certificates are used which wouldn't be accepted anyway by the other side.
-In these cases it is recommended to add
-
-    leftsendcert=never
-
-to the connection definition(s) in order to avoid the sending of the host's
-own certificate.  The default value is
-
-    leftsendcert=ifasked
-
-which causes certificates to only be sent if a certificate request is received.
-If a peer does not send a certificate request then the setting
-
-    leftsendcert=always
-
-may be used to force sending of the certificate to the other peer.
-
-If a peer certificate contains a _subjectAltName_ extension, then an alternative
-`rightid` type can be used, as the example `conn sun` shows.  If no `rightid`
-entry is present then the subject distinguished name contained in the
-certificate is taken as the ID.
-
-Using the same rules concerning pathnames that apply to the gateway's own
-certificates, the following two definitions are also valid for trusted peer
-certificates:
-
-    rightcert=peercerts/carolCert.der
-
-or
-
-    rightcert=/usr/ssl/certs/carolCert.der
-
-
-## Configuring the private keys - ipsec.secrets ##
-
-
-### Loading private key files ###
-
-strongSwan is able to load RSA (or ECDSA) private keys in the PKCS#1 or PKCS#8
-file formats, or from PKCS#12 containers. The key files can optionally be
-secured with a passphrase.
-
-RSA private key files are declared in `/etc/ipsec.secrets` using the syntax
-
-    : RSA <my keyfile> "<optional passphrase>"
-
-The key file can be either in Base64 PEM-format or binary DER-format.  The
-actual coding is detected automatically.  The example
-
-    : RSA moonKey.pem
-
-uses a pathname relative to the default directory
-
-    /etc/ipsec.d/private
-
-As an alternative an absolute pathname can be given as in
-
-    : RSA /usr/ssl/private/moonKey.pem
-
-In both cases make sure that the key files are root readable only.
-
-Often a private key must be transported from the Certification Authority
-where it was generated to the target security gateway where it is going
-to be used.  In order to protect the key it can be encrypted with a symmetric
-cipher using a transport key derived from a cryptographically strong
-passphrase.
-
-Once on the security gateway the private key can either be permanently
-unlocked so that it can be used by the IKE daemon without having to know a
-passphrase
-
-    openssl rsa -in moonKey.pem -out moonKey.pem
-
-or as an option the key file can remain secured.  In this case the passphrase
-unlocking the private key must be added after the pathname in
-`/etc/ipsec.secrets`
-
-    : RSA moonKey.pem "This is my passphrase"
-
-Some CAs distribute private keys embedded in a PKCS#12 file. strongSwan can read
-private keys directly from such a file (end-entity and CA certificates are
-also extracted):
-
-    : P12 moonCert.p12 "This is my passphrase"
-
-
-### Entering passphrases interactively ###
-
-On a VPN gateway you would want to put the passphrase protecting the private
-key file right into `/etc/ipsec.secrets` as described in the previous section,
-so that the gateway can be booted in unattended mode.  The risk of keeping
-unencrypted secrets on a server can be minimized by putting the box into a
-locked room.  As long as no one can get root access on the machine the private
-keys are safe.
-
-On a mobile laptop computer the situation is quite different.  The computer can
-be stolen or the user may leave it unattended so that unauthorized persons
-can get access to it.  In theses cases it would be preferable not to keep any
-passphrases openly in `/etc/ipsec.secrets` but to prompt for them interactively
-instead.  This is easily done by defining
-
-    : RSA moonKey.pem %prompt
-
-Since strongSwan is usually started during the boot process, usually no
-interactive console windows is available which can be used to prompt for
-the passphrase.  This must be initiated by the user by typing
-
-    ipsec secrets
-
-which actually is an alias for the existing command
-
-    ipsec rereadsecrets
-
-and which causes a passphrase prompt to appear.  To abort entering a passphrase
-enter just a carriage return.
-
-
-## Configuring CA properties - ipsec.conf ##
-
-Besides the definition of IPsec connections the `ipsec.conf` file can also
-be used to configure a few properties of the certification authorities
-needed to establish the X.509 trust chains.  The following example shows
-some of the parameters that are currently available:
-
-    ca strongswan
-        cacert=strongswanCert.pem
-        ocspuri=http://ocsp.strongswan.org:8880
-        crluri=http://crl.strongswan.org/strongswan.crl'
-        crluri2="ldap://ldap.strongswan.org/O=strongSwan, C=CH?certificateRevocationList"
-        auto=add
-
-In a similar way as `conn` sections are used for connection definitions, an
-arbitrary number of optional `ca` sections define the basic properties of CAs.
-
-Each ca section is named with a unique label
-
-    ca strongswan
-
-The only mandatory parameter is
-
-    cacert=strongswanCert.pem
-
-which points to the CA certificate which usually resides in the default
-directory `/etc/ipsec.d/cacerts/` but could also be retrieved via an absolute
-path name.
-
-The OCSP URI
-
-    ocspuri=http://ocsp.strongswan.org:8880
-
-allows to define an individual OCSP server per CA.  Also up to two additional
-CRL distribution points (CDPs) can be defined
-
-    crluri=http://crl.strongswan.org/strongswan.crl'
-    crluri2="ldap://ldap.strongswan.org/O=strongSwan, C=CH?certificateRevocationList"
-
-which are added to any CDPs already present in the received certificates
-themselves.
-
-With the `auto=add` statement the `ca` definition is automatically loaded during
-startup.  Setting `auto=ignore` will ignore the `ca` section.
-
-Any parameters which appear in several ca definitions can be put in
-a common `ca %default` section
-
-    ca %default
-        crluri=http://crl.strongswan.org/strongswan.crl'
-
-
-## Monitoring functions ##
-
-strongSwan offers the following monitoring functions:
-
-| Command             | Action                                            |
-|---------------------|---------------------------------------------------|
-| ipsec listaacerts   | list all Authorization Authority certificates loaded from `/etc/ipsec.d/aacerts/` |
-| ipsec listacerts    | list all X.509 attribute certificates loaded from `/etc/ipsec.d/acerts/` |
-| ipsec listalgs      | list cryptographic algorithms for IKE             |
-| ipsec listcacerts   | list all CA certificates loaded from `/etc/ipsec.d/cacerts/` or received via IKE |
-| ipsec listcainfos   | list all properties defined in `ca` sections in `ipsec.conf` |
-| ipsec listcerts     | list all certificates loaded via `leftcert` and `rightcert` |
-| ipsec listcounters  | list global or connection specific counter values |
-| ipsec listcrls      | list all CLRs loaded from `/etc/ipsec.d/crls/`    |
-| ipsec listocsp      | list contents of the OCSP response cache          |
-| ipsec listocspcerts | list all OCSP signer certificates loaded from `/etc/ipsec.d/ocspcerts/` or received in OCSP responses |
-| ipsec listplugins   | list all loaded plugin features                   |
-| ipsec listpubkeys   | list all raw public keys e.g. loaded via `leftsigkey` and `rightsigkey` |
-| ipsec listall       | all the above commands combined                   |
-| ipsec status        | list concise status information on established connections |
-| ipsec statusall     | list detailed status information on connections |
-
-
-## Firewall support functions ##
-
-
-### Environment variables in the updown script ###
-
-strongSwan makes the following environment variables available
-in the _updown_ script indicated by the `leftupdown` option:
-
-| Variable              | Example                   | Comment         |
-|-----------------------|---------------------------|-----------------|
-| $PLUTO_PEER_ID        | carol at strongswan.org      | RFC822_ADDR (1) |
-| $PLUTO_PEER_PROTOCOL  | 17                        | udp         (2) |
-| $PLUTO_PEER_PORT      | 68                        | bootpc      (3) |
-| $PLUTO_MY_ID          | moon.strongswan.org       | FQDN        (1) |
-| $PLUTO_MY_PROTOCOL    | 17                        | udp         (2) |
-| $PLUTO_MY_PORT        | 67                        | bootps      (3) |
-
-(1) $PLUTO_PEER_ID/$PLUTO_MY_ID contain the IDs of the two ends
-    of an established connection. In our examples these
-    correspond to the strings defined by `rightid` and `leftid`,
-    respectively.
-
-(2) $PLUTO_PEER_PROTOCOL/$PLUTO_MY_PROTOCOL contain the protocol
-    defined by the `rightprotoport` and `leftprotoport` options,
-    respectively. Both variables contain the same protocol value.
-    The variables take on the value '0' if no protocol has been defined.
-
-(3) $PLUTO_PEER_PORT/$PLUTO_MY_PORT contain the ports defined by
-    the `rightprotoport` and `leftprotoport` options, respectively.
-    The variables take on the value '0' if no port has been defined.
-
-There are several more, refer to the provided default script for a documentation
-of them.
-
-
-### Automatic insertion and deletion of iptables firewall rules ###
-
-The default `_updown` script automatically inserts and deletes dynamic
-`iptables` firewall rules upon the establishment or teardown, respectively, of
-an IPsec security association.  This feature is activated with the line
-
-    leftfirewall=yes
-
-If you define a `leftsubnet` with a netmask larger than `/32` then the
-automatically inserted _FORWARD_ `iptables` rules will not allow clients to
-access the internal IP address of the gateway even if it is part of that subnet
-definition.  If you want additional _INPUT_ and _OUTPUT_ `iptables` rules to be
-inserted, so that the host itself can be accessed then add the following line:
-
-    lefthostaccess=yes
-
-The `_updown` script also features a logging facility which will register the
-creation (+) and the expiration (-) of each successfully established VPN
-connection in a special syslog file in the following concise and easily
-readable format:
-
-    Jul 19 18:58:38 moon vpn:
-        + carol.strongswan.org  192.168.0.100 -- 192.168.0.1 == 10.1.0.0/16
-    Jul 19 22:15:17 moon vpn:
-        - carol.strongswan.org  192.168.0.100 -- 192.168.0.1 == 10.1.0.0/16
+local copy has become stale, an updated CRL is automatically fetched from one of
+the defined CRL distribution points during the next IKEv2 authentication.
diff --git a/conf/Makefile.in b/conf/Makefile.in
index 70e1b01..9a85514 100644
--- a/conf/Makefile.in
+++ b/conf/Makefile.in
@@ -310,6 +310,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -332,6 +333,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/conf/options/charon.conf b/conf/options/charon.conf
index 1b5d52d..7ccb749 100644
--- a/conf/options/charon.conf
+++ b/conf/options/charon.conf
@@ -29,6 +29,10 @@ charon {
     # Delete CHILD_SAs right after they got successfully rekeyed (IKEv1 only).
     # delete_rekeyed = no
 
+    # Delay in seconds until inbound IPsec SAs are deleted after rekeyings
+    # (IKEv2 only).
+    # delete_rekeyed_delay = 5
+
     # Use ANSI X9.42 DH exponent size or optimum size matched to cryptographic
     # strength.
     # dh_exponent_ansi_x9_42 = yes
@@ -199,6 +203,14 @@ charon {
     # in strongswan.conf(5).
     # retransmit_base = 1.8
 
+    # Maximum jitter in percent to apply randomly to calculated retransmission
+    # timeout (0 to disable).
+    # retransmit_jitter = 0
+
+    # Upper limit in seconds for calculated retransmission timeout (0 to
+    # disable).
+    # retransmit_limit = 0
+
     # Timeout in seconds before sending first retransmit.
     # retransmit_timeout = 4.0
 
diff --git a/conf/options/charon.opt b/conf/options/charon.opt
index 4c4311e..3593c6a 100644
--- a/conf/options/charon.opt
+++ b/conf/options/charon.opt
@@ -75,6 +75,16 @@ charon.delete_rekeyed = no
 	However, this might cause problems with implementations that continue to
 	use rekeyed SAs until they expire.
 
+charon.delete_rekeyed_delay = 5
+	Delay in seconds until inbound IPsec SAs are deleted after rekeyings (IKEv2
+	only).
+
+	Delay in seconds until inbound IPsec SAs are deleted after rekeyings (IKEv2
+	only). To process delayed packets the inbound part of a CHILD_SA is kept
+	installed up to the configured number of seconds after it got replaced
+	during a rekeying. If set to 0 the CHILD_SA will be kept installed until it
+	expires (if no lifetime is set it will be destroyed immediately).
+
 charon.dh_exponent_ansi_x9_42 = yes
 	Use ANSI X9.42 DH exponent size or optimum size matched to cryptographic
 	strength.
@@ -311,6 +321,13 @@ charon.retransmit_timeout = 4.0
 charon.retransmit_tries = 5
 	Number of times to retransmit a packet before giving up.
 
+charon.retransmit_jitter = 0
+	Maximum jitter in percent to apply randomly to calculated retransmission
+	timeout (0 to disable).
+
+charon.retransmit_limit = 0
+	Upper limit in seconds for calculated retransmission timeout (0 to disable).
+
 charon.retry_initiate_interval = 0
 	Interval in seconds to use when retrying to initiate an IKE_SA (e.g. if DNS
 	resolution failed), 0 to disable retries.
diff --git a/conf/plugins/attr-sql.conf b/conf/plugins/attr-sql.conf
index 24d4e80..f56f54a 100644
--- a/conf/plugins/attr-sql.conf
+++ b/conf/plugins/attr-sql.conf
@@ -1,5 +1,9 @@
 attr-sql {
 
+    # Release all online leases during startup.  Disable this to share the DB
+    # between multiple VPN gateways.
+    # crash_recovery = yes
+
     # Database URI for attr-sql plugin used by charon. If it contains a
     # password, make sure to adjust the permissions of the config file
     # accordingly.
diff --git a/conf/plugins/attr-sql.opt b/conf/plugins/attr-sql.opt
index abd749e..58f05bb 100644
--- a/conf/plugins/attr-sql.opt
+++ b/conf/plugins/attr-sql.opt
@@ -1,3 +1,7 @@
+charon.plugins.attr-sql.crash_recovery = yes
+	Release all online leases during startup.  Disable this to share the DB
+	between multiple VPN gateways.
+
 charon.plugins.attr-sql.database
 	Database URI for attr-sql plugin used by charon. If it contains a password,
 	make sure to adjust the permissions of the config file accordingly.
diff --git a/conf/plugins/kernel-netlink.opt b/conf/plugins/kernel-netlink.opt
index 1136af1..3d9c4a7 100644
--- a/conf/plugins/kernel-netlink.opt
+++ b/conf/plugins/kernel-netlink.opt
@@ -113,6 +113,6 @@ charon.plugins.kernel-netlink.xfrm_acq_expires = 165
 	trap policy. The value gets written to /proc/sys/net/core/xfrm_acq_expires.
 	Indirectly controls the delay between XFRM acquire messages triggered by the
 	kernel for a trap policy. The same value is used as timeout for SPIs
-	allocated by the kernel. The default value equals the default total
-	retransmission timeout for IKE messages, see IKEv2 RETRANSMISSION
-	in **strongswan.conf**(5).
+	allocated by the kernel. The default value equals the total	retransmission
+	timeout for IKE messages, see IKEv2 RETRANSMISSION in
+	**strongswan.conf**(5).
diff --git a/conf/plugins/socket-default.conf b/conf/plugins/socket-default.conf
index 6d4b73d..abf4650 100644
--- a/conf/plugins/socket-default.conf
+++ b/conf/plugins/socket-default.conf
@@ -10,6 +10,9 @@ socket-default {
     # Set source address on outbound packets, if possible.
     # set_source = yes
 
+    # Force sending interface on outbound packets, if possible.
+    # set_sourceif = no
+
     # Listen on IPv4, if possible.
     # use_ipv4 = yes
 
diff --git a/conf/plugins/socket-default.opt b/conf/plugins/socket-default.opt
index 483a0f0..570bd0e 100644
--- a/conf/plugins/socket-default.opt
+++ b/conf/plugins/socket-default.opt
@@ -4,6 +4,12 @@ charon.plugins.socket-default.fwmark =
 charon.plugins.socket-default.set_source = yes
 	Set source address on outbound packets, if possible.
 
+charon.plugins.socket-default.set_sourceif = no
+	Force sending interface on outbound packets, if possible.
+
+	Force sending interface on outbound packets, if possible. This allows
+	using IPv6 link-local addresses as tunnel endpoints.
+
 charon.plugins.socket-default.use_ipv4 = yes
 	Listen on IPv4, if possible.
 
diff --git a/conf/strongswan.conf.5.main b/conf/strongswan.conf.5.main
index 72ab3a7..4df7ce4 100644
--- a/conf/strongswan.conf.5.main
+++ b/conf/strongswan.conf.5.main
@@ -114,6 +114,14 @@ this might cause problems with implementations that continue to use rekeyed SAs
 until they expire.
 
 .TP
+.BR charon.delete_rekeyed_delay " [5]"
+Delay in seconds until inbound IPsec SAs are deleted after rekeyings (IKEv2
+only). To process delayed packets the inbound part of a CHILD_SA is kept
+installed up to the configured number of seconds after it got replaced during a
+rekeying. If set to 0 the CHILD_SA will be kept installed until it expires (if
+no lifetime is set it will be destroyed immediately).
+
+.TP
 .BR charon.dh_exponent_ansi_x9_42 " [yes]"
 Use ANSI X9.42 DH exponent size or optimum size matched to cryptographic
 strength.
@@ -432,6 +440,11 @@ or an arbitrary value depending on the attribute type.  For some attribute types
 multiple values may be specified as a comma separated list.
 
 .TP
+.BR charon.plugins.attr-sql.crash_recovery " [yes]"
+Release all online leases during startup.  Disable this to share the DB between
+multiple VPN gateways.
+
+.TP
 .BR charon.plugins.attr-sql.database " []"
 Database URI for attr\-sql plugin used by charon. If it contains a password, make
 sure to adjust the permissions of the config file accordingly.
@@ -1049,8 +1062,8 @@ Lifetime of XFRM acquire state created by the kernel when traffic matches a trap
 policy. The value gets written to /proc/sys/net/core/xfrm_acq_expires.
 Indirectly controls the delay between XFRM acquire messages triggered by the
 kernel for a trap policy. The same value is used as timeout for SPIs allocated
-by the kernel. The default value equals the default total retransmission timeout
-for IKE messages, see IKEv2 RETRANSMISSION in
+by the kernel. The default value equals the total   retransmission timeout for
+IKE messages, see IKEv2 RETRANSMISSION in
 .RB "" "strongswan.conf" "(5)."
 
 
@@ -1394,6 +1407,11 @@ Firewall mark to set on outbound packets.
 Set source address on outbound packets, if possible.
 
 .TP
+.BR charon.plugins.socket-default.set_sourceif " [no]"
+Force sending interface on outbound packets, if possible. This allows using IPv6
+link\-local addresses as tunnel endpoints.
+
+.TP
 .BR charon.plugins.socket-default.use_ipv4 " [yes]"
 Listen on IPv4, if possible.
 
@@ -1698,6 +1716,15 @@ Base to use for calculating exponential back off, see IKEv2 RETRANSMISSION in
 
 
 .TP
+.BR charon.retransmit_jitter " [0]"
+Maximum jitter in percent to apply randomly to calculated retransmission timeout
+(0 to disable).
+
+.TP
+.BR charon.retransmit_limit " [0]"
+Upper limit in seconds for calculated retransmission timeout (0 to disable).
+
+.TP
 .BR charon.retransmit_timeout " [4.0]"
 Timeout in seconds before sending first retransmit.
 
diff --git a/conf/strongswan.conf.5.tail.in b/conf/strongswan.conf.5.tail.in
index 72aa7f8..f428fc3 100644
--- a/conf/strongswan.conf.5.tail.in
+++ b/conf/strongswan.conf.5.tail.in
@@ -408,6 +408,8 @@ using the three keys listed below:
 .BR charon.retransmit_base " [1.8]"
 .BR charon.retransmit_timeout " [4.0]"
 .BR charon.retransmit_tries " [5]"
+.BR charon.retransmit_jitter " [0]"
+.BR charon.retransmit_limit " [0]"
 .fi
 .RE
 .PP
@@ -419,7 +421,15 @@ The following algorithm is used to calculate the timeout:
 .PP
 Where
 .I n
-is the current retransmission count.
+is the current retransmission count. The calculated timeout can't exceed the
+configured retransmit_limit (if any), which is useful if the number of retries
+is high.
+.PP
+If a jitter in percent is configured, the timeout is modified as follows:
+.PP
+.EX
+	relative timeout -= random(0, retransmit_jitter * relative timeout)
+.EE
 .PP
 Using the default values, packets are retransmitted in:
 
diff --git a/config.h.in b/config.h.in
index 477cc2b..49aa093 100644
--- a/config.h.in
+++ b/config.h.in
@@ -313,6 +313,9 @@
 	STACK_DIRECTION = 0 => direction of growth unknown */
 #undef STACK_DIRECTION
 
+/* static plugin constructors */
+#undef STATIC_PLUGIN_CONSTRUCTORS
+
 /* Define to 1 if you have the ANSI C header files. */
 #undef STDC_HEADERS
 
@@ -328,6 +331,9 @@
 /* using builtin printf for printf hooks */
 #undef USE_BUILTIN_PRINTF
 
+/* build code for fuzzing */
+#undef USE_FUZZING
+
 /* support for IKEv1 protocol */
 #undef USE_IKEV1
 
diff --git a/configure b/configure
index bdf0dfe..21db534 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for strongSwan 5.5.2.
+# Generated by GNU Autoconf 2.69 for strongSwan 5.5.3.
 #
 #
 # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
@@ -587,8 +587,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='strongSwan'
 PACKAGE_TARNAME='strongswan'
-PACKAGE_VERSION='5.5.2'
-PACKAGE_STRING='strongSwan 5.5.2'
+PACKAGE_VERSION='5.5.3'
+PACKAGE_STRING='strongSwan 5.5.3'
 PACKAGE_BUGREPORT=''
 PACKAGE_URL=''
 
@@ -661,6 +661,8 @@ COVERAGE_FALSE
 COVERAGE_TRUE
 USE_SILENT_RULES_FALSE
 USE_SILENT_RULES_TRUE
+STATIC_PLUGIN_CONSTRUCTORS_FALSE
+STATIC_PLUGIN_CONSTRUCTORS_TRUE
 MONOLITHIC_FALSE
 MONOLITHIC_TRUE
 USE_TSS2_FALSE
@@ -703,6 +705,8 @@ USE_LIBSTRONGSWAN_FALSE
 USE_LIBSTRONGSWAN_TRUE
 USE_CONFTEST_FALSE
 USE_CONFTEST_TRUE
+USE_FUZZING_FALSE
+USE_FUZZING_TRUE
 USE_SCRIPTS_FALSE
 USE_SCRIPTS_TRUE
 USE_SCEPCLIENT_FALSE
@@ -1034,6 +1038,7 @@ cmd_plugins
 nm_plugins
 medsrv_plugins
 manager_plugins
+fuzz_plugins
 scripts_plugins
 pki_plugins
 scepclient_plugins
@@ -1176,6 +1181,7 @@ charon_udp_port
 ipsecgroup
 ipsecuser
 systemdsystemunitdir
+libfuzzer
 fips_mode
 ipsec_script
 routing_table_prio
@@ -1270,6 +1276,7 @@ ac_subst_files=''
 ac_user_opts='
 enable_option_checking
 enable_silent_rules
+enable_static
 with_random_device
 with_urandom_device
 with_strongswan_conf
@@ -1286,6 +1293,7 @@ with_routing_table
 with_routing_table_prio
 with_ipsec_script
 with_fips_mode
+with_libfuzzer
 with_capabilities
 with_mpz_powm_sec
 with_dev_headers
@@ -1444,6 +1452,7 @@ enable_cmd
 enable_conftest
 enable_dumm
 enable_fast
+enable_fuzzing
 enable_libipsec
 enable_manager
 enable_medcli
@@ -1482,7 +1491,6 @@ enable_all
 enable_dependency_tracking
 with_lib_prefix
 enable_shared
-enable_static
 with_pic
 enable_fast_install
 with_aix_soname
@@ -2078,7 +2086,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures strongSwan 5.5.2 to adapt to many kinds of systems.
+\`configure' configures strongSwan 5.5.3 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -2149,7 +2157,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of strongSwan 5.5.2:";;
+     short | recursive ) echo "Configuration of strongSwan 5.5.3:";;
    esac
   cat <<\_ACEOF
 
@@ -2159,6 +2167,7 @@ Optional Features:
   --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
   --enable-silent-rules   less verbose build output (undo: "make V=1")
   --disable-silent-rules  verbose build output (undo: "make V=0")
+  --enable-static[=PKGS]  build static libraries [default=no]
   --disable-aes           disable AES software implementation plugin.
   --enable-af-alg         enable AF_ALG crypto interface to Linux Crypto API.
   --enable-bliss          enable BLISS software implementation plugin.
@@ -2346,6 +2355,7 @@ Optional Features:
   --enable-dumm           enable the DUMM UML test framework.
   --enable-fast           enable libfast (FastCGI Application Server w/
                           templates.
+  --enable-fuzzing        enable fuzzing scripts (found in directory fuzz).
   --enable-libipsec       enable user space IPsec implementation.
   --enable-manager        enable web management console (proof of concept).
   --enable-medcli         enable mediation client configuration database
@@ -2407,7 +2417,6 @@ Optional Features:
   --disable-dependency-tracking
                           speeds up one-time build
   --enable-shared[=PKGS]  build shared libraries [default=yes]
-  --enable-static[=PKGS]  build static libraries [default=yes]
   --enable-fast-install[=PKGS]
                           optimize for fast installation [default=yes]
   --disable-libtool-lock  avoid locking (might break parallel builds)
@@ -2453,6 +2462,7 @@ Optional Packages:
                           ipsec).
   --with-fips-mode=arg    set openssl FIPS mode: disabled(0), enabled(1),
                           Suite B enabled(2) (default: 0).
+  --with-libfuzzer=arg    path to libFuzzer.a (default: ).
   --with-capabilities=arg set capability dropping library. Currently supported
                           values are "libcap" and "native" (default: no).
   --with-mpz_powm_sec=arg use the more side-channel resistant mpz_powm_sec in
@@ -2613,7 +2623,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-strongSwan configure 5.5.2
+strongSwan configure 5.5.3
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -3135,7 +3145,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by strongSwan $as_me 5.5.2, which was
+It was created by strongSwan $as_me 5.5.3, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -3998,7 +4008,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='strongswan'
- VERSION='5.5.2'
+ VERSION='5.5.3'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -4252,6 +4262,37 @@ ac_config_headers="$ac_config_headers config.h"
 
 $as_echo "#define CONFIG_H_INCLUDED /**/" >>confdefs.h
 
+# Check whether --enable-static was given.
+if test "${enable_static+set}" = set; then :
+  enableval=$enable_static; p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_static=yes ;;
+    no) enable_static=no ;;
+    *)
+     enable_static=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
+      for pkg in $enableval; do
+	IFS=$lt_save_ifs
+	if test "X$pkg" = "X$p"; then
+	  enable_static=yes
+	fi
+      done
+      IFS=$lt_save_ifs
+      ;;
+    esac
+else
+  enable_static=no
+fi
+
+
+
+
+
+
+
+
+
 
 
 
@@ -4670,6 +4711,18 @@ fi
 
 
 
+# Check whether --with-libfuzzer was given.
+if test "${with_libfuzzer+set}" = set; then :
+  withval=$with_libfuzzer; libfuzzer="$withval"
+
+else
+  libfuzzer=""
+
+
+fi
+
+
+
 # Check whether --with-capabilities was given.
 if test "${with_capabilities+set}" = set; then :
   withval=$with_capabilities; capabilities="$withval"
@@ -7203,6 +7256,22 @@ fi
 
 	disabled_by_default=${disabled_by_default}" fast"
 
+# Check whether --enable-fuzzing was given.
+if test "${enable_fuzzing+set}" = set; then :
+  enableval=$enable_fuzzing; fuzzing_given=true
+		if test x$enableval = xyes; then
+			fuzzing=true
+		 else
+			fuzzing=false
+		fi
+else
+  fuzzing=false
+		fuzzing_given=false
+
+fi
+
+	disabled_by_default=${disabled_by_default}" fuzzing"
+
 # Check whether --enable-libipsec was given.
 if test "${enable_libipsec+set}" = set; then :
   enableval=$enable_libipsec; libipsec_given=true
@@ -13075,36 +13144,6 @@ fi
 
 
 
-  # Check whether --enable-static was given.
-if test "${enable_static+set}" = set; then :
-  enableval=$enable_static; p=${PACKAGE-default}
-    case $enableval in
-    yes) enable_static=yes ;;
-    no) enable_static=no ;;
-    *)
-     enable_static=no
-      # Look at the argument we got.  We use all the common list separators.
-      lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
-      for pkg in $enableval; do
-	IFS=$lt_save_ifs
-	if test "X$pkg" = "X$p"; then
-	  enable_static=yes
-	fi
-      done
-      IFS=$lt_save_ifs
-      ;;
-    esac
-else
-  enable_static=yes
-fi
-
-
-
-
-
-
-
-
 
 
 # Check whether --with-pic was given.
@@ -23002,6 +23041,24 @@ else
 fi
 
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if plugin constructors should be resolved statically" >&5
+$as_echo_n "checking if plugin constructors should be resolved statically... " >&6; }
+if ${ss_cv_static_plugin_constructors+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test x$monolithic = xtrue -a x$enable_static = xyes; then
+		ss_cv_static_plugin_constructors=yes
+	 else
+		ss_cv_static_plugin_constructors="no (enabled for static, monolithic builds)"
+	 fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ss_cv_static_plugin_constructors" >&5
+$as_echo "$ss_cv_static_plugin_constructors" >&6; }
+if test "x$ss_cv_static_plugin_constructors" = xyes; then
+	static_plugin_constructors=true
+fi
+
 # ===============================================
 #  collect plugin list for strongSwan components
 # ===============================================
@@ -23020,6 +23077,7 @@ attest_plugins=
 scepclient_plugins=
 pki_plugins=
 scripts_plugins=
+fuzz_plugins=
 manager_plugins=
 medsrv_plugins=
 nm_plugins=
@@ -23145,6 +23203,7 @@ if test x$sha2 = xtrue; then
 		nm_plugins=${nm_plugins}" sha2"
 		cmd_plugins=${cmd_plugins}" sha2"
 		aikgen_plugins=${aikgen_plugins}" sha2"
+		fuzz_plugins=${fuzz_plugins}" sha2"
 
 	fi
 
@@ -23159,6 +23218,7 @@ if test x$sha3 = xtrue; then
 		nm_plugins=${nm_plugins}" sha3"
 		cmd_plugins=${cmd_plugins}" sha3"
 		aikgen_plugins=${aikgen_plugins}" sha3"
+		fuzz_plugins=${fuzz_plugins}" sha3"
 
 	fi
 
@@ -23174,6 +23234,7 @@ if test x$sha1 = xtrue; then
 		nm_plugins=${nm_plugins}" sha1"
 		cmd_plugins=${cmd_plugins}" sha1"
 		aikgen_plugins=${aikgen_plugins}" sha1"
+		fuzz_plugins=${fuzz_plugins}" sha1"
 
 	fi
 
@@ -23262,6 +23323,7 @@ if test x$x509 = xtrue; then
 		nm_plugins=${nm_plugins}" x509"
 		cmd_plugins=${cmd_plugins}" x509"
 		aikgen_plugins=${aikgen_plugins}" x509"
+		fuzz_plugins=${fuzz_plugins}" x509"
 
 	fi
 
@@ -23308,6 +23370,7 @@ if test x$pkcs1 = xtrue; then
 		nm_plugins=${nm_plugins}" pkcs1"
 		cmd_plugins=${cmd_plugins}" pkcs1"
 		aikgen_plugins=${aikgen_plugins}" pkcs1"
+		fuzz_plugins=${fuzz_plugins}" pkcs1"
 
 	fi
 
@@ -23392,6 +23455,7 @@ if test x$pem = xtrue; then
 		nm_plugins=${nm_plugins}" pem"
 		cmd_plugins=${cmd_plugins}" pem"
 		aikgen_plugins=${aikgen_plugins}" pem"
+		fuzz_plugins=${fuzz_plugins}" pem"
 
 	fi
 
@@ -23465,12 +23529,14 @@ if test x$gmp = xtrue; then
 		nm_plugins=${nm_plugins}" gmp"
 		cmd_plugins=${cmd_plugins}" gmp"
 		aikgen_plugins=${aikgen_plugins}" gmp"
+		fuzz_plugins=${fuzz_plugins}" gmp"
 
 	fi
 
 if test x$curve25519 = xtrue; then
 		s_plugins=${s_plugins}" curve25519"
 		charon_plugins=${charon_plugins}" curve25519"
+		pki_plugins=${pki_plugins}" curve25519"
 		scripts_plugins=${scripts_plugins}" curve25519"
 		nm_plugins=${nm_plugins}" curve25519"
 		cmd_plugins=${cmd_plugins}" curve25519"
@@ -24132,6 +24198,7 @@ if test x$unity = xtrue; then
 
 
 
+
 # ======================
 #  set Makefile.am vars
 # ======================
@@ -25432,6 +25499,14 @@ else
   USE_SCRIPTS_FALSE=
 fi
 
+ if test x$fuzzing = xtrue; then
+  USE_FUZZING_TRUE=
+  USE_FUZZING_FALSE='#'
+else
+  USE_FUZZING_TRUE='#'
+  USE_FUZZING_FALSE=
+fi
+
  if test x$conftest = xtrue; then
   USE_CONFTEST_TRUE=
   USE_CONFTEST_FALSE='#'
@@ -25600,6 +25675,14 @@ else
   MONOLITHIC_FALSE=
 fi
 
+ if test x$static_plugin_constructors = xtrue; then
+  STATIC_PLUGIN_CONSTRUCTORS_TRUE=
+  STATIC_PLUGIN_CONSTRUCTORS_FALSE='#'
+else
+  STATIC_PLUGIN_CONSTRUCTORS_TRUE='#'
+  STATIC_PLUGIN_CONSTRUCTORS_FALSE=
+fi
+
  if test x$enable_silent_rules = xyes; then
   USE_SILENT_RULES_TRUE=
   USE_SILENT_RULES_FALSE='#'
@@ -25737,6 +25820,11 @@ if test x$monolithic = xtrue; then
 $as_echo "#define MONOLITHIC /**/" >>confdefs.h
 
 fi
+if test x$static_plugin_constructors = xtrue; then
+
+$as_echo "#define STATIC_PLUGIN_CONSTRUCTORS /**/" >>confdefs.h
+
+fi
 if test x$ikev1 = xtrue; then
 
 $as_echo "#define USE_IKEV1 /**/" >>confdefs.h
@@ -25747,6 +25835,11 @@ if test x$ikev2 = xtrue; then
 $as_echo "#define USE_IKEV2 /**/" >>confdefs.h
 
 fi
+if test x$fuzzing = xtrue; then
+
+$as_echo "#define USE_FUZZING /**/" >>confdefs.h
+
+fi
 
 # ====================================================
 #  options for enabled modules (see conf/Makefile.am)
@@ -25800,7 +25893,7 @@ fi
 #  build Makefiles
 # =================
 
-ac_config_files="$ac_config_files Makefile conf/Makefile man/Makefile init/Makefile init/systemd/Makefile init/systemd-swanctl/Makefile src/Makefile src/include/Makefile src/libstrongswan/Makefile src/libstrongswan/math/libnttfft/Makefile src/libstrongswan/math/libnttfft/tests/Makefile src/libstrongswan/plugins/aes/Makefile src/libstrongswan/plugins/cmac/Makefile src/libstrongswan/plugins/des/Makefile src/libstrongswan/plugins/blowfish/Makefile src/libstrongswan/plugins/rc2/Makefile src/ [...]
+ac_config_files="$ac_config_files Makefile conf/Makefile fuzz/Makefile man/Makefile init/Makefile init/systemd/Makefile init/systemd-swanctl/Makefile src/Makefile src/include/Makefile src/libstrongswan/Makefile src/libstrongswan/math/libnttfft/Makefile src/libstrongswan/math/libnttfft/tests/Makefile src/libstrongswan/plugins/aes/Makefile src/libstrongswan/plugins/cmac/Makefile src/libstrongswan/plugins/des/Makefile src/libstrongswan/plugins/blowfish/Makefile src/libstrongswan/plugins/rc2 [...]
 
 
 # =================
@@ -26616,6 +26709,10 @@ if test -z "${USE_SCRIPTS_TRUE}" && test -z "${USE_SCRIPTS_FALSE}"; then
   as_fn_error $? "conditional \"USE_SCRIPTS\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
+if test -z "${USE_FUZZING_TRUE}" && test -z "${USE_FUZZING_FALSE}"; then
+  as_fn_error $? "conditional \"USE_FUZZING\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
 if test -z "${USE_CONFTEST_TRUE}" && test -z "${USE_CONFTEST_FALSE}"; then
   as_fn_error $? "conditional \"USE_CONFTEST\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
@@ -26700,6 +26797,10 @@ if test -z "${MONOLITHIC_TRUE}" && test -z "${MONOLITHIC_FALSE}"; then
   as_fn_error $? "conditional \"MONOLITHIC\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
+if test -z "${STATIC_PLUGIN_CONSTRUCTORS_TRUE}" && test -z "${STATIC_PLUGIN_CONSTRUCTORS_FALSE}"; then
+  as_fn_error $? "conditional \"STATIC_PLUGIN_CONSTRUCTORS\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
 if test -z "${USE_SILENT_RULES_TRUE}" && test -z "${USE_SILENT_RULES_FALSE}"; then
   as_fn_error $? "conditional \"USE_SILENT_RULES\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
@@ -27153,7 +27254,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by strongSwan $as_me 5.5.2, which was
+This file was extended by strongSwan $as_me 5.5.3, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -27219,7 +27320,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-strongSwan config.status 5.5.2
+strongSwan config.status 5.5.3
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
@@ -27348,10 +27449,10 @@ AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"
 sed_quote_subst='$sed_quote_subst'
 double_quote_subst='$double_quote_subst'
 delay_variable_subst='$delay_variable_subst'
+enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`'
 macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`'
 macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`'
 enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`'
-enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`'
 pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`'
 enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`'
 shared_archive_member_spec='`$ECHO "$shared_archive_member_spec" | $SED "$delay_single_quote_subst"`'
@@ -27636,6 +27737,7 @@ do
     "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;;
     "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
     "conf/Makefile") CONFIG_FILES="$CONFIG_FILES conf/Makefile" ;;
+    "fuzz/Makefile") CONFIG_FILES="$CONFIG_FILES fuzz/Makefile" ;;
     "man/Makefile") CONFIG_FILES="$CONFIG_FILES man/Makefile" ;;
     "init/Makefile") CONFIG_FILES="$CONFIG_FILES init/Makefile" ;;
     "init/systemd/Makefile") CONFIG_FILES="$CONFIG_FILES init/systemd/Makefile" ;;
@@ -28598,6 +28700,9 @@ available_tags=''
 
 # ### BEGIN LIBTOOL CONFIG
 
+# Whether or not to build static libraries.
+build_old_libs=$enable_static
+
 # Which release of libtool.m4 was used?
 macro_version=$macro_version
 macro_revision=$macro_revision
@@ -28605,9 +28710,6 @@ macro_revision=$macro_revision
 # Whether or not to build shared libraries.
 build_libtool_libs=$enable_shared
 
-# Whether or not to build static libraries.
-build_old_libs=$enable_static
-
 # What type of objects to build.
 pic_mode=$pic_mode
 
diff --git a/configure.ac b/configure.ac
index 29988d3..1ca254e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,5 +1,5 @@
 #
-# Copyright (C) 2007-2015 Tobias Brunner
+# Copyright (C) 2007-2017 Tobias Brunner
 # Copyright (C) 2006-2016 Andreas Steffen
 # Copyright (C) 2006-2014 Martin Willi
 # HSR Hochschule fuer Technik Rapperswil
@@ -19,7 +19,7 @@
 #  initialize & set some vars
 # ============================
 
-AC_INIT([strongSwan],[5.5.2])
+AC_INIT([strongSwan],[5.5.3])
 AM_INIT_AUTOMAKE(m4_esyscmd([
 	echo tar-ustar
 	echo subdir-objects
@@ -35,6 +35,7 @@ m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES])
 AC_CONFIG_MACRO_DIR([m4/config])
 AC_CONFIG_HEADERS([config.h])
 AC_DEFINE([CONFIG_H_INCLUDED], [], [defined if config.h included])
+AC_DISABLE_STATIC
 PKG_PROG_PKG_CONFIG
 
 m4_include(m4/macros/split-package-version.m4)
@@ -62,6 +63,7 @@ ARG_WITH_SUBST([routing-table],      [220], [set routing table to use for IPsec
 ARG_WITH_SUBST([routing-table-prio], [220], [set priority for IPsec routing table])
 ARG_WITH_SUBST([ipsec-script],       [ipsec], [change the name of the ipsec script])
 ARG_WITH_SUBST([fips-mode],          [0], [set openssl FIPS mode: disabled(0), enabled(1), Suite B enabled(2)])
+ARG_WITH_SUBST([libfuzzer],          [], [path to libFuzzer.a])
 ARG_WITH_SET([capabilities],         [no], [set capability dropping library. Currently supported values are "libcap" and "native"])
 ARG_WITH_SET([mpz_powm_sec],         [yes], [use the more side-channel resistant mpz_powm_sec in libgmp, if available])
 ARG_WITH_SET([dev-headers],          [no], [install strongSwan development headers to directory.])
@@ -277,6 +279,7 @@ ARG_ENABL_SET([cmd],            [enable the command line IKE client charon-cmd.]
 ARG_ENABL_SET([conftest],       [enforce Suite B conformance test framework.])
 ARG_ENABL_SET([dumm],           [enable the DUMM UML test framework.])
 ARG_ENABL_SET([fast],           [enable libfast (FastCGI Application Server w/ templates.])
+ARG_ENABL_SET([fuzzing],        [enable fuzzing scripts (found in directory fuzz).])
 ARG_ENABL_SET([libipsec],       [enable user space IPsec implementation.])
 ARG_ENABL_SET([manager],        [enable web management console (proof of concept).])
 ARG_ENABL_SET([medcli],         [enable mediation client configuration database plugin.])
@@ -1295,6 +1298,19 @@ AM_CONDITIONAL(PYTHON_EGGS_INSTALL, [test "x$python_eggs_install" = xtrue])
 
 AM_CONDITIONAL(PERL_CPAN_INSTALL, [test "x$perl_cpan_install" = xtrue])
 
+AC_CACHE_CHECK(
+	[if plugin constructors should be resolved statically],
+	[ss_cv_static_plugin_constructors],
+	[if test x$monolithic = xtrue -a x$enable_static = xyes; then
+		ss_cv_static_plugin_constructors=yes
+	 else
+		ss_cv_static_plugin_constructors="no (enabled for static, monolithic builds)"
+	 fi]
+)
+if test "x$ss_cv_static_plugin_constructors" = xyes; then
+	static_plugin_constructors=true
+fi
+
 # ===============================================
 #  collect plugin list for strongSwan components
 # ===============================================
@@ -1309,6 +1325,7 @@ attest_plugins=
 scepclient_plugins=
 pki_plugins=
 scripts_plugins=
+fuzz_plugins=
 manager_plugins=
 medsrv_plugins=
 nm_plugins=
@@ -1332,21 +1349,21 @@ ADD_PLUGIN([aes],                  [s charon scepclient pki scripts nm cmd])
 ADD_PLUGIN([des],                  [s charon scepclient pki scripts nm cmd])
 ADD_PLUGIN([blowfish],             [s charon scepclient pki scripts nm cmd])
 ADD_PLUGIN([rc2],                  [s charon scepclient pki scripts nm cmd])
-ADD_PLUGIN([sha2],                 [s charon scepclient pki scripts medsrv attest nm cmd aikgen])
-ADD_PLUGIN([sha3],                 [s charon scepclient pki scripts medsrv attest nm cmd aikgen])
-ADD_PLUGIN([sha1],                 [s charon scepclient pki scripts manager medsrv attest nm cmd aikgen])
+ADD_PLUGIN([sha2],                 [s charon scepclient pki scripts medsrv attest nm cmd aikgen fuzz])
+ADD_PLUGIN([sha3],                 [s charon scepclient pki scripts medsrv attest nm cmd aikgen fuzz])
+ADD_PLUGIN([sha1],                 [s charon scepclient pki scripts manager medsrv attest nm cmd aikgen fuzz])
 ADD_PLUGIN([md4],                  [s charon scepclient pki nm cmd])
 ADD_PLUGIN([md5],                  [s charon scepclient pki scripts attest nm cmd aikgen])
 ADD_PLUGIN([mgf1],                 [s charon scepclient pki scripts medsrv attest nm cmd aikgen])
 ADD_PLUGIN([rdrand],               [s charon scepclient pki scripts medsrv attest nm cmd aikgen])
 ADD_PLUGIN([random],               [s charon scepclient pki scripts manager medsrv attest nm cmd aikgen])
 ADD_PLUGIN([nonce],                [s charon nm cmd aikgen])
-ADD_PLUGIN([x509],                 [s charon scepclient pki scripts attest nm cmd aikgen])
+ADD_PLUGIN([x509],                 [s charon scepclient pki scripts attest nm cmd aikgen fuzz])
 ADD_PLUGIN([revocation],           [s charon pki nm cmd])
 ADD_PLUGIN([constraints],          [s charon nm cmd])
 ADD_PLUGIN([acert],                [s charon])
 ADD_PLUGIN([pubkey],               [s charon cmd aikgen])
-ADD_PLUGIN([pkcs1],                [s charon scepclient pki scripts manager medsrv attest nm cmd aikgen])
+ADD_PLUGIN([pkcs1],                [s charon scepclient pki scripts manager medsrv attest nm cmd aikgen fuzz])
 ADD_PLUGIN([pkcs7],                [s charon scepclient pki scripts nm cmd])
 ADD_PLUGIN([pkcs8],                [s charon scepclient pki scripts manager medsrv attest nm cmd])
 ADD_PLUGIN([pkcs12],               [s charon scepclient pki scripts cmd])
@@ -1355,14 +1372,14 @@ ADD_PLUGIN([dnskey],               [s charon pki])
 ADD_PLUGIN([sshkey],               [s charon pki nm cmd])
 ADD_PLUGIN([dnscert],              [c charon])
 ADD_PLUGIN([ipseckey],             [c charon])
-ADD_PLUGIN([pem],                  [s charon scepclient pki scripts manager medsrv attest nm cmd aikgen])
+ADD_PLUGIN([pem],                  [s charon scepclient pki scripts manager medsrv attest nm cmd aikgen fuzz])
 ADD_PLUGIN([padlock],              [s charon])
 ADD_PLUGIN([openssl],              [s charon scepclient pki scripts manager medsrv attest nm cmd aikgen])
 ADD_PLUGIN([gcrypt],               [s charon scepclient pki scripts manager medsrv attest nm cmd aikgen])
 ADD_PLUGIN([af-alg],               [s charon scepclient pki scripts medsrv attest nm cmd aikgen])
 ADD_PLUGIN([fips-prf],             [s charon nm cmd])
-ADD_PLUGIN([gmp],                  [s charon scepclient pki scripts manager medsrv attest nm cmd aikgen])
-ADD_PLUGIN([curve25519],           [s charon scripts nm cmd])
+ADD_PLUGIN([gmp],                  [s charon scepclient pki scripts manager medsrv attest nm cmd aikgen fuzz])
+ADD_PLUGIN([curve25519],           [s charon pki scripts nm cmd])
 ADD_PLUGIN([agent],                [s charon nm cmd])
 ADD_PLUGIN([keychain],             [s charon cmd])
 ADD_PLUGIN([chapoly],              [s charon scripts nm cmd])
@@ -1462,6 +1479,7 @@ AC_SUBST(attest_plugins)
 AC_SUBST(scepclient_plugins)
 AC_SUBST(pki_plugins)
 AC_SUBST(scripts_plugins)
+AC_SUBST(fuzz_plugins)
 AC_SUBST(manager_plugins)
 AC_SUBST(medsrv_plugins)
 AC_SUBST(nm_plugins)
@@ -1646,6 +1664,7 @@ AM_CONDITIONAL(USE_NM, test x$nm = xtrue)
 AM_CONDITIONAL(USE_PKI, test x$pki = xtrue)
 AM_CONDITIONAL(USE_SCEPCLIENT, test x$scepclient = xtrue)
 AM_CONDITIONAL(USE_SCRIPTS, test x$scripts = xtrue)
+AM_CONDITIONAL(USE_FUZZING, test x$fuzzing = xtrue)
 AM_CONDITIONAL(USE_CONFTEST, test x$conftest = xtrue)
 AM_CONDITIONAL(USE_LIBSTRONGSWAN, test x$charon = xtrue -o x$pki = xtrue -o x$scepclient = xtrue -o x$conftest = xtrue -o x$fast = xtrue -o x$imcv = xtrue -o x$nm = xtrue -o x$tkm = xtrue -o x$cmd = xtrue -o x$tls = xtrue -o x$tnc_tnccs = xtrue -o x$aikgen = xtrue -o x$svc = xtrue -o x$systemd = xtrue)
 AM_CONDITIONAL(USE_LIBCHARON, test x$charon = xtrue -o x$conftest = xtrue -o x$nm = xtrue -o x$tkm = xtrue -o x$cmd = xtrue -o x$svc = xtrue -o x$systemd = xtrue)
@@ -1667,6 +1686,7 @@ AM_CONDITIONAL(USE_IMCV, test x$imcv = xtrue)
 AM_CONDITIONAL(USE_TROUSERS, test x$tss_trousers = xtrue)
 AM_CONDITIONAL(USE_TSS2, test x$tss_tss2 = xtrue)
 AM_CONDITIONAL(MONOLITHIC, test x$monolithic = xtrue)
+AM_CONDITIONAL(STATIC_PLUGIN_CONSTRUCTORS, test x$static_plugin_constructors = xtrue)
 AM_CONDITIONAL(USE_SILENT_RULES, test x$enable_silent_rules = xyes)
 AM_CONDITIONAL(COVERAGE, test x$coverage = xtrue)
 AM_CONDITIONAL(USE_DBGHELP, test x$dbghelp_backtraces = xtrue)
@@ -1698,12 +1718,18 @@ fi
 if test x$monolithic = xtrue; then
 	AC_DEFINE([MONOLITHIC], [], [monolithic build embedding plugins])
 fi
+if test x$static_plugin_constructors = xtrue; then
+	AC_DEFINE([STATIC_PLUGIN_CONSTRUCTORS], [], [static plugin constructors])
+fi
 if test x$ikev1 = xtrue; then
 	AC_DEFINE([USE_IKEV1], [], [support for IKEv1 protocol])
 fi
 if test x$ikev2 = xtrue; then
 	AC_DEFINE([USE_IKEV2], [], [support for IKEv2 protocol])
 fi
+if test x$fuzzing = xtrue; then
+	AC_DEFINE([USE_FUZZING], [], [build code for fuzzing])
+fi
 
 # ====================================================
 #  options for enabled modules (see conf/Makefile.am)
@@ -1734,6 +1760,7 @@ AC_SUBST(strongswan_options)
 AC_CONFIG_FILES([
 	Makefile
 	conf/Makefile
+	fuzz/Makefile
 	man/Makefile
 	init/Makefile
 	init/systemd/Makefile
diff --git a/fuzz/Makefile.am b/fuzz/Makefile.am
new file mode 100644
index 0000000..66debc2
--- /dev/null
+++ b/fuzz/Makefile.am
@@ -0,0 +1,18 @@
+CPPFLAGS = @CPPFLAGS@ \
+	-I$(top_srcdir)/src/libstrongswan \
+	-DPLUGINDIR=\""$(abs_top_builddir)/src/libstrongswan/plugins\"" \
+	-DPLUGINS="\"${fuzz_plugins}\""
+
+LDFLAGS = @LDFLAGS@ ${libfuzzer} \
+	$(top_builddir)/src/libstrongswan/.libs/libstrongswan.a \
+	-Wl,-Bstatic -lgmp -Wl,-Bdynamic \
+	-stdlib=libc++ -lstdc++
+
+FUZZ_TARGETS=fuzz_certs
+
+all-local: $(FUZZ_TARGETS)
+
+CLEANFILES=$(FUZZ_TARGETS)
+
+fuzz_certs: fuzz_certs.c
+	$(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $< $(LDFLAGS)
diff --git a/src/include/Makefile.in b/fuzz/Makefile.in
similarity index 91%
copy from src/include/Makefile.in
copy to fuzz/Makefile.in
index 068cae1..ea2365f 100644
--- a/src/include/Makefile.in
+++ b/fuzz/Makefile.in
@@ -87,7 +87,7 @@ PRE_UNINSTALL = :
 POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
-subdir = src/include
+subdir = fuzz
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \
 	$(top_srcdir)/m4/config/ltoptions.m4 \
@@ -146,7 +146,11 @@ CFLAGS = @CFLAGS@
 COVERAGE_CFLAGS = @COVERAGE_CFLAGS@
 COVERAGE_LDFLAGS = @COVERAGE_LDFLAGS@
 CPP = @CPP@
-CPPFLAGS = @CPPFLAGS@
+CPPFLAGS = @CPPFLAGS@ \
+	-I$(top_srcdir)/src/libstrongswan \
+	-DPLUGINDIR=\""$(abs_top_builddir)/src/libstrongswan/plugins\"" \
+	-DPLUGINS="\"${fuzz_plugins}\""
+
 CYGPATH_W = @CYGPATH_W@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
@@ -173,7 +177,11 @@ INSTALL_SCRIPT = @INSTALL_SCRIPT@
 INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
 LCOV = @LCOV@
 LD = @LD@
-LDFLAGS = @LDFLAGS@
+LDFLAGS = @LDFLAGS@ ${libfuzzer} \
+	$(top_builddir)/src/libstrongswan/.libs/libstrongswan.a \
+	-Wl,-Bstatic -lgmp -Wl,-Bdynamic \
+	-stdlib=libc++ -lstdc++
+
 LEX = @LEX@
 LEXLIB = @LEXLIB@
 LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
@@ -272,6 +280,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -294,6 +303,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
@@ -358,9 +368,8 @@ tss2_LIBS = @tss2_LIBS@
 urandom_device = @urandom_device@
 xml_CFLAGS = @xml_CFLAGS@
 xml_LIBS = @xml_LIBS@
-EXTRA_DIST = linux/if_alg.h linux/ipsec.h linux/netlink.h linux/rtnetlink.h \
-             linux/pfkeyv2.h linux/udp.h linux/socket.h linux/xfrm.h sys/queue.h
-
+FUZZ_TARGETS = fuzz_certs
+CLEANFILES = $(FUZZ_TARGETS)
 all: all-am
 
 .SUFFIXES:
@@ -373,9 +382,9 @@ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
 	      exit 1;; \
 	  esac; \
 	done; \
-	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/include/Makefile'; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu fuzz/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
-	  $(AUTOMAKE) --gnu src/include/Makefile
+	  $(AUTOMAKE) --gnu fuzz/Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -438,7 +447,7 @@ distdir: $(DISTFILES)
 	done
 check-am: all-am
 check: check-am
-all-am: Makefile
+all-am: Makefile all-local
 installdirs:
 install: install-am
 install-exec: install-exec-am
@@ -462,6 +471,7 @@ install-strip:
 mostlyclean-generic:
 
 clean-generic:
+	-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
 
 distclean-generic:
 	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
@@ -538,21 +548,27 @@ uninstall-am:
 
 .MAKE: install-am install-strip
 
-.PHONY: all all-am check check-am clean clean-generic clean-libtool \
-	cscopelist-am ctags-am distclean distclean-generic \
-	distclean-libtool distdir dvi dvi-am html html-am info info-am \
-	install install-am install-data install-data-am install-dvi \
-	install-dvi-am install-exec install-exec-am install-html \
-	install-html-am install-info install-info-am install-man \
-	install-pdf install-pdf-am install-ps install-ps-am \
-	install-strip installcheck installcheck-am installdirs \
-	maintainer-clean maintainer-clean-generic mostlyclean \
-	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
-	tags-am uninstall uninstall-am
+.PHONY: all all-am all-local check check-am clean clean-generic \
+	clean-libtool cscopelist-am ctags-am distclean \
+	distclean-generic distclean-libtool distdir dvi dvi-am html \
+	html-am info info-am install install-am install-data \
+	install-data-am install-dvi install-dvi-am install-exec \
+	install-exec-am install-html install-html-am install-info \
+	install-info-am install-man install-pdf install-pdf-am \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-generic \
+	mostlyclean-libtool pdf pdf-am ps ps-am tags-am uninstall \
+	uninstall-am
 
 .PRECIOUS: Makefile
 
 
+all-local: $(FUZZ_TARGETS)
+
+fuzz_certs: fuzz_certs.c
+	$(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $< $(LDFLAGS)
+
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
 .NOEXPORT:
diff --git a/init/Makefile.in b/init/Makefile.in
index e1600d0..118b62e 100644
--- a/init/Makefile.in
+++ b/init/Makefile.in
@@ -334,6 +334,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -356,6 +357,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/init/systemd-swanctl/Makefile.in b/init/systemd-swanctl/Makefile.in
index adb2809..432e87c 100644
--- a/init/systemd-swanctl/Makefile.in
+++ b/init/systemd-swanctl/Makefile.in
@@ -302,6 +302,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -324,6 +325,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/init/systemd/Makefile.in b/init/systemd/Makefile.in
index 593727d..a551f8f 100644
--- a/init/systemd/Makefile.in
+++ b/init/systemd/Makefile.in
@@ -302,6 +302,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -324,6 +325,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/man/Makefile.in b/man/Makefile.in
index 61f825c..22b23c0 100644
--- a/man/Makefile.in
+++ b/man/Makefile.in
@@ -308,6 +308,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -330,6 +331,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/man/ipsec.conf.5.in b/man/ipsec.conf.5.in
index 5d1c639..fef44ae 100644
--- a/man/ipsec.conf.5.in
+++ b/man/ipsec.conf.5.in
@@ -445,22 +445,31 @@ force UDP encapsulation for ESP packets even if no NAT situation is detected.
 This may help to surmount restrictive firewalls. In order to force the peer to
 encapsulate packets, NAT detection payloads are faked.
 .TP
-.BR fragmentation " = " yes "  | force | no"
+.BR fragmentation " = " yes "  | accept | force | no"
 whether to use IKE fragmentation (proprietary IKEv1 extension or IKEv2
 fragmentation as per RFC 7383).  Acceptable values are
 .B yes
 (the default),
+.BR accept ,
 .B force
 and
 .BR no .
-Fragmented IKE messages sent by a peer are always accepted
-irrespective of the value of this option. If set to
-.BR yes ,
-and the peer supports it, larger IKE messages will be sent in fragments.
 If set to
+.BR yes ,
+and the peer supports it, oversized IKE messages will be sent in fragments. If
+set to
+.BR accept ,
+support for fragmentation is announced to the peer but the daemon does not send
+its own messages in fragments. If set to
 .B force
 (only supported for IKEv1) the initial IKE message will already be fragmented
-if required.
+if required. Finally, setting the option to
+.B no
+will disable announcing support for this feature.
+
+Note that fragmented IKE messages sent by a peer are always accepted
+irrespective of the value of this option (even when set to
+.BR no ).
 .TP
 .BR ike " = <cipher suites>"
 comma-separated list of IKE/ISAKMP SA encryption/authentication algorithms
@@ -1132,6 +1141,13 @@ a value of 0 disables IPsec replay protection.
 .BR reqid " = <number>"
 sets the reqid for a given connection to a pre-configured fixed value.
 .TP
+.BR sha256_96 " = " no " | yes"
+HMAC-SHA-256 is used with 128-bit truncation with IPsec. For compatibility
+with implementations that incorrectly use 96-bit truncation this option may be
+enabled to configure the shorter truncation length in the kernel.  This is not
+negotiated, so this only works with peers that use the incorrect truncation
+length (or have this option enabled).
+.TP
 .BR tfc " = <value>"
 number of bytes to pad ESP payload data to. Traffic Flow Confidentiality
 is currently supported in IKEv2 and applies to outgoing packets only. The
diff --git a/scripts/Makefile.in b/scripts/Makefile.in
index 6b8319c..2dcbe4d 100644
--- a/scripts/Makefile.in
+++ b/scripts/Makefile.in
@@ -416,6 +416,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -438,6 +439,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/Makefile.in b/src/Makefile.in
index b102370..17c4a9a 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -371,6 +371,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -393,6 +394,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/_copyright/Makefile.in b/src/_copyright/Makefile.in
index aa94c55..0bea80a 100644
--- a/src/_copyright/Makefile.in
+++ b/src/_copyright/Makefile.in
@@ -324,6 +324,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -346,6 +347,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/_updown/Makefile.in b/src/_updown/Makefile.in
index 46b81cb..ba891c1 100644
--- a/src/_updown/Makefile.in
+++ b/src/_updown/Makefile.in
@@ -302,6 +302,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -324,6 +325,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/aikgen/Makefile.in b/src/aikgen/Makefile.in
index 6b19041..7096dd6 100644
--- a/src/aikgen/Makefile.in
+++ b/src/aikgen/Makefile.in
@@ -325,6 +325,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -347,6 +348,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/charon-cmd/Makefile.in b/src/charon-cmd/Makefile.in
index 3a5f028..e4d057f 100644
--- a/src/charon-cmd/Makefile.in
+++ b/src/charon-cmd/Makefile.in
@@ -362,6 +362,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -384,6 +385,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/charon-nm/Makefile.in b/src/charon-nm/Makefile.in
index 90cdb8c..3efcb8f 100644
--- a/src/charon-nm/Makefile.in
+++ b/src/charon-nm/Makefile.in
@@ -361,6 +361,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -383,6 +384,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/charon-nm/charon-nm.c b/src/charon-nm/charon-nm.c
index ca12db8..89aa34d 100644
--- a/src/charon-nm/charon-nm.c
+++ b/src/charon-nm/charon-nm.c
@@ -196,7 +196,7 @@ int main(int argc, char *argv[])
 
 	/* use random ports to avoid conflicts with regular charon */
 	lib->settings->set_int(lib->settings, "charon-nm.port", 0);
-	lib->settings->set_int(lib->settings, "charon-nm.port_natt_t", 0);
+	lib->settings->set_int(lib->settings, "charon-nm.port_nat_t", 0);
 
 	DBG1(DBG_DMN, "Starting charon NetworkManager backend (strongSwan "VERSION")");
 	if (lib->integrity)
diff --git a/src/charon-nm/nm/nm_creds.c b/src/charon-nm/nm/nm_creds.c
index f8fae95..e70fd9e 100644
--- a/src/charon-nm/nm/nm_creds.c
+++ b/src/charon-nm/nm/nm_creds.c
@@ -120,48 +120,49 @@ typedef struct {
 	identification_t *id;
 } cert_data_t;
 
-/**
- * Destroy CA certificate enumerator data
- */
-static void cert_data_destroy(cert_data_t *data)
+CALLBACK(cert_data_destroy, void,
+	cert_data_t *data)
 {
 	data->this->lock->unlock(data->this->lock);
 	free(data);
 }
 
-/**
- * Filter function for certificates enumerator
- */
-static bool cert_filter(cert_data_t *data, certificate_t **in,
-						 certificate_t **out)
+CALLBACK(cert_filter, bool,
+	cert_data_t *data, enumerator_t *orig, va_list args)
 {
-	certificate_t *cert = *in;
+	certificate_t *cert, **out;
 	public_key_t *public;
 
-	public = cert->get_public_key(cert);
-	if (!public)
-	{
-		return FALSE;
-	}
-	if (data->key != KEY_ANY && public->get_type(public) != data->key)
-	{
-		public->destroy(public);
-		return FALSE;
-	}
-	if (data->id && data->id->get_type(data->id) == ID_KEY_ID &&
-		public->has_fingerprint(public, data->id->get_encoding(data->id)))
+	VA_ARGS_VGET(args, out);
+
+	while (orig->enumerate(orig, &cert))
 	{
+		public = cert->get_public_key(cert);
+		if (!public)
+		{
+			continue;
+		}
+		if (data->key != KEY_ANY && public->get_type(public) != data->key)
+		{
+			public->destroy(public);
+			continue;
+		}
+		if (data->id && data->id->get_type(data->id) == ID_KEY_ID &&
+			public->has_fingerprint(public, data->id->get_encoding(data->id)))
+		{
+			public->destroy(public);
+			*out = cert;
+			return TRUE;
+		}
 		public->destroy(public);
+		if (data->id && !cert->has_subject(cert, data->id))
+		{
+			continue;
+		}
 		*out = cert;
 		return TRUE;
 	}
-	public->destroy(public);
-	if (data->id && !cert->has_subject(cert, data->id))
-	{
-		return FALSE;
-	}
-	*out = cert;
-	return TRUE;
+	return FALSE;
 }
 
 /**
@@ -181,7 +182,7 @@ static enumerator_t *create_trusted_cert_enumerator(private_nm_creds_t *this,
 	this->lock->read_lock(this->lock);
 	return enumerator_create_filter(
 					this->certs->create_enumerator(this->certs),
-					(void*)cert_filter, data, (void*)cert_data_destroy);
+					cert_filter, data, cert_data_destroy);
 }
 
 METHOD(credential_set_t, create_cert_enumerator, enumerator_t*,
@@ -235,9 +236,13 @@ typedef struct {
 } shared_enumerator_t;
 
 METHOD(enumerator_t, shared_enumerate, bool,
-	shared_enumerator_t *this, shared_key_t **key, id_match_t *me,
-	id_match_t *other)
+	shared_enumerator_t *this, va_list args)
 {
+	shared_key_t **key;
+	id_match_t *me, *other;
+
+	VA_ARGS_VGET(args, key, me, other);
+
 	if (this->done)
 	{
 		return FALSE;
@@ -307,7 +312,8 @@ METHOD(credential_set_t, create_shared_enumerator, enumerator_t*,
 
 	INIT(enumerator,
 		.public = {
-			.enumerate = (void*)_shared_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _shared_enumerate,
 			.destroy = _shared_destroy,
 		},
 		.this = this,
diff --git a/src/charon-nm/nm/nm_handler.c b/src/charon-nm/nm/nm_handler.c
index bdc0667..3eb2eb1 100644
--- a/src/charon-nm/nm/nm_handler.c
+++ b/src/charon-nm/nm/nm_handler.c
@@ -65,29 +65,33 @@ METHOD(attribute_handler_t, handle, bool,
 	return TRUE;
 }
 
-/**
- * Implementation of create_attribute_enumerator().enumerate() for WINS
- */
-static bool enumerate_nbns(enumerator_t *this,
-						   configuration_attribute_type_t *type, chunk_t *data)
+METHOD(enumerator_t, enumerate_nbns, bool,
+	enumerator_t *this, va_list args)
 {
+	configuration_attribute_type_t *type;
+	chunk_t *data;
+
+	VA_ARGS_VGET(args, type, data);
 	*type = INTERNAL_IP4_NBNS;
 	*data = chunk_empty;
-	/* done */
-	this->enumerate = (void*)return_false;
+	this->venumerate = (void*)return_false;
 	return TRUE;
 }
 
 /**
  * Implementation of create_attribute_enumerator().enumerate() for DNS
  */
-static bool enumerate_dns(enumerator_t *this,
-						  configuration_attribute_type_t *type, chunk_t *data)
+METHOD(enumerator_t, enumerate_dns, bool,
+	enumerator_t *this, va_list args)
 {
+	configuration_attribute_type_t *type;
+	chunk_t *data;
+
+	VA_ARGS_VGET(args, type, data);
 	*type = INTERNAL_IP4_DNS;
 	*data = chunk_empty;
 	/* enumerate WINS server as next attribute ... */
-	this->enumerate = (void*)enumerate_nbns;
+	this->venumerate = _enumerate_nbns;
 	return TRUE;
 }
 
@@ -100,7 +104,8 @@ METHOD(attribute_handler_t, create_attribute_enumerator, enumerator_t*,
 
 		INIT(enumerator,
 			/* enumerate DNS attribute first ... */
-			.enumerate = (void*)enumerate_dns,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _enumerate_dns,
 			.destroy = (void*)free,
 		);
 		return enumerator;
@@ -108,13 +113,20 @@ METHOD(attribute_handler_t, create_attribute_enumerator, enumerator_t*,
 	return enumerator_create_empty();
 }
 
-/**
- * convert plain byte ptrs to handy chunk during enumeration
- */
-static bool filter_chunks(void* null, char **in, chunk_t *out)
+CALLBACK(filter_chunks, bool,
+	void *null, enumerator_t *orig, va_list args)
 {
-	*out = chunk_create(*in, 4);
-	return TRUE;
+	chunk_t *out;
+	char *ptr;
+
+	VA_ARGS_VGET(args, out);
+
+	if (orig->enumerate(orig, &ptr))
+	{
+		*out = chunk_create(ptr, 4);
+		return TRUE;
+	}
+	return FALSE;
 }
 
 METHOD(nm_handler_t, create_enumerator, enumerator_t*,
@@ -134,7 +146,7 @@ METHOD(nm_handler_t, create_enumerator, enumerator_t*,
 			return enumerator_create_empty();
 	}
 	return enumerator_create_filter(list->create_enumerator(list),
-						(void*)filter_chunks, NULL, NULL);
+									filter_chunks, NULL, NULL);
 }
 
 METHOD(nm_handler_t, reset, void,
diff --git a/src/charon-nm/nm/nm_service.c b/src/charon-nm/nm/nm_service.c
index 571c0ed..3e8392a 100644
--- a/src/charon-nm/nm/nm_service.c
+++ b/src/charon-nm/nm/nm_service.c
@@ -283,9 +283,11 @@ static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection,
 	NMStrongswanPluginPrivate *priv;
 	NMSettingConnection *conn;
 	NMSettingVPN *vpn;
+	enumerator_t *enumerator;
 	identification_t *user = NULL, *gateway = NULL;
 	const char *address, *str;
-	bool virtual, encap;
+	bool virtual, encap, proposal;
+	proposal_t *prop;
 	ike_cfg_t *ike_cfg;
 	peer_cfg_t *peer_cfg;
 	child_cfg_t *child_cfg;
@@ -344,7 +346,7 @@ static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection,
 	str = nm_setting_vpn_get_data_item(vpn, "encap");
 	encap = streq(str, "yes");
 	str = nm_setting_vpn_get_data_item(vpn, "ipcomp");
-	child.ipcomp = streq(str, "yes");
+	child.options |= streq(str, "yes") ? OPT_IPCOMP : 0;
 	str = nm_setting_vpn_get_data_item(vpn, "method");
 	if (streq(str, "psk"))
 	{
@@ -540,8 +542,36 @@ static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection,
 							 charon->socket->get_port(charon->socket, FALSE),
 							(char*)address, IKEV2_UDP_PORT,
 							 FRAGMENTATION_YES, 0);
-	ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE));
-	ike_cfg->add_proposal(ike_cfg, proposal_create_default_aead(PROTO_IKE));
+
+	str = nm_setting_vpn_get_data_item(vpn, "proposal");
+	proposal = streq(str, "yes");
+	str = nm_setting_vpn_get_data_item(vpn, "ike");
+	if (proposal && str && strlen(str))
+	{
+		enumerator = enumerator_create_token(str, ";", "");
+		while (enumerator->enumerate(enumerator, &str))
+		{
+			prop = proposal_create_from_string(PROTO_IKE, str);
+			if (!prop)
+			{
+				g_set_error(err, NM_VPN_PLUGIN_ERROR,
+							NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED,
+							"Invalid IKE proposal.");
+				enumerator->destroy(enumerator);
+				ike_cfg->destroy(ike_cfg);
+				gateway->destroy(gateway);
+				user->destroy(user);
+				return FALSE;
+			}
+			ike_cfg->add_proposal(ike_cfg, prop);
+		}
+		enumerator->destroy(enumerator);
+	}
+	else
+	{
+		ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE));
+		ike_cfg->add_proposal(ike_cfg, proposal_create_default_aead(PROTO_IKE));
+	}
 
 	peer_cfg = peer_cfg_create(priv->name, ike_cfg, &peer);
 	if (virtual)
@@ -566,8 +596,32 @@ static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection,
 	peer_cfg->add_auth_cfg(peer_cfg, auth, FALSE);
 
 	child_cfg = child_cfg_create(priv->name, &child);
-	child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP));
-	child_cfg->add_proposal(child_cfg, proposal_create_default_aead(PROTO_ESP));
+	str = nm_setting_vpn_get_data_item(vpn, "esp");
+	if (proposal && str && strlen(str))
+	{
+		enumerator = enumerator_create_token(str, ";", "");
+		while (enumerator->enumerate(enumerator, &str))
+		{
+			prop = proposal_create_from_string(PROTO_ESP, str);
+			if (!prop)
+			{
+				g_set_error(err, NM_VPN_PLUGIN_ERROR,
+							NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED,
+							"Invalid ESP proposal.");
+				enumerator->destroy(enumerator);
+				child_cfg->destroy(child_cfg);
+				peer_cfg->destroy(peer_cfg);
+				return FALSE;
+			}
+			child_cfg->add_proposal(child_cfg, prop);
+		}
+		enumerator->destroy(enumerator);
+	}
+	else
+	{
+		child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP));
+		child_cfg->add_proposal(child_cfg, proposal_create_default_aead(PROTO_ESP));
+	}
 	ts = traffic_selector_create_dynamic(0, 0, 65535);
 	child_cfg->add_traffic_selector(child_cfg, TRUE, ts);
 	ts = traffic_selector_create_from_string(0, TS_IPV4_ADDR_RANGE,
diff --git a/src/charon-svc/Makefile.in b/src/charon-svc/Makefile.in
index 7dd0fb6..9c08e8a 100644
--- a/src/charon-svc/Makefile.in
+++ b/src/charon-svc/Makefile.in
@@ -325,6 +325,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -347,6 +348,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/charon-systemd/Makefile.in b/src/charon-systemd/Makefile.in
index 1959818..9377539 100644
--- a/src/charon-systemd/Makefile.in
+++ b/src/charon-systemd/Makefile.in
@@ -329,6 +329,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -351,6 +352,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/charon-tkm/Makefile.in b/src/charon-tkm/Makefile.in
index 538335b..9987b44 100644
--- a/src/charon-tkm/Makefile.in
+++ b/src/charon-tkm/Makefile.in
@@ -272,6 +272,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -294,6 +295,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/charon-tkm/src/tkm/tkm_kernel_sad.c b/src/charon-tkm/src/tkm/tkm_kernel_sad.c
index 22d2aac..97226f1 100644
--- a/src/charon-tkm/src/tkm/tkm_kernel_sad.c
+++ b/src/charon-tkm/src/tkm/tkm_kernel_sad.c
@@ -101,61 +101,63 @@ static void sad_entry_destroy(sad_entry_t *entry)
 	}
 }
 
-/**
- * Find a list entry with given src, dst, (remote) spi and proto values.
- */
-static bool sad_entry_match(sad_entry_t * const entry, const host_t * const src,
-							const host_t * const dst, const uint32_t * const spi,
-							const uint8_t * const proto)
+CALLBACK(sad_entry_match, bool,
+	sad_entry_t * const entry, va_list args)
 {
+	const host_t *src, *dst;
+	const uint32_t *spi;
+	const uint8_t *proto;
+
+	VA_ARGS_VGET(args, src, dst, spi, proto);
+
 	if (entry->src == NULL || entry->dst == NULL)
 	{
 		return FALSE;
 	}
-
 	return src->ip_equals(entry->src, (host_t *)src) &&
 		   dst->ip_equals(entry->dst, (host_t *)dst) &&
 		   entry->spi_rem == *spi && entry->proto == *proto;
 }
 
-/**
- * Find a list entry with given reqid, spi and proto values.
- */
-static bool sad_entry_match_dst(sad_entry_t * const entry,
-								const uint32_t * const reqid,
-								const uint32_t * const spi,
-								const uint8_t * const proto)
+CALLBACK(sad_entry_match_dst, bool,
+	sad_entry_t * const entry, va_list args)
 {
+	const uint32_t *reqid, *spi;
+	const uint8_t *proto;
+
+	VA_ARGS_VGET(args, reqid, spi, proto);
 	return entry->reqid   == *reqid &&
 		   entry->spi_rem == *spi   &&
 		   entry->proto   == *proto;
 }
 
-/**
- * Find a list entry with given esa id.
- */
-static bool sad_entry_match_esa_id(sad_entry_t * const entry,
-								   const esa_id_type * const esa_id)
+CALLBACK(sad_entry_match_esa_id, bool,
+	sad_entry_t * const entry, va_list args)
 {
+	const esa_id_type *esa_id;
+
+	VA_ARGS_VGET(args, esa_id);
 	return entry->esa_id == *esa_id;
 }
 
-/**
- * Find a list entry with given reqid and different esa id.
- */
-static bool sad_entry_match_other_esa(sad_entry_t * const entry,
-									  const esa_id_type * const esa_id,
-									  const uint32_t * const reqid)
+CALLBACK(sad_entry_match_other_esa, bool,
+	sad_entry_t * const entry, va_list args)
 {
+	const esa_id_type *esa_id;
+	const uint32_t *reqid;
+
+	VA_ARGS_VGET(args, esa_id, reqid);
 	return entry->reqid  == *reqid &&
 		   entry->esa_id != *esa_id;
 }
 
-/**
- * Compare two SAD entries for equality.
- */
-static bool sad_entry_equal(sad_entry_t * const left, sad_entry_t * const right)
+CALLBACK(sad_entry_equal, bool,
+	sad_entry_t * const left, va_list args)
 {
+	sad_entry_t *right;
+
+	VA_ARGS_VGET(args, right);
+
 	if (left->src == NULL || left->dst == NULL || right->src == NULL ||
 		right->dst == NULL)
 	{
@@ -175,8 +177,8 @@ METHOD(tkm_kernel_sad_t, insert, bool,
 	const uint32_t reqid, const host_t * const src, const host_t * const dst,
 	const uint32_t spi_loc, const uint32_t spi_rem, const uint8_t proto)
 {
-	status_t result;
 	sad_entry_t *new_entry;
+	bool found;
 
 	INIT(new_entry,
 		 .esa_id = esa_id,
@@ -189,10 +191,9 @@ METHOD(tkm_kernel_sad_t, insert, bool,
 	);
 
 	this->mutex->lock(this->mutex);
-	result = this->data->find_first(this->data,
-									(linked_list_match_t)sad_entry_equal, NULL,
+	found = this->data->find_first(this->data, sad_entry_equal, NULL,
 									new_entry);
-	if (result == NOT_FOUND)
+	if (!found)
 	{
 		DBG3(DBG_KNL, "inserting SAD entry (esa: %llu, reqid: %u, src: %H, "
 			 "dst: %H, spi_loc: %x, spi_rem: %x,proto: %u)", esa_id, reqid, src,
@@ -207,7 +208,7 @@ METHOD(tkm_kernel_sad_t, insert, bool,
 		free(new_entry);
 	}
 	this->mutex->unlock(this->mutex);
-	return result == NOT_FOUND;
+	return !found;
 }
 
 METHOD(tkm_kernel_sad_t, get_esa_id, esa_id_type,
@@ -218,11 +219,10 @@ METHOD(tkm_kernel_sad_t, get_esa_id, esa_id_type,
 	sad_entry_t *entry = NULL;
 
 	this->mutex->lock(this->mutex);
-	const status_t res = this->data->find_first(this->data,
-												(linked_list_match_t)sad_entry_match,
-												(void**)&entry, src, dst, &spi,
-												&proto);
-	if (res == SUCCESS && entry)
+	const bool res = this->data->find_first(this->data, sad_entry_match,
+											(void**)&entry, src, dst, &spi,
+											&proto);
+	if (res && entry)
 	{
 		id = entry->esa_id;
 		DBG3(DBG_KNL, "returning ESA id %llu of SAD entry (src: %H, dst: %H, "
@@ -243,13 +243,12 @@ METHOD(tkm_kernel_sad_t, get_other_esa_id, esa_id_type,
 	esa_id_type id = 0;
 	sad_entry_t *entry = NULL;
 	uint32_t reqid;
-	status_t res;
+	bool res;
 
 	this->mutex->lock(this->mutex);
-	res = this->data->find_first(this->data,
-								 (linked_list_match_t)sad_entry_match_esa_id,
+	res = this->data->find_first(this->data, sad_entry_match_esa_id,
 								 (void**)&entry, &esa_id);
-	if (res == SUCCESS && entry)
+	if (res && entry)
 	{
 		reqid = entry->reqid;
 	}
@@ -260,10 +259,9 @@ METHOD(tkm_kernel_sad_t, get_other_esa_id, esa_id_type,
 		return id;
 	}
 
-	res = this->data->find_first(this->data,
-								 (linked_list_match_t)sad_entry_match_other_esa,
+	res = this->data->find_first(this->data, sad_entry_match_other_esa,
 								 (void**)&entry, &esa_id, &reqid);
-	if (res == SUCCESS && entry)
+	if (res && entry)
 	{
 		id = entry->esa_id;
 		DBG3(DBG_KNL, "returning ESA id %llu of other SAD entry with reqid %u",
@@ -281,10 +279,9 @@ METHOD(tkm_kernel_sad_t, get_dst_host, host_t *,
 	sad_entry_t *entry = NULL;
 
 	this->mutex->lock(this->mutex);
-	const status_t res = this->data->find_first(this->data,
-												(linked_list_match_t)sad_entry_match_dst,
-												(void**)&entry, &reqid, &spi, &proto);
-	if (res == SUCCESS && entry)
+	const bool res = this->data->find_first(this->data, sad_entry_match_dst,
+											(void**)&entry, &reqid, &spi, &proto);
+	if (res && entry)
 	{
 		dst = entry->dst;
 		DBG3(DBG_KNL, "returning destination host %H of SAD entry (reqid: %u,"
diff --git a/src/charon/Makefile.in b/src/charon/Makefile.in
index 8cf782f..d4cec54 100644
--- a/src/charon/Makefile.in
+++ b/src/charon/Makefile.in
@@ -328,6 +328,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -350,6 +351,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/checksum/Makefile.in b/src/checksum/Makefile.in
index 5e7a4ca..e4e3a16 100644
--- a/src/checksum/Makefile.in
+++ b/src/checksum/Makefile.in
@@ -397,6 +397,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -419,6 +420,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/conftest/Makefile.in b/src/conftest/Makefile.in
index 14b8351..c7d4c6b 100644
--- a/src/conftest/Makefile.in
+++ b/src/conftest/Makefile.in
@@ -342,6 +342,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -364,6 +365,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/conftest/config.c b/src/conftest/config.c
index 06a6850..d926dfc 100644
--- a/src/conftest/config.c
+++ b/src/conftest/config.c
@@ -36,13 +36,20 @@ struct private_config_t {
 	linked_list_t *configs;
 };
 
-/**
- * filter function for ike configs
- */
-static bool ike_filter(void *data, peer_cfg_t **in, ike_cfg_t **out)
+CALLBACK(ike_filter, bool,
+	void *data, enumerator_t *orig, va_list args)
 {
-	*out = (*in)->get_ike_cfg(*in);
-	return TRUE;
+	peer_cfg_t *cfg;
+	ike_cfg_t **out;
+
+	VA_ARGS_VGET(args, out);
+
+	if (orig->enumerate(orig, &cfg))
+	{
+		*out = cfg->get_ike_cfg(cfg);
+		return TRUE;
+	}
+	return FALSE;
 }
 
 METHOD(backend_t, create_ike_cfg_enumerator, enumerator_t*,
@@ -51,7 +58,7 @@ METHOD(backend_t, create_ike_cfg_enumerator, enumerator_t*,
 
 	return enumerator_create_filter(
 							this->configs->create_enumerator(this->configs),
-							(void*)ike_filter, NULL, NULL);
+							ike_filter, NULL, NULL);
 }
 
 METHOD(backend_t, create_peer_cfg_enumerator, enumerator_t*,
diff --git a/src/dumm/Makefile.in b/src/dumm/Makefile.in
index dc1e3dc..276ca2e 100644
--- a/src/dumm/Makefile.in
+++ b/src/dumm/Makefile.in
@@ -363,6 +363,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -385,6 +386,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/dumm/cowfs.c b/src/dumm/cowfs.c
index 28c62c2..5332ba5 100644
--- a/src/dumm/cowfs.c
+++ b/src/dumm/cowfs.c
@@ -92,11 +92,12 @@ static void overlay_destroy(overlay_t *this)
 	free(this);
 }
 
-/**
- * compare two overlays by path
- */
-static bool overlay_equals(overlay_t *this, overlay_t *other)
+CALLBACK(overlay_equals, bool,
+	overlay_t *this, va_list args)
 {
+	overlay_t *other;
+
+	VA_ARGS_VGET(args, other);
 	return streq(this->path, other->path);
 }
 
@@ -108,8 +109,8 @@ static bool overlay_remove(private_cowfs_t *this, char *path)
 {
 	overlay_t over, *current;
 	over.path = path;
-	if (this->overlays->find_first(this->overlays,
-			(linked_list_match_t)overlay_equals, (void**)&current, &over) != SUCCESS)
+	if (!this->overlays->find_first(this->overlays, overlay_equals,
+									(void**)&current, &over))
 	{
 		return FALSE;
 	}
diff --git a/src/dumm/dumm.c b/src/dumm/dumm.c
index cc4f5a1..d147b2d 100644
--- a/src/dumm/dumm.c
+++ b/src/dumm/dumm.c
@@ -267,10 +267,12 @@ typedef struct {
 } template_enumerator_t;
 
 METHOD(enumerator_t, template_enumerate, bool,
-	template_enumerator_t *this, char **template)
+	template_enumerator_t *this, va_list args)
 {
 	struct stat st;
-	char *rel;
+	char *rel, **template;
+
+	VA_ARGS_VGET(args, template);
 
 	while (this->inner->enumerate(this->inner, &rel, NULL, &st))
 	{
@@ -296,7 +298,8 @@ METHOD(dumm_t, create_template_enumerator, enumerator_t*,
 	template_enumerator_t *enumerator;
 	INIT(enumerator,
 		.public = {
-			.enumerate = (void*)_template_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _template_enumerate,
 			.destroy = (void*)_template_enumerator_destroy,
 		},
 		.inner = enumerator_create_directory(TEMPLATE_DIR),
diff --git a/src/include/Makefile.in b/src/include/Makefile.in
index 068cae1..569574f 100644
--- a/src/include/Makefile.in
+++ b/src/include/Makefile.in
@@ -272,6 +272,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -294,6 +295,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/include/linux/xfrm.h b/src/include/linux/xfrm.h
index 02d5125..dbaa4f1 100644
--- a/src/include/linux/xfrm.h
+++ b/src/include/linux/xfrm.h
@@ -296,10 +296,12 @@ enum xfrm_attr_type_t {
 	XFRMA_ALG_AUTH_TRUNC,	/* struct xfrm_algo_auth */
 	XFRMA_MARK,		/* struct xfrm_mark */
 	XFRMA_TFCPAD,		/* __u32 */
-	XFRMA_REPLAY_ESN_VAL,	/* struct xfrm_replay_esn */
+	XFRMA_REPLAY_ESN_VAL,	/* struct xfrm_replay_state_esn */
 	XFRMA_SA_EXTRA_FLAGS,	/* __u32 */
 	XFRMA_PROTO,		/* __u8 */
 	XFRMA_ADDRESS_FILTER,	/* struct xfrm_address_filter */
+	XFRMA_PAD,
+	XFRMA_OFFLOAD_DEV,	/* struct xfrm_state_offload */
 	__XFRMA_MAX
 
 #define XFRMA_MAX (__XFRMA_MAX - 1)
@@ -491,6 +493,13 @@ struct xfrm_address_filter {
 	__u8				dplen;
 };
 
+struct xfrm_user_offload {
+	int				ifindex;
+	__u8				flags;
+};
+#define XFRM_OFFLOAD_IPV6	1
+#define XFRM_OFFLOAD_INBOUND	2
+
 #ifndef __KERNEL__
 /* backwards compatibility for userspace */
 #define XFRMGRP_ACQUIRE		1
diff --git a/src/ipsec/Makefile.in b/src/ipsec/Makefile.in
index faf7c76..1a92242 100644
--- a/src/ipsec/Makefile.in
+++ b/src/ipsec/Makefile.in
@@ -305,6 +305,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -327,6 +328,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/ipsec/_ipsec.8 b/src/ipsec/_ipsec.8
index 1ae6375..3f4316d 100644
--- a/src/ipsec/_ipsec.8
+++ b/src/ipsec/_ipsec.8
@@ -1,4 +1,4 @@
-.TH IPSEC 8 "2013-10-29" "5.5.2dr4" "strongSwan"
+.TH IPSEC 8 "2013-10-29" "5.5.3dr2" "strongSwan"
 .
 .SH NAME
 .
diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am
index 8461d62..3fcaedc 100644
--- a/src/libcharon/Makefile.am
+++ b/src/libcharon/Makefile.am
@@ -184,6 +184,15 @@ if USE_ME
     sa/ikev2/tasks/ike_me.c sa/ikev2/tasks/ike_me.h
 endif
 
+if STATIC_PLUGIN_CONSTRUCTORS
+BUILT_SOURCES = $(srcdir)/plugin_constructors.c
+CLEANFILES = $(srcdir)/plugin_constructors.c
+
+$(srcdir)/plugin_constructors.c: $(top_srcdir)/src/libstrongswan/plugins/plugin_constructors.py
+		$(AM_V_GEN) \
+		$(PYTHON) $(top_srcdir)/src/libstrongswan/plugins/plugin_constructors.py ${c_plugins} > $@
+endif
+
 # build optional plugins
 ########################
 
diff --git a/src/libcharon/Makefile.in b/src/libcharon/Makefile.in
index 8f6dc89..ef9ffd3 100644
--- a/src/libcharon/Makefile.in
+++ b/src/libcharon/Makefile.in
@@ -934,6 +934,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -956,6 +957,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
@@ -1167,6 +1169,8 @@ libcharon_la_LIBADD =  \
 	$(am__append_141) $(am__append_143) $(am__append_145) \
 	$(am__append_147)
 EXTRA_DIST = Android.mk
+ at STATIC_PLUGIN_CONSTRUCTORS_TRUE@BUILT_SOURCES = $(srcdir)/plugin_constructors.c
+ at STATIC_PLUGIN_CONSTRUCTORS_TRUE@CLEANFILES = $(srcdir)/plugin_constructors.c
 @MONOLITHIC_FALSE at SUBDIRS = . $(am__append_6) $(am__append_8) \
 @MONOLITHIC_FALSE@	$(am__append_10) $(am__append_12) \
 @MONOLITHIC_FALSE@	$(am__append_14) $(am__append_16) \
@@ -1240,7 +1244,8 @@ EXTRA_DIST = Android.mk
 @MONOLITHIC_TRUE@	$(am__append_138) $(am__append_140) \
 @MONOLITHIC_TRUE@	$(am__append_142) $(am__append_144) \
 @MONOLITHIC_TRUE@	$(am__append_146) . tests
-all: all-recursive
+all: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) all-recursive
 
 .SUFFIXES:
 .SUFFIXES: .c .lo .o .obj
@@ -2095,14 +2100,16 @@ distdir: $(DISTFILES)
 	  fi; \
 	done
 check-am: all-am
-check: check-recursive
+check: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) check-recursive
 all-am: Makefile $(LTLIBRARIES)
 installdirs: installdirs-recursive
 installdirs-am:
 	for dir in "$(DESTDIR)$(ipseclibdir)"; do \
 	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
 	done
-install: install-recursive
+install: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) install-recursive
 install-exec: install-exec-recursive
 install-data: install-data-recursive
 uninstall: uninstall-recursive
@@ -2124,6 +2131,7 @@ install-strip:
 mostlyclean-generic:
 
 clean-generic:
+	-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
 
 distclean-generic:
 	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
@@ -2170,6 +2178,7 @@ distclean-generic:
 maintainer-clean-generic:
 	@echo "This command is intended for maintainers to use"
 	@echo "it deletes files that may require special tools to rebuild."
+	-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
 clean: clean-recursive
 
 clean-am: clean-generic clean-ipseclibLTLIBRARIES clean-libtool \
@@ -2241,7 +2250,8 @@ ps-am:
 
 uninstall-am: uninstall-ipseclibLTLIBRARIES
 
-.MAKE: $(am__recursive_targets) install-am install-strip
+.MAKE: $(am__recursive_targets) all check install install-am \
+	install-strip
 
 .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
 	check-am clean clean-generic clean-ipseclibLTLIBRARIES \
@@ -2264,6 +2274,10 @@ uninstall-am: uninstall-ipseclibLTLIBRARIES
 
 daemon.lo :		$(top_builddir)/config.status
 
+ at STATIC_PLUGIN_CONSTRUCTORS_TRUE@$(srcdir)/plugin_constructors.c: $(top_srcdir)/src/libstrongswan/plugins/plugin_constructors.py
+ at STATIC_PLUGIN_CONSTRUCTORS_TRUE@		$(AM_V_GEN) \
+ at STATIC_PLUGIN_CONSTRUCTORS_TRUE@		$(PYTHON) $(top_srcdir)/src/libstrongswan/plugins/plugin_constructors.py ${c_plugins} > $@
+
 @MONOLITHIC_TRUE@@USE_SIMAKA_TRUE@  # otherwise this library is linked to both the eap_aka and the eap_sim plugin
 
 @MONOLITHIC_TRUE@@USE_TLS_TRUE@  # otherwise this library is linked to eap_tls
diff --git a/src/libcharon/attributes/attribute_manager.c b/src/libcharon/attributes/attribute_manager.c
index 2ab7ed1..3a4a21a 100644
--- a/src/libcharon/attributes/attribute_manager.c
+++ b/src/libcharon/attributes/attribute_manager.c
@@ -237,14 +237,14 @@ typedef struct {
 	linked_list_t *vips;
 } initiator_enumerator_t;
 
-/**
- * Enumerator implementation for initiator attributes
- */
-static bool initiator_enumerate(initiator_enumerator_t *this,
-								attribute_handler_t **handler,
-								configuration_attribute_type_t *type,
-								chunk_t *value)
+METHOD(enumerator_t, initiator_enumerate, bool,
+	initiator_enumerator_t *this, va_list args)
 {
+	configuration_attribute_type_t *type;
+	attribute_handler_t **handler;
+	chunk_t *value;
+
+	VA_ARGS_VGET(args, handler, type, value);
 	/* enumerate inner attributes using outer handler enumerator */
 	while (!this->inner || !this->inner->enumerate(this->inner, type, value))
 	{
@@ -261,10 +261,8 @@ static bool initiator_enumerate(initiator_enumerator_t *this,
 	return TRUE;
 }
 
-/**
- * Cleanup function of initiator attribute enumerator
- */
-static void initiator_destroy(initiator_enumerator_t *this)
+METHOD(enumerator_t, initiator_destroy, void,
+	initiator_enumerator_t *this)
 {
 	this->this->lock->unlock(this->this->lock);
 	this->outer->destroy(this->outer);
@@ -281,8 +279,9 @@ METHOD(attribute_manager_t, create_initiator_enumerator, enumerator_t*,
 
 	INIT(enumerator,
 		.public = {
-			.enumerate = (void*)initiator_enumerate,
-			.destroy = (void*)initiator_destroy,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _initiator_enumerate,
+			.destroy = _initiator_destroy,
 		},
 		.this = this,
 		.ike_sa = ike_sa,
diff --git a/src/libcharon/attributes/mem_pool.c b/src/libcharon/attributes/mem_pool.c
index a2b7c28..e1a9a6d 100644
--- a/src/libcharon/attributes/mem_pool.c
+++ b/src/libcharon/attributes/mem_pool.c
@@ -512,10 +512,15 @@ typedef struct {
 } lease_enumerator_t;
 
 METHOD(enumerator_t, lease_enumerate, bool,
-	lease_enumerator_t *this, identification_t **id, host_t **addr, bool *online)
+	lease_enumerator_t *this, va_list args)
 {
-	u_int *offset;
+	identification_t **id;
 	unique_lease_t *lease;
+	host_t **addr;
+	u_int *offset;
+	bool *online;
+
+	VA_ARGS_VGET(args, id, addr, online);
 
 	DESTROY_IF(this->addr);
 	this->addr = NULL;
@@ -570,7 +575,8 @@ METHOD(mem_pool_t, create_lease_enumerator, enumerator_t*,
 	this->mutex->lock(this->mutex);
 	INIT(enumerator,
 		.public = {
-			.enumerate = (void*)_lease_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _lease_enumerate,
 			.destroy = _lease_enumerator_destroy,
 		},
 		.pool = this,
diff --git a/src/libcharon/bus/bus.c b/src/libcharon/bus/bus.c
index f4bba87..77a9101 100644
--- a/src/libcharon/bus/bus.c
+++ b/src/libcharon/bus/bus.c
@@ -207,20 +207,20 @@ static inline void register_logger(private_bus_t *this, debug_t group,
 	}
 }
 
-/**
- * Find the log level of the first registered logger that implements log or
- * vlog (or both).
- */
-static bool find_max_levels(log_entry_t *entry, debug_t *group, level_t *level,
-							level_t *vlevel)
+CALLBACK(find_max_levels, bool,
+	log_entry_t *entry, va_list args)
 {
+	level_t *level, *vlevel;
+	debug_t group;
+
+	VA_ARGS_VGET(args, group, level, vlevel);
 	if (entry->logger->log && *level == LEVEL_SILENT)
 	{
-		*level = entry->levels[*group];
+		*level = entry->levels[group];
 	}
 	if (entry->logger->vlog && *vlevel == LEVEL_SILENT)
 	{
-		*vlevel = entry->levels[*group];
+		*vlevel = entry->levels[group];
 	}
 	return *level > LEVEL_SILENT && *vlevel > LEVEL_SILENT;
 }
@@ -258,8 +258,8 @@ static inline void unregister_logger(private_bus_t *this, logger_t *logger)
 
 				loggers = this->loggers[group];
 				loggers->remove(loggers, found, NULL);
-				loggers->find_first(loggers, (linked_list_match_t)find_max_levels,
-									NULL, &group, &level, &vlevel);
+				loggers->find_first(loggers, find_max_levels, NULL, group,
+									&level, &vlevel);
 				set_level(&this->max_level[group], level);
 				set_level(&this->max_vlevel[group], vlevel);
 			}
@@ -330,11 +330,12 @@ typedef struct {
 	va_list args;
 } log_data_t;
 
-/**
- * logger->log() invocation as a invoke_function callback
- */
-static void log_cb(log_entry_t *entry, log_data_t *data)
+CALLBACK(log_cb, void,
+	log_entry_t *entry, va_list args)
 {
+	log_data_t *data;
+
+	VA_ARGS_VGET(args, data);
 	if (entry->logger->log && entry->levels[data->group] >= data->level)
 	{
 		entry->logger->log(entry->logger, data->group, data->level,
@@ -342,11 +343,12 @@ static void log_cb(log_entry_t *entry, log_data_t *data)
 	}
 }
 
-/**
- * logger->vlog() invocation as a invoke_function callback
- */
-static void vlog_cb(log_entry_t *entry, log_data_t *data)
+CALLBACK(vlog_cb, void,
+	log_entry_t *entry, va_list args)
 {
+	log_data_t *data;
+
+	VA_ARGS_VGET(args, data);
 	if (entry->logger->vlog && entry->levels[data->group] >= data->level)
 	{
 		va_list copy;
@@ -405,8 +407,7 @@ METHOD(bus_t, vlog, void,
 		}
 		if (len > 0)
 		{
-			loggers->invoke_function(loggers, (linked_list_invoke_t)log_cb,
-									 &data);
+			loggers->invoke_function(loggers, log_cb, &data);
 		}
 		if (data.message != buf)
 		{
@@ -422,7 +423,7 @@ METHOD(bus_t, vlog, void,
 		data.message = format;
 
 		va_copy(data.args, args);
-		loggers->invoke_function(loggers, (linked_list_invoke_t)vlog_cb, &data);
+		loggers->invoke_function(loggers, vlog_cb, &data);
 		va_end(data.args);
 	}
 
diff --git a/src/libcharon/config/backend_manager.c b/src/libcharon/config/backend_manager.c
index 79f1d9f..4f154df 100644
--- a/src/libcharon/config/backend_manager.c
+++ b/src/libcharon/config/backend_manager.c
@@ -265,20 +265,24 @@ static void peer_enum_destroy(peer_data_t *data)
 	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)
+CALLBACK(peer_enum_filter, bool,
+	linked_list_t *configs, enumerator_t *orig, va_list args)
 {
-	*out = (*in)->cfg;
-	return TRUE;
+	match_entry_t *entry;
+	peer_cfg_t **out;
+
+	VA_ARGS_VGET(args, out);
+
+	if (orig->enumerate(orig, &entry))
+	{
+		*out = entry->cfg;
+		return TRUE;
+	}
+	return FALSE;
 }
 
-/**
- * Clean up temporary config list
- */
-static void peer_enum_filter_destroy(linked_list_t *configs)
+CALLBACK(peer_enum_filter_destroy, void,
+	linked_list_t *configs)
 {
 	match_entry_t *entry;
 
@@ -379,8 +383,8 @@ METHOD(backend_manager_t, create_peer_cfg_enumerator, enumerator_t*,
 	helper->destroy(helper);
 
 	return enumerator_create_filter(configs->create_enumerator(configs),
-									(void*)peer_enum_filter, configs,
-									(void*)peer_enum_filter_destroy);
+									peer_enum_filter, configs,
+									peer_enum_filter_destroy);
 }
 
 METHOD(backend_manager_t, get_peer_cfg_by_name, peer_cfg_t*,
diff --git a/src/libcharon/config/child_cfg.c b/src/libcharon/config/child_cfg.c
index 3c6dd51..ec2a124 100644
--- a/src/libcharon/config/child_cfg.c
+++ b/src/libcharon/config/child_cfg.c
@@ -1,6 +1,6 @@
 /*
+ * Copyright (C) 2008-2017 Tobias Brunner
  * Copyright (C) 2016 Andreas Steffen
- * Copyright (C) 2008-2016 Tobias Brunner
  * Copyright (C) 2005-2007 Martin Willi
  * Copyright (C) 2005 Jan Hutter
  * HSR Hochschule fuer Technik Rapperswil
@@ -54,6 +54,11 @@ struct private_child_cfg_t {
 	char *name;
 
 	/**
+	 * Options
+	 */
+	child_cfg_option_t options;
+
+	/**
 	 * list for all proposals
 	 */
 	linked_list_t *proposals;
@@ -74,11 +79,6 @@ struct private_child_cfg_t {
 	char *updown;
 
 	/**
-	 * allow host access
-	 */
-	bool hostaccess;
-
-	/**
 	 * Mode to propose for a initiated CHILD: tunnel/transport
 	 */
 	ipsec_mode_t mode;
@@ -104,11 +104,6 @@ struct private_child_cfg_t {
 	lifetime_cfg_t lifetime;
 
 	/**
-	 * enable IPComp
-	 */
-	bool use_ipcomp;
-
-	/**
 	 * Inactivity timeout
 	 */
 	uint32_t inactivity;
@@ -144,21 +139,6 @@ struct private_child_cfg_t {
 	char *interface;
 
 	/**
-	 * set up IPsec transport SA in MIPv6 proxy mode
-	 */
-	bool proxy_mode;
-
-	/**
-	 * enable installation and removal of kernel IPsec policies
-	 */
-	bool install_policy;
-
-	/**
-	 * Install outbound FWD policies
-	 */
-	bool fwd_out_policy;
-
-	/**
 	 * anti-replay window size
 	 */
 	uint32_t replay_window;
@@ -170,6 +150,12 @@ METHOD(child_cfg_t, get_name, char*,
 	return this->name;
 }
 
+METHOD(child_cfg_t, has_option, bool,
+	private_child_cfg_t *this, child_cfg_option_t option)
+{
+	return this->options & option;
+}
+
 METHOD(child_cfg_t, add_proposal, void,
 	private_child_cfg_t *this, proposal_t *proposal)
 {
@@ -179,8 +165,12 @@ METHOD(child_cfg_t, add_proposal, void,
 	}
 }
 
-static bool match_proposal(proposal_t *item, proposal_t *proposal)
+CALLBACK(match_proposal, bool,
+	proposal_t *item, va_list args)
 {
+	proposal_t *proposal;
+
+	VA_ARGS_VGET(args, proposal);
 	return item->equals(item, proposal);
 }
 
@@ -199,8 +189,7 @@ METHOD(child_cfg_t, get_proposals, linked_list_t*,
 		{
 			current->strip_dh(current, MODP_NONE);
 		}
-		if (proposals->find_first(proposals, (linked_list_match_t)match_proposal,
-								  NULL, current) == SUCCESS)
+		if (proposals->find_first(proposals, match_proposal, NULL, current))
 		{
 			current->destroy(current);
 			continue;
@@ -311,8 +300,9 @@ METHOD(child_cfg_t, get_traffic_selectors, linked_list_t*,
 	{
 		if (hosts && hosts->get_count(hosts))
 		{	/* set hosts if TS is dynamic or as initiator in transport mode */
-			bool dynamic = ts1->is_dynamic(ts1);
-			if (dynamic || (this->mode == MODE_TRANSPORT && !this->proxy_mode &&
+			bool dynamic = ts1->is_dynamic(ts1),
+				 proxy_mode = has_option(this, OPT_PROXY_MODE);
+			if (dynamic || (this->mode == MODE_TRANSPORT && !proxy_mode &&
 							!supplied))
 			{
 				e2 = hosts->create_enumerator(hosts);
@@ -428,12 +418,6 @@ METHOD(child_cfg_t, get_updown, char*,
 	return this->updown;
 }
 
-METHOD(child_cfg_t, get_hostaccess, bool,
-	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
@@ -508,12 +492,6 @@ METHOD(child_cfg_t, get_dh_group, diffie_hellman_group_t,
 	return dh_group;
 }
 
-METHOD(child_cfg_t, use_ipcomp, bool,
-	private_child_cfg_t *this)
-{
-	return this->use_ipcomp;
-}
-
 METHOD(child_cfg_t, get_inactivity, uint32_t,
 	private_child_cfg_t *this)
 {
@@ -562,24 +540,6 @@ METHOD(child_cfg_t, set_replay_window, void,
 	this->replay_window = replay_window;
 }
 
-METHOD(child_cfg_t, use_proxy_mode, bool,
-	private_child_cfg_t *this)
-{
-	return this->proxy_mode;
-}
-
-METHOD(child_cfg_t, install_policy, bool,
-	private_child_cfg_t *this)
-{
-	return this->install_policy;
-}
-
-METHOD(child_cfg_t, install_fwd_out_policy, bool,
-	private_child_cfg_t *this)
-{
-	return this->fwd_out_policy;
-}
-
 #define LT_PART_EQUALS(a, b) ({ a.life == b.life && a.rekey == b.rekey && a.jitter == b.jitter; })
 #define LIFETIME_EQUALS(a, b) ({ LT_PART_EQUALS(a.time, b.time) && LT_PART_EQUALS(a.bytes, b.bytes) && LT_PART_EQUALS(a.packets, b.packets); })
 
@@ -611,13 +571,12 @@ METHOD(child_cfg_t, equals, bool,
 	{
 		return FALSE;
 	}
-	return this->hostaccess == other->hostaccess &&
+	return this->options == other->options &&
 		this->mode == other->mode &&
 		this->start_action == other->start_action &&
 		this->dpd_action == other->dpd_action &&
 		this->close_action == other->close_action &&
 		LIFETIME_EQUALS(this->lifetime, other->lifetime) &&
-		this->use_ipcomp == other->use_ipcomp &&
 		this->inactivity == other->inactivity &&
 		this->reqid == other->reqid &&
 		this->mark_in.value == other->mark_in.value &&
@@ -627,9 +586,6 @@ METHOD(child_cfg_t, equals, bool,
 		this->tfc == other->tfc &&
 		this->manual_prio == other->manual_prio &&
 		this->replay_window == other->replay_window &&
-		this->proxy_mode == other->proxy_mode &&
-		this->install_policy == other->install_policy &&
-		this->fwd_out_policy == other->fwd_out_policy &&
 		streq(this->updown, other->updown) &&
 		streq(this->interface, other->interface);
 }
@@ -672,14 +628,12 @@ child_cfg_t *child_cfg_create(char *name, child_cfg_create_t *data)
 			.get_proposals = _get_proposals,
 			.select_proposal = _select_proposal,
 			.get_updown = _get_updown,
-			.get_hostaccess = _get_hostaccess,
 			.get_mode = _get_mode,
 			.get_start_action = _get_start_action,
 			.get_dpd_action = _get_dpd_action,
 			.get_close_action = _get_close_action,
 			.get_lifetime = _get_lifetime,
 			.get_dh_group = _get_dh_group,
-			.use_ipcomp = _use_ipcomp,
 			.get_inactivity = _get_inactivity,
 			.get_reqid = _get_reqid,
 			.get_mark = _get_mark,
@@ -688,19 +642,16 @@ child_cfg_t *child_cfg_create(char *name, child_cfg_create_t *data)
 			.get_interface = _get_interface,
 			.get_replay_window = _get_replay_window,
 			.set_replay_window = _set_replay_window,
-			.use_proxy_mode = _use_proxy_mode,
-			.install_policy = _install_policy,
-			.install_fwd_out_policy = _install_fwd_out_policy,
+			.has_option = _has_option,
 			.equals = _equals,
 			.get_ref = _get_ref,
 			.destroy = _destroy,
 		},
 		.name = strdup(name),
+		.options = data->options,
 		.updown = strdupnull(data->updown),
-		.hostaccess = data->hostaccess,
 		.reqid = data->reqid,
 		.mode = data->mode,
-		.proxy_mode = data->proxy_mode,
 		.start_action = data->start_action,
 		.dpd_action = data->dpd_action,
 		.close_action = data->close_action,
@@ -708,12 +659,9 @@ child_cfg_t *child_cfg_create(char *name, child_cfg_create_t *data)
 		.mark_out = data->mark_out,
 		.lifetime = data->lifetime,
 		.inactivity = data->inactivity,
-		.use_ipcomp = data->ipcomp,
 		.tfc = data->tfc,
 		.manual_prio = data->priority,
 		.interface = strdupnull(data->interface),
-		.install_policy = !data->suppress_policies,
-		.fwd_out_policy = data->fwd_out_policies,
 		.refcount = 1,
 		.proposals = linked_list_create(),
 		.my_ts = linked_list_create(),
diff --git a/src/libcharon/config/child_cfg.h b/src/libcharon/config/child_cfg.h
index b85bfd9..a102c45 100644
--- a/src/libcharon/config/child_cfg.h
+++ b/src/libcharon/config/child_cfg.h
@@ -1,6 +1,6 @@
 /*
+ * Copyright (C) 2008-2017 Tobias Brunner
  * Copyright (C) 2016 Andreas Steffen
- * Copyright (C) 2008-2016 Tobias Brunner
  * Copyright (C) 2005-2007 Martin Willi
  * Copyright (C) 2005 Jan Hutter
  * HSR Hochschule fuer Technik Rapperswil
@@ -25,6 +25,7 @@
 #define CHILD_CFG_H_
 
 typedef enum action_t action_t;
+typedef enum child_cfg_option_t child_cfg_option_t;
 typedef struct child_cfg_t child_cfg_t;
 typedef struct child_cfg_create_t child_cfg_create_t;
 
@@ -147,13 +148,6 @@ struct child_cfg_t {
 	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
@@ -203,14 +197,6 @@ struct child_cfg_t {
 	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
@@ -263,33 +249,17 @@ struct child_cfg_t {
 	/**
 	 * Set anti-replay window size
 	 *
-	 * @param window		anti-replay window size
+	 * @param window        anti-replay window size
 	 */
 	void (*set_replay_window)(child_cfg_t *this, uint32_t window);
 
 	/**
-	 * 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);
-
-	/**
-	 * Check whether outbound FWD IPsec policies should be installed.
+	 * Check if an option flag is set.
 	 *
-	 * @return				TRUE, if outbound FWD policies should be installed
-	 *						FALSE, otherwise
+	 * @param option		option flag to check
+	 * @return				TRUE if option flag set, FALSE otherwise
 	 */
-	bool (*install_fwd_out_policy)(child_cfg_t *this);
+	bool (*has_option)(child_cfg_t *this, child_cfg_option_t option);
 
 	/**
 	 * Check if two child_cfg objects are equal.
@@ -315,11 +285,39 @@ struct child_cfg_t {
 	void (*destroy) (child_cfg_t *this);
 };
 
+/**
+ * Option flags that may be set on a child_cfg_t object
+ */
+enum child_cfg_option_t {
+
+	/** Use IPsec transport proxy mode */
+	OPT_PROXY_MODE = (1<<0),
+
+	/** Use IPComp, if peer supports it */
+	OPT_IPCOMP = (1<<1),
+
+	/** Allow access to the local host */
+	OPT_HOSTACCESS = (1<<2),
+
+	/** Don't install any IPsec policies */
+	OPT_NO_POLICIES = (1<<3),
+
+	/** Install outbound FWD IPsec policies to bypass drop policies */
+	OPT_FWD_OUT_POLICIES = (1<<4),
+
+	/** Enable hardware offload, if supported by the IPsec backend */
+	OPT_HW_OFFLOAD = (1<<5),
+
+	/** Force 96-bit truncation for SHA-256 */
+	OPT_SHA256_96 = (1<<6),
+};
 
 /**
  * Data passed to the constructor of a child_cfg_t object.
  */
 struct child_cfg_create_t {
+	/** Options set for CHILD_SA */
+	child_cfg_option_t options;
 	/** Specific reqid to use for CHILD_SA, 0 for auto assignment */
 	uint32_t reqid;
 	/** Optional inbound mark */
@@ -328,10 +326,6 @@ struct child_cfg_create_t {
 	mark_t mark_out;
 	/** Mode to propose for CHILD_SA */
 	ipsec_mode_t mode;
-	/** Use IPsec transport proxy mode */
-	bool proxy_mode;
-	/** Use IPComp, if peer supports it */
-	bool ipcomp;
 	/** TFC padding size, 0 to disable, -1 to pad to PMTU */
 	uint32_t tfc;
 	/** Optional manually-set IPsec policy priority */
@@ -350,12 +344,6 @@ struct child_cfg_create_t {
 	action_t close_action;
 	/** updown script to execute on up/down event (cloned) */
 	char *updown;
-	/** TRUE to allow access to the local host */
-	bool hostaccess;
-	/** Don't install IPsec policies */
-	bool suppress_policies;
-	/** Install outbound FWD IPsec policies to bypass drop policies */
-	bool fwd_out_policies;
 };
 
 /**
diff --git a/src/libcharon/config/ike_cfg.c b/src/libcharon/config/ike_cfg.c
index 480dd37..9330078 100644
--- a/src/libcharon/config/ike_cfg.c
+++ b/src/libcharon/config/ike_cfg.c
@@ -224,12 +224,12 @@ static u_int match(linked_list_t *hosts, linked_list_t *ranges, host_t *cand)
 			if (ts->to_subnet(ts, &host, &mask))
 			{
 				quality = max(quality, mask + 1);
-				host->destroy(host);
 			}
 			else
 			{
 				quality = max(quality, 1);
 			}
+			host->destroy(host);
 		}
 	}
 	enumerator->destroy(enumerator);
diff --git a/src/libcharon/config/ike_cfg.h b/src/libcharon/config/ike_cfg.h
index 4d37264..034996f 100644
--- a/src/libcharon/config/ike_cfg.h
+++ b/src/libcharon/config/ike_cfg.h
@@ -47,14 +47,16 @@ enum ike_version_t {
 };
 
 /**
- * Proprietary IKEv1 fragmentation
+ * Proprietary IKEv1 fragmentation and IKEv2 fragmentation
  */
 enum fragmentation_t {
 	/** disable fragmentation */
 	FRAGMENTATION_NO,
-	/** enable fragmentation if supported by peer */
+	/** announce support, but don't send any fragments */
+	FRAGMENTATION_ACCEPT,
+	/** enable fragmentation, if supported by peer */
 	FRAGMENTATION_YES,
-	/** force use of fragmentation (even for the first message) */
+	/** force use of fragmentation (even for the first message for IKEv1) */
 	FRAGMENTATION_FORCE,
 };
 
diff --git a/src/libcharon/config/peer_cfg.c b/src/libcharon/config/peer_cfg.c
index 5d7ab07..fcdd6fd 100644
--- a/src/libcharon/config/peer_cfg.c
+++ b/src/libcharon/config/peer_cfg.c
@@ -209,9 +209,12 @@ typedef struct {
 } child_cfgs_replace_enumerator_t;
 
 METHOD(enumerator_t, child_cfgs_replace_enumerate, bool,
-	child_cfgs_replace_enumerator_t *this, child_cfg_t **chd, bool *added)
+	child_cfgs_replace_enumerator_t *this, va_list args)
 {
-	child_cfg_t *child_cfg;
+	child_cfg_t *child_cfg, **chd;
+	bool *added;
+
+	VA_ARGS_VGET(args, chd, added);
 
 	if (!this->wrapped)
 	{
@@ -303,8 +306,9 @@ METHOD(peer_cfg_t, replace_child_cfgs, enumerator_t*,
 
 	INIT(enumerator,
 		.public = {
-			.enumerate = (void*)_child_cfgs_replace_enumerate,
-			.destroy = (void*)_child_cfgs_replace_enumerator_destroy,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _child_cfgs_replace_enumerate,
+			.destroy = _child_cfgs_replace_enumerator_destroy,
 		},
 		.removed = removed,
 		.added = added,
@@ -336,8 +340,11 @@ METHOD(enumerator_t, child_cfg_enumerator_destroy, void,
 }
 
 METHOD(enumerator_t, child_cfg_enumerate, bool,
-	child_cfg_enumerator_t *this, child_cfg_t **chd)
+	child_cfg_enumerator_t *this, va_list args)
 {
+	child_cfg_t **chd;
+
+	VA_ARGS_VGET(args, chd);
 	return this->wrapped->enumerate(this->wrapped, chd);
 }
 
@@ -348,8 +355,9 @@ METHOD(peer_cfg_t, create_child_cfg_enumerator, enumerator_t*,
 
 	INIT(enumerator,
 		.public = {
-			.enumerate = (void*)_child_cfg_enumerate,
-			.destroy = (void*)_child_cfg_enumerator_destroy,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _child_cfg_enumerate,
+			.destroy = _child_cfg_enumerator_destroy,
 		},
 		.mutex = this->mutex,
 		.wrapped = this->child_cfgs->create_enumerator(this->child_cfgs),
diff --git a/src/libcharon/config/proposal.c b/src/libcharon/config/proposal.c
index a2dc113..6c71f78 100644
--- a/src/libcharon/config/proposal.c
+++ b/src/libcharon/config/proposal.c
@@ -94,27 +94,31 @@ METHOD(proposal_t, add_algorithm, void,
 	array_insert(this->transforms, ARRAY_TAIL, &entry);
 }
 
-/**
- * filter function for peer configs
- */
-static bool alg_filter(uintptr_t type, entry_t **in, uint16_t *alg,
-					   void **unused, uint16_t *key_size)
+CALLBACK(alg_filter, bool,
+	uintptr_t type, enumerator_t *orig, va_list args)
 {
-	entry_t *entry = *in;
+	entry_t *entry;
+	uint16_t *alg, *key_size;
 
-	if (entry->type != type)
-	{
-		return FALSE;
-	}
-	if (alg)
-	{
-		*alg = entry->alg;
-	}
-	if (key_size)
+	VA_ARGS_VGET(args, alg, key_size);
+
+	while (orig->enumerate(orig, &entry))
 	{
-		*key_size = entry->key_size;
+		if (entry->type != type)
+		{
+			continue;
+		}
+		if (alg)
+		{
+			*alg = entry->alg;
+		}
+		if (key_size)
+		{
+			*key_size = entry->key_size;
+		}
+		return TRUE;
 	}
-	return TRUE;
+	return FALSE;
 }
 
 METHOD(proposal_t, create_enumerator, enumerator_t*,
@@ -122,7 +126,7 @@ METHOD(proposal_t, create_enumerator, enumerator_t*,
 {
 	return enumerator_create_filter(
 						array_create_enumerator(this->transforms),
-						(void*)alg_filter, (void*)(uintptr_t)type, NULL);
+						alg_filter, (void*)(uintptr_t)type, NULL);
 }
 
 METHOD(proposal_t, get_algorithm, bool,
diff --git a/src/libcharon/daemon.c b/src/libcharon/daemon.c
index eadc10a..7c9f83d 100644
--- a/src/libcharon/daemon.c
+++ b/src/libcharon/daemon.c
@@ -118,6 +118,13 @@ struct private_daemon_t {
 };
 
 /**
+ * Register plugins if built statically
+ */
+#ifdef STATIC_PLUGIN_CONSTRUCTORS
+#include "plugin_constructors.c"
+#endif
+
+/**
  * One and only instance of the daemon.
  */
 daemon_t *charon;
@@ -275,13 +282,14 @@ static void logger_entry_unregister_destroy(logger_entry_t *this)
 	logger_entry_destroy(this);
 }
 
-/**
- * Match a logger entry by target and whether it is a file or syslog logger
- */
-static bool logger_entry_match(logger_entry_t *this, char *target,
-							   logger_type_t *type)
+CALLBACK(logger_entry_match, bool,
+	logger_entry_t *this, va_list args)
 {
-	return this->type == *type && streq(this->target, target);
+	logger_type_t type;
+	char *target;
+
+	VA_ARGS_VGET(args, target, type);
+	return this->type == type && streq(this->target, target);
 }
 
 /**
@@ -343,8 +351,8 @@ static logger_entry_t *get_logger_entry(char *target, logger_type_t type,
 {
 	logger_entry_t *entry;
 
-	if (existing->find_first(existing, (void*)logger_entry_match,
-							(void**)&entry, target, &type) != SUCCESS)
+	if (!existing->find_first(existing, logger_entry_match, (void**)&entry,
+							  target, type))
 	{
 		INIT(entry,
 			.target = strdup(target),
diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c
index 50dab9e..6d850aa 100644
--- a/src/libcharon/encoding/message.c
+++ b/src/libcharon/encoding/message.c
@@ -554,10 +554,10 @@ static payload_order_t aggressive_i_order[] = {
 	{PLV1_CERTREQ,					0},
 	{PLV1_NOTIFY,					0},
 	{PLV1_VENDOR_ID,				0},
+	{PLV1_HASH,						0},
 	{PLV1_NAT_D,					0},
 	{PLV1_NAT_D_DRAFT_00_03,		0},
 	{PLV1_SIGNATURE,				0},
-	{PLV1_HASH,						0},
 	{PLV1_FRAGMENT,					0},
 };
 
diff --git a/src/libcharon/encoding/payloads/certreq_payload.c b/src/libcharon/encoding/payloads/certreq_payload.c
index 09bfa24..643fbc4 100644
--- a/src/libcharon/encoding/payloads/certreq_payload.c
+++ b/src/libcharon/encoding/payloads/certreq_payload.c
@@ -190,8 +190,12 @@ struct keyid_enumerator_t  {
 };
 
 METHOD(enumerator_t, keyid_enumerate, bool,
-	keyid_enumerator_t *this, chunk_t *chunk)
+	keyid_enumerator_t *this, va_list args)
 {
+	chunk_t *chunk;
+
+	VA_ARGS_VGET(args, chunk);
+
 	if (this->pos == NULL)
 	{
 		this->pos = this->full.ptr;
@@ -224,7 +228,8 @@ METHOD(certreq_payload_t, create_keyid_enumerator, enumerator_t*,
 	}
 	INIT(enumerator,
 		.public = {
-			.enumerate = (void*)_keyid_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _keyid_enumerate,
 			.destroy = (void*)free,
 		},
 		.full = this->data,
diff --git a/src/libcharon/encoding/payloads/delete_payload.c b/src/libcharon/encoding/payloads/delete_payload.c
index 584e6f2..3634cd3 100644
--- a/src/libcharon/encoding/payloads/delete_payload.c
+++ b/src/libcharon/encoding/payloads/delete_payload.c
@@ -306,8 +306,12 @@ typedef struct {
 } spi_enumerator_t;
 
 METHOD(enumerator_t, spis_enumerate, bool,
-	spi_enumerator_t *this, uint32_t *spi)
+	spi_enumerator_t *this, va_list args)
 {
+	uint32_t *spi;
+
+	VA_ARGS_VGET(args, spi);
+
 	if (this->spis.len >= sizeof(*spi))
 	{
 		memcpy(spi, this->spis.ptr, sizeof(*spi));
@@ -328,7 +332,8 @@ METHOD(delete_payload_t, create_spi_enumerator, enumerator_t*,
 	}
 	INIT(e,
 		.public = {
-			.enumerate = (void*)_spis_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _spis_enumerate,
 			.destroy = (void*)free,
 		},
 		.spis = this->spis,
diff --git a/src/libcharon/encoding/payloads/eap_payload.c b/src/libcharon/encoding/payloads/eap_payload.c
index 8c3fc59..923135d 100644
--- a/src/libcharon/encoding/payloads/eap_payload.c
+++ b/src/libcharon/encoding/payloads/eap_payload.c
@@ -270,8 +270,12 @@ typedef struct {
 } type_enumerator_t;
 
 METHOD(enumerator_t, enumerate_types, bool,
-	type_enumerator_t *this, eap_type_t *type, uint32_t *vendor)
+	type_enumerator_t *this, va_list args)
 {
+	eap_type_t *type;
+	uint32_t *vendor;
+
+	VA_ARGS_VGET(args, type, vendor);
 	this->offset = extract_type(this->payload, this->offset, type, vendor);
 	return this->offset;
 }
@@ -289,7 +293,8 @@ METHOD(eap_payload_t, get_types, enumerator_t*,
 	{
 		INIT(enumerator,
 			.public = {
-				.enumerate = (void*)_enumerate_types,
+				.enumerate = enumerator_enumerate_default,
+				.venumerate = _enumerate_types,
 				.destroy = (void*)free,
 			},
 			.payload = this,
diff --git a/src/libcharon/kernel/kernel_interface.c b/src/libcharon/kernel/kernel_interface.c
index ea5af9e..3d736b2 100644
--- a/src/libcharon/kernel/kernel_interface.c
+++ b/src/libcharon/kernel/kernel_interface.c
@@ -632,21 +632,18 @@ METHOD(kernel_interface_t, enable_udp_decap, bool,
 METHOD(kernel_interface_t, is_interface_usable, bool,
 	private_kernel_interface_t *this, const char *iface)
 {
-	status_t expected;
-
 	if (!this->ifaces_filter)
 	{
 		return TRUE;
 	}
-	expected = this->ifaces_exclude ? NOT_FOUND : SUCCESS;
-	return this->ifaces_filter->find_first(this->ifaces_filter, (void*)streq,
-										   NULL, iface) == expected;
+	return this->ifaces_filter->find_first(this->ifaces_filter,
+					linked_list_match_str, NULL, iface) != this->ifaces_exclude;
 }
 
 METHOD(kernel_interface_t, all_interfaces_usable, bool,
 	private_kernel_interface_t *this)
 {
-	return this->ifaces_filter == NULL;
+	return !this->ifaces_filter;
 }
 
 METHOD(kernel_interface_t, get_address_by_ts, status_t,
diff --git a/src/libcharon/kernel/kernel_ipsec.h b/src/libcharon/kernel/kernel_ipsec.h
index 0ad5660..6fafeb7 100644
--- a/src/libcharon/kernel/kernel_ipsec.h
+++ b/src/libcharon/kernel/kernel_ipsec.h
@@ -91,6 +91,8 @@ struct kernel_ipsec_add_sa_t {
 	uint16_t cpi;
 	/** TRUE to enable UDP encapsulation for NAT traversal */
 	bool encap;
+	/** TRUE to enable hardware offloading if available */
+	bool hw_offload;
 	/** TRUE to use Extended Sequence Numbers */
 	bool esn;
 	/** TRUE if initiator of the exchange creating the SA */
diff --git a/src/libcharon/network/receiver.c b/src/libcharon/network/receiver.c
index 1bf93ad..8fb4828 100644
--- a/src/libcharon/network/receiver.c
+++ b/src/libcharon/network/receiver.c
@@ -321,18 +321,16 @@ static bool cookie_required(private_receiver_t *this,
  */
 static bool drop_ike_sa_init(private_receiver_t *this, message_t *message)
 {
-	u_int half_open, half_open_r;
+	u_int half_open;
 	uint32_t now;
 
 	now = time_monotonic(NULL);
 	half_open = charon->ike_sa_manager->get_half_open_count(
-										charon->ike_sa_manager, NULL, FALSE);
-	half_open_r = charon->ike_sa_manager->get_half_open_count(
 										charon->ike_sa_manager, NULL, TRUE);
 
 	/* check for cookies in IKEv2 */
 	if (message->get_major_version(message) == IKEV2_MAJOR_VERSION &&
-		cookie_required(this, half_open_r, now) && !check_cookie(this, message))
+		cookie_required(this, half_open, now) && !check_cookie(this, message))
 	{
 		chunk_t cookie;
 
diff --git a/src/libcharon/plugins/addrblock/Makefile.in b/src/libcharon/plugins/addrblock/Makefile.in
index f5dfc14..60fd19b 100644
--- a/src/libcharon/plugins/addrblock/Makefile.in
+++ b/src/libcharon/plugins/addrblock/Makefile.in
@@ -358,6 +358,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/addrblock/addrblock_validator.c b/src/libcharon/plugins/addrblock/addrblock_validator.c
index d16a117..78e377c 100644
--- a/src/libcharon/plugins/addrblock/addrblock_validator.c
+++ b/src/libcharon/plugins/addrblock/addrblock_validator.c
@@ -56,12 +56,12 @@ static bool check_addrblock(private_addrblock_validator_t *this,
 	}
 	if (!subject_const)
 	{
-		DBG1(DBG_CFG, "subject certficate lacks ipAddrBlocks extension");
+		DBG1(DBG_CFG, "subject certificate lacks ipAddrBlocks extension");
 		return !this->strict;
 	}
 	if (!issuer_const)
 	{
-		DBG1(DBG_CFG, "issuer certficate lacks ipAddrBlocks extension");
+		DBG1(DBG_CFG, "issuer certificate lacks ipAddrBlocks extension");
 		return FALSE;
 	}
 	subject_enumerator = subject->create_ipAddrBlock_enumerator(subject);
diff --git a/src/libcharon/plugins/android_dns/Makefile.in b/src/libcharon/plugins/android_dns/Makefile.in
index d79c753..0533d81 100644
--- a/src/libcharon/plugins/android_dns/Makefile.in
+++ b/src/libcharon/plugins/android_dns/Makefile.in
@@ -358,6 +358,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/android_dns/android_dns_handler.c b/src/libcharon/plugins/android_dns/android_dns_handler.c
index 160a145..68bbaec 100644
--- a/src/libcharon/plugins/android_dns/android_dns_handler.c
+++ b/src/libcharon/plugins/android_dns/android_dns_handler.c
@@ -182,12 +182,15 @@ METHOD(attribute_handler_t, release, void,
 }
 
 METHOD(enumerator_t, enumerate_dns, bool,
-	enumerator_t *this, configuration_attribute_type_t *type, chunk_t *data)
+	enumerator_t *this, va_list args)
 {
+	configuration_attribute_type_t *type;
+	chunk_t *data;
+
+	VA_ARGS_VGET(args, type, data);
 	*type = INTERNAL_IP4_DNS;
 	*data = chunk_empty;
-	/* stop enumeration */
-	this->enumerate = (void*)return_false;
+	this->venumerate = return_false;
 	return TRUE;
 }
 
@@ -198,7 +201,8 @@ METHOD(attribute_handler_t, create_attribute_enumerator, enumerator_t *,
 	enumerator_t *enumerator;
 
 	INIT(enumerator,
-		.enumerate = (void*)_enumerate_dns,
+		.enumerate = enumerator_enumerate_default,
+		.venumerate = _enumerate_dns,
 		.destroy = (void*)free,
 	);
 	return enumerator;
diff --git a/src/libcharon/plugins/android_log/Makefile.am b/src/libcharon/plugins/android_log/Makefile.am
index 9f82f6e..4f062ee 100644
--- a/src/libcharon/plugins/android_log/Makefile.am
+++ b/src/libcharon/plugins/android_log/Makefile.am
@@ -16,3 +16,4 @@ libstrongswan_android_log_la_SOURCES = \
 	android_log_logger.c android_log_logger.h
 
 libstrongswan_android_log_la_LDFLAGS = -module -avoid-version
+libstrongswan_android_log_la_LIBADD  = -llog
diff --git a/src/libcharon/plugins/android_log/Makefile.in b/src/libcharon/plugins/android_log/Makefile.in
index 65cdcff..bc402ef 100644
--- a/src/libcharon/plugins/android_log/Makefile.in
+++ b/src/libcharon/plugins/android_log/Makefile.in
@@ -136,7 +136,7 @@ am__uninstall_files_from_dir = { \
   }
 am__installdirs = "$(DESTDIR)$(plugindir)"
 LTLIBRARIES = $(noinst_LTLIBRARIES) $(plugin_LTLIBRARIES)
-libstrongswan_android_log_la_LIBADD =
+libstrongswan_android_log_la_DEPENDENCIES =
 am_libstrongswan_android_log_la_OBJECTS = android_log_plugin.lo \
 	android_log_logger.lo
 libstrongswan_android_log_la_OBJECTS =  \
@@ -358,6 +358,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
@@ -458,6 +460,7 @@ libstrongswan_android_log_la_SOURCES = \
 	android_log_logger.c android_log_logger.h
 
 libstrongswan_android_log_la_LDFLAGS = -module -avoid-version
+libstrongswan_android_log_la_LIBADD = -llog
 all: all-am
 
 .SUFFIXES:
diff --git a/src/libcharon/plugins/attr/Makefile.in b/src/libcharon/plugins/attr/Makefile.in
index 217a42a..9fe4d94 100644
--- a/src/libcharon/plugins/attr/Makefile.in
+++ b/src/libcharon/plugins/attr/Makefile.in
@@ -355,6 +355,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -377,6 +378,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/attr/attr_provider.c b/src/libcharon/plugins/attr/attr_provider.c
index f4c1436..3310f79 100644
--- a/src/libcharon/plugins/attr/attr_provider.c
+++ b/src/libcharon/plugins/attr/attr_provider.c
@@ -75,17 +75,23 @@ typedef struct {
 	ike_version_t ike;
 } enumerator_data_t;
 
-/**
- * convert enumerator value from attribute_entry
- */
-static bool attr_enum_filter(enumerator_data_t *data, attribute_entry_t **in,
-			configuration_attribute_type_t *type, void* none, chunk_t *value)
+CALLBACK(attr_enum_filter, bool,
+	enumerator_data_t *data, enumerator_t *orig, va_list args)
 {
-	if ((*in)->ike == IKE_ANY || (*in)->ike == data->ike)
+	configuration_attribute_type_t *type;
+	attribute_entry_t *entry;
+	chunk_t *value;
+
+	VA_ARGS_VGET(args, type, value);
+
+	while (orig->enumerate(orig, &entry))
 	{
-		*type = (*in)->type;
-		*value = (*in)->value;
-		return TRUE;
+		if (entry->ike == IKE_ANY || entry->ike == data->ike)
+		{
+			*type = entry->type;
+			*value = entry->value;
+			return TRUE;
+		}
 	}
 	return FALSE;
 }
@@ -112,7 +118,7 @@ METHOD(attribute_provider_t, create_attribute_enumerator, enumerator_t*,
 		this->lock->read_lock(this->lock);
 		return enumerator_create_filter(
 				this->attributes->create_enumerator(this->attributes),
-				(void*)attr_enum_filter, data, attr_enum_destroy);
+				attr_enum_filter, data, attr_enum_destroy);
 	}
 	return enumerator_create_empty();
 }
diff --git a/src/libcharon/plugins/attr_sql/Makefile.in b/src/libcharon/plugins/attr_sql/Makefile.in
index 668e23f..b3ddf69 100644
--- a/src/libcharon/plugins/attr_sql/Makefile.in
+++ b/src/libcharon/plugins/attr_sql/Makefile.in
@@ -358,6 +358,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/attr_sql/attr_sql_provider.c b/src/libcharon/plugins/attr_sql/attr_sql_provider.c
index c241070..33d9f99 100644
--- a/src/libcharon/plugins/attr_sql/attr_sql_provider.c
+++ b/src/libcharon/plugins/attr_sql/attr_sql_provider.c
@@ -200,7 +200,6 @@ static host_t* get_lease(private_attr_sql_provider_t *this, char *name,
 				"SELECT id, address FROM addresses "
 				"WHERE pool = ? AND identity = 0 LIMIT 1",
 				DB_UINT, pool, DB_UINT, DB_BLOB);
-
 		}
 
 		if (!e || !e->enumerate(e, &id, &address))
@@ -447,7 +446,6 @@ METHOD(attr_sql_provider_t, destroy, void,
 attr_sql_provider_t *attr_sql_provider_create(database_t *db)
 {
 	private_attr_sql_provider_t *this;
-	time_t now = time(NULL);
 
 	INIT(this,
 		.public = {
@@ -460,19 +458,25 @@ attr_sql_provider_t *attr_sql_provider_create(database_t *db)
 		},
 		.db = db,
 		.history = lib->settings->get_bool(lib->settings,
-							"%s.plugins.attr-sql.lease_history", TRUE, lib->ns),
+						"%s.plugins.attr-sql.lease_history", TRUE, lib->ns),
 	);
 
-	/* close any "online" leases in the case we crashed */
-	if (this->history)
+	if (lib->settings->get_bool(lib->settings,
+						"%s.plugins.attr-sql.crash_recovery", TRUE, lib->ns))
 	{
-		this->db->execute(this->db, NULL,
+		time_t now = time(NULL);
+
+		/* close any "online" leases in the case we crashed */
+		if (this->history)
+		{
+			this->db->execute(this->db, NULL,
 					"INSERT INTO leases (address, identity, acquired, released)"
 					" SELECT id, identity, acquired, ? FROM addresses "
 					" WHERE released = 0", DB_UINT, now);
-	}
-	this->db->execute(this->db, NULL,
+		}
+		this->db->execute(this->db, NULL,
 					  "UPDATE addresses SET released = ? WHERE released = 0",
 					  DB_UINT, now);
+	}
 	return &this->public;
 }
diff --git a/src/libcharon/plugins/bypass_lan/Makefile.in b/src/libcharon/plugins/bypass_lan/Makefile.in
index 9f1dc71..6c07948 100644
--- a/src/libcharon/plugins/bypass_lan/Makefile.in
+++ b/src/libcharon/plugins/bypass_lan/Makefile.in
@@ -358,6 +358,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/bypass_lan/bypass_lan_listener.c b/src/libcharon/plugins/bypass_lan/bypass_lan_listener.c
index e690028..644cff0 100644
--- a/src/libcharon/plugins/bypass_lan/bypass_lan_listener.c
+++ b/src/libcharon/plugins/bypass_lan/bypass_lan_listener.c
@@ -110,15 +110,12 @@ static bool policy_equals(bypass_policy_t *a, bypass_policy_t *b)
  */
 static bool consider_interface(private_bypass_lan_listener_t *this, char *iface)
 {
-	status_t expected;
-
 	if (!iface || !this->ifaces_filter)
 	{
 		return TRUE;
 	}
-	expected = this->ifaces_exclude ? NOT_FOUND : SUCCESS;
-	return this->ifaces_filter->find_first(this->ifaces_filter, (void*)streq,
-										   NULL, iface) == expected;
+	return this->ifaces_filter->find_first(this->ifaces_filter,
+					linked_list_match_str, NULL, iface) != this->ifaces_exclude;
 }
 
 /**
diff --git a/src/libcharon/plugins/certexpire/Makefile.in b/src/libcharon/plugins/certexpire/Makefile.in
index ffde2d7..acbd7a8 100644
--- a/src/libcharon/plugins/certexpire/Makefile.in
+++ b/src/libcharon/plugins/certexpire/Makefile.in
@@ -358,6 +358,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/connmark/Makefile.in b/src/libcharon/plugins/connmark/Makefile.in
index 140f1b6..55bc25a 100644
--- a/src/libcharon/plugins/connmark/Makefile.in
+++ b/src/libcharon/plugins/connmark/Makefile.in
@@ -359,6 +359,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -381,6 +382,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/coupling/Makefile.in b/src/libcharon/plugins/coupling/Makefile.in
index 3910e4e..6d6fe25 100644
--- a/src/libcharon/plugins/coupling/Makefile.in
+++ b/src/libcharon/plugins/coupling/Makefile.in
@@ -358,6 +358,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/dhcp/Makefile.in b/src/libcharon/plugins/dhcp/Makefile.in
index 6033c6e..d3f4ec8 100644
--- a/src/libcharon/plugins/dhcp/Makefile.in
+++ b/src/libcharon/plugins/dhcp/Makefile.in
@@ -356,6 +356,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -378,6 +379,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/dhcp/dhcp_provider.c b/src/libcharon/plugins/dhcp/dhcp_provider.c
index f0681b1..50ffbab 100644
--- a/src/libcharon/plugins/dhcp/dhcp_provider.c
+++ b/src/libcharon/plugins/dhcp/dhcp_provider.c
@@ -151,8 +151,7 @@ METHOD(attribute_provider_t, create_attribute_enumerator, enumerator_t*,
 	identification_t *id;
 	host_t *vip;
 
-	if (pools->find_first(pools, (linked_list_match_t)streq,
-						  NULL, "dhcp") != SUCCESS)
+	if (!pools->find_first(pools, linked_list_match_str, NULL, "dhcp"))
 	{
 		return NULL;
 	}
diff --git a/src/libcharon/plugins/dhcp/dhcp_socket.c b/src/libcharon/plugins/dhcp/dhcp_socket.c
index 807c682..42f8f1e 100644
--- a/src/libcharon/plugins/dhcp/dhcp_socket.c
+++ b/src/libcharon/plugins/dhcp/dhcp_socket.c
@@ -382,8 +382,7 @@ METHOD(dhcp_socket_t, enroll, dhcp_transaction_t*,
 	while (try <= DHCP_TRIES && discover(this, transaction))
 	{
 		if (!this->condvar->timed_wait(this->condvar, this->mutex, 1000 * try) &&
-			this->request->find_first(this->request, NULL,
-									  (void**)&transaction) == SUCCESS)
+			this->request->find_first(this->request, NULL, (void**)&transaction))
 		{
 			break;
 		}
diff --git a/src/libcharon/plugins/dhcp/dhcp_transaction.c b/src/libcharon/plugins/dhcp/dhcp_transaction.c
index 3ee88a6..8771179 100644
--- a/src/libcharon/plugins/dhcp/dhcp_transaction.c
+++ b/src/libcharon/plugins/dhcp/dhcp_transaction.c
@@ -114,16 +114,22 @@ METHOD(dhcp_transaction_t, add_attribute, void,
 	this->attributes->insert_last(this->attributes, entry);
 }
 
-/**
- * Filter function to map entries to type/data
- */
-static bool attribute_filter(void *null, attribute_entry_t **entry,
-							 configuration_attribute_type_t *type,
-							 void **dummy, chunk_t *data)
+CALLBACK(attribute_filter, bool,
+	void *null, enumerator_t *orig, va_list args)
 {
-	*type = (*entry)->type;
-	*data = (*entry)->data;
-	return TRUE;
+	configuration_attribute_type_t *type;
+	attribute_entry_t *entry;
+	chunk_t *data;
+
+	VA_ARGS_VGET(args, type, data);
+
+	if (orig->enumerate(orig, &entry))
+	{
+		*type = entry->type;
+		*data = entry->data;
+		return TRUE;
+	}
+	return FALSE;
 }
 
 METHOD(dhcp_transaction_t, create_attribute_enumerator, enumerator_t*,
@@ -131,7 +137,7 @@ METHOD(dhcp_transaction_t, create_attribute_enumerator, enumerator_t*,
 {
 	return enumerator_create_filter(
 						this->attributes->create_enumerator(this->attributes),
-						(void*)attribute_filter, NULL, NULL);
+						attribute_filter, NULL, NULL);
 }
 
 /**
diff --git a/src/libcharon/plugins/dnscert/Makefile.in b/src/libcharon/plugins/dnscert/Makefile.in
index cd66af8..3687f0c 100644
--- a/src/libcharon/plugins/dnscert/Makefile.in
+++ b/src/libcharon/plugins/dnscert/Makefile.in
@@ -358,6 +358,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/dnscert/dnscert_cred.c b/src/libcharon/plugins/dnscert/dnscert_cred.c
index d32794c..533bd5b 100644
--- a/src/libcharon/plugins/dnscert/dnscert_cred.c
+++ b/src/libcharon/plugins/dnscert/dnscert_cred.c
@@ -75,12 +75,15 @@ typedef struct {
 } cert_enumerator_t;
 
 METHOD(enumerator_t, cert_enumerator_enumerate, bool,
-	cert_enumerator_t *this, certificate_t **cert)
+	cert_enumerator_t *this, va_list args)
 {
+	certificate_t **cert;
 	dnscert_t *cur_crt;
 	rr_t *cur_rr;
 	chunk_t certificate;
 
+	VA_ARGS_VGET(args, cert);
+
 	/* Get the next supported CERT using the inner enumerator. */
 	while (this->inner->enumerate(this->inner, &cur_rr))
 	{
@@ -175,7 +178,8 @@ METHOD(credential_set_t, create_cert_enumerator, enumerator_t*,
 
 	INIT(e,
 		.public = {
-			.enumerate = (void*)_cert_enumerator_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _cert_enumerator_enumerate,
 			.destroy = _cert_enumerator_destroy,
 		},
 		.inner = response->get_rr_set(response)->create_rr_enumerator(
diff --git a/src/libcharon/plugins/duplicheck/Makefile.in b/src/libcharon/plugins/duplicheck/Makefile.in
index e4b60e6..69959d3 100644
--- a/src/libcharon/plugins/duplicheck/Makefile.in
+++ b/src/libcharon/plugins/duplicheck/Makefile.in
@@ -365,6 +365,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -387,6 +388,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/eap_aka/Makefile.in b/src/libcharon/plugins/eap_aka/Makefile.in
index 20c0ddb..5fff128 100644
--- a/src/libcharon/plugins/eap_aka/Makefile.in
+++ b/src/libcharon/plugins/eap_aka/Makefile.in
@@ -359,6 +359,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -381,6 +382,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/eap_aka_3gpp2/Makefile.in b/src/libcharon/plugins/eap_aka_3gpp2/Makefile.in
index f4fb8ec..4782255 100644
--- a/src/libcharon/plugins/eap_aka_3gpp2/Makefile.in
+++ b/src/libcharon/plugins/eap_aka_3gpp2/Makefile.in
@@ -360,6 +360,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -382,6 +383,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/eap_dynamic/Makefile.in b/src/libcharon/plugins/eap_dynamic/Makefile.in
index 2dbc05f..2591dee 100644
--- a/src/libcharon/plugins/eap_dynamic/Makefile.in
+++ b/src/libcharon/plugins/eap_dynamic/Makefile.in
@@ -358,6 +358,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/eap_dynamic/eap_dynamic.c b/src/libcharon/plugins/eap_dynamic/eap_dynamic.c
index 83ccd3a..204fb31 100644
--- a/src/libcharon/plugins/eap_dynamic/eap_dynamic.c
+++ b/src/libcharon/plugins/eap_dynamic/eap_dynamic.c
@@ -69,6 +69,15 @@ static bool entry_matches(eap_vendor_type_t *item, eap_vendor_type_t *other)
 	return item->type == other->type && item->vendor == other->vendor;
 }
 
+CALLBACK(entry_matches_cb, bool,
+	eap_vendor_type_t *item, va_list args)
+{
+	eap_vendor_type_t *other;
+
+	VA_ARGS_VGET(args, other);
+	return entry_matches(item, other);
+}
+
 /**
  * Load the given EAP method
  */
@@ -121,8 +130,7 @@ static void select_method(private_eap_dynamic_t *this)
 	{
 		if (inner)
 		{
-			if (inner->find_first(inner, (void*)entry_matches,
-								  NULL, entry) != SUCCESS)
+			if (!inner->find_first(inner, entry_matches_cb, NULL, entry))
 			{
 				if (entry->vendor)
 				{
diff --git a/src/libcharon/plugins/eap_gtc/Makefile.in b/src/libcharon/plugins/eap_gtc/Makefile.in
index 01d509e..08d8ef8 100644
--- a/src/libcharon/plugins/eap_gtc/Makefile.in
+++ b/src/libcharon/plugins/eap_gtc/Makefile.in
@@ -357,6 +357,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -379,6 +380,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/eap_identity/Makefile.in b/src/libcharon/plugins/eap_identity/Makefile.in
index cc1f21e..4859833 100644
--- a/src/libcharon/plugins/eap_identity/Makefile.in
+++ b/src/libcharon/plugins/eap_identity/Makefile.in
@@ -358,6 +358,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/eap_md5/Makefile.in b/src/libcharon/plugins/eap_md5/Makefile.in
index 939bbf9..796d42f 100644
--- a/src/libcharon/plugins/eap_md5/Makefile.in
+++ b/src/libcharon/plugins/eap_md5/Makefile.in
@@ -357,6 +357,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -379,6 +380,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/eap_mschapv2/Makefile.in b/src/libcharon/plugins/eap_mschapv2/Makefile.in
index 1e1936c..00a9f73 100644
--- a/src/libcharon/plugins/eap_mschapv2/Makefile.in
+++ b/src/libcharon/plugins/eap_mschapv2/Makefile.in
@@ -358,6 +358,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/eap_peap/Makefile.in b/src/libcharon/plugins/eap_peap/Makefile.in
index b83a80f..df3c2ea 100644
--- a/src/libcharon/plugins/eap_peap/Makefile.in
+++ b/src/libcharon/plugins/eap_peap/Makefile.in
@@ -359,6 +359,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -381,6 +382,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/eap_radius/Makefile.in b/src/libcharon/plugins/eap_radius/Makefile.in
index 29a2f38..d8ebeb8 100644
--- a/src/libcharon/plugins/eap_radius/Makefile.in
+++ b/src/libcharon/plugins/eap_radius/Makefile.in
@@ -360,6 +360,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -382,6 +383,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/eap_radius/eap_radius_provider.c b/src/libcharon/plugins/eap_radius/eap_radius_provider.c
index 9a87ad3..58bbc2e 100644
--- a/src/libcharon/plugins/eap_radius/eap_radius_provider.c
+++ b/src/libcharon/plugins/eap_radius/eap_radius_provider.c
@@ -404,11 +404,13 @@ typedef struct {
 	attr_t *current;
 } attribute_enumerator_t;
 
-
 METHOD(enumerator_t, attribute_enumerate, bool,
-	attribute_enumerator_t *this, configuration_attribute_type_t *type,
-	chunk_t *data)
+	attribute_enumerator_t *this, va_list args)
 {
+	configuration_attribute_type_t *type;
+	chunk_t *data;
+
+	VA_ARGS_VGET(args, type, data);
 	if (this->current)
 	{
 		destroy_attr(this->current);
@@ -446,7 +448,8 @@ METHOD(attribute_provider_t, create_attribute_enumerator, enumerator_t*,
 
 	INIT(enumerator,
 		.public = {
-			.enumerate = (void*)_attribute_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _attribute_enumerate,
 			.destroy = _attribute_destroy,
 		},
 		.list = linked_list_create(),
diff --git a/src/libcharon/plugins/eap_sim/Makefile.in b/src/libcharon/plugins/eap_sim/Makefile.in
index b4abce9..6c2584a 100644
--- a/src/libcharon/plugins/eap_sim/Makefile.in
+++ b/src/libcharon/plugins/eap_sim/Makefile.in
@@ -359,6 +359,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -381,6 +382,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/eap_sim_file/Makefile.in b/src/libcharon/plugins/eap_sim_file/Makefile.in
index 914c8c0..b247372 100644
--- a/src/libcharon/plugins/eap_sim_file/Makefile.in
+++ b/src/libcharon/plugins/eap_sim_file/Makefile.in
@@ -360,6 +360,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -382,6 +383,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/eap_sim_file/eap_sim_file_triplets.c b/src/libcharon/plugins/eap_sim_file/eap_sim_file_triplets.c
index ec16869..03a60cf 100644
--- a/src/libcharon/plugins/eap_sim_file/eap_sim_file_triplets.c
+++ b/src/libcharon/plugins/eap_sim_file/eap_sim_file_triplets.c
@@ -79,10 +79,8 @@ typedef struct {
 	private_eap_sim_file_triplets_t *this;
 } triplet_enumerator_t;
 
-/**
- * destroy a triplet enumerator
- */
-static void enumerator_destroy(triplet_enumerator_t *e)
+METHOD(enumerator_t, enumerator_destroy, void,
+	triplet_enumerator_t *e)
 {
 	if (e->current)
 	{
@@ -97,13 +95,14 @@ static void enumerator_destroy(triplet_enumerator_t *e)
 	free(e);
 }
 
-/**
- * enumerate through triplets
- */
-static bool enumerator_enumerate(triplet_enumerator_t *e, identification_t **imsi,
-								 char **rand, char **sres, char **kc)
+METHOD(enumerator_t, enumerator_enumerate, bool,
+	triplet_enumerator_t *e, va_list args)
 {
+	identification_t **imsi;
 	triplet_t *triplet;
+	char **rand, **sres, **kc;
+
+	VA_ARGS_VGET(args, imsi, rand, sres, kc);
 
 	if (e->inner->enumerate(e->inner, &triplet))
 	{
@@ -121,15 +120,18 @@ static bool enumerator_enumerate(triplet_enumerator_t *e, identification_t **ims
 METHOD(eap_sim_file_triplets_t, create_enumerator, enumerator_t*,
 	private_eap_sim_file_triplets_t *this)
 {
-	triplet_enumerator_t *enumerator = malloc_thing(triplet_enumerator_t);
+	triplet_enumerator_t *enumerator;
 
 	this->mutex->lock(this->mutex);
-	enumerator->public.enumerate = (void*)enumerator_enumerate;
-	enumerator->public.destroy = (void*)enumerator_destroy;
-	enumerator->inner = this->triplets->create_enumerator(this->triplets);
-	enumerator->current = NULL;
-	enumerator->this = this;
-
+	INIT(enumerator,
+		.public = {
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _enumerator_enumerate,
+			.destroy = _enumerator_destroy,
+		},
+		.inner = this->triplets->create_enumerator(this->triplets),
+		.this = this,
+	);
 	return &enumerator->public;
 }
 
diff --git a/src/libcharon/plugins/eap_sim_pcsc/Makefile.in b/src/libcharon/plugins/eap_sim_pcsc/Makefile.in
index 48ef921..88c31a9 100644
--- a/src/libcharon/plugins/eap_sim_pcsc/Makefile.in
+++ b/src/libcharon/plugins/eap_sim_pcsc/Makefile.in
@@ -361,6 +361,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -383,6 +384,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/eap_simaka_pseudonym/Makefile.in b/src/libcharon/plugins/eap_simaka_pseudonym/Makefile.in
index 5f12e2e..62c8ca1 100644
--- a/src/libcharon/plugins/eap_simaka_pseudonym/Makefile.in
+++ b/src/libcharon/plugins/eap_simaka_pseudonym/Makefile.in
@@ -361,6 +361,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -383,6 +384,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/eap_simaka_reauth/Makefile.in b/src/libcharon/plugins/eap_simaka_reauth/Makefile.in
index 45e2b74..ef20102 100644
--- a/src/libcharon/plugins/eap_simaka_reauth/Makefile.in
+++ b/src/libcharon/plugins/eap_simaka_reauth/Makefile.in
@@ -360,6 +360,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -382,6 +383,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/eap_simaka_sql/Makefile.in b/src/libcharon/plugins/eap_simaka_sql/Makefile.in
index 8c134cf..c9af52f 100644
--- a/src/libcharon/plugins/eap_simaka_sql/Makefile.in
+++ b/src/libcharon/plugins/eap_simaka_sql/Makefile.in
@@ -359,6 +359,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -381,6 +382,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/eap_simaka_sql/eap_simaka_sql_card.c b/src/libcharon/plugins/eap_simaka_sql/eap_simaka_sql_card.c
index 90627b5..0f59c5b 100644
--- a/src/libcharon/plugins/eap_simaka_sql/eap_simaka_sql_card.c
+++ b/src/libcharon/plugins/eap_simaka_sql/eap_simaka_sql_card.c
@@ -2,6 +2,9 @@
  * Copyright (C) 2010 Martin Willi
  * Copyright (C) 2010 revosec AG
  *
+ * Copyright (C) 2017 Andreas Steffen
+ * HSR 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
@@ -54,7 +57,7 @@ METHOD(simaka_card_t, get_triplet, bool,
 	snprintf(buf, sizeof(buf), "%Y", id);
 	query = this->db->query(this->db,
 				"select sres, kc from triplets where rand = ? and id = ? "
-				"order by use limit 1",
+				"order by used limit 1",
 				DB_BLOB, chunk_create(rand, SIM_RAND_LEN), DB_TEXT, buf,
 				DB_BLOB, DB_BLOB);
 	if (query)
@@ -82,7 +85,7 @@ METHOD(simaka_card_t, get_triplet, bool,
 		else
 		{
 			this->db->execute(this->db, NULL,
-					"update triplets set use = ? where id = ? and rand = ?",
+					"update triplets set used = ? where id = ? and rand = ?",
 					DB_UINT, time(NULL), DB_TEXT, buf,
 					DB_BLOB, chunk_create(rand, SIM_RAND_LEN));
 		}
@@ -102,7 +105,7 @@ METHOD(simaka_card_t, get_quintuplet, status_t,
 
 	snprintf(buf, sizeof(buf), "%Y", id);
 	query = this->db->query(this->db, "select ck, ik, res from quintuplets "
-				"where rand = ? and autn = ? and id = ? order by use limit 1",
+				"where rand = ? and autn = ? and id = ? order by used limit 1",
 				DB_BLOB, chunk_create(rand, AKA_RAND_LEN),
 				DB_BLOB, chunk_create(autn, AKA_AUTN_LEN), DB_TEXT, buf,
 				DB_BLOB, DB_BLOB, DB_BLOB);
@@ -134,7 +137,7 @@ METHOD(simaka_card_t, get_quintuplet, status_t,
 		else
 		{
 			this->db->execute(this->db, NULL,
-					"update quintuplets set use = ? where id = ? and rand = ?",
+					"update quintuplets set used = ? where id = ? and rand = ?",
 					DB_UINT, time(NULL), DB_TEXT, buf,
 					DB_BLOB, chunk_create(rand, AKA_RAND_LEN));
 		}
diff --git a/src/libcharon/plugins/eap_tls/Makefile.in b/src/libcharon/plugins/eap_tls/Makefile.in
index a9a2ded..dfe6d8b 100644
--- a/src/libcharon/plugins/eap_tls/Makefile.in
+++ b/src/libcharon/plugins/eap_tls/Makefile.in
@@ -358,6 +358,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/eap_tnc/Makefile.in b/src/libcharon/plugins/eap_tnc/Makefile.in
index cda1728..902d79d 100644
--- a/src/libcharon/plugins/eap_tnc/Makefile.in
+++ b/src/libcharon/plugins/eap_tnc/Makefile.in
@@ -359,6 +359,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -381,6 +382,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/eap_ttls/Makefile.in b/src/libcharon/plugins/eap_ttls/Makefile.in
index a72b005..53fb187 100644
--- a/src/libcharon/plugins/eap_ttls/Makefile.in
+++ b/src/libcharon/plugins/eap_ttls/Makefile.in
@@ -360,6 +360,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -382,6 +383,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/error_notify/Makefile.in b/src/libcharon/plugins/error_notify/Makefile.in
index 33862f0..1514f40 100644
--- a/src/libcharon/plugins/error_notify/Makefile.in
+++ b/src/libcharon/plugins/error_notify/Makefile.in
@@ -366,6 +366,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -388,6 +389,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/ext_auth/Makefile.in b/src/libcharon/plugins/ext_auth/Makefile.in
index de83d83..c3a1819 100644
--- a/src/libcharon/plugins/ext_auth/Makefile.in
+++ b/src/libcharon/plugins/ext_auth/Makefile.in
@@ -358,6 +358,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/farp/Makefile.in b/src/libcharon/plugins/farp/Makefile.in
index daee657..3de99da 100644
--- a/src/libcharon/plugins/farp/Makefile.in
+++ b/src/libcharon/plugins/farp/Makefile.in
@@ -356,6 +356,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -378,6 +379,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/forecast/Makefile.in b/src/libcharon/plugins/forecast/Makefile.in
index 5254bca..5263ccd 100644
--- a/src/libcharon/plugins/forecast/Makefile.in
+++ b/src/libcharon/plugins/forecast/Makefile.in
@@ -359,6 +359,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -381,6 +382,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/forecast/forecast_listener.c b/src/libcharon/plugins/forecast/forecast_listener.c
index 2024c26..4585731 100644
--- a/src/libcharon/plugins/forecast/forecast_listener.c
+++ b/src/libcharon/plugins/forecast/forecast_listener.c
@@ -613,17 +613,23 @@ METHOD(listener_t, ike_update, bool,
 	return TRUE;
 }
 
-/**
- * Filter to map entries to ts/mark
- */
-static bool ts_filter(entry_t *entry, traffic_selector_t **ts,
-					  traffic_selector_t **out, void *dummy, uint32_t *mark,
-					  void *dummy2, bool *reinject)
+CALLBACK(ts_filter, bool,
+	entry_t *entry, enumerator_t *orig, va_list args)
 {
-	*out = *ts;
-	*mark = entry->mark;
-	*reinject = entry->reinject;
-	return TRUE;
+	traffic_selector_t *ts, **out;
+	uint32_t *mark;
+	bool *reinject;
+
+	VA_ARGS_VGET(args, out, mark, reinject);
+
+	if (orig->enumerate(orig, &ts))
+	{
+		*out = ts;
+		*mark = entry->mark;
+		*reinject = entry->reinject;
+		return TRUE;
+	}
+	return FALSE;
 }
 
 /**
@@ -632,7 +638,7 @@ static bool ts_filter(entry_t *entry, traffic_selector_t **ts,
 static enumerator_t* create_inner_local(entry_t *entry, rwlock_t *lock)
 {
 	return enumerator_create_filter(array_create_enumerator(entry->lts),
-									(void*)ts_filter, entry, NULL);
+									ts_filter, entry, NULL);
 }
 
 /**
@@ -641,7 +647,7 @@ static enumerator_t* create_inner_local(entry_t *entry, rwlock_t *lock)
 static enumerator_t* create_inner_remote(entry_t *entry, rwlock_t *lock)
 {
 	return enumerator_create_filter(array_create_enumerator(entry->rts),
-									(void*)ts_filter, entry, NULL);
+									ts_filter, entry, NULL);
 }
 
 METHOD(forecast_listener_t, create_enumerator, enumerator_t*,
diff --git a/src/libcharon/plugins/ha/Makefile.in b/src/libcharon/plugins/ha/Makefile.in
index dd2a7a9..d82bdd2 100644
--- a/src/libcharon/plugins/ha/Makefile.in
+++ b/src/libcharon/plugins/ha/Makefile.in
@@ -358,6 +358,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/ha/ha_dispatcher.c b/src/libcharon/plugins/ha/ha_dispatcher.c
index ee66b84..7d22257 100644
--- a/src/libcharon/plugins/ha/ha_dispatcher.c
+++ b/src/libcharon/plugins/ha/ha_dispatcher.c
@@ -818,14 +818,14 @@ static void process_child_add(private_ha_dispatcher_t *this,
 	}
 	enumerator->destroy(enumerator);
 
+	child_sa->set_policies(child_sa, local_ts, remote_ts);
+
 	if (initiator)
 	{
 		if (child_sa->install(child_sa, encr_r, integ_r, inbound_spi,
-							  inbound_cpi, initiator, TRUE, TRUE,
-							  local_ts, remote_ts) != SUCCESS ||
+							  inbound_cpi, initiator, TRUE, TRUE) != SUCCESS ||
 			child_sa->install(child_sa, encr_i, integ_i, outbound_spi,
-							  outbound_cpi, initiator, FALSE, TRUE,
-							  local_ts, remote_ts) != SUCCESS)
+							  outbound_cpi, initiator, FALSE, TRUE) != SUCCESS)
 		{
 			failed = TRUE;
 		}
@@ -833,11 +833,9 @@ static void process_child_add(private_ha_dispatcher_t *this,
 	else
 	{
 		if (child_sa->install(child_sa, encr_i, integ_i, inbound_spi,
-							  inbound_cpi, initiator, TRUE, TRUE,
-							  local_ts, remote_ts) != SUCCESS ||
+							  inbound_cpi, initiator, TRUE, TRUE) != SUCCESS ||
 			child_sa->install(child_sa, encr_r, integ_r, outbound_spi,
-							  outbound_cpi, initiator, FALSE, TRUE,
-							  local_ts, remote_ts) != SUCCESS)
+							  outbound_cpi, initiator, FALSE, TRUE) != SUCCESS)
 		{
 			failed = TRUE;
 		}
@@ -868,7 +866,7 @@ static void process_child_add(private_ha_dispatcher_t *this,
 		child_sa->get_unique_id(child_sa), local_ts, remote_ts,
 		seg_i, this->segments->is_active(this->segments, seg_i) ? "*" : "",
 		seg_o, this->segments->is_active(this->segments, seg_o) ? "*" : "");
-	child_sa->add_policies(child_sa, local_ts, remote_ts);
+	child_sa->install_policies(child_sa);
 	local_ts->destroy_offset(local_ts, offsetof(traffic_selector_t, destroy));
 	remote_ts->destroy_offset(remote_ts, offsetof(traffic_selector_t, destroy));
 
diff --git a/src/libcharon/plugins/ha/ha_message.c b/src/libcharon/plugins/ha/ha_message.c
index 42dfaf0..5f73b71 100644
--- a/src/libcharon/plugins/ha/ha_message.c
+++ b/src/libcharon/plugins/ha/ha_message.c
@@ -331,10 +331,12 @@ typedef struct {
 } attribute_enumerator_t;
 
 METHOD(enumerator_t, attribute_enumerate, bool,
-	attribute_enumerator_t *this, ha_message_attribute_t *attr_out,
-	ha_message_value_t *value)
+	attribute_enumerator_t *this, va_list args)
 {
-	ha_message_attribute_t attr;
+	ha_message_attribute_t attr, *attr_out;
+	ha_message_value_t *value;
+
+	VA_ARGS_VGET(args, attr_out, value);
 
 	if (this->cleanup)
 	{
@@ -602,7 +604,8 @@ METHOD(ha_message_t, create_attribute_enumerator, enumerator_t*,
 
 	INIT(e,
 		.public = {
-			.enumerate = (void*)_attribute_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _attribute_enumerate,
 			.destroy = _enum_destroy,
 		},
 		.buf = chunk_skip(this->buf, 2),
diff --git a/src/libcharon/plugins/ha/ha_tunnel.c b/src/libcharon/plugins/ha/ha_tunnel.c
index a0e5146..1a6108e 100644
--- a/src/libcharon/plugins/ha/ha_tunnel.c
+++ b/src/libcharon/plugins/ha/ha_tunnel.c
@@ -111,8 +111,12 @@ typedef struct {
 } shared_enum_t;
 
 METHOD(enumerator_t, shared_enumerate, bool,
-	shared_enum_t *this, shared_key_t **key, id_match_t *me, id_match_t *other)
+	shared_enum_t *this, va_list args)
 {
+	shared_key_t **key;
+	id_match_t *me, *other;
+
+	VA_ARGS_VGET(args, key, me, other);
 	if (this->key)
 	{
 		if (me)
@@ -151,7 +155,8 @@ METHOD(ha_creds_t, create_shared_enumerator, enumerator_t*,
 
 	INIT(enumerator,
 		.public = {
-			.enumerate = (void*)_shared_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _shared_enumerate,
 			.destroy = (void*)free,
 		},
 		.key = this->key,
diff --git a/src/libcharon/plugins/ipseckey/Makefile.in b/src/libcharon/plugins/ipseckey/Makefile.in
index 025a1a2..02243e4 100644
--- a/src/libcharon/plugins/ipseckey/Makefile.in
+++ b/src/libcharon/plugins/ipseckey/Makefile.in
@@ -358,6 +358,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/ipseckey/ipseckey_cred.c b/src/libcharon/plugins/ipseckey/ipseckey_cred.c
index ff50d8a..b3ac2b3 100644
--- a/src/libcharon/plugins/ipseckey/ipseckey_cred.c
+++ b/src/libcharon/plugins/ipseckey/ipseckey_cred.c
@@ -62,13 +62,16 @@ typedef struct {
 } cert_enumerator_t;
 
 METHOD(enumerator_t, cert_enumerator_enumerate, bool,
-	cert_enumerator_t *this, certificate_t **cert)
+	cert_enumerator_t *this, va_list args)
 {
+	certificate_t **cert;
 	ipseckey_t *cur_ipseckey;
 	public_key_t *public;
 	rr_t *cur_rr;
 	chunk_t key;
 
+	VA_ARGS_VGET(args, cert);
+
 	/* Get the next supported IPSECKEY using the inner enumerator. */
 	while (this->inner->enumerate(this->inner, &cur_rr))
 	{
@@ -211,7 +214,8 @@ METHOD(credential_set_t, create_cert_enumerator, enumerator_t*,
 
 	INIT(e,
 		.public = {
-			.enumerate = (void*)_cert_enumerator_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _cert_enumerator_enumerate,
 			.destroy = _cert_enumerator_destroy,
 		},
 		.inner = rrset->create_rr_enumerator(rrset),
diff --git a/src/libcharon/plugins/kernel_iph/Makefile.in b/src/libcharon/plugins/kernel_iph/Makefile.in
index fb8e42e..d9c172c 100644
--- a/src/libcharon/plugins/kernel_iph/Makefile.in
+++ b/src/libcharon/plugins/kernel_iph/Makefile.in
@@ -358,6 +358,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/kernel_iph/kernel_iph_net.c b/src/libcharon/plugins/kernel_iph/kernel_iph_net.c
index efeb980..18a87b7 100644
--- a/src/libcharon/plugins/kernel_iph/kernel_iph_net.c
+++ b/src/libcharon/plugins/kernel_iph/kernel_iph_net.c
@@ -466,9 +466,12 @@ typedef struct {
 } addr_enumerator_t;
 
 METHOD(enumerator_t, addr_enumerate, bool,
-	addr_enumerator_t *this, host_t **host)
+	addr_enumerator_t *this, va_list args)
 {
 	iface_t *entry;
+	host_t **host;
+
+	VA_ARGS_VGET(args, host);
 
 	while (TRUE)
 	{
@@ -523,7 +526,8 @@ METHOD(kernel_net_t, create_address_enumerator, enumerator_t*,
 
 	INIT(enumerator,
 		.public = {
-			.enumerate = (void*)_addr_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _addr_enumerate,
 			.destroy = _addr_destroy,
 		},
 		.which = which,
diff --git a/src/libcharon/plugins/kernel_libipsec/Makefile.in b/src/libcharon/plugins/kernel_libipsec/Makefile.in
index 4d5e460..9f1a490 100644
--- a/src/libcharon/plugins/kernel_libipsec/Makefile.in
+++ b/src/libcharon/plugins/kernel_libipsec/Makefile.in
@@ -360,6 +360,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -382,6 +383,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_ipsec.c b/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_ipsec.c
index 77e37e2..d4832e2 100644
--- a/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_ipsec.c
+++ b/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_ipsec.c
@@ -84,12 +84,12 @@ static void exclude_route_destroy(exclude_route_t *this)
 	free(this);
 }
 
-/**
- * Find an exclude route entry by destination address
- */
-static bool exclude_route_match(exclude_route_t *current,
-								host_t *dst)
+CALLBACK(exclude_route_match, bool,
+	exclude_route_t *current, va_list args)
 {
+	host_t *dst;
+
+	VA_ARGS_VGET(args, dst);
 	return dst->ip_equals(dst, current->dst);
 }
 
@@ -204,12 +204,12 @@ static void policy_entry_destroy(policy_entry_t *this)
 	free(this);
 }
 
-/**
- * Compare two policy_entry_t objects
- */
-static inline bool policy_entry_equals(policy_entry_t *a,
-									   policy_entry_t *b)
+CALLBACK(policy_entry_equals, bool,
+	policy_entry_t *a, va_list args)
 {
+	policy_entry_t *b;
+
+	VA_ARGS_VGET(args, b);
 	return a->direction == b->direction &&
 		   a->src.proto == b->src.proto &&
 		   a->dst.proto == b->dst.proto &&
@@ -297,9 +297,8 @@ static void add_exclude_route(private_kernel_libipsec_ipsec_t *this,
 	exclude_route_t *exclude;
 	host_t *gtw;
 
-	if (this->excludes->find_first(this->excludes,
-								  (linked_list_match_t)exclude_route_match,
-								  (void**)&exclude, dst) == SUCCESS)
+	if (this->excludes->find_first(this->excludes, exclude_route_match,
+								  (void**)&exclude, dst))
 	{
 		route->exclude = exclude;
 		exclude->refs++;
@@ -524,9 +523,8 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
 	policy = create_policy_entry(id->src_ts, id->dst_ts, id->dir);
 
 	this->mutex->lock(this->mutex);
-	if (this->policies->find_first(this->policies,
-								  (linked_list_match_t)policy_entry_equals,
-								  (void**)&found, policy) == SUCCESS)
+	if (this->policies->find_first(this->policies, policy_entry_equals,
+								  (void**)&found, policy))
 	{
 		policy_entry_destroy(policy);
 		policy = found;
@@ -567,9 +565,8 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
 	policy = create_policy_entry(id->src_ts, id->dst_ts, id->dir);
 
 	this->mutex->lock(this->mutex);
-	if (this->policies->find_first(this->policies,
-								  (linked_list_match_t)policy_entry_equals,
-								  (void**)&found, policy) != SUCCESS)
+	if (!this->policies->find_first(this->policies, policy_entry_equals,
+									(void**)&found, policy))
 	{
 		policy_entry_destroy(policy);
 		this->mutex->unlock(this->mutex);
diff --git a/src/libcharon/plugins/kernel_netlink/Makefile.in b/src/libcharon/plugins/kernel_netlink/Makefile.in
index 26a7090..7f25c52 100644
--- a/src/libcharon/plugins/kernel_netlink/Makefile.in
+++ b/src/libcharon/plugins/kernel_netlink/Makefile.in
@@ -397,6 +397,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -419,6 +420,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c
index becf6b5..c411b82 100644
--- a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c
+++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c
@@ -78,9 +78,6 @@
 /** Base priority for installed policies */
 #define PRIO_BASE 200000
 
-/** Default lifetime of an acquire XFRM state (in seconds) */
-#define DEFAULT_ACQUIRE_LIFETIME 165
-
 /**
  * Map the limit for bytes and packets to XFRM_INF by default
  */
@@ -545,10 +542,10 @@ static policy_sa_t *policy_sa_create(private_kernel_netlink_ipsec_t *this,
 /**
  * Destroy a policy_sa(_in)_t object
  */
-static void policy_sa_destroy(policy_sa_t *policy, policy_dir_t *dir,
+static void policy_sa_destroy(policy_sa_t *policy, policy_dir_t dir,
 							  private_kernel_netlink_ipsec_t *this)
 {
-	if (*dir == POLICY_OUT)
+	if (dir == POLICY_OUT)
 	{
 		policy_sa_out_t *out = (policy_sa_out_t*)policy;
 		out->src_ts->destroy(out->src_ts);
@@ -558,6 +555,16 @@ static void policy_sa_destroy(policy_sa_t *policy, policy_dir_t *dir,
 	free(policy);
 }
 
+CALLBACK(policy_sa_destroy_cb, void,
+	policy_sa_t *policy, va_list args)
+{
+	private_kernel_netlink_ipsec_t *this;
+	policy_dir_t dir;
+
+	VA_ARGS_VGET(args, dir, this);
+	policy_sa_destroy(policy, dir, this);
+}
+
 typedef struct policy_entry_t policy_entry_t;
 
 /**
@@ -602,9 +609,8 @@ static void policy_entry_destroy(private_kernel_netlink_ipsec_t *this,
 	}
 	if (policy->used_by)
 	{
-		policy->used_by->invoke_function(policy->used_by,
-										(linked_list_invoke_t)policy_sa_destroy,
-										 &policy->direction, this);
+		policy->used_by->invoke_function(policy->used_by, policy_sa_destroy_cb,
+										 policy->direction, this);
 		policy->used_by->destroy(policy->used_by);
 	}
 	free(policy);
@@ -1639,12 +1645,46 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
 				 data->replay_window);
 			sa->replay_window = data->replay_window;
 		}
+		if (data->hw_offload)
+		{
+			host_t *local = data->inbound ? id->dst : id->src;
+			char *ifname;
+
+			if (charon->kernel->get_interface(charon->kernel, local, &ifname))
+			{
+				struct xfrm_user_offload *offload;
+
+				offload = netlink_reserve(hdr, sizeof(request),
+										  XFRMA_OFFLOAD_DEV, sizeof(*offload));
+				if (!offload)
+				{
+					free(ifname);
+					goto failed;
+				}
+				offload->ifindex = if_nametoindex(ifname);
+				if (local->get_family(local) == AF_INET6)
+				{
+					offload->flags |= XFRM_OFFLOAD_IPV6;
+				}
+				offload->flags |= data->inbound ? XFRM_OFFLOAD_INBOUND : 0;
+				free(ifname);
+			}
+		}
 	}
 
-	if (this->socket_xfrm->send_ack(this->socket_xfrm, hdr) != SUCCESS)
+	status = this->socket_xfrm->send_ack(this->socket_xfrm, hdr);
+	if (status == NOT_FOUND && data->update)
 	{
-		DBG1(DBG_KNL, "unable to add SAD entry with SPI %.8x%s", ntohl(id->spi),
-			 markstr);
+		DBG1(DBG_KNL, "allocated SPI not found anymore, try to add SAD entry");
+		hdr->nlmsg_type = XFRM_MSG_NEWSA;
+		status = this->socket_xfrm->send_ack(this->socket_xfrm, hdr);
+	}
+
+	if (status != SUCCESS)
+	{
+		DBG1(DBG_KNL, "unable to add SAD entry with SPI %.8x%s (%N)", ntohl(id->spi),
+			 markstr, status_names, status);
+		status = FAILED;
 		goto failed;
 	}
 
@@ -1919,13 +1959,13 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
 	kernel_ipsec_update_sa_t *data)
 {
 	netlink_buf_t request;
-	struct nlmsghdr *hdr, *out = NULL;
+	struct nlmsghdr *hdr, *out_hdr = NULL, *out = NULL;
 	struct xfrm_usersa_id *sa_id;
-	struct xfrm_usersa_info *out_sa = NULL, *sa;
+	struct xfrm_usersa_info *sa;
 	size_t len;
 	struct rtattr *rta;
 	size_t rtasize;
-	struct xfrm_encap_tmpl* tmpl = NULL;
+	struct xfrm_encap_tmpl* encap = NULL;
 	struct xfrm_replay_state *replay = NULL;
 	struct xfrm_replay_state_esn *replay_esn = NULL;
 	struct xfrm_lifetime_cur *lifetime = NULL;
@@ -1983,7 +2023,7 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
 			{
 				case XFRM_MSG_NEWSA:
 				{
-					out_sa = NLMSG_DATA(hdr);
+					out_hdr = hdr;
 					break;
 				}
 				case NLMSG_ERROR:
@@ -2002,7 +2042,7 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
 			break;
 		}
 	}
-	if (out_sa == NULL)
+	if (!out_hdr)
 	{
 		DBG1(DBG_KNL, "unable to update SAD entry with SPI %.8x%s",
 			 ntohl(id->spi), markstr);
@@ -2029,7 +2069,7 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
 	hdr->nlmsg_type = XFRM_MSG_NEWSA;
 	hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_info));
 	sa = NLMSG_DATA(hdr);
-	memcpy(sa, NLMSG_DATA(out), sizeof(struct xfrm_usersa_info));
+	memcpy(sa, NLMSG_DATA(out_hdr), sizeof(struct xfrm_usersa_info));
 	sa->family = data->new_dst->get_family(data->new_dst);
 
 	if (!id->src->ip_equals(id->src, data->new_src))
@@ -2041,8 +2081,8 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
 		host2xfrm(data->new_dst, &sa->id.daddr);
 	}
 
-	rta = XFRM_RTA(out, struct xfrm_usersa_info);
-	rtasize = XFRM_PAYLOAD(out, struct xfrm_usersa_info);
+	rta = XFRM_RTA(out_hdr, struct xfrm_usersa_info);
+	rtasize = XFRM_PAYLOAD(out_hdr, struct xfrm_usersa_info);
 	while (RTA_OK(rta, rtasize))
 	{
 		/* copy all attributes, but not XFRMA_ENCAP if we are disabling it */
@@ -2050,9 +2090,34 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
 		{
 			if (rta->rta_type == XFRMA_ENCAP)
 			{	/* update encap tmpl */
-				tmpl = RTA_DATA(rta);
-				tmpl->encap_sport = ntohs(data->new_src->get_port(data->new_src));
-				tmpl->encap_dport = ntohs(data->new_dst->get_port(data->new_dst));
+				encap = RTA_DATA(rta);
+				encap->encap_sport = ntohs(data->new_src->get_port(data->new_src));
+				encap->encap_dport = ntohs(data->new_dst->get_port(data->new_dst));
+			}
+			if (rta->rta_type == XFRMA_OFFLOAD_DEV)
+			{	/* update offload device */
+				struct xfrm_user_offload *offload;
+				host_t *local;
+				char *ifname;
+
+				offload = RTA_DATA(rta);
+				local = offload->flags & XFRM_OFFLOAD_INBOUND ? data->new_dst
+															  : data->new_src;
+
+				if (charon->kernel->get_interface(charon->kernel, local,
+												  &ifname))
+				{
+					offload->ifindex = if_nametoindex(ifname);
+					if (local->get_family(local) == AF_INET6)
+					{
+						offload->flags |= XFRM_OFFLOAD_IPV6;
+					}
+					else
+					{
+						offload->flags &= ~XFRM_OFFLOAD_IPV6;
+					}
+					free(ifname);
+				}
 			}
 			netlink_add_attribute(hdr, rta->rta_type,
 								  chunk_create(RTA_DATA(rta), RTA_PAYLOAD(rta)),
@@ -2061,17 +2126,18 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
 		rta = RTA_NEXT(rta, rtasize);
 	}
 
-	if (tmpl == NULL && data->new_encap)
+	if (encap == NULL && data->new_encap)
 	{	/* add tmpl if we are enabling it */
-		tmpl = netlink_reserve(hdr, sizeof(request), XFRMA_ENCAP, sizeof(*tmpl));
-		if (!tmpl)
+		encap = netlink_reserve(hdr, sizeof(request), XFRMA_ENCAP,
+								sizeof(*encap));
+		if (!encap)
 		{
 			goto failed;
 		}
-		tmpl->encap_type = UDP_ENCAP_ESPINUDP;
-		tmpl->encap_sport = ntohs(data->new_src->get_port(data->new_src));
-		tmpl->encap_dport = ntohs(data->new_dst->get_port(data->new_dst));
-		memset(&tmpl->encap_oa, 0, sizeof (xfrm_address_t));
+		encap->encap_type = UDP_ENCAP_ESPINUDP;
+		encap->encap_sport = ntohs(data->new_src->get_port(data->new_src));
+		encap->encap_dport = ntohs(data->new_dst->get_port(data->new_dst));
+		memset(&encap->encap_oa, 0, sizeof (xfrm_address_t));
 	}
 
 	if (replay_esn)
@@ -2711,7 +2777,7 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
 			ipsec_sa_equals(mapping->sa, &assigned_sa))
 		{
 			current->used_by->remove_at(current->used_by, enumerator);
-			policy_sa_destroy(mapping, &id->dir, this);
+			policy_sa_destroy(mapping, id->dir, this);
 			break;
 		}
 		if (is_installed)
@@ -3171,7 +3237,6 @@ kernel_netlink_ipsec_t *kernel_netlink_ipsec_create()
 {
 	private_kernel_netlink_ipsec_t *this;
 	bool register_for_events = TRUE;
-	FILE *f;
 
 	INIT(this,
 		.public = {
@@ -3216,15 +3281,6 @@ kernel_netlink_ipsec_t *kernel_netlink_ipsec_create()
 		register_for_events = FALSE;
 	}
 
-	f = fopen("/proc/sys/net/core/xfrm_acq_expires", "w");
-	if (f)
-	{
-		fprintf(f, "%u", lib->settings->get_int(lib->settings,
-								"%s.plugins.kernel-netlink.xfrm_acq_expires",
-								DEFAULT_ACQUIRE_LIFETIME, lib->ns));
-		fclose(f);
-	}
-
 	this->socket_xfrm = netlink_socket_create(NETLINK_XFRM, xfrm_msg_names,
 				lib->settings->get_bool(lib->settings,
 					"%s.plugins.kernel-netlink.parallel_xfrm", FALSE, lib->ns));
diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_net.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_net.c
index 2dc76d9..0dd3e30 100644
--- a/src/libcharon/plugins/kernel_netlink/kernel_netlink_net.c
+++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_net.c
@@ -163,19 +163,21 @@ static void iface_entry_destroy(iface_entry_t *this)
 	free(this);
 }
 
-/**
- * find an interface entry by index
- */
-static bool iface_entry_by_index(iface_entry_t *this, int *ifindex)
+CALLBACK(iface_entry_by_index, bool,
+	iface_entry_t *this, va_list args)
 {
-	return this->ifindex == *ifindex;
+	int ifindex;
+
+	VA_ARGS_VGET(args, ifindex);
+	return this->ifindex == ifindex;
 }
 
-/**
- * find an interface entry by name
- */
-static bool iface_entry_by_name(iface_entry_t *this, char *ifname)
+CALLBACK(iface_entry_by_name, bool,
+	iface_entry_t *this, va_list args)
 {
+	char *ifname;
+
+	VA_ARGS_VGET(args, ifname);
 	return streq(this->ifname, ifname);
 }
 
@@ -1112,8 +1114,8 @@ static bool is_interface_up_and_usable(private_kernel_netlink_net_t *this,
 {
 	iface_entry_t *iface;
 
-	if (this->ifaces->find_first(this->ifaces, (void*)iface_entry_by_index,
-								 (void**)&iface, &index) == SUCCESS)
+	if (this->ifaces->find_first(this->ifaces, iface_entry_by_index,
+								 (void**)&iface, index))
 	{
 		return iface_entry_up_and_usable(iface);
 	}
@@ -1125,9 +1127,13 @@ static bool is_interface_up_and_usable(private_kernel_netlink_net_t *this,
  *
  * this->lock must be locked when calling this function
  */
-static void addr_entry_unregister(addr_entry_t *addr, iface_entry_t *iface,
-								  private_kernel_netlink_net_t *this)
+CALLBACK(addr_entry_unregister, void,
+	addr_entry_t *addr, va_list args)
 {
+	private_kernel_netlink_net_t *this;
+	iface_entry_t *iface;
+
+	VA_ARGS_VGET(args, iface, this);
 	if (addr->refcount)
 	{
 		addr_map_entry_remove(this->vips, addr, iface);
@@ -1171,9 +1177,8 @@ static void process_link(private_kernel_netlink_net_t *this,
 	{
 		case RTM_NEWLINK:
 		{
-			if (this->ifaces->find_first(this->ifaces,
-									(void*)iface_entry_by_index, (void**)&entry,
-									&msg->ifi_index) != SUCCESS)
+			if (!this->ifaces->find_first(this->ifaces, iface_entry_by_index,
+										 (void**)&entry, msg->ifi_index))
 			{
 				INIT(entry,
 					.ifindex = msg->ifi_index,
@@ -1217,7 +1222,7 @@ static void process_link(private_kernel_netlink_net_t *this,
 					 * another interface? */
 					this->ifaces->remove_at(this->ifaces, enumerator);
 					current->addrs->invoke_function(current->addrs,
-								(void*)addr_entry_unregister, current, this);
+										addr_entry_unregister, current, this);
 					iface_entry_destroy(current);
 					break;
 				}
@@ -1288,8 +1293,8 @@ static void process_addr(private_kernel_netlink_net_t *this,
 	}
 
 	this->lock->write_lock(this->lock);
-	if (this->ifaces->find_first(this->ifaces, (void*)iface_entry_by_index,
-								 (void**)&iface, &msg->ifa_index) == SUCCESS)
+	if (this->ifaces->find_first(this->ifaces, iface_entry_by_index,
+								 (void**)&iface, msg->ifa_index))
 	{
 		addr_map_entry_t *entry, lookup = {
 			.ip = host,
@@ -1518,35 +1523,39 @@ typedef struct {
 	kernel_address_type_t which;
 } address_enumerator_t;
 
-/**
- * cleanup function for address enumerator
- */
-static void address_enumerator_destroy(address_enumerator_t *data)
+CALLBACK(address_enumerator_destroy, void,
+	address_enumerator_t *data)
 {
 	data->this->lock->unlock(data->this->lock);
 	free(data);
 }
 
-/**
- * filter for addresses
- */
-static bool filter_addresses(address_enumerator_t *data,
-							 addr_entry_t** in, host_t** out)
+CALLBACK(filter_addresses, bool,
+	address_enumerator_t *data, enumerator_t *orig, va_list args)
 {
-	if (!(data->which & ADDR_TYPE_VIRTUAL) && (*in)->refcount)
-	{	/* skip virtual interfaces added by us */
-		return FALSE;
-	}
-	if (!(data->which & ADDR_TYPE_REGULAR) && !(*in)->refcount)
-	{	/* address is regular, but not requested */
-		return FALSE;
-	}
-	if ((*in)->scope >= RT_SCOPE_LINK)
-	{	/* skip addresses with a unusable scope */
-		return FALSE;
+	addr_entry_t *addr;
+	host_t **out;
+
+	VA_ARGS_VGET(args, out);
+
+	while (orig->enumerate(orig, &addr))
+	{
+		if (!(data->which & ADDR_TYPE_VIRTUAL) && addr->refcount)
+		{	/* skip virtual interfaces added by us */
+			continue;
+		}
+		if (!(data->which & ADDR_TYPE_REGULAR) && !addr->refcount)
+		{	/* address is regular, but not requested */
+			continue;
+		}
+		if (addr->scope >= RT_SCOPE_LINK)
+		{	/* skip addresses with a unusable scope */
+			continue;
+		}
+		*out = addr->ip;
+		return TRUE;
 	}
-	*out = (*in)->ip;
-	return TRUE;
+	return FALSE;
 }
 
 /**
@@ -1556,30 +1565,35 @@ static enumerator_t *create_iface_enumerator(iface_entry_t *iface,
 											 address_enumerator_t *data)
 {
 	return enumerator_create_filter(
-				iface->addrs->create_enumerator(iface->addrs),
-				(void*)filter_addresses, data, NULL);
+						iface->addrs->create_enumerator(iface->addrs),
+						filter_addresses, data, NULL);
 }
 
-/**
- * filter for interfaces
- */
-static bool filter_interfaces(address_enumerator_t *data, iface_entry_t** in,
-							  iface_entry_t** out)
+CALLBACK(filter_interfaces, bool,
+	address_enumerator_t *data, enumerator_t *orig, va_list args)
 {
-	if (!(data->which & ADDR_TYPE_IGNORED) && !(*in)->usable)
-	{	/* skip interfaces excluded by config */
-		return FALSE;
-	}
-	if (!(data->which & ADDR_TYPE_LOOPBACK) && ((*in)->flags & IFF_LOOPBACK))
-	{	/* ignore loopback devices */
-		return FALSE;
-	}
-	if (!(data->which & ADDR_TYPE_DOWN) && !((*in)->flags & IFF_UP))
-	{	/* skip interfaces not up */
-		return FALSE;
+	iface_entry_t *iface, **out;
+
+	VA_ARGS_VGET(args, out);
+
+	while (orig->enumerate(orig, &iface))
+	{
+		if (!(data->which & ADDR_TYPE_IGNORED) && !iface->usable)
+		{	/* skip interfaces excluded by config */
+			continue;
+		}
+		if (!(data->which & ADDR_TYPE_LOOPBACK) && (iface->flags & IFF_LOOPBACK))
+		{	/* ignore loopback devices */
+			continue;
+		}
+		if (!(data->which & ADDR_TYPE_DOWN) && !(iface->flags & IFF_UP))
+		{	/* skip interfaces not up */
+			continue;
+		}
+		*out = iface;
+		return TRUE;
 	}
-	*out = *in;
-	return TRUE;
+	return FALSE;
 }
 
 METHOD(kernel_net_t, create_address_enumerator, enumerator_t*,
@@ -1596,9 +1610,9 @@ METHOD(kernel_net_t, create_address_enumerator, enumerator_t*,
 	return enumerator_create_nested(
 				enumerator_create_filter(
 					this->ifaces->create_enumerator(this->ifaces),
-					(void*)filter_interfaces, data, NULL),
+					filter_interfaces, data, NULL),
 				(void*)create_iface_enumerator, data,
-				(void*)address_enumerator_destroy);
+				address_enumerator_destroy);
 }
 
 METHOD(kernel_net_t, get_interface_name, bool,
@@ -1661,8 +1675,8 @@ static int get_interface_index(private_kernel_netlink_net_t *this, char* name)
 	DBG2(DBG_KNL, "getting iface index for %s", name);
 
 	this->lock->read_lock(this->lock);
-	if (this->ifaces->find_first(this->ifaces, (void*)iface_entry_by_name,
-								(void**)&iface, name) == SUCCESS)
+	if (this->ifaces->find_first(this->ifaces, iface_entry_by_name,
+								(void**)&iface, name))
 	{
 		ifindex = iface->ifindex;
 	}
@@ -1687,8 +1701,8 @@ static char *get_interface_name_by_index(private_kernel_netlink_net_t *this,
 	DBG2(DBG_KNL, "getting iface name for index %d", index);
 
 	this->lock->read_lock(this->lock);
-	if (this->ifaces->find_first(this->ifaces, (void*)iface_entry_by_index,
-								(void**)&iface, &index) == SUCCESS)
+	if (this->ifaces->find_first(this->ifaces, iface_entry_by_index,
+								(void**)&iface, index))
 	{
 		name = strdup(iface->ifname);
 	}
@@ -1928,7 +1942,7 @@ static host_t *get_route(private_kernel_netlink_net_t *this, host_t *dest,
 
 				table = (uintptr_t)route->table;
 				if (this->rt_exclude->find_first(this->rt_exclude, NULL,
-												 (void**)&table) == SUCCESS)
+												 (void**)&table))
 				{	/* route is from an excluded routing table */
 					continue;
 				}
@@ -2165,8 +2179,14 @@ METHOD(enumerator_t, destroy_subnet_enumerator, void,
 }
 
 METHOD(enumerator_t, enumerate_subnets, bool,
-	subnet_enumerator_t *this, host_t **net, uint8_t *mask, char **ifname)
+	subnet_enumerator_t *this, va_list args)
 {
+	host_t **net;
+	uint8_t *mask;
+	char **ifname;
+
+	VA_ARGS_VGET(args, net, mask, ifname);
+
 	if (!this->current)
 	{
 		this->current = this->msg;
@@ -2270,7 +2290,8 @@ METHOD(kernel_net_t, create_local_subnet_enumerator, enumerator_t*,
 
 	INIT(enumerator,
 		.public = {
-			.enumerate = (void*)_enumerate_subnets,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _enumerate_subnets,
 			.destroy = _destroy_subnet_enumerator,
 		},
 		.private = this,
@@ -2380,11 +2401,11 @@ METHOD(kernel_net_t, add_ip, status_t,
 	}
 	/* try to find the target interface, either by config or via src ip */
 	if (!this->install_virtual_ip_on ||
-		 this->ifaces->find_first(this->ifaces, (void*)iface_entry_by_name,
-						(void**)&iface, this->install_virtual_ip_on) != SUCCESS)
+		!this->ifaces->find_first(this->ifaces, iface_entry_by_name,
+								 (void**)&iface, this->install_virtual_ip_on))
 	{
-		if (this->ifaces->find_first(this->ifaces, (void*)iface_entry_by_name,
-									 (void**)&iface, iface_name) != SUCCESS)
+		if (!this->ifaces->find_first(this->ifaces, iface_entry_by_name,
+									 (void**)&iface, iface_name))
 		{	/* if we don't find the requested interface we just use the first */
 			this->ifaces->get_first(this->ifaces, (void**)&iface);
 		}
diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_plugin.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_plugin.c
index 8bafc3c..5835002 100644
--- a/src/libcharon/plugins/kernel_netlink/kernel_netlink_plugin.c
+++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_plugin.c
@@ -19,6 +19,8 @@
 #include "kernel_netlink_ipsec.h"
 #include "kernel_netlink_net.h"
 
+#include <sa/task_manager.h>
+
 typedef struct private_kernel_netlink_plugin_t private_kernel_netlink_plugin_t;
 
 /**
@@ -50,6 +52,24 @@ METHOD(plugin_t, get_features, int,
 	return countof(f);
 }
 
+METHOD(plugin_t, reload, bool,
+	private_kernel_netlink_plugin_t *this)
+{
+	u_int timeout;
+	FILE *f;
+
+	f = fopen("/proc/sys/net/core/xfrm_acq_expires", "w");
+	if (f)
+	{
+		timeout = lib->settings->get_int(lib->settings,
+							"%s.plugins.kernel-netlink.xfrm_acq_expires",
+							task_manager_total_retransmit_timeout(), lib->ns);
+		fprintf(f, "%u", timeout);
+		fclose(f);
+	}
+	return TRUE;
+}
+
 METHOD(plugin_t, destroy, void,
 	private_kernel_netlink_plugin_t *this)
 {
@@ -76,10 +96,13 @@ plugin_t *kernel_netlink_plugin_create()
 			.plugin = {
 				.get_name = _get_name,
 				.get_features = _get_features,
+				.reload = _reload,
 				.destroy = _destroy,
 			},
 		},
 	);
 
+	reload(this);
+
 	return &this->public.plugin;
 }
diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_shared.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_shared.c
index da54031..cf85cb0 100644
--- a/src/libcharon/plugins/kernel_netlink/kernel_netlink_shared.c
+++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_shared.c
@@ -333,7 +333,8 @@ static status_t send_once(private_netlink_socket_t *this, struct nlmsghdr *in,
 	while (!entry->complete)
 	{
 		if (this->parallel &&
-			lib->watcher->get_state(lib->watcher) != WATCHER_STOPPED)
+			lib->watcher->get_state(lib->watcher) != WATCHER_STOPPED &&
+			lib->processor->get_total_threads(lib->processor))
 		{
 			if (this->timeout)
 			{
diff --git a/src/libcharon/plugins/kernel_pfkey/Makefile.in b/src/libcharon/plugins/kernel_pfkey/Makefile.in
index b138a96..b27408a 100644
--- a/src/libcharon/plugins/kernel_pfkey/Makefile.in
+++ b/src/libcharon/plugins/kernel_pfkey/Makefile.in
@@ -358,6 +358,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c b/src/libcharon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c
index 1787814..fd1adb2 100644
--- a/src/libcharon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c
+++ b/src/libcharon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c
@@ -464,10 +464,10 @@ static policy_sa_t *policy_sa_create(private_kernel_pfkey_ipsec_t *this,
 /**
  * Destroy a policy_sa(_in)_t object
  */
-static void policy_sa_destroy(policy_sa_t *policy, policy_dir_t *dir,
+static void policy_sa_destroy(policy_sa_t *policy, policy_dir_t dir,
 							  private_kernel_pfkey_ipsec_t *this)
 {
-	if (*dir == POLICY_OUT)
+	if (dir == POLICY_OUT)
 	{
 		policy_sa_out_t *out = (policy_sa_out_t*)policy;
 		out->src_ts->destroy(out->src_ts);
@@ -477,6 +477,16 @@ static void policy_sa_destroy(policy_sa_t *policy, policy_dir_t *dir,
 	free(policy);
 }
 
+CALLBACK(policy_sa_destroy_cb, void,
+	policy_sa_t *policy, va_list args)
+{
+	private_kernel_pfkey_ipsec_t *this;
+	policy_dir_t dir;
+
+	VA_ARGS_VGET(args, dir, this);
+	policy_sa_destroy(policy, dir, this);
+}
+
 typedef struct policy_entry_t policy_entry_t;
 
 /**
@@ -557,9 +567,8 @@ static void policy_entry_destroy(policy_entry_t *policy,
 	}
 	if (policy->used_by)
 	{
-		policy->used_by->invoke_function(policy->used_by,
-										(linked_list_invoke_t)policy_sa_destroy,
-										 &policy->direction, this);
+		policy->used_by->invoke_function(policy->used_by, policy_sa_destroy_cb,
+										 policy->direction, this);
 		policy->used_by->destroy(policy->used_by);
 	}
 	DESTROY_IF(policy->src.net);
@@ -567,12 +576,21 @@ static void policy_entry_destroy(policy_entry_t *policy,
 	free(policy);
 }
 
-/**
- * compares two policy_entry_t
- */
-static inline bool policy_entry_equals(policy_entry_t *current,
-									   policy_entry_t *policy)
+CALLBACK(policy_entry_destroy_cb, void,
+	policy_entry_t *policy, va_list args)
 {
+	private_kernel_pfkey_ipsec_t *this;
+
+	VA_ARGS_VGET(args, this);
+	policy_entry_destroy(policy, this);
+}
+
+CALLBACK(policy_entry_equals, bool,
+	policy_entry_t *current, va_list args)
+{
+	policy_entry_t *policy;
+
+	VA_ARGS_VGET(args, policy);
 	return current->direction == policy->direction &&
 		   current->src.proto == policy->src.proto &&
 		   current->dst.proto == policy->dst.proto &&
@@ -582,13 +600,13 @@ static inline bool policy_entry_equals(policy_entry_t *current,
 		   current->dst.net->equals(current->dst.net, policy->dst.net);
 }
 
-/**
- * compare the given kernel index with that of a policy
- */
-static inline bool policy_entry_match_byindex(policy_entry_t *current,
-											  uint32_t *index)
+CALLBACK(policy_entry_match_byindex, bool,
+	policy_entry_t *current, va_list args)
 {
-	return current->index == *index;
+	uint32_t index;
+
+	VA_ARGS_VGET(args, index);
+	return current->index == index;
 }
 
 /**
@@ -999,24 +1017,6 @@ static void add_addr_ext(struct sadb_msg *msg, host_t *host, uint16_t type,
 	PFKEY_EXT_ADD(msg, addr);
 }
 
-/**
- * adds an empty address extension to the given sadb_msg
- */
-static void add_anyaddr_ext(struct sadb_msg *msg, int family, uint8_t type)
-{
-	socklen_t len = (family == AF_INET) ? sizeof(struct sockaddr_in) :
-										  sizeof(struct sockaddr_in6);
-	struct sadb_address *addr = (struct sadb_address*)PFKEY_EXT_ADD_NEXT(msg);
-	addr->sadb_address_exttype = type;
-	sockaddr_t *saddr = (sockaddr_t*)(addr + 1);
-	saddr->sa_family = family;
-#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
-	saddr->sa_len = len;
-#endif
-	addr->sadb_address_len = PFKEY_LEN(sizeof(*addr) + len);
-	PFKEY_EXT_ADD(msg, addr);
-}
-
 #ifdef HAVE_NATT
 /**
  * add udp encap extensions to a sadb_msg
@@ -1279,9 +1279,8 @@ static void process_acquire(private_kernel_pfkey_ipsec_t *this,
 
 	index = response.x_policy->sadb_x_policy_id;
 	this->mutex->lock(this->mutex);
-	if (this->policies->find_first(this->policies,
-								(linked_list_match_t)policy_entry_match_byindex,
-								(void**)&policy, &index) == SUCCESS &&
+	if (this->policies->find_first(this->policies, policy_entry_match_byindex,
+								  (void**)&policy, index) &&
 		policy->used_by->get_first(policy->used_by, (void**)&sa) == SUCCESS)
 	{
 		reqid = sa->sa->cfg.reqid;
@@ -1854,6 +1853,7 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
 	pfkey_msg_t response;
 	size_t len;
 
+#ifndef SADB_X_EXT_NEW_ADDRESS_SRC
 	/* we can't update the SA if any of the ip addresses have changed.
 	 * that's because we can't use SADB_UPDATE and by deleting and readding the
 	 * SA the sequence numbers would get lost */
@@ -1864,6 +1864,7 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
 			 "changes are not supported", ntohl(id->spi));
 		return NOT_SUPPORTED;
 	}
+#endif /*SADB_X_EXT_NEW_ADDRESS_SRC*/
 
 	/* if IPComp is used, we first update the IPComp SA */
 	if (data->cpi)
@@ -1900,9 +1901,7 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
 	sa->sadb_sa_state = SADB_SASTATE_MATURE;
 	PFKEY_EXT_ADD(msg, sa);
 
-	/* the kernel wants a SADB_EXT_ADDRESS_SRC to be present even though
-	 * it is not used for anything. */
-	add_anyaddr_ext(msg, id->dst->get_family(id->dst), SADB_EXT_ADDRESS_SRC);
+	add_addr_ext(msg, id->src, SADB_EXT_ADDRESS_SRC, 0, 0, FALSE);
 	add_addr_ext(msg, id->dst, SADB_EXT_ADDRESS_DST, 0, 0, FALSE);
 
 	if (pfkey_send(this, msg, &out, &len) != SUCCESS)
@@ -1944,7 +1943,7 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
 		sa_2 = (struct sadb_sa_2*)PFKEY_EXT_ADD_NEXT(msg);
 		sa_2->sa.sadb_sa_len = PFKEY_LEN(sizeof(struct sadb_sa_2));
 		memcpy(&sa_2->sa, response.sa, sizeof(struct sadb_sa));
-		if (data->encap)
+		if (data->new_encap)
 		{
 			sa_2->sadb_sa_natt_port = data->new_dst->get_port(data->new_dst);
 			sa_2->sa.sadb_sa_flags |= SADB_X_EXT_NATT;
@@ -1978,6 +1977,19 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
 	}
 #endif /*HAVE_NATT*/
 
+#ifdef SADB_X_EXT_NEW_ADDRESS_SRC
+	if (!id->src->ip_equals(id->src, data->new_src))
+	{
+		add_addr_ext(msg, data->new_src, SADB_X_EXT_NEW_ADDRESS_SRC, 0, 0,
+					 FALSE);
+	}
+	if (!id->dst->ip_equals(id->dst, data->new_dst))
+	{
+		add_addr_ext(msg, data->new_dst, SADB_X_EXT_NEW_ADDRESS_DST, 0, 0,
+					 FALSE);
+	}
+#endif /*SADB_X_EXT_NEW_ADDRESS_SRC*/
+
 	free(out);
 
 	if (pfkey_send(this, msg, &out, &len) != SUCCESS)
@@ -2559,8 +2571,7 @@ static status_t add_policy_internal(private_kernel_pfkey_ipsec_t *this,
 
 	/* we try to find the policy again and update the kernel index */
 	this->mutex->lock(this->mutex);
-	if (this->policies->find_first(this->policies, NULL,
-								  (void**)&policy) != SUCCESS)
+	if (!this->policies->find_first(this->policies, NULL, (void**)&policy))
 	{
 		DBG2(DBG_KNL, "unable to update index, the policy is already gone, "
 					  "ignoring");
@@ -2611,9 +2622,8 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
 
 	/* find a matching policy */
 	this->mutex->lock(this->mutex);
-	if (this->policies->find_first(this->policies,
-								  (linked_list_match_t)policy_entry_equals,
-								  (void**)&found, policy) == SUCCESS)
+	if (this->policies->find_first(this->policies, policy_entry_equals,
+								   (void**)&found, policy))
 	{	/* use existing policy */
 		DBG2(DBG_KNL, "policy %R === %R %N already exists, increasing "
 			 "refcount", id->src_ts, id->dst_ts, policy_dir_names, id->dir);
@@ -2706,9 +2716,8 @@ METHOD(kernel_ipsec_t, query_policy, status_t,
 
 	/* find a matching policy */
 	this->mutex->lock(this->mutex);
-	if (this->policies->find_first(this->policies,
-								  (linked_list_match_t)policy_entry_equals,
-								  (void**)&found, policy) != SUCCESS)
+	if (!this->policies->find_first(this->policies, policy_entry_equals,
+									(void**)&found, policy))
 	{
 		DBG1(DBG_KNL, "querying policy %R === %R %N failed, not found",
 			 id->src_ts, id->dst_ts, policy_dir_names, id->dir);
@@ -2819,9 +2828,8 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
 
 	/* find a matching policy */
 	this->mutex->lock(this->mutex);
-	if (this->policies->find_first(this->policies,
-								  (linked_list_match_t)policy_entry_equals,
-								  (void**)&found, policy) != SUCCESS)
+	if (!this->policies->find_first(this->policies, policy_entry_equals,
+									(void**)&found, policy))
 	{
 		DBG1(DBG_KNL, "deleting policy %R === %R %N failed, not found",
 			 id->src_ts, id->dst_ts, policy_dir_names, id->dir);
@@ -2865,7 +2873,7 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
 	if (policy->used_by->get_count(policy->used_by) > 0)
 	{	/* policy is used by more SAs, keep in kernel */
 		DBG2(DBG_KNL, "policy still used by another CHILD_SA, not removed");
-		policy_sa_destroy(mapping, &id->dir, this);
+		policy_sa_destroy(mapping, id->dir, this);
 
 		if (!is_installed)
 		{	/* no need to update as the policy was not installed for this SA */
@@ -2920,7 +2928,7 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
 	}
 
 	this->policies->remove(this->policies, found, NULL);
-	policy_sa_destroy(mapping, &id->dir, this);
+	policy_sa_destroy(mapping, id->dir, this);
 	policy_entry_destroy(policy, this);
 	this->mutex->unlock(this->mutex);
 
@@ -3093,8 +3101,7 @@ METHOD(kernel_ipsec_t, destroy, void,
 		lib->watcher->remove(lib->watcher, this->socket_events);
 		close(this->socket_events);
 	}
-	this->policies->invoke_function(this->policies,
-								   (linked_list_invoke_t)policy_entry_destroy,
+	this->policies->invoke_function(this->policies, policy_entry_destroy_cb,
 									this);
 	this->policies->destroy(this->policies);
 	this->excludes->destroy(this->excludes);
diff --git a/src/libcharon/plugins/kernel_pfroute/Makefile.in b/src/libcharon/plugins/kernel_pfroute/Makefile.in
index 1e4b3e2..e7005bb 100644
--- a/src/libcharon/plugins/kernel_pfroute/Makefile.in
+++ b/src/libcharon/plugins/kernel_pfroute/Makefile.in
@@ -358,6 +358,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/kernel_pfroute/kernel_pfroute_net.c b/src/libcharon/plugins/kernel_pfroute/kernel_pfroute_net.c
index efcf1c2..6d06ee1 100644
--- a/src/libcharon/plugins/kernel_pfroute/kernel_pfroute_net.c
+++ b/src/libcharon/plugins/kernel_pfroute/kernel_pfroute_net.c
@@ -601,9 +601,12 @@ typedef struct {
 } rt_enumerator_t;
 
 METHOD(enumerator_t, rt_enumerate, bool,
-	rt_enumerator_t *this, int *xtype, struct sockaddr **addr)
+	rt_enumerator_t *this, va_list args)
 {
-	int i, type;
+	struct sockaddr **addr;
+	int i, type, *xtype;
+
+	VA_ARGS_VGET(args, xtype, addr);
 
 	if (this->remaining < sizeof(this->addr->sa_len) ||
 		this->remaining < this->addr->sa_len)
@@ -637,7 +640,8 @@ static enumerator_t *create_rt_enumerator(int types, int remaining,
 
 	INIT(this,
 		.public = {
-			.enumerate = (void*)_rt_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _rt_enumerate,
 			.destroy = (void*)free,
 		},
 		.types = types,
@@ -1050,41 +1054,45 @@ typedef struct {
 	kernel_address_type_t which;
 } address_enumerator_t;
 
-/**
- * cleanup function for address enumerator
- */
-static void address_enumerator_destroy(address_enumerator_t *data)
+CALLBACK(address_enumerator_destroy, void,
+	address_enumerator_t *data)
 {
 	data->this->lock->unlock(data->this->lock);
 	free(data);
 }
 
-/**
- * filter for addresses
- */
-static bool filter_addresses(address_enumerator_t *data,
-							 addr_entry_t** in, host_t** out)
+CALLBACK(filter_addresses, bool,
+	address_enumerator_t *data, enumerator_t *orig, va_list args)
 {
-	host_t *ip;
-	if (!(data->which & ADDR_TYPE_VIRTUAL) && (*in)->virtual)
-	{   /* skip virtual interfaces added by us */
-		return FALSE;
-	}
-	if (!(data->which & ADDR_TYPE_REGULAR) && !(*in)->virtual)
-	{	/* address is regular, but not requested */
-		return FALSE;
-	}
-	ip = (*in)->ip;
-	if (ip->get_family(ip) == AF_INET6)
+	addr_entry_t *addr;
+	host_t *ip, **out;
+	struct sockaddr_in6 *sin6;
+
+	VA_ARGS_VGET(args, out);
+
+	while (orig->enumerate(orig, &addr))
 	{
-		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ip->get_sockaddr(ip);
-		if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
-		{   /* skip addresses with a unusable scope */
-			return FALSE;
+		if (!(data->which & ADDR_TYPE_VIRTUAL) && addr->virtual)
+		{   /* skip virtual interfaces added by us */
+			continue;
 		}
+		if (!(data->which & ADDR_TYPE_REGULAR) && !addr->virtual)
+		{	/* address is regular, but not requested */
+			continue;
+		}
+		ip = addr->ip;
+		if (ip->get_family(ip) == AF_INET6)
+		{
+			sin6 = (struct sockaddr_in6 *)ip->get_sockaddr(ip);
+			if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
+			{   /* skip addresses with a unusable scope */
+				continue;
+			}
+		}
+		*out = ip;
+		return TRUE;
 	}
-	*out = ip;
-	return TRUE;
+	return FALSE;
 }
 
 /**
@@ -1094,29 +1102,34 @@ static enumerator_t *create_iface_enumerator(iface_entry_t *iface,
 											 address_enumerator_t *data)
 {
 	return enumerator_create_filter(iface->addrs->create_enumerator(iface->addrs),
-									(void*)filter_addresses, data, NULL);
+									filter_addresses, data, NULL);
 }
 
-/**
- * filter for interfaces
- */
-static bool filter_interfaces(address_enumerator_t *data, iface_entry_t** in,
-							  iface_entry_t** out)
+CALLBACK(filter_interfaces, bool,
+	address_enumerator_t *data, enumerator_t *orig, va_list args)
 {
-	if (!(data->which & ADDR_TYPE_IGNORED) && !(*in)->usable)
-	{	/* skip interfaces excluded by config */
-		return FALSE;
-	}
-	if (!(data->which & ADDR_TYPE_LOOPBACK) && ((*in)->flags & IFF_LOOPBACK))
-	{	/* ignore loopback devices */
-		return FALSE;
-	}
-	if (!(data->which & ADDR_TYPE_DOWN) && !((*in)->flags & IFF_UP))
-	{	/* skip interfaces not up */
-		return FALSE;
+	iface_entry_t *iface, **out;
+
+	VA_ARGS_VGET(args, out);
+
+	while (orig->enumerate(orig, &iface))
+	{
+		if (!(data->which & ADDR_TYPE_IGNORED) && !iface->usable)
+		{	/* skip interfaces excluded by config */
+			continue;
+		}
+		if (!(data->which & ADDR_TYPE_LOOPBACK) && (iface->flags & IFF_LOOPBACK))
+		{	/* ignore loopback devices */
+			continue;
+		}
+		if (!(data->which & ADDR_TYPE_DOWN) && !(iface->flags & IFF_UP))
+		{	/* skip interfaces not up */
+			continue;
+		}
+		*out = iface;
+		return TRUE;
 	}
-	*out = *in;
-	return TRUE;
+	return FALSE;
 }
 
 METHOD(kernel_net_t, create_address_enumerator, enumerator_t*,
@@ -1133,9 +1146,9 @@ METHOD(kernel_net_t, create_address_enumerator, enumerator_t*,
 	return enumerator_create_nested(
 				enumerator_create_filter(
 					this->ifaces->create_enumerator(this->ifaces),
-					(void*)filter_interfaces, data, NULL),
+					filter_interfaces, data, NULL),
 				(void*)create_iface_enumerator, data,
-				(void*)address_enumerator_destroy);
+				address_enumerator_destroy);
 }
 
 METHOD(kernel_net_t, get_features, kernel_feature_t,
@@ -1789,13 +1802,18 @@ METHOD(enumerator_t, destroy_subnet_enumerator, void,
 }
 
 METHOD(enumerator_t, enumerate_subnets, bool,
-	subnet_enumerator_t *this, host_t **net, uint8_t *mask, char **ifname)
+	subnet_enumerator_t *this, va_list args)
 {
 	enumerator_t *enumerator;
+	host_t **net;
 	struct rt_msghdr *rtm;
 	struct sockaddr *addr;
+	uint8_t *mask;
+	char **ifname;
 	int type;
 
+	VA_ARGS_VGET(args, net, mask, ifname);
+
 	if (!this->current)
 	{
 		this->current = this->buf;
@@ -1888,7 +1906,8 @@ METHOD(kernel_net_t, create_local_subnet_enumerator, enumerator_t*,
 
 	INIT(enumerator,
 		.public = {
-			.enumerate = (void*)_enumerate_subnets,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _enumerate_subnets,
 			.destroy = _destroy_subnet_enumerator,
 		},
 		.buf = buf,
diff --git a/src/libcharon/plugins/kernel_wfp/Makefile.in b/src/libcharon/plugins/kernel_wfp/Makefile.in
index a3368d5..ffdae84 100644
--- a/src/libcharon/plugins/kernel_wfp/Makefile.in
+++ b/src/libcharon/plugins/kernel_wfp/Makefile.in
@@ -366,6 +366,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -388,6 +389,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/led/Makefile.in b/src/libcharon/plugins/led/Makefile.in
index f16304d..7f82029 100644
--- a/src/libcharon/plugins/led/Makefile.in
+++ b/src/libcharon/plugins/led/Makefile.in
@@ -355,6 +355,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -377,6 +378,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/load_tester/Makefile.in b/src/libcharon/plugins/load_tester/Makefile.in
index c6e17fb..c55e357 100644
--- a/src/libcharon/plugins/load_tester/Makefile.in
+++ b/src/libcharon/plugins/load_tester/Makefile.in
@@ -368,6 +368,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -390,6 +391,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/load_tester/load_tester_creds.c b/src/libcharon/plugins/load_tester/load_tester_creds.c
index 2f48296..2cedd13 100644
--- a/src/libcharon/plugins/load_tester/load_tester_creds.c
+++ b/src/libcharon/plugins/load_tester/load_tester_creds.c
@@ -395,22 +395,28 @@ METHOD(credential_set_t, create_cert_enumerator, enumerator_t*,
 	return NULL;
 }
 
-/**
- * Filter function for shared keys, returning ID matches
- */
-static bool shared_filter(void *null, shared_key_t **in, shared_key_t **out,
-				void **un1, id_match_t *me, void **un2, id_match_t *other)
+CALLBACK(shared_filter, bool,
+	void *null, enumerator_t *orig, va_list args)
 {
-	*out = *in;
-	if (me)
-	{
-		*me = ID_MATCH_ANY;
-	}
-	if (other)
+	shared_key_t *key, **out;
+	id_match_t *me, *other;
+
+	VA_ARGS_VGET(args, out, me, other);
+
+	if (orig->enumerate(orig, &key))
 	{
-		*other = ID_MATCH_ANY;
+		*out = key;
+		if (me)
+		{
+			*me = ID_MATCH_ANY;
+		}
+		if (other)
+		{
+			*other = ID_MATCH_ANY;
+		}
+		return TRUE;
 	}
-	return TRUE;
+	return FALSE;
 }
 
 METHOD(credential_set_t, create_shared_enumerator, enumerator_t*,
@@ -431,7 +437,7 @@ METHOD(credential_set_t, create_shared_enumerator, enumerator_t*,
 			return NULL;
 	}
 	return enumerator_create_filter(enumerator_create_single(shared, NULL),
-									(void*)shared_filter, NULL, NULL);
+									shared_filter, NULL, NULL);
 }
 
 METHOD(load_tester_creds_t, destroy, void,
diff --git a/src/libcharon/plugins/lookip/Makefile.in b/src/libcharon/plugins/lookip/Makefile.in
index 9190604..ba86d37 100644
--- a/src/libcharon/plugins/lookip/Makefile.in
+++ b/src/libcharon/plugins/lookip/Makefile.in
@@ -364,6 +364,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -386,6 +387,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/medcli/Makefile.in b/src/libcharon/plugins/medcli/Makefile.in
index 4db68a3..e2d63be 100644
--- a/src/libcharon/plugins/medcli/Makefile.in
+++ b/src/libcharon/plugins/medcli/Makefile.in
@@ -358,6 +358,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/medcli/medcli_config.c b/src/libcharon/plugins/medcli/medcli_config.c
index 78159c8..f349901 100644
--- a/src/libcharon/plugins/medcli/medcli_config.c
+++ b/src/libcharon/plugins/medcli/medcli_config.c
@@ -223,10 +223,11 @@ typedef struct {
 } peer_enumerator_t;
 
 METHOD(enumerator_t, peer_enumerator_enumerate, bool,
-	peer_enumerator_t *this, peer_cfg_t **cfg)
+	peer_enumerator_t *this, va_list args)
 {
 	char *name, *local_net, *remote_net;
 	chunk_t me, other;
+	peer_cfg_t **cfg;
 	child_cfg_t *child_cfg;
 	auth_cfg_t *auth;
 	peer_cfg_create_t peer = {
@@ -249,6 +250,8 @@ METHOD(enumerator_t, peer_enumerator_enumerate, bool,
 		.mode = MODE_TUNNEL,
 	};
 
+	VA_ARGS_VGET(args, cfg);
+
 	DESTROY_IF(this->current);
 	if (!this->inner->enumerate(this->inner, &name, &me, &other,
 								&local_net, &remote_net))
@@ -295,7 +298,8 @@ METHOD(backend_t, create_peer_cfg_enumerator, enumerator_t*,
 
 	INIT(e,
 		.public = {
-			.enumerate = (void*)_peer_enumerator_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _peer_enumerator_enumerate,
 			.destroy = _peer_enumerator_destroy,
 		},
 		.ike = this->ike,
diff --git a/src/libcharon/plugins/medcli/medcli_creds.c b/src/libcharon/plugins/medcli/medcli_creds.c
index 677229b..528fc00 100644
--- a/src/libcharon/plugins/medcli/medcli_creds.c
+++ b/src/libcharon/plugins/medcli/medcli_creds.c
@@ -50,10 +50,13 @@ typedef struct {
 } private_enumerator_t;
 
 METHOD(enumerator_t, private_enumerator_enumerate, bool,
-	private_enumerator_t *this, private_key_t **key)
+	private_enumerator_t *this, va_list args)
 {
+	private_key_t **key;
 	chunk_t chunk;
 
+	VA_ARGS_VGET(args, key);
+
 	DESTROY_IF(this->current);
 	while (this->inner->enumerate(this->inner, &chunk))
 	{
@@ -92,7 +95,8 @@ METHOD(credential_set_t, create_private_enumerator, enumerator_t*,
 
 	INIT(e,
 		.public = {
-			.enumerate = (void*)_private_enumerator_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _private_enumerator_enumerate,
 			.destroy = _private_enumerator_destroy,
 		},
 	);
@@ -123,11 +127,14 @@ typedef struct {
 } cert_enumerator_t;
 
 METHOD(enumerator_t, cert_enumerator_enumerate, bool,
-	cert_enumerator_t *this, certificate_t **cert)
+	cert_enumerator_t *this, va_list args)
 {
+	certificate_t **cert;
 	public_key_t *public;
 	chunk_t chunk;
 
+	VA_ARGS_VGET(args, cert);
+
 	DESTROY_IF(this->current);
 	while (this->inner->enumerate(this->inner, &chunk))
 	{
@@ -180,7 +187,8 @@ METHOD(credential_set_t, create_cert_enumerator, enumerator_t*,
 
 	INIT(e,
 		.public = {
-			.enumerate = (void*)_cert_enumerator_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _cert_enumerator_enumerate,
 			.destroy = _cert_enumerator_destroy,
 		},
 		.type = key,
diff --git a/src/libcharon/plugins/medcli/medcli_creds.h b/src/libcharon/plugins/medcli/medcli_creds.h
index 4b54026..ec17955 100644
--- a/src/libcharon/plugins/medcli/medcli_creds.h
+++ b/src/libcharon/plugins/medcli/medcli_creds.h
@@ -37,7 +37,7 @@ struct medcli_creds_t {
 	credential_set_t set;
 
 	/**
-	 * Destroy the credentials databse.
+	 * Destroy the credentials database.
 	 */
 	void (*destroy)(medcli_creds_t *this);
 };
diff --git a/src/libcharon/plugins/medcli/medcli_listener.h b/src/libcharon/plugins/medcli/medcli_listener.h
index 4768bec..860dcdc 100644
--- a/src/libcharon/plugins/medcli/medcli_listener.h
+++ b/src/libcharon/plugins/medcli/medcli_listener.h
@@ -37,7 +37,7 @@ struct medcli_listener_t {
 	listener_t listener;
 
 	/**
-	 * Destroy the credentials databse.
+	 * Destroy the credentials database.
 	 */
 	void (*destroy)(medcli_listener_t *this);
 };
diff --git a/src/libcharon/plugins/medsrv/Makefile.in b/src/libcharon/plugins/medsrv/Makefile.in
index ceb06de..10b48da 100644
--- a/src/libcharon/plugins/medsrv/Makefile.in
+++ b/src/libcharon/plugins/medsrv/Makefile.in
@@ -358,6 +358,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/medsrv/medsrv_creds.c b/src/libcharon/plugins/medsrv/medsrv_creds.c
index 0d99c4f..16d4bd7 100644
--- a/src/libcharon/plugins/medsrv/medsrv_creds.c
+++ b/src/libcharon/plugins/medsrv/medsrv_creds.c
@@ -52,12 +52,14 @@ typedef struct {
 } cert_enumerator_t;
 
 METHOD(enumerator_t, cert_enumerator_enumerate, bool,
-	cert_enumerator_t *this, certificate_t **cert)
+	cert_enumerator_t *this, va_list args)
 {
-	certificate_t *trusted;
+	certificate_t *trusted, **cert;
 	public_key_t *public;
 	chunk_t chunk;
 
+	VA_ARGS_VGET(args, cert);
+
 	DESTROY_IF(this->current);
 	while (this->inner->enumerate(this->inner, &chunk))
 	{
@@ -110,7 +112,8 @@ METHOD(credential_set_t, create_cert_enumerator, enumerator_t*,
 
 	INIT(e,
 		.public = {
-			.enumerate = (void*)_cert_enumerator_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _cert_enumerator_enumerate,
 			.destroy = _cert_enumerator_destroy,
 		},
 		.type = key,
diff --git a/src/libcharon/plugins/medsrv/medsrv_creds.h b/src/libcharon/plugins/medsrv/medsrv_creds.h
index 2079601..08ecaa3 100644
--- a/src/libcharon/plugins/medsrv/medsrv_creds.h
+++ b/src/libcharon/plugins/medsrv/medsrv_creds.h
@@ -37,7 +37,7 @@ struct medsrv_creds_t {
 	credential_set_t set;
 
 	/**
-	 * Destroy the credentials databse.
+	 * Destroy the credentials database.
 	 */
 	void (*destroy)(medsrv_creds_t *this);
 };
diff --git a/src/libcharon/plugins/osx_attr/Makefile.in b/src/libcharon/plugins/osx_attr/Makefile.in
index ab9ece5..8e0b10e 100644
--- a/src/libcharon/plugins/osx_attr/Makefile.in
+++ b/src/libcharon/plugins/osx_attr/Makefile.in
@@ -358,6 +358,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/osx_attr/osx_attr_handler.c b/src/libcharon/plugins/osx_attr/osx_attr_handler.c
index 6baf76d..e7a627b 100644
--- a/src/libcharon/plugins/osx_attr/osx_attr_handler.c
+++ b/src/libcharon/plugins/osx_attr/osx_attr_handler.c
@@ -218,12 +218,15 @@ METHOD(attribute_handler_t, release, void,
 }
 
 METHOD(enumerator_t, enumerate_dns, bool,
-	enumerator_t *this, configuration_attribute_type_t *type, chunk_t *data)
+	enumerator_t *this, va_list args)
 {
+	configuration_attribute_type_t *type;
+	chunk_t *data;
+
+	VA_ARGS_VGET(args, type, data);
 	*type = INTERNAL_IP4_DNS;
 	*data = chunk_empty;
-	/* stop enumeration */
-	this->enumerate = (void*)return_false;
+	this->venumerate = (void*)return_false;
 	return TRUE;
 }
 
@@ -234,7 +237,8 @@ METHOD(attribute_handler_t, create_attribute_enumerator, enumerator_t *,
 	enumerator_t *enumerator;
 
 	INIT(enumerator,
-		.enumerate = (void*)_enumerate_dns,
+		.enumerate = enumerator_enumerate_default,
+		.venumerate = _enumerate_dns,
 		.destroy = (void*)free,
 	);
 	return enumerator;
diff --git a/src/libcharon/plugins/p_cscf/Makefile.in b/src/libcharon/plugins/p_cscf/Makefile.in
index 7b3cb2f..954a43d 100644
--- a/src/libcharon/plugins/p_cscf/Makefile.in
+++ b/src/libcharon/plugins/p_cscf/Makefile.in
@@ -358,6 +358,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/p_cscf/p_cscf_handler.c b/src/libcharon/plugins/p_cscf/p_cscf_handler.c
index 7663384..cdf2660 100644
--- a/src/libcharon/plugins/p_cscf/p_cscf_handler.c
+++ b/src/libcharon/plugins/p_cscf/p_cscf_handler.c
@@ -83,9 +83,12 @@ typedef struct {
 } attr_enumerator_t;
 
 METHOD(enumerator_t, enumerate_attrs, bool,
-	attr_enumerator_t *this, configuration_attribute_type_t *type,
-	chunk_t *data)
+	attr_enumerator_t *this, va_list args)
 {
+	configuration_attribute_type_t *type;
+	chunk_t *data;
+
+	VA_ARGS_VGET(args, type, data);
 	if (this->request_ipv4)
 	{
 		*type = P_CSCF_IP4_ADDRESS;
@@ -103,12 +106,13 @@ METHOD(enumerator_t, enumerate_attrs, bool,
 	return FALSE;
 }
 
-/**
- * Check if the given host has a matching address family
- */
-static bool is_family(host_t *host, int *family)
+CALLBACK(is_family, bool,
+	host_t *host, va_list args)
 {
-	return host->get_family(host) == *family;
+	int family;
+
+	VA_ARGS_VGET(args, family);
+	return host->get_family(host) == family;
 }
 
 /**
@@ -116,7 +120,7 @@ static bool is_family(host_t *host, int *family)
  */
 static bool has_host_family(linked_list_t *list, int family)
 {
-	return list->find_first(list, (void*)is_family, NULL, &family) == SUCCESS;
+	return list->find_first(list, is_family, NULL, family);
 }
 
 METHOD(attribute_handler_t, create_attribute_enumerator, enumerator_t *,
@@ -132,7 +136,8 @@ METHOD(attribute_handler_t, create_attribute_enumerator, enumerator_t *,
 
 	INIT(enumerator,
 		.public = {
-			.enumerate = (void*)_enumerate_attrs,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _enumerate_attrs,
 			.destroy = (void*)free,
 		},
 	);
diff --git a/src/libcharon/plugins/radattr/Makefile.in b/src/libcharon/plugins/radattr/Makefile.in
index 1fe3033..add1f54 100644
--- a/src/libcharon/plugins/radattr/Makefile.in
+++ b/src/libcharon/plugins/radattr/Makefile.in
@@ -359,6 +359,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -381,6 +382,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/resolve/Makefile.in b/src/libcharon/plugins/resolve/Makefile.in
index f8b62ed..5e166f2 100644
--- a/src/libcharon/plugins/resolve/Makefile.in
+++ b/src/libcharon/plugins/resolve/Makefile.in
@@ -358,6 +358,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/resolve/resolve_handler.c b/src/libcharon/plugins/resolve/resolve_handler.c
index 9077b51..05b8654 100644
--- a/src/libcharon/plugins/resolve/resolve_handler.c
+++ b/src/libcharon/plugins/resolve/resolve_handler.c
@@ -391,10 +391,13 @@ typedef struct {
 	bool v6;
 } attribute_enumerator_t;
 
-static bool attribute_enumerate(attribute_enumerator_t *this,
-								configuration_attribute_type_t *type,
-								chunk_t *data)
+METHOD(enumerator_t, attribute_enumerate, bool,
+	attribute_enumerator_t *this, va_list args)
 {
+	configuration_attribute_type_t *type;
+	chunk_t *data;
+
+	VA_ARGS_VGET(args, type, data);
 	if (this->v4)
 	{
 		*type = INTERNAL_IP4_DNS;
@@ -443,7 +446,8 @@ METHOD(attribute_handler_t, create_attribute_enumerator, enumerator_t*,
 
 	INIT(enumerator,
 		.public = {
-			.enumerate = (void*)attribute_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _attribute_enumerate,
 			.destroy = (void*)free,
 		},
 		.v4 = has_host_family(vips, AF_INET),
diff --git a/src/libcharon/plugins/smp/Makefile.in b/src/libcharon/plugins/smp/Makefile.in
index bf0791c..9aac318 100644
--- a/src/libcharon/plugins/smp/Makefile.in
+++ b/src/libcharon/plugins/smp/Makefile.in
@@ -356,6 +356,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -378,6 +379,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/socket_default/Makefile.in b/src/libcharon/plugins/socket_default/Makefile.in
index f66ae16..b87afa4 100644
--- a/src/libcharon/plugins/socket_default/Makefile.in
+++ b/src/libcharon/plugins/socket_default/Makefile.in
@@ -358,6 +358,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/socket_default/socket_default_socket.c b/src/libcharon/plugins/socket_default/socket_default_socket.c
index ba22b0c..109b3fe 100644
--- a/src/libcharon/plugins/socket_default/socket_default_socket.c
+++ b/src/libcharon/plugins/socket_default/socket_default_socket.c
@@ -142,6 +142,11 @@ struct private_socket_default_socket_t {
 	bool set_source;
 
 	/**
+	 * TRUE to force sending source interface on outbound packetrs
+	 */
+	bool set_sourceif;
+
+	/**
 	 * A counter to implement round-robin selection of read sockets
 	 */
 	u_int rr_counter;
@@ -362,12 +367,33 @@ static ssize_t send_msg_generic(int skt, struct msghdr *msg)
 	return sendmsg(skt, msg, 0);
 }
 
+#if defined(IP_PKTINFO) || defined(HAVE_IN6_PKTINFO)
+
+/**
+ * Find the interface index a source address is installed on
+ */
+static int find_srcif(host_t *src)
+{
+	char *ifname;
+	int idx = 0;
+
+	if (charon->kernel->get_interface(charon->kernel, src, &ifname))
+	{
+		idx = if_nametoindex(ifname);
+		free(ifname);
+	}
+	return idx;
+}
+
+#endif /* IP_PKTINFO || HAVE_IN6_PKTINFO */
+
 /**
  * Send a message with the IPv4 source address set, if possible.
  */
 #ifdef IP_PKTINFO
 
-static ssize_t send_msg_v4(int skt, struct msghdr *msg, host_t *src)
+static ssize_t send_msg_v4(private_socket_default_socket_t *this, int skt,
+						   struct msghdr *msg, host_t *src)
 {
 	char buf[CMSG_SPACE(sizeof(struct in_pktinfo))] = {};
 	struct cmsghdr *cmsg;
@@ -383,6 +409,10 @@ static ssize_t send_msg_v4(int skt, struct msghdr *msg, host_t *src)
 	cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
 
 	pktinfo = (struct in_pktinfo*)CMSG_DATA(cmsg);
+	if (this->set_sourceif)
+	{
+		pktinfo->ipi_ifindex = find_srcif(src);
+	}
 	addr = &pktinfo->ipi_spec_dst;
 
 	sin = (struct sockaddr_in*)src->get_sockaddr(src);
@@ -392,7 +422,8 @@ static ssize_t send_msg_v4(int skt, struct msghdr *msg, host_t *src)
 
 #elif defined(IP_SENDSRCADDR)
 
-static ssize_t send_msg_v4(int skt, struct msghdr *msg, host_t *src)
+static ssize_t send_msg_v4(private_socket_default_socket_t *this, int skt,
+						   struct msghdr *msg, host_t *src)
 {
 	char buf[CMSG_SPACE(sizeof(struct in_addr))] = {};
 	struct cmsghdr *cmsg;
@@ -415,7 +446,8 @@ static ssize_t send_msg_v4(int skt, struct msghdr *msg, host_t *src)
 
 #else /* IP_PKTINFO || IP_RECVDSTADDR */
 
-static ssize_t send_msg_v4(int skt, struct msghdr *msg, host_t *src)
+static ssize_t send_msg_v4(private_socket_default_socket_t *this,
+						   int skt, struct msghdr *msg, host_t *src)
 {
 	return send_msg_generic(skt, msg);
 }
@@ -427,7 +459,8 @@ static ssize_t send_msg_v4(int skt, struct msghdr *msg, host_t *src)
  */
 #ifdef HAVE_IN6_PKTINFO
 
-static ssize_t send_msg_v6(int skt, struct msghdr *msg, host_t *src)
+static ssize_t send_msg_v6(private_socket_default_socket_t *this, int skt,
+						   struct msghdr *msg, host_t *src)
 {
 	char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))] = {};
 	struct cmsghdr *cmsg;
@@ -441,6 +474,10 @@ static ssize_t send_msg_v6(int skt, struct msghdr *msg, host_t *src)
 	cmsg->cmsg_type = IPV6_PKTINFO;
 	cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
 	pktinfo = (struct in6_pktinfo*)CMSG_DATA(cmsg);
+	if (this->set_sourceif)
+	{
+		pktinfo->ipi6_ifindex = find_srcif(src);
+	}
 	sin = (struct sockaddr_in6*)src->get_sockaddr(src);
 	memcpy(&pktinfo->ipi6_addr, &sin->sin6_addr, sizeof(struct in6_addr));
 	return send_msg_generic(skt, msg);
@@ -448,7 +485,8 @@ static ssize_t send_msg_v6(int skt, struct msghdr *msg, host_t *src)
 
 #else /* HAVE_IN6_PKTINFO */
 
-static ssize_t send_msg_v6(int skt, struct msghdr *msg, host_t *src)
+static ssize_t send_msg_v6(private_socket_default_socket_t *this,
+						   int skt, struct msghdr *msg, host_t *src)
 {
 	return send_msg_generic(skt, msg);
 }
@@ -564,11 +602,11 @@ METHOD(socket_t, sender, status_t,
 	{
 		if (family == AF_INET)
 		{
-			bytes_sent = send_msg_v4(skt, &msg, src);
+			bytes_sent = send_msg_v4(this, skt, &msg, src);
 		}
 		else
 		{
-			bytes_sent = send_msg_v6(skt, &msg, src);
+			bytes_sent = send_msg_v6(this, skt, &msg, src);
 		}
 	}
 	else
@@ -831,6 +869,9 @@ socket_default_socket_t *socket_default_socket_create()
 		.set_source = lib->settings->get_bool(lib->settings,
 							"%s.plugins.socket-default.set_source", TRUE,
 							lib->ns),
+		.set_sourceif = lib->settings->get_bool(lib->settings,
+							"%s.plugins.socket-default.set_sourceif", FALSE,
+							lib->ns),
 	);
 
 	if (this->port && this->port == this->natt)
diff --git a/src/libcharon/plugins/socket_dynamic/Makefile.in b/src/libcharon/plugins/socket_dynamic/Makefile.in
index 3d07b54..595651f 100644
--- a/src/libcharon/plugins/socket_dynamic/Makefile.in
+++ b/src/libcharon/plugins/socket_dynamic/Makefile.in
@@ -358,6 +358,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/socket_win/Makefile.in b/src/libcharon/plugins/socket_win/Makefile.in
index 6924898..8f1e439 100644
--- a/src/libcharon/plugins/socket_win/Makefile.in
+++ b/src/libcharon/plugins/socket_win/Makefile.in
@@ -358,6 +358,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/sql/Makefile.in b/src/libcharon/plugins/sql/Makefile.in
index 581225b..5c14619 100644
--- a/src/libcharon/plugins/sql/Makefile.in
+++ b/src/libcharon/plugins/sql/Makefile.in
@@ -356,6 +356,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -378,6 +379,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/sql/sql_config.c b/src/libcharon/plugins/sql/sql_config.c
index 88cac7f..00ed693 100644
--- a/src/libcharon/plugins/sql/sql_config.c
+++ b/src/libcharon/plugins/sql/sql_config.c
@@ -173,7 +173,8 @@ static child_cfg_t *build_child_cfg(private_sql_config_t *this, enumerator_t *e)
 		child_cfg_create_t child = {
 			.mode = mode,
 			.reqid = reqid,
-			.ipcomp = ipcomp,
+			.options = (ipcomp ? OPT_IPCOMP : 0) |
+					   (hostaccess ? OPT_HOSTACCESS : 0),
 			.lifetime = {
 				.time = {
 					.life = lifetime, .rekey = rekeytime, .jitter = jitter
@@ -183,7 +184,6 @@ static child_cfg_t *build_child_cfg(private_sql_config_t *this, enumerator_t *e)
 			.dpd_action = dpd,
 			.close_action = close,
 			.updown = updown,
-			.hostaccess = hostaccess,
 		};
 		child_cfg = child_cfg_create(name, &child);
 		add_esp_proposals(this, child_cfg, id);
@@ -504,11 +504,12 @@ typedef struct {
 	ike_cfg_t *current;
 } ike_enumerator_t;
 
-/**
- * Implementation of ike_enumerator_t.public.enumerate
- */
-static bool ike_enumerator_enumerate(ike_enumerator_t *this, ike_cfg_t **cfg)
+METHOD(enumerator_t, ike_enumerator_enumerate, bool,
+	ike_enumerator_t *this, va_list args)
 {
+	ike_cfg_t **cfg;
+
+	VA_ARGS_VGET(args, cfg);
 	DESTROY_IF(this->current);
 	this->current = build_ike_cfg(this->this, this->inner, this->me, this->other);
 	if (this->current)
@@ -519,10 +520,8 @@ static bool ike_enumerator_enumerate(ike_enumerator_t *this, ike_cfg_t **cfg)
 	return FALSE;
 }
 
-/**
- * Implementation of ike_enumerator_t.public.destroy
- */
-static void ike_enumerator_destroy(ike_enumerator_t *this)
+METHOD(enumerator_t, ike_enumerator_destroy, void,
+	ike_enumerator_t *this)
 {
 	DESTROY_IF(this->current);
 	this->inner->destroy(this->inner);
@@ -532,19 +531,22 @@ static void ike_enumerator_destroy(ike_enumerator_t *this)
 METHOD(backend_t, create_ike_cfg_enumerator, enumerator_t*,
 	private_sql_config_t *this, host_t *me, host_t *other)
 {
-	ike_enumerator_t *e = malloc_thing(ike_enumerator_t);
-
-	e->this = this;
-	e->me = me;
-	e->other = other;
-	e->current = NULL;
-	e->public.enumerate = (void*)ike_enumerator_enumerate;
-	e->public.destroy = (void*)ike_enumerator_destroy;
+	ike_enumerator_t *e;
 
+	INIT(e,
+		.public = {
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _ike_enumerator_enumerate,
+			.destroy = _ike_enumerator_destroy,
+		},
+		.this = this,
+		.me = me,
+		.other = other,
+	);
 	e->inner = this->db->query(this->db,
-			"SELECT id, certreq, force_encap, local, remote "
-			"FROM ike_configs",
-			DB_INT, DB_INT, DB_INT, DB_TEXT, DB_TEXT);
+							   "SELECT id, certreq, force_encap, local, remote "
+							   "FROM ike_configs",
+							   DB_INT, DB_INT, DB_INT, DB_TEXT, DB_TEXT);
 	if (!e->inner)
 	{
 		free(e);
@@ -569,11 +571,12 @@ typedef struct {
 	peer_cfg_t *current;
 } peer_enumerator_t;
 
-/**
- * Implementation of peer_enumerator_t.public.enumerate
- */
-static bool peer_enumerator_enumerate(peer_enumerator_t *this, peer_cfg_t **cfg)
+METHOD(enumerator_t, peer_enumerator_enumerate, bool,
+	peer_enumerator_t *this, va_list args)
 {
+	peer_cfg_t **cfg;
+
+	VA_ARGS_VGET(args, cfg);
 	DESTROY_IF(this->current);
 	this->current = build_peer_cfg(this->this, this->inner, this->me, this->other);
 	if (this->current)
@@ -584,10 +587,8 @@ static bool peer_enumerator_enumerate(peer_enumerator_t *this, peer_cfg_t **cfg)
 	return FALSE;
 }
 
-/**
- * Implementation of peer_enumerator_t.public.destroy
- */
-static void peer_enumerator_destroy(peer_enumerator_t *this)
+METHOD(enumerator_t, peer_enumerator_destroy, void,
+	peer_enumerator_t *this)
 {
 	DESTROY_IF(this->current);
 	this->inner->destroy(this->inner);
@@ -597,14 +598,18 @@ static void peer_enumerator_destroy(peer_enumerator_t *this)
 METHOD(backend_t, create_peer_cfg_enumerator, enumerator_t*,
 	private_sql_config_t *this, identification_t *me, identification_t *other)
 {
-	peer_enumerator_t *e = malloc_thing(peer_enumerator_t);
-
-	e->this = this;
-	e->me = me;
-	e->other = other;
-	e->current = NULL;
-	e->public.enumerate = (void*)peer_enumerator_enumerate;
-	e->public.destroy = (void*)peer_enumerator_destroy;
+	peer_enumerator_t *e;
+
+	INIT(e,
+		.public = {
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _peer_enumerator_enumerate,
+			.destroy = _peer_enumerator_destroy,
+		},
+		.this = this,
+		.me = me,
+		.other = other,
+	);
 
 	/* TODO: only get configs whose IDs match exactly or contain wildcards */
 	e->inner = this->db->query(this->db,
diff --git a/src/libcharon/plugins/sql/sql_cred.c b/src/libcharon/plugins/sql/sql_cred.c
index 117eec9..3317de6 100644
--- a/src/libcharon/plugins/sql/sql_cred.c
+++ b/src/libcharon/plugins/sql/sql_cred.c
@@ -52,11 +52,14 @@ typedef struct {
 } private_enumerator_t;
 
 METHOD(enumerator_t, private_enumerator_enumerate, bool,
-	   private_enumerator_t *this, private_key_t **key)
+	   private_enumerator_t *this, va_list args)
 {
+	private_key_t **key;
 	chunk_t blob;
 	int type;
 
+	VA_ARGS_VGET(args, key);
+
 	DESTROY_IF(this->current);
 	while (this->inner->enumerate(this->inner, &type, &blob))
 	{
@@ -88,7 +91,8 @@ METHOD(credential_set_t, create_private_enumerator, enumerator_t*,
 
 	INIT(e,
 		.public = {
-			.enumerate = (void*)_private_enumerator_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _private_enumerator_enumerate,
 			.destroy = _private_enumerator_destroy,
 		},
 	);
@@ -132,11 +136,14 @@ typedef struct {
 } cert_enumerator_t;
 
 METHOD(enumerator_t, cert_enumerator_enumerate, bool,
-	   cert_enumerator_t *this, certificate_t **cert)
+	   cert_enumerator_t *this, va_list args)
 {
+	certificate_t **cert;
 	chunk_t blob;
 	int type;
 
+	VA_ARGS_VGET(args, cert);
+
 	DESTROY_IF(this->current);
 	while (this->inner->enumerate(this->inner, &type, &blob))
 	{
@@ -169,7 +176,8 @@ METHOD(credential_set_t, create_cert_enumerator, enumerator_t*,
 
 	INIT(e,
 		.public = {
-			.enumerate = (void*)_cert_enumerator_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _cert_enumerator_enumerate,
 			.destroy = _cert_enumerator_destroy,
 		},
 	);
@@ -221,12 +229,15 @@ typedef struct {
 } shared_enumerator_t;
 
 METHOD(enumerator_t, shared_enumerator_enumerate, bool,
-	   shared_enumerator_t *this, shared_key_t **shared,
-	   id_match_t *me, id_match_t *other)
+	   shared_enumerator_t *this, va_list args)
 {
+	shared_key_t **shared;
+	id_match_t *me, *other;
 	chunk_t blob;
 	int type;
 
+	VA_ARGS_VGET(args, shared, me, other);
+
 	DESTROY_IF(this->current);
 	while (this->inner->enumerate(this->inner, &type, &blob))
 	{
@@ -265,7 +276,8 @@ METHOD(credential_set_t, create_shared_enumerator, enumerator_t*,
 
 	INIT(e,
 		.public = {
-			.enumerate = (void*)_shared_enumerator_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _shared_enumerator_enumerate,
 			.destroy = _shared_enumerator_destroy,
 		},
 		.me = me,
@@ -340,9 +352,11 @@ typedef enum {
 } cdp_type_t;
 
 METHOD(enumerator_t, cdp_enumerator_enumerate, bool,
-	   cdp_enumerator_t *this, char **uri)
+	   cdp_enumerator_t *this, va_list args)
 {
-	char *text;
+	char *text, **uri;
+
+	VA_ARGS_VGET(args, uri);
 
 	free(this->current);
 	while (this->inner->enumerate(this->inner, &text))
@@ -384,7 +398,8 @@ METHOD(credential_set_t, create_cdp_enumerator, enumerator_t*,
 	}
 	INIT(e,
 		.public = {
-			.enumerate = (void*)_cdp_enumerator_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _cdp_enumerator_enumerate,
 			.destroy = _cdp_enumerator_destroy,
 		},
 	);
diff --git a/src/libcharon/plugins/stroke/Makefile.in b/src/libcharon/plugins/stroke/Makefile.in
index 50a6d59..0af607f 100644
--- a/src/libcharon/plugins/stroke/Makefile.in
+++ b/src/libcharon/plugins/stroke/Makefile.in
@@ -360,6 +360,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -382,6 +383,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/stroke/stroke_attribute.c b/src/libcharon/plugins/stroke/stroke_attribute.c
index cd1b4d0..7835031 100644
--- a/src/libcharon/plugins/stroke/stroke_attribute.c
+++ b/src/libcharon/plugins/stroke/stroke_attribute.c
@@ -178,28 +178,32 @@ METHOD(attribute_provider_t, release_address, bool,
 	return found;
 }
 
-/**
- * Filter function to convert host to DNS configuration attributes
- */
-static bool attr_filter(void *lock, host_t **in,
-						configuration_attribute_type_t *type,
-						void *dummy, chunk_t *data)
+CALLBACK(attr_filter, bool,
+	void *lock, enumerator_t *orig, va_list args)
 {
-	host_t *host = *in;
+	configuration_attribute_type_t *type;
+	chunk_t *data;
+	host_t *host;
 
-	switch (host->get_family(host))
+	VA_ARGS_VGET(args, type, data);
+
+	while (orig->enumerate(orig, &host))
 	{
-		case AF_INET:
-			*type = INTERNAL_IP4_DNS;
-			break;
-		case AF_INET6:
-			*type = INTERNAL_IP6_DNS;
-			break;
-		default:
-			return FALSE;
+		switch (host->get_family(host))
+		{
+			case AF_INET:
+				*type = INTERNAL_IP4_DNS;
+				break;
+			case AF_INET6:
+				*type = INTERNAL_IP6_DNS;
+				break;
+			default:
+				continue;
+		}
+		*data = host->get_address(host);
+		return TRUE;
 	}
-	*data = host->get_address(host);
-	return TRUE;
+	return FALSE;
 }
 
 METHOD(attribute_provider_t, create_attribute_enumerator, enumerator_t*,
@@ -223,7 +227,7 @@ METHOD(attribute_provider_t, create_attribute_enumerator, enumerator_t*,
 				enumerator->destroy(enumerator);
 				return enumerator_create_filter(
 									attr->dns->create_enumerator(attr->dns),
-									(void*)attr_filter, this->lock,
+									attr_filter, this->lock,
 									(void*)this->lock->unlock);
 			}
 		}
@@ -338,24 +342,28 @@ METHOD(stroke_attribute_t, del_dns, void,
 	this->lock->unlock(this->lock);
 }
 
-/**
- * Pool enumerator filter function, converts pool_t to name, size, ...
- */
-static bool pool_filter(void *lock, mem_pool_t **poolp, const char **name,
-						void *d1, u_int *size, void *d2, u_int *online,
-						void *d3, u_int *offline)
+CALLBACK(pool_filter, bool,
+	void *lock, enumerator_t *orig, va_list args)
 {
-	mem_pool_t *pool = *poolp;
+	mem_pool_t *pool;
+	const char **name;
+	u_int *size, *online, *offline;
 
-	if (pool->get_size(pool) == 0)
+	VA_ARGS_VGET(args, name, size, online, offline);
+
+	while (orig->enumerate(orig, &pool))
 	{
-		return FALSE;
+		if (pool->get_size(pool) == 0)
+		{
+			continue;
+		}
+		*name = pool->get_name(pool);
+		*size = pool->get_size(pool);
+		*online = pool->get_online(pool);
+		*offline = pool->get_offline(pool);
+		return TRUE;
 	}
-	*name = pool->get_name(pool);
-	*size = pool->get_size(pool);
-	*online = pool->get_online(pool);
-	*offline = pool->get_offline(pool);
-	return TRUE;
+	return FALSE;
 }
 
 METHOD(stroke_attribute_t, create_pool_enumerator, enumerator_t*,
@@ -363,7 +371,7 @@ METHOD(stroke_attribute_t, create_pool_enumerator, enumerator_t*,
 {
 	this->lock->read_lock(this->lock);
 	return enumerator_create_filter(this->pools->create_enumerator(this->pools),
-									(void*)pool_filter,
+									pool_filter,
 									this->lock, (void*)this->lock->unlock);
 }
 
diff --git a/src/libcharon/plugins/stroke/stroke_ca.c b/src/libcharon/plugins/stroke/stroke_ca.c
index 13ed41e..4593e9b 100644
--- a/src/libcharon/plugins/stroke/stroke_ca.c
+++ b/src/libcharon/plugins/stroke/stroke_ca.c
@@ -171,26 +171,30 @@ typedef struct {
 	identification_t *id;
 } cert_data_t;
 
-/**
- * destroy cert_data
- */
-static void cert_data_destroy(cert_data_t *data)
+CALLBACK(cert_data_destroy, void,
+	cert_data_t *data)
 {
 	data->this->lock->unlock(data->this->lock);
 	free(data);
 }
 
-/**
- * filter function for certs enumerator
- */
-static bool certs_filter(cert_data_t *data, ca_cert_t **in,
-						 certificate_t **out)
+CALLBACK(certs_filter, bool,
+	cert_data_t *data, enumerator_t *orig, va_list args)
 {
+	ca_cert_t *cacert;
 	public_key_t *public;
-	certificate_t *cert = (*in)->cert;
+	certificate_t **out;
+
+	VA_ARGS_VGET(args, out);
 
-	if (data->cert == CERT_ANY || data->cert == cert->get_type(cert))
+	while (orig->enumerate(orig, &cacert))
 	{
+		certificate_t *cert = cacert->cert;
+
+		if (data->cert != CERT_ANY && data->cert != cert->get_type(cert))
+		{
+			continue;
+		}
 		public = cert->get_public_key(cert);
 		if (public)
 		{
@@ -208,9 +212,9 @@ static bool certs_filter(cert_data_t *data, ca_cert_t **in,
 		}
 		else if (data->key != KEY_ANY)
 		{
-			return FALSE;
+			continue;
 		}
-		if (data->id == NULL || cert->has_subject(cert, data->id))
+		if (!data->id || cert->has_subject(cert, data->id))
 		{
 			*out = cert;
 			return TRUE;
@@ -235,8 +239,8 @@ METHOD(credential_set_t, create_cert_enumerator, enumerator_t*,
 
 	this->lock->read_lock(this->lock);
 	enumerator = this->certs->create_enumerator(this->certs);
-	return enumerator_create_filter(enumerator, (void*)certs_filter, data,
-									(void*)cert_data_destroy);
+	return enumerator_create_filter(enumerator, certs_filter, data,
+									cert_data_destroy);
 }
 
 /**
@@ -354,11 +358,12 @@ METHOD(credential_set_t, create_cdp_enumerator, enumerator_t*,
 			data, (void*)cdp_data_destroy);
 }
 
-/**
- * Compare the given certificate to the ca_cert_t items in the list
- */
-static bool match_cert(ca_cert_t *item, certificate_t *cert)
+CALLBACK(match_cert, bool,
+	ca_cert_t *item, va_list args)
 {
+	certificate_t *cert;
+
+	VA_ARGS_VGET(args, cert);
 	return cert->equals(cert, item->cert);
 }
 
@@ -405,8 +410,7 @@ static certificate_t *add_cert_internal(private_stroke_ca_t *this,
 {
 	ca_cert_t *found;
 
-	if (this->certs->find_first(this->certs, (linked_list_match_t)match_cert,
-								(void**)&found, cert) == SUCCESS)
+	if (this->certs->find_first(this->certs, match_cert, (void**)&found, cert))
 	{
 		cert->destroy(cert);
 		cert = found->cert->get_ref(found->cert);
@@ -511,8 +515,7 @@ METHOD(stroke_ca_t, get_cert_ref, certificate_t*,
 	ca_cert_t *found;
 
 	this->lock->read_lock(this->lock);
-	if (this->certs->find_first(this->certs, (linked_list_match_t)match_cert,
-								(void**)&found, cert) == SUCCESS)
+	if (this->certs->find_first(this->certs, match_cert, (void**)&found, cert))
 	{
 		cert->destroy(cert);
 		cert = found->cert->get_ref(found->cert);
diff --git a/src/libcharon/plugins/stroke/stroke_config.c b/src/libcharon/plugins/stroke/stroke_config.c
index bbdc211..00f7483 100644
--- a/src/libcharon/plugins/stroke/stroke_config.c
+++ b/src/libcharon/plugins/stroke/stroke_config.c
@@ -68,13 +68,20 @@ METHOD(backend_t, create_peer_cfg_enumerator, enumerator_t*,
 									 (void*)this->mutex->unlock, this->mutex);
 }
 
-/**
- * filter function for ike configs
- */
-static bool ike_filter(void *data, peer_cfg_t **in, ike_cfg_t **out)
+CALLBACK(ike_filter, bool,
+	void *data, enumerator_t *orig, va_list args)
 {
-	*out = (*in)->get_ike_cfg(*in);
-	return TRUE;
+	peer_cfg_t *cfg;
+	ike_cfg_t **out;
+
+	VA_ARGS_VGET(args, out);
+
+	if (orig->enumerate(orig, &cfg))
+	{
+		*out = cfg->get_ike_cfg(cfg);
+		return TRUE;
+	}
+	return FALSE;
 }
 
 METHOD(backend_t, create_ike_cfg_enumerator, enumerator_t*,
@@ -82,7 +89,7 @@ METHOD(backend_t, create_ike_cfg_enumerator, enumerator_t*,
 {
 	this->mutex->lock(this->mutex);
 	return enumerator_create_filter(this->list->create_enumerator(this->list),
-									(void*)ike_filter, this->mutex,
+									ike_filter, this->mutex,
 									(void*)this->mutex->unlock);
 }
 
@@ -1071,15 +1078,16 @@ static child_cfg_t *build_child_cfg(private_stroke_config_t *this,
 		},
 		.reqid = msg->add_conn.reqid,
 		.mode = msg->add_conn.mode,
-		.proxy_mode = msg->add_conn.proxy_mode,
-		.ipcomp = msg->add_conn.ipcomp,
+		.options = (msg->add_conn.proxy_mode ? OPT_PROXY_MODE : 0) |
+				   (msg->add_conn.ipcomp ? OPT_IPCOMP : 0) |
+				   (msg->add_conn.me.hostaccess ? OPT_HOSTACCESS : 0) |
+				   (msg->add_conn.install_policy ? 0 : OPT_NO_POLICIES) |
+				   (msg->add_conn.sha256_96 ? OPT_SHA256_96 : 0),
 		.tfc = msg->add_conn.tfc,
 		.inactivity = msg->add_conn.inactivity,
 		.dpd_action = map_action(msg->add_conn.dpd.action),
 		.close_action = map_action(msg->add_conn.close_action),
 		.updown = msg->add_conn.me.updown,
-		.hostaccess = msg->add_conn.me.hostaccess,
-		.suppress_policies = !msg->add_conn.install_policy,
 	};
 
 	child_cfg = child_cfg_create(msg->add_conn.name, &child);
diff --git a/src/libcharon/plugins/stroke/stroke_handler.c b/src/libcharon/plugins/stroke/stroke_handler.c
index d0cc9af..19d5a62 100644
--- a/src/libcharon/plugins/stroke/stroke_handler.c
+++ b/src/libcharon/plugins/stroke/stroke_handler.c
@@ -62,35 +62,39 @@ static void attributes_destroy(attributes_t *this)
 	free(this);
 }
 
-/**
- * Filter function to convert host to DNS configuration attributes
- */
-static bool attr_filter(void *lock, host_t **in,
-						configuration_attribute_type_t *type,
-						void *dummy, chunk_t *data)
+CALLBACK(attr_filter, bool,
+	void *lock, enumerator_t *orig, va_list args)
 {
-	host_t *host = *in;
+	configuration_attribute_type_t *type;
+	chunk_t *data;
+	host_t *host;
 
-	switch (host->get_family(host))
-	{
-		case AF_INET:
-			*type = INTERNAL_IP4_DNS;
-			break;
-		case AF_INET6:
-			*type = INTERNAL_IP6_DNS;
-			break;
-		default:
-			return FALSE;
-	}
-	if (host->is_anyaddr(host))
-	{
-		*data = chunk_empty;
-	}
-	else
+	VA_ARGS_VGET(args, type, data);
+
+	while (orig->enumerate(orig, &host))
 	{
-		*data = host->get_address(host);
+		switch (host->get_family(host))
+		{
+			case AF_INET:
+				*type = INTERNAL_IP4_DNS;
+				break;
+			case AF_INET6:
+				*type = INTERNAL_IP6_DNS;
+				break;
+			default:
+				continue;
+		}
+		if (host->is_anyaddr(host))
+		{
+			*data = chunk_empty;
+		}
+		else
+		{
+			*data = host->get_address(host);
+		}
+		return TRUE;
 	}
-	return TRUE;
+	return FALSE;
 }
 
 METHOD(attribute_handler_t, create_attribute_enumerator, enumerator_t*,
@@ -114,7 +118,7 @@ METHOD(attribute_handler_t, create_attribute_enumerator, enumerator_t*,
 				enumerator->destroy(enumerator);
 				return enumerator_create_filter(
 									attr->dns->create_enumerator(attr->dns),
-									(void*)attr_filter, this->lock,
+									attr_filter, this->lock,
 									(void*)this->lock->unlock);
 			}
 		}
diff --git a/src/libcharon/plugins/stroke/stroke_list.c b/src/libcharon/plugins/stroke/stroke_list.c
index 92e3686..2299259 100644
--- a/src/libcharon/plugins/stroke/stroke_list.c
+++ b/src/libcharon/plugins/stroke/stroke_list.c
@@ -218,7 +218,7 @@ static void log_child_sa(FILE *out, child_sa_t *child_sa, bool all)
 			child_sa->get_name(child_sa), child_sa->get_unique_id(child_sa),
 			child_sa_state_names, child_sa->get_state(child_sa),
 			ipsec_mode_names, child_sa->get_mode(child_sa),
-			config->use_proxy_mode(config) ? "_PROXY" : "",
+			config->has_option(config, OPT_PROXY_MODE) ? "_PROXY" : "",
 			child_sa->get_reqid(child_sa));
 
 	if (child_sa->get_state(child_sa) == CHILD_INSTALLED)
@@ -958,8 +958,7 @@ static void list_plugins(FILE *out)
 				{
 					case FEATURE_PROVIDE:
 						fp = &features[i];
-						loaded = list->find_first(list, NULL,
-												  (void**)&fp) == SUCCESS;
+						loaded = list->find_first(list, NULL, (void**)&fp);
 						fprintf(out, "    %s%s\n",
 								str, loaded ? "" : " (not loaded)");
 						break;
diff --git a/src/libcharon/plugins/stroke/stroke_socket.c b/src/libcharon/plugins/stroke/stroke_socket.c
index 46de90c..65d345d 100644
--- a/src/libcharon/plugins/stroke/stroke_socket.c
+++ b/src/libcharon/plugins/stroke/stroke_socket.c
@@ -216,6 +216,7 @@ static void stroke_add_conn(private_stroke_socket_t *this, stroke_msg_t *msg)
 	DBG_OPT("  dpdtimeout=%d", msg->add_conn.dpd.timeout);
 	DBG_OPT("  dpdaction=%d", msg->add_conn.dpd.action);
 	DBG_OPT("  closeaction=%d", msg->add_conn.close_action);
+	DBG_OPT("  sha256_96=%s", msg->add_conn.sha256_96 ? "yes" : "no");
 	DBG_OPT("  mediation=%s", msg->add_conn.ikeme.mediation ? "yes" : "no");
 	DBG_OPT("  mediated_by=%s", msg->add_conn.ikeme.mediated_by);
 	DBG_OPT("  me_peerid=%s", msg->add_conn.ikeme.peerid);
diff --git a/src/libcharon/plugins/systime_fix/Makefile.in b/src/libcharon/plugins/systime_fix/Makefile.in
index 78fd6e8..3274430 100644
--- a/src/libcharon/plugins/systime_fix/Makefile.in
+++ b/src/libcharon/plugins/systime_fix/Makefile.in
@@ -358,6 +358,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/tnc_ifmap/Makefile.in b/src/libcharon/plugins/tnc_ifmap/Makefile.in
index 7ec4eaa..438001b 100644
--- a/src/libcharon/plugins/tnc_ifmap/Makefile.in
+++ b/src/libcharon/plugins/tnc_ifmap/Makefile.in
@@ -361,6 +361,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -383,6 +384,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/tnc_ifmap/tnc_ifmap_soap_msg.c b/src/libcharon/plugins/tnc_ifmap/tnc_ifmap_soap_msg.c
index b862886..db19bd5 100644
--- a/src/libcharon/plugins/tnc_ifmap/tnc_ifmap_soap_msg.c
+++ b/src/libcharon/plugins/tnc_ifmap/tnc_ifmap_soap_msg.c
@@ -55,7 +55,7 @@ struct private_tnc_ifmap_soap_msg_t {
 static xmlNodePtr find_child(xmlNodePtr parent, const xmlChar* name)
 {
 	xmlNodePtr child;
-	
+
 	child = parent->xmlChildrenNode;
 	while (child)
 	{
@@ -80,7 +80,7 @@ METHOD(tnc_ifmap_soap_msg_t, post, bool,
 	xmlChar *xml_str, *errorCode, *errorString;
 	int xml_len, len, written;
 	chunk_t xml, http;
-	char buf[4096];
+	char buf[4096] = { 0 };
 	status_t status;
 
 	DBG2(DBG_TNC, "sending ifmap %s", request->name);
@@ -131,7 +131,8 @@ METHOD(tnc_ifmap_soap_msg_t, post, bool,
 	xml = chunk_empty;
 	do
 	{
-		len = this->tls->read(this->tls, buf, sizeof(buf), TRUE);
+		/* reduce size so the buffer is null-terminated */
+		len = this->tls->read(this->tls, buf, sizeof(buf)-1, TRUE);
 		if (len <= 0)
 		{
 			return FALSE;
@@ -150,7 +151,7 @@ METHOD(tnc_ifmap_soap_msg_t, post, bool,
 	DBG3(DBG_TNC, "parsing XML message %B", &xml);
 	this->doc = xmlParseMemory(xml.ptr, xml.len);
 	free(xml.ptr);
-	
+
 	if (!this->doc)
 	{
 		DBG1(DBG_TNC, "failed to parse XML message");
diff --git a/src/libcharon/plugins/tnc_pdp/Makefile.in b/src/libcharon/plugins/tnc_pdp/Makefile.in
index 215e3b3..abc7743 100644
--- a/src/libcharon/plugins/tnc_pdp/Makefile.in
+++ b/src/libcharon/plugins/tnc_pdp/Makefile.in
@@ -362,6 +362,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -384,6 +385,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/uci/Makefile.in b/src/libcharon/plugins/uci/Makefile.in
index 64b4bca..46f4e4f 100644
--- a/src/libcharon/plugins/uci/Makefile.in
+++ b/src/libcharon/plugins/uci/Makefile.in
@@ -356,6 +356,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -378,6 +379,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/uci/uci_config.c b/src/libcharon/plugins/uci/uci_config.c
index e0578fe..dcd4ae3 100644
--- a/src/libcharon/plugins/uci/uci_config.c
+++ b/src/libcharon/plugins/uci/uci_config.c
@@ -118,11 +118,12 @@ static u_int create_rekey(char *string)
 }
 
 METHOD(enumerator_t, peer_enumerator_enumerate, bool,
-	peer_enumerator_t *this, peer_cfg_t **cfg)
+	peer_enumerator_t *this, va_list args)
 {
 	char *name, *ike_proposal, *esp_proposal, *ike_rekey, *esp_rekey;
 	char *local_id, *local_addr, *local_net;
 	char *remote_id, *remote_addr, *remote_net;
+	peer_cfg_t **cfg;
 	child_cfg_t *child_cfg;
 	ike_cfg_t *ike_cfg;
 	auth_cfg_t *auth;
@@ -145,6 +146,8 @@ METHOD(enumerator_t, peer_enumerator_enumerate, bool,
 		.mode = MODE_TUNNEL,
 	};
 
+	VA_ARGS_VGET(args, cfg);
+
 	/* defaults */
 	name = "unnamed";
 	local_id = NULL;
@@ -212,7 +215,8 @@ METHOD(backend_t, create_peer_cfg_enumerator, enumerator_t*,
 
 	INIT(e,
 		.public = {
-			.enumerate = (void*)_peer_enumerator_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _peer_enumerator_enumerate,
 			.destroy = _peer_enumerator_destroy,
 		},
 		.inner = this->parser->create_section_enumerator(this->parser,
@@ -241,10 +245,13 @@ typedef struct {
 } ike_enumerator_t;
 
 METHOD(enumerator_t, ike_enumerator_enumerate, bool,
-	ike_enumerator_t *this, ike_cfg_t **cfg)
+	ike_enumerator_t *this, va_list args)
 {
+	ike_cfg_t **cfg;
 	char *local_addr, *remote_addr, *ike_proposal;
 
+	VA_ARGS_VGET(args, cfg);
+
 	/* defaults */
 	local_addr = "0.0.0.0";
 	remote_addr = "0.0.0.0";
@@ -282,7 +289,8 @@ METHOD(backend_t, create_ike_cfg_enumerator, enumerator_t*,
 
 	INIT(e,
 		.public = {
-			.enumerate = (void*)_ike_enumerator_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _ike_enumerator_enumerate,
 			.destroy = _ike_enumerator_destroy,
 		},
 		.inner = this->parser->create_section_enumerator(this->parser,
diff --git a/src/libcharon/plugins/uci/uci_creds.c b/src/libcharon/plugins/uci/uci_creds.c
index f5d5ace..404a3e3 100644
--- a/src/libcharon/plugins/uci/uci_creds.c
+++ b/src/libcharon/plugins/uci/uci_creds.c
@@ -52,12 +52,15 @@ typedef struct {
 } shared_enumerator_t;
 
 METHOD(enumerator_t, shared_enumerator_enumerate, bool,
-	shared_enumerator_t *this, shared_key_t **key, id_match_t *me,
-	id_match_t *other)
+	shared_enumerator_t *this, va_list args)
 {
+	shared_key_t **key;
+	id_match_t *me, *other;
 	char *local_id, *remote_id, *psk;
 	identification_t *local, *remote;
 
+	VA_ARGS_VGET(args, key, me, other);
+
 	while (TRUE)
 	{
 		/* defaults */
@@ -126,7 +129,8 @@ METHOD(credential_set_t, create_shared_enumerator, enumerator_t*,
 
 	INIT(e,
 		.public = {
-			.enumerate = (void*)_shared_enumerator_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _shared_enumerator_enumerate,
 			.destroy = _shared_enumerator_destroy,
 		},
 		.me = me,
diff --git a/src/libcharon/plugins/uci/uci_parser.c b/src/libcharon/plugins/uci/uci_parser.c
index 2429e9e..e847dd3 100644
--- a/src/libcharon/plugins/uci/uci_parser.c
+++ b/src/libcharon/plugins/uci/uci_parser.c
@@ -58,11 +58,10 @@ typedef struct {
 } section_enumerator_t;
 
 METHOD(enumerator_t, section_enumerator_enumerate, bool,
-	section_enumerator_t *this, ...)
+	section_enumerator_t *this, va_list args)
 {
 	struct uci_element *element;
 	char **value;
-	va_list args;
 	int i;
 
 	if (&this->current->list == this->list)
@@ -70,8 +69,6 @@ METHOD(enumerator_t, section_enumerator_enumerate, bool,
 		return FALSE;
 	}
 
-	va_start(args, this);
-
 	value = va_arg(args, char**);
 	if (value)
 	{
@@ -96,7 +93,6 @@ METHOD(enumerator_t, section_enumerator_enumerate, bool,
 			*value = uci_to_option(element)->value;
 		}
 	}
-	va_end(args);
 
 	this->current = list_to_element(this->current->list.next);
 	return TRUE;
@@ -124,7 +120,13 @@ METHOD(uci_parser_t, create_section_enumerator, enumerator_t*,
 		i++;
 	}
 	va_end(args);
-	e = malloc(sizeof(section_enumerator_t) + sizeof(char*) * i);
+	INIT_EXTRA(e, sizeof(char*) * i,
+		.public = {
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _section_enumerator_enumerate,
+			.destroy = _section_enumerator_destroy,
+		},
+	);
 	i = 0;
 	va_start(args, this);
 	do
@@ -134,9 +136,6 @@ METHOD(uci_parser_t, create_section_enumerator, enumerator_t*,
 	while (e->keywords[i++]);
 	va_end(args);
 
-	e->public.enumerate = (void*)_section_enumerator_enumerate;
-	e->public.destroy = _section_enumerator_destroy;
-
 	/* load uci context */
 	e->ctx = uci_alloc_context();
 	if (uci_load(e->ctx, this->package, &e->package) != UCI_OK)
diff --git a/src/libcharon/plugins/unity/Makefile.in b/src/libcharon/plugins/unity/Makefile.in
index 6811eb7..245bbd4 100644
--- a/src/libcharon/plugins/unity/Makefile.in
+++ b/src/libcharon/plugins/unity/Makefile.in
@@ -357,6 +357,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -379,6 +380,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/unity/unity_handler.c b/src/libcharon/plugins/unity/unity_handler.c
index 25e0756..4a1478c 100644
--- a/src/libcharon/plugins/unity/unity_handler.c
+++ b/src/libcharon/plugins/unity/unity_handler.c
@@ -368,9 +368,12 @@ typedef struct {
 } attribute_enumerator_t;
 
 METHOD(enumerator_t, enumerate_attributes, bool,
-	attribute_enumerator_t *this, configuration_attribute_type_t *type,
-	chunk_t *data)
+	attribute_enumerator_t *this, va_list args)
 {
+	configuration_attribute_type_t *type;
+	chunk_t *data;
+
+	VA_ARGS_VGET(args, type, data);
 	if (this->i < countof(attributes))
 	{
 		*type = attributes[this->i++];
@@ -393,7 +396,8 @@ METHOD(attribute_handler_t, create_attribute_enumerator, enumerator_t *,
 	}
 	INIT(enumerator,
 		.public = {
-			.enumerate = (void*)_enumerate_attributes,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _enumerate_attributes,
 			.destroy = (void*)free,
 		},
 	);
@@ -407,24 +411,27 @@ typedef struct {
 	ike_sa_id_t *id;
 } include_filter_t;
 
-/**
- * Include enumerator filter function
- */
-static bool include_filter(include_filter_t *data,
-						   entry_t **entry, traffic_selector_t **ts)
+CALLBACK(include_filter, bool,
+	include_filter_t *data, enumerator_t *orig, va_list args)
 {
-	if (data->id->equals(data->id, (*entry)->id))
+	entry_t *entry;
+	traffic_selector_t **ts;
+
+	VA_ARGS_VGET(args, ts);
+
+	while (orig->enumerate(orig, &entry))
 	{
-		*ts = (*entry)->ts;
-		return TRUE;
+		if (data->id->equals(data->id, entry->id))
+		{
+			*ts = entry->ts;
+			return TRUE;
+		}
 	}
 	return FALSE;
 }
 
-/**
- * Destroy include filter data, unlock mutex
- */
-static void destroy_filter(include_filter_t *data)
+CALLBACK(destroy_filter, void,
+	include_filter_t *data)
 {
 	data->mutex->unlock(data->mutex);
 	free(data);
@@ -442,7 +449,7 @@ METHOD(unity_handler_t, create_include_enumerator, enumerator_t*,
 	data->mutex->lock(data->mutex);
 	return enumerator_create_filter(
 					this->include->create_enumerator(this->include),
-					(void*)include_filter, data, (void*)destroy_filter);
+					include_filter, data, destroy_filter);
 }
 
 METHOD(unity_handler_t, destroy, void,
diff --git a/src/libcharon/plugins/unity/unity_provider.c b/src/libcharon/plugins/unity/unity_provider.c
index 07f5f9b..b6a5564 100644
--- a/src/libcharon/plugins/unity/unity_provider.c
+++ b/src/libcharon/plugins/unity/unity_provider.c
@@ -77,12 +77,15 @@ static void append_ts(bio_writer_t *writer, traffic_selector_t *ts)
 }
 
 METHOD(enumerator_t, attribute_enumerate, bool,
-	attribute_enumerator_t *this, configuration_attribute_type_t *type,
-	chunk_t *attr)
+	attribute_enumerator_t *this, va_list args)
 {
+	configuration_attribute_type_t *type;
+	chunk_t *attr;
 	traffic_selector_t *ts;
 	bio_writer_t *writer;
 
+	VA_ARGS_VGET(args, type, attr);
+
 	if (this->list->get_count(this->list) == 0)
 	{
 		return FALSE;
@@ -183,7 +186,8 @@ METHOD(attribute_provider_t, create_attribute_enumerator, enumerator_t*,
 
 	INIT(attr_enum,
 		.public = {
-			.enumerate = (void*)_attribute_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _attribute_enumerate,
 			.destroy = _attribute_destroy,
 		},
 		.list = list,
diff --git a/src/libcharon/plugins/updown/Makefile.in b/src/libcharon/plugins/updown/Makefile.in
index 1a44e55..ef0f33c 100644
--- a/src/libcharon/plugins/updown/Makefile.in
+++ b/src/libcharon/plugins/updown/Makefile.in
@@ -358,6 +358,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/updown/updown_listener.c b/src/libcharon/plugins/updown/updown_listener.c
index 6a1581c..bbefd6a 100644
--- a/src/libcharon/plugins/updown/updown_listener.c
+++ b/src/libcharon/plugins/updown/updown_listener.c
@@ -366,7 +366,7 @@ static void invoke_once(private_updown_listener_t *this, ike_sa_t *ike_sa,
 		push_env(envp, countof(envp), "PLUTO_IPCOMP=1");
 	}
 	push_dns_env(this, ike_sa, envp, countof(envp));
-	if (config->get_hostaccess(config))
+	if (config->has_option(config, OPT_HOSTACCESS))
 	{
 		push_env(envp, countof(envp), "PLUTO_HOST_ACCESS=1");
 	}
diff --git a/src/libcharon/plugins/vici/Makefile.in b/src/libcharon/plugins/vici/Makefile.in
index cdefbff..fd2b898 100644
--- a/src/libcharon/plugins/vici/Makefile.in
+++ b/src/libcharon/plugins/vici/Makefile.in
@@ -454,6 +454,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -476,6 +477,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/vici/README.md b/src/libcharon/plugins/vici/README.md
index 9bda949..f47f80c 100644
--- a/src/libcharon/plugins/vici/README.md
+++ b/src/libcharon/plugins/vici/README.md
@@ -480,11 +480,12 @@ Load a certificate into the daemon.
 Load a private key into the daemon.
 
 	{
-		type = <private key type, RSA|ECDSA>
+		type = <private key type, rsa|ecdsa|bliss|any>
 		data = <PEM or DER encoded key data>
 	} => {
 		success = <yes or no>
 		errmsg = <error string on failure>
+		id = <hex-encoded SHA-1 key identifier of the public key on success>
 	}
 
 ### unload-key() ###
diff --git a/src/libcharon/plugins/vici/perl/Makefile.in b/src/libcharon/plugins/vici/perl/Makefile.in
index 385aa97..0e9626a 100644
--- a/src/libcharon/plugins/vici/perl/Makefile.in
+++ b/src/libcharon/plugins/vici/perl/Makefile.in
@@ -272,6 +272,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -294,6 +295,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/vici/python/Makefile.in b/src/libcharon/plugins/vici/python/Makefile.in
index f783d70..7d53832 100644
--- a/src/libcharon/plugins/vici/python/Makefile.in
+++ b/src/libcharon/plugins/vici/python/Makefile.in
@@ -294,6 +294,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -316,6 +317,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/vici/python/vici/protocol.py b/src/libcharon/plugins/vici/python/vici/protocol.py
index 919231d..3702294 100644
--- a/src/libcharon/plugins/vici/python/vici/protocol.py
+++ b/src/libcharon/plugins/vici/python/vici/protocol.py
@@ -62,7 +62,7 @@ class Packet(object):
 
     @classmethod
     def _named_request(cls, request_type, request, message=None):
-        requestdata = request.encode("UTF-8")
+        request = request.encode("UTF-8")
         payload = struct.pack("!BB", request_type, len(request)) + request
         if message is not None:
             return payload + message
diff --git a/src/libcharon/plugins/vici/ruby/Makefile.in b/src/libcharon/plugins/vici/ruby/Makefile.in
index 125f44e..5691a74 100644
--- a/src/libcharon/plugins/vici/ruby/Makefile.in
+++ b/src/libcharon/plugins/vici/ruby/Makefile.in
@@ -272,6 +272,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -294,6 +295,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
@@ -468,8 +470,8 @@ distclean-generic:
 maintainer-clean-generic:
 	@echo "This command is intended for maintainers to use"
 	@echo "it deletes files that may require special tools to rebuild."
- at RUBY_GEMS_INSTALL_FALSE@install-data-local:
 @RUBY_GEMS_INSTALL_FALSE at uninstall-local:
+ at RUBY_GEMS_INSTALL_FALSE@install-data-local:
 clean: clean-am
 
 clean-am: clean-generic clean-libtool clean-local mostlyclean-am
diff --git a/src/libcharon/plugins/vici/suites/test_message.c b/src/libcharon/plugins/vici/suites/test_message.c
index 045e34f..73bba23 100644
--- a/src/libcharon/plugins/vici/suites/test_message.c
+++ b/src/libcharon/plugins/vici/suites/test_message.c
@@ -122,9 +122,14 @@ typedef struct {
 	endecode_test_t *next;
 } endecode_enum_t;
 
-static bool endecode_enumerate(endecode_enum_t *this, vici_type_t *type,
-							   char **name, chunk_t *data)
+METHOD(enumerator_t, endecode_enumerate, bool,
+	endecode_enum_t *this, va_list args)
 {
+	vici_type_t *type;
+	chunk_t *data;
+	char **name;
+
+	VA_ARGS_VGET(args, type, name, data);
 	if (this->next)
 	{
 		*type = this->next->type;
@@ -149,7 +154,8 @@ static enumerator_t *endecode_create_enumerator(endecode_test_t *test)
 
 	INIT(enumerator,
 		.public = {
-			.enumerate = (void*)endecode_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _endecode_enumerate,
 			.destroy = (void*)free,
 		},
 		.next = test,
diff --git a/src/libcharon/plugins/vici/vici_attribute.c b/src/libcharon/plugins/vici/vici_attribute.c
index 4e1fa97..ab765fa 100644
--- a/src/libcharon/plugins/vici/vici_attribute.c
+++ b/src/libcharon/plugins/vici/vici_attribute.c
@@ -184,16 +184,22 @@ METHOD(attribute_provider_t, release_address, bool,
 	return found;
 }
 
-/**
- * Filter mapping attribute_t to enumerated type/value arguments
- */
-static bool attr_filter(void *data, attribute_t **attr,
-						configuration_attribute_type_t *type,
-						void *in, chunk_t *value)
+CALLBACK(attr_filter, bool,
+	void *data, enumerator_t *orig, va_list args)
 {
-	*type = (*attr)->type;
-	*value = (*attr)->value;
-	return TRUE;
+	attribute_t *attr;
+	configuration_attribute_type_t *type;
+	chunk_t *value;
+
+	VA_ARGS_VGET(args, type, value);
+
+	if (orig->enumerate(orig, &attr))
+	{
+		*type = attr->type;
+		*value = attr->value;
+		return TRUE;
+	}
+	return FALSE;
 }
 
 /**
@@ -203,7 +209,7 @@ CALLBACK(create_nested, enumerator_t*,
 	pool_t *pool, void *this)
 {
 	return enumerator_create_filter(array_create_enumerator(pool->attrs),
-									(void*)attr_filter, NULL, NULL);
+									attr_filter, NULL, NULL);
 }
 
 /**
diff --git a/src/libcharon/plugins/vici/vici_config.c b/src/libcharon/plugins/vici/vici_config.c
index 12497ec..0c355e3 100644
--- a/src/libcharon/plugins/vici/vici_config.c
+++ b/src/libcharon/plugins/vici/vici_config.c
@@ -141,13 +141,20 @@ METHOD(backend_t, create_peer_cfg_enumerator, enumerator_t*,
 									 (void*)this->lock->unlock, this->lock);
 }
 
-/**
- * Enumerator filter function for ike configs
- */
-static bool ike_filter(void *data, peer_cfg_t **in, ike_cfg_t **out)
+CALLBACK(ike_filter, bool,
+	void *data, enumerator_t *orig, va_list args)
 {
-	*out = (*in)->get_ike_cfg(*in);
-	return TRUE;
+	peer_cfg_t *cfg;
+	ike_cfg_t **out;
+
+	VA_ARGS_VGET(args, out);
+
+	if (orig->enumerate(orig, &cfg))
+	{
+		*out = cfg->get_ike_cfg(cfg);
+		return TRUE;
+	}
+	return FALSE;
 }
 
 METHOD(backend_t, create_ike_cfg_enumerator, enumerator_t*,
@@ -155,7 +162,7 @@ METHOD(backend_t, create_ike_cfg_enumerator, enumerator_t*,
 {
 	this->lock->read_lock(this->lock);
 	return enumerator_create_filter(this->conns->create_enumerator(this->conns),
-									(void*)ike_filter, this->lock,
+									ike_filter, this->lock,
 									(void*)this->lock->unlock);
 }
 
@@ -478,7 +485,6 @@ typedef struct {
 	linked_list_t *remote_ts;
 	uint32_t replay_window;
 	bool policies;
-	bool policies_fwd_out;
 	child_cfg_create_t cfg;
 } child_data_t;
 
@@ -500,12 +506,12 @@ static void log_child_data(child_data_t *data, char *name)
 	DBG2(DBG_CFG, "   life_packets = %llu", cfg->lifetime.packets.life);
 	DBG2(DBG_CFG, "   rand_packets = %llu", cfg->lifetime.packets.jitter);
 	DBG2(DBG_CFG, "   updown = %s", cfg->updown);
-	DBG2(DBG_CFG, "   hostaccess = %u", cfg->hostaccess);
-	DBG2(DBG_CFG, "   ipcomp = %u", cfg->ipcomp);
+	DBG2(DBG_CFG, "   hostaccess = %u", cfg->options & OPT_HOSTACCESS);
+	DBG2(DBG_CFG, "   ipcomp = %u", cfg->options & OPT_IPCOMP);
 	DBG2(DBG_CFG, "   mode = %N%s", ipsec_mode_names, cfg->mode,
-		 cfg->proxy_mode ? "_PROXY" : "");
+		 cfg->options & OPT_PROXY_MODE ? "_PROXY" : "");
 	DBG2(DBG_CFG, "   policies = %u", data->policies);
-	DBG2(DBG_CFG, "   policies_fwd_out = %u", data->policies_fwd_out);
+	DBG2(DBG_CFG, "   policies_fwd_out = %u", cfg->options & OPT_FWD_OUT_POLICIES);
 	if (data->replay_window != REPLAY_UNDEFINED)
 	{
 		DBG2(DBG_CFG, "   replay_window = %u", data->replay_window);
@@ -525,6 +531,8 @@ static void log_child_data(child_data_t *data, char *name)
 	DBG2(DBG_CFG, "   proposals = %#P", data->proposals);
 	DBG2(DBG_CFG, "   local_ts = %#R", data->local_ts);
 	DBG2(DBG_CFG, "   remote_ts = %#R", data->remote_ts);
+	DBG2(DBG_CFG, "   hw_offload = %u", cfg->options & OPT_HW_OFFLOAD);
+	DBG2(DBG_CFG, "   sha256_96 = %u", cfg->options & OPT_SHA256_96);
 }
 
 /**
@@ -827,13 +835,80 @@ CALLBACK(parse_mode, bool,
 	if (parse_map(map, countof(map), &d, v))
 	{
 		cfg->mode = d;
-		cfg->proxy_mode = (d == MODE_TRANSPORT) && (v.len > 9);
+		if ((d == MODE_TRANSPORT) && (v.len > 9))
+		{
+			cfg->options |= OPT_PROXY_MODE;
+		}
 		return TRUE;
 	}
 	return FALSE;
 }
 
 /**
+ * Enable a child_cfg_option_t
+ */
+static bool parse_option(child_cfg_option_t *out, child_cfg_option_t opt,
+						 chunk_t v)
+{
+	bool val;
+
+	if (parse_bool(&val, v))
+	{
+		if (val)
+		{
+			*out |= opt;
+		}
+		return TRUE;
+	}
+	return FALSE;
+}
+
+/**
+ * Parse OPT_HOSTACCESS option
+ */
+CALLBACK(parse_opt_haccess, bool,
+	child_cfg_option_t *out, chunk_t v)
+{
+	return parse_option(out, OPT_HOSTACCESS, v);
+}
+
+/**
+ * Parse OPT_FWD_OUT_POLICIES option
+ */
+CALLBACK(parse_opt_fwd_out, bool,
+	child_cfg_option_t *out, chunk_t v)
+{
+	return parse_option(out, OPT_FWD_OUT_POLICIES, v);
+}
+
+/**
+ * Parse OPT_FWD_OUT_POLICIES option
+ */
+CALLBACK(parse_opt_ipcomp, bool,
+	child_cfg_option_t *out, chunk_t v)
+{
+	return parse_option(out, OPT_IPCOMP, v);
+}
+
+/**
+ * Parse OPT_HW_OFFLOAD option
+ */
+CALLBACK(parse_opt_hw_offl, bool,
+	child_cfg_option_t *out, chunk_t v)
+{
+	return parse_option(out, OPT_HW_OFFLOAD, v);
+}
+
+/**
+ * Parse OPT_SHA256_96 option
+ */
+CALLBACK(parse_opt_sha256_96, bool,
+	child_cfg_option_t *out, chunk_t v)
+{
+	return parse_option(out, OPT_SHA256_96, v);
+}
+
+/**
  * Parse an action_t
  */
 CALLBACK(parse_action, bool,
@@ -1336,6 +1411,7 @@ CALLBACK(parse_frag, bool,
 {
 	enum_map_t map[] = {
 		{ "yes",		FRAGMENTATION_YES		},
+		{ "accept",		FRAGMENTATION_ACCEPT	},
 		{ "no",			FRAGMENTATION_NO		},
 		{ "force",		FRAGMENTATION_FORCE		},
 	};
@@ -1465,10 +1541,10 @@ CALLBACK(child_kv, bool,
 {
 	parse_rule_t rules[] = {
 		{ "updown",				parse_string,		&child->cfg.updown					},
-		{ "hostaccess",			parse_bool,			&child->cfg.hostaccess				},
+		{ "hostaccess",			parse_opt_haccess,	&child->cfg.options					},
 		{ "mode",				parse_mode,			&child->cfg							},
 		{ "policies",			parse_bool,			&child->policies					},
-		{ "policies_fwd_out",	parse_bool,			&child->policies_fwd_out			},
+		{ "policies_fwd_out",	parse_opt_fwd_out,	&child->cfg.options					},
 		{ "replay_window",		parse_uint32,		&child->replay_window				},
 		{ "rekey_time",			parse_time,			&child->cfg.lifetime.time.rekey		},
 		{ "life_time",			parse_time,			&child->cfg.lifetime.time.life		},
@@ -1482,7 +1558,7 @@ CALLBACK(child_kv, bool,
 		{ "dpd_action",			parse_action,		&child->cfg.dpd_action				},
 		{ "start_action",		parse_action,		&child->cfg.start_action			},
 		{ "close_action",		parse_action,		&child->cfg.close_action			},
-		{ "ipcomp",				parse_bool,			&child->cfg.ipcomp					},
+		{ "ipcomp",				parse_opt_ipcomp,	&child->cfg.options					},
 		{ "inactivity",			parse_time,			&child->cfg.inactivity				},
 		{ "reqid",				parse_uint32,		&child->cfg.reqid					},
 		{ "mark_in",			parse_mark,			&child->cfg.mark_in					},
@@ -1490,6 +1566,8 @@ CALLBACK(child_kv, bool,
 		{ "tfc_padding",		parse_tfc,			&child->cfg.tfc						},
 		{ "priority",			parse_uint32,		&child->cfg.priority				},
 		{ "interface",			parse_string,		&child->cfg.interface				},
+		{ "hw_offload",			parse_opt_hw_offl,	&child->cfg.options					},
+		{ "sha256_96",			parse_opt_sha256_96,&child->cfg.options					},
 	};
 
 	return parse_rules(rules, countof(rules), name, value,
@@ -1755,8 +1833,7 @@ CALLBACK(children_sn, bool,
 			child.proposals->insert_last(child.proposals, proposal);
 		}
 	}
-	child.cfg.suppress_policies = !child.policies;
-	child.cfg.fwd_out_policies = child.policies_fwd_out;
+	child.cfg.options |= child.policies ? 0 : OPT_NO_POLICIES;
 
 	check_lifetimes(&child.cfg.lifetime);
 
diff --git a/src/libcharon/plugins/vici/vici_cred.c b/src/libcharon/plugins/vici/vici_cred.c
index 6c7c194..5d8bf2f 100644
--- a/src/libcharon/plugins/vici/vici_cred.c
+++ b/src/libcharon/plugins/vici/vici_cred.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2015-2016 Andreas Steffen
- * Copyright (C) 2016 Tobias Brunner
+ * Copyright (C) 2016-2017 Tobias Brunner
  * HSR Hochschule fuer Technik Rapperswil
  *
  * Copyright (C) 2014 Martin Willi
@@ -206,9 +206,10 @@ CALLBACK(load_cert, vici_message_t*,
 CALLBACK(load_key, vici_message_t*,
 	private_vici_cred_t *this, char *name, u_int id, vici_message_t *message)
 {
+	vici_builder_t *builder;
 	key_type_t type;
 	private_key_t *key;
-	chunk_t data;
+	chunk_t data, fp;
 	char *str;
 
 	str = message->get_str(message, NULL, "type");
@@ -248,12 +249,19 @@ CALLBACK(load_key, vici_message_t*,
 		return create_reply("parsing %N private key failed",
 							key_type_names, type);
 	}
+	if (!key->get_fingerprint(key, KEYID_PUBKEY_SHA1, &fp))
+	{
+		return create_reply("failed to get key id");
+	}
 
 	DBG1(DBG_CFG, "loaded %N private key", key_type_names, type);
 
+	builder = vici_builder_create();
+	builder->add_kv(builder, "success", "yes");
+	builder->add_kv(builder, "id", "%+B", &fp);
 	this->creds->add_key(this->creds, key);
 
-	return create_reply(NULL);
+	return builder->finalize(builder);
 }
 
 CALLBACK(unload_key, vici_message_t*,
diff --git a/src/libcharon/plugins/vici/vici_message.c b/src/libcharon/plugins/vici/vici_message.c
index 58b8967..91d3449 100644
--- a/src/libcharon/plugins/vici/vici_message.c
+++ b/src/libcharon/plugins/vici/vici_message.c
@@ -135,11 +135,16 @@ typedef struct {
 } parse_enumerator_t;
 
 METHOD(enumerator_t, parse_enumerate, bool,
-	parse_enumerator_t *this, vici_type_t *out, char **name, chunk_t *value)
+	parse_enumerator_t *this, va_list args)
 {
+	vici_type_t *out;
+	chunk_t *value;
+	char **name;
 	uint8_t type;
 	chunk_t data;
 
+	VA_ARGS_VGET(args, out, name, value);
+
 	if (!this->reader->remaining(this->reader) ||
 		!this->reader->read_uint8(this->reader, &type))
 	{
@@ -218,7 +223,8 @@ METHOD(vici_message_t, create_enumerator, enumerator_t*,
 
 	INIT(enumerator,
 		.public = {
-			.enumerate = (void*)_parse_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _parse_enumerate,
 			.destroy = _parse_destroy,
 		},
 		.reader = bio_reader_create(this->encoding),
diff --git a/src/libcharon/plugins/vici/vici_query.c b/src/libcharon/plugins/vici/vici_query.c
index c0f4e2d..2cc5959 100644
--- a/src/libcharon/plugins/vici/vici_query.c
+++ b/src/libcharon/plugins/vici/vici_query.c
@@ -107,7 +107,7 @@ static void list_mode(vici_builder_t *b, child_sa_t *child, child_cfg_t *cfg)
 			cfg = child->get_config(child);
 		}
 		mode = child ? child->get_mode(child) : cfg->get_mode(cfg);
-		if (mode == MODE_TRANSPORT && cfg->use_proxy_mode(cfg))
+		if (mode == MODE_TRANSPORT && cfg->has_option(cfg, OPT_PROXY_MODE))
 		{	/* only report this if the negotiated mode is actually TRANSPORT */
 			sub_mode = "_PROXY";
 		}
diff --git a/src/libcharon/plugins/whitelist/Makefile.in b/src/libcharon/plugins/whitelist/Makefile.in
index b859613..0347c5f 100644
--- a/src/libcharon/plugins/whitelist/Makefile.in
+++ b/src/libcharon/plugins/whitelist/Makefile.in
@@ -365,6 +365,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -387,6 +388,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/whitelist/whitelist_listener.c b/src/libcharon/plugins/whitelist/whitelist_listener.c
index 7e5b2f4..1365546 100644
--- a/src/libcharon/plugins/whitelist/whitelist_listener.c
+++ b/src/libcharon/plugins/whitelist/whitelist_listener.c
@@ -119,14 +119,19 @@ METHOD(whitelist_listener_t, remove_, void,
 	DESTROY_IF(id);
 }
 
-/**
- * Enumerator filter, from hashtable (key, value) to single identity
- */
-static bool whitelist_filter(rwlock_t *lock, identification_t **key,
-							 identification_t **id, identification_t **value)
+CALLBACK(whitelist_filter, bool,
+	rwlock_t *lock, enumerator_t *orig, va_list args)
 {
-	*id = *value;
-	return TRUE;
+	identification_t *key, *value, **out;
+
+	VA_ARGS_VGET(args, out);
+
+	if (orig->enumerate(orig, &key, &value))
+	{
+		*out = value;
+		return TRUE;
+	}
+	return FALSE;
 }
 
 METHOD(whitelist_listener_t, create_enumerator, enumerator_t*,
@@ -134,7 +139,7 @@ METHOD(whitelist_listener_t, create_enumerator, enumerator_t*,
 {
 	this->lock->read_lock(this->lock);
 	return enumerator_create_filter(this->ids->create_enumerator(this->ids),
-									(void*)whitelist_filter, this->lock,
+									whitelist_filter, this->lock,
 									(void*)this->lock->unlock);
 }
 
diff --git a/src/libcharon/plugins/xauth_eap/Makefile.in b/src/libcharon/plugins/xauth_eap/Makefile.in
index a6554d6..28158a3 100644
--- a/src/libcharon/plugins/xauth_eap/Makefile.in
+++ b/src/libcharon/plugins/xauth_eap/Makefile.in
@@ -358,6 +358,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/xauth_generic/Makefile.in b/src/libcharon/plugins/xauth_generic/Makefile.in
index 87d627b..1dc2675 100644
--- a/src/libcharon/plugins/xauth_generic/Makefile.in
+++ b/src/libcharon/plugins/xauth_generic/Makefile.in
@@ -358,6 +358,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/xauth_noauth/Makefile.in b/src/libcharon/plugins/xauth_noauth/Makefile.in
index 13fb71a..a610bab 100644
--- a/src/libcharon/plugins/xauth_noauth/Makefile.in
+++ b/src/libcharon/plugins/xauth_noauth/Makefile.in
@@ -358,6 +358,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/plugins/xauth_pam/Makefile.in b/src/libcharon/plugins/xauth_pam/Makefile.in
index 821d46e..8c31f24 100644
--- a/src/libcharon/plugins/xauth_pam/Makefile.in
+++ b/src/libcharon/plugins/xauth_pam/Makefile.in
@@ -358,6 +358,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/processing/jobs/delete_child_sa_job.c b/src/libcharon/processing/jobs/delete_child_sa_job.c
index 70dbc1b..048b879 100644
--- a/src/libcharon/processing/jobs/delete_child_sa_job.c
+++ b/src/libcharon/processing/jobs/delete_child_sa_job.c
@@ -1,6 +1,7 @@
 /*
+ * Copyright (C) 2017 Tobias Brunner
  * Copyright (C) 2006 Martin Willi
- * Hochschule fuer Technik Rapperswil
+ * HSR 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
@@ -24,19 +25,19 @@ typedef struct private_delete_child_sa_job_t private_delete_child_sa_job_t;
  * Private data of an delete_child_sa_job_t object.
  */
 struct private_delete_child_sa_job_t {
-	/**
 
+	/**
 	 * Public delete_child_sa_job_t interface.
 	 */
 	delete_child_sa_job_t public;
 
 	/**
-	 * protocol of the CHILD_SA (ESP/AH)
+	 * Protocol of the CHILD_SA (ESP/AH)
 	 */
 	protocol_id_t protocol;
 
 	/**
-	 * inbound SPI of the CHILD_SA
+	 * Inbound SPI of the CHILD_SA
 	 */
 	uint32_t spi;
 
@@ -49,12 +50,17 @@ struct private_delete_child_sa_job_t {
 	 * Delete for an expired CHILD_SA
 	 */
 	bool expired;
+
+	/**
+	 * Unique ID of the CHILD_SA
+	 */
+	uint32_t id;
 };
 
 METHOD(job_t, destroy, void,
 	private_delete_child_sa_job_t *this)
 {
-	this->dst->destroy(this->dst);
+	DESTROY_IF(this->dst);
 	free(this);
 }
 
@@ -63,17 +69,37 @@ METHOD(job_t, execute, job_requeue_t,
 {
 	ike_sa_t *ike_sa;
 
-	ike_sa = charon->child_sa_manager->checkout(charon->child_sa_manager,
-									this->protocol, this->spi, this->dst, NULL);
-	if (ike_sa == NULL)
+	if (this->id)
 	{
-		DBG1(DBG_JOB, "CHILD_SA %N/0x%08x/%H not found for delete",
-			 protocol_id_names, this->protocol, htonl(this->spi), this->dst);
+		child_sa_t *child_sa;
+
+		ike_sa = charon->child_sa_manager->checkout_by_id(
+								charon->child_sa_manager, this->id, &child_sa);
+		if (!ike_sa)
+		{
+			DBG1(DBG_JOB, "CHILD_SA {%d} not found for delete", this->id);
+		}
+		else
+		{
+			this->spi = child_sa->get_spi(child_sa, TRUE);
+			this->protocol = child_sa->get_protocol(child_sa);
+		}
 	}
 	else
 	{
-		ike_sa->delete_child_sa(ike_sa, this->protocol, this->spi, this->expired);
+		ike_sa = charon->child_sa_manager->checkout(charon->child_sa_manager,
+									this->protocol, this->spi, this->dst, NULL);
+		if (!ike_sa)
+		{
+			DBG1(DBG_JOB, "CHILD_SA %N/0x%08x/%H not found for delete",
+				 protocol_id_names, this->protocol, htonl(this->spi), this->dst);
+		}
+	}
 
+	if (ike_sa)
+	{
+		ike_sa->delete_child_sa(ike_sa, this->protocol, this->spi,
+								this->expired);
 		charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
 	}
 	return JOB_REQUEUE_NONE;
@@ -109,3 +135,24 @@ delete_child_sa_job_t *delete_child_sa_job_create(protocol_id_t protocol,
 
 	return &this->public;
 }
+
+/*
+ * Described in header
+ */
+delete_child_sa_job_t *delete_child_sa_job_create_id(uint32_t id)
+{
+	private_delete_child_sa_job_t *this;
+
+	INIT(this,
+		.public = {
+			.job_interface = {
+				.execute = _execute,
+				.get_priority = _get_priority,
+				.destroy = _destroy,
+			},
+		},
+		.id = id,
+	);
+
+	return &this->public;
+}
diff --git a/src/libcharon/processing/jobs/delete_child_sa_job.h b/src/libcharon/processing/jobs/delete_child_sa_job.h
index 349f5de..b2d5a11 100644
--- a/src/libcharon/processing/jobs/delete_child_sa_job.h
+++ b/src/libcharon/processing/jobs/delete_child_sa_job.h
@@ -1,6 +1,7 @@
 /*
+ * Copyright (C) 2017 Tobias Brunner
  * Copyright (C) 2006 Martin Willi
- * Hochschule fuer Technik Rapperswil
+ * HSR 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
@@ -42,7 +43,7 @@ struct delete_child_sa_job_t {
 };
 
 /**
- * Creates a job of type DELETE_CHILD_SA.
+ * Creates a job that deletes a CHILD_SA.
  *
  * @param protocol	protocol of the CHILD_SA
  * @param spi		security parameter index of the CHILD_SA
@@ -53,4 +54,12 @@ struct delete_child_sa_job_t {
 delete_child_sa_job_t *delete_child_sa_job_create(protocol_id_t protocol,
 									uint32_t spi, host_t *dst, bool expired);
 
+/**
+ * Creates a job that deletes a CHILD_SA identified by its unique ID.
+ *
+ * @param id		unique ID of the CHILD_SA
+ * @return			delete_child_sa_job_t object
+ */
+delete_child_sa_job_t *delete_child_sa_job_create_id(uint32_t id);
+
 #endif /** DELETE_CHILD_SA_JOB_H_ @}*/
diff --git a/src/libcharon/sa/child_sa.c b/src/libcharon/sa/child_sa.c
index b9dd59b..3d9f613 100644
--- a/src/libcharon/sa/child_sa.c
+++ b/src/libcharon/sa/child_sa.c
@@ -1,6 +1,6 @@
 /*
+ * Copyright (C) 2006-2017 Tobias Brunner
  * Copyright (C) 2016 Andreas Steffen
- * Copyright (C) 2006-2016 Tobias Brunner
  * Copyright (C) 2005-2008 Martin Willi
  * Copyright (C) 2006 Daniel Roethlisberger
  * Copyright (C) 2005 Jan Hutter
@@ -40,6 +40,12 @@ ENUM(child_sa_state_names, CHILD_CREATED, CHILD_DESTROYING,
 	"DESTROYING",
 );
 
+ENUM(child_sa_outbound_state_names, CHILD_OUTBOUND_NONE, CHILD_OUTBOUND_INSTALLED,
+	"NONE",
+	"REGISTERED",
+	"INSTALLED",
+);
+
 typedef struct private_child_sa_t private_child_sa_t;
 
 /**
@@ -92,6 +98,31 @@ struct private_child_sa_t {
 	array_t *other_ts;
 
 	/**
+	 * Outbound encryption key cached during a rekeying
+	 */
+	chunk_t encr_r;
+
+	/**
+	 * Outbound integrity key cached during a rekeying
+	 */
+	chunk_t integ_r;
+
+	/**
+	 * Whether the outbound SA has only been registered yet during a rekeying
+	 */
+	child_sa_outbound_state_t outbound_state;
+
+	/**
+	 * Whether the peer supports TFCv3
+	 */
+	bool tfcv3;
+
+	/**
+	 * The outbound SPI of the CHILD_SA that replaced this one during a rekeying
+	 */
+	uint32_t rekey_spi;
+
+	/**
 	 * Protocol used to protect this SA, ESP|AH
 	 */
 	protocol_id_t protocol;
@@ -265,6 +296,10 @@ METHOD(child_sa_t, get_config, child_cfg_t*,
 METHOD(child_sa_t, set_state, void,
 	   private_child_sa_t *this, child_sa_state_t state)
 {
+	DBG2(DBG_CHD, "CHILD_SA %s{%d} state change: %N => %N",
+		 get_name(this), this->unique_id,
+		 child_sa_state_names, this->state,
+		 child_sa_state_names, state);
 	charon->bus->child_state_change(charon->bus, &this->public, state);
 	this->state = state;
 }
@@ -275,6 +310,12 @@ METHOD(child_sa_t, get_state, child_sa_state_t,
 	return this->state;
 }
 
+METHOD(child_sa_t, get_outbound_state, child_sa_outbound_state_t,
+	   private_child_sa_t *this)
+{
+	return this->outbound_state;
+}
+
 METHOD(child_sa_t, get_spi, uint32_t,
 	   private_child_sa_t *this, bool inbound)
 {
@@ -394,10 +435,11 @@ struct policy_enumerator_t {
 };
 
 METHOD(enumerator_t, policy_enumerate, bool,
-	   policy_enumerator_t *this, traffic_selector_t **my_out,
-	   traffic_selector_t **other_out)
+	   policy_enumerator_t *this, va_list args)
 {
-	traffic_selector_t *other_ts;
+	traffic_selector_t *other_ts, **my_out, **other_out;
+
+	VA_ARGS_VGET(args, my_out, other_out);
 
 	while (this->ts || this->mine->enumerate(this->mine, &this->ts))
 	{
@@ -446,7 +488,8 @@ METHOD(child_sa_t, create_policy_enumerator, enumerator_t*,
 
 	INIT(e,
 		.public = {
-			.enumerate = (void*)_policy_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _policy_enumerate,
 			.destroy = _policy_destroy,
 		},
 		.mine = array_create_enumerator(this->my_ts),
@@ -504,7 +547,7 @@ static status_t update_usebytes(private_child_sa_t *this, bool inbound)
 	}
 	else
 	{
-		if (this->other_spi)
+		if (this->other_spi && this->outbound_state == CHILD_OUTBOUND_INSTALLED)
 		{
 			kernel_ipsec_sa_id_t id = {
 				.src = this->my_addr,
@@ -691,14 +734,16 @@ METHOD(child_sa_t, alloc_cpi, uint16_t,
 	return 0;
 }
 
-METHOD(child_sa_t, install, status_t,
-	private_child_sa_t *this, chunk_t encr, chunk_t integ, uint32_t spi,
-	uint16_t cpi, bool initiator, bool inbound, bool tfcv3,
-	linked_list_t *my_ts, linked_list_t *other_ts)
+/**
+ * Install the given SA in the kernel
+ */
+static status_t install_internal(private_child_sa_t *this, chunk_t encr,
+	chunk_t integ, uint32_t spi, uint16_t cpi, bool initiator, bool inbound,
+	bool tfcv3)
 {
 	uint16_t enc_alg = ENCR_UNDEFINED, int_alg = AUTH_UNDEFINED, size;
 	uint16_t esn = NO_EXT_SEQ_NUMBERS;
-	linked_list_t *src_ts = NULL, *dst_ts = NULL;
+	linked_list_t *my_ts, *other_ts, *src_ts, *dst_ts;
 	time_t now;
 	kernel_ipsec_sa_id_t id;
 	kernel_ipsec_add_sa_t sa;
@@ -708,6 +753,12 @@ METHOD(child_sa_t, install, status_t,
 	status_t status;
 	bool update = FALSE;
 
+	/* BEET requires the bound address from the traffic selectors */
+	my_ts = linked_list_create_from_enumerator(
+									array_create_enumerator(this->my_ts));
+	other_ts = linked_list_create_from_enumerator(
+									array_create_enumerator(this->other_ts));
+
 	/* now we have to decide which spi to use. Use self allocated, if "in",
 	 * or the one in the proposal, if not "in" (others). Additionally,
 	 * source and dest host switch depending on the role */
@@ -721,6 +772,8 @@ METHOD(child_sa_t, install, status_t,
 		}
 		this->my_spi = spi;
 		this->my_cpi = cpi;
+		dst_ts = my_ts;
+		src_ts = other_ts;
 	}
 	else
 	{
@@ -728,11 +781,14 @@ METHOD(child_sa_t, install, status_t,
 		dst = this->other_addr;
 		this->other_spi = spi;
 		this->other_cpi = cpi;
+		src_ts = my_ts;
+		dst_ts = other_ts;
 
 		if (tfcv3)
 		{
 			tfc = this->config->get_tfc(this->config);
 		}
+		this->outbound_state = CHILD_OUTBOUND_INSTALLED;
 	}
 
 	DBG2(DBG_CHD, "adding %s %N SA", inbound ? "inbound" : "outbound",
@@ -748,12 +804,22 @@ METHOD(child_sa_t, install, status_t,
 	this->proposal->get_algorithm(this->proposal, EXTENDED_SEQUENCE_NUMBERS,
 								  &esn, NULL);
 
+	if (int_alg == AUTH_HMAC_SHA2_256_128 &&
+		this->config->has_option(this->config, OPT_SHA256_96))
+	{
+		DBG2(DBG_CHD, "  using %N with 96-bit truncation",
+			 integrity_algorithm_names, int_alg);
+		int_alg = AUTH_HMAC_SHA2_256_96;
+	}
+
 	if (!this->reqid_allocated && !this->static_reqid)
 	{
 		status = charon->kernel->alloc_reqid(charon->kernel, my_ts, other_ts,
 								this->mark_in, this->mark_out, &this->reqid);
 		if (status != SUCCESS)
 		{
+			my_ts->destroy(my_ts);
+			other_ts->destroy(other_ts);
 			return status;
 		}
 		this->reqid_allocated = TRUE;
@@ -783,18 +849,6 @@ METHOD(child_sa_t, install, status_t,
 		lifetime->time.rekey = 0;
 	}
 
-	/* BEET requires the bound address from the traffic selectors */
-	if (inbound)
-	{
-		dst_ts = my_ts;
-		src_ts = other_ts;
-	}
-	else
-	{
-		src_ts = my_ts;
-		dst_ts = other_ts;
-	}
-
 	id = (kernel_ipsec_sa_id_t){
 		.src = src,
 		.dst = dst,
@@ -818,6 +872,7 @@ METHOD(child_sa_t, install, status_t,
 		.ipcomp = this->ipcomp,
 		.cpi = cpi,
 		.encap = this->encap,
+		.hw_offload = this->config->has_option(this->config, OPT_HW_OFFLOAD),
 		.esn = esn,
 		.initiator = initiator,
 		.inbound = inbound,
@@ -826,11 +881,21 @@ METHOD(child_sa_t, install, status_t,
 
 	status = charon->kernel->add_sa(charon->kernel, &id, &sa);
 
+	my_ts->destroy(my_ts);
+	other_ts->destroy(other_ts);
 	free(lifetime);
 
 	return status;
 }
 
+METHOD(child_sa_t, install, status_t,
+	private_child_sa_t *this, chunk_t encr, chunk_t integ, uint32_t spi,
+	uint16_t cpi, bool initiator, bool inbound, bool tfcv3)
+{
+	return install_internal(this, encr, integ, spi, cpi, initiator, inbound,
+							tfcv3);
+}
+
 /**
  * Check kernel interface if policy updates are required
  */
@@ -887,34 +952,21 @@ static void prepare_sa_cfg(private_child_sa_t *this, ipsec_sa_cfg_t *my_sa,
 }
 
 /**
- * Install 3 policies: out, in and forward
+ * Install inbound policie(s): in, fwd
  */
-static status_t install_policies_internal(private_child_sa_t *this,
+static status_t install_policies_inbound(private_child_sa_t *this,
 	host_t *my_addr, host_t *other_addr, traffic_selector_t *my_ts,
 	traffic_selector_t *other_ts, ipsec_sa_cfg_t *my_sa,
 	ipsec_sa_cfg_t *other_sa, policy_type_t type,
 	policy_priority_t priority,	uint32_t manual_prio)
 {
-	kernel_ipsec_policy_id_t out_id = {
-		.dir = POLICY_OUT,
-		.src_ts = my_ts,
-		.dst_ts = other_ts,
-		.mark = this->mark_out,
-		.interface = this->config->get_interface(this->config),
-	}, in_id = {
+	kernel_ipsec_policy_id_t in_id = {
 		.dir = POLICY_IN,
 		.src_ts = other_ts,
 		.dst_ts = my_ts,
 		.mark = this->mark_in,
 	};
-	kernel_ipsec_manage_policy_t out_policy = {
-		.type = type,
-		.prio = priority,
-		.manual_prio = manual_prio,
-		.src = my_addr,
-		.dst = other_addr,
-		.sa = other_sa,
-	}, in_policy = {
+	kernel_ipsec_manage_policy_t in_policy = {
 		.type = type,
 		.prio = priority,
 		.manual_prio = manual_prio,
@@ -924,13 +976,45 @@ static status_t install_policies_internal(private_child_sa_t *this,
 	};
 	status_t status = SUCCESS;
 
-	status |= charon->kernel->add_policy(charon->kernel, &out_id, &out_policy);
 	status |= charon->kernel->add_policy(charon->kernel, &in_id, &in_policy);
 	if (this->mode != MODE_TRANSPORT)
 	{
 		in_id.dir = POLICY_FWD;
 		status |= charon->kernel->add_policy(charon->kernel, &in_id, &in_policy);
+	}
+	return status;
+}
 
+/**
+ * Install outbound policie(s): out, [fwd]
+ */
+static status_t install_policies_outbound(private_child_sa_t *this,
+	host_t *my_addr, host_t *other_addr, traffic_selector_t *my_ts,
+	traffic_selector_t *other_ts, ipsec_sa_cfg_t *my_sa,
+	ipsec_sa_cfg_t *other_sa, policy_type_t type,
+	policy_priority_t priority,	uint32_t manual_prio)
+{
+	kernel_ipsec_policy_id_t out_id = {
+		.dir = POLICY_OUT,
+		.src_ts = my_ts,
+		.dst_ts = other_ts,
+		.mark = this->mark_out,
+		.interface = this->config->get_interface(this->config),
+	};
+	kernel_ipsec_manage_policy_t out_policy = {
+		.type = type,
+		.prio = priority,
+		.manual_prio = manual_prio,
+		.src = my_addr,
+		.dst = other_addr,
+		.sa = other_sa,
+	};
+	status_t status = SUCCESS;
+
+	status |= charon->kernel->add_policy(charon->kernel, &out_id, &out_policy);
+
+	if (this->mode != MODE_TRANSPORT && this->policies_fwd_out)
+	{
 		/* install an "outbound" FWD policy in case there is a drop policy
 		 * matching outbound forwarded traffic, to allow another tunnel to use
 		 * the reversed subnets and do the same we don't set a reqid (this also
@@ -939,52 +1023,56 @@ static status_t install_policies_internal(private_child_sa_t *this,
 		 * policies of two SAs we install them with reduced priority.  As they
 		 * basically act as bypass policies for drop policies we use a higher
 		 * priority than is used for them. */
-		if (this->policies_fwd_out)
+		out_id.dir = POLICY_FWD;
+		other_sa->reqid = 0;
+		if (priority == POLICY_PRIORITY_DEFAULT)
 		{
-			out_id.dir = POLICY_FWD;
-			other_sa->reqid = 0;
-			if (priority == POLICY_PRIORITY_DEFAULT)
-			{
-				out_policy.prio = POLICY_PRIORITY_ROUTED;
-			}
-			status |= charon->kernel->add_policy(charon->kernel, &out_id,
-												 &out_policy);
-			/* reset the reqid for any other further policies */
-			other_sa->reqid = this->reqid;
+			out_policy.prio = POLICY_PRIORITY_ROUTED;
 		}
+		status |= charon->kernel->add_policy(charon->kernel, &out_id,
+											 &out_policy);
+		/* reset the reqid for any other further policies */
+		other_sa->reqid = this->reqid;
 	}
 	return status;
 }
 
 /**
- * Delete 3 policies: out, in and forward
+ * Install all policies
  */
-static void del_policies_internal(private_child_sa_t *this,
+static status_t install_policies_internal(private_child_sa_t *this,
+	host_t *my_addr, host_t *other_addr, traffic_selector_t *my_ts,
+	traffic_selector_t *other_ts, ipsec_sa_cfg_t *my_sa,
+	ipsec_sa_cfg_t *other_sa, policy_type_t type,
+	policy_priority_t priority,	uint32_t manual_prio)
+{
+	status_t status = SUCCESS;
+
+	status |= install_policies_inbound(this, my_addr, other_addr, my_ts,
+									   other_ts, my_sa, other_sa, type,
+									   priority, manual_prio);
+	status |= install_policies_outbound(this, my_addr, other_addr, my_ts,
+										other_ts, my_sa, other_sa, type,
+										priority, manual_prio);
+	return status;
+}
+
+/**
+ * Delete inbound policies: in, fwd
+ */
+static void del_policies_inbound(private_child_sa_t *this,
 	host_t *my_addr, host_t *other_addr, traffic_selector_t *my_ts,
 	traffic_selector_t *other_ts, ipsec_sa_cfg_t *my_sa,
 	ipsec_sa_cfg_t *other_sa, policy_type_t type,
 	policy_priority_t priority, uint32_t manual_prio)
 {
-	kernel_ipsec_policy_id_t out_id = {
-		.dir = POLICY_OUT,
-		.src_ts = my_ts,
-		.dst_ts = other_ts,
-		.mark = this->mark_out,
-		.interface = this->config->get_interface(this->config),
-	}, in_id = {
+	kernel_ipsec_policy_id_t in_id = {
 		.dir = POLICY_IN,
 		.src_ts = other_ts,
 		.dst_ts = my_ts,
 		.mark = this->mark_in,
 	};
-	kernel_ipsec_manage_policy_t out_policy = {
-		.type = type,
-		.prio = priority,
-		.manual_prio = manual_prio,
-		.src = my_addr,
-		.dst = other_addr,
-		.sa = other_sa,
-	}, in_policy = {
+	kernel_ipsec_manage_policy_t in_policy = {
 		.type = type,
 		.prio = priority,
 		.manual_prio = manual_prio,
@@ -993,49 +1081,83 @@ static void del_policies_internal(private_child_sa_t *this,
 		.sa = my_sa,
 	};
 
-	charon->kernel->del_policy(charon->kernel, &out_id, &out_policy);
 	charon->kernel->del_policy(charon->kernel, &in_id, &in_policy);
+
 	if (this->mode != MODE_TRANSPORT)
 	{
 		in_id.dir = POLICY_FWD;
 		charon->kernel->del_policy(charon->kernel, &in_id, &in_policy);
+	}
+}
 
-		if (this->policies_fwd_out)
+/**
+ * Delete outbound policies: out, [fwd]
+ */
+static void del_policies_outbound(private_child_sa_t *this,
+	host_t *my_addr, host_t *other_addr, traffic_selector_t *my_ts,
+	traffic_selector_t *other_ts, ipsec_sa_cfg_t *my_sa,
+	ipsec_sa_cfg_t *other_sa, policy_type_t type,
+	policy_priority_t priority, uint32_t manual_prio)
+{
+	kernel_ipsec_policy_id_t out_id = {
+		.dir = POLICY_OUT,
+		.src_ts = my_ts,
+		.dst_ts = other_ts,
+		.mark = this->mark_out,
+		.interface = this->config->get_interface(this->config),
+	};
+	kernel_ipsec_manage_policy_t out_policy = {
+		.type = type,
+		.prio = priority,
+		.manual_prio = manual_prio,
+		.src = my_addr,
+		.dst = other_addr,
+		.sa = other_sa,
+	};
+
+	charon->kernel->del_policy(charon->kernel, &out_id, &out_policy);
+
+	if (this->mode != MODE_TRANSPORT && this->policies_fwd_out)
+	{
+		out_id.dir = POLICY_FWD;
+		other_sa->reqid = 0;
+		if (priority == POLICY_PRIORITY_DEFAULT)
 		{
-			out_id.dir = POLICY_FWD;
-			other_sa->reqid = 0;
-			if (priority == POLICY_PRIORITY_DEFAULT)
-			{
-				out_policy.prio = POLICY_PRIORITY_ROUTED;
-			}
-			charon->kernel->del_policy(charon->kernel, &out_id, &out_policy);
-			other_sa->reqid = this->reqid;
+			out_policy.prio = POLICY_PRIORITY_ROUTED;
 		}
+		charon->kernel->del_policy(charon->kernel, &out_id, &out_policy);
+		other_sa->reqid = this->reqid;
 	}
 }
 
-METHOD(child_sa_t, add_policies, status_t,
+/**
+ * Delete in- and outbound policies
+ */
+static void del_policies_internal(private_child_sa_t *this,
+	host_t *my_addr, host_t *other_addr, traffic_selector_t *my_ts,
+	traffic_selector_t *other_ts, ipsec_sa_cfg_t *my_sa,
+	ipsec_sa_cfg_t *other_sa, policy_type_t type,
+	policy_priority_t priority, uint32_t manual_prio)
+{
+	del_policies_outbound(this, my_addr, other_addr, my_ts, other_ts, my_sa,
+						 other_sa, type, priority, manual_prio);
+	del_policies_inbound(this, my_addr, other_addr, my_ts, other_ts, my_sa,
+						 other_sa, type, priority, manual_prio);
+}
+
+METHOD(child_sa_t, set_policies, void,
 	   private_child_sa_t *this, linked_list_t *my_ts_list,
 	   linked_list_t *other_ts_list)
 {
 	enumerator_t *enumerator;
 	traffic_selector_t *my_ts, *other_ts;
-	status_t status = SUCCESS;
 
-	if (!this->reqid_allocated && !this->static_reqid)
+	if (array_count(this->my_ts))
 	{
-		/* trap policy, get or confirm reqid */
-		status = charon->kernel->alloc_reqid(
-							charon->kernel, my_ts_list, other_ts_list,
-							this->mark_in, this->mark_out, &this->reqid);
-		if (status != SUCCESS)
-		{
-			return status;
-		}
-		this->reqid_allocated = TRUE;
+		array_destroy_offset(this->my_ts,
+							 offsetof(traffic_selector_t, destroy));
+		this->my_ts = array_create(0, 0);
 	}
-
-	/* apply traffic selectors */
 	enumerator = my_ts_list->create_enumerator(my_ts_list);
 	while (enumerator->enumerate(enumerator, &my_ts))
 	{
@@ -1044,6 +1166,12 @@ METHOD(child_sa_t, add_policies, status_t,
 	enumerator->destroy(enumerator);
 	array_sort(this->my_ts, (void*)traffic_selector_cmp, NULL);
 
+	if (array_count(this->other_ts))
+	{
+		array_destroy_offset(this->other_ts,
+							 offsetof(traffic_selector_t, destroy));
+		this->other_ts = array_create(0, 0);
+	}
 	enumerator = other_ts_list->create_enumerator(other_ts_list);
 	while (enumerator->enumerate(enumerator, &other_ts))
 	{
@@ -1051,12 +1179,40 @@ METHOD(child_sa_t, add_policies, status_t,
 	}
 	enumerator->destroy(enumerator);
 	array_sort(this->other_ts, (void*)traffic_selector_cmp, NULL);
+}
+
+METHOD(child_sa_t, install_policies, status_t,
+	   private_child_sa_t *this)
+{
+	enumerator_t *enumerator;
+	linked_list_t *my_ts_list, *other_ts_list;
+	traffic_selector_t *my_ts, *other_ts;
+	status_t status = SUCCESS;
 
-	if (this->config->install_policy(this->config))
+	if (!this->reqid_allocated && !this->static_reqid)
+	{
+		my_ts_list = linked_list_create_from_enumerator(
+									array_create_enumerator(this->my_ts));
+		other_ts_list = linked_list_create_from_enumerator(
+									array_create_enumerator(this->other_ts));
+		status = charon->kernel->alloc_reqid(
+							charon->kernel, my_ts_list, other_ts_list,
+							this->mark_in, this->mark_out, &this->reqid);
+		my_ts_list->destroy(my_ts_list);
+		other_ts_list->destroy(other_ts_list);
+		if (status != SUCCESS)
+		{
+			return status;
+		}
+		this->reqid_allocated = TRUE;
+	}
+
+	if (!this->config->has_option(this->config, OPT_NO_POLICIES))
 	{
 		policy_priority_t priority;
 		ipsec_sa_cfg_t my_sa, other_sa;
 		uint32_t manual_prio;
+		bool install_outbound;
 
 		prepare_sa_cfg(this, &my_sa, &other_sa);
 		manual_prio = this->config->get_manual_prio(this->config);
@@ -1066,6 +1222,7 @@ METHOD(child_sa_t, add_policies, status_t,
 		this->trap = this->state == CHILD_CREATED;
 		priority = this->trap ? POLICY_PRIORITY_ROUTED
 							  : POLICY_PRIORITY_DEFAULT;
+		install_outbound = this->outbound_state != CHILD_OUTBOUND_REGISTERED;
 
 		/* enumerate pairs of traffic selectors */
 		enumerator = create_policy_enumerator(this);
@@ -1074,20 +1231,27 @@ METHOD(child_sa_t, add_policies, status_t,
 			/* install outbound drop policy to avoid packets leaving unencrypted
 			 * when updating policies */
 			if (priority == POLICY_PRIORITY_DEFAULT && manual_prio == 0 &&
-				require_policy_update())
+				require_policy_update() && install_outbound)
 			{
-				status |= install_policies_internal(this, this->my_addr,
+				status |= install_policies_outbound(this, this->my_addr,
 									this->other_addr, my_ts, other_ts,
 									&my_sa, &other_sa, POLICY_DROP,
 									POLICY_PRIORITY_FALLBACK, 0);
 			}
 
-			/* install policies */
-			status |= install_policies_internal(this, this->my_addr,
+			status |= install_policies_inbound(this, this->my_addr,
 									this->other_addr, my_ts, other_ts,
 									&my_sa, &other_sa, POLICY_IPSEC,
 									priority, manual_prio);
 
+			if (install_outbound)
+			{
+				status |= install_policies_outbound(this, this->my_addr,
+									this->other_addr, my_ts, other_ts,
+									&my_sa, &other_sa, POLICY_IPSEC,
+									priority, manual_prio);
+
+			}
 			if (status != SUCCESS)
 			{
 				break;
@@ -1103,13 +1267,150 @@ METHOD(child_sa_t, add_policies, status_t,
 	return status;
 }
 
-/**
- * Callback to reinstall a virtual IP
- */
-static void reinstall_vip(host_t *vip, host_t *me)
+METHOD(child_sa_t, register_outbound, void,
+	private_child_sa_t *this, chunk_t encr, chunk_t integ, uint32_t spi,
+	uint16_t cpi, bool tfcv3)
+{
+	DBG2(DBG_CHD, "registering outbound %N SA", protocol_id_names,
+		 this->protocol);
+	DBG2(DBG_CHD, "  SPI 0x%.8x, src %H dst %H", ntohl(spi), this->my_addr,
+		 this->other_addr);
+
+	this->other_spi = spi;
+	this->other_cpi = cpi;
+	this->encr_r = chunk_clone(encr);
+	this->integ_r = chunk_clone(integ);
+	this->tfcv3 = tfcv3;
+	this->outbound_state = CHILD_OUTBOUND_REGISTERED;
+}
+
+METHOD(child_sa_t, install_outbound, status_t,
+	private_child_sa_t *this)
+{
+	enumerator_t *enumerator;
+	traffic_selector_t *my_ts, *other_ts;
+	status_t status;
+
+	status = install_internal(this, this->encr_r, this->integ_r,
+							  this->other_spi, this->other_cpi, FALSE, FALSE,
+							  this->tfcv3);
+	chunk_clear(&this->encr_r);
+	chunk_clear(&this->integ_r);
+	if (status != SUCCESS)
+	{
+		return status;
+	}
+	if (!this->config->has_option(this->config, OPT_NO_POLICIES))
+	{
+		ipsec_sa_cfg_t my_sa, other_sa;
+		uint32_t manual_prio;
+
+		prepare_sa_cfg(this, &my_sa, &other_sa);
+		manual_prio = this->config->get_manual_prio(this->config);
+
+		enumerator = create_policy_enumerator(this);
+		while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
+		{
+			/* install outbound drop policy to avoid packets leaving unencrypted
+			 * when updating policies */
+			if (manual_prio == 0 &&	require_policy_update())
+			{
+				status |= install_policies_outbound(this, this->my_addr,
+									this->other_addr, my_ts, other_ts,
+									&my_sa, &other_sa, POLICY_DROP,
+									POLICY_PRIORITY_FALLBACK, 0);
+			}
+			status |= install_policies_outbound(this, this->my_addr,
+									this->other_addr, my_ts, other_ts,
+									&my_sa, &other_sa, POLICY_IPSEC,
+									POLICY_PRIORITY_DEFAULT, manual_prio);
+			if (status != SUCCESS)
+			{
+				break;
+			}
+		}
+		enumerator->destroy(enumerator);
+	}
+	return status;
+}
+
+METHOD(child_sa_t, remove_outbound, void,
+	private_child_sa_t *this)
+{
+	enumerator_t *enumerator;
+	traffic_selector_t *my_ts, *other_ts;
+
+	switch (this->outbound_state)
+	{
+		case CHILD_OUTBOUND_INSTALLED:
+			break;
+		case CHILD_OUTBOUND_REGISTERED:
+			chunk_clear(&this->encr_r);
+			chunk_clear(&this->integ_r);
+			this->outbound_state = CHILD_OUTBOUND_NONE;
+			/* fall-through */
+		case CHILD_OUTBOUND_NONE:
+			return;
+	}
+
+	if (!this->config->has_option(this->config, OPT_NO_POLICIES))
+	{
+		ipsec_sa_cfg_t my_sa, other_sa;
+		uint32_t manual_prio;
+
+		prepare_sa_cfg(this, &my_sa, &other_sa);
+		manual_prio = this->config->get_manual_prio(this->config);
+
+		enumerator = create_policy_enumerator(this);
+		while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
+		{
+			del_policies_outbound(this, this->my_addr, this->other_addr,
+								  my_ts, other_ts, &my_sa, &other_sa,
+								  POLICY_IPSEC, POLICY_PRIORITY_DEFAULT,
+								  manual_prio);
+			if (manual_prio == 0 && require_policy_update())
+			{
+				del_policies_outbound(this, this->my_addr, this->other_addr,
+									  my_ts, other_ts, &my_sa, &other_sa,
+									  POLICY_DROP, POLICY_PRIORITY_FALLBACK, 0);
+			}
+		}
+		enumerator->destroy(enumerator);
+	}
+
+	kernel_ipsec_sa_id_t id = {
+		.src = this->my_addr,
+		.dst = this->other_addr,
+		.spi = this->other_spi,
+		.proto = proto_ike2ip(this->protocol),
+		.mark = this->mark_out,
+	};
+	kernel_ipsec_del_sa_t sa = {
+		.cpi = this->other_cpi,
+	};
+	charon->kernel->del_sa(charon->kernel, &id, &sa);
+	this->outbound_state = CHILD_OUTBOUND_NONE;
+}
+
+METHOD(child_sa_t, set_rekey_spi, void,
+	private_child_sa_t *this, uint32_t spi)
+{
+	this->rekey_spi = spi;
+}
+
+METHOD(child_sa_t, get_rekey_spi, uint32_t,
+	private_child_sa_t *this)
 {
+	return this->rekey_spi;
+}
+
+CALLBACK(reinstall_vip, void,
+	host_t *vip, va_list args)
+{
+	host_t *me;
 	char *iface;
 
+	VA_ARGS_VGET(args, me);
 	if (charon->kernel->get_interface(charon->kernel, me, &iface))
 	{
 		charon->kernel->del_ip(charon->kernel, vip, -1, TRUE);
@@ -1134,8 +1435,9 @@ METHOD(child_sa_t, update, status_t,
 
 	old = this->state;
 	set_state(this, CHILD_UPDATING);
-	transport_proxy_mode = this->config->use_proxy_mode(this->config) &&
-						   this->mode == MODE_TRANSPORT;
+	transport_proxy_mode = this->mode == MODE_TRANSPORT &&
+						   this->config->has_option(this->config,
+													OPT_PROXY_MODE);
 
 	if (!transport_proxy_mode)
 	{
@@ -1189,7 +1491,8 @@ METHOD(child_sa_t, update, status_t,
 		}
 	}
 
-	if (this->config->install_policy(this->config) && require_policy_update())
+	if (!this->config->has_option(this->config, OPT_NO_POLICIES) &&
+		require_policy_update())
 	{
 		if (!me->ip_equals(me, this->my_addr) ||
 			!other->ip_equals(other, this->other_addr))
@@ -1229,7 +1532,7 @@ METHOD(child_sa_t, update, status_t,
 
 				/* we reinstall the virtual IP to handle interface roaming
 				 * correctly */
-				vips->invoke_function(vips, (void*)reinstall_vip, me);
+				vips->invoke_function(vips, reinstall_vip, me);
 
 				/* reinstall updated policies */
 				install_policies_internal(this, me, other, my_ts, other_ts,
@@ -1239,12 +1542,12 @@ METHOD(child_sa_t, update, status_t,
 				/* update fallback policies after the new policy is in place */
 				if (manual_prio == 0)
 				{
-					del_policies_internal(this, this->my_addr, this->other_addr,
+					del_policies_outbound(this, this->my_addr, this->other_addr,
 										  old_my_ts ?: my_ts,
 										  old_other_ts ?: other_ts,
 										  &my_sa, &other_sa, POLICY_DROP,
 										  POLICY_PRIORITY_FALLBACK, 0);
-					install_policies_internal(this, me, other, my_ts, other_ts,
+					install_policies_outbound(this, me, other, my_ts, other_ts,
 										  &my_sa, &other_sa, POLICY_DROP,
 										  POLICY_PRIORITY_FALLBACK, 0);
 				}
@@ -1287,25 +1590,35 @@ METHOD(child_sa_t, destroy, void,
 
 	set_state(this, CHILD_DESTROYING);
 
-	if (this->config->install_policy(this->config))
+	if (!this->config->has_option(this->config, OPT_NO_POLICIES))
 	{
 		ipsec_sa_cfg_t my_sa, other_sa;
 		uint32_t manual_prio;
+		bool del_outbound;
 
 		prepare_sa_cfg(this, &my_sa, &other_sa);
 		manual_prio = this->config->get_manual_prio(this->config);
+		del_outbound = this->trap ||
+					   this->outbound_state == CHILD_OUTBOUND_INSTALLED;
 
 		/* delete all policies in the kernel */
 		enumerator = create_policy_enumerator(this);
 		while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
 		{
-			del_policies_internal(this, this->my_addr, this->other_addr,
-								  my_ts, other_ts, &my_sa, &other_sa,
-								  POLICY_IPSEC, priority, manual_prio);
-			if (priority == POLICY_PRIORITY_DEFAULT && manual_prio == 0 &&
-				require_policy_update())
+			if (del_outbound)
 			{
-				del_policies_internal(this, this->my_addr, this->other_addr,
+				del_policies_outbound(this, this->my_addr,
+									  this->other_addr, my_ts, other_ts,
+									  &my_sa, &other_sa, POLICY_IPSEC,
+									  priority, manual_prio);
+			}
+			del_policies_inbound(this, this->my_addr, this->other_addr,
+								 my_ts, other_ts, &my_sa, &other_sa,
+								 POLICY_IPSEC, priority, manual_prio);
+			if (!this->trap && manual_prio == 0 && require_policy_update() &&
+				del_outbound)
+			{
+				del_policies_outbound(this, this->my_addr, this->other_addr,
 									  my_ts, other_ts, &my_sa, &other_sa,
 									  POLICY_DROP, POLICY_PRIORITY_FALLBACK, 0);
 			}
@@ -1327,7 +1640,7 @@ METHOD(child_sa_t, destroy, void,
 		};
 		charon->kernel->del_sa(charon->kernel, &id, &sa);
 	}
-	if (this->other_spi)
+	if (this->other_spi && this->outbound_state == CHILD_OUTBOUND_INSTALLED)
 	{
 		kernel_ipsec_sa_id_t id = {
 			.src = this->my_addr,
@@ -1357,6 +1670,8 @@ METHOD(child_sa_t, destroy, void,
 	this->other_addr->destroy(this->other_addr);
 	DESTROY_IF(this->proposal);
 	this->config->destroy(this->config);
+	chunk_clear(&this->encr_r);
+	chunk_clear(&this->integ_r);
 	free(this);
 }
 
@@ -1414,6 +1729,7 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
 			.get_config = _get_config,
 			.get_state = _get_state,
 			.set_state = _set_state,
+			.get_outbound_state = _get_outbound_state,
 			.get_spi = _get_spi,
 			.get_cpi = _get_cpi,
 			.get_protocol = _get_protocol,
@@ -1436,8 +1752,14 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
 			.alloc_spi = _alloc_spi,
 			.alloc_cpi = _alloc_cpi,
 			.install = _install,
+			.register_outbound = _register_outbound,
+			.install_outbound = _install_outbound,
+			.remove_outbound = _remove_outbound,
+			.set_rekey_spi = _set_rekey_spi,
+			.get_rekey_spi = _get_rekey_spi,
 			.update = _update,
-			.add_policies = _add_policies,
+			.set_policies = _set_policies,
+			.install_policies = _install_policies,
 			.create_ts_enumerator = _create_ts_enumerator,
 			.create_policy_enumerator = _create_policy_enumerator,
 			.destroy = _destroy,
@@ -1456,7 +1778,7 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
 		.mark_in = config->get_mark(config, TRUE),
 		.mark_out = config->get_mark(config, FALSE),
 		.install_time = time_monotonic(NULL),
-		.policies_fwd_out = config->install_fwd_out_policy(config),
+		.policies_fwd_out = config->has_option(config, OPT_FWD_OUT_POLICIES),
 	);
 
 	this->config = config;
@@ -1509,7 +1831,7 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
 
 	/* MIPv6 proxy transport mode sets SA endpoints to TS hosts */
 	if (config->get_mode(config) == MODE_TRANSPORT &&
-		config->use_proxy_mode(config))
+		config->has_option(config, OPT_PROXY_MODE))
 	{
 		this->mode = MODE_TRANSPORT;
 
diff --git a/src/libcharon/sa/child_sa.h b/src/libcharon/sa/child_sa.h
index bc7df99..b9a913d 100644
--- a/src/libcharon/sa/child_sa.h
+++ b/src/libcharon/sa/child_sa.h
@@ -1,8 +1,8 @@
 /*
- * Copyright (C) 2006-2008 Tobias Brunner
+ * Copyright (C) 2006-2017 Tobias Brunner
  * Copyright (C) 2006-2008 Martin Willi
  * Copyright (C) 2006 Daniel Roethlisberger
- * Hochschule fuer Technik Rapperswil
+ * HSR 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
@@ -24,6 +24,7 @@
 #define CHILD_SA_H_
 
 typedef enum child_sa_state_t child_sa_state_t;
+typedef enum child_sa_outbound_state_t child_sa_outbound_state_t;
 typedef struct child_sa_t child_sa_t;
 
 #include <library.h>
@@ -53,7 +54,7 @@ enum child_sa_state_t {
 	CHILD_INSTALLING,
 
 	/**
-	 * Installed an in-use CHILD_SA
+	 * Installed both SAs of a CHILD_SA
 	 */
 	CHILD_INSTALLED,
 
@@ -94,6 +95,32 @@ enum child_sa_state_t {
 extern enum_name_t *child_sa_state_names;
 
 /**
+ * States of the outbound SA of a CHILD_SA
+ */
+enum child_sa_outbound_state_t {
+
+	/**
+	 * Outbound SA is not installed
+	 */
+	CHILD_OUTBOUND_NONE,
+
+	/**
+	 * Data for the outbound SA has been registered, but not installed yet
+	 */
+	CHILD_OUTBOUND_REGISTERED,
+
+	/**
+	 * The outbound SA is currently installed
+	 */
+	CHILD_OUTBOUND_INSTALLED,
+};
+
+/**
+ * enum strings for child_sa_outbound_state_t.
+ */
+extern enum_name_t *child_sa_outbound_state_names;
+
+/**
  * Represents an IPsec SAs between two hosts.
  *
  * A child_sa_t contains two SAs. SAs for both
@@ -152,7 +179,14 @@ struct child_sa_t {
 	 *
 	 * @return 			CHILD_SA state
 	 */
-	child_sa_state_t (*get_state) (child_sa_t *this);
+	child_sa_state_t (*get_state)(child_sa_t *this);
+
+	/**
+	 * Get the state of the outbound SA.
+	 *
+	 * @return 			outbound SA state
+	 */
+	child_sa_outbound_state_t (*get_outbound_state)(child_sa_t *this);
 
 	/**
 	 * Set the state of the CHILD_SA.
@@ -347,6 +381,8 @@ struct child_sa_t {
 	/**
 	 * Install an IPsec SA for one direction.
 	 *
+	 * set_policies() should be called before calling this.
+	 *
 	 * @param encr		encryption key, if any
 	 * @param integ		integrity key
 	 * @param spi		SPI to use, allocated for inbound
@@ -354,26 +390,84 @@ struct child_sa_t {
 	 * @param initiator	TRUE if initiator of exchange resulting in this SA
 	 * @param inbound	TRUE to install an inbound SA, FALSE for outbound
 	 * @param tfcv3		TRUE if peer supports ESPv3 TFC
-	 * @param my_ts		negotiated local traffic selector list
-	 * @param other_ts	negotiated remote traffic selector list
 	 * @return			SUCCESS or FAILED
 	 */
 	status_t (*install)(child_sa_t *this, chunk_t encr, chunk_t integ,
 						uint32_t spi, uint16_t cpi,
-						bool initiator, bool inbound, bool tfcv3,
-						linked_list_t *my_ts, linked_list_t *other_ts);
+						bool initiator, bool inbound, bool tfcv3);
+
+	/**
+	 * Register data for the installation of an outbound SA as responder during
+	 * a rekeying.
+	 *
+	 * The SA is not installed until install_outbound() is called.
+	 *
+	 * @param encr		encryption key, if any (cloned)
+	 * @param integ		integrity key (cloned)
+	 * @param spi		SPI to use, allocated for inbound
+	 * @param cpi		CPI to use, allocated for outbound
+	 * @param tfcv3		TRUE if peer supports ESPv3 TFC
+	 */
+	void (*register_outbound)(child_sa_t *this, chunk_t encr, chunk_t integ,
+							  uint32_t spi, uint16_t cpi, bool tfcv3);
+
+	/**
+	 * Install the outbound SA and the outbound policies as responder during a
+	 * rekeying.
+	 *
+	 * @return			SUCCESS or FAILED
+	 */
+	status_t (*install_outbound)(child_sa_t *this);
+
+	/**
+	 * Remove the outbound SA and the outbound policies after a rekeying.
+	 */
+	void (*remove_outbound)(child_sa_t *this);
+
 	/**
-	 * Install the policies using some traffic selectors.
+	 * Configure the policies using some traffic selectors.
 	 *
 	 * Supplied lists of traffic_selector_t's specify the policies
 	 * to use for this child sa.
 	 *
-	 * @param my_ts		traffic selectors for local site
-	 * @param other_ts	traffic selectors for remote site
+	 * Install the policies by calling install_policies().
+	 *
+	 * This should be called before calling install() so the traffic selectors
+	 * may be passed to the kernel interface when installing the SAs.
+	 *
+	 * @param my_ts		traffic selectors for local site (cloned)
+	 * @param other_ts	traffic selectors for remote site (cloned)
+	 */
+	void (*set_policies)(child_sa_t *this, linked_list_t *my_ts_list,
+						 linked_list_t *other_ts_list);
+
+	/**
+	 * Install the configured policies.
+	 *
+	 * If register_outbound() was called previously this only installs the
+	 * inbound and forward policies, the outbound policies are installed when
+	 * install_outbound() is called.
+	 *
 	 * @return			SUCCESS or FAILED
 	 */
-	status_t (*add_policies)(child_sa_t *this, linked_list_t *my_ts_list,
-							 linked_list_t *other_ts_list);
+	status_t (*install_policies)(child_sa_t *this);
+
+	/**
+	 * Set the outbound SPI of the CHILD_SA that replaced this CHILD_SA during
+	 * a rekeying.
+	 *
+	 * @param spi		outbound SPI of the CHILD_SA that replaced this CHILD_SA
+	 */
+	void (*set_rekey_spi)(child_sa_t *this, uint32_t spi);
+
+	/**
+	 * Get the outbound SPI of the CHILD_SA that replaced this CHILD_SA during
+	 * a rekeying.
+	 *
+	 * @return			outbound SPI of the CHILD_SA that replaced this CHILD_SA
+	 */
+	uint32_t (*get_rekey_spi)(child_sa_t *this);
+
 	/**
 	 * Update hosts and ecapulation mode in the kernel SAs and policies.
 	 *
diff --git a/src/libcharon/sa/eap/eap_manager.c b/src/libcharon/sa/eap/eap_manager.c
index e4fcbc8..b2a57cc 100644
--- a/src/libcharon/sa/eap/eap_manager.c
+++ b/src/libcharon/sa/eap/eap_manager.c
@@ -105,31 +105,38 @@ METHOD(eap_manager_t, remove_method, void,
 	this->lock->unlock(this->lock);
 }
 
-/**
- * filter the registered methods
- */
-static bool filter_methods(uintptr_t role, eap_entry_t **entry,
-						   eap_type_t *type, void *in, uint32_t *vendor)
+CALLBACK(filter_methods, bool,
+	uintptr_t role, enumerator_t *orig, va_list args)
 {
-	if ((*entry)->role != (eap_role_t)role)
-	{
-		return FALSE;
-	}
-	if ((*entry)->vendor == 0 &&
-	   ((*entry)->type < 4 || (*entry)->type == EAP_EXPANDED ||
-	    (*entry)->type > EAP_EXPERIMENTAL))
-	{	/* filter invalid types */
-		return FALSE;
-	}
-	if (type)
-	{
-		*type = (*entry)->type;
-	}
-	if (vendor)
+	eap_entry_t *entry;
+	eap_type_t *type;
+	uint32_t *vendor;
+
+	VA_ARGS_VGET(args, type, vendor);
+
+	while (orig->enumerate(orig, &entry))
 	{
-		*vendor = (*entry)->vendor;
+		if (entry->role != (eap_role_t)role)
+		{
+			continue;
+		}
+		if (entry->vendor == 0 &&
+		   (entry->type < 4 || entry->type == EAP_EXPANDED ||
+		    entry->type > EAP_EXPERIMENTAL))
+		{	/* filter invalid types */
+			continue;
+		}
+		if (type)
+		{
+			*type = entry->type;
+		}
+		if (vendor)
+		{
+			*vendor = entry->vendor;
+		}
+		return TRUE;
 	}
-	return TRUE;
+	return FALSE;
 }
 
 METHOD(eap_manager_t, create_enumerator, enumerator_t*,
@@ -139,7 +146,7 @@ METHOD(eap_manager_t, create_enumerator, enumerator_t*,
 	return enumerator_create_cleaner(
 				enumerator_create_filter(
 					this->methods->create_enumerator(this->methods),
-					(void*)filter_methods, (void*)(uintptr_t)role, NULL),
+					filter_methods, (void*)(uintptr_t)role, NULL),
 				(void*)this->lock->unlock, this->lock);
 }
 
diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c
index 76e1069..0458587 100644
--- a/src/libcharon/sa/ike_sa.c
+++ b/src/libcharon/sa/ike_sa.c
@@ -1200,12 +1200,20 @@ METHOD(ike_sa_t, generate_message, status_t,
 	return status;
 }
 
-static bool filter_fragments(private_ike_sa_t *this, packet_t **fragment,
-							 packet_t **packet)
+CALLBACK(filter_fragments, bool,
+	private_ike_sa_t *this, enumerator_t *orig, va_list args)
 {
-	*packet = (*fragment)->clone(*fragment);
-	set_dscp(this, *packet);
-	return TRUE;
+	packet_t *fragment, **packet;
+
+	VA_ARGS_VGET(args, packet);
+
+	if (orig->enumerate(orig, &fragment))
+	{
+		*packet = fragment->clone(fragment);
+		set_dscp(this, *packet);
+		return TRUE;
+	}
+	return FALSE;
 }
 
 METHOD(ike_sa_t, generate_message_fragmented, status_t,
@@ -1265,7 +1273,7 @@ METHOD(ike_sa_t, generate_message_fragmented, status_t,
 		{
 			charon->bus->message(charon->bus, message, FALSE, FALSE);
 		}
-		*packets = enumerator_create_filter(fragments, (void*)filter_fragments,
+		*packets = enumerator_create_filter(fragments, filter_fragments,
 											this, NULL);
 	}
 	return status;
@@ -1699,8 +1707,11 @@ typedef struct {
 } child_enumerator_t;
 
 METHOD(enumerator_t, child_enumerate, bool,
-	child_enumerator_t *this, child_sa_t **child_sa)
+	child_enumerator_t *this, va_list args)
 {
+	child_sa_t **child_sa;
+
+	VA_ARGS_VGET(args, child_sa);
 	if (this->inner->enumerate(this->inner, &this->current))
 	{
 		*child_sa = this->current;
@@ -1723,7 +1734,8 @@ METHOD(ike_sa_t, create_child_sa_enumerator, enumerator_t*,
 
 	INIT(enumerator,
 		.public = {
-			.enumerate = (void*)_child_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _child_enumerate,
 			.destroy = _child_enumerator_destroy,
 		},
 		.inner = array_create_enumerator(this->child_sas),
@@ -2619,24 +2631,31 @@ METHOD(ike_sa_t, add_configuration_attribute, void,
 	array_insert(this->attributes, ARRAY_TAIL, &entry);
 }
 
-/**
- * Enumerator filter for attributes
- */
-static bool filter_attribute(void *null, attribute_entry_t **in,
-							 configuration_attribute_type_t *type, void *in2,
-							 chunk_t *data, void *in3, bool *handled)
+CALLBACK(filter_attribute, bool,
+	void *null, enumerator_t *orig, va_list args)
 {
-	*type = (*in)->type;
-	*data = (*in)->data;
-	*handled = (*in)->handler != NULL;
-	return TRUE;
+	attribute_entry_t *entry;
+	configuration_attribute_type_t *type;
+	chunk_t *data;
+	bool *handled;
+
+	VA_ARGS_VGET(args, type, data, handled);
+
+	if (orig->enumerate(orig, &entry))
+	{
+		*type = entry->type;
+		*data = entry->data;
+		*handled = entry->handler != NULL;
+		return TRUE;
+	}
+	return FALSE;
 }
 
 METHOD(ike_sa_t, create_attribute_enumerator, enumerator_t*,
 	private_ike_sa_t *this)
 {
 	return enumerator_create_filter(array_create_enumerator(this->attributes),
-									(void*)filter_attribute, NULL, NULL);
+									filter_attribute, NULL, NULL);
 }
 
 METHOD(ike_sa_t, create_task_enumerator, enumerator_t*,
diff --git a/src/libcharon/sa/ike_sa_manager.c b/src/libcharon/sa/ike_sa_manager.c
index 6bd49a0..c0bfebb 100644
--- a/src/libcharon/sa/ike_sa_manager.c
+++ b/src/libcharon/sa/ike_sa_manager.c
@@ -151,8 +151,10 @@ static entry_t *entry_create()
 /**
  * Function that matches entry_t objects by ike_sa_id_t.
  */
-static bool entry_match_by_id(entry_t *entry, ike_sa_id_t *id)
+static bool entry_match_by_id(entry_t *entry, void *arg)
 {
+	ike_sa_id_t *id = arg;
+
 	if (id->equals(id, entry->ike_sa_id))
 	{
 		return TRUE;
@@ -172,7 +174,7 @@ static bool entry_match_by_id(entry_t *entry, ike_sa_id_t *id)
 /**
  * Function that matches entry_t objects by ike_sa_t pointers.
  */
-static bool entry_match_by_sa(entry_t *entry, ike_sa_t *ike_sa)
+static bool entry_match_by_sa(entry_t *entry, void *ike_sa)
 {
 	return entry->ike_sa == ike_sa;
 }
@@ -276,9 +278,6 @@ typedef struct segment_t segment_t;
 struct segment_t {
 	/** mutex to access a segment exclusively */
 	mutex_t *mutex;
-
-	/** the number of entries in this segment */
-	u_int count;
 };
 
 typedef struct shareable_segment_t shareable_segment_t;
@@ -371,6 +370,11 @@ struct private_ike_sa_manager_t {
 	refcount_t half_open_count_responder;
 
 	/**
+	 * Total number of IKE_SAs registered with IKE_SA manager.
+	 */
+	refcount_t total_sa_count;
+
+	/**
 	 * Hash table with connected_peers_t objects.
 	 */
 	table_item_t **connected_peers_table;
@@ -511,8 +515,13 @@ struct private_enumerator_t {
 };
 
 METHOD(enumerator_t, enumerate, bool,
-	private_enumerator_t *this, entry_t **entry, u_int *segment)
+	private_enumerator_t *this, va_list args)
 {
+	entry_t **entry;
+	u_int *segment;
+
+	VA_ARGS_VGET(args, entry, segment);
+
 	if (this->entry)
 	{
 		this->entry->condvar->signal(this->entry->condvar);
@@ -570,7 +579,8 @@ static enumerator_t* create_table_enumerator(private_ike_sa_manager_t *this)
 
 	INIT(enumerator,
 		.enumerator = {
-			.enumerate = (void*)_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _enumerate,
 			.destroy = _enumerator_destroy,
 		},
 		.manager = this,
@@ -601,7 +611,7 @@ static u_int put_entry(private_ike_sa_manager_t *this, entry_t *entry)
 		item->next = current;
 	}
 	this->ike_sa_table[row] = item;
-	this->segments[segment].count++;
+	ref_get(&this->total_sa_count);
 	return segment;
 }
 
@@ -612,10 +622,9 @@ static u_int put_entry(private_ike_sa_manager_t *this, entry_t *entry)
 static void remove_entry(private_ike_sa_manager_t *this, entry_t *entry)
 {
 	table_item_t *item, *prev = NULL;
-	u_int row, segment;
+	u_int row;
 
 	row = ike_sa_id_hash(entry->ike_sa_id) & this->table_mask;
-	segment = row & this->segment_mask;
 	item = this->ike_sa_table[row];
 	while (item)
 	{
@@ -629,7 +638,7 @@ static void remove_entry(private_ike_sa_manager_t *this, entry_t *entry)
 			{
 				this->ike_sa_table[row] = item->next;
 			}
-			this->segments[segment].count--;
+			ignore_result(ref_put(&this->total_sa_count));
 			free(item);
 			break;
 		}
@@ -648,7 +657,7 @@ static void remove_entry_at(private_enumerator_t *this)
 	{
 		table_item_t *current = this->current;
 
-		this->manager->segments[this->segment].count--;
+		ignore_result(ref_put(&this->manager->total_sa_count));
 		this->current = this->prev;
 
 		if (this->prev)
@@ -670,7 +679,7 @@ static void remove_entry_at(private_enumerator_t *this)
  */
 static status_t get_entry_by_match_function(private_ike_sa_manager_t *this,
 					ike_sa_id_t *ike_sa_id, entry_t **entry, u_int *segment,
-					linked_list_match_t match, void *param)
+					bool (*match)(entry_t*,void*), void *param)
 {
 	table_item_t *item;
 	u_int row, seg;
@@ -703,7 +712,7 @@ static status_t get_entry_by_id(private_ike_sa_manager_t *this,
 						ike_sa_id_t *ike_sa_id, entry_t **entry, u_int *segment)
 {
 	return get_entry_by_match_function(this, ike_sa_id, entry, segment,
-				(linked_list_match_t)entry_match_by_id, ike_sa_id);
+									   entry_match_by_id, ike_sa_id);
 }
 
 /**
@@ -714,7 +723,7 @@ static status_t get_entry_by_sa(private_ike_sa_manager_t *this,
 			ike_sa_id_t *ike_sa_id, ike_sa_t *ike_sa, entry_t **entry, u_int *segment)
 {
 	return get_entry_by_match_function(this, ike_sa_id, entry, segment,
-				(linked_list_match_t)entry_match_by_sa, ike_sa);
+									   entry_match_by_sa, ike_sa);
 }
 
 /**
@@ -851,6 +860,15 @@ static void remove_half_open(private_ike_sa_manager_t *this, entry_t *entry)
 	lock->unlock(lock);
 }
 
+CALLBACK(id_matches, bool,
+	ike_sa_id_t *a, va_list args)
+{
+	ike_sa_id_t *b;
+
+	VA_ARGS_VGET(args, b);
+	return a->equals(a, b);
+}
+
 /**
  * Put an SA between two peers into the hash table.
  */
@@ -879,8 +897,7 @@ static void put_connected_peers(private_ike_sa_manager_t *this, entry_t *entry)
 								  entry->other_id, family))
 		{
 			if (connected_peers->sas->find_first(connected_peers->sas,
-					(linked_list_match_t)entry->ike_sa_id->equals,
-					NULL, entry->ike_sa_id) == SUCCESS)
+											id_matches, NULL, entry->ike_sa_id))
 			{
 				lock->unlock(lock);
 				return;
@@ -1555,42 +1572,52 @@ METHOD(ike_sa_manager_t, checkout_by_name, ike_sa_t*,
 	return ike_sa;
 }
 
-/**
- * enumerator filter function, waiting variant
- */
-static bool enumerator_filter_wait(private_ike_sa_manager_t *this,
-								   entry_t **in, ike_sa_t **out, u_int *segment)
+CALLBACK(enumerator_filter_wait, bool,
+	private_ike_sa_manager_t *this, enumerator_t *orig, va_list args)
 {
-	if (wait_for_entry(this, *in, *segment))
+	entry_t *entry;
+	u_int segment;
+	ike_sa_t **out;
+
+	VA_ARGS_VGET(args, out);
+
+	while (orig->enumerate(orig, &entry, &segment))
 	{
-		*out = (*in)->ike_sa;
-		charon->bus->set_sa(charon->bus, *out);
-		return TRUE;
+		if (wait_for_entry(this, entry, segment))
+		{
+			*out = entry->ike_sa;
+			charon->bus->set_sa(charon->bus, *out);
+			return TRUE;
+		}
 	}
 	return FALSE;
 }
 
-/**
- * enumerator filter function, skipping variant
- */
-static bool enumerator_filter_skip(private_ike_sa_manager_t *this,
-								   entry_t **in, ike_sa_t **out, u_int *segment)
+CALLBACK(enumerator_filter_skip, bool,
+	private_ike_sa_manager_t *this, enumerator_t *orig, va_list args)
 {
-	if (!(*in)->driveout_new_threads &&
-		!(*in)->driveout_waiting_threads &&
-		!(*in)->checked_out)
+	entry_t *entry;
+	u_int segment;
+	ike_sa_t **out;
+
+	VA_ARGS_VGET(args, out);
+
+	while (orig->enumerate(orig, &entry, &segment))
 	{
-		*out = (*in)->ike_sa;
-		charon->bus->set_sa(charon->bus, *out);
-		return TRUE;
+		if (!entry->driveout_new_threads &&
+			!entry->driveout_waiting_threads &&
+			!entry->checked_out)
+		{
+			*out = entry->ike_sa;
+			charon->bus->set_sa(charon->bus, *out);
+			return TRUE;
+		}
 	}
 	return FALSE;
 }
 
-/**
- * Reset threads SA after enumeration
- */
-static void reset_sa(void *data)
+CALLBACK(reset_sa, void,
+	void *data)
 {
 	charon->bus->set_sa(charon->bus, NULL);
 }
@@ -2034,17 +2061,7 @@ METHOD(ike_sa_manager_t, has_contact, bool,
 METHOD(ike_sa_manager_t, get_count, u_int,
 	private_ike_sa_manager_t *this)
 {
-	u_int segment, count = 0;
-	mutex_t *mutex;
-
-	for (segment = 0; segment < this->segment_count; segment++)
-	{
-		mutex = this->segments[segment & this->segment_mask].mutex;
-		mutex->lock(mutex);
-		count += this->segments[segment].count;
-		mutex->unlock(mutex);
-	}
-	return count;
+	return (u_int)ref_cur(&this->total_sa_count);
 }
 
 METHOD(ike_sa_manager_t, get_half_open_count, u_int,
diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c
index 1da17ee..48ec3e7 100644
--- a/src/libcharon/sa/ikev1/task_manager_v1.c
+++ b/src/libcharon/sa/ikev1/task_manager_v1.c
@@ -210,6 +210,16 @@ struct private_task_manager_t {
 	double retransmit_base;
 
 	/**
+	 * Jitter to apply to calculated retransmit timeout (in percent)
+	 */
+	u_int retransmit_jitter;
+
+	/**
+	 * Limit retransmit timeout to this value
+	 */
+	uint32_t retransmit_limit;
+
+	/**
 	 * Sequence number for sending DPD requests
 	 */
 	uint32_t dpd_send;
@@ -345,7 +355,7 @@ static status_t retransmit_packet(private_task_manager_t *this, uint32_t seqnr,
 							u_int mid, u_int retransmitted, array_t *packets)
 {
 	packet_t *packet;
-	uint32_t t;
+	uint32_t t, max_jitter;
 
 	array_get(packets, 0, &packet);
 	if (retransmitted > this->retransmit_tries)
@@ -356,6 +366,15 @@ static status_t retransmit_packet(private_task_manager_t *this, uint32_t seqnr,
 	}
 	t = (uint32_t)(this->retransmit_timeout * 1000.0 *
 					pow(this->retransmit_base, retransmitted));
+	if (this->retransmit_limit)
+	{
+		t = min(t, this->retransmit_limit);
+	}
+	if (this->retransmit_jitter)
+	{
+		max_jitter = (t / 100.0) * this->retransmit_jitter;
+		t -= max_jitter * (random() / (RAND_MAX + 1.0));
+	}
 	if (retransmitted)
 	{
 		DBG1(DBG_IKE, "sending retransmit %u of %s message ID %u, seq %u",
@@ -2034,11 +2053,15 @@ task_manager_v1_t *task_manager_v1_create(ike_sa_t *ike_sa)
 		.active_tasks = linked_list_create(),
 		.passive_tasks = linked_list_create(),
 		.retransmit_tries = lib->settings->get_int(lib->settings,
-						"%s.retransmit_tries", RETRANSMIT_TRIES, lib->ns),
+					"%s.retransmit_tries", RETRANSMIT_TRIES, lib->ns),
 		.retransmit_timeout = lib->settings->get_double(lib->settings,
-						"%s.retransmit_timeout", RETRANSMIT_TIMEOUT, lib->ns),
+					"%s.retransmit_timeout", RETRANSMIT_TIMEOUT, lib->ns),
 		.retransmit_base = lib->settings->get_double(lib->settings,
-						"%s.retransmit_base", RETRANSMIT_BASE, lib->ns),
+					"%s.retransmit_base", RETRANSMIT_BASE, lib->ns),
+		.retransmit_jitter = min(lib->settings->get_int(lib->settings,
+					"%s.retransmit_jitter", 0, lib->ns), RETRANSMIT_JITTER_MAX),
+		.retransmit_limit = lib->settings->get_int(lib->settings,
+					"%s.retransmit_limit", 0, lib->ns) * 1000,
 	);
 
 	if (!this->rng)
diff --git a/src/libcharon/sa/ikev1/tasks/quick_mode.c b/src/libcharon/sa/ikev1/tasks/quick_mode.c
index bbb8858..8be82eb 100644
--- a/src/libcharon/sa/ikev1/tasks/quick_mode.c
+++ b/src/libcharon/sa/ikev1/tasks/quick_mode.c
@@ -325,6 +325,17 @@ static bool install(private_quick_mode_t *this)
 		return FALSE;
 	}
 
+	if (this->initiator)
+	{
+		this->child_sa->set_policies(this->child_sa, tsi, tsr);
+	}
+	else
+	{
+		this->child_sa->set_policies(this->child_sa, tsr, tsi);
+	}
+	tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy));
+	tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy));
+
 	if (this->keymat->derive_child_keys(this->keymat, this->proposal, this->dh,
 						this->spi_i, this->spi_r, this->nonce_i, this->nonce_r,
 						&encr_i, &integ_i, &encr_r, &integ_r))
@@ -333,19 +344,19 @@ static bool install(private_quick_mode_t *this)
 		{
 			status_i = this->child_sa->install(this->child_sa,
 									encr_r, integ_r, this->spi_i, this->cpi_i,
-									this->initiator, TRUE, FALSE, tsi, tsr);
+									this->initiator, TRUE, FALSE);
 			status_o = this->child_sa->install(this->child_sa,
 									encr_i, integ_i, this->spi_r, this->cpi_r,
-									this->initiator, FALSE, FALSE, tsi, tsr);
+									this->initiator, FALSE, FALSE);
 		}
 		else
 		{
 			status_i = this->child_sa->install(this->child_sa,
 									encr_i, integ_i, this->spi_r, this->cpi_r,
-									this->initiator, TRUE, FALSE, tsr, tsi);
+									this->initiator, TRUE, FALSE);
 			status_o = this->child_sa->install(this->child_sa,
 									encr_r, integ_r, this->spi_i, this->cpi_i,
-									this->initiator, FALSE, FALSE, tsr, tsi);
+									this->initiator, FALSE, FALSE);
 		}
 	}
 
@@ -355,22 +366,12 @@ static bool install(private_quick_mode_t *this)
 			(status_i != SUCCESS) ? "inbound " : "",
 			(status_i != SUCCESS && status_o != SUCCESS) ? "and ": "",
 			(status_o != SUCCESS) ? "outbound " : "");
-		tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy));
-		tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy));
 		status = FAILED;
 	}
 	else
 	{
-		if (this->initiator)
-		{
-			status = this->child_sa->add_policies(this->child_sa, tsi, tsr);
-		}
-		else
-		{
-			status = this->child_sa->add_policies(this->child_sa, tsr, tsi);
-		}
-		tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy));
-		tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy));
+		status = this->child_sa->install_policies(this->child_sa);
+
 		if (status != SUCCESS)
 		{
 			DBG1(DBG_IKE, "unable to install IPsec policies (SPD) in kernel");
@@ -853,7 +854,7 @@ METHOD(task_t, build_i, status_t,
 				add_nat_oa_payloads(this, message);
 			}
 
-			if (this->config->use_ipcomp(this->config))
+			if (this->config->has_option(this->config, OPT_IPCOMP))
 			{
 				this->cpi_i = this->child_sa->alloc_cpi(this->child_sa);
 				if (!this->cpi_i)
@@ -1108,7 +1109,7 @@ METHOD(task_t, process_r, status_t,
 				return send_notify(this, INVALID_ID_INFORMATION);
 			}
 
-			if (this->config->use_ipcomp(this->config))
+			if (this->config->has_option(this->config, OPT_IPCOMP))
 			{
 				list = sa_payload->get_ipcomp_proposals(sa_payload,
 														&this->cpi_i);
diff --git a/src/libcharon/sa/ikev2/connect_manager.c b/src/libcharon/sa/ikev2/connect_manager.c
index 280796d..3585678 100644
--- a/src/libcharon/sa/ikev2/connect_manager.c
+++ b/src/libcharon/sa/ikev2/connect_manager.c
@@ -450,22 +450,21 @@ static initiate_data_t *initiate_data_create(check_list_t *checklist,
 	return this;
 }
 
-/**
- * Find an initiated connection by the peers' ids
- */
-static bool match_initiated_by_ids(initiated_t *current, identification_t *id,
-								   identification_t *peer_id)
+CALLBACK(match_initiated_by_ids, bool,
+	initiated_t *current, va_list args)
 {
+	identification_t *id, *peer_id;
+
+	VA_ARGS_VGET(args, id, peer_id);
 	return id->equals(id, current->id) && peer_id->equals(peer_id, current->peer_id);
 }
 
-static status_t get_initiated_by_ids(private_connect_manager_t *this,
-									 identification_t *id,
-									 identification_t *peer_id,
-									 initiated_t **initiated)
+static bool get_initiated_by_ids(private_connect_manager_t *this,
+								 identification_t *id,
+								 identification_t *peer_id,
+								 initiated_t **initiated)
 {
-	return this->initiated->find_first(this->initiated,
-								(linked_list_match_t)match_initiated_by_ids,
+	return this->initiated->find_first(this->initiated, match_initiated_by_ids,
 								(void**)initiated, id, peer_id);
 }
 
@@ -490,21 +489,20 @@ static void remove_initiated(private_connect_manager_t *this,
 	enumerator->destroy(enumerator);
 }
 
-/**
- * Find the checklist with a specific connect ID
- */
-static bool match_checklist_by_id(check_list_t *current, chunk_t *connect_id)
+CALLBACK(match_checklist_by_id, bool,
+	check_list_t *current, va_list args)
 {
-	return chunk_equals(*connect_id, current->connect_id);
+	chunk_t connect_id;
+
+	VA_ARGS_VGET(args, connect_id);
+	return chunk_equals(connect_id, current->connect_id);
 }
 
-static status_t get_checklist_by_id(private_connect_manager_t *this,
-									chunk_t connect_id,
-									check_list_t **check_list)
+static bool get_checklist_by_id(private_connect_manager_t *this,
+								chunk_t connect_id, check_list_t **check_list)
 {
-	return this->checklists->find_first(this->checklists,
-								(linked_list_match_t)match_checklist_by_id,
-								(void**)check_list, &connect_id);
+	return this->checklists->find_first(this->checklists, match_checklist_by_id,
+										(void**)check_list, connect_id);
 }
 
 /**
@@ -528,19 +526,19 @@ static void remove_checklist(private_connect_manager_t *this,
 	enumerator->destroy(enumerator);
 }
 
-/**
- * Checks if a list of endpoint_notify_t contains a certain host_t
- */
-static bool match_endpoint_by_host(endpoint_notify_t *current, host_t *host)
+CALLBACK(match_endpoint_by_host, bool,
+	endpoint_notify_t *current, va_list args)
 {
+	host_t *host;
+
+	VA_ARGS_VGET(args, host);
 	return host->equals(host, current->get_host(current));
 }
 
-static status_t endpoints_contain(linked_list_t *endpoints, host_t *host,
+static bool endpoints_contain(linked_list_t *endpoints, host_t *host,
 								  endpoint_notify_t **endpoint)
 {
-	return endpoints->find_first(endpoints,
-								 (linked_list_match_t)match_endpoint_by_host,
+	return endpoints->find_first(endpoints, match_endpoint_by_host,
 								 (void**)endpoint, host);
 }
 
@@ -560,39 +558,44 @@ static void insert_pair_by_priority(linked_list_t *pairs, endpoint_pair_t *pair)
 	enumerator->destroy(enumerator);
 }
 
-/**
- * Searches a list of endpoint_pair_t for a pair with specific host_ts
- */
-static bool match_pair_by_hosts(endpoint_pair_t *current, host_t *local,
-								host_t *remote)
+CALLBACK(match_pair_by_hosts, bool,
+	endpoint_pair_t *current, va_list args)
 {
-	return local->equals(local, current->local) && remote->equals(remote, current->remote);
+	host_t *local, *remote;
+
+	VA_ARGS_VGET(args, local, remote);
+	return local->equals(local, current->local) &&
+		   remote->equals(remote, current->remote);
 }
 
-static status_t get_pair_by_hosts(linked_list_t *pairs, host_t *local,
-								  host_t *remote, endpoint_pair_t **pair)
+static bool get_pair_by_hosts(linked_list_t *pairs, host_t *local,
+							  host_t *remote, endpoint_pair_t **pair)
 {
-	return pairs->find_first(pairs, (linked_list_match_t)match_pair_by_hosts,
-							 (void**)pair, local, remote);
+	return pairs->find_first(pairs, match_pair_by_hosts, (void**)pair, local,
+							 remote);
 }
 
-static bool match_pair_by_id(endpoint_pair_t *current, uint32_t *id)
+CALLBACK(match_pair_by_id, bool,
+	endpoint_pair_t *current, va_list args)
 {
-	return current->id == *id;
+	uint32_t id;
+
+	VA_ARGS_VGET(args, id);
+	return current->id == id;
 }
 
 /**
  * Searches for a pair with a specific id
  */
-static status_t get_pair_by_id(check_list_t *checklist, uint32_t id,
-							   endpoint_pair_t **pair)
+static bool get_pair_by_id(check_list_t *checklist, uint32_t id,
+						   endpoint_pair_t **pair)
 {
-	return checklist->pairs->find_first(checklist->pairs,
-										(linked_list_match_t)match_pair_by_id,
-										(void**)pair, &id);
+	return checklist->pairs->find_first(checklist->pairs, match_pair_by_id,
+										(void**)pair, id);
 }
 
-static bool match_succeeded_pair(endpoint_pair_t *current)
+CALLBACK(match_succeeded_pair, bool,
+	endpoint_pair_t *current, va_list args)
 {
 	return current->state == CHECK_SUCCEEDED;
 }
@@ -600,15 +603,14 @@ static bool match_succeeded_pair(endpoint_pair_t *current)
 /**
  * Returns the best pair of state CHECK_SUCCEEDED from a checklist.
  */
-static status_t get_best_valid_pair(check_list_t *checklist,
-									endpoint_pair_t **pair)
+static bool get_best_valid_pair(check_list_t *checklist, endpoint_pair_t **pair)
 {
-	return checklist->pairs->find_first(checklist->pairs,
-									(linked_list_match_t)match_succeeded_pair,
-									(void**)pair);
+	return checklist->pairs->find_first(checklist->pairs, match_succeeded_pair,
+										(void**)pair);
 }
 
-static bool match_waiting_pair(endpoint_pair_t *current)
+CALLBACK(match_waiting_pair, bool,
+	endpoint_pair_t *current, va_list args)
 {
 	return current->state == CHECK_WAITING;
 }
@@ -865,7 +867,7 @@ static job_requeue_t initiator_finish(callback_data_t *data)
 	this->mutex->lock(this->mutex);
 
 	check_list_t *checklist;
-	if (get_checklist_by_id(this, data->connect_id, &checklist) != SUCCESS)
+	if (!get_checklist_by_id(this, data->connect_id, &checklist))
 	{
 		DBG1(DBG_IKE, "checklist with id '%#B' not found, can't finish "
 			 "connectivity checks", &data->connect_id);
@@ -953,7 +955,7 @@ static job_requeue_t retransmit(callback_data_t *data)
 	this->mutex->lock(this->mutex);
 
 	check_list_t *checklist;
-	if (get_checklist_by_id(this, data->connect_id, &checklist) != SUCCESS)
+	if (!get_checklist_by_id(this, data->connect_id, &checklist))
 	{
 		DBG1(DBG_IKE, "checklist with id '%#B' not found, can't retransmit "
 			 "connectivity check", &data->connect_id);
@@ -962,7 +964,7 @@ static job_requeue_t retransmit(callback_data_t *data)
 	}
 
 	endpoint_pair_t *pair;
-	if (get_pair_by_id(checklist, data->mid, &pair) != SUCCESS)
+	if (!get_pair_by_id(checklist, data->mid, &pair))
 	{
 		DBG1(DBG_IKE, "pair with id '%d' not found, can't retransmit "
 			 "connectivity check", data->mid);
@@ -1108,7 +1110,7 @@ static job_requeue_t sender(callback_data_t *data)
 	this->mutex->lock(this->mutex);
 
 	check_list_t *checklist;
-	if (get_checklist_by_id(this, data->connect_id, &checklist) != SUCCESS)
+	if (!get_checklist_by_id(this, data->connect_id, &checklist))
 	{
 		DBG1(DBG_IKE, "checklist with id '%#B' not found, can't send "
 			 "connectivity check", &data->connect_id);
@@ -1124,9 +1126,8 @@ static job_requeue_t sender(callback_data_t *data)
 	{
 		DBG1(DBG_IKE, "no triggered check queued, sending an ordinary check");
 
-		if (checklist->pairs->find_first(checklist->pairs,
-									(linked_list_match_t)match_waiting_pair,
-									(void**)&pair) != SUCCESS)
+		if (!checklist->pairs->find_first(checklist->pairs, match_waiting_pair,
+										  (void**)&pair))
 		{
 			this->mutex->unlock(this->mutex);
 			DBG1(DBG_IKE, "no pairs in waiting state, aborting");
@@ -1182,7 +1183,7 @@ static job_requeue_t initiate_mediated(initiate_data_t *data)
 	initiated_t *initiated = data->initiated;
 
 	endpoint_pair_t *pair;
-	if (get_best_valid_pair(checklist, &pair) == SUCCESS)
+	if (get_best_valid_pair(checklist, &pair))
 	{
 		ike_sa_id_t *waiting_sa;
 		enumerator_t *enumerator = initiated->mediated->create_enumerator(
@@ -1219,7 +1220,7 @@ static void finish_checks(private_connect_manager_t *this, check_list_t *checkli
 	{
 		initiated_t *initiated;
 		if (get_initiated_by_ids(this, checklist->initiator.id,
-				checklist->responder.id, &initiated) == SUCCESS)
+								 checklist->responder.id, &initiated))
 		{
 			callback_job_t *job;
 
@@ -1247,7 +1248,7 @@ static void process_response(private_connect_manager_t *this, check_t *check,
 		check_list_t *checklist)
 {
 	endpoint_pair_t *pair;
-	if (get_pair_by_id(checklist, check->mid, &pair) == SUCCESS)
+	if (get_pair_by_id(checklist, check->mid, &pair))
 	{
 		if (pair->local->equals(pair->local, check->dst) &&
 			pair->remote->equals(pair->remote, check->src))
@@ -1261,9 +1262,9 @@ static void process_response(private_connect_manager_t *this, check_t *check,
 			checklist->initiator.endpoints : checklist->responder.endpoints;
 
 		endpoint_notify_t *local_endpoint;
-		if (endpoints_contain(local_endpoints,
-							  check->endpoint->get_host(check->endpoint),
-							  &local_endpoint) != SUCCESS)
+		if (!endpoints_contain(local_endpoints,
+							   check->endpoint->get_host(check->endpoint),
+							   &local_endpoint))
 		{
 			local_endpoint = endpoint_notify_create_from_host(PEER_REFLEXIVE,
 					check->endpoint->get_host(check->endpoint), pair->local);
@@ -1302,15 +1303,14 @@ static void process_request(private_connect_manager_t *this, check_t *check,
 	peer_reflexive->set_priority(peer_reflexive,
 							check->endpoint->get_priority(check->endpoint));
 
-	if (endpoints_contain(remote_endpoints, check->src, &remote_endpoint) != SUCCESS)
+	if (!endpoints_contain(remote_endpoints, check->src, &remote_endpoint))
 	{
 		remote_endpoint = peer_reflexive->clone(peer_reflexive);
 		remote_endpoints->insert_last(remote_endpoints, remote_endpoint);
 	}
 
 	endpoint_pair_t *pair;
-	if (get_pair_by_hosts(checklist->pairs, check->dst, check->src,
-						  &pair) == SUCCESS)
+	if (get_pair_by_hosts(checklist->pairs, check->dst, check->src, &pair))
 	{
 		switch(pair->state)
 		{
@@ -1389,7 +1389,7 @@ METHOD(connect_manager_t, process_check, void,
 	this->mutex->lock(this->mutex);
 
 	check_list_t *checklist;
-	if (get_checklist_by_id(this, check->connect_id, &checklist) != SUCCESS)
+	if (!get_checklist_by_id(this, check->connect_id, &checklist))
 	{
 		DBG1(DBG_IKE, "checklist with id '%#B' not found",
 			 &check->connect_id);
@@ -1423,6 +1423,15 @@ METHOD(connect_manager_t, process_check, void,
 	check_destroy(check);
 }
 
+CALLBACK(id_matches, bool,
+	ike_sa_id_t *a, va_list args)
+{
+	ike_sa_id_t *b;
+
+	VA_ARGS_VGET(args, b);
+	return a->equals(a, b);
+}
+
 METHOD(connect_manager_t, check_and_register, bool,
 	private_connect_manager_t *this, identification_t *id,
 	identification_t *peer_id, ike_sa_id_t *mediated_sa)
@@ -1432,7 +1441,7 @@ METHOD(connect_manager_t, check_and_register, bool,
 
 	this->mutex->lock(this->mutex);
 
-	if (get_initiated_by_ids(this, id, peer_id, &initiated) != SUCCESS)
+	if (!get_initiated_by_ids(this, id, peer_id, &initiated))
 	{
 		DBG2(DBG_IKE, "registered waiting mediated connection with '%Y'",
 			 peer_id);
@@ -1441,9 +1450,8 @@ METHOD(connect_manager_t, check_and_register, bool,
 		already_there = FALSE;
 	}
 
-	if (initiated->mediated->find_first(initiated->mediated,
-								(linked_list_match_t)mediated_sa->equals,
-								NULL, mediated_sa) != SUCCESS)
+	if (!initiated->mediated->find_first(initiated->mediated, id_matches,
+										 NULL, mediated_sa))
 	{
 		initiated->mediated->insert_last(initiated->mediated,
 										 mediated_sa->clone(mediated_sa));
@@ -1462,7 +1470,7 @@ METHOD(connect_manager_t, check_and_initiate, void,
 
 	this->mutex->lock(this->mutex);
 
-	if (get_initiated_by_ids(this, id, peer_id, &initiated) != SUCCESS)
+	if (!get_initiated_by_ids(this, id, peer_id, &initiated))
 	{
 		DBG2(DBG_IKE, "no waiting mediated connections with '%Y'", peer_id);
 		this->mutex->unlock(this->mutex);
@@ -1492,7 +1500,7 @@ METHOD(connect_manager_t, set_initiator_data, status_t,
 
 	this->mutex->lock(this->mutex);
 
-	if (get_checklist_by_id(this, connect_id, NULL) == SUCCESS)
+	if (get_checklist_by_id(this, connect_id, NULL))
 	{
 		DBG1(DBG_IKE, "checklist with id '%#B' already exists, aborting",
 			 &connect_id);
@@ -1517,7 +1525,7 @@ METHOD(connect_manager_t, set_responder_data, status_t,
 
 	this->mutex->lock(this->mutex);
 
-	if (get_checklist_by_id(this, connect_id, &checklist) != SUCCESS)
+	if (!get_checklist_by_id(this, connect_id, &checklist))
 	{
 		DBG1(DBG_IKE, "checklist with id '%#B' not found",
 			 &connect_id);
@@ -1547,7 +1555,7 @@ METHOD(connect_manager_t, stop_checks, status_t,
 
 	this->mutex->lock(this->mutex);
 
-	if (get_checklist_by_id(this, connect_id, &checklist) != SUCCESS)
+	if (!get_checklist_by_id(this, connect_id, &checklist))
 	{
 		DBG1(DBG_IKE, "checklist with id '%#B' not found",
 			 &connect_id);
diff --git a/src/libcharon/sa/ikev2/task_manager_v2.c b/src/libcharon/sa/ikev2/task_manager_v2.c
index e4a16fa..c2ddbc5 100644
--- a/src/libcharon/sa/ikev2/task_manager_v2.c
+++ b/src/libcharon/sa/ikev2/task_manager_v2.c
@@ -161,6 +161,16 @@ struct private_task_manager_t {
 	double retransmit_base;
 
 	/**
+	 * Jitter to apply to calculated retransmit timeout (in percent)
+	 */
+	u_int retransmit_jitter;
+
+	/**
+	 * Limit retransmit timeout to this value
+	 */
+	uint32_t retransmit_limit;
+
+	/**
 	 * Use make-before-break instead of break-before-make reauth?
 	 */
 	bool make_before_break;
@@ -321,7 +331,7 @@ METHOD(task_manager_t, retransmit, status_t,
 	if (message_id == this->initiating.mid &&
 		array_count(this->initiating.packets))
 	{
-		uint32_t timeout;
+		uint32_t timeout, max_jitter;
 		job_t *job;
 		enumerator_t *enumerator;
 		packet_t *packet;
@@ -351,6 +361,16 @@ METHOD(task_manager_t, retransmit, status_t,
 			{
 				timeout = (uint32_t)(this->retransmit_timeout * 1000.0 *
 					pow(this->retransmit_base, this->initiating.retransmitted));
+
+				if (this->retransmit_limit)
+				{
+					timeout = min(timeout, this->retransmit_limit);
+				}
+				if (this->retransmit_jitter)
+				{
+					max_jitter = (timeout / 100.0) * this->retransmit_jitter;
+					timeout -= max_jitter * (random() / (RAND_MAX + 1.0));
+				}
 			}
 			else
 			{
@@ -2059,13 +2079,20 @@ METHOD(task_manager_t, reset, void,
 	this->reset = TRUE;
 }
 
-/**
- * Filter queued tasks
- */
-static bool filter_queued(void *unused, queued_task_t **queued, task_t **task)
+CALLBACK(filter_queued, bool,
+	void *unused, enumerator_t *orig, va_list args)
 {
-	*task = (*queued)->task;
-	return TRUE;
+	queued_task_t *queued;
+	task_t **task;
+
+	VA_ARGS_VGET(args, task);
+
+	if (orig->enumerate(orig, &queued))
+	{
+		*task = queued->task;
+		return TRUE;
+	}
+	return FALSE;
 }
 
 METHOD(task_manager_t, create_task_enumerator, enumerator_t*,
@@ -2080,7 +2107,7 @@ METHOD(task_manager_t, create_task_enumerator, enumerator_t*,
 		case TASK_QUEUE_QUEUED:
 			return enumerator_create_filter(
 									array_create_enumerator(this->queued_tasks),
-									(void*)filter_queued, NULL, NULL);
+									filter_queued, NULL, NULL);
 		default:
 			return enumerator_create_empty();
 	}
@@ -2151,6 +2178,10 @@ task_manager_v2_t *task_manager_v2_create(ike_sa_t *ike_sa)
 					"%s.retransmit_timeout", RETRANSMIT_TIMEOUT, lib->ns),
 		.retransmit_base = lib->settings->get_double(lib->settings,
 					"%s.retransmit_base", RETRANSMIT_BASE, lib->ns),
+		.retransmit_jitter = min(lib->settings->get_int(lib->settings,
+					"%s.retransmit_jitter", 0, lib->ns), RETRANSMIT_JITTER_MAX),
+		.retransmit_limit = lib->settings->get_int(lib->settings,
+					"%s.retransmit_limit", 0, lib->ns) * 1000,
 		.make_before_break = lib->settings->get_bool(lib->settings,
 					"%s.make_before_break", FALSE, lib->ns),
 	);
diff --git a/src/libcharon/sa/ikev2/tasks/child_create.c b/src/libcharon/sa/ikev2/tasks/child_create.c
index 71cb6b8..896cabb 100644
--- a/src/libcharon/sa/ikev2/tasks/child_create.c
+++ b/src/libcharon/sa/ikev2/tasks/child_create.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008-2016 Tobias Brunner
+ * Copyright (C) 2008-2017 Tobias Brunner
  * Copyright (C) 2005-2008 Martin Willi
  * Copyright (C) 2005 Jan Hutter
  * HSR Hochschule fuer Technik Rapperswil
@@ -602,7 +602,7 @@ static status_t select_and_install(private_child_create_t *this,
 		switch (this->mode)
 		{
 			case MODE_TRANSPORT:
-				if (!this->config->use_proxy_mode(this->config) &&
+				if (!this->config->has_option(this->config, OPT_PROXY_MODE) &&
 					   (!ts_list_is_host(this->tsi, other) ||
 						!ts_list_is_host(this->tsr, me))
 				   )
@@ -630,6 +630,32 @@ static status_t select_and_install(private_child_create_t *this,
 			default:
 				break;
 		}
+		/* use a copy of the traffic selectors, as the POST hook should not
+		 * change payloads */
+		my_ts = this->tsr->clone_offset(this->tsr,
+										offsetof(traffic_selector_t, clone));
+		other_ts = this->tsi->clone_offset(this->tsi,
+										offsetof(traffic_selector_t, clone));
+		charon->bus->narrow(charon->bus, this->child_sa,
+							NARROW_RESPONDER_POST, my_ts, other_ts);
+
+		if (my_ts->get_count(my_ts) == 0 ||	other_ts->get_count(other_ts) == 0)
+		{
+			my_ts->destroy_offset(my_ts,
+								  offsetof(traffic_selector_t, destroy));
+			other_ts->destroy_offset(other_ts,
+								  offsetof(traffic_selector_t, destroy));
+			return NOT_FOUND;
+		}
+	}
+
+	this->child_sa->set_policies(this->child_sa, my_ts, other_ts);
+	if (!this->initiator)
+	{
+		my_ts->destroy_offset(my_ts,
+							  offsetof(traffic_selector_t, destroy));
+		other_ts->destroy_offset(other_ts,
+							  offsetof(traffic_selector_t, destroy));
 	}
 
 	this->child_sa->set_state(this->child_sa, CHILD_INSTALLING);
@@ -651,19 +677,30 @@ static status_t select_and_install(private_child_create_t *this,
 		{
 			status_i = this->child_sa->install(this->child_sa, encr_r, integ_r,
 							this->my_spi, this->my_cpi, this->initiator,
-							TRUE, this->tfcv3, my_ts, other_ts);
+							TRUE, this->tfcv3);
 			status_o = this->child_sa->install(this->child_sa, encr_i, integ_i,
 							this->other_spi, this->other_cpi, this->initiator,
-							FALSE, this->tfcv3, my_ts, other_ts);
+							FALSE, this->tfcv3);
 		}
-		else
+		else if (!this->rekey)
 		{
 			status_i = this->child_sa->install(this->child_sa, encr_i, integ_i,
 							this->my_spi, this->my_cpi, this->initiator,
-							TRUE, this->tfcv3, my_ts, other_ts);
+							TRUE, this->tfcv3);
 			status_o = this->child_sa->install(this->child_sa, encr_r, integ_r,
 							this->other_spi, this->other_cpi, this->initiator,
-							FALSE, this->tfcv3, my_ts, other_ts);
+							FALSE, this->tfcv3);
+		}
+		else
+		{	/* as responder during a rekeying we only install the inbound
+			 * SA now, the outbound SA and policies are installed when we
+			 * receive the delete for the old SA */
+			status_i = this->child_sa->install(this->child_sa, encr_i, integ_i,
+							this->my_spi, this->my_cpi, this->initiator,
+							TRUE, this->tfcv3);
+			this->child_sa->register_outbound(this->child_sa, encr_r, integ_r,
+							this->other_spi, this->other_cpi, this->tfcv3);
+			status_o = SUCCESS;
 		}
 	}
 
@@ -679,36 +716,8 @@ static status_t select_and_install(private_child_create_t *this,
 	}
 	else
 	{
-		if (this->initiator)
-		{
-			status = this->child_sa->add_policies(this->child_sa,
-												  my_ts, other_ts);
-		}
-		else
-		{
-			/* use a copy of the traffic selectors, as the POST hook should not
-			 * change payloads */
-			my_ts = this->tsr->clone_offset(this->tsr,
-										offsetof(traffic_selector_t, clone));
-			other_ts = this->tsi->clone_offset(this->tsi,
-										offsetof(traffic_selector_t, clone));
-			charon->bus->narrow(charon->bus, this->child_sa,
-								NARROW_RESPONDER_POST, my_ts, other_ts);
-			if (my_ts->get_count(my_ts) == 0 ||
-				other_ts->get_count(other_ts) == 0)
-			{
-				status = FAILED;
-			}
-			else
-			{
-				status = this->child_sa->add_policies(this->child_sa,
-													  my_ts, other_ts);
-			}
-			my_ts->destroy_offset(my_ts,
-								  offsetof(traffic_selector_t, destroy));
-			other_ts->destroy_offset(other_ts,
-								  offsetof(traffic_selector_t, destroy));
-		}
+		status = this->child_sa->install_policies(this->child_sa);
+
 		if (status != SUCCESS)
 		{
 			DBG1(DBG_IKE, "unable to install IPsec policies (SPD) in kernel");
@@ -736,7 +745,6 @@ static status_t select_and_install(private_child_create_t *this,
 	charon->bus->child_keys(charon->bus, this->child_sa, this->initiator,
 							this->dh, nonce_i, nonce_r);
 
-	/* add to IKE_SA, and remove from task */
 	this->child_sa->set_state(this->child_sa, CHILD_INSTALLED);
 	this->ike_sa->add_child_sa(this->ike_sa, this->child_sa);
 	this->established = TRUE;
@@ -748,16 +756,17 @@ static status_t select_and_install(private_child_create_t *this,
 	other_ts = linked_list_create_from_enumerator(
 				this->child_sa->create_ts_enumerator(this->child_sa, FALSE));
 
-	DBG0(DBG_IKE, "CHILD_SA %s{%d} established "
+	DBG0(DBG_IKE, "%sCHILD_SA %s{%d} established "
 		 "with SPIs %.8x_i %.8x_o and TS %#R === %#R",
+		 this->rekey && !this->initiator ? "inbound " : "",
 		 this->child_sa->get_name(this->child_sa),
 		 this->child_sa->get_unique_id(this->child_sa),
 		 ntohl(this->child_sa->get_spi(this->child_sa, TRUE)),
-		 ntohl(this->child_sa->get_spi(this->child_sa, FALSE)), my_ts, other_ts);
+		 ntohl(this->child_sa->get_spi(this->child_sa, FALSE)),
+		 my_ts, other_ts);
 
 	my_ts->destroy(my_ts);
 	other_ts->destroy(other_ts);
-
 	return SUCCESS;
 }
 
@@ -1073,7 +1082,7 @@ METHOD(task_t, build_i, status_t,
 												  this->dh_group);
 	}
 
-	if (this->config->use_ipcomp(this->config))
+	if (this->config->has_option(this->config, OPT_IPCOMP))
 	{
 		/* IPCOMP_DEFLATE is the only transform we support at the moment */
 		add_ipcomp_notify(this, message, IPCOMP_DEFLATE);
@@ -1327,7 +1336,7 @@ METHOD(task_t, build_r, status_t,
 
 	if (this->ipcomp_received != IPCOMP_NONE)
 	{
-		if (this->config->use_ipcomp(this->config))
+		if (this->config->has_option(this->config, OPT_IPCOMP))
 		{
 			add_ipcomp_notify(this, message, this->ipcomp_received);
 		}
@@ -1690,7 +1699,6 @@ METHOD(task_t, destroy, void,
 	{
 		this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy));
 	}
-
 	DESTROY_IF(this->config);
 	DESTROY_IF(this->nonceg);
 	free(this);
diff --git a/src/libcharon/sa/ikev2/tasks/child_delete.c b/src/libcharon/sa/ikev2/tasks/child_delete.c
index 6fa8836..6267963 100644
--- a/src/libcharon/sa/ikev2/tasks/child_delete.c
+++ b/src/libcharon/sa/ikev2/tasks/child_delete.c
@@ -18,9 +18,14 @@
 
 #include <daemon.h>
 #include <encoding/payloads/delete_payload.h>
+#include <processing/jobs/delete_child_sa_job.h>
 #include <sa/ikev2/tasks/child_create.h>
 #include <sa/ikev2/tasks/child_rekey.h>
 
+#ifndef DELETE_REKEYED_DELAY
+#define DELETE_REKEYED_DELAY 5
+#endif
+
 typedef struct private_child_delete_t private_child_delete_t;
 
 /**
@@ -39,67 +44,80 @@ struct private_child_delete_t {
 	ike_sa_t *ike_sa;
 
 	/**
-	 * Are we the initiator?
+	 * Whether we are the initiator of the exchange
 	 */
 	bool initiator;
 
 	/**
-	 * Protocol of CHILD_SA to delete
+	 * Protocol of CHILD_SA to delete (as initiator)
 	 */
 	protocol_id_t protocol;
 
 	/**
-	 * Inbound SPI of CHILD_SA to delete
+	 * Inbound SPI of CHILD_SA to delete (as initiator)
 	 */
 	uint32_t spi;
 
 	/**
-	 * whether to enforce delete action policy
-	 */
-	bool check_delete_action;
-
-	/**
-	 * is this delete exchange following a rekey?
-	 */
-	bool rekeyed;
-
-	/**
-	 * CHILD_SA already expired?
+	 * CHILD_SA already expired (as initiator)
 	 */
 	bool expired;
 
 	/**
-	 * CHILD_SAs which get deleted
+	 * CHILD_SAs which get deleted, entry_t*
 	 */
 	linked_list_t *child_sas;
 };
 
 /**
+ * Information about a deleted CHILD_SA
+ */
+typedef struct {
+	/** Deleted CHILD_SA */
+	child_sa_t *child_sa;
+	/** Whether the CHILD_SA was rekeyed */
+	bool rekeyed;
+	/** Whether to enforce any delete action policy */
+	bool check_delete_action;
+} entry_t;
+
+CALLBACK(match_child, bool,
+	entry_t *entry, va_list args)
+{
+	child_sa_t *child_sa;
+
+	VA_ARGS_VGET(args, child_sa);
+	return entry->child_sa == child_sa;
+}
+
+/**
  * build the delete payloads from the listed child_sas
  */
 static void build_payloads(private_child_delete_t *this, message_t *message)
 {
 	delete_payload_t *ah = NULL, *esp = NULL;
 	enumerator_t *enumerator;
-	child_sa_t *child_sa;
+	entry_t *entry;
+	protocol_id_t protocol;
+	uint32_t spi;
 
 	enumerator = this->child_sas->create_enumerator(this->child_sas);
-	while (enumerator->enumerate(enumerator, (void**)&child_sa))
+	while (enumerator->enumerate(enumerator, (void**)&entry))
 	{
-		protocol_id_t protocol = child_sa->get_protocol(child_sa);
-		uint32_t spi = child_sa->get_spi(child_sa, TRUE);
+		protocol = entry->child_sa->get_protocol(entry->child_sa);
+		spi = entry->child_sa->get_spi(entry->child_sa, TRUE);
 
 		switch (protocol)
 		{
 			case PROTO_ESP:
-				if (esp == NULL)
+				if (!esp)
 				{
 					esp = delete_payload_create(PLV2_DELETE, PROTO_ESP);
 					message->add_payload(message, (payload_t*)esp);
 				}
 				esp->add_spi(esp, spi);
 				DBG1(DBG_IKE, "sending DELETE for %N CHILD_SA with SPI %.8x",
-							   protocol_id_names, protocol, ntohl(spi));
+					 protocol_id_names, protocol, ntohl(spi));
 				break;
 			case PROTO_AH:
 				if (ah == NULL)
@@ -109,12 +127,12 @@ static void build_payloads(private_child_delete_t *this, message_t *message)
 				}
 				ah->add_spi(ah, spi);
 				DBG1(DBG_IKE, "sending DELETE for %N CHILD_SA with SPI %.8x",
-							   protocol_id_names, protocol, ntohl(spi));
+					 protocol_id_names, protocol, ntohl(spi));
 				break;
 			default:
 				break;
 		}
-		child_sa->set_state(child_sa, CHILD_DELETING);
+		entry->child_sa->set_state(entry->child_sa, CHILD_DELETING);
 	}
 	enumerator->destroy(enumerator);
 }
@@ -147,6 +165,57 @@ static bool is_redundant(private_child_delete_t *this, child_sa_t *child)
 }
 
 /**
+ * Install the outbound CHILD_SA with the given SPI
+ */
+static void install_outbound(private_child_delete_t *this,
+							 protocol_id_t protocol, uint32_t spi)
+{
+	child_sa_t *child_sa;
+	linked_list_t *my_ts, *other_ts;
+	status_t status;
+
+	child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol,
+										  spi, FALSE);
+	if (!child_sa)
+	{
+		DBG1(DBG_IKE, "CHILD_SA not found after rekeying");
+		return;
+	}
+	if (this->initiator && is_redundant(this, child_sa))
+	{	/* if we won the rekey collision we don't want to install the
+		 * redundant SA created by the peer */
+		return;
+	}
+
+	status = child_sa->install_outbound(child_sa);
+	if (status != SUCCESS)
+	{
+		DBG1(DBG_IKE, "unable to install outbound IPsec SA (SAD) in kernel");
+		charon->bus->alert(charon->bus, ALERT_INSTALL_CHILD_SA_FAILED,
+						   child_sa);
+		/* FIXME: delete the new child_sa? */
+		return;
+	}
+	child_sa->set_state(child_sa, CHILD_INSTALLED);
+
+	my_ts = linked_list_create_from_enumerator(
+							child_sa->create_ts_enumerator(child_sa, TRUE));
+	other_ts = linked_list_create_from_enumerator(
+							child_sa->create_ts_enumerator(child_sa, FALSE));
+
+	DBG0(DBG_IKE, "outbound CHILD_SA %s{%d} established "
+		 "with SPIs %.8x_i %.8x_o and TS %#R === %#R",
+		 child_sa->get_name(child_sa),
+		 child_sa->get_unique_id(child_sa),
+		 ntohl(child_sa->get_spi(child_sa, TRUE)),
+		 ntohl(child_sa->get_spi(child_sa, FALSE)),
+		 my_ts, other_ts);
+
+	my_ts->destroy(my_ts);
+	other_ts->destroy(other_ts);
+}
+
+/**
  * read in payloads and find the children to delete
  */
 static void process_payloads(private_child_delete_t *this, message_t *message)
@@ -157,6 +226,7 @@ static void process_payloads(private_child_delete_t *this, message_t *message)
 	uint32_t spi;
 	protocol_id_t protocol;
 	child_sa_t *child_sa;
+	entry_t *entry;
 
 	payloads = message->create_payload_enumerator(message);
 	while (payloads->enumerate(payloads, &payload))
@@ -174,27 +244,37 @@ static void process_payloads(private_child_delete_t *this, message_t *message)
 			{
 				child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol,
 													  spi, FALSE);
-				if (child_sa == NULL)
+				if (!child_sa)
 				{
-					DBG1(DBG_IKE, "received DELETE for %N CHILD_SA with SPI %.8x, "
-						 "but no such SA", protocol_id_names, protocol, ntohl(spi));
+					DBG1(DBG_IKE, "received DELETE for unknown %N CHILD_SA with"
+						 " SPI %.8x", protocol_id_names, protocol, ntohl(spi));
 					continue;
 				}
 				DBG1(DBG_IKE, "received DELETE for %N CHILD_SA with SPI %.8x",
 					 protocol_id_names, protocol, ntohl(spi));
 
+				if (this->child_sas->find_first(this->child_sas, match_child,
+												NULL, child_sa))
+				{
+					continue;
+				}
+				INIT(entry,
+					.child_sa = child_sa
+				);
 				switch (child_sa->get_state(child_sa))
 				{
 					case CHILD_REKEYED:
-						this->rekeyed = TRUE;
+						entry->rekeyed = TRUE;
 						break;
 					case CHILD_DELETING:
-						/* we don't send back a delete if we initiated ourself */
+						/* we don't send back a delete if we already initiated
+						 * a delete ourself */
 						if (!this->initiator)
 						{
+							free(entry);
 							continue;
 						}
-						/* fall through */
+						break;
 					case CHILD_REKEYING:
 						/* we reply as usual, rekeying will fail */
 					case CHILD_INSTALLED:
@@ -202,22 +282,18 @@ static void process_payloads(private_child_delete_t *this, message_t *message)
 						{
 							if (is_redundant(this, child_sa))
 							{
-								this->rekeyed = TRUE;
+								entry->rekeyed = TRUE;
 							}
 							else
 							{
-								this->check_delete_action = TRUE;
+								entry->check_delete_action = TRUE;
 							}
 						}
 						break;
 					default:
 						break;
 				}
-				if (this->child_sas->find_first(this->child_sas, NULL,
-												(void**)&child_sa) != SUCCESS)
-				{
-					this->child_sas->insert_last(this->child_sas, child_sa);
-				}
+				this->child_sas->insert_last(this->child_sas, entry);
 			}
 			spis->destroy(spis);
 		}
@@ -231,29 +307,64 @@ static void process_payloads(private_child_delete_t *this, message_t *message)
 static status_t destroy_and_reestablish(private_child_delete_t *this)
 {
 	enumerator_t *enumerator;
+	entry_t *entry;
 	child_sa_t *child_sa;
 	child_cfg_t *child_cfg;
 	protocol_id_t protocol;
-	uint32_t spi, reqid;
+	uint32_t spi, reqid, rekey_spi;
 	action_t action;
 	status_t status = SUCCESS;
+	time_t now, expire;
+	u_int delay;
+
+	now = time_monotonic(NULL);
+	delay = lib->settings->get_int(lib->settings, "%s.delete_rekeyed_delay",
+								   DELETE_REKEYED_DELAY, lib->ns);
 
 	enumerator = this->child_sas->create_enumerator(this->child_sas);
-	while (enumerator->enumerate(enumerator, (void**)&child_sa))
+	while (enumerator->enumerate(enumerator, (void**)&entry))
 	{
+		child_sa = entry->child_sa;
 		/* signal child down event if we weren't rekeying */
-		if (!this->rekeyed)
+		protocol = child_sa->get_protocol(child_sa);
+		if (!entry->rekeyed)
 		{
 			charon->bus->child_updown(charon->bus, child_sa, FALSE);
 		}
+		else
+		{
+			rekey_spi = child_sa->get_rekey_spi(child_sa);
+			if (rekey_spi)
+			{
+				install_outbound(this, protocol, rekey_spi);
+			}
+			/* for rekeyed CHILD_SAs we uninstall the outbound SA but don't
+			 * immediately destroy it, by default, so we can process delayed
+			 * packets */
+			child_sa->remove_outbound(child_sa);
+			expire = child_sa->get_lifetime(child_sa, TRUE);
+			if (delay && (!expire || ((now + delay) < expire)))
+			{
+				lib->scheduler->schedule_job(lib->scheduler,
+					(job_t*)delete_child_sa_job_create_id(
+									child_sa->get_unique_id(child_sa)), delay);
+				continue;
+			}
+			else if (expire)
+			{	/* let it expire naturally */
+				continue;
+			}
+			/* no delay and no lifetime, destroy it immediately */
+		}
 		spi = child_sa->get_spi(child_sa, TRUE);
 		reqid = child_sa->get_reqid(child_sa);
-		protocol = child_sa->get_protocol(child_sa);
 		child_cfg = child_sa->get_config(child_sa);
 		child_cfg->get_ref(child_cfg);
 		action = child_sa->get_close_action(child_sa);
+
 		this->ike_sa->destroy_child_sa(this->ike_sa, protocol, spi);
-		if (this->check_delete_action)
+
+		if (entry->check_delete_action)
 		{	/* enforce child_cfg policy if deleted passively */
 			switch (action)
 			{
@@ -288,12 +399,14 @@ static void log_children(private_child_delete_t *this)
 {
 	linked_list_t *my_ts, *other_ts;
 	enumerator_t *enumerator;
+	entry_t *entry;
 	child_sa_t *child_sa;
 	uint64_t bytes_in, bytes_out;
 
 	enumerator = this->child_sas->create_enumerator(this->child_sas);
-	while (enumerator->enumerate(enumerator, (void**)&child_sa))
+	while (enumerator->enumerate(enumerator, (void**)&entry))
 	{
+		child_sa = entry->child_sa;
 		my_ts = linked_list_create_from_enumerator(
 							child_sa->create_ts_enumerator(child_sa, TRUE));
 		other_ts = linked_list_create_from_enumerator(
@@ -328,6 +441,7 @@ METHOD(task_t, build_i, status_t,
 	private_child_delete_t *this, message_t *message)
 {
 	child_sa_t *child_sa;
+	entry_t *entry;
 
 	child_sa = this->ike_sa->get_child_sa(this->ike_sa, this->protocol,
 										  this->spi, TRUE);
@@ -342,15 +456,24 @@ METHOD(task_t, build_i, status_t,
 		/* we work only with the inbound SPI */
 		this->spi = child_sa->get_spi(child_sa, TRUE);
 	}
-	this->child_sas->insert_last(this->child_sas, child_sa);
-	if (child_sa->get_state(child_sa) == CHILD_REKEYED)
-	{
-		this->rekeyed = TRUE;
+
+	if (child_sa->get_state(child_sa) == CHILD_DELETING)
+	{	/* DELETEs for this CHILD_SA were already exchanged, but it was not yet
+		 * destroyed to allow delayed packets to get processed */
+		this->ike_sa->destroy_child_sa(this->ike_sa, this->protocol, this->spi);
+		message->set_exchange_type(message, EXCHANGE_TYPE_UNDEFINED);
+		return SUCCESS;
 	}
+
+	INIT(entry,
+		.child_sa = child_sa,
+		.rekeyed = child_sa->get_state(child_sa) == CHILD_REKEYED,
+	);
+	this->child_sas->insert_last(this->child_sas, entry);
 	log_children(this);
 	build_payloads(this, message);
 
-	if (!this->rekeyed && this->expired)
+	if (!entry->rekeyed && this->expired)
 	{
 		child_cfg_t *child_cfg;
 
@@ -397,24 +520,28 @@ METHOD(child_delete_t , get_child, child_sa_t*,
 	private_child_delete_t *this)
 {
 	child_sa_t *child_sa = NULL;
-	this->child_sas->get_first(this->child_sas, (void**)&child_sa);
+	entry_t *entry;
+
+	if (this->child_sas->get_first(this->child_sas, (void**)&entry) == SUCCESS)
+	{
+		child_sa = entry->child_sa;
+	}
 	return child_sa;
 }
 
 METHOD(task_t, migrate, void,
 	private_child_delete_t *this, ike_sa_t *ike_sa)
 {
-	this->check_delete_action = FALSE;
 	this->ike_sa = ike_sa;
 
-	this->child_sas->destroy(this->child_sas);
+	this->child_sas->destroy_function(this->child_sas, free);
 	this->child_sas = linked_list_create();
 }
 
 METHOD(task_t, destroy, void,
 	private_child_delete_t *this)
 {
-	this->child_sas->destroy(this->child_sas);
+	this->child_sas->destroy_function(this->child_sas, free);
 	free(this);
 }
 
diff --git a/src/libcharon/sa/ikev2/tasks/child_rekey.c b/src/libcharon/sa/ikev2/tasks/child_rekey.c
index c04ec14..761c860 100644
--- a/src/libcharon/sa/ikev2/tasks/child_rekey.c
+++ b/src/libcharon/sa/ikev2/tasks/child_rekey.c
@@ -132,6 +132,7 @@ static void find_child(private_child_rekey_t *this, message_t *message)
 	notify_payload_t *notify;
 	protocol_id_t protocol;
 	uint32_t spi;
+	child_sa_t *child_sa;
 
 	notify = message->get_notify(message, REKEY_SA);
 	if (notify)
@@ -141,8 +142,15 @@ static void find_child(private_child_rekey_t *this, message_t *message)
 
 		if (protocol == PROTO_ESP || protocol == PROTO_AH)
 		{
-			this->child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol,
-														spi, FALSE);
+			child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol,
+												  spi, FALSE);
+			if (child_sa &&
+				child_sa->get_state(child_sa) == CHILD_DELETING &&
+				child_sa->get_outbound_state(child_sa) == CHILD_OUTBOUND_NONE)
+			{	/* ignore rekeyed CHILD_SAs we keep around */
+				return;
+			}
+			this->child_sa = child_sa;
 		}
 	}
 }
@@ -227,6 +235,7 @@ METHOD(task_t, build_r, status_t,
 	child_cfg_t *config;
 	uint32_t reqid;
 	child_sa_state_t state;
+	child_sa_t *child_sa;
 
 	if (!this->child_sa)
 	{
@@ -260,7 +269,10 @@ METHOD(task_t, build_r, status_t,
 		return SUCCESS;
 	}
 
+	child_sa = this->child_create->get_child(this->child_create);
 	this->child_sa->set_state(this->child_sa, CHILD_REKEYED);
+	this->child_sa->set_rekey_spi(this->child_sa,
+								  child_sa->get_spi(child_sa, FALSE));
 
 	/* invoke rekey hook */
 	charon->bus->child_rekey(charon->bus, this->child_sa,
diff --git a/src/libcharon/sa/shunt_manager.c b/src/libcharon/sa/shunt_manager.c
index b016275..ad12f05 100644
--- a/src/libcharon/sa/shunt_manager.c
+++ b/src/libcharon/sa/shunt_manager.c
@@ -381,14 +381,24 @@ METHOD(shunt_manager_t, uninstall, bool,
 }
 
 CALLBACK(filter_entries, bool,
-	void *unused, entry_t **entry, char **ns, void **in, child_cfg_t **cfg)
+	void *unused, enumerator_t *orig, va_list args)
 {
-	if (ns)
+	entry_t *entry;
+	child_cfg_t **cfg;
+	char **ns;
+
+	VA_ARGS_VGET(args, ns, cfg);
+
+	if (orig->enumerate(orig, &entry))
 	{
-		*ns = (*entry)->ns;
+		if (ns)
+		{
+			*ns = entry->ns;
+		}
+		*cfg = entry->cfg;
+		return TRUE;
 	}
-	*cfg = (*entry)->cfg;
-	return TRUE;
+	return FALSE;
 }
 
 METHOD(shunt_manager_t, create_enumerator, enumerator_t*,
@@ -397,7 +407,7 @@ METHOD(shunt_manager_t, create_enumerator, enumerator_t*,
 	this->lock->read_lock(this->lock);
 	return enumerator_create_filter(
 							this->shunts->create_enumerator(this->shunts),
-							(void*)filter_entries, this->lock,
+							filter_entries, this->lock,
 							(void*)this->lock->unlock);
 }
 
diff --git a/src/libcharon/sa/task_manager.c b/src/libcharon/sa/task_manager.c
index c42008b..bd11914 100644
--- a/src/libcharon/sa/task_manager.c
+++ b/src/libcharon/sa/task_manager.c
@@ -15,10 +15,40 @@
 
 #include "task_manager.h"
 
+#include <math.h>
 #include <sa/ikev1/task_manager_v1.h>
 #include <sa/ikev2/task_manager_v2.h>
 
-/**
+/*
+ * See header
+ */
+u_int task_manager_total_retransmit_timeout()
+{
+	double timeout, base, limit = 0, total = 0;
+	int tries, i;
+
+	tries = lib->settings->get_int(lib->settings, "%s.retransmit_tries",
+								   RETRANSMIT_TRIES, lib->ns);
+	base = lib->settings->get_double(lib->settings, "%s.retransmit_base",
+									 RETRANSMIT_BASE, lib->ns);
+	timeout = lib->settings->get_double(lib->settings, "%s.retransmit_timeout",
+										RETRANSMIT_TIMEOUT, lib->ns);
+	limit = lib->settings->get_double(lib->settings, "%s.retransmit_limit",
+									  0, lib->ns);
+
+	for (i = 0; i <= tries; i++)
+	{
+		double interval = timeout * pow(base, i);
+		if (limit)
+		{
+			interval = min(interval, limit);
+		}
+		total += interval;
+	}
+	return (u_int)total;
+}
+
+/*
  * See header
  */
 task_manager_t *task_manager_create(ike_sa_t *ike_sa)
diff --git a/src/libcharon/sa/task_manager.h b/src/libcharon/sa/task_manager.h
index 7e92622..e3fddf3 100644
--- a/src/libcharon/sa/task_manager.h
+++ b/src/libcharon/sa/task_manager.h
@@ -48,6 +48,11 @@ typedef enum task_queue_t task_queue_t;
 #define RETRANSMIT_TRIES 5
 
 /**
+ * Maximum jitter in percent.
+ */
+#define RETRANSMIT_JITTER_MAX 20
+
+/**
  * Interval for mobike routability checks in ms.
  */
 #define ROUTEABILITY_CHECK_INTERVAL 2500
@@ -298,6 +303,17 @@ struct task_manager_t {
 };
 
 /**
+ * Calculate total timeout of the retransmission mechanism.
+ *
+ * This is affected by modifications of retransmit_base, retransmit_timeout,
+ * retransmit_limit or retransmit_tries. The resulting value can then be used
+ * e.g. in kernel plugins to set the system's acquire timeout properly.
+ *
+ * @return					calculated total retransmission timeout in seconds
+ */
+u_int task_manager_total_retransmit_timeout();
+
+/**
  * Create a task manager instance for the correct IKE version.
  *
  * @param ike_sa			IKE_SA to create a task manager for
diff --git a/src/libcharon/sa/trap_manager.c b/src/libcharon/sa/trap_manager.c
index 40a0682..f9fee5e 100644
--- a/src/libcharon/sa/trap_manager.c
+++ b/src/libcharon/sa/trap_manager.c
@@ -140,19 +140,21 @@ static void destroy_acquire(acquire_t *this)
 	free(this);
 }
 
-/**
- * match an acquire entry by reqid
- */
-static bool acquire_by_reqid(acquire_t *this, uint32_t *reqid)
+CALLBACK(acquire_by_reqid, bool,
+	acquire_t *this, va_list args)
 {
-	return this->reqid == *reqid;
+	uint32_t reqid;
+
+	VA_ARGS_VGET(args, reqid);
+	return this->reqid == reqid;
 }
 
-/**
- * match an acquire entry by destination address
- */
-static bool acquire_by_dst(acquire_t *this, host_t *dst)
+CALLBACK(acquire_by_dst, bool,
+	acquire_t *this, va_list args)
 {
+	host_t *dst;
+
+	VA_ARGS_VGET(args, dst);
 	return this->dst && this->dst->ip_equals(this->dst, dst);
 }
 
@@ -272,7 +274,8 @@ METHOD(trap_manager_t, install, uint32_t,
 	proposals->destroy_offset(proposals, offsetof(proposal_t, destroy));
 	child_sa->set_protocol(child_sa, proto);
 	child_sa->set_mode(child_sa, child->get_mode(child));
-	status = child_sa->add_policies(child_sa, my_ts, other_ts);
+	child_sa->set_policies(child_sa, my_ts, other_ts);
+	status = child_sa->install_policies(child_sa);
 	my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy));
 	other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy));
 	if (status != SUCCESS)
@@ -334,25 +337,32 @@ METHOD(trap_manager_t, uninstall, bool,
 	return TRUE;
 }
 
-/**
- * convert enumerated entries to peer_cfg, child_sa
- */
-static bool trap_filter(rwlock_t *lock, entry_t **entry, peer_cfg_t **peer_cfg,
-						void *none, child_sa_t **child_sa)
+CALLBACK(trap_filter, bool,
+	rwlock_t *lock, enumerator_t *orig, va_list args)
 {
-	if (!(*entry)->child_sa)
-	{	/* skip entries that are currently being installed */
-		return FALSE;
-	}
-	if (peer_cfg)
-	{
-		*peer_cfg = (*entry)->peer_cfg;
-	}
-	if (child_sa)
+	entry_t *entry;
+	peer_cfg_t **peer_cfg;
+	child_sa_t **child_sa;
+
+	VA_ARGS_VGET(args, peer_cfg, child_sa);
+
+	while (orig->enumerate(orig, &entry))
 	{
-		*child_sa = (*entry)->child_sa;
+		if (!entry->child_sa)
+		{	/* skip entries that are currently being installed */
+			continue;
+		}
+		if (peer_cfg)
+		{
+			*peer_cfg = entry->peer_cfg;
+		}
+		if (child_sa)
+		{
+			*child_sa = entry->child_sa;
+		}
+		return TRUE;
 	}
-	return TRUE;
+	return FALSE;
 }
 
 METHOD(trap_manager_t, create_enumerator, enumerator_t*,
@@ -360,7 +370,7 @@ METHOD(trap_manager_t, create_enumerator, enumerator_t*,
 {
 	this->lock->read_lock(this->lock);
 	return enumerator_create_filter(this->traps->create_enumerator(this->traps),
-									(void*)trap_filter, this->lock,
+									trap_filter, this->lock,
 									(void*)this->lock->unlock);
 }
 
@@ -431,8 +441,8 @@ METHOD(trap_manager_t, acquire, void,
 		uint8_t mask;
 
 		dst->to_subnet(dst, &host, &mask);
-		if (this->acquires->find_first(this->acquires, (void*)acquire_by_dst,
-									  (void**)&acquire, host) == SUCCESS)
+		if (this->acquires->find_first(this->acquires, acquire_by_dst,
+									  (void**)&acquire, host))
 		{
 			host->destroy(host);
 			ignore = TRUE;
@@ -448,8 +458,8 @@ METHOD(trap_manager_t, acquire, void,
 	}
 	else
 	{
-		if (this->acquires->find_first(this->acquires, (void*)acquire_by_reqid,
-									  (void**)&acquire, &reqid) == SUCCESS)
+		if (this->acquires->find_first(this->acquires, acquire_by_reqid,
+									  (void**)&acquire, reqid))
 		{
 			ignore = TRUE;
 		}
diff --git a/src/libcharon/tests/Makefile.in b/src/libcharon/tests/Makefile.in
index e922a71..3070f42 100644
--- a/src/libcharon/tests/Makefile.in
+++ b/src/libcharon/tests/Makefile.in
@@ -380,6 +380,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -402,6 +403,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libcharon/tests/suites/test_child_rekey.c b/src/libcharon/tests/suites/test_child_rekey.c
index fcac493..76b23f5 100644
--- a/src/libcharon/tests/suites/test_child_rekey.c
+++ b/src/libcharon/tests/suites/test_child_rekey.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 Tobias Brunner
+ * Copyright (C) 2016-2017 Tobias Brunner
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -28,7 +28,23 @@
 	assert_hook_not_called(child_updown); \
 	assert_hook_not_called(child_rekey); \
 	call_ikesa(sa, rekey_child_sa, PROTO_ESP, spi); \
-	assert_child_sa_state(sa, spi, CHILD_REKEYING); \
+	assert_child_sa_state(sa, spi, CHILD_REKEYING, CHILD_OUTBOUND_INSTALLED); \
+	assert_hook(); \
+	assert_hook(); \
+})
+
+/**
+ * Destroy a rekeyed CHILD_SA that was kept around to accept inbound traffic.
+ * Simulates the job that's scheduled to do this.
+ */
+#define destroy_rekeyed(sa, spi) ({ \
+	assert_hook_not_called(child_updown); \
+	assert_hook_not_called(child_rekey); \
+	assert_no_jobs_scheduled(); \
+	assert_child_sa_state(sa, spi, CHILD_DELETING, CHILD_OUTBOUND_NONE); \
+	call_ikesa(sa, delete_child_sa, PROTO_ESP, spi, FALSE); \
+	assert_child_sa_not_exists(sa, spi); \
+	assert_scheduler(); \
 	assert_hook(); \
 	assert_hook(); \
 })
@@ -53,6 +69,7 @@ START_TEST(test_regular)
 										   &a, &b, NULL);
 	}
 	initiate_rekey(a, spi_a);
+	assert_ipsec_sas_installed(a, spi_a, spi_b);
 
 	/* this should never get called as this results in a successful rekeying */
 	assert_hook_not_called(child_updown);
@@ -61,33 +78,51 @@ START_TEST(test_regular)
 	assert_hook_called(child_rekey);
 	assert_notify(IN, REKEY_SA);
 	exchange_test_helper->process_message(exchange_test_helper, b, NULL);
-	assert_child_sa_state(b, spi_b, CHILD_REKEYED);
-	assert_child_sa_state(b, 4, CHILD_INSTALLED);
+	assert_child_sa_state(b, spi_b, CHILD_REKEYED, CHILD_OUTBOUND_INSTALLED);
+	assert_child_sa_state(b, 4, CHILD_INSTALLED, CHILD_OUTBOUND_REGISTERED);
+	assert_ipsec_sas_installed(b, spi_a, spi_b, 4);
 	assert_hook();
 
 	/* <-- CREATE_CHILD_SA { SA, Nr, [KEr,] TSi, TSr } */
 	assert_hook_called(child_rekey);
 	assert_no_notify(IN, REKEY_SA);
 	exchange_test_helper->process_message(exchange_test_helper, a, NULL);
-	assert_child_sa_state(a, spi_a, CHILD_DELETING);
-	assert_child_sa_state(a, 3, CHILD_INSTALLED);
+	assert_child_sa_state(a, spi_a, CHILD_DELETING, CHILD_OUTBOUND_INSTALLED);
+	assert_child_sa_state(a, 3, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED);
+	assert_ipsec_sas_installed(a, spi_a, spi_b, 3, 4);
 	assert_hook();
 
 	/* INFORMATIONAL { D } --> */
 	assert_hook_not_called(child_rekey);
+	assert_jobs_scheduled(1);
 	assert_single_payload(IN, PLV2_DELETE);
 	exchange_test_helper->process_message(exchange_test_helper, b, NULL);
-	assert_child_sa_state(b, 4, CHILD_INSTALLED);
-	assert_child_sa_count(b, 1);
+	assert_child_sa_state(b, spi_b, CHILD_DELETING, CHILD_OUTBOUND_NONE);
+	assert_child_sa_state(b, 4, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED);
+	assert_child_sa_count(b, 2);
+	assert_ipsec_sas_installed(b, spi_b, 3, 4);
+	assert_scheduler();
 	assert_hook();
 	/* <-- INFORMATIONAL { D } */
 	assert_hook_not_called(child_rekey);
+	assert_jobs_scheduled(1);
 	assert_single_payload(IN, PLV2_DELETE);
 	exchange_test_helper->process_message(exchange_test_helper, a, NULL);
-	assert_child_sa_state(a, 3, CHILD_INSTALLED);
-	assert_child_sa_count(a, 1);
+	assert_child_sa_state(a, spi_a, CHILD_DELETING, CHILD_OUTBOUND_NONE);
+	assert_child_sa_state(a, 3, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED);
+	assert_child_sa_count(a, 2);
+	assert_ipsec_sas_installed(a, spi_a, 3, 4);
+	assert_scheduler();
 	assert_hook();
 
+	/* simulate the execution of the scheduled jobs */
+	destroy_rekeyed(a, spi_a);
+	assert_child_sa_count(a, 1);
+	assert_ipsec_sas_installed(a, 3, 4);
+	destroy_rekeyed(b, spi_b);
+	assert_child_sa_count(b, 1);
+	assert_ipsec_sas_installed(a, 3, 4);
+
 	/* child_updown */
 	assert_hook();
 
@@ -125,6 +160,7 @@ START_TEST(test_regular_ke_invalid)
 										   &a, &b, &conf);
 	}
 	initiate_rekey(a, spi_a);
+	assert_ipsec_sas_installed(a, spi_a, spi_b);
 
 	/* this should never get called as this results in a successful rekeying */
 	assert_hook_not_called(child_updown);
@@ -135,6 +171,7 @@ START_TEST(test_regular_ke_invalid)
 	exchange_test_helper->process_message(exchange_test_helper, b, NULL);
 	assert_child_sa_state(b, spi_b, CHILD_INSTALLED);
 	assert_child_sa_count(b, 1);
+	assert_ipsec_sas_installed(b, spi_a, spi_b);
 	assert_hook();
 
 	/* <-- CREATE_CHILD_SA { N(INVAL_KE) } */
@@ -143,6 +180,7 @@ START_TEST(test_regular_ke_invalid)
 	exchange_test_helper->process_message(exchange_test_helper, a, NULL);
 	assert_child_sa_state(a, spi_a, CHILD_REKEYING);
 	assert_child_sa_count(a, 1);
+	assert_ipsec_sas_installed(a, spi_a, spi_b);
 	assert_hook();
 
 	/* CREATE_CHILD_SA { N(REKEY_SA), SA, Ni, [KEi,] TSi, TSr } --> */
@@ -150,7 +188,8 @@ START_TEST(test_regular_ke_invalid)
 	assert_notify(IN, REKEY_SA);
 	exchange_test_helper->process_message(exchange_test_helper, b, NULL);
 	assert_child_sa_state(b, spi_b, CHILD_REKEYED);
-	assert_child_sa_state(b, 6, CHILD_INSTALLED);
+	assert_child_sa_state(b, 6, CHILD_INSTALLED, CHILD_OUTBOUND_REGISTERED);
+	assert_ipsec_sas_installed(b, spi_a, spi_b, 6);
 	assert_hook();
 
 	/* <-- CREATE_CHILD_SA { SA, Nr, [KEr,] TSi, TSr } */
@@ -158,24 +197,37 @@ START_TEST(test_regular_ke_invalid)
 	assert_no_notify(IN, REKEY_SA);
 	exchange_test_helper->process_message(exchange_test_helper, a, NULL);
 	assert_child_sa_state(a, spi_a, CHILD_DELETING);
-	assert_child_sa_state(a, 5, CHILD_INSTALLED);
+	assert_child_sa_state(a, 5, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED);
+	assert_ipsec_sas_installed(a, spi_a, spi_b, 5, 6);
 	assert_hook();
 
 	/* INFORMATIONAL { D } --> */
 	assert_hook_not_called(child_rekey);
 	assert_single_payload(IN, PLV2_DELETE);
 	exchange_test_helper->process_message(exchange_test_helper, b, NULL);
-	assert_child_sa_state(b, 6, CHILD_INSTALLED);
-	assert_child_sa_count(b, 1);
+	assert_child_sa_state(b, spi_b, CHILD_DELETING, CHILD_OUTBOUND_NONE);
+	assert_child_sa_state(b, 6, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED);
+	assert_child_sa_count(b, 2);
+	assert_ipsec_sas_installed(b, spi_b, 5, 6);
 	assert_hook();
 	/* <-- INFORMATIONAL { D } */
 	assert_hook_not_called(child_rekey);
 	assert_single_payload(IN, PLV2_DELETE);
 	exchange_test_helper->process_message(exchange_test_helper, a, NULL);
+	assert_child_sa_state(a, spi_a, CHILD_DELETING, CHILD_OUTBOUND_NONE);
 	assert_child_sa_state(a, 5, CHILD_INSTALLED);
-	assert_child_sa_count(a, 1);
+	assert_child_sa_count(a, 2);
+	assert_ipsec_sas_installed(a, spi_a, 5, 6);
 	assert_hook();
 
+	/* simulate the execution of the scheduled jobs */
+	destroy_rekeyed(a, spi_a);
+	assert_child_sa_count(a, 1);
+	assert_ipsec_sas_installed(a, 5, 6);
+	destroy_rekeyed(b, spi_b);
+	assert_child_sa_count(b, 1);
+	assert_ipsec_sas_installed(b, 5, 6);
+
 	/* child_updown */
 	assert_hook();
 
@@ -195,6 +247,7 @@ START_TEST(test_regular_responder_ignore_soft_expire)
 	exchange_test_helper->establish_sa(exchange_test_helper,
 									   &a, &b, NULL);
 	initiate_rekey(a, 1);
+	assert_ipsec_sas_installed(a, 1, 2);
 
 	/* this should never get called as this results in a successful rekeying */
 	assert_hook_not_called(child_updown);
@@ -204,7 +257,8 @@ START_TEST(test_regular_responder_ignore_soft_expire)
 	assert_notify(IN, REKEY_SA);
 	exchange_test_helper->process_message(exchange_test_helper, b, NULL);
 	assert_child_sa_state(b, 2, CHILD_REKEYED);
-	assert_child_sa_state(b, 4, CHILD_INSTALLED);
+	assert_child_sa_state(b, 4, CHILD_INSTALLED, CHILD_OUTBOUND_REGISTERED);
+	assert_ipsec_sas_installed(b, 1, 2, 4);
 	assert_hook();
 
 	/* <-- CREATE_CHILD_SA { SA, Nr, [KEr,] TSi, TSr } */
@@ -212,7 +266,8 @@ START_TEST(test_regular_responder_ignore_soft_expire)
 	assert_no_notify(IN, REKEY_SA);
 	exchange_test_helper->process_message(exchange_test_helper, a, NULL);
 	assert_child_sa_state(a, 1, CHILD_DELETING);
-	assert_child_sa_state(a, 3, CHILD_INSTALLED);
+	assert_child_sa_state(a, 3, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED);
+	assert_ipsec_sas_installed(a, 1, 2, 3, 4);
 	assert_hook();
 
 	/* we don't expect this to get called anymore */
@@ -223,15 +278,31 @@ START_TEST(test_regular_responder_ignore_soft_expire)
 	assert_child_sa_state(b, 2, CHILD_REKEYED);
 
 	/* INFORMATIONAL { D } --> */
+	assert_jobs_scheduled(1);
 	assert_single_payload(IN, PLV2_DELETE);
 	exchange_test_helper->process_message(exchange_test_helper, b, NULL);
-	assert_child_sa_state(b, 4, CHILD_INSTALLED);
-	assert_child_sa_count(b, 1);
+	assert_child_sa_state(b, 2, CHILD_DELETING, CHILD_OUTBOUND_NONE);
+	assert_child_sa_state(b, 4, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED);
+	assert_child_sa_count(b, 2);
+	assert_ipsec_sas_installed(b, 2, 3, 4);
+	assert_scheduler();
 	/* <-- INFORMATIONAL { D } */
+	assert_jobs_scheduled(1);
 	assert_single_payload(IN, PLV2_DELETE);
 	exchange_test_helper->process_message(exchange_test_helper, a, NULL);
+	assert_child_sa_state(a, 1, CHILD_DELETING, CHILD_OUTBOUND_NONE);
 	assert_child_sa_state(a, 3, CHILD_INSTALLED);
+	assert_child_sa_count(a, 2);
+	assert_ipsec_sas_installed(a, 1, 3, 4);
+	assert_scheduler();
+
+	/* simulate the execution of the scheduled jobs */
+	destroy_rekeyed(a, 1);
 	assert_child_sa_count(a, 1);
+	assert_ipsec_sas_installed(a, 3, 4);
+	destroy_rekeyed(b, 2);
+	assert_child_sa_count(b, 1);
+	assert_ipsec_sas_installed(b, 3, 4);
 
 	/* child_rekey/child_updown */
 	assert_hook();
@@ -254,6 +325,7 @@ START_TEST(test_regular_responder_handle_hard_expire)
 	exchange_test_helper->establish_sa(exchange_test_helper,
 									   &a, &b, NULL);
 	initiate_rekey(a, 1);
+	assert_ipsec_sas_installed(a, 1, 2);
 
 	/* this should never get called as this results in a successful rekeying */
 	assert_hook_not_called(child_updown);
@@ -263,7 +335,8 @@ START_TEST(test_regular_responder_handle_hard_expire)
 	assert_notify(IN, REKEY_SA);
 	exchange_test_helper->process_message(exchange_test_helper, b, NULL);
 	assert_child_sa_state(b, 2, CHILD_REKEYED);
-	assert_child_sa_state(b, 4, CHILD_INSTALLED);
+	assert_child_sa_state(b, 4, CHILD_INSTALLED, CHILD_OUTBOUND_REGISTERED);
+	assert_ipsec_sas_installed(b, 1, 2, 4);
 	assert_hook();
 
 	/* <-- CREATE_CHILD_SA { SA, Nr, [KEr,] TSi, TSr } */
@@ -271,7 +344,8 @@ START_TEST(test_regular_responder_handle_hard_expire)
 	assert_no_notify(IN, REKEY_SA);
 	exchange_test_helper->process_message(exchange_test_helper, a, NULL);
 	assert_child_sa_state(a, 1, CHILD_DELETING);
-	assert_child_sa_state(a, 3, CHILD_INSTALLED);
+	assert_child_sa_state(a, 3, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED);
+	assert_ipsec_sas_installed(a, 1, 2, 3, 4);
 	assert_hook();
 
 	/* we don't expect this to get called anymore */
@@ -279,28 +353,51 @@ START_TEST(test_regular_responder_handle_hard_expire)
 	/* this is similar to a regular delete collision */
 	assert_single_payload(OUT, PLV2_DELETE);
 	call_ikesa(b, delete_child_sa, PROTO_ESP, 2, TRUE);
-	assert_child_sa_state(b, 2, CHILD_DELETING);
+	assert_child_sa_state(b, 2, CHILD_DELETING, CHILD_OUTBOUND_INSTALLED);
+	assert_child_sa_state(b, 4, CHILD_INSTALLED, CHILD_OUTBOUND_REGISTERED);
+	/* since the SAs expired they would not actually be installed in the kernel
+	 * anymore and since we have not yet installed a new outbound SA this
+	 * will result in dropped packets and possibly acquires */
+	assert_ipsec_sas_installed(b, 1, 2, 4);
 
 	/* INFORMATIONAL { D } --> */
 	assert_single_payload(IN, PLV2_DELETE);
 	exchange_test_helper->process_message(exchange_test_helper, b, NULL);
-	assert_child_sa_state(b, 4, CHILD_INSTALLED);
-	assert_child_sa_state(a, 2, CHILD_DELETING);
+	assert_child_sa_state(b, 2, CHILD_DELETING, CHILD_OUTBOUND_INSTALLED);
+	assert_child_sa_state(b, 4, CHILD_INSTALLED, CHILD_OUTBOUND_REGISTERED);
+	assert_ipsec_sas_installed(b, 1, 2, 4);
 	/* <-- INFORMATIONAL { D } */
 	assert_single_payload(IN, PLV2_DELETE);
 	exchange_test_helper->process_message(exchange_test_helper, a, NULL);
-	assert_child_sa_state(a, 3, CHILD_INSTALLED);
-	assert_child_sa_state(a, 1, CHILD_DELETING);
+	assert_child_sa_state(a, 1, CHILD_DELETING, CHILD_OUTBOUND_INSTALLED);
+	assert_child_sa_state(a, 3, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED);
+	assert_ipsec_sas_installed(a, 1, 2, 3, 4);
 	/* <-- INFORMATIONAL { } */
+	assert_jobs_scheduled(1);
 	assert_message_empty(IN);
 	exchange_test_helper->process_message(exchange_test_helper, a, NULL);
-	assert_child_sa_state(a, 3, CHILD_INSTALLED);
-	assert_child_sa_count(a, 1);
+	assert_child_sa_state(a, 1, CHILD_DELETING, CHILD_OUTBOUND_NONE);
+	assert_child_sa_state(a, 3, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED);
+	assert_child_sa_count(a, 2);
+	assert_ipsec_sas_installed(a, 1, 3, 4);
+	assert_scheduler();
 	/* INFORMATIONAL { } --> */
+	assert_jobs_scheduled(1);
 	assert_message_empty(IN);
 	exchange_test_helper->process_message(exchange_test_helper, b, NULL);
-	assert_child_sa_state(b, 4, CHILD_INSTALLED);
+	assert_child_sa_state(b, 2, CHILD_DELETING, CHILD_OUTBOUND_NONE);
+	assert_child_sa_state(b, 4, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED);
+	assert_child_sa_count(b, 2);
+	assert_ipsec_sas_installed(b, 2, 3, 4);
+	assert_scheduler();
+
+	/* simulate the execution of the scheduled jobs */
+	destroy_rekeyed(a, 1);
+	assert_child_sa_count(a, 1);
+	assert_ipsec_sas_installed(a, 3, 4);
+	destroy_rekeyed(b, 2);
 	assert_child_sa_count(b, 1);
+	assert_ipsec_sas_installed(b, 3, 4);
 
 	/* child_rekey/child_updown */
 	assert_hook();
@@ -350,8 +447,10 @@ START_TEST(test_collision)
 
 	exchange_test_helper->nonce_first_byte = data[_i].nonces[0];
 	initiate_rekey(a, 1);
+	assert_ipsec_sas_installed(a, 1, 2);
 	exchange_test_helper->nonce_first_byte = data[_i].nonces[1];
 	initiate_rekey(b, 2);
+	assert_ipsec_sas_installed(b, 1, 2);
 
 	/* this should never get called as this results in a successful rekeying */
 	assert_hook_not_called(child_updown);
@@ -360,15 +459,17 @@ START_TEST(test_collision)
 	exchange_test_helper->nonce_first_byte = data[_i].nonces[2];
 	assert_hook_rekey(child_rekey, 2, 5);
 	exchange_test_helper->process_message(exchange_test_helper, b, NULL);
-	assert_child_sa_state(b, 2, CHILD_REKEYED);
-	assert_child_sa_state(b, 5, CHILD_INSTALLED);
+	assert_child_sa_state(b, 2, CHILD_REKEYED, CHILD_OUTBOUND_INSTALLED);
+	assert_child_sa_state(b, 5, CHILD_INSTALLED, CHILD_OUTBOUND_REGISTERED);
+	assert_ipsec_sas_installed(b, 1, 2, 5);
 	assert_hook();
 	/* <-- CREATE_CHILD_SA { N(REKEY_SA), SA, Ni, [KEi,] TSi, TSr } */
 	exchange_test_helper->nonce_first_byte = data[_i].nonces[3];
 	assert_hook_rekey(child_rekey, 1, 6);
 	exchange_test_helper->process_message(exchange_test_helper, a, NULL);
-	assert_child_sa_state(a, 1, CHILD_REKEYED);
-	assert_child_sa_state(a, 6, CHILD_INSTALLED);
+	assert_child_sa_state(a, 1, CHILD_REKEYED, CHILD_OUTBOUND_INSTALLED);
+	assert_child_sa_state(a, 6, CHILD_INSTALLED, CHILD_OUTBOUND_REGISTERED);
+	assert_ipsec_sas_installed(a, 1, 2, 6);
 	assert_hook();
 
 	/* <-- CREATE_CHILD_SA { SA, Nr, [KEr,] TSi, TSr } */
@@ -378,53 +479,113 @@ START_TEST(test_collision)
 		assert_hook_rekey(child_rekey, 1, data[_i].spi_a);
 		exchange_test_helper->process_message(exchange_test_helper, a, NULL);
 		assert_hook();
+		assert_child_sa_state(a, data[_i].spi_del_b, CHILD_REKEYED,
+							  CHILD_OUTBOUND_REGISTERED);
+		assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED,
+							  CHILD_OUTBOUND_INSTALLED);
 	}
 	else
 	{
 		assert_hook_not_called(child_rekey);
 		exchange_test_helper->process_message(exchange_test_helper, a, NULL);
 		assert_hook();
+		assert_child_sa_state(a, data[_i].spi_del_b, CHILD_REKEYED,
+							  CHILD_OUTBOUND_INSTALLED);
+		assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED,
+							  CHILD_OUTBOUND_REGISTERED);
 	}
-	assert_child_sa_state(a, data[_i].spi_del_a, CHILD_DELETING);
-	assert_child_sa_state(a, data[_i].spi_del_b, CHILD_REKEYED);
-	assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED);
+	assert_child_sa_state(a, data[_i].spi_del_a, CHILD_DELETING,
+						  CHILD_OUTBOUND_INSTALLED);
+	assert_ipsec_sas_installed(a, 1, 2, 3, 5, 6);
 	/* CREATE_CHILD_SA { SA, Nr, [KEr,] TSi, TSr } --> */
 	if (data[_i].spi_del_b == 2)
 	{
 		assert_hook_rekey(child_rekey, 2, data[_i].spi_b);
 		exchange_test_helper->process_message(exchange_test_helper, b, NULL);
 		assert_hook();
+		assert_child_sa_state(b, data[_i].spi_del_a, CHILD_REKEYED,
+							  CHILD_OUTBOUND_REGISTERED);
+		assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED,
+							  CHILD_OUTBOUND_INSTALLED);
 	}
 	else
 	{
 		assert_hook_not_called(child_rekey);
 		exchange_test_helper->process_message(exchange_test_helper, b, NULL);
 		assert_hook();
+		assert_child_sa_state(b, data[_i].spi_del_a, CHILD_REKEYED,
+							  CHILD_OUTBOUND_INSTALLED);
+		assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED,
+							  CHILD_OUTBOUND_REGISTERED);
 	}
-	assert_child_sa_state(b, data[_i].spi_del_b, CHILD_DELETING);
-	assert_child_sa_state(b, data[_i].spi_del_a, CHILD_REKEYED);
-	assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED);
+	assert_child_sa_state(b, data[_i].spi_del_b, CHILD_DELETING,
+						  CHILD_OUTBOUND_INSTALLED);
+	assert_ipsec_sas_installed(b, 1, 2, 4, 5, 6);
 
 	/* we don't expect this hook to get called anymore */
 	assert_hook_not_called(child_rekey);
 	/* INFORMATIONAL { D } --> */
+	assert_jobs_scheduled(1);
 	exchange_test_helper->process_message(exchange_test_helper, b, NULL);
-	assert_child_sa_state(b, data[_i].spi_del_b, CHILD_DELETING);
-	assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED);
-	assert_child_sa_count(b, 2);
+	assert_child_sa_state(b, data[_i].spi_del_b, CHILD_DELETING,
+						  CHILD_OUTBOUND_INSTALLED);
+	assert_child_sa_state(b, data[_i].spi_del_a, CHILD_DELETING,
+						  CHILD_OUTBOUND_NONE);
+	assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED,
+						  CHILD_OUTBOUND_INSTALLED);
+	assert_child_sa_count(b, 3);
+	assert_ipsec_sas_installed(b, 2, 4, 5, 6,
+							   data[_i].spi_del_b == 2 ? 1 : 3);
+	assert_scheduler();
 	/* <-- INFORMATIONAL { D } */
+	assert_jobs_scheduled(1);
 	exchange_test_helper->process_message(exchange_test_helper, a, NULL);
-	assert_child_sa_state(a, data[_i].spi_del_a, CHILD_DELETING);
-	assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED);
-	assert_child_sa_count(a, 2);
+	assert_child_sa_state(a, data[_i].spi_del_a, CHILD_DELETING,
+						  CHILD_OUTBOUND_INSTALLED);
+	assert_child_sa_state(a, data[_i].spi_del_b, CHILD_DELETING,
+						  CHILD_OUTBOUND_NONE);
+	assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED,
+						  CHILD_OUTBOUND_INSTALLED);
+	assert_child_sa_count(a, 3);
+	assert_ipsec_sas_installed(a, 1, 3, 5, 6,
+							   data[_i].spi_del_a == 1 ? 2 : 4);
+	assert_scheduler();
 	/* <-- INFORMATIONAL { D } */
+	assert_jobs_scheduled(1);
 	exchange_test_helper->process_message(exchange_test_helper, a, NULL);
-	assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED);
-	assert_child_sa_count(a, 1);
+	assert_child_sa_state(a, data[_i].spi_del_a, CHILD_DELETING,
+						  CHILD_OUTBOUND_NONE);
+	assert_child_sa_state(a, data[_i].spi_del_b, CHILD_DELETING,
+						  CHILD_OUTBOUND_NONE);
+	assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED,
+						  CHILD_OUTBOUND_INSTALLED);
+	assert_child_sa_count(a, 3);
+	assert_ipsec_sas_installed(a, 1, 3, 6,
+							   data[_i].spi_del_a == 1 ? 5 : 4);
+	assert_scheduler();
 	/* INFORMATIONAL { D } --> */
+	assert_jobs_scheduled(1);
 	exchange_test_helper->process_message(exchange_test_helper, b, NULL);
-	assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED);
+	assert_child_sa_state(b, data[_i].spi_del_b, CHILD_DELETING,
+						  CHILD_OUTBOUND_NONE);
+	assert_child_sa_state(b, data[_i].spi_del_a, CHILD_DELETING,
+						  CHILD_OUTBOUND_NONE);
+	assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED,
+						  CHILD_OUTBOUND_INSTALLED);
+	assert_child_sa_count(b, 3);
+	assert_ipsec_sas_installed(b, 2, 4, 5,
+							   data[_i].spi_del_b == 2 ? 6 : 3);
+	assert_scheduler();
+
+	/* simulate the execution of the scheduled jobs */
+	destroy_rekeyed(a, data[_i].spi_del_a);
+	destroy_rekeyed(a, data[_i].spi_del_b);
+	assert_child_sa_count(a, 1);
+	assert_ipsec_sas_installed(a, data[_i].spi_a, data[_i].spi_b);
+	destroy_rekeyed(b, data[_i].spi_del_a);
+	destroy_rekeyed(b, data[_i].spi_del_b);
 	assert_child_sa_count(b, 1);
+	assert_ipsec_sas_installed(b, data[_i].spi_a, data[_i].spi_b);
 
 	/* child_rekey/child_updown */
 	assert_hook();
@@ -483,8 +644,10 @@ START_TEST(test_collision_delayed_response)
 
 	exchange_test_helper->nonce_first_byte = data[_i].nonces[0];
 	initiate_rekey(a, 1);
+	assert_ipsec_sas_installed(a, 1, 2);
 	exchange_test_helper->nonce_first_byte = data[_i].nonces[1];
 	initiate_rekey(b, 2);
+	assert_ipsec_sas_installed(b, 1, 2);
 
 	/* this should never get called as this results in a successful rekeying */
 	assert_hook_not_called(child_updown);
@@ -493,15 +656,17 @@ START_TEST(test_collision_delayed_response)
 	exchange_test_helper->nonce_first_byte = data[_i].nonces[2];
 	assert_hook_rekey(child_rekey, 2, 5);
 	exchange_test_helper->process_message(exchange_test_helper, b, NULL);
-	assert_child_sa_state(b, 2, CHILD_REKEYED);
-	assert_child_sa_state(b, 5, CHILD_INSTALLED);
+	assert_child_sa_state(b, 2, CHILD_REKEYED, CHILD_OUTBOUND_INSTALLED);
+	assert_child_sa_state(b, 5, CHILD_INSTALLED, CHILD_OUTBOUND_REGISTERED);
+	assert_ipsec_sas_installed(b, 1, 2, 5);
 	assert_hook();
 	/* <-- CREATE_CHILD_SA { N(REKEY_SA), SA, Ni, [KEi,] TSi, TSr } */
 	exchange_test_helper->nonce_first_byte = data[_i].nonces[3];
 	assert_hook_rekey(child_rekey, 1, 6);
 	exchange_test_helper->process_message(exchange_test_helper, a, NULL);
-	assert_child_sa_state(a, 1, CHILD_REKEYED);
-	assert_child_sa_state(a, 6, CHILD_INSTALLED);
+	assert_child_sa_state(a, 1, CHILD_REKEYED, CHILD_OUTBOUND_INSTALLED);
+	assert_child_sa_state(a, 6, CHILD_INSTALLED, CHILD_OUTBOUND_REGISTERED);
+	assert_ipsec_sas_installed(a, 1, 2, 6);
 	assert_hook();
 
 	/* delay the CREATE_CHILD_SA response from b to a */
@@ -513,35 +678,68 @@ START_TEST(test_collision_delayed_response)
 		assert_hook_rekey(child_rekey, 2, data[_i].spi_b);
 		exchange_test_helper->process_message(exchange_test_helper, b, NULL);
 		assert_hook();
+		assert_child_sa_state(b, data[_i].spi_del_a, CHILD_REKEYED,
+							  CHILD_OUTBOUND_REGISTERED);
+		assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED,
+							  CHILD_OUTBOUND_INSTALLED);
 	}
 	else
 	{
 		assert_hook_not_called(child_rekey);
 		exchange_test_helper->process_message(exchange_test_helper, b, NULL);
 		assert_hook();
+		assert_child_sa_state(b, data[_i].spi_del_a, CHILD_REKEYED,
+							  CHILD_OUTBOUND_INSTALLED);
+		assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED,
+							  CHILD_OUTBOUND_REGISTERED);
 	}
-	assert_child_sa_state(b, data[_i].spi_del_b, CHILD_DELETING);
-	assert_child_sa_state(b, data[_i].spi_del_a, CHILD_REKEYED);
-	assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED);
+	assert_child_sa_state(b, data[_i].spi_del_b, CHILD_DELETING,
+						  CHILD_OUTBOUND_INSTALLED);
+	assert_ipsec_sas_installed(b, 1, 2, 4, 5, 6);
 
 	/* <-- INFORMATIONAL { D } */
 	assert_hook_not_called(child_rekey);
+	assert_jobs_scheduled(1);
 	exchange_test_helper->process_message(exchange_test_helper, a, NULL);
 	if (data[_i].spi_del_b == 2)
 	{
-		assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED);
-		assert_child_sa_count(a, 1);
+		assert_child_sa_state(a, 1, CHILD_DELETING, CHILD_OUTBOUND_NONE);
+		assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED,
+							  CHILD_OUTBOUND_INSTALLED);
+		assert_ipsec_sas_installed(a, 1, 4, 6);
 	}
 	else
 	{
-		assert_child_sa_state(a, 1, CHILD_REKEYED);
-		assert_child_sa_count(a, 1);
+		assert_child_sa_state(a, 1, CHILD_REKEYED, CHILD_OUTBOUND_INSTALLED);
+		assert_child_sa_state(a, data[_i].spi_del_b, CHILD_DELETING,
+							  CHILD_OUTBOUND_NONE);
+		assert_ipsec_sas_installed(a, 1, 2, 6);
 	}
+	assert_child_sa_count(a, 2);
+	assert_scheduler();
 	/* INFORMATIONAL { D } --> */
+	assert_jobs_scheduled(1);
 	exchange_test_helper->process_message(exchange_test_helper, b, NULL);
-	assert_child_sa_state(b, data[_i].spi_del_a, CHILD_REKEYED);
-	assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED);
-	assert_child_sa_count(b, 2);
+	if (data[_i].spi_del_b == 2)
+	{
+		assert_child_sa_state(b, data[_i].spi_del_a, CHILD_REKEYED,
+							  CHILD_OUTBOUND_REGISTERED);
+		assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED,
+							  CHILD_OUTBOUND_INSTALLED);
+		assert_ipsec_sas_installed(b, 2, 4, 5, 6);
+	}
+	else
+	{
+		assert_child_sa_state(b, data[_i].spi_del_a, CHILD_REKEYED,
+							  CHILD_OUTBOUND_INSTALLED);
+		assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED,
+							  CHILD_OUTBOUND_REGISTERED);
+		assert_ipsec_sas_installed(b, 1, 2, 4, 5);
+	}
+	assert_child_sa_state(b, data[_i].spi_del_b, CHILD_DELETING,
+						  CHILD_OUTBOUND_NONE);
+	assert_child_sa_count(b, 3);
+	assert_scheduler();
 	assert_hook();
 
 	/* <-- CREATE_CHILD_SA { SA, Nr, [KEr,] TSi, TSr } (delayed) */
@@ -557,20 +755,54 @@ START_TEST(test_collision_delayed_response)
 		exchange_test_helper->process_message(exchange_test_helper, a, msg);
 		assert_hook();
 	}
-	assert_child_sa_state(a, data[_i].spi_del_a, CHILD_DELETING);
-	assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED);
-	assert_child_sa_count(a, 2);
+	assert_child_sa_state(a, data[_i].spi_del_a, CHILD_DELETING,
+						  CHILD_OUTBOUND_INSTALLED);
+	assert_child_sa_state(a, data[_i].spi_del_b, CHILD_DELETING,
+						  CHILD_OUTBOUND_NONE);
+	assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED,
+						  CHILD_OUTBOUND_INSTALLED);
+	assert_ipsec_sas_installed(a, 1, 3, 5, 6,
+							   data[_i].spi_del_a == 1 ? 2 : 4);
+	assert_child_sa_count(a, 3);
 
 	/* we don't expect this hook to get called anymore */
 	assert_hook_not_called(child_rekey);
 	/* INFORMATIONAL { D } --> */
+	assert_jobs_scheduled(1);
 	exchange_test_helper->process_message(exchange_test_helper, b, NULL);
-	assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED);
-	assert_child_sa_count(b, 1);
+	assert_child_sa_state(b, data[_i].spi_del_a, CHILD_DELETING,
+						  CHILD_OUTBOUND_NONE);
+	assert_child_sa_state(b, data[_i].spi_del_b, CHILD_DELETING,
+						  CHILD_OUTBOUND_NONE);
+	assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED,
+						  CHILD_OUTBOUND_INSTALLED);
+	assert_ipsec_sas_installed(b, 2, 4, 5,
+							   data[_i].spi_del_b == 2 ? 6 : 3);
+	assert_child_sa_count(b, 3);
+	assert_scheduler();
 	/* <-- INFORMATIONAL { D } */
+	assert_jobs_scheduled(1);
 	exchange_test_helper->process_message(exchange_test_helper, a, NULL);
-	assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED);
+	assert_child_sa_state(a, data[_i].spi_del_a, CHILD_DELETING,
+						  CHILD_OUTBOUND_NONE);
+	assert_child_sa_state(a, data[_i].spi_del_b, CHILD_DELETING,
+						  CHILD_OUTBOUND_NONE);
+	assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED,
+						  CHILD_OUTBOUND_INSTALLED);
+	assert_child_sa_count(a, 3);
+	assert_ipsec_sas_installed(a, 1, 3, 6,
+							   data[_i].spi_del_a == 1 ? 5 : 4);
+	assert_scheduler();
+
+	/* simulate the execution of the scheduled jobs */
+	destroy_rekeyed(a, data[_i].spi_del_a);
+	destroy_rekeyed(a, data[_i].spi_del_b);
 	assert_child_sa_count(a, 1);
+	assert_ipsec_sas_installed(a, data[_i].spi_a, data[_i].spi_b);
+	destroy_rekeyed(b, data[_i].spi_del_a);
+	destroy_rekeyed(b, data[_i].spi_del_b);
+	assert_child_sa_count(b, 1);
+	assert_ipsec_sas_installed(b, data[_i].spi_a, data[_i].spi_b);
 
 	/* child_rekey/child_updown */
 	assert_hook();
@@ -621,8 +853,10 @@ START_TEST(test_collision_delayed_request)
 
 	exchange_test_helper->nonce_first_byte = data[_i].nonces[0];
 	initiate_rekey(a, 1);
+	assert_ipsec_sas_installed(a, 1, 2);
 	exchange_test_helper->nonce_first_byte = data[_i].nonces[1];
 	initiate_rekey(b, 2);
+	assert_ipsec_sas_installed(b, 1, 2);
 
 	/* delay the CREATE_CHILD_SA request from a to b */
 	msg = exchange_test_helper->sender->dequeue(exchange_test_helper->sender);
@@ -634,14 +868,16 @@ START_TEST(test_collision_delayed_request)
 	exchange_test_helper->nonce_first_byte = data[_i].nonces[2];
 	assert_hook_rekey(child_rekey, 1, 5);
 	exchange_test_helper->process_message(exchange_test_helper, a, NULL);
-	assert_child_sa_state(a, 1, CHILD_REKEYED);
-	assert_child_sa_state(a, 5, CHILD_INSTALLED);
+	assert_child_sa_state(a, 1, CHILD_REKEYED, CHILD_OUTBOUND_INSTALLED);
+	assert_child_sa_state(a, 5, CHILD_INSTALLED, CHILD_OUTBOUND_REGISTERED);
+	assert_ipsec_sas_installed(a, 1, 2, 5);
 	assert_hook();
 	/* CREATE_CHILD_SA { SA, Nr, [KEr,] TSi, TSr } --> */
 	assert_hook_rekey(child_rekey, 2, 4);
 	exchange_test_helper->process_message(exchange_test_helper, b, NULL);
-	assert_child_sa_state(b, 2, CHILD_DELETING);
-	assert_child_sa_state(b, 4, CHILD_INSTALLED);
+	assert_child_sa_state(b, 2, CHILD_DELETING, CHILD_OUTBOUND_INSTALLED);
+	assert_child_sa_state(b, 4, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED);
+	assert_ipsec_sas_installed(b, 1, 2, 4, 5);
 	assert_hook();
 
 	/* we don't expect this hook to get called anymore */
@@ -650,25 +886,43 @@ START_TEST(test_collision_delayed_request)
 	/* CREATE_CHILD_SA { N(REKEY_SA), SA, Ni, [KEi,] TSi, TSr } --> (delayed) */
 	assert_single_notify(OUT, TEMPORARY_FAILURE);
 	exchange_test_helper->process_message(exchange_test_helper, b, msg);
-	assert_child_sa_state(b, 2, CHILD_DELETING);
-	assert_child_sa_state(b, 4, CHILD_INSTALLED);
+	assert_child_sa_state(b, 2, CHILD_DELETING, CHILD_OUTBOUND_INSTALLED);
+	assert_child_sa_state(b, 4, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED);
 
 	/* <-- INFORMATIONAL { D } */
+	assert_jobs_scheduled(1);
 	exchange_test_helper->process_message(exchange_test_helper, a, NULL);
-	assert_child_sa_state(a, 5, CHILD_INSTALLED);
-	assert_child_sa_count(a, 1);
+	assert_child_sa_state(a, 1, CHILD_DELETING, CHILD_OUTBOUND_NONE);
+	assert_child_sa_state(a, 5, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED);
+	assert_child_sa_count(a, 2);
+	assert_ipsec_sas_installed(a, 1, 4, 5);
+	assert_scheduler();
 
 	/* <-- CREATE_CHILD_SA { N(TEMP_FAIL) } */
 	assert_no_jobs_scheduled();
 	exchange_test_helper->process_message(exchange_test_helper, a, NULL);
-	assert_child_sa_state(a, 5, CHILD_INSTALLED);
-	assert_child_sa_count(a, 1);
+	assert_child_sa_state(a, 1, CHILD_DELETING, CHILD_OUTBOUND_NONE);
+	assert_child_sa_state(a, 5, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED);
+	assert_child_sa_count(a, 2);
+	assert_ipsec_sas_installed(a, 1, 4, 5);
 	assert_scheduler();
 
 	/* INFORMATIONAL { D } --> */
+	assert_jobs_scheduled(1);
 	exchange_test_helper->process_message(exchange_test_helper, b, NULL);
-	assert_child_sa_state(b, 4, CHILD_INSTALLED);
+	assert_child_sa_state(b, 2, CHILD_DELETING, CHILD_OUTBOUND_NONE);
+	assert_child_sa_state(b, 4, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED);
+	assert_child_sa_count(b, 2);
+	assert_ipsec_sas_installed(b, 2, 4, 5);
+	assert_scheduler();
+
+	/* simulate the execution of the scheduled jobs */
+	destroy_rekeyed(a, 1);
+	assert_child_sa_count(a, 1);
+	assert_ipsec_sas_installed(a, 4, 5);
+	destroy_rekeyed(b, 2);
 	assert_child_sa_count(b, 1);
+	assert_ipsec_sas_installed(b, 4, 5);
 
 	/* child_rekey/child_updown */
 	assert_hook();
@@ -722,8 +976,10 @@ START_TEST(test_collision_delayed_request_more)
 
 	exchange_test_helper->nonce_first_byte = data[_i].nonces[0];
 	initiate_rekey(a, 1);
+	assert_ipsec_sas_installed(a, 1, 2);
 	exchange_test_helper->nonce_first_byte = data[_i].nonces[1];
 	initiate_rekey(b, 2);
+	assert_ipsec_sas_installed(b, 1, 2);
 
 	/* delay the CREATE_CHILD_SA request from a to b */
 	msg = exchange_test_helper->sender->dequeue(exchange_test_helper->sender);
@@ -735,40 +991,62 @@ START_TEST(test_collision_delayed_request_more)
 	exchange_test_helper->nonce_first_byte = data[_i].nonces[2];
 	assert_hook_rekey(child_rekey, 1, 5);
 	exchange_test_helper->process_message(exchange_test_helper, a, NULL);
-	assert_child_sa_state(a, 1, CHILD_REKEYED);
-	assert_child_sa_state(a, 5, CHILD_INSTALLED);
+	assert_child_sa_state(a, 1, CHILD_REKEYED, CHILD_OUTBOUND_INSTALLED);
+	assert_child_sa_state(a, 5, CHILD_INSTALLED, CHILD_OUTBOUND_REGISTERED);
+	assert_ipsec_sas_installed(a, 1, 2, 5);
 	assert_hook();
 	/* CREATE_CHILD_SA { SA, Nr, [KEr,] TSi, TSr } --> */
 	assert_hook_rekey(child_rekey, 2, 4);
 	exchange_test_helper->process_message(exchange_test_helper, b, NULL);
-	assert_child_sa_state(b, 2, CHILD_DELETING);
-	assert_child_sa_state(b, 4, CHILD_INSTALLED);
+	assert_child_sa_state(b, 2, CHILD_DELETING, CHILD_OUTBOUND_INSTALLED);
+	assert_child_sa_state(b, 4, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED);
+	assert_ipsec_sas_installed(b, 1, 2, 4, 5);
 	assert_hook();
 
 	/* we don't expect this hook to get called anymore */
 	assert_hook_not_called(child_rekey);
 
 	/* <-- INFORMATIONAL { D } */
+	assert_jobs_scheduled(1);
 	exchange_test_helper->process_message(exchange_test_helper, a, NULL);
-	assert_child_sa_state(a, 5, CHILD_INSTALLED);
-	assert_child_sa_count(a, 1);
+	assert_child_sa_state(a, 1, CHILD_DELETING, CHILD_OUTBOUND_NONE);
+	assert_child_sa_state(a, 5, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED);
+	assert_child_sa_count(a, 2);
+	assert_ipsec_sas_installed(a, 1, 4, 5);
+	assert_scheduler();
 	/* INFORMATIONAL { D } --> */
+	assert_jobs_scheduled(1);
 	exchange_test_helper->process_message(exchange_test_helper, b, NULL);
-	assert_child_sa_state(b, 4, CHILD_INSTALLED);
-	assert_child_sa_count(b, 1);
+	assert_child_sa_state(b, 2, CHILD_DELETING, CHILD_OUTBOUND_NONE);
+	assert_child_sa_state(b, 4, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED);
+	assert_child_sa_count(b, 2);
+	assert_ipsec_sas_installed(b, 2, 4, 5);
+	assert_scheduler();
 
 	/* CREATE_CHILD_SA { N(REKEY_SA), SA, Ni, [KEi,] TSi, TSr } --> */
 	assert_single_notify(OUT, CHILD_SA_NOT_FOUND);
 	exchange_test_helper->process_message(exchange_test_helper, b, msg);
-	assert_child_sa_state(b, 4, CHILD_INSTALLED);
-	assert_child_sa_count(b, 1);
+	assert_child_sa_state(b, 2, CHILD_DELETING, CHILD_OUTBOUND_NONE);
+	assert_child_sa_state(b, 4, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED);
+	assert_child_sa_count(b, 2);
+	assert_ipsec_sas_installed(b, 2, 4, 5);
 	/* <-- CREATE_CHILD_SA { N(NO_CHILD_SA) } */
 	assert_no_jobs_scheduled();
 	exchange_test_helper->process_message(exchange_test_helper, a, NULL);
-	assert_child_sa_state(a, 5, CHILD_INSTALLED);
-	assert_child_sa_count(a, 1);
+	assert_child_sa_state(a, 1, CHILD_DELETING, CHILD_OUTBOUND_NONE);
+	assert_child_sa_state(a, 5, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED);
+	assert_child_sa_count(a, 2);
+	assert_ipsec_sas_installed(a, 1, 4, 5);
 	assert_scheduler();
 
+	/* simulate the execution of the scheduled jobs */
+	destroy_rekeyed(a, 1);
+	assert_child_sa_count(a, 1);
+	assert_ipsec_sas_installed(a, 4, 5);
+	destroy_rekeyed(b, 2);
+	assert_child_sa_count(b, 1);
+	assert_ipsec_sas_installed(b, 4, 5);
+
 	/* child_rekey/child_updown */
 	assert_hook();
 	assert_hook();
@@ -842,13 +1120,13 @@ START_TEST(test_collision_ke_invalid)
 	/* CREATE_CHILD_SA { N(REKEY_SA), SA, Ni, [KEi,] TSi, TSr } --> */
 	assert_hook_not_called(child_rekey);
 	exchange_test_helper->process_message(exchange_test_helper, b, NULL);
-	assert_child_sa_state(b, 2, CHILD_REKEYING);
+	assert_child_sa_state(b, 2, CHILD_REKEYING, CHILD_OUTBOUND_INSTALLED);
 	assert_child_sa_count(b, 1);
 	assert_hook();
 	/* <-- CREATE_CHILD_SA { N(REKEY_SA), SA, Ni, [KEi,] TSi, TSr } */
 	assert_hook_not_called(child_rekey);
 	exchange_test_helper->process_message(exchange_test_helper, a, NULL);
-	assert_child_sa_state(a, 1, CHILD_REKEYING);
+	assert_child_sa_state(a, 1, CHILD_REKEYING, CHILD_OUTBOUND_INSTALLED);
 	assert_child_sa_count(a, 1);
 	assert_hook();
 
@@ -857,7 +1135,7 @@ START_TEST(test_collision_ke_invalid)
 	assert_hook_not_called(child_rekey);
 	assert_single_notify(IN, INVALID_KE_PAYLOAD);
 	exchange_test_helper->process_message(exchange_test_helper, a, NULL);
-	assert_child_sa_state(a, 1, CHILD_REKEYING);
+	assert_child_sa_state(a, 1, CHILD_REKEYING, CHILD_OUTBOUND_INSTALLED);
 	assert_child_sa_count(a, 1);
 	assert_hook();
 	/* CREATE_CHILD_SA { N(INVAL_KE) } --> */
@@ -865,7 +1143,7 @@ START_TEST(test_collision_ke_invalid)
 	assert_hook_not_called(child_rekey);
 	assert_single_notify(IN, INVALID_KE_PAYLOAD);
 	exchange_test_helper->process_message(exchange_test_helper, b, NULL);
-	assert_child_sa_state(b, 2, CHILD_REKEYING);
+	assert_child_sa_state(b, 2, CHILD_REKEYING, CHILD_OUTBOUND_INSTALLED);
 	assert_child_sa_count(b, 1);
 	assert_hook();
 
@@ -873,15 +1151,15 @@ START_TEST(test_collision_ke_invalid)
 	exchange_test_helper->nonce_first_byte = data[_i].nonces[2];
 	assert_hook_rekey(child_rekey, 2, 9);
 	exchange_test_helper->process_message(exchange_test_helper, b, NULL);
-	assert_child_sa_state(b, 2, CHILD_REKEYED);
-	assert_child_sa_state(b, 9, CHILD_INSTALLED);
+	assert_child_sa_state(b, 2, CHILD_REKEYED, CHILD_OUTBOUND_INSTALLED);
+	assert_child_sa_state(b, 9, CHILD_INSTALLED, CHILD_OUTBOUND_REGISTERED);
 	assert_hook();
 	/* <-- CREATE_CHILD_SA { N(REKEY_SA), SA, Ni, [KEi,] TSi, TSr } */
 	exchange_test_helper->nonce_first_byte = data[_i].nonces[3];
 	assert_hook_rekey(child_rekey, 1, 10);
 	exchange_test_helper->process_message(exchange_test_helper, a, NULL);
-	assert_child_sa_state(a, 1, CHILD_REKEYED);
-	assert_child_sa_state(a,10, CHILD_INSTALLED);
+	assert_child_sa_state(a, 1, CHILD_REKEYED, CHILD_OUTBOUND_INSTALLED);
+	assert_child_sa_state(a,10, CHILD_INSTALLED, CHILD_OUTBOUND_REGISTERED);
 	assert_hook();
 
 	/* <-- CREATE_CHILD_SA { SA, Nr, [KEr,] TSi, TSr } */
@@ -891,49 +1169,99 @@ START_TEST(test_collision_ke_invalid)
 		assert_hook_rekey(child_rekey, 1, data[_i].spi_a);
 		exchange_test_helper->process_message(exchange_test_helper, a, NULL);
 		assert_hook();
+		assert_child_sa_state(a, data[_i].spi_del_b, CHILD_REKEYED,
+							  CHILD_OUTBOUND_REGISTERED);
+		assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED,
+							  CHILD_OUTBOUND_INSTALLED);
 	}
 	else
 	{
 		exchange_test_helper->process_message(exchange_test_helper, a, NULL);
+		assert_child_sa_state(a, data[_i].spi_del_b, CHILD_REKEYED,
+							  CHILD_OUTBOUND_INSTALLED);
+		assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED,
+							  CHILD_OUTBOUND_REGISTERED);
 	}
-	assert_child_sa_state(a, data[_i].spi_del_a, CHILD_DELETING);
-	assert_child_sa_state(a, data[_i].spi_del_b, CHILD_REKEYED);
-	assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED);
+	assert_child_sa_state(a, data[_i].spi_del_a, CHILD_DELETING,
+						  CHILD_OUTBOUND_INSTALLED);
 	/* CREATE_CHILD_SA { SA, Nr, [KEr,] TSi, TSr } --> */
 	if (data[_i].spi_del_b == 2)
 	{
 		assert_hook_rekey(child_rekey, 2, data[_i].spi_b);
 		exchange_test_helper->process_message(exchange_test_helper, b, NULL);
 		assert_hook();
+		assert_child_sa_state(b, data[_i].spi_del_a, CHILD_REKEYED,
+							  CHILD_OUTBOUND_REGISTERED);
+		assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED,
+							  CHILD_OUTBOUND_INSTALLED);
 	}
 	else
 	{
 		exchange_test_helper->process_message(exchange_test_helper, b, NULL);
+		assert_child_sa_state(b, data[_i].spi_del_a, CHILD_REKEYED,
+							  CHILD_OUTBOUND_INSTALLED);
+		assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED,
+							  CHILD_OUTBOUND_REGISTERED);
 	}
-	assert_child_sa_state(b, data[_i].spi_del_b, CHILD_DELETING);
-	assert_child_sa_state(b, data[_i].spi_del_a, CHILD_REKEYED);
-	assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED);
+	assert_child_sa_state(b, data[_i].spi_del_b, CHILD_DELETING,
+						  CHILD_OUTBOUND_INSTALLED);
 
 	/* we don't expect this hook to get called anymore */
 	assert_hook_not_called(child_rekey);
 	/* INFORMATIONAL { D } --> */
+	assert_jobs_scheduled(1);
 	exchange_test_helper->process_message(exchange_test_helper, b, NULL);
-	assert_child_sa_state(b, data[_i].spi_del_b, CHILD_DELETING);
-	assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED);
-	assert_child_sa_count(b, 2);
+	assert_child_sa_state(b, data[_i].spi_del_b, CHILD_DELETING,
+						  CHILD_OUTBOUND_INSTALLED);
+	assert_child_sa_state(b, data[_i].spi_del_a, CHILD_DELETING,
+						  CHILD_OUTBOUND_NONE);
+	assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED,
+						  CHILD_OUTBOUND_INSTALLED);
+	assert_child_sa_count(b, 3);
+	assert_scheduler();
 	/* <-- INFORMATIONAL { D } */
+	assert_jobs_scheduled(1);
 	exchange_test_helper->process_message(exchange_test_helper, a, NULL);
-	assert_child_sa_state(a, data[_i].spi_del_a, CHILD_DELETING);
-	assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED);
-	assert_child_sa_count(a, 2);
+	assert_child_sa_state(a, data[_i].spi_del_a, CHILD_DELETING,
+						  CHILD_OUTBOUND_INSTALLED);
+	assert_child_sa_state(a, data[_i].spi_del_b, CHILD_DELETING,
+						  CHILD_OUTBOUND_NONE);
+	assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED,
+						  CHILD_OUTBOUND_INSTALLED);
+	assert_child_sa_count(a, 3);
+	assert_scheduler();
 	/* <-- INFORMATIONAL { D } */
+	assert_jobs_scheduled(1);
 	exchange_test_helper->process_message(exchange_test_helper, a, NULL);
-	assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED);
-	assert_child_sa_count(a, 1);
+	assert_child_sa_state(a, data[_i].spi_del_a, CHILD_DELETING,
+						  CHILD_OUTBOUND_NONE);
+	assert_child_sa_state(a, data[_i].spi_del_b, CHILD_DELETING,
+						  CHILD_OUTBOUND_NONE);
+	assert_child_sa_state(a, data[_i].spi_a, CHILD_INSTALLED,
+						  CHILD_OUTBOUND_INSTALLED);
+	assert_child_sa_count(a, 3);
+	assert_scheduler();
 	/* INFORMATIONAL { D } --> */
+	assert_jobs_scheduled(1);
 	exchange_test_helper->process_message(exchange_test_helper, b, NULL);
-	assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED);
+	assert_child_sa_state(b, data[_i].spi_del_b, CHILD_DELETING,
+						  CHILD_OUTBOUND_NONE);
+	assert_child_sa_state(b, data[_i].spi_del_a, CHILD_DELETING,
+						  CHILD_OUTBOUND_NONE);
+	assert_child_sa_state(b, data[_i].spi_b, CHILD_INSTALLED,
+						  CHILD_OUTBOUND_INSTALLED);
+	assert_child_sa_count(b, 3);
+	assert_scheduler();
+
+	/* simulate the execution of the scheduled jobs */
+	destroy_rekeyed(a, data[_i].spi_del_a);
+	destroy_rekeyed(a, data[_i].spi_del_b);
+	assert_child_sa_count(a, 1);
+	assert_ipsec_sas_installed(a, data[_i].spi_a, data[_i].spi_b);
+	destroy_rekeyed(b, data[_i].spi_del_a);
+	destroy_rekeyed(b, data[_i].spi_del_b);
 	assert_child_sa_count(b, 1);
+	assert_ipsec_sas_installed(b, data[_i].spi_a, data[_i].spi_b);
 
 	/* child_rekey/child_updown */
 	assert_hook();
@@ -1004,13 +1332,13 @@ START_TEST(test_collision_ke_invalid_delayed_retry)
 	/* CREATE_CHILD_SA { N(REKEY_SA), SA, Ni, [KEi,] TSi, TSr } --> */
 	assert_hook_not_called(child_rekey);
 	exchange_test_helper->process_message(exchange_test_helper, b, NULL);
-	assert_child_sa_state(b, 2, CHILD_REKEYING);
+	assert_child_sa_state(b, 2, CHILD_REKEYING, CHILD_OUTBOUND_INSTALLED);
 	assert_child_sa_count(b, 1);
 	assert_hook();
 	/* <-- CREATE_CHILD_SA { N(REKEY_SA), SA, Ni, [KEi,] TSi, TSr } */
 	assert_hook_not_called(child_rekey);
 	exchange_test_helper->process_message(exchange_test_helper, a, NULL);
-	assert_child_sa_state(a, 1, CHILD_REKEYING);
+	assert_child_sa_state(a, 1, CHILD_REKEYING, CHILD_OUTBOUND_INSTALLED);
 	assert_child_sa_count(a, 1);
 	assert_hook();
 
@@ -1019,7 +1347,7 @@ START_TEST(test_collision_ke_invalid_delayed_retry)
 	assert_hook_not_called(child_rekey);
 	assert_single_notify(IN, INVALID_KE_PAYLOAD);
 	exchange_test_helper->process_message(exchange_test_helper, a, NULL);
-	assert_child_sa_state(a, 1, CHILD_REKEYING);
+	assert_child_sa_state(a, 1, CHILD_REKEYING, CHILD_OUTBOUND_INSTALLED);
 	assert_child_sa_count(a, 1);
 	assert_hook();
 	/* CREATE_CHILD_SA { N(INVAL_KE) } --> */
@@ -1027,7 +1355,7 @@ START_TEST(test_collision_ke_invalid_delayed_retry)
 	assert_hook_not_called(child_rekey);
 	assert_single_notify(IN, INVALID_KE_PAYLOAD);
 	exchange_test_helper->process_message(exchange_test_helper, b, NULL);
-	assert_child_sa_state(b, 2, CHILD_REKEYING);
+	assert_child_sa_state(b, 2, CHILD_REKEYING, CHILD_OUTBOUND_INSTALLED);
 	assert_child_sa_count(b, 1);
 	assert_hook();
 
@@ -1038,14 +1366,14 @@ START_TEST(test_collision_ke_invalid_delayed_retry)
 	exchange_test_helper->nonce_first_byte = data[_i].nonces[2];
 	assert_hook_rekey(child_rekey, 1, 9);
 	exchange_test_helper->process_message(exchange_test_helper, a, NULL);
-	assert_child_sa_state(a, 1, CHILD_REKEYED);
-	assert_child_sa_state(a, 9, CHILD_INSTALLED);
+	assert_child_sa_state(a, 1, CHILD_REKEYED, CHILD_OUTBOUND_INSTALLED);
+	assert_child_sa_state(a, 9, CHILD_INSTALLED, CHILD_OUTBOUND_REGISTERED);
 	assert_hook();
 	/* CREATE_CHILD_SA { SA, Nr, [KEr,] TSi, TSr } --> */
 	assert_hook_rekey(child_rekey, 2, 8);
 	exchange_test_helper->process_message(exchange_test_helper, b, NULL);
-	assert_child_sa_state(b, 2, CHILD_DELETING);
-	assert_child_sa_state(b, 8, CHILD_INSTALLED);
+	assert_child_sa_state(b, 2, CHILD_DELETING, CHILD_OUTBOUND_INSTALLED);
+	assert_child_sa_state(b, 8, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED);
 	assert_hook();
 
 	/* we don't expect this hook to get called anymore */
@@ -1054,25 +1382,40 @@ START_TEST(test_collision_ke_invalid_delayed_retry)
 	/* CREATE_CHILD_SA { N(REKEY_SA), SA, Ni, [KEi,] TSi, TSr } --> (delayed) */
 	assert_single_notify(OUT, TEMPORARY_FAILURE);
 	exchange_test_helper->process_message(exchange_test_helper, b, msg);
-	assert_child_sa_state(b, 2, CHILD_DELETING);
-	assert_child_sa_state(b, 8, CHILD_INSTALLED);
+	assert_child_sa_state(b, 2, CHILD_DELETING, CHILD_OUTBOUND_INSTALLED);
+	assert_child_sa_state(b, 8, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED);
 
 	/* <-- INFORMATIONAL { D } */
+	assert_jobs_scheduled(1);
 	exchange_test_helper->process_message(exchange_test_helper, a, NULL);
-	assert_child_sa_state(a, 9, CHILD_INSTALLED);
-	assert_child_sa_count(a, 1);
+	assert_child_sa_state(a, 1, CHILD_DELETING, CHILD_OUTBOUND_NONE);
+	assert_child_sa_state(a, 9, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED);
+	assert_child_sa_count(a, 2);
+	assert_scheduler();
 
 	/* <-- CREATE_CHILD_SA { N(TEMP_FAIL) } */
 	assert_no_jobs_scheduled();
 	exchange_test_helper->process_message(exchange_test_helper, a, NULL);
-	assert_child_sa_state(a, 9, CHILD_INSTALLED);
-	assert_child_sa_count(a, 1);
+	assert_child_sa_state(a, 1, CHILD_DELETING, CHILD_OUTBOUND_NONE);
+	assert_child_sa_state(a, 9, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED);
+	assert_child_sa_count(a, 2);
 	assert_scheduler();
 
 	/* INFORMATIONAL { D } --> */
+	assert_jobs_scheduled(1);
 	exchange_test_helper->process_message(exchange_test_helper, b, NULL);
-	assert_child_sa_state(b, 8, CHILD_INSTALLED);
+	assert_child_sa_state(b, 2, CHILD_DELETING, CHILD_OUTBOUND_NONE);
+	assert_child_sa_state(b, 8, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED);
+	assert_child_sa_count(b, 2);
+	assert_scheduler();
+
+	/* simulate the execution of the scheduled jobs */
+	destroy_rekeyed(a, 1);
+	assert_child_sa_count(a, 1);
+	assert_ipsec_sas_installed(a, 8, 9);
+	destroy_rekeyed(b, 2);
 	assert_child_sa_count(b, 1);
+	assert_ipsec_sas_installed(b, 8, 9);
 
 	/* child_rekey/child_updown */
 	assert_hook();
@@ -1114,7 +1457,7 @@ START_TEST(test_collision_delete)
 	}
 	initiate_rekey(a, spi_a);
 	call_ikesa(b, delete_child_sa, PROTO_ESP, spi_b, FALSE);
-	assert_child_sa_state(b, spi_b, CHILD_DELETING);
+	assert_child_sa_state(b, spi_b, CHILD_DELETING, CHILD_OUTBOUND_INSTALLED);
 
 	/* this should never get called as there is no successful rekeying on
 	 * either side */
@@ -1129,7 +1472,7 @@ START_TEST(test_collision_delete)
 	assert_notify(IN, REKEY_SA);
 	assert_single_notify(OUT, TEMPORARY_FAILURE);
 	exchange_test_helper->process_message(exchange_test_helper, b, NULL);
-	assert_child_sa_state(b, spi_b, CHILD_DELETING);
+	assert_child_sa_state(b, spi_b, CHILD_DELETING, CHILD_OUTBOUND_INSTALLED);
 	assert_hook();
 
 	/* RFC 7296, 2.25.1: If a peer receives a request to delete a CHILD_SA that
@@ -1201,7 +1544,7 @@ START_TEST(test_collision_delete_drop_delete)
 	}
 	initiate_rekey(a, spi_a);
 	call_ikesa(b, delete_child_sa, PROTO_ESP, spi_b, FALSE);
-	assert_child_sa_state(b, spi_b, CHILD_DELETING);
+	assert_child_sa_state(b, spi_b, CHILD_DELETING, CHILD_OUTBOUND_INSTALLED);
 
 	/* this should never get called as there is no successful rekeying on
 	 * either side */
@@ -1216,7 +1559,7 @@ START_TEST(test_collision_delete_drop_delete)
 	assert_notify(IN, REKEY_SA);
 	assert_single_notify(OUT, TEMPORARY_FAILURE);
 	exchange_test_helper->process_message(exchange_test_helper, b, NULL);
-	assert_child_sa_state(b, spi_b, CHILD_DELETING);
+	assert_child_sa_state(b, spi_b, CHILD_DELETING, CHILD_OUTBOUND_INSTALLED);
 	assert_hook();
 
 	/* delay the DELETE request */
@@ -1227,7 +1570,7 @@ START_TEST(test_collision_delete_drop_delete)
 	/* we expect a job to retry the rekeying is scheduled */
 	assert_jobs_scheduled(1);
 	exchange_test_helper->process_message(exchange_test_helper, a, NULL);
-	assert_child_sa_state(a, spi_a, CHILD_INSTALLED);
+	assert_child_sa_state(a, spi_a, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED);
 	assert_scheduler();
 	assert_hook();
 
@@ -1286,7 +1629,7 @@ END_TEST
 	}
 	initiate_rekey(a, spi_a);
 	call_ikesa(b, delete_child_sa, PROTO_ESP, spi_b, FALSE);
-	assert_child_sa_state(b, spi_b, CHILD_DELETING);
+	assert_child_sa_state(b, spi_b, CHILD_DELETING, CHILD_OUTBOUND_INSTALLED);
 
 	/* this should never get called as there is no successful rekeying on
 	 * either side */
@@ -1419,13 +1762,13 @@ START_TEST(test_collision_ike_rekey)
 	/* <-- CREATE_CHILD_SA { SA, Ni, KEi } */
 	assert_single_notify(OUT, TEMPORARY_FAILURE);
 	exchange_test_helper->process_message(exchange_test_helper, a, NULL);
-	assert_child_sa_state(a, spi_a, CHILD_REKEYING);
+	assert_child_sa_state(a, spi_a, CHILD_REKEYING, CHILD_OUTBOUND_INSTALLED);
 
 	/* <-- CREATE_CHILD_SA { N(TEMP_FAIL) } */
 	/* we expect a job to retry the rekeying is scheduled */
 	assert_jobs_scheduled(1);
 	exchange_test_helper->process_message(exchange_test_helper, a, NULL);
-	assert_child_sa_state(a, spi_a, CHILD_INSTALLED);
+	assert_child_sa_state(a, spi_a, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED);
 	assert_scheduler();
 
 	/* CREATE_CHILD_SA { N(TEMP_FAIL) } --> */
diff --git a/src/libcharon/tests/utils/exchange_test_asserts.c b/src/libcharon/tests/utils/exchange_test_asserts.c
index 2602b97..8042d0b 100644
--- a/src/libcharon/tests/utils/exchange_test_asserts.c
+++ b/src/libcharon/tests/utils/exchange_test_asserts.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 Tobias Brunner
+ * Copyright (C) 2016-2017 Tobias Brunner
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -18,6 +18,7 @@
 #include <test_suite.h>
 
 #include "exchange_test_asserts.h"
+#include "mock_ipsec.h"
 
 /*
  * Described in header
@@ -180,3 +181,57 @@ bool exchange_test_asserts_message(listener_t *listener, ike_sa_t *ike_sa,
 	}
 	return TRUE;
 }
+
+/**
+ * Compare two SPIs
+ */
+static int spis_cmp(const void *a, const void *b)
+{
+	return *(const uint32_t*)a - *(const uint32_t*)b;
+}
+
+/**
+ * Compare two SPIs to sort them
+ */
+static int spis_sort(const void *a, const void *b, void *data)
+{
+	return spis_cmp(a, b);
+}
+
+
+/*
+ * Described in header
+ */
+void exchange_test_asserts_ipsec_sas(ipsec_sas_assert_t *sas)
+{
+	enumerator_t *enumerator;
+	array_t *spis;
+	ike_sa_t *ike_sa;
+	uint32_t spi;
+	int i;
+
+	spis = array_create(sizeof(uint32_t), 0);
+	for (i = 0; i < sas->count; i++)
+	{
+		array_insert(spis, ARRAY_TAIL, &sas->spis[i]);
+	}
+	array_sort(spis, spis_sort, NULL);
+
+	enumerator = mock_ipsec_create_sa_enumerator();
+	while (enumerator->enumerate(enumerator, &ike_sa, &spi))
+	{
+		if (ike_sa == sas->ike_sa)
+		{
+			i = array_bsearch(spis, &spi, spis_cmp, NULL);
+			assert_listener_msg(i != -1, sas, "unexpected IPsec SA %.8x", spi);
+			array_remove(spis, i, NULL);
+		}
+	}
+	enumerator->destroy(enumerator);
+	for (i = 0; i < array_count(spis); i++)
+	{
+		array_get(spis, i, &spi);
+		assert_listener_msg(!spi, sas, "expected IPsec SA %.8x not found", spi);
+	}
+	array_destroy(spis);
+}
diff --git a/src/libcharon/tests/utils/exchange_test_asserts.h b/src/libcharon/tests/utils/exchange_test_asserts.h
index 32afcc2..4d363ed 100644
--- a/src/libcharon/tests/utils/exchange_test_asserts.h
+++ b/src/libcharon/tests/utils/exchange_test_asserts.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 Tobias Brunner
+ * Copyright (C) 2016-2017 Tobias Brunner
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -14,7 +14,7 @@
  */
 
 /**
- * Special assertions using listener_t.
+ * Special assertions using listener_t etc.
  *
  * @defgroup exchange_test_asserts exchange_test_asserts
  * @{ @ingroup test_utils_c
@@ -28,6 +28,7 @@
 typedef struct listener_hook_assert_t listener_hook_assert_t;
 typedef struct listener_message_assert_t listener_message_assert_t;
 typedef struct listener_message_rule_t listener_message_rule_t;
+typedef struct ipsec_sas_assert_t ipsec_sas_assert_t;
 
 struct listener_hook_assert_t {
 
@@ -340,4 +341,60 @@ bool exchange_test_asserts_message(listener_t *this, ike_sa_t *ike_sa,
 	exchange_test_helper->add_listener(exchange_test_helper, &_listener.listener); \
 })
 
+/**
+ * Data used to check IPsec SAs
+ */
+struct ipsec_sas_assert_t {
+
+	/**
+	 * Original source file
+	 */
+	const char *file;
+
+	/**
+	 * Source line
+	 */
+	int line;
+
+	/**
+	 * IKE_SA that installed the IPsec SAs
+	 */
+	ike_sa_t *ike_sa;
+
+	/**
+	 * SPIs to check
+	 */
+	uint32_t *spis;
+
+	/**
+	 * Number of SPIs for IPsec SAs to check
+	 */
+	int count;
+};
+
+/**
+ * Assert that all given IPsec SAs (and only these) are installed for the given
+ * IKE_SA.
+ */
+void exchange_test_asserts_ipsec_sas(ipsec_sas_assert_t *sas);
+
+/**
+ * Assert that the IPsec SAs with the given SPIs (and none other) are currently
+ * installed by the given IKE_SA.
+ *
+ * @param sa		IKE_SA
+ * @param ...		list of SPIs
+ */
+#define assert_ipsec_sas_installed(sa, ...) ({ \
+	uint32_t _spis[] = { __VA_ARGS__ }; \
+	ipsec_sas_assert_t _sas_assert = { \
+		.file = __FILE__, \
+		.line = __LINE__, \
+		.ike_sa = sa, \
+		.spis = _spis, \
+		.count = countof(_spis), \
+	}; \
+	exchange_test_asserts_ipsec_sas(&_sas_assert); \
+})
+
 #endif /** EXCHANGE_TEST_ASSERTS_H_ @}*/
diff --git a/src/libcharon/tests/utils/mock_ipsec.c b/src/libcharon/tests/utils/mock_ipsec.c
index d57a26a..d6172f5 100644
--- a/src/libcharon/tests/utils/mock_ipsec.c
+++ b/src/libcharon/tests/utils/mock_ipsec.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 Tobias Brunner
+ * Copyright (C) 2016-2017 Tobias Brunner
  * Copyright (C) 2008 Martin Willi
  * HSR Hochschule fuer Technik Rapperswil
  *
@@ -16,6 +16,12 @@
 
 #include "mock_ipsec.h"
 
+#include <daemon.h>
+#include <collections/hashtable.h>
+#include <collections/array.h>
+
+#include <assert.h>
+
 typedef struct private_kernel_ipsec_t private_kernel_ipsec_t;
 
 /**
@@ -29,16 +35,80 @@ struct private_kernel_ipsec_t {
 	kernel_ipsec_t public;
 
 	/**
+	 * Rekey listener
+	 */
+	listener_t listener;
+
+	/**
 	 * Allocated SPI
 	 */
 	refcount_t spi;
+
+	/**
+	 * Installed SAs
+	 */
+	hashtable_t *sas;
 };
 
+/**
+ * Global instance
+ */
+static private_kernel_ipsec_t *instance;
+
+/**
+ * Data about installed IPsec SAs
+ */
+typedef struct {
+	/**
+	 * SPI of the SA
+	 */
+	uint32_t spi;
+
+	/**
+	 * Associated IKE_SA
+	 */
+	ike_sa_t *ike_sa;
+
+	/**
+	 * TRUE if this was an allocated SPI
+	 */
+	bool alloc;
+
+} entry_t;
+
+/**
+ * Hash an IPsec SA entry
+ */
+static u_int entry_hash(const void *key)
+{
+	entry_t *entry = (entry_t*)key;
+	return chunk_hash_inc(chunk_from_thing(entry->spi),
+						  chunk_hash(chunk_from_thing(entry->ike_sa)));
+}
+
+/**
+ * Compare an IPsec SA entry
+ */
+static bool entry_equals(const void *key, const void *other_key)
+{
+	entry_t *a = (entry_t*)key, *b = (entry_t*)other_key;
+	return a->spi == b->spi && a->ike_sa == b->ike_sa;
+}
+
 METHOD(kernel_ipsec_t, get_spi, status_t,
 	private_kernel_ipsec_t *this, host_t *src, host_t *dst, uint8_t protocol,
 	uint32_t *spi)
 {
+	entry_t *entry;
+
 	*spi = (uint32_t)ref_get(&this->spi);
+	INIT(entry,
+		.spi = *spi,
+		.ike_sa = charon->bus->get_sa(charon->bus),
+		.alloc = TRUE,
+	);
+	entry = this->sas->put(this->sas, entry, entry);
+	assert(!entry);
 	return SUCCESS;
 }
 
@@ -52,6 +122,23 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
 	private_kernel_ipsec_t *this, kernel_ipsec_sa_id_t *id,
 	kernel_ipsec_add_sa_t *data)
 {
+	entry_t *entry;
+
+	INIT(entry,
+		.spi = id->spi,
+		.ike_sa = charon->bus->get_sa(charon->bus),
+	);
+	if (data->inbound)
+	{
+		entry = this->sas->put(this->sas, entry, entry);
+		assert(entry && entry->alloc);
+		free(entry);
+	}
+	else
+	{
+		entry = this->sas->put(this->sas, entry, entry);
+		assert(!entry);
+	}
 	return SUCCESS;
 }
 
@@ -74,9 +161,47 @@ METHOD(kernel_ipsec_t, del_sa, status_t,
 	private_kernel_ipsec_t *this, kernel_ipsec_sa_id_t *id,
 	kernel_ipsec_del_sa_t *data)
 {
+	entry_t *entry, lookup = {
+		.spi = id->spi,
+		.ike_sa = charon->bus->get_sa(charon->bus),
+	};
+
+	entry = this->sas->remove(this->sas, &lookup);
+	assert(entry);
+	free(entry);
 	return SUCCESS;
 }
 
+METHOD(listener_t, ike_rekey, bool,
+	listener_t *listener, ike_sa_t *old, ike_sa_t *new)
+{
+	enumerator_t *enumerator;
+	array_t *sas = NULL;
+	entry_t *entry;
+
+	enumerator = instance->sas->create_enumerator(instance->sas);
+	while (enumerator->enumerate(enumerator, &entry, NULL))
+	{
+		if (entry->ike_sa == old)
+		{
+			instance->sas->remove_at(instance->sas, enumerator);
+			array_insert_create(&sas, ARRAY_TAIL, entry);
+		}
+	}
+	enumerator->destroy(enumerator);
+	enumerator = array_create_enumerator(sas);
+	while (enumerator->enumerate(enumerator, &entry))
+	{
+		array_remove_at(sas, enumerator);
+		entry->ike_sa = new;
+		entry = instance->sas->put(instance->sas, entry, entry);
+		assert(!entry);
+	}
+	enumerator->destroy(enumerator);
+	array_destroy(sas);
+	return TRUE;
+}
+
 METHOD(kernel_ipsec_t, add_policy, status_t,
 	private_kernel_ipsec_t *this, kernel_ipsec_policy_id_t *id,
 	kernel_ipsec_manage_policy_t *data)
@@ -99,6 +224,14 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
 	return SUCCESS;
 }
 
+METHOD(kernel_ipsec_t, destroy, void,
+	private_kernel_ipsec_t *this)
+{
+	charon->bus->remove_listener(charon->bus, &this->listener);
+	this->sas->destroy(this->sas);
+	free(this);
+}
+
 /*
  * Described in header
  */
@@ -121,8 +254,50 @@ kernel_ipsec_t *mock_ipsec_create()
 			.flush_policies = (void*)return_failed,
 			.bypass_socket = (void*)return_true,
 			.enable_udp_decap = (void*)return_true,
-			.destroy = (void*)free,
+			.destroy = _destroy,
+		},
+		.listener = {
+			.ike_rekey = _ike_rekey,
 		},
+		.sas = hashtable_create(entry_hash, entry_equals, 8),
 	);
+
+	instance = this;
+
+	charon->bus->add_listener(charon->bus, &this->listener);
+
 	return &this->public;
 }
+
+
+CALLBACK(filter_sas, bool,
+	void *data, enumerator_t *orig, va_list args)
+{
+	entry_t *entry;
+	ike_sa_t **ike_sa;
+	uint32_t *spi;
+
+	VA_ARGS_VGET(args, ike_sa, spi);
+
+	while (orig->enumerate(orig, &entry, NULL))
+	{
+		if (entry->alloc)
+		{
+			continue;
+		}
+		*ike_sa = entry->ike_sa;
+		*spi = entry->spi;
+		return TRUE;
+	}
+	return FALSE;
+}
+
+/*
+ * Described in header
+ */
+enumerator_t *mock_ipsec_create_sa_enumerator()
+{
+	return enumerator_create_filter(
+							instance->sas->create_enumerator(instance->sas),
+							filter_sas, NULL, NULL);
+}
diff --git a/src/libcharon/tests/utils/mock_ipsec.h b/src/libcharon/tests/utils/mock_ipsec.h
index cbf2152..95038a5 100644
--- a/src/libcharon/tests/utils/mock_ipsec.h
+++ b/src/libcharon/tests/utils/mock_ipsec.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 Tobias Brunner
+ * Copyright (C) 2016-2017 Tobias Brunner
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -15,7 +15,7 @@
 
 /**
  * kernel_ipsec_t implementation used for exchange unit tests.  Currently
- * returns sequential SPIs, all other methods are noops.
+ * returns sequential SPIs, and keeps track of installed SAs.
  *
  * @defgroup mock_ipsec mock_ipsec
  * @{ @ingroup test_utils_c
@@ -33,4 +33,11 @@
  */
 kernel_ipsec_t *mock_ipsec_create();
 
+/**
+ * Enumerate the installed SAs
+ *
+ * @return		enumerator over (ike_sa_t*, uint32_t)
+ */
+enumerator_t *mock_ipsec_create_sa_enumerator();
+
 #endif /** MOCK_IPSEC_H_ @}*/
diff --git a/src/libcharon/tests/utils/sa_asserts.h b/src/libcharon/tests/utils/sa_asserts.h
index 7afa3b5..d23f724 100644
--- a/src/libcharon/tests/utils/sa_asserts.h
+++ b/src/libcharon/tests/utils/sa_asserts.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 Tobias Brunner
+ * Copyright (C) 2016-2017 Tobias Brunner
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -82,13 +82,38 @@
 })
 
 /**
+ * Check if the CHILD_SA with the given SPI is in the expected state, optionally
+ * check the state of the outbound SA.
+ */
+#define assert_child_sa_state(...) VA_ARGS_DISPATCH(assert_child_sa_state, __VA_ARGS__)(__VA_ARGS__)
+
+/**
  * Check if the CHILD_SA with the given SPI is in the expected state.
  */
-#define assert_child_sa_state(ike_sa, spi, state) \
+#define assert_child_sa_state3(ike_sa, spi, state) \
+({ \
+	typeof(ike_sa) _sa = ike_sa; \
+	typeof(spi) _spi = spi; \
+	typeof(state) _state = state; \
+	child_sa_t *_child = _sa->get_child_sa(_sa, PROTO_ESP, _spi, TRUE) ?: \
+						 _sa->get_child_sa(_sa, PROTO_ESP, _spi, FALSE); \
+	test_assert_msg(_child, "CHILD_SA with SPI %.8x does not exist", \
+					ntohl(_spi)); \
+	test_assert_msg(_state == _child->get_state(_child), "%N != %N", \
+					child_sa_state_names, _state, \
+					child_sa_state_names, _child->get_state(_child)); \
+})
+
+/**
+ * Check if the outbound SA of a CHILD_SA with the given SPI is in the
+ * expected state.
+ */
+#define assert_child_sa_state4(ike_sa, spi, state, outbound) \
 ({ \
 	typeof(ike_sa) _sa = ike_sa; \
 	typeof(spi) _spi = spi; \
 	typeof(state) _state = state; \
+	typeof(outbound) _outbound = outbound; \
 	child_sa_t *_child = _sa->get_child_sa(_sa, PROTO_ESP, _spi, TRUE) ?: \
 						 _sa->get_child_sa(_sa, PROTO_ESP, _spi, FALSE); \
 	test_assert_msg(_child, "CHILD_SA with SPI %.8x does not exist", \
@@ -96,6 +121,9 @@
 	test_assert_msg(_state == _child->get_state(_child), "%N != %N", \
 					child_sa_state_names, _state, \
 					child_sa_state_names, _child->get_state(_child)); \
+	test_assert_msg(_outbound == _child->get_outbound_state(_child), "%N != %N", \
+					child_sa_outbound_state_names, _outbound, \
+					child_sa_outbound_state_names, _child->get_outbound_state(_child)); \
 })
 
 /**
diff --git a/src/libfast/Makefile.in b/src/libfast/Makefile.in
index c3512b6..8adf068 100644
--- a/src/libfast/Makefile.in
+++ b/src/libfast/Makefile.in
@@ -361,6 +361,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -383,6 +384,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libimcv/Makefile.in b/src/libimcv/Makefile.in
index b0b55fb..e361f20 100644
--- a/src/libimcv/Makefile.in
+++ b/src/libimcv/Makefile.in
@@ -530,6 +530,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -552,6 +553,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libimcv/ietf/ietf_attr_installed_packages.c b/src/libimcv/ietf/ietf_attr_installed_packages.c
index 7a870ac..d8e5b33 100644
--- a/src/libimcv/ietf/ietf_attr_installed_packages.c
+++ b/src/libimcv/ietf/ietf_attr_installed_packages.c
@@ -179,7 +179,7 @@ METHOD(pa_tnc_attr_t, process, status_t,
 	u_char *pos;
 
 	if (this->offset == 0)
-	{	
+	{
 		if (this->length < IETF_INSTALLED_PACKAGES_MIN_SIZE)
 		{
 			DBG1(DBG_TNC, "insufficient data for %N/%N", pen_names, PEN_IETF,
@@ -291,15 +291,21 @@ METHOD(ietf_attr_installed_packages_t, add, void,
 	this->packages->insert_last(this->packages, entry);
 }
 
-/**
- * Enumerate package filter entries
- */
-static bool package_filter(void *null, package_entry_t **entry, chunk_t *name,
-						   void *i2, chunk_t *version)
+CALLBACK(package_filter, bool,
+	void *null, enumerator_t *orig, va_list args)
 {
-	*name = (*entry)->name;
-	*version = (*entry)->version;
-	return TRUE;
+	package_entry_t *entry;
+	chunk_t *name, *version;
+
+	VA_ARGS_VGET(args, name, version);
+
+	if (orig->enumerate(orig, &entry))
+	{
+		*name = entry->name;
+		*version = entry->version;
+		return TRUE;
+	}
+	return FALSE;
 }
 
 METHOD(ietf_attr_installed_packages_t, create_enumerator, enumerator_t*,
@@ -307,7 +313,7 @@ METHOD(ietf_attr_installed_packages_t, create_enumerator, enumerator_t*,
 {
 	return enumerator_create_filter(
 						this->packages->create_enumerator(this->packages),
-						(void*)package_filter, NULL, NULL);
+						package_filter, NULL, NULL);
 }
 
 METHOD(ietf_attr_installed_packages_t, get_count, uint16_t,
diff --git a/src/libimcv/ietf/ietf_attr_op_status.c b/src/libimcv/ietf/ietf_attr_op_status.c
index f04c89b..1f813b3 100644
--- a/src/libimcv/ietf/ietf_attr_op_status.c
+++ b/src/libimcv/ietf/ietf_attr_op_status.c
@@ -170,6 +170,7 @@ METHOD(pa_tnc_attr_t, process, status_t,
 	chunk_t last_use;
 	uint16_t reserved;
 	struct tm t;
+	char buf[BUF_LEN];
 
 	*offset = 0;
 
@@ -208,7 +209,8 @@ METHOD(pa_tnc_attr_t, process, status_t,
 	*offset = 4;
 
 	/* Conversion from RFC 3339 ASCII string to time_t */
-	if (sscanf(last_use.ptr, "%4d-%2d-%2dT%2d:%2d:%2dZ", &t.tm_year, &t.tm_mon,
+	snprintf(buf, sizeof(buf), "%.*s", (int)last_use.len, last_use.ptr);
+	if (sscanf(buf, "%4d-%2d-%2dT%2d:%2d:%2dZ", &t.tm_year, &t.tm_mon,
 			   &t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec) != 6)
 	{
 		DBG1(DBG_TNC, "invalid last_use time format in IETF operational status");
diff --git a/src/libimcv/ietf/ietf_attr_port_filter.c b/src/libimcv/ietf/ietf_attr_port_filter.c
index 05920fd..2f7e445 100644
--- a/src/libimcv/ietf/ietf_attr_port_filter.c
+++ b/src/libimcv/ietf/ietf_attr_port_filter.c
@@ -213,24 +213,31 @@ METHOD(ietf_attr_port_filter_t, add_port, void,
 	this->ports->insert_last(this->ports, entry);
 }
 
-/**
- * Enumerate port filter entries
- */
-static bool port_filter(void *null, port_entry_t **entry,
-						bool *blocked, void *i2, uint8_t *protocol, void *i3,
-						uint16_t *port)
+CALLBACK(port_filter, bool,
+	void *null, enumerator_t *orig, va_list args)
 {
-	*blocked = (*entry)->blocked;
-	*protocol = (*entry)->protocol;
-	*port = (*entry)->port;
-	return TRUE;
+	port_entry_t *entry;
+	uint16_t *port;
+	uint8_t *protocol;
+	bool *blocked;
+
+	VA_ARGS_VGET(args, blocked, protocol, port);
+
+	if (orig->enumerate(orig, &entry))
+	{
+		*blocked = entry->blocked;
+		*protocol = entry->protocol;
+		*port = entry->port;
+		return TRUE;
+	}
+	return FALSE;
 }
 
 METHOD(ietf_attr_port_filter_t, create_port_enumerator, enumerator_t*,
 	private_ietf_attr_port_filter_t *this)
 {
 	return enumerator_create_filter(this->ports->create_enumerator(this->ports),
-					(void*)port_filter, NULL, NULL);
+									port_filter, NULL, NULL);
 }
 
 /**
diff --git a/src/libimcv/imc/imc_os_info.c b/src/libimcv/imc/imc_os_info.c
index 3315c20..cc23bb2 100644
--- a/src/libimcv/imc/imc_os_info.c
+++ b/src/libimcv/imc/imc_os_info.c
@@ -283,23 +283,20 @@ typedef struct {
 
 } package_enumerator_t;
 
-/**
- * Implementation of package_enumerator.destroy.
- */
-static void package_enumerator_destroy(package_enumerator_t *this)
+METHOD(enumerator_t, package_enumerator_destroy, void,
+	package_enumerator_t *this)
 {
 	pclose(this->file);
 	free(this);
 }
 
-/**
- * Implementation of package_enumerator.enumerate
- */
-static bool package_enumerator_enumerate(package_enumerator_t *this, ...)
+METHOD(enumerator_t, package_enumerator_enumerate, bool,
+	package_enumerator_t *this, va_list args)
 {
 	chunk_t *name, *version;
 	u_char *pos;
-	va_list args;
+
+	VA_ARGS_VGET(args, name, version);
 
 	while (TRUE)
 	{
@@ -319,23 +316,16 @@ static bool package_enumerator_enumerate(package_enumerator_t *this, ...)
 		{
 			continue;
 		}
-		va_start(args, this);
-
-		name = va_arg(args, chunk_t*);
 		name->ptr = pos;
 		pos = strchr(pos, '\t');
 		if (!pos)
 		{
-			va_end(args);
 			return FALSE;
 		}
 		name->len = pos++ - name->ptr;
 
-		version = va_arg(args, chunk_t*);
 		version->ptr = pos;
 		version->len = strlen(pos) - 1;
-
-		va_end(args);
 		return TRUE;
 	}
 }
@@ -354,7 +344,7 @@ METHOD(imc_os_info_t, create_package_enumerator, enumerator_t*,
 		return NULL;
 	}
 
-	/* Open a pipe stream for reading the output of the dpkg-query commmand */
+	/* Open a pipe stream for reading the output of the dpkg-query command */
 	file = popen(command, "r");
 	if (!file)
 	{
@@ -362,12 +352,14 @@ METHOD(imc_os_info_t, create_package_enumerator, enumerator_t*,
 		return NULL;
 	}
 
-	/* Create a package enumerator instance */
-	enumerator = malloc_thing(package_enumerator_t);
-	enumerator->public.enumerate = (void*)package_enumerator_enumerate;
-	enumerator->public.destroy = (void*)package_enumerator_destroy;
-	enumerator->file = file;
-
+	INIT(enumerator,
+		.public = {
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _package_enumerator_enumerate,
+			.destroy = _package_enumerator_destroy,
+		},
+		.file = file,
+	);
 	return (enumerator_t*)enumerator;
 }
 
diff --git a/src/libimcv/imv/imv_agent.c b/src/libimcv/imv/imv_agent.c
index d050862..e96faa7 100644
--- a/src/libimcv/imv/imv_agent.c
+++ b/src/libimcv/imv/imv_agent.c
@@ -626,22 +626,13 @@ typedef struct {
 
 } language_enumerator_t;
 
-/**
- * Implementation of language_enumerator.destroy.
- */
-static void language_enumerator_destroy(language_enumerator_t *this)
-{
-	free(this);
-}
-
-/**
- * Implementation of language_enumerator.enumerate
- */
-static bool language_enumerator_enumerate(language_enumerator_t *this, ...)
+METHOD(enumerator_t, language_enumerator_enumerate, bool,
+	language_enumerator_t *this, va_list args)
 {
 	char *pos, *cur_lang, **lang;
 	TNC_UInt32 len;
-	va_list args;
+
+	VA_ARGS_VGET(args, lang);
 
 	if (!this->lang_len)
 	{
@@ -676,11 +667,7 @@ static bool language_enumerator_enumerate(language_enumerator_t *this, ...)
 	}
 	cur_lang[len] = '\0';
 
-	va_start(args, this);
-	lang = va_arg(args, char**);
 	*lang = cur_lang;
-	va_end(args);
-
 	return TRUE;
 }
 
@@ -689,10 +676,13 @@ METHOD(imv_agent_t, create_language_enumerator, enumerator_t*,
 {
 	language_enumerator_t *e;
 
-	/* Create a language enumerator instance */
-	e = malloc_thing(language_enumerator_t);
-	e->public.enumerate = (void*)language_enumerator_enumerate;
-	e->public.destroy = (void*)language_enumerator_destroy;
+	INIT(e,
+		.public = {
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _language_enumerator_enumerate,
+			.destroy = (void*)free,
+		},
+	);
 
 	if (!this->get_attribute ||
 		!this->get_attribute(this->id, state->get_connection_id(state),
diff --git a/src/libimcv/ita/ita_attr_settings.c b/src/libimcv/ita/ita_attr_settings.c
index c7c968a..b090778 100644
--- a/src/libimcv/ita/ita_attr_settings.c
+++ b/src/libimcv/ita/ita_attr_settings.c
@@ -262,22 +262,29 @@ METHOD(ita_attr_settings_t, add, void,
 	this->list->insert_last(this->list, entry);
 }
 
-/**
- * Enumerate name/value pairs
- */
-static bool entry_filter(void *null, entry_t **entry, char **name,
-						 void *i2, chunk_t *value)
+CALLBACK(entry_filter, bool,
+	void *null, enumerator_t *orig, va_list args)
 {
-	*name = (*entry)->name;
-	*value = (*entry)->value;
-	return TRUE;
+	entry_t *entry;
+	chunk_t *value;
+	char **name;
+
+	VA_ARGS_VGET(args, name, value);
+
+	while (orig->enumerate(orig, &entry))
+	{
+		*name = entry->name;
+		*value = entry->value;
+		return TRUE;
+	}
+	return FALSE;
 }
 
 METHOD(ita_attr_settings_t, create_enumerator, enumerator_t*,
 	private_ita_attr_settings_t *this)
 {
 	return enumerator_create_filter(this->list->create_enumerator(this->list),
-								   (void*)entry_filter, NULL, NULL);
+									entry_filter, NULL, NULL);
 }
 
 /**
diff --git a/src/libimcv/plugins/imc_attestation/Makefile.in b/src/libimcv/plugins/imc_attestation/Makefile.in
index 0475cee..d67050f 100644
--- a/src/libimcv/plugins/imc_attestation/Makefile.in
+++ b/src/libimcv/plugins/imc_attestation/Makefile.in
@@ -356,6 +356,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -378,6 +379,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libimcv/plugins/imc_hcd/Makefile.in b/src/libimcv/plugins/imc_hcd/Makefile.in
index e2f1dc5..981af39 100644
--- a/src/libimcv/plugins/imc_hcd/Makefile.in
+++ b/src/libimcv/plugins/imc_hcd/Makefile.in
@@ -353,6 +353,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -375,6 +376,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libimcv/plugins/imc_os/Makefile.in b/src/libimcv/plugins/imc_os/Makefile.in
index 0fa0d19..aa0c49a 100644
--- a/src/libimcv/plugins/imc_os/Makefile.in
+++ b/src/libimcv/plugins/imc_os/Makefile.in
@@ -353,6 +353,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -375,6 +376,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libimcv/plugins/imc_scanner/Makefile.in b/src/libimcv/plugins/imc_scanner/Makefile.in
index 1b776b2..63b4315 100644
--- a/src/libimcv/plugins/imc_scanner/Makefile.in
+++ b/src/libimcv/plugins/imc_scanner/Makefile.in
@@ -354,6 +354,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -376,6 +377,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libimcv/plugins/imc_scanner/imc_scanner.c b/src/libimcv/plugins/imc_scanner/imc_scanner.c
index bf2479c..93ed427 100644
--- a/src/libimcv/plugins/imc_scanner/imc_scanner.c
+++ b/src/libimcv/plugins/imc_scanner/imc_scanner.c
@@ -116,7 +116,7 @@ static bool do_netstat(ietf_attr_port_filter_t *attr)
 	const char loopback_v4[] = "127.0.0.1";
 	const char loopback_v6[] = "::1";
 
-	/* Open a pipe stream for reading the output of the netstat commmand */
+	/* Open a pipe stream for reading the output of the netstat command */
 	file = popen("/bin/netstat -n -l -p -4 -6 --inet", "r");
 	if (!file)
 	{
diff --git a/src/libimcv/plugins/imc_swid/Makefile.in b/src/libimcv/plugins/imc_swid/Makefile.in
index 13d1924..02bc2bf 100644
--- a/src/libimcv/plugins/imc_swid/Makefile.in
+++ b/src/libimcv/plugins/imc_swid/Makefile.in
@@ -356,6 +356,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -378,6 +379,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libimcv/plugins/imc_test/Makefile.in b/src/libimcv/plugins/imc_test/Makefile.in
index 7a4149e..93c0748 100644
--- a/src/libimcv/plugins/imc_test/Makefile.in
+++ b/src/libimcv/plugins/imc_test/Makefile.in
@@ -353,6 +353,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -375,6 +376,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libimcv/plugins/imc_test/imc_test_state.h b/src/libimcv/plugins/imc_test/imc_test_state.h
index 5f9ee25..365caff 100644
--- a/src/libimcv/plugins/imc_test/imc_test_state.h
+++ b/src/libimcv/plugins/imc_test/imc_test_state.h
@@ -42,14 +42,14 @@ struct imc_test_state_t {
 	/**
 	 * get the command to send to IMV
 	 *
-	 * @return				commmand to send to IMV
+	 * @return				command to send to IMV
 	 */
 	char* (*get_command)(imc_test_state_t *this);
 
 	/**
 	 * set the command to send to IMV
 	 *
-	 * @param command		commmand to send to IMV
+	 * @param command		command to send to IMV
 	 */
 	void (*set_command)(imc_test_state_t *this, char *command);
 
diff --git a/src/libimcv/plugins/imv_attestation/Makefile.in b/src/libimcv/plugins/imv_attestation/Makefile.in
index 9782757..02bd5f5 100644
--- a/src/libimcv/plugins/imv_attestation/Makefile.in
+++ b/src/libimcv/plugins/imv_attestation/Makefile.in
@@ -367,6 +367,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -389,6 +390,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libimcv/plugins/imv_attestation/imv_attestation_state.c b/src/libimcv/plugins/imv_attestation/imv_attestation_state.c
index 1c3b91a..d639407 100644
--- a/src/libimcv/plugins/imv_attestation/imv_attestation_state.c
+++ b/src/libimcv/plugins/imv_attestation/imv_attestation_state.c
@@ -418,24 +418,24 @@ METHOD(imv_attestation_state_t, create_component, pts_component_t*,
 	}
 }
 
-/**
- * Enumerate file measurement entries
- */
-static bool entry_filter(void *null, func_comp_t **entry, uint8_t *flags,
-						 void *i2, uint32_t *depth,
-						 void *i3, pts_comp_func_name_t **comp_name)
+CALLBACK(entry_filter, bool,
+	void *null, enumerator_t *orig, va_list args)
 {
-	pts_component_t *comp;
-	pts_comp_func_name_t *name;
-
-	comp = (*entry)->comp;
-	name = (*entry)->name;
+	func_comp_t *entry;
+	pts_comp_func_name_t **comp_name;
+	uint32_t *depth;
+	uint8_t *flags;
 
-	*flags = comp->get_evidence_flags(comp);
-	*depth = comp->get_depth(comp);
-	*comp_name = name;
+	VA_ARGS_VGET(args, flags, depth, comp_name);
 
-	return TRUE;
+	if (orig->enumerate(orig, &entry))
+	{
+		*flags = entry->comp->get_evidence_flags(entry->comp);
+		*depth = entry->comp->get_depth(entry->comp);
+		*comp_name = entry->name;
+		return TRUE;
+	}
+	return FALSE;
 }
 
 METHOD(imv_attestation_state_t, create_component_enumerator, enumerator_t*,
@@ -443,7 +443,7 @@ METHOD(imv_attestation_state_t, create_component_enumerator, enumerator_t*,
 {
 	return enumerator_create_filter(
 				this->components->create_enumerator(this->components),
-				(void*)entry_filter, NULL, NULL);
+				entry_filter, NULL, NULL);
 }
 
 METHOD(imv_attestation_state_t, get_component, pts_component_t*,
diff --git a/src/libimcv/plugins/imv_hcd/Makefile.in b/src/libimcv/plugins/imv_hcd/Makefile.in
index 62bd827..b19cb4a 100644
--- a/src/libimcv/plugins/imv_hcd/Makefile.in
+++ b/src/libimcv/plugins/imv_hcd/Makefile.in
@@ -353,6 +353,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -375,6 +376,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libimcv/plugins/imv_os/Makefile.in b/src/libimcv/plugins/imv_os/Makefile.in
index efefdc8..f2804f3 100644
--- a/src/libimcv/plugins/imv_os/Makefile.in
+++ b/src/libimcv/plugins/imv_os/Makefile.in
@@ -361,6 +361,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -383,6 +384,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libimcv/plugins/imv_scanner/Makefile.in b/src/libimcv/plugins/imv_scanner/Makefile.in
index 535e28f..6cc107e 100644
--- a/src/libimcv/plugins/imv_scanner/Makefile.in
+++ b/src/libimcv/plugins/imv_scanner/Makefile.in
@@ -355,6 +355,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -377,6 +378,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libimcv/plugins/imv_swid/Makefile.in b/src/libimcv/plugins/imv_swid/Makefile.in
index 1150f12..3560752 100644
--- a/src/libimcv/plugins/imv_swid/Makefile.in
+++ b/src/libimcv/plugins/imv_swid/Makefile.in
@@ -356,6 +356,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -378,6 +379,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libimcv/plugins/imv_swid/imv_swid_rest.c b/src/libimcv/plugins/imv_swid/imv_swid_rest.c
index 143b0b2..0fe96ed 100644
--- a/src/libimcv/plugins/imv_swid/imv_swid_rest.c
+++ b/src/libimcv/plugins/imv_swid/imv_swid_rest.c
@@ -70,27 +70,29 @@ METHOD(imv_swid_rest_t, post, status_t,
 				FETCH_END);
 	free(uri);
 
-	if (status == SUCCESS)
+	if (status != SUCCESS)
 	{
-		return 	SUCCESS;
-	}
-
-	if (code != HTTP_STATUS_CODE_PRECONDITION_FAILED || !response.ptr)
-	{
-		DBG2(DBG_IMV, "REST http request failed with status code: %d", code);
-		return FAILED;
-	}
-
-	if (jresponse)
-	{
-		/* Parse HTTP response into a JSON object */
-		tokener = json_tokener_new();
-		*jresponse = json_tokener_parse_ex(tokener, response.ptr, response.len);
-		json_tokener_free(tokener);
+		if (code != HTTP_STATUS_CODE_PRECONDITION_FAILED || !response.ptr)
+		{
+			DBG2(DBG_IMV, "REST http request failed with status code: %d", code);
+			status = FAILED;
+		}
+		else
+		{
+			if (jresponse)
+			{
+				/* Parse HTTP response into a JSON object */
+				tokener = json_tokener_new();
+				*jresponse = json_tokener_parse_ex(tokener, response.ptr,
+															response.len);
+				json_tokener_free(tokener);
+			}
+			status = NEED_MORE;
+		}
 	}
 	free(response.ptr);
 
-	return NEED_MORE;
+	return status;
 }
 
 METHOD(imv_swid_rest_t, destroy, void,
diff --git a/src/libimcv/plugins/imv_test/Makefile.in b/src/libimcv/plugins/imv_test/Makefile.in
index 055d6fd..9aebfef 100644
--- a/src/libimcv/plugins/imv_test/Makefile.in
+++ b/src/libimcv/plugins/imv_test/Makefile.in
@@ -354,6 +354,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -376,6 +377,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libimcv/plugins/imv_test/imv_test_agent.c b/src/libimcv/plugins/imv_test/imv_test_agent.c
index 5e4b486..fc14359 100644
--- a/src/libimcv/plugins/imv_test/imv_test_agent.c
+++ b/src/libimcv/plugins/imv_test/imv_test_agent.c
@@ -188,6 +188,8 @@ static TNC_Result receive_msg(private_imv_test_agent_t *this, imv_state_t *state
 	if (retry)
 	{
 		test_state->set_rounds(test_state, rounds);
+		out_msg->destroy(out_msg);
+
 		return this->agent->request_handshake_retry(
 									this->agent->get_id(this->agent),
 									state->get_connection_id(state),
diff --git a/src/libimcv/pts/pts_file_meas.c b/src/libimcv/pts/pts_file_meas.c
index 6cfb86c..92f513a 100644
--- a/src/libimcv/pts/pts_file_meas.c
+++ b/src/libimcv/pts/pts_file_meas.c
@@ -94,22 +94,29 @@ METHOD(pts_file_meas_t, add, void,
 	this->list->insert_last(this->list, entry);
 }
 
-/**
- * Enumerate file measurement entries
- */
-static bool entry_filter(void *null, entry_t **entry, char **filename,
-						 void *i2, chunk_t *measurement)
+CALLBACK(entry_filter, bool,
+	void *null, enumerator_t *orig, va_list args)
 {
-	*filename = (*entry)->filename;
-	*measurement = (*entry)->measurement;
-	return TRUE;
+	entry_t *entry;
+	chunk_t *measurement;
+	char **filename;
+
+	VA_ARGS_VGET(args, filename, measurement);
+
+	if (orig->enumerate(orig, &entry))
+	{
+		*filename = entry->filename;
+		*measurement = entry->measurement;
+		return TRUE;
+	}
+	return FALSE;
 }
 
 METHOD(pts_file_meas_t, create_enumerator, enumerator_t*,
 	private_pts_file_meas_t *this)
 {
 	return enumerator_create_filter(this->list->create_enumerator(this->list),
-								   (void*)entry_filter, NULL, NULL);
+									entry_filter, NULL, NULL);
 }
 
 METHOD(pts_file_meas_t, check, bool,
diff --git a/src/libimcv/pts/pts_pcr.c b/src/libimcv/pts/pts_pcr.c
index d514532..9f098c0 100644
--- a/src/libimcv/pts/pts_pcr.c
+++ b/src/libimcv/pts/pts_pcr.c
@@ -111,17 +111,12 @@ typedef struct {
 	private_pts_pcr_t *pcrs;
 } pcr_enumerator_t;
 
-/**
- * Implementation of enumerator.enumerate
- */
-static bool pcr_enumerator_enumerate(pcr_enumerator_t *this, ...)
+METHOD(enumerator_t, pcr_enumerator_enumerate, bool,
+	pcr_enumerator_t *this, va_list args)
 {
-	uint32_t *pcr, i, f;
-	va_list args;
+	uint32_t i, f, *pcr;
 
-	va_start(args, this);
-	pcr = va_arg(args, uint32_t*);
-	va_end(args);
+	VA_ARGS_VGET(args, pcr);
 
 	while (this->pcr <= this->pcrs->pcr_max)
 	{
@@ -148,7 +143,8 @@ METHOD(pts_pcr_t, create_enumerator, enumerator_t*,
 
 	INIT(enumerator,
 		.public = {
-			.enumerate = (void*)pcr_enumerator_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _pcr_enumerator_enumerate,
 			.destroy = (void*)free,
 		},
 		.pcrs = this,
diff --git a/src/libimcv/tcg/pts/tcg_pts_attr_req_func_comp_evid.c b/src/libimcv/tcg/pts/tcg_pts_attr_req_func_comp_evid.c
index da21003..0d84867 100644
--- a/src/libimcv/tcg/pts/tcg_pts_attr_req_func_comp_evid.c
+++ b/src/libimcv/tcg/pts/tcg_pts_attr_req_func_comp_evid.c
@@ -115,18 +115,24 @@ struct entry_t {
 	pts_comp_func_name_t *name;
 };
 
-/**
- * Enumerate functional component entries
- */
-static bool entry_filter(void *null, entry_t **entry, uint8_t *flags,
-						 void *i2, uint32_t *depth, void *i3,
-						 pts_comp_func_name_t **name)
+CALLBACK(entry_filter, bool,
+	void *null, enumerator_t *orig, va_list args)
 {
-	*flags = (*entry)->flags;
-	*depth = (*entry)->depth;
-	*name  = (*entry)->name;
+	entry_t *entry;
+	pts_comp_func_name_t **name;
+	uint32_t *depth;
+	uint8_t *flags;
 
-	return TRUE;
+	VA_ARGS_VGET(args, flags, depth, name);
+
+	if (orig->enumerate(orig, &entry))
+	{
+		*flags = entry->flags;
+		*depth = entry->depth;
+		*name  = entry->name;
+		return TRUE;
+	}
+	return FALSE;
 }
 
 /**
@@ -318,7 +324,7 @@ METHOD(tcg_pts_attr_req_func_comp_evid_t, create_enumerator, enumerator_t*,
 	private_tcg_pts_attr_req_func_comp_evid_t *this)
 {
 	return enumerator_create_filter(this->list->create_enumerator(this->list),
-								   (void*)entry_filter, NULL, NULL);
+									entry_filter, NULL, NULL);
 }
 
 /**
diff --git a/src/libimcv/tcg/pts/tcg_pts_attr_simple_comp_evid.c b/src/libimcv/tcg/pts/tcg_pts_attr_simple_comp_evid.c
index c249ca1..9438fa0 100644
--- a/src/libimcv/tcg/pts/tcg_pts_attr_simple_comp_evid.c
+++ b/src/libimcv/tcg/pts/tcg_pts_attr_simple_comp_evid.c
@@ -263,13 +263,15 @@ bool measurement_time_from_utc(time_t *measurement_time, chunk_t utc_time)
 {
 	int tm_year, tm_mon, tm_day, tm_days, tm_hour, tm_min, tm_sec, tm_secs;
 	int tm_leap_4, tm_leap_100, tm_leap_400, tm_leap;
+	char buf[BUF_LEN];
 
 	if (memeq(utc_undefined_time_str, utc_time.ptr, utc_time.len))
 	{
 		*measurement_time = 0;
 		return TRUE;
 	}
-	if (sscanf(utc_time.ptr, "%4d-%2d-%2dT%2d:%2d:%2dZ",
+	snprintf(buf, sizeof(buf), "%.*s", (int)utc_time.len, utc_time.ptr);
+	if (sscanf(buf, "%4d-%2d-%2dT%2d:%2d:%2dZ",
 		&tm_year, &tm_mon, &tm_day, &tm_hour, &tm_min, &tm_sec) != 6)
 	{
 		return FALSE;
diff --git a/src/libipsec/Makefile.in b/src/libipsec/Makefile.in
index 7d514fd..55d1d58 100644
--- a/src/libipsec/Makefile.in
+++ b/src/libipsec/Makefile.in
@@ -398,6 +398,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -420,6 +421,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libipsec/ipsec_sa_mgr.c b/src/libipsec/ipsec_sa_mgr.c
index a1fa23e..957d930 100644
--- a/src/libipsec/ipsec_sa_mgr.c
+++ b/src/libipsec/ipsec_sa_mgr.c
@@ -224,42 +224,60 @@ static void flush_entries(private_ipsec_sa_mgr_t *this)
 	enumerator->destroy(enumerator);
 }
 
-/*
- * Different match functions to find SAs in the linked list
- */
-static bool match_entry_by_ptr(ipsec_sa_entry_t *item, ipsec_sa_entry_t *entry)
+CALLBACK(match_entry_by_sa_ptr, bool,
+	ipsec_sa_entry_t *item, va_list args)
 {
-	return item == entry;
-}
+	ipsec_sa_t *sa;
 
-static bool match_entry_by_sa_ptr(ipsec_sa_entry_t *item, ipsec_sa_t *sa)
-{
+	VA_ARGS_VGET(args, sa);
 	return item->sa == sa;
 }
 
-static bool match_entry_by_spi_inbound(ipsec_sa_entry_t *item, uint32_t *spi,
-									   bool *inbound)
+CALLBACK(match_entry_by_spi_inbound, bool,
+	ipsec_sa_entry_t *item, va_list args)
 {
-	return item->sa->get_spi(item->sa) == *spi &&
-		   item->sa->is_inbound(item->sa) == *inbound;
+	uint32_t spi;
+	int inbound;
+
+	VA_ARGS_VGET(args, spi, inbound);
+	return item->sa->get_spi(item->sa) == spi &&
+		   item->sa->is_inbound(item->sa) == inbound;
 }
 
-static bool match_entry_by_spi_src_dst(ipsec_sa_entry_t *item, uint32_t *spi,
+static bool match_entry_by_spi_src_dst(ipsec_sa_entry_t *item, uint32_t spi,
 									   host_t *src, host_t *dst)
 {
-	return item->sa->match_by_spi_src_dst(item->sa, *spi, src, dst);
+	return item->sa->match_by_spi_src_dst(item->sa, spi, src, dst);
 }
 
-static bool match_entry_by_reqid_inbound(ipsec_sa_entry_t *item,
-										 uint32_t *reqid, bool *inbound)
+CALLBACK(match_entry_by_spi_src_dst_cb, bool,
+	ipsec_sa_entry_t *item, va_list args)
 {
-	return item->sa->match_by_reqid(item->sa, *reqid, *inbound);
+	host_t *src, *dst;
+	uint32_t spi;
+
+	VA_ARGS_VGET(args, spi, src, dst);
+	return match_entry_by_spi_src_dst(item, spi, src, dst);
+}
+
+CALLBACK(match_entry_by_reqid_inbound, bool,
+	ipsec_sa_entry_t *item, va_list args)
+{
+	uint32_t reqid;
+	int inbound;
+
+	VA_ARGS_VGET(args, reqid, inbound);
+	return item->sa->match_by_reqid(item->sa, reqid, inbound);
 }
 
-static bool match_entry_by_spi_dst(ipsec_sa_entry_t *item, uint32_t *spi,
-								   host_t *dst)
+CALLBACK(match_entry_by_spi_dst, bool,
+	ipsec_sa_entry_t *item, va_list args)
 {
-	return item->sa->match_by_spi_dst(item->sa, *spi, dst);
+	host_t *dst;
+	uint32_t spi;
+
+	VA_ARGS_VGET(args, spi, dst);
+	return item->sa->match_by_spi_dst(item->sa, spi, dst);
 }
 
 /**
@@ -296,8 +314,7 @@ static job_requeue_t sa_expired(ipsec_sa_expired_t *expired)
 	private_ipsec_sa_mgr_t *this = expired->manager;
 
 	this->mutex->lock(this->mutex);
-	if (this->sas->find_first(this->sas, (void*)match_entry_by_ptr,
-							  NULL, expired->entry) == SUCCESS)
+	if (this->sas->find_first(this->sas, NULL, (void**)&expired->entry))
 	{
 		uint32_t hard_offset;
 
@@ -383,8 +400,8 @@ static bool allocate_spi(private_ipsec_sa_mgr_t *this, uint32_t spi)
 	uint32_t *spi_alloc;
 
 	if (this->allocated_spis->get(this->allocated_spis, &spi) ||
-		this->sas->find_first(this->sas, (void*)match_entry_by_spi_inbound,
-							  NULL, &spi, TRUE) == SUCCESS)
+		this->sas->find_first(this->sas, match_entry_by_spi_inbound,
+							  NULL, spi, TRUE))
 	{
 		return FALSE;
 	}
@@ -484,8 +501,8 @@ METHOD(ipsec_sa_mgr_t, add_sa, status_t,
 		free(spi_alloc);
 	}
 
-	if (this->sas->find_first(this->sas, (void*)match_entry_by_spi_src_dst,
-							  NULL, &spi, src, dst) == SUCCESS)
+	if (this->sas->find_first(this->sas, match_entry_by_spi_src_dst_cb, NULL,
+							  spi, src, dst))
 	{
 		this->mutex->unlock(this->mutex);
 		DBG1(DBG_ESP, "failed to install SAD entry: already installed");
@@ -519,8 +536,8 @@ METHOD(ipsec_sa_mgr_t, update_sa, status_t,
 	}
 
 	this->mutex->lock(this->mutex);
-	if (this->sas->find_first(this->sas, (void*)match_entry_by_spi_src_dst,
-							 (void**)&entry, &spi, src, dst) == SUCCESS &&
+	if (this->sas->find_first(this->sas, match_entry_by_spi_src_dst_cb,
+							 (void**)&entry, spi, src, dst) &&
 		wait_for_entry(this, entry))
 	{
 		entry->sa->set_source(entry->sa, new_src);
@@ -547,8 +564,8 @@ METHOD(ipsec_sa_mgr_t, query_sa, status_t,
 	ipsec_sa_entry_t *entry = NULL;
 
 	this->mutex->lock(this->mutex);
-	if (this->sas->find_first(this->sas, (void*)match_entry_by_spi_src_dst,
-							 (void**)&entry, &spi, src, dst) == SUCCESS &&
+	if (this->sas->find_first(this->sas, match_entry_by_spi_src_dst_cb,
+							 (void**)&entry, spi, src, dst) &&
 		wait_for_entry(this, entry))
 	{
 		entry->sa->get_usestats(entry->sa, bytes, packets, time);
@@ -572,7 +589,7 @@ METHOD(ipsec_sa_mgr_t, del_sa, status_t,
 	enumerator = this->sas->create_enumerator(this->sas);
 	while (enumerator->enumerate(enumerator, (void**)&current))
 	{
-		if (match_entry_by_spi_src_dst(current, &spi, src, dst))
+		if (match_entry_by_spi_src_dst(current, spi, src, dst))
 		{
 			if (wait_remove_entry(this, current))
 			{
@@ -602,8 +619,8 @@ METHOD(ipsec_sa_mgr_t, checkout_by_reqid, ipsec_sa_t*,
 	ipsec_sa_t *sa = NULL;
 
 	this->mutex->lock(this->mutex);
-	if (this->sas->find_first(this->sas, (void*)match_entry_by_reqid_inbound,
-							 (void**)&entry, &reqid, &inbound) == SUCCESS &&
+	if (this->sas->find_first(this->sas, match_entry_by_reqid_inbound,
+							 (void**)&entry, reqid, inbound) &&
 		wait_for_entry(this, entry))
 	{
 		sa = entry->sa;
@@ -619,8 +636,8 @@ METHOD(ipsec_sa_mgr_t, checkout_by_spi, ipsec_sa_t*,
 	ipsec_sa_t *sa = NULL;
 
 	this->mutex->lock(this->mutex);
-	if (this->sas->find_first(this->sas, (void*)match_entry_by_spi_dst,
-							 (void**)&entry, &spi, dst) == SUCCESS &&
+	if (this->sas->find_first(this->sas, match_entry_by_spi_dst,
+							 (void**)&entry, spi, dst) &&
 		wait_for_entry(this, entry))
 	{
 		sa = entry->sa;
@@ -635,8 +652,8 @@ METHOD(ipsec_sa_mgr_t, checkin, void,
 	ipsec_sa_entry_t *entry;
 
 	this->mutex->lock(this->mutex);
-	if (this->sas->find_first(this->sas, (void*)match_entry_by_sa_ptr,
-							 (void**)&entry, sa) == SUCCESS)
+	if (this->sas->find_first(this->sas, match_entry_by_sa_ptr,
+							 (void**)&entry, sa))
 	{
 		if (entry->locked)
 		{
diff --git a/src/libipsec/tests/Makefile.in b/src/libipsec/tests/Makefile.in
index e81d6fc..b1fdea4 100644
--- a/src/libipsec/tests/Makefile.in
+++ b/src/libipsec/tests/Makefile.in
@@ -351,6 +351,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -373,6 +374,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libpttls/Makefile.in b/src/libpttls/Makefile.in
index fd3e763..803d687 100644
--- a/src/libpttls/Makefile.in
+++ b/src/libpttls/Makefile.in
@@ -356,6 +356,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -378,6 +379,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libpttls/sasl/sasl_mechanism.c b/src/libpttls/sasl/sasl_mechanism.c
index 05a02e5..4e54de3 100644
--- a/src/libpttls/sasl/sasl_mechanism.c
+++ b/src/libpttls/sasl/sasl_mechanism.c
@@ -59,8 +59,11 @@ typedef struct {
 } mech_enumerator_t;
 
 METHOD(enumerator_t, mech_enumerate, bool,
-	mech_enumerator_t *this, char **name)
+	mech_enumerator_t *this, va_list args)
 {
+	char **name;
+
+	VA_ARGS_VGET(args, name);
 	while (this->i < countof(mechs))
 	{
 		if (mechs[this->i].server == this->server)
@@ -83,7 +86,8 @@ enumerator_t* sasl_mechanism_create_enumerator(bool server)
 
 	INIT(enumerator,
 		.public = {
-			.enumerate = (void*)_mech_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _mech_enumerate,
 			.destroy = (void*)free,
 		},
 		.server = server,
diff --git a/src/libradius/Makefile.in b/src/libradius/Makefile.in
index 8f91275..9e7b737 100644
--- a/src/libradius/Makefile.in
+++ b/src/libradius/Makefile.in
@@ -351,6 +351,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -373,6 +374,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libradius/radius_message.c b/src/libradius/radius_message.c
index 9705d3b..51135fb 100644
--- a/src/libradius/radius_message.c
+++ b/src/libradius/radius_message.c
@@ -244,8 +244,12 @@ typedef struct {
 } attribute_enumerator_t;
 
 METHOD(enumerator_t, attribute_enumerate, bool,
-	attribute_enumerator_t *this, int *type, chunk_t *data)
+	attribute_enumerator_t *this, va_list args)
 {
+	chunk_t *data;
+	int *type;
+
+	VA_ARGS_VGET(args, type, data);
 	if (this->left == 0)
 	{
 		return FALSE;
@@ -275,7 +279,8 @@ METHOD(radius_message_t, create_enumerator, enumerator_t*,
 	}
 	INIT(e,
 		.public = {
-			.enumerate = (void*)_attribute_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _attribute_enumerate,
 			.destroy = (void*)free,
 		},
 		.next = (rattr_t*)this->msg->attributes,
@@ -299,12 +304,14 @@ typedef struct {
 } vendor_enumerator_t;
 
 METHOD(enumerator_t, vendor_enumerate, bool,
-	vendor_enumerator_t *this, int *vendor, int *type, chunk_t *data)
+	vendor_enumerator_t *this, va_list args)
 {
-	chunk_t inner_data;
-	int inner_type;
+	chunk_t inner_data, *data;
+	int inner_type, *vendor, *type;
 	uint8_t type8, len;
 
+	VA_ARGS_VGET(args, vendor, type, data);
+
 	while (TRUE)
 	{
 		if (this->reader)
@@ -354,7 +361,8 @@ METHOD(radius_message_t, create_vendor_enumerator, enumerator_t*,
 
 	INIT(e,
 		.public = {
-			.enumerate = (void*)_vendor_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _vendor_enumerate,
 			.destroy = _vendor_destroy,
 		},
 		.inner = create_enumerator(this),
diff --git a/src/libsimaka/Makefile.in b/src/libsimaka/Makefile.in
index 6af66e3..6ecbaec 100644
--- a/src/libsimaka/Makefile.in
+++ b/src/libsimaka/Makefile.in
@@ -354,6 +354,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -376,6 +377,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libsimaka/simaka_message.c b/src/libsimaka/simaka_message.c
index 234d7ef..6827c17 100644
--- a/src/libsimaka/simaka_message.c
+++ b/src/libsimaka/simaka_message.c
@@ -222,17 +222,22 @@ METHOD(simaka_message_t, get_type, eap_type_t,
 	return this->hdr->type;
 }
 
-/**
- * convert attr_t to type and data enumeration
- */
-static bool attr_enum_filter(void *null, attr_t **in, simaka_attribute_t *type,
-							 void *dummy, chunk_t *data)
+CALLBACK(attr_enum_filter, bool,
+	void *null, enumerator_t *orig, va_list args)
 {
-	attr_t *attr = *in;
+	attr_t *attr;
+	simaka_attribute_t *type;
+	chunk_t *data;
 
-	*type = attr->type;
-	*data = chunk_create(attr->data, attr->len);
-	return TRUE;
+	VA_ARGS_VGET(args, type, data);
+
+	if (orig->enumerate(orig, &attr))
+	{
+		*type = attr->type;
+		*data = chunk_create(attr->data, attr->len);
+		return TRUE;
+	}
+	return FALSE;
 }
 
 METHOD(simaka_message_t, create_attribute_enumerator, enumerator_t*,
@@ -240,7 +245,7 @@ METHOD(simaka_message_t, create_attribute_enumerator, enumerator_t*,
 {
 	return enumerator_create_filter(
 						this->attributes->create_enumerator(this->attributes),
-						(void*)attr_enum_filter, NULL, NULL);
+						attr_enum_filter, NULL, NULL);
 }
 
 METHOD(simaka_message_t, add_attribute, void,
diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am
index f6d6f54..b4d8452 100644
--- a/src/libstrongswan/Makefile.am
+++ b/src/libstrongswan/Makefile.am
@@ -195,6 +195,7 @@ endif
 EXTRA_DIST = \
 asn1/oid.txt asn1/oid.pl \
 crypto/proposal/proposal_keywords_static.txt \
+plugins/plugin_constructors.py \
 Android.mk
 
 BUILT_SOURCES = \
@@ -220,6 +221,15 @@ $(srcdir)/crypto/proposal/proposal_keywords_static.c:	$(srcdir)/crypto/proposal/
 		$(GPERF) -N proposal_get_token_static -m 10 -C -G -c -t -D < \
 												$(srcdir)/crypto/proposal/proposal_keywords_static.txt > $@
 
+if STATIC_PLUGIN_CONSTRUCTORS
+BUILT_SOURCES += $(srcdir)/plugin_constructors.c
+CLEANFILES = $(srcdir)/plugin_constructors.c
+
+$(srcdir)/plugin_constructors.c: $(srcdir)/plugins/plugin_constructors.py
+		$(AM_V_GEN) \
+		$(PYTHON) $(srcdir)/plugins/plugin_constructors.py ${s_plugins} > $@
+endif
+
 if MONOLITHIC
 SUBDIRS =
 else
diff --git a/src/libstrongswan/Makefile.in b/src/libstrongswan/Makefile.in
index 99bb115..9b1c26b 100644
--- a/src/libstrongswan/Makefile.in
+++ b/src/libstrongswan/Makefile.in
@@ -123,128 +123,129 @@ host_triplet = @host@
 @USE_BUILTIN_PRINTF_TRUE at am__append_15 = -lm
 @USE_BUILTIN_PRINTF_FALSE@@USE_VSTR_FALSE at am__append_16 = utils/printf_hook/printf_hook_glibc.c
 @USE_LIBCAP_TRUE at am__append_17 = -lcap
+ at STATIC_PLUGIN_CONSTRUCTORS_TRUE@am__append_18 = $(srcdir)/plugin_constructors.c
 
 # build libnttfft used by some plugins
 ######################################
- at USE_LIBNTTFFT_TRUE@am__append_18 = math/libnttfft
+ at USE_LIBNTTFFT_TRUE@am__append_19 = math/libnttfft
 
 # build plugins with their own Makefile
 #######################################
- at USE_AF_ALG_TRUE@am__append_19 = plugins/af_alg
- at MONOLITHIC_TRUE@@USE_AF_ALG_TRUE at am__append_20 = plugins/af_alg/libstrongswan-af-alg.la
- at USE_AES_TRUE@am__append_21 = plugins/aes
- at MONOLITHIC_TRUE@@USE_AES_TRUE at am__append_22 = plugins/aes/libstrongswan-aes.la
- at USE_DES_TRUE@am__append_23 = plugins/des
- at MONOLITHIC_TRUE@@USE_DES_TRUE at am__append_24 = plugins/des/libstrongswan-des.la
- at USE_BLOWFISH_TRUE@am__append_25 = plugins/blowfish
- at MONOLITHIC_TRUE@@USE_BLOWFISH_TRUE at am__append_26 = plugins/blowfish/libstrongswan-blowfish.la
- at USE_RC2_TRUE@am__append_27 = plugins/rc2
- at MONOLITHIC_TRUE@@USE_RC2_TRUE at am__append_28 = plugins/rc2/libstrongswan-rc2.la
- at USE_MD4_TRUE@am__append_29 = plugins/md4
- at MONOLITHIC_TRUE@@USE_MD4_TRUE at am__append_30 = plugins/md4/libstrongswan-md4.la
- at USE_MD5_TRUE@am__append_31 = plugins/md5
- at MONOLITHIC_TRUE@@USE_MD5_TRUE at am__append_32 = plugins/md5/libstrongswan-md5.la
- at USE_SHA1_TRUE@am__append_33 = plugins/sha1
- at MONOLITHIC_TRUE@@USE_SHA1_TRUE at am__append_34 = plugins/sha1/libstrongswan-sha1.la
- at USE_SHA2_TRUE@am__append_35 = plugins/sha2
- at MONOLITHIC_TRUE@@USE_SHA2_TRUE at am__append_36 = plugins/sha2/libstrongswan-sha2.la
- at USE_SHA3_TRUE@am__append_37 = plugins/sha3
- at MONOLITHIC_TRUE@@USE_SHA3_TRUE at am__append_38 = plugins/sha3/libstrongswan-sha3.la
- at USE_GMP_TRUE@am__append_39 = plugins/gmp
- at MONOLITHIC_TRUE@@USE_GMP_TRUE at am__append_40 = plugins/gmp/libstrongswan-gmp.la
- at USE_CURVE25519_TRUE@am__append_41 = plugins/curve25519
- at MONOLITHIC_TRUE@@USE_CURVE25519_TRUE at am__append_42 = plugins/curve25519/libstrongswan-curve25519.la
- at USE_RDRAND_TRUE@am__append_43 = plugins/rdrand
- at MONOLITHIC_TRUE@@USE_RDRAND_TRUE at am__append_44 = plugins/rdrand/libstrongswan-rdrand.la
- at USE_AESNI_TRUE@am__append_45 = plugins/aesni
- at MONOLITHIC_TRUE@@USE_AESNI_TRUE at am__append_46 = plugins/aesni/libstrongswan-aesni.la
- at USE_RANDOM_TRUE@am__append_47 = plugins/random
- at MONOLITHIC_TRUE@@USE_RANDOM_TRUE at am__append_48 = plugins/random/libstrongswan-random.la
- at USE_NONCE_TRUE@am__append_49 = plugins/nonce
- at MONOLITHIC_TRUE@@USE_NONCE_TRUE at am__append_50 = plugins/nonce/libstrongswan-nonce.la
- at USE_HMAC_TRUE@am__append_51 = plugins/hmac
- at MONOLITHIC_TRUE@@USE_HMAC_TRUE at am__append_52 = plugins/hmac/libstrongswan-hmac.la
- at USE_CMAC_TRUE@am__append_53 = plugins/cmac
- at MONOLITHIC_TRUE@@USE_CMAC_TRUE at am__append_54 = plugins/cmac/libstrongswan-cmac.la
- at USE_XCBC_TRUE@am__append_55 = plugins/xcbc
- at MONOLITHIC_TRUE@@USE_XCBC_TRUE at am__append_56 = plugins/xcbc/libstrongswan-xcbc.la
- at USE_X509_TRUE@am__append_57 = plugins/x509
- at MONOLITHIC_TRUE@@USE_X509_TRUE at am__append_58 = plugins/x509/libstrongswan-x509.la
- at USE_REVOCATION_TRUE@am__append_59 = plugins/revocation
- at MONOLITHIC_TRUE@@USE_REVOCATION_TRUE at am__append_60 = plugins/revocation/libstrongswan-revocation.la
- at USE_CONSTRAINTS_TRUE@am__append_61 = plugins/constraints
- at MONOLITHIC_TRUE@@USE_CONSTRAINTS_TRUE at am__append_62 = plugins/constraints/libstrongswan-constraints.la
- at USE_ACERT_TRUE@am__append_63 = plugins/acert
- at MONOLITHIC_TRUE@@USE_ACERT_TRUE at am__append_64 = plugins/acert/libstrongswan-acert.la
- at USE_PUBKEY_TRUE@am__append_65 = plugins/pubkey
- at MONOLITHIC_TRUE@@USE_PUBKEY_TRUE at am__append_66 = plugins/pubkey/libstrongswan-pubkey.la
- at USE_PKCS1_TRUE@am__append_67 = plugins/pkcs1
- at MONOLITHIC_TRUE@@USE_PKCS1_TRUE at am__append_68 = plugins/pkcs1/libstrongswan-pkcs1.la
- at USE_PKCS7_TRUE@am__append_69 = plugins/pkcs7
- at MONOLITHIC_TRUE@@USE_PKCS7_TRUE at am__append_70 = plugins/pkcs7/libstrongswan-pkcs7.la
- at USE_PKCS8_TRUE@am__append_71 = plugins/pkcs8
- at MONOLITHIC_TRUE@@USE_PKCS8_TRUE at am__append_72 = plugins/pkcs8/libstrongswan-pkcs8.la
- at USE_PKCS12_TRUE@am__append_73 = plugins/pkcs12
- at MONOLITHIC_TRUE@@USE_PKCS12_TRUE at am__append_74 = plugins/pkcs12/libstrongswan-pkcs12.la
- at USE_PGP_TRUE@am__append_75 = plugins/pgp
- at MONOLITHIC_TRUE@@USE_PGP_TRUE at am__append_76 = plugins/pgp/libstrongswan-pgp.la
- at USE_DNSKEY_TRUE@am__append_77 = plugins/dnskey
- at MONOLITHIC_TRUE@@USE_DNSKEY_TRUE at am__append_78 = plugins/dnskey/libstrongswan-dnskey.la
- at USE_SSHKEY_TRUE@am__append_79 = plugins/sshkey
- at MONOLITHIC_TRUE@@USE_SSHKEY_TRUE at am__append_80 = plugins/sshkey/libstrongswan-sshkey.la
- at USE_PEM_TRUE@am__append_81 = plugins/pem
- at MONOLITHIC_TRUE@@USE_PEM_TRUE at am__append_82 = plugins/pem/libstrongswan-pem.la
- at USE_CURL_TRUE@am__append_83 = plugins/curl
- at MONOLITHIC_TRUE@@USE_CURL_TRUE at am__append_84 = plugins/curl/libstrongswan-curl.la
- at USE_FILES_TRUE@am__append_85 = plugins/files
- at MONOLITHIC_TRUE@@USE_FILES_TRUE at am__append_86 = plugins/files/libstrongswan-files.la
- at USE_WINHTTP_TRUE@am__append_87 = plugins/winhttp
- at MONOLITHIC_TRUE@@USE_WINHTTP_TRUE at am__append_88 = plugins/winhttp/libstrongswan-winhttp.la
- at USE_UNBOUND_TRUE@am__append_89 = plugins/unbound
- at MONOLITHIC_TRUE@@USE_UNBOUND_TRUE at am__append_90 = plugins/unbound/libstrongswan-unbound.la
- at USE_SOUP_TRUE@am__append_91 = plugins/soup
- at MONOLITHIC_TRUE@@USE_SOUP_TRUE at am__append_92 = plugins/soup/libstrongswan-soup.la
- at USE_LDAP_TRUE@am__append_93 = plugins/ldap
- at MONOLITHIC_TRUE@@USE_LDAP_TRUE at am__append_94 = plugins/ldap/libstrongswan-ldap.la
- at USE_MYSQL_TRUE@am__append_95 = plugins/mysql
- at MONOLITHIC_TRUE@@USE_MYSQL_TRUE at am__append_96 = plugins/mysql/libstrongswan-mysql.la
- at USE_SQLITE_TRUE@am__append_97 = plugins/sqlite
- at MONOLITHIC_TRUE@@USE_SQLITE_TRUE at am__append_98 = plugins/sqlite/libstrongswan-sqlite.la
- at USE_PADLOCK_TRUE@am__append_99 = plugins/padlock
- at MONOLITHIC_TRUE@@USE_PADLOCK_TRUE at am__append_100 = plugins/padlock/libstrongswan-padlock.la
- at USE_OPENSSL_TRUE@am__append_101 = plugins/openssl
- at MONOLITHIC_TRUE@@USE_OPENSSL_TRUE at am__append_102 = plugins/openssl/libstrongswan-openssl.la
- at USE_GCRYPT_TRUE@am__append_103 = plugins/gcrypt
- at MONOLITHIC_TRUE@@USE_GCRYPT_TRUE at am__append_104 = plugins/gcrypt/libstrongswan-gcrypt.la
- at USE_FIPS_PRF_TRUE@am__append_105 = plugins/fips_prf
- at MONOLITHIC_TRUE@@USE_FIPS_PRF_TRUE at am__append_106 = plugins/fips_prf/libstrongswan-fips-prf.la
- at USE_AGENT_TRUE@am__append_107 = plugins/agent
- at MONOLITHIC_TRUE@@USE_AGENT_TRUE at am__append_108 = plugins/agent/libstrongswan-agent.la
- at USE_KEYCHAIN_TRUE@am__append_109 = plugins/keychain
- at MONOLITHIC_TRUE@@USE_KEYCHAIN_TRUE at am__append_110 = plugins/keychain/libstrongswan-keychain.la
- at USE_PKCS11_TRUE@am__append_111 = plugins/pkcs11
- at MONOLITHIC_TRUE@@USE_PKCS11_TRUE at am__append_112 = plugins/pkcs11/libstrongswan-pkcs11.la
- at USE_CHAPOLY_TRUE@am__append_113 = plugins/chapoly
- at MONOLITHIC_TRUE@@USE_CHAPOLY_TRUE at am__append_114 = plugins/chapoly/libstrongswan-chapoly.la
- at USE_CTR_TRUE@am__append_115 = plugins/ctr
- at MONOLITHIC_TRUE@@USE_CTR_TRUE at am__append_116 = plugins/ctr/libstrongswan-ctr.la
- at USE_CCM_TRUE@am__append_117 = plugins/ccm
- at MONOLITHIC_TRUE@@USE_CCM_TRUE at am__append_118 = plugins/ccm/libstrongswan-ccm.la
- at USE_GCM_TRUE@am__append_119 = plugins/gcm
- at MONOLITHIC_TRUE@@USE_GCM_TRUE at am__append_120 = plugins/gcm/libstrongswan-gcm.la
- at USE_MGF1_TRUE@am__append_121 = plugins/mgf1
- at MONOLITHIC_TRUE@@USE_MGF1_TRUE at am__append_122 = plugins/mgf1/libstrongswan-mgf1.la
- at USE_NTRU_TRUE@am__append_123 = plugins/ntru
- at MONOLITHIC_TRUE@@USE_NTRU_TRUE at am__append_124 = plugins/ntru/libstrongswan-ntru.la
- at USE_BLISS_TRUE@am__append_125 = plugins/bliss
- at MONOLITHIC_TRUE@@USE_BLISS_TRUE at am__append_126 = plugins/bliss/libstrongswan-bliss.la
- at USE_NEWHOPE_TRUE@am__append_127 = plugins/newhope
- at MONOLITHIC_TRUE@@USE_NEWHOPE_TRUE at am__append_128 = plugins/newhope/libstrongswan-newhope.la
- at USE_TEST_VECTORS_TRUE@am__append_129 = plugins/test_vectors
- at MONOLITHIC_TRUE@@USE_TEST_VECTORS_TRUE at am__append_130 = plugins/test_vectors/libstrongswan-test-vectors.la
- at USE_LIBNTTFFT_TRUE@am__append_131 = math/libnttfft/tests
- at USE_BLISS_TRUE@am__append_132 = plugins/bliss/tests
- at USE_NEWHOPE_TRUE@am__append_133 = plugins/newhope/tests
+ at USE_AF_ALG_TRUE@am__append_20 = plugins/af_alg
+ at MONOLITHIC_TRUE@@USE_AF_ALG_TRUE at am__append_21 = plugins/af_alg/libstrongswan-af-alg.la
+ at USE_AES_TRUE@am__append_22 = plugins/aes
+ at MONOLITHIC_TRUE@@USE_AES_TRUE at am__append_23 = plugins/aes/libstrongswan-aes.la
+ at USE_DES_TRUE@am__append_24 = plugins/des
+ at MONOLITHIC_TRUE@@USE_DES_TRUE at am__append_25 = plugins/des/libstrongswan-des.la
+ at USE_BLOWFISH_TRUE@am__append_26 = plugins/blowfish
+ at MONOLITHIC_TRUE@@USE_BLOWFISH_TRUE at am__append_27 = plugins/blowfish/libstrongswan-blowfish.la
+ at USE_RC2_TRUE@am__append_28 = plugins/rc2
+ at MONOLITHIC_TRUE@@USE_RC2_TRUE at am__append_29 = plugins/rc2/libstrongswan-rc2.la
+ at USE_MD4_TRUE@am__append_30 = plugins/md4
+ at MONOLITHIC_TRUE@@USE_MD4_TRUE at am__append_31 = plugins/md4/libstrongswan-md4.la
+ at USE_MD5_TRUE@am__append_32 = plugins/md5
+ at MONOLITHIC_TRUE@@USE_MD5_TRUE at am__append_33 = plugins/md5/libstrongswan-md5.la
+ at USE_SHA1_TRUE@am__append_34 = plugins/sha1
+ at MONOLITHIC_TRUE@@USE_SHA1_TRUE at am__append_35 = plugins/sha1/libstrongswan-sha1.la
+ at USE_SHA2_TRUE@am__append_36 = plugins/sha2
+ at MONOLITHIC_TRUE@@USE_SHA2_TRUE at am__append_37 = plugins/sha2/libstrongswan-sha2.la
+ at USE_SHA3_TRUE@am__append_38 = plugins/sha3
+ at MONOLITHIC_TRUE@@USE_SHA3_TRUE at am__append_39 = plugins/sha3/libstrongswan-sha3.la
+ at USE_GMP_TRUE@am__append_40 = plugins/gmp
+ at MONOLITHIC_TRUE@@USE_GMP_TRUE at am__append_41 = plugins/gmp/libstrongswan-gmp.la
+ at USE_CURVE25519_TRUE@am__append_42 = plugins/curve25519
+ at MONOLITHIC_TRUE@@USE_CURVE25519_TRUE at am__append_43 = plugins/curve25519/libstrongswan-curve25519.la
+ at USE_RDRAND_TRUE@am__append_44 = plugins/rdrand
+ at MONOLITHIC_TRUE@@USE_RDRAND_TRUE at am__append_45 = plugins/rdrand/libstrongswan-rdrand.la
+ at USE_AESNI_TRUE@am__append_46 = plugins/aesni
+ at MONOLITHIC_TRUE@@USE_AESNI_TRUE at am__append_47 = plugins/aesni/libstrongswan-aesni.la
+ at USE_RANDOM_TRUE@am__append_48 = plugins/random
+ at MONOLITHIC_TRUE@@USE_RANDOM_TRUE at am__append_49 = plugins/random/libstrongswan-random.la
+ at USE_NONCE_TRUE@am__append_50 = plugins/nonce
+ at MONOLITHIC_TRUE@@USE_NONCE_TRUE at am__append_51 = plugins/nonce/libstrongswan-nonce.la
+ at USE_HMAC_TRUE@am__append_52 = plugins/hmac
+ at MONOLITHIC_TRUE@@USE_HMAC_TRUE at am__append_53 = plugins/hmac/libstrongswan-hmac.la
+ at USE_CMAC_TRUE@am__append_54 = plugins/cmac
+ at MONOLITHIC_TRUE@@USE_CMAC_TRUE at am__append_55 = plugins/cmac/libstrongswan-cmac.la
+ at USE_XCBC_TRUE@am__append_56 = plugins/xcbc
+ at MONOLITHIC_TRUE@@USE_XCBC_TRUE at am__append_57 = plugins/xcbc/libstrongswan-xcbc.la
+ at USE_X509_TRUE@am__append_58 = plugins/x509
+ at MONOLITHIC_TRUE@@USE_X509_TRUE at am__append_59 = plugins/x509/libstrongswan-x509.la
+ at USE_REVOCATION_TRUE@am__append_60 = plugins/revocation
+ at MONOLITHIC_TRUE@@USE_REVOCATION_TRUE at am__append_61 = plugins/revocation/libstrongswan-revocation.la
+ at USE_CONSTRAINTS_TRUE@am__append_62 = plugins/constraints
+ at MONOLITHIC_TRUE@@USE_CONSTRAINTS_TRUE at am__append_63 = plugins/constraints/libstrongswan-constraints.la
+ at USE_ACERT_TRUE@am__append_64 = plugins/acert
+ at MONOLITHIC_TRUE@@USE_ACERT_TRUE at am__append_65 = plugins/acert/libstrongswan-acert.la
+ at USE_PUBKEY_TRUE@am__append_66 = plugins/pubkey
+ at MONOLITHIC_TRUE@@USE_PUBKEY_TRUE at am__append_67 = plugins/pubkey/libstrongswan-pubkey.la
+ at USE_PKCS1_TRUE@am__append_68 = plugins/pkcs1
+ at MONOLITHIC_TRUE@@USE_PKCS1_TRUE at am__append_69 = plugins/pkcs1/libstrongswan-pkcs1.la
+ at USE_PKCS7_TRUE@am__append_70 = plugins/pkcs7
+ at MONOLITHIC_TRUE@@USE_PKCS7_TRUE at am__append_71 = plugins/pkcs7/libstrongswan-pkcs7.la
+ at USE_PKCS8_TRUE@am__append_72 = plugins/pkcs8
+ at MONOLITHIC_TRUE@@USE_PKCS8_TRUE at am__append_73 = plugins/pkcs8/libstrongswan-pkcs8.la
+ at USE_PKCS12_TRUE@am__append_74 = plugins/pkcs12
+ at MONOLITHIC_TRUE@@USE_PKCS12_TRUE at am__append_75 = plugins/pkcs12/libstrongswan-pkcs12.la
+ at USE_PGP_TRUE@am__append_76 = plugins/pgp
+ at MONOLITHIC_TRUE@@USE_PGP_TRUE at am__append_77 = plugins/pgp/libstrongswan-pgp.la
+ at USE_DNSKEY_TRUE@am__append_78 = plugins/dnskey
+ at MONOLITHIC_TRUE@@USE_DNSKEY_TRUE at am__append_79 = plugins/dnskey/libstrongswan-dnskey.la
+ at USE_SSHKEY_TRUE@am__append_80 = plugins/sshkey
+ at MONOLITHIC_TRUE@@USE_SSHKEY_TRUE at am__append_81 = plugins/sshkey/libstrongswan-sshkey.la
+ at USE_PEM_TRUE@am__append_82 = plugins/pem
+ at MONOLITHIC_TRUE@@USE_PEM_TRUE at am__append_83 = plugins/pem/libstrongswan-pem.la
+ at USE_CURL_TRUE@am__append_84 = plugins/curl
+ at MONOLITHIC_TRUE@@USE_CURL_TRUE at am__append_85 = plugins/curl/libstrongswan-curl.la
+ at USE_FILES_TRUE@am__append_86 = plugins/files
+ at MONOLITHIC_TRUE@@USE_FILES_TRUE at am__append_87 = plugins/files/libstrongswan-files.la
+ at USE_WINHTTP_TRUE@am__append_88 = plugins/winhttp
+ at MONOLITHIC_TRUE@@USE_WINHTTP_TRUE at am__append_89 = plugins/winhttp/libstrongswan-winhttp.la
+ at USE_UNBOUND_TRUE@am__append_90 = plugins/unbound
+ at MONOLITHIC_TRUE@@USE_UNBOUND_TRUE at am__append_91 = plugins/unbound/libstrongswan-unbound.la
+ at USE_SOUP_TRUE@am__append_92 = plugins/soup
+ at MONOLITHIC_TRUE@@USE_SOUP_TRUE at am__append_93 = plugins/soup/libstrongswan-soup.la
+ at USE_LDAP_TRUE@am__append_94 = plugins/ldap
+ at MONOLITHIC_TRUE@@USE_LDAP_TRUE at am__append_95 = plugins/ldap/libstrongswan-ldap.la
+ at USE_MYSQL_TRUE@am__append_96 = plugins/mysql
+ at MONOLITHIC_TRUE@@USE_MYSQL_TRUE at am__append_97 = plugins/mysql/libstrongswan-mysql.la
+ at USE_SQLITE_TRUE@am__append_98 = plugins/sqlite
+ at MONOLITHIC_TRUE@@USE_SQLITE_TRUE at am__append_99 = plugins/sqlite/libstrongswan-sqlite.la
+ at USE_PADLOCK_TRUE@am__append_100 = plugins/padlock
+ at MONOLITHIC_TRUE@@USE_PADLOCK_TRUE at am__append_101 = plugins/padlock/libstrongswan-padlock.la
+ at USE_OPENSSL_TRUE@am__append_102 = plugins/openssl
+ at MONOLITHIC_TRUE@@USE_OPENSSL_TRUE at am__append_103 = plugins/openssl/libstrongswan-openssl.la
+ at USE_GCRYPT_TRUE@am__append_104 = plugins/gcrypt
+ at MONOLITHIC_TRUE@@USE_GCRYPT_TRUE at am__append_105 = plugins/gcrypt/libstrongswan-gcrypt.la
+ at USE_FIPS_PRF_TRUE@am__append_106 = plugins/fips_prf
+ at MONOLITHIC_TRUE@@USE_FIPS_PRF_TRUE at am__append_107 = plugins/fips_prf/libstrongswan-fips-prf.la
+ at USE_AGENT_TRUE@am__append_108 = plugins/agent
+ at MONOLITHIC_TRUE@@USE_AGENT_TRUE at am__append_109 = plugins/agent/libstrongswan-agent.la
+ at USE_KEYCHAIN_TRUE@am__append_110 = plugins/keychain
+ at MONOLITHIC_TRUE@@USE_KEYCHAIN_TRUE at am__append_111 = plugins/keychain/libstrongswan-keychain.la
+ at USE_PKCS11_TRUE@am__append_112 = plugins/pkcs11
+ at MONOLITHIC_TRUE@@USE_PKCS11_TRUE at am__append_113 = plugins/pkcs11/libstrongswan-pkcs11.la
+ at USE_CHAPOLY_TRUE@am__append_114 = plugins/chapoly
+ at MONOLITHIC_TRUE@@USE_CHAPOLY_TRUE at am__append_115 = plugins/chapoly/libstrongswan-chapoly.la
+ at USE_CTR_TRUE@am__append_116 = plugins/ctr
+ at MONOLITHIC_TRUE@@USE_CTR_TRUE at am__append_117 = plugins/ctr/libstrongswan-ctr.la
+ at USE_CCM_TRUE@am__append_118 = plugins/ccm
+ at MONOLITHIC_TRUE@@USE_CCM_TRUE at am__append_119 = plugins/ccm/libstrongswan-ccm.la
+ at USE_GCM_TRUE@am__append_120 = plugins/gcm
+ at MONOLITHIC_TRUE@@USE_GCM_TRUE at am__append_121 = plugins/gcm/libstrongswan-gcm.la
+ at USE_MGF1_TRUE@am__append_122 = plugins/mgf1
+ at MONOLITHIC_TRUE@@USE_MGF1_TRUE at am__append_123 = plugins/mgf1/libstrongswan-mgf1.la
+ at USE_NTRU_TRUE@am__append_124 = plugins/ntru
+ at MONOLITHIC_TRUE@@USE_NTRU_TRUE at am__append_125 = plugins/ntru/libstrongswan-ntru.la
+ at USE_BLISS_TRUE@am__append_126 = plugins/bliss
+ at MONOLITHIC_TRUE@@USE_BLISS_TRUE at am__append_127 = plugins/bliss/libstrongswan-bliss.la
+ at USE_NEWHOPE_TRUE@am__append_128 = plugins/newhope
+ at MONOLITHIC_TRUE@@USE_NEWHOPE_TRUE at am__append_129 = plugins/newhope/libstrongswan-newhope.la
+ at USE_TEST_VECTORS_TRUE@am__append_130 = plugins/test_vectors
+ at MONOLITHIC_TRUE@@USE_TEST_VECTORS_TRUE at am__append_131 = plugins/test_vectors/libstrongswan-test-vectors.la
+ at USE_LIBNTTFFT_TRUE@am__append_132 = math/libnttfft/tests
+ at USE_BLISS_TRUE@am__append_133 = plugins/bliss/tests
+ at USE_NEWHOPE_TRUE@am__append_134 = plugins/newhope/tests
 subdir = src/libstrongswan
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \
@@ -304,26 +305,26 @@ libstrongswan_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
-	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) $(am__append_20) \
-	$(am__append_22) $(am__append_24) $(am__append_26) \
-	$(am__append_28) $(am__append_30) $(am__append_32) \
-	$(am__append_34) $(am__append_36) $(am__append_38) \
-	$(am__append_40) $(am__append_42) $(am__append_44) \
-	$(am__append_46) $(am__append_48) $(am__append_50) \
-	$(am__append_52) $(am__append_54) $(am__append_56) \
-	$(am__append_58) $(am__append_60) $(am__append_62) \
-	$(am__append_64) $(am__append_66) $(am__append_68) \
-	$(am__append_70) $(am__append_72) $(am__append_74) \
-	$(am__append_76) $(am__append_78) $(am__append_80) \
-	$(am__append_82) $(am__append_84) $(am__append_86) \
-	$(am__append_88) $(am__append_90) $(am__append_92) \
-	$(am__append_94) $(am__append_96) $(am__append_98) \
-	$(am__append_100) $(am__append_102) $(am__append_104) \
-	$(am__append_106) $(am__append_108) $(am__append_110) \
-	$(am__append_112) $(am__append_114) $(am__append_116) \
-	$(am__append_118) $(am__append_120) $(am__append_122) \
-	$(am__append_124) $(am__append_126) $(am__append_128) \
-	$(am__append_130)
+	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) $(am__append_21) \
+	$(am__append_23) $(am__append_25) $(am__append_27) \
+	$(am__append_29) $(am__append_31) $(am__append_33) \
+	$(am__append_35) $(am__append_37) $(am__append_39) \
+	$(am__append_41) $(am__append_43) $(am__append_45) \
+	$(am__append_47) $(am__append_49) $(am__append_51) \
+	$(am__append_53) $(am__append_55) $(am__append_57) \
+	$(am__append_59) $(am__append_61) $(am__append_63) \
+	$(am__append_65) $(am__append_67) $(am__append_69) \
+	$(am__append_71) $(am__append_73) $(am__append_75) \
+	$(am__append_77) $(am__append_79) $(am__append_81) \
+	$(am__append_83) $(am__append_85) $(am__append_87) \
+	$(am__append_89) $(am__append_91) $(am__append_93) \
+	$(am__append_95) $(am__append_97) $(am__append_99) \
+	$(am__append_101) $(am__append_103) $(am__append_105) \
+	$(am__append_107) $(am__append_109) $(am__append_111) \
+	$(am__append_113) $(am__append_115) $(am__append_117) \
+	$(am__append_119) $(am__append_121) $(am__append_123) \
+	$(am__append_125) $(am__append_127) $(am__append_129) \
+	$(am__append_131)
 am__libstrongswan_la_SOURCES_DIST = library.c asn1/asn1.c \
 	asn1/asn1_parser.c asn1/oid.c bio/bio_reader.c \
 	bio/bio_writer.c collections/blocking_queue.c \
@@ -830,6 +831,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -852,6 +854,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
@@ -1037,26 +1040,26 @@ settings/settings_types.h
 libstrongswan_la_LIBADD = $(DLLIB) $(ATOMICLIB) $(BTLIB) $(SOCKLIB) \
 	$(RTLIB) $(BFDLIB) $(UNWINDLIB) $(am__append_2) \
 	$(am__append_4) $(am__append_5) $(am__append_13) \
-	$(am__append_15) $(am__append_17) $(am__append_20) \
-	$(am__append_22) $(am__append_24) $(am__append_26) \
-	$(am__append_28) $(am__append_30) $(am__append_32) \
-	$(am__append_34) $(am__append_36) $(am__append_38) \
-	$(am__append_40) $(am__append_42) $(am__append_44) \
-	$(am__append_46) $(am__append_48) $(am__append_50) \
-	$(am__append_52) $(am__append_54) $(am__append_56) \
-	$(am__append_58) $(am__append_60) $(am__append_62) \
-	$(am__append_64) $(am__append_66) $(am__append_68) \
-	$(am__append_70) $(am__append_72) $(am__append_74) \
-	$(am__append_76) $(am__append_78) $(am__append_80) \
-	$(am__append_82) $(am__append_84) $(am__append_86) \
-	$(am__append_88) $(am__append_90) $(am__append_92) \
-	$(am__append_94) $(am__append_96) $(am__append_98) \
-	$(am__append_100) $(am__append_102) $(am__append_104) \
-	$(am__append_106) $(am__append_108) $(am__append_110) \
-	$(am__append_112) $(am__append_114) $(am__append_116) \
-	$(am__append_118) $(am__append_120) $(am__append_122) \
-	$(am__append_124) $(am__append_126) $(am__append_128) \
-	$(am__append_130)
+	$(am__append_15) $(am__append_17) $(am__append_21) \
+	$(am__append_23) $(am__append_25) $(am__append_27) \
+	$(am__append_29) $(am__append_31) $(am__append_33) \
+	$(am__append_35) $(am__append_37) $(am__append_39) \
+	$(am__append_41) $(am__append_43) $(am__append_45) \
+	$(am__append_47) $(am__append_49) $(am__append_51) \
+	$(am__append_53) $(am__append_55) $(am__append_57) \
+	$(am__append_59) $(am__append_61) $(am__append_63) \
+	$(am__append_65) $(am__append_67) $(am__append_69) \
+	$(am__append_71) $(am__append_73) $(am__append_75) \
+	$(am__append_77) $(am__append_79) $(am__append_81) \
+	$(am__append_83) $(am__append_85) $(am__append_87) \
+	$(am__append_89) $(am__append_91) $(am__append_93) \
+	$(am__append_95) $(am__append_97) $(am__append_99) \
+	$(am__append_101) $(am__append_103) $(am__append_105) \
+	$(am__append_107) $(am__append_109) $(am__append_111) \
+	$(am__append_113) $(am__append_115) $(am__append_117) \
+	$(am__append_119) $(am__append_121) $(am__append_123) \
+	$(am__append_125) $(am__append_127) $(am__append_129) \
+	$(am__append_131)
 AM_CPPFLAGS = -I$(top_srcdir)/src/libstrongswan \
 	-DIPSEC_DIR=\"${ipsecdir}\" -DIPSEC_LIB_DIR=\"${ipseclibdir}\" \
 	-DPLUGINDIR=\"${plugindir}\" \
@@ -1072,83 +1075,83 @@ AM_YFLAGS = -v -d
 EXTRA_DIST = \
 asn1/oid.txt asn1/oid.pl \
 crypto/proposal/proposal_keywords_static.txt \
+plugins/plugin_constructors.py \
 Android.mk
 
-BUILT_SOURCES = \
-$(srcdir)/asn1/oid.c $(srcdir)/asn1/oid.h \
-$(srcdir)/crypto/proposal/proposal_keywords_static.c \
-settings/settings_parser.h
-
+BUILT_SOURCES = $(srcdir)/asn1/oid.c $(srcdir)/asn1/oid.h \
+	$(srcdir)/crypto/proposal/proposal_keywords_static.c \
+	settings/settings_parser.h $(am__append_18)
 MAINTAINERCLEANFILES = \
 $(srcdir)/asn1/oid.c $(srcdir)/asn1/oid.h \
 $(srcdir)/crypto/proposal/proposal_keywords_static.c
 
+ at STATIC_PLUGIN_CONSTRUCTORS_TRUE@CLEANFILES = $(srcdir)/plugin_constructors.c
 
 # build unit tests
 ##################
- at MONOLITHIC_FALSE@SUBDIRS = . $(am__append_18) $(am__append_19) \
- at MONOLITHIC_FALSE@	$(am__append_21) $(am__append_23) \
- at MONOLITHIC_FALSE@	$(am__append_25) $(am__append_27) \
- at MONOLITHIC_FALSE@	$(am__append_29) $(am__append_31) \
- at MONOLITHIC_FALSE@	$(am__append_33) $(am__append_35) \
- at MONOLITHIC_FALSE@	$(am__append_37) $(am__append_39) \
- at MONOLITHIC_FALSE@	$(am__append_41) $(am__append_43) \
- at MONOLITHIC_FALSE@	$(am__append_45) $(am__append_47) \
- at MONOLITHIC_FALSE@	$(am__append_49) $(am__append_51) \
- at MONOLITHIC_FALSE@	$(am__append_53) $(am__append_55) \
- at MONOLITHIC_FALSE@	$(am__append_57) $(am__append_59) \
- at MONOLITHIC_FALSE@	$(am__append_61) $(am__append_63) \
- at MONOLITHIC_FALSE@	$(am__append_65) $(am__append_67) \
- at MONOLITHIC_FALSE@	$(am__append_69) $(am__append_71) \
- at MONOLITHIC_FALSE@	$(am__append_73) $(am__append_75) \
- at MONOLITHIC_FALSE@	$(am__append_77) $(am__append_79) \
- at MONOLITHIC_FALSE@	$(am__append_81) $(am__append_83) \
- at MONOLITHIC_FALSE@	$(am__append_85) $(am__append_87) \
- at MONOLITHIC_FALSE@	$(am__append_89) $(am__append_91) \
- at MONOLITHIC_FALSE@	$(am__append_93) $(am__append_95) \
- at MONOLITHIC_FALSE@	$(am__append_97) $(am__append_99) \
- at MONOLITHIC_FALSE@	$(am__append_101) $(am__append_103) \
- at MONOLITHIC_FALSE@	$(am__append_105) $(am__append_107) \
- at MONOLITHIC_FALSE@	$(am__append_109) $(am__append_111) \
- at MONOLITHIC_FALSE@	$(am__append_113) $(am__append_115) \
- at MONOLITHIC_FALSE@	$(am__append_117) $(am__append_119) \
- at MONOLITHIC_FALSE@	$(am__append_121) $(am__append_123) \
- at MONOLITHIC_FALSE@	$(am__append_125) $(am__append_127) \
- at MONOLITHIC_FALSE@	$(am__append_129) tests $(am__append_131) \
- at MONOLITHIC_FALSE@	$(am__append_132) $(am__append_133)
+ at MONOLITHIC_FALSE@SUBDIRS = . $(am__append_19) $(am__append_20) \
+ at MONOLITHIC_FALSE@	$(am__append_22) $(am__append_24) \
+ at MONOLITHIC_FALSE@	$(am__append_26) $(am__append_28) \
+ at MONOLITHIC_FALSE@	$(am__append_30) $(am__append_32) \
+ at MONOLITHIC_FALSE@	$(am__append_34) $(am__append_36) \
+ at MONOLITHIC_FALSE@	$(am__append_38) $(am__append_40) \
+ at MONOLITHIC_FALSE@	$(am__append_42) $(am__append_44) \
+ at MONOLITHIC_FALSE@	$(am__append_46) $(am__append_48) \
+ at MONOLITHIC_FALSE@	$(am__append_50) $(am__append_52) \
+ at MONOLITHIC_FALSE@	$(am__append_54) $(am__append_56) \
+ at MONOLITHIC_FALSE@	$(am__append_58) $(am__append_60) \
+ at MONOLITHIC_FALSE@	$(am__append_62) $(am__append_64) \
+ at MONOLITHIC_FALSE@	$(am__append_66) $(am__append_68) \
+ at MONOLITHIC_FALSE@	$(am__append_70) $(am__append_72) \
+ at MONOLITHIC_FALSE@	$(am__append_74) $(am__append_76) \
+ at MONOLITHIC_FALSE@	$(am__append_78) $(am__append_80) \
+ at MONOLITHIC_FALSE@	$(am__append_82) $(am__append_84) \
+ at MONOLITHIC_FALSE@	$(am__append_86) $(am__append_88) \
+ at MONOLITHIC_FALSE@	$(am__append_90) $(am__append_92) \
+ at MONOLITHIC_FALSE@	$(am__append_94) $(am__append_96) \
+ at MONOLITHIC_FALSE@	$(am__append_98) $(am__append_100) \
+ at MONOLITHIC_FALSE@	$(am__append_102) $(am__append_104) \
+ at MONOLITHIC_FALSE@	$(am__append_106) $(am__append_108) \
+ at MONOLITHIC_FALSE@	$(am__append_110) $(am__append_112) \
+ at MONOLITHIC_FALSE@	$(am__append_114) $(am__append_116) \
+ at MONOLITHIC_FALSE@	$(am__append_118) $(am__append_120) \
+ at MONOLITHIC_FALSE@	$(am__append_122) $(am__append_124) \
+ at MONOLITHIC_FALSE@	$(am__append_126) $(am__append_128) \
+ at MONOLITHIC_FALSE@	$(am__append_130) tests $(am__append_132) \
+ at MONOLITHIC_FALSE@	$(am__append_133) $(am__append_134)
 
 # build unit tests
 ##################
- at MONOLITHIC_TRUE@SUBDIRS = $(am__append_18) $(am__append_19) \
- at MONOLITHIC_TRUE@	$(am__append_21) $(am__append_23) \
- at MONOLITHIC_TRUE@	$(am__append_25) $(am__append_27) \
- at MONOLITHIC_TRUE@	$(am__append_29) $(am__append_31) \
- at MONOLITHIC_TRUE@	$(am__append_33) $(am__append_35) \
- at MONOLITHIC_TRUE@	$(am__append_37) $(am__append_39) \
- at MONOLITHIC_TRUE@	$(am__append_41) $(am__append_43) \
- at MONOLITHIC_TRUE@	$(am__append_45) $(am__append_47) \
- at MONOLITHIC_TRUE@	$(am__append_49) $(am__append_51) \
- at MONOLITHIC_TRUE@	$(am__append_53) $(am__append_55) \
- at MONOLITHIC_TRUE@	$(am__append_57) $(am__append_59) \
- at MONOLITHIC_TRUE@	$(am__append_61) $(am__append_63) \
- at MONOLITHIC_TRUE@	$(am__append_65) $(am__append_67) \
- at MONOLITHIC_TRUE@	$(am__append_69) $(am__append_71) \
- at MONOLITHIC_TRUE@	$(am__append_73) $(am__append_75) \
- at MONOLITHIC_TRUE@	$(am__append_77) $(am__append_79) \
- at MONOLITHIC_TRUE@	$(am__append_81) $(am__append_83) \
- at MONOLITHIC_TRUE@	$(am__append_85) $(am__append_87) \
- at MONOLITHIC_TRUE@	$(am__append_89) $(am__append_91) \
- at MONOLITHIC_TRUE@	$(am__append_93) $(am__append_95) \
- at MONOLITHIC_TRUE@	$(am__append_97) $(am__append_99) \
- at MONOLITHIC_TRUE@	$(am__append_101) $(am__append_103) \
- at MONOLITHIC_TRUE@	$(am__append_105) $(am__append_107) \
- at MONOLITHIC_TRUE@	$(am__append_109) $(am__append_111) \
- at MONOLITHIC_TRUE@	$(am__append_113) $(am__append_115) \
- at MONOLITHIC_TRUE@	$(am__append_117) $(am__append_119) \
- at MONOLITHIC_TRUE@	$(am__append_121) $(am__append_123) \
- at MONOLITHIC_TRUE@	$(am__append_125) $(am__append_127) \
- at MONOLITHIC_TRUE@	$(am__append_129) . tests $(am__append_131) \
- at MONOLITHIC_TRUE@	$(am__append_132) $(am__append_133)
+ at MONOLITHIC_TRUE@SUBDIRS = $(am__append_19) $(am__append_20) \
+ at MONOLITHIC_TRUE@	$(am__append_22) $(am__append_24) \
+ at MONOLITHIC_TRUE@	$(am__append_26) $(am__append_28) \
+ at MONOLITHIC_TRUE@	$(am__append_30) $(am__append_32) \
+ at MONOLITHIC_TRUE@	$(am__append_34) $(am__append_36) \
+ at MONOLITHIC_TRUE@	$(am__append_38) $(am__append_40) \
+ at MONOLITHIC_TRUE@	$(am__append_42) $(am__append_44) \
+ at MONOLITHIC_TRUE@	$(am__append_46) $(am__append_48) \
+ at MONOLITHIC_TRUE@	$(am__append_50) $(am__append_52) \
+ at MONOLITHIC_TRUE@	$(am__append_54) $(am__append_56) \
+ at MONOLITHIC_TRUE@	$(am__append_58) $(am__append_60) \
+ at MONOLITHIC_TRUE@	$(am__append_62) $(am__append_64) \
+ at MONOLITHIC_TRUE@	$(am__append_66) $(am__append_68) \
+ at MONOLITHIC_TRUE@	$(am__append_70) $(am__append_72) \
+ at MONOLITHIC_TRUE@	$(am__append_74) $(am__append_76) \
+ at MONOLITHIC_TRUE@	$(am__append_78) $(am__append_80) \
+ at MONOLITHIC_TRUE@	$(am__append_82) $(am__append_84) \
+ at MONOLITHIC_TRUE@	$(am__append_86) $(am__append_88) \
+ at MONOLITHIC_TRUE@	$(am__append_90) $(am__append_92) \
+ at MONOLITHIC_TRUE@	$(am__append_94) $(am__append_96) \
+ at MONOLITHIC_TRUE@	$(am__append_98) $(am__append_100) \
+ at MONOLITHIC_TRUE@	$(am__append_102) $(am__append_104) \
+ at MONOLITHIC_TRUE@	$(am__append_106) $(am__append_108) \
+ at MONOLITHIC_TRUE@	$(am__append_110) $(am__append_112) \
+ at MONOLITHIC_TRUE@	$(am__append_114) $(am__append_116) \
+ at MONOLITHIC_TRUE@	$(am__append_118) $(am__append_120) \
+ at MONOLITHIC_TRUE@	$(am__append_122) $(am__append_124) \
+ at MONOLITHIC_TRUE@	$(am__append_126) $(am__append_128) \
+ at MONOLITHIC_TRUE@	$(am__append_130) . tests $(am__append_132) \
+ at MONOLITHIC_TRUE@	$(am__append_133) $(am__append_134)
 all: $(BUILT_SOURCES)
 	$(MAKE) $(AM_MAKEFLAGS) all-recursive
 
@@ -2184,6 +2187,7 @@ install-strip:
 mostlyclean-generic:
 
 clean-generic:
+	-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
 
 distclean-generic:
 	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
@@ -2382,6 +2386,10 @@ $(srcdir)/crypto/proposal/proposal_keywords_static.c:	$(srcdir)/crypto/proposal/
 		$(GPERF) -N proposal_get_token_static -m 10 -C -G -c -t -D < \
 												$(srcdir)/crypto/proposal/proposal_keywords_static.txt > $@
 
+ at STATIC_PLUGIN_CONSTRUCTORS_TRUE@$(srcdir)/plugin_constructors.c: $(srcdir)/plugins/plugin_constructors.py
+ at STATIC_PLUGIN_CONSTRUCTORS_TRUE@		$(AM_V_GEN) \
+ at STATIC_PLUGIN_CONSTRUCTORS_TRUE@		$(PYTHON) $(srcdir)/plugins/plugin_constructors.py ${s_plugins} > $@
+
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
 .NOEXPORT:
diff --git a/src/libstrongswan/asn1/asn1.c b/src/libstrongswan/asn1/asn1.c
index 5ce8403..8b9dc1c 100644
--- a/src/libstrongswan/asn1/asn1.c
+++ b/src/libstrongswan/asn1/asn1.c
@@ -350,13 +350,15 @@ time_t asn1_to_time(const chunk_t *utctime, asn1_t type)
 	int tm_leap_4, tm_leap_100, tm_leap_400, tm_leap;
 	int tz_hour, tz_min, tz_offset;
 	time_t tm_days, tm_secs;
-	u_char *eot = NULL;
+	char buf[BUF_LEN], *eot = NULL;
 
-	if ((eot = memchr(utctime->ptr, 'Z', utctime->len)) != NULL)
+	snprintf(buf, sizeof(buf), "%.*s", (int)utctime->len, utctime->ptr);
+
+	if ((eot = strchr(buf, 'Z')) != NULL)
 	{
 		tz_offset = 0; /* Zulu time with a zero time zone offset */
 	}
-	else if ((eot = memchr(utctime->ptr, '+', utctime->len)) != NULL)
+	else if ((eot = strchr(buf, '+')) != NULL)
 	{
 		if (sscanf(eot+1, "%2d%2d", &tz_hour, &tz_min) != 2)
 		{
@@ -364,7 +366,7 @@ time_t asn1_to_time(const chunk_t *utctime, asn1_t type)
 		}
 		tz_offset = 3600*tz_hour + 60*tz_min;  /* positive time zone offset */
 	}
-	else if ((eot = memchr(utctime->ptr, '-', utctime->len)) != NULL)
+	else if ((eot = strchr(buf, '-')) != NULL)
 	{
 		if (sscanf(eot+1, "%2d%2d", &tz_hour, &tz_min) != 2)
 		{
@@ -382,15 +384,15 @@ time_t asn1_to_time(const chunk_t *utctime, asn1_t type)
 		const char* format = (type == ASN1_UTCTIME)? "%2d%2d%2d%2d%2d":
 													 "%4d%2d%2d%2d%2d";
 
-		if (sscanf(utctime->ptr, format, &tm_year, &tm_mon, &tm_day,
-										 &tm_hour, &tm_min) != 5)
+		if (sscanf(buf, format, &tm_year, &tm_mon, &tm_day,
+								&tm_hour, &tm_min) != 5)
 		{
 			return 0; /* error in [yy]yymmddhhmm time format */
 		}
 	}
 
 	/* is there a seconds field? */
-	if ((eot - utctime->ptr) == ((type == ASN1_UTCTIME)?12:14))
+	if ((eot - buf) == ((type == ASN1_UTCTIME)?12:14))
 	{
 		if (sscanf(eot-2, "%2d", &tm_sec) != 1)
 		{
diff --git a/src/libstrongswan/asn1/asn1_parser.c b/src/libstrongswan/asn1/asn1_parser.c
index e7b7a42..4d5f799 100644
--- a/src/libstrongswan/asn1/asn1_parser.c
+++ b/src/libstrongswan/asn1/asn1_parser.c
@@ -1,8 +1,7 @@
 /*
  * Copyright (C) 2006 Martin Will
- * Copyright (C) 2000-2008 Andreas Steffen
- *
- * Hochschule fuer Technik Rapperswil
+ * Copyright (C) 2000-2017 Andreas Steffen
+ * HSR 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
@@ -76,12 +75,18 @@ struct private_asn1_parser_t {
 	 * Current parsing pointer for each level
 	 */
 	chunk_t blobs[ASN1_MAX_LEVEL + 2];
+
+	/**
+	 * Parsing a CHOICE on the current level ?
+	 */
+	bool choice[ASN1_MAX_LEVEL + 2];
+
 };
 
 METHOD(asn1_parser_t, iterate, bool,
 	private_asn1_parser_t *this, int *objectID, chunk_t *object)
 {
-	chunk_t *blob, *blob1;
+	chunk_t *blob, *blob1, blob_ori;
 	u_char *start_ptr;
 	u_int level;
 	asn1Object_t obj;
@@ -97,7 +102,7 @@ METHOD(asn1_parser_t, iterate, bool,
 		return FALSE;
 	}
 
-	if (obj.flags & ASN1_END)  /* end of loop or option found */
+	if (obj.flags & ASN1_END)  /* end of loop or choice or option found */
 	{
 		if (this->loopAddr[obj.level] && this->blobs[obj.level+1].len > 0)
 		{
@@ -106,13 +111,42 @@ METHOD(asn1_parser_t, iterate, bool,
 		}
 		else
 		{
-			this->loopAddr[obj.level] = 0;		 /* exit loop or option*/
+			this->loopAddr[obj.level] = 0;		 /* exit loop */
+
+			if (obj.flags & ASN1_CHOICE) /* end of choices */
+			{
+				if (this->choice[obj.level+1])
+				{
+					DBG1(DBG_ASN, "L%d - %s:  incorrect choice encoding",
+						this->level0 + obj.level, obj.name);
+					this->success = FALSE;
+					goto end;
+				}
+			}
+
+			if (obj.flags & ASN1_CH) /* end of choice */
+			{
+				/* parsed a valid choice */
+				this->choice[obj.level] = FALSE;
+
+				/* advance to end of choices */
+				do
+				{
+					this->line++;
+				}
+				while (!((this->objects[this->line].flags & ASN1_END) &&
+						 (this->objects[this->line].flags & ASN1_CHOICE) &&
+						 (this->objects[this->line].level == obj.level-1)));
+				this->line--;
+			}
+
 			goto end;
 		}
 	}
 
 	level = this->level0 + obj.level;
 	blob = this->blobs + obj.level;
+	blob_ori = *blob;
 	blob1 = blob + 1;
 	start_ptr = blob->ptr;
 
@@ -129,7 +163,6 @@ METHOD(asn1_parser_t, iterate, bool,
 	}
 
 	/* handle ASN.1 options */
-
 	if ((obj.flags & ASN1_OPT)
 			&& (blob->len == 0 || *start_ptr != obj.type))
 	{
@@ -144,7 +177,6 @@ METHOD(asn1_parser_t, iterate, bool,
 	}
 
 	/* an ASN.1 object must possess at least a tag and length field */
-
 	if (blob->len < 2)
 	{
 		DBG1(DBG_ASN, "L%d - %s:  ASN.1 object smaller than 2 octets",
@@ -167,8 +199,16 @@ METHOD(asn1_parser_t, iterate, bool,
 	blob->ptr += blob1->len;
 	blob->len -= blob1->len;
 
-	/* return raw ASN.1 object without prior type checking */
+	/* handle ASN.1 choice without explicit context encoding */
+	if ((obj.flags & ASN1_CHOICE) && obj.type == ASN1_EOC)
+	{
+		DBG2(DBG_ASN, "L%d - %s:", level, obj.name);
+		this->choice[obj.level+1] = TRUE;
+		*blob1 = blob_ori;
+		goto end;
+	}
 
+	/* return raw ASN.1 object without prior type checking */
 	if (obj.flags & ASN1_RAW)
 	{
 		DBG2(DBG_ASN, "L%d - %s:", level, obj.name);
@@ -209,6 +249,18 @@ METHOD(asn1_parser_t, iterate, bool,
 		}
 	}
 
+	/* In case of a "CHOICE" start to scan for exactly one valid choice */
+	if (obj.flags & ASN1_CHOICE)
+	{
+		if (blob1->len == 0)
+		{
+			DBG1(DBG_ASN, "L%d - %s:  contains no choice", level, obj.name);
+			this->success = FALSE;
+			goto end;
+		}
+		this->choice[obj.level+1] = TRUE;
+	}
+
 	if (obj.flags & ASN1_OBJ)
 	{
 		object->ptr = start_ptr;
diff --git a/src/libstrongswan/asn1/asn1_parser.h b/src/libstrongswan/asn1/asn1_parser.h
index 0edc22c..2ee1e89 100644
--- a/src/libstrongswan/asn1/asn1_parser.h
+++ b/src/libstrongswan/asn1/asn1_parser.h
@@ -1,8 +1,7 @@
 /*
  * Copyright (C) 2006 Martin Will
- * Copyright (C) 2000-2008 Andreas Steffen
- *
- * Hochschule fuer Technik Rapperswil
+ * Copyright (C) 2000-2017 Andreas Steffen
+ * HSR 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
@@ -32,15 +31,17 @@
 /**
  * Definition of ASN.1 flags
  */
-#define ASN1_NONE	0x00
-#define ASN1_DEF	0x01
-#define ASN1_OPT	0x02
-#define ASN1_LOOP	0x04
-#define ASN1_END	0x08
-#define ASN1_OBJ	0x10
-#define ASN1_BODY	0x20
-#define ASN1_RAW	0x40
-#define ASN1_EXIT	0x80
+#define ASN1_NONE    0x0000
+#define ASN1_DEF     0x0001
+#define ASN1_OPT     0x0002
+#define ASN1_LOOP    0x0004
+#define ASN1_CHOICE  0x0008
+#define ASN1_CH      0x0010
+#define ASN1_END     0x0020
+#define ASN1_OBJ     0x0040
+#define ASN1_BODY    0x0080
+#define ASN1_RAW     0x0100
+#define ASN1_EXIT    0x0200
 
 typedef struct asn1Object_t asn1Object_t;
 
@@ -51,7 +52,7 @@ struct asn1Object_t{
 	u_int level;
 	const u_char *name;
 	asn1_t type;
-	u_char flags;
+	uint16_t flags;
 };
 
 typedef struct asn1_parser_t asn1_parser_t;
diff --git a/src/libstrongswan/collections/array.c b/src/libstrongswan/collections/array.c
index 69e7df9..c3dd6e0 100644
--- a/src/libstrongswan/collections/array.c
+++ b/src/libstrongswan/collections/array.c
@@ -214,9 +214,11 @@ typedef struct {
 } array_enumerator_t;
 
 METHOD(enumerator_t, enumerate, bool,
-	array_enumerator_t *this, void **out)
+	array_enumerator_t *this, va_list args)
 {
-	void *pos;
+	void *pos, **out;
+
+	VA_ARGS_VGET(args, out);
 
 	if (this->idx >= this->array->count)
 	{
@@ -250,7 +252,8 @@ enumerator_t* array_create_enumerator(array_t *array)
 
 	INIT(enumerator,
 		.public = {
-			.enumerate = (void*)_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _enumerate,
 			.destroy = (void*)free,
 		},
 		.array = array,
diff --git a/src/libstrongswan/collections/enumerator.c b/src/libstrongswan/collections/enumerator.c
index fa277e7..52c9e1c 100644
--- a/src/libstrongswan/collections/enumerator.c
+++ b/src/libstrongswan/collections/enumerator.c
@@ -1,7 +1,7 @@
 /*
- * Copyright (C) 2008-2013 Tobias Brunner
+ * Copyright (C) 2008-2017 Tobias Brunner
  * Copyright (C) 2007 Martin Willi
- * Hochschule fuer Technik Rapperswil
+ * HSR 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
@@ -31,22 +31,43 @@
 
 #include <utils/debug.h>
 
-/**
- * Implementation of enumerator_create_empty().enumerate
+/*
+ * Described in header.
  */
-static bool enumerate_empty(enumerator_t *enumerator, ...)
+bool enumerator_enumerate_default(enumerator_t *enumerator, ...)
+{
+	va_list args;
+	bool result;
+
+	if (!enumerator->venumerate)
+	{
+		DBG1(DBG_LIB, "!!! ENUMERATE DEFAULT: venumerate() missing !!!");
+		return FALSE;
+	}
+	va_start(args, enumerator);
+	result = enumerator->venumerate(enumerator, args);
+	va_end(args);
+	return result;
+}
+
+METHOD(enumerator_t, enumerate_empty, bool,
+	enumerator_t *enumerator, va_list args)
 {
 	return FALSE;
 }
 
-/**
- * See header
+/*
+ * Described in header
  */
 enumerator_t* enumerator_create_empty()
 {
-	enumerator_t *this = malloc_thing(enumerator_t);
-	this->enumerate = enumerate_empty;
-	this->destroy = (void*)free;
+	enumerator_t *this;
+
+	INIT(this,
+		.enumerate = enumerator_enumerate_default,
+		.venumerate = _enumerate_empty,
+		.destroy = (void*)free,
+	);
 	return this;
 }
 
@@ -64,32 +85,31 @@ typedef struct {
 	char *full_end;
 } dir_enum_t;
 
-/**
- * Implementation of enumerator_create_directory().destroy
- */
-static void destroy_dir_enum(dir_enum_t *this)
+METHOD(enumerator_t, destroy_dir_enum, void,
+	dir_enum_t *this)
 {
 	closedir(this->dir);
 	free(this);
 }
 
-/**
- * Implementation of enumerator_create_directory().enumerate
- */
-static bool enumerate_dir_enum(dir_enum_t *this, char **relative,
-							   char **absolute, struct stat *st)
+METHOD(enumerator_t, enumerate_dir_enum, bool,
+	dir_enum_t *this, va_list args)
 {
 	struct dirent *entry = readdir(this->dir);
+	struct stat *st;
 	size_t remaining;
+	char **relative, **absolute;
 	int len;
 
+	VA_ARGS_VGET(args, relative, absolute, st);
+
 	if (!entry)
 	{
 		return FALSE;
 	}
 	if (streq(entry->d_name, ".") || streq(entry->d_name, ".."))
 	{
-		return enumerate_dir_enum(this, relative, absolute, st);
+		return this->public.enumerate(&this->public, relative, absolute, st);
 	}
 	if (relative)
 	{
@@ -122,15 +142,21 @@ static bool enumerate_dir_enum(dir_enum_t *this, char **relative,
 	return TRUE;
 }
 
-/**
- * See header
+/*
+ * Described in header
  */
 enumerator_t* enumerator_create_directory(const char *path)
 {
+	dir_enum_t *this;
 	int len;
-	dir_enum_t *this = malloc_thing(dir_enum_t);
-	this->public.enumerate = (void*)enumerate_dir_enum;
-	this->public.destroy = (void*)destroy_dir_enum;
+
+	INIT(this,
+		.public = {
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _enumerate_dir_enum,
+			.destroy = _destroy_dir_enum,
+		},
+	);
 
 	if (*path == '\0')
 	{
@@ -152,9 +178,10 @@ enumerator_t* enumerator_create_directory(const char *path)
 	this->full_end = &this->full[len];
 
 	this->dir = opendir(path);
-	if (this->dir == NULL)
+	if (!this->dir)
 	{
-		DBG1(DBG_LIB, "opening directory '%s' failed: %s", path, strerror(errno));
+		DBG1(DBG_LIB, "opening directory '%s' failed: %s", path,
+			 strerror(errno));
 		free(this);
 		return NULL;
 	}
@@ -177,21 +204,21 @@ typedef struct {
 	char full[PATH_MAX];
 } glob_enum_t;
 
-/**
- * Implementation of enumerator_create_glob().destroy
- */
-static void destroy_glob_enum(glob_enum_t *this)
+METHOD(enumerator_t, destroy_glob_enum, void,
+	glob_enum_t *this)
 {
 	globfree(&this->glob);
 	free(this);
 }
 
-/**
- * Implementation of enumerator_create_glob().enumerate
- */
-static bool enumerate_glob_enum(glob_enum_t *this, char **file, struct stat *st)
+METHOD(enumerator_t, enumerate_glob_enum, bool,
+	glob_enum_t *this, va_list args)
 {
+	struct stat *st;
 	char *match;
+	char **file;
+
+	VA_ARGS_VGET(args, file, st);
 
 	if (this->pos >= this->glob.gl_pathc)
 	{
@@ -202,20 +229,17 @@ static bool enumerate_glob_enum(glob_enum_t *this, char **file, struct stat *st)
 	{
 		*file = match;
 	}
-	if (st)
+	if (st && stat(match, st))
 	{
-		if (stat(match, st))
-		{
-			DBG1(DBG_LIB, "stat() on '%s' failed: %s", match,
-				 strerror(errno));
-			return FALSE;
-		}
+		DBG1(DBG_LIB, "stat() on '%s' failed: %s", match,
+			 strerror(errno));
+		return FALSE;
 	}
 	return TRUE;
 }
 
-/**
- * See header
+/*
+ * Described in header
  */
 enumerator_t* enumerator_create_glob(const char *pattern)
 {
@@ -229,8 +253,9 @@ enumerator_t* enumerator_create_glob(const char *pattern)
 
 	INIT(this,
 		.public = {
-			.enumerate = (void*)enumerate_glob_enum,
-			.destroy = (void*)destroy_glob_enum,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _enumerate_glob_enum,
+			.destroy = _destroy_glob_enum,
 		},
 	);
 
@@ -272,24 +297,22 @@ typedef struct {
 	const char *trim;
 } token_enum_t;
 
-/**
- * Implementation of enumerator_create_token().destroy
- */
-static void destroy_token_enum(token_enum_t *this)
+METHOD(enumerator_t, destroy_token_enum, void,
+	token_enum_t *this)
 {
 	free(this->string);
 	free(this);
 }
 
-/**
- * Implementation of enumerator_create_token().enumerate
- */
-static bool enumerate_token_enum(token_enum_t *this, char **token)
+METHOD(enumerator_t, enumerate_token_enum, bool,
+	token_enum_t *this, va_list args)
 {
 	const char *sep, *trim;
-	char *pos = NULL, *tmp;
+	char *pos = NULL, *tmp, **token;
 	bool last = FALSE;
 
+	VA_ARGS_VGET(args, token);
+
 	/* trim leading characters/separators */
 	while (*this->pos)
 	{
@@ -390,52 +413,48 @@ static bool enumerate_token_enum(token_enum_t *this, char **token)
 	return FALSE;
 }
 
-/**
- * See header
+/*
+ * Described in header
  */
 enumerator_t* enumerator_create_token(const char *string, const char *sep,
 									  const char *trim)
 {
-	token_enum_t *enumerator = malloc_thing(token_enum_t);
+	token_enum_t *this;
 
-	enumerator->public.enumerate = (void*)enumerate_token_enum;
-	enumerator->public.destroy = (void*)destroy_token_enum;
-	enumerator->string = strdup(string);
-	enumerator->pos = enumerator->string;
-	enumerator->sep = sep;
-	enumerator->trim = trim;
+	INIT(this,
+		.public = {
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _enumerate_token_enum,
+			.destroy = _destroy_token_enum,
+		},
+		.string = strdup(string),
+		.sep = sep,
+		.trim = trim,
+	);
+	this->pos = this->string;
 
-	return &enumerator->public;
+	return &this->public;
 }
 
 /**
- * enumerator for nested enumerations
+ * Enumerator for nested enumerations
  */
 typedef struct {
-	/* implements enumerator_t */
 	enumerator_t public;
-	/* outer enumerator */
 	enumerator_t *outer;
-	/* inner enumerator */
 	enumerator_t *inner;
-	/* constructor for inner enumerator */
 	enumerator_t *(*create_inner)(void *outer, void *data);
-	/* data to pass to constructor above */
 	void *data;
-	/* destructor for data */
-	void (*destroy_data)(void *data);
+	void (*destructor)(void *data);
 } nested_enumerator_t;
 
 
-/**
- * Implementation of enumerator_create_nested().enumerate()
- */
-static bool enumerate_nested(nested_enumerator_t *this, void *v1, void *v2,
-							 void *v3, void *v4, void *v5)
+METHOD(enumerator_t, enumerate_nested, bool,
+	nested_enumerator_t *this, va_list args)
 {
 	while (TRUE)
 	{
-		while (this->inner == NULL)
+		while (!this->inner)
 		{
 			void *outer;
 
@@ -444,8 +463,13 @@ static bool enumerate_nested(nested_enumerator_t *this, void *v1, void *v2,
 				return FALSE;
 			}
 			this->inner = this->create_inner(outer, this->data);
+			if (this->inner && !this->inner->venumerate)
+			{
+				DBG1(DBG_LIB, "!!! ENUMERATE NESTED: venumerate() missing !!!");
+				return FALSE;
+			}
 		}
-		if (this->inner->enumerate(this->inner, v1, v2, v3, v4, v5))
+		if (this->inner->venumerate(this->inner, args))
 		{
 			return TRUE;
 		}
@@ -454,103 +478,100 @@ static bool enumerate_nested(nested_enumerator_t *this, void *v1, void *v2,
 	}
 }
 
-/**
- * Implementation of enumerator_create_nested().destroy()
- **/
-static void destroy_nested(nested_enumerator_t *this)
+METHOD(enumerator_t, destroy_nested, void,
+	nested_enumerator_t *this)
 {
-	if (this->destroy_data)
+	if (this->destructor)
 	{
-		this->destroy_data(this->data);
+		this->destructor(this->data);
 	}
 	DESTROY_IF(this->inner);
 	this->outer->destroy(this->outer);
 	free(this);
 }
 
-/**
- * See header
+/*
+ * Described in header
  */
 enumerator_t *enumerator_create_nested(enumerator_t *outer,
 					enumerator_t *(inner_constructor)(void *outer, void *data),
-					void *data, void (*destroy_data)(void *data))
+					void *data, void (*destructor)(void *data))
 {
-	nested_enumerator_t *enumerator = malloc_thing(nested_enumerator_t);
+	nested_enumerator_t *this;
 
-	enumerator->public.enumerate = (void*)enumerate_nested;
-	enumerator->public.destroy = (void*)destroy_nested;
-	enumerator->outer = outer;
-	enumerator->inner = NULL;
-	enumerator->create_inner = (void*)inner_constructor;
-	enumerator->data = data;
-	enumerator->destroy_data = destroy_data;
-
-	return &enumerator->public;
+	INIT(this,
+		.public = {
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _enumerate_nested,
+			.destroy = _destroy_nested,
+		},
+		.outer = outer,
+		.create_inner = inner_constructor,
+		.data = data,
+		.destructor = destructor,
+	);
+	return &this->public;
 }
 
 /**
- * enumerator for filtered enumerator
+ * Enumerator for filtered enumerator
  */
 typedef struct {
 	enumerator_t public;
-	enumerator_t *unfiltered;
+	enumerator_t *orig;
 	void *data;
-	bool (*filter)(void *data, ...);
+	bool (*filter)(void*,enumerator_t*,va_list);
 	void (*destructor)(void *data);
 } filter_enumerator_t;
 
-/**
- * Implementation of enumerator_create_filter().destroy
- */
-static void destroy_filter(filter_enumerator_t *this)
+METHOD(enumerator_t, destroy_filter, void,
+	filter_enumerator_t *this)
 {
 	if (this->destructor)
 	{
 		this->destructor(this->data);
 	}
-	this->unfiltered->destroy(this->unfiltered);
+	this->orig->destroy(this->orig);
 	free(this);
 }
 
-/**
- * Implementation of enumerator_create_filter().enumerate
- */
-static bool enumerate_filter(filter_enumerator_t *this, void *o1, void *o2,
-							 void *o3, void *o4, void *o5)
+METHOD(enumerator_t, enumerate_filter, bool,
+	filter_enumerator_t *this, va_list args)
 {
-	void *i1, *i2, *i3, *i4, *i5;
+	bool result = FALSE;
 
-	while (this->unfiltered->enumerate(this->unfiltered, &i1, &i2, &i3, &i4, &i5))
+	if (this->filter(this->data, this->orig, args))
 	{
-		if (this->filter(this->data, &i1, o1, &i2, o2, &i3, o3, &i4, o4, &i5, o5))
-		{
-			return TRUE;
-		}
+		result = TRUE;
 	}
-	return FALSE;
+	return result;
 }
 
-/**
- * see header
+/*
+ * Described in header
  */
-enumerator_t *enumerator_create_filter(enumerator_t *unfiltered,
-									   bool (*filter)(void *data, ...),
-									   void *data, void (*destructor)(void *data))
+enumerator_t *enumerator_create_filter(enumerator_t *orig,
+			bool (*filter)(void *data, enumerator_t *orig, va_list args),
+			void *data, void (*destructor)(void *data))
 {
-	filter_enumerator_t *this = malloc_thing(filter_enumerator_t);
-
-	this->public.enumerate = (void*)enumerate_filter;
-	this->public.destroy = (void*)destroy_filter;
-	this->unfiltered = unfiltered;
-	this->filter = filter;
-	this->data = data;
-	this->destructor = destructor;
+	filter_enumerator_t *this;
 
+	INIT(this,
+		.public = {
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _enumerate_filter,
+			.destroy = _destroy_filter,
+		},
+		.orig = orig,
+		.filter = filter,
+		.data = data,
+		.destructor = destructor,
+	);
 	return &this->public;
 }
 
 /**
- * enumerator for cleaner enumerator
+ * Enumerator for cleaner enumerator
  */
 typedef struct {
 	enumerator_t public;
@@ -559,44 +580,48 @@ typedef struct {
 	void *data;
 } cleaner_enumerator_t;
 
-/**
- * Implementation of enumerator_create_cleanup().destroy
- */
-static void destroy_cleaner(cleaner_enumerator_t *this)
+METHOD(enumerator_t, destroy_cleaner, void,
+	cleaner_enumerator_t *this)
 {
 	this->cleanup(this->data);
 	this->wrapped->destroy(this->wrapped);
 	free(this);
 }
 
-/**
- * Implementation of enumerator_create_cleaner().enumerate
- */
-static bool enumerate_cleaner(cleaner_enumerator_t *this, void *v1, void *v2,
-							  void *v3, void *v4, void *v5)
+METHOD(enumerator_t, enumerate_cleaner, bool,
+	cleaner_enumerator_t *this, va_list args)
 {
-	return this->wrapped->enumerate(this->wrapped, v1, v2, v3, v4, v5);
+	if (!this->wrapped->venumerate)
+	{
+		DBG1(DBG_LIB, "!!! CLEANER ENUMERATOR: venumerate() missing !!!");
+		return FALSE;
+	}
+	return this->wrapped->venumerate(this->wrapped, args);
 }
 
-/**
- * see header
+/*
+ * Described in header
  */
 enumerator_t *enumerator_create_cleaner(enumerator_t *wrapped,
 										void (*cleanup)(void *data), void *data)
 {
-	cleaner_enumerator_t *this = malloc_thing(cleaner_enumerator_t);
-
-	this->public.enumerate = (void*)enumerate_cleaner;
-	this->public.destroy = (void*)destroy_cleaner;
-	this->wrapped = wrapped;
-	this->cleanup = cleanup;
-	this->data = data;
+	cleaner_enumerator_t *this;
 
+	INIT(this,
+		.public = {
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _enumerate_cleaner,
+			.destroy = _destroy_cleaner,
+		},
+		.wrapped = wrapped,
+		.cleanup = cleanup,
+		.data = data,
+	);
 	return &this->public;
 }
 
 /**
- * enumerator for single enumerator
+ * Enumerator for single enumerator
  */
 typedef struct {
 	enumerator_t public;
@@ -605,10 +630,8 @@ typedef struct {
 	bool done;
 } single_enumerator_t;
 
-/**
- * Implementation of enumerator_create_single().destroy
- */
-static void destroy_single(single_enumerator_t *this)
+METHOD(enumerator_t, destroy_single, void,
+	single_enumerator_t *this)
 {
 	if (this->cleanup)
 	{
@@ -617,11 +640,12 @@ static void destroy_single(single_enumerator_t *this)
 	free(this);
 }
 
-/**
- * Implementation of enumerator_create_single().enumerate
- */
-static bool enumerate_single(single_enumerator_t *this, void **item)
+METHOD(enumerator_t, enumerate_single, bool,
+	single_enumerator_t *this, va_list args)
 {
+	void **item;
+
+	VA_ARGS_VGET(args, item);
 	if (this->done)
 	{
 		return FALSE;
@@ -631,19 +655,21 @@ static bool enumerate_single(single_enumerator_t *this, void **item)
 	return TRUE;
 }
 
-/**
- * see header
+/*
+ * Described in header
  */
 enumerator_t *enumerator_create_single(void *item, void (*cleanup)(void *item))
 {
-	single_enumerator_t *this = malloc_thing(single_enumerator_t);
-
-	this->public.enumerate = (void*)enumerate_single;
-	this->public.destroy = (void*)destroy_single;
-	this->item = item;
-	this->cleanup = cleanup;
-	this->done = FALSE;
+	single_enumerator_t *this;
 
+	INIT(this,
+		.public = {
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _enumerate_single,
+			.destroy = _destroy_single,
+		},
+		.item = item,
+		.cleanup = cleanup,
+	);
 	return &this->public;
 }
-
diff --git a/src/libstrongswan/collections/enumerator.h b/src/libstrongswan/collections/enumerator.h
index 55f8d83..99f8847 100644
--- a/src/libstrongswan/collections/enumerator.h
+++ b/src/libstrongswan/collections/enumerator.h
@@ -1,7 +1,7 @@
 /*
- * Copyright (C) 2013 Tobias Brunner
+ * Copyright (C) 2013-2017 Tobias Brunner
  * Copyright (C) 2007 Martin Willi
- * Hochschule fuer Technik Rapperswil
+ * HSR 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
@@ -34,8 +34,11 @@ struct enumerator_t {
 	/**
 	 * Enumerate collection.
 	 *
-	 * The enumerate function takes a variable argument list containing
-	 * pointers where the enumerated values get written.
+	 * The enumerate() method takes a variable number of pointer arguments
+	 * where the enumerated values get written to.
+	 *
+	 * @note Just assigning the generic enumerator_enumerate_default() function
+	 * that calls the enumerator's venumerate() method is usually enough.
 	 *
 	 * @param ...	variable list of enumerated items, implementation dependent
 	 * @return		TRUE if pointers returned
@@ -43,12 +46,34 @@ struct enumerator_t {
 	bool (*enumerate)(enumerator_t *this, ...);
 
 	/**
-	 * Destroy a enumerator instance.
+	 * Enumerate collection.
+	 *
+	 * The venumerate() method takes a variable argument list containing
+	 * pointers where the enumerated values get written to.
+	 *
+	 * To simplify the implementation the VA_ARGS_VGET() macro may be used.
+	 *
+	 * @param args	variable list of enumerated items, implementation dependent
+	 * @return		TRUE if pointers returned
+	 */
+	bool (*venumerate)(enumerator_t *this, va_list args);
+
+	/**
+	 * Destroy an enumerator_t instance.
 	 */
 	void (*destroy)(enumerator_t *this);
 };
 
 /**
+ * Generic implementation of enumerator_t::enumerate() that simply calls
+ * the enumerator's venumerate() method.
+ *
+ * @param enumerator	the enumerator
+ * @param ...			arguments passed to enumerate()
+ */
+bool enumerator_enumerate_default(enumerator_t *enumerator, ...);
+
+/**
  * Create an enumerator which enumerates over nothing
  *
  * @return			an enumerator over no values
@@ -147,38 +172,41 @@ enumerator_t* enumerator_create_token(const char *string, const char *sep,
 /**
  * Creates an enumerator which enumerates over enumerated enumerators :-).
  *
- * The variable argument list of enumeration values is limit to 5.
+ * The outer enumerator is expected to return objects that, when passed to
+ * inner_contructor, will create a new enumerator that will be enumerated until
+ * completion (to this enumerator will the pointer arguments that are passed to
+ * this enumerator be forwarded) at which point a new element from the outer
+ * enumerator is requested to create a new inner enumerator.
  *
  * @param outer					outer enumerator
- * @param inner_constructor		constructor to inner enumerator
+ * @param inner_constructor		constructor to create inner enumerator
  * @param data					data to pass to each inner_constructor call
- * @param destroy_data			destructor to pass to data
+ * @param destructor			destructor function to clean up data after use
  * @return						the nested enumerator
  */
 enumerator_t *enumerator_create_nested(enumerator_t *outer,
 					enumerator_t *(*inner_constructor)(void *outer, void *data),
-					void *data, void (*destroy_data)(void *data));
+					void *data, void (*destructor)(void *data));
 
 /**
- * Creates an enumerator which filters output of another enumerator.
+ * Creates an enumerator which filters/maps output of another enumerator.
  *
- * The filter function receives the user supplied "data" followed by a
- * unfiltered enumeration item, followed by an output pointer where to write
- * the filtered data. Then the next input/output pair follows.
- * It returns TRUE to deliver the
- * values to the caller of enumerate(), FALSE to filter this enumeration.
+ * The filter function receives the user supplied "data" followed by the
+ * original enumerator, followed by the arguments passed to the outer
+ * enumerator.  It returns TRUE to deliver the values assigned to these
+ * arguments to the caller of enumerate() and FALSE to end the enumeration.
+ * Filtering items is simple as the filter function may just skip enumerated
+ * items from the original enumerator.
  *
- * The variable argument list of enumeration values is limit to 5.
- *
- * @param unfiltered			unfiltered enumerator to wrap, gets destroyed
+ * @param orig					original enumerator to wrap, gets destroyed
  * @param filter				filter function
  * @param data					user data to supply to filter
  * @param destructor			destructor function to clean up data after use
  * @return						the filtered enumerator
  */
-enumerator_t *enumerator_create_filter(enumerator_t *unfiltered,
-					bool (*filter)(void *data, ...),
-					void *data, void (*destructor)(void *data));
+enumerator_t *enumerator_create_filter(enumerator_t *orig,
+				bool (*filter)(void *data, enumerator_t *orig, va_list args),
+				void *data, void (*destructor)(void *data));
 
 /**
  * Create an enumerator wrapper which does a cleanup on destroy.
diff --git a/src/libstrongswan/collections/hashtable.c b/src/libstrongswan/collections/hashtable.c
index 2b77a37..b0eda9e 100644
--- a/src/libstrongswan/collections/hashtable.c
+++ b/src/libstrongswan/collections/hashtable.c
@@ -379,8 +379,13 @@ METHOD(hashtable_t, get_count, u_int,
 }
 
 METHOD(enumerator_t, enumerate, bool,
-	private_enumerator_t *this, const void **key, void **value)
+	private_enumerator_t *this, va_list args)
 {
+	const void **key;
+	void **value;
+
+	VA_ARGS_VGET(args, key, value);
+
 	while (this->count && this->row < this->table->capacity)
 	{
 		this->prev = this->current;
@@ -417,7 +422,8 @@ METHOD(hashtable_t, create_enumerator, enumerator_t*,
 
 	INIT(enumerator,
 		.enumerator = {
-			.enumerate = (void*)_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _enumerate,
 			.destroy = (void*)free,
 		},
 		.table = this,
diff --git a/src/libstrongswan/collections/linked_list.c b/src/libstrongswan/collections/linked_list.c
index b8fe815..f877be5 100644
--- a/src/libstrongswan/collections/linked_list.c
+++ b/src/libstrongswan/collections/linked_list.c
@@ -47,6 +47,17 @@ struct element_t {
 	element_t *next;
 };
 
+/*
+ * Described in header
+ */
+bool linked_list_match_str(void *item, va_list args)
+{
+	char *a = item, *b;
+
+	VA_ARGS_VGET(args, b);
+	return streq(a, b);
+}
+
 /**
  * Creates an empty linked list object.
  */
@@ -119,8 +130,12 @@ struct private_enumerator_t {
 };
 
 METHOD(enumerator_t, enumerate, bool,
-	private_enumerator_t *this, void **item)
+	private_enumerator_t *this, va_list args)
 {
+	void **item;
+
+	VA_ARGS_VGET(args, item);
+
 	if (this->finished)
 	{
 		return FALSE;
@@ -152,7 +167,8 @@ METHOD(linked_list_t, create_enumerator, enumerator_t*,
 
 	INIT(enumerator,
 		.enumerator = {
-			.enumerate = (void*)_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _enumerate,
 			.destroy = (void*)free,
 		},
 		.list = this,
@@ -366,52 +382,68 @@ METHOD(linked_list_t, remove_at, void,
 	}
 }
 
-METHOD(linked_list_t, find_first, status_t,
-	private_linked_list_t *this, linked_list_match_t match,
-	void **item, void *d1, void *d2, void *d3, void *d4, void *d5)
+METHOD(linked_list_t, find_first, bool,
+	private_linked_list_t *this, linked_list_match_t match, void **item, ...)
 {
 	element_t *current = this->first;
+	va_list args;
+	bool matched = FALSE;
+
+	if (!match && !item)
+	{
+		return FALSE;
+	}
 
 	while (current)
 	{
-		if ((match && match(current->value, d1, d2, d3, d4, d5)) ||
-			(!match && item && current->value == *item))
+		if (match)
+		{
+			va_start(args, item);
+			matched = match(current->value, args);
+			va_end(args);
+		}
+		else
+		{
+			matched = current->value == *item;
+		}
+		if (matched)
 		{
 			if (item != NULL)
 			{
 				*item = current->value;
 			}
-			return SUCCESS;
+			return TRUE;
 		}
 		current = current->next;
 	}
-	return NOT_FOUND;
+	return FALSE;
 }
 
 METHOD(linked_list_t, invoke_offset, void,
-	private_linked_list_t *this, size_t offset,
-	void *d1, void *d2, void *d3, void *d4, void *d5)
+	private_linked_list_t *this, size_t offset)
 {
 	element_t *current = this->first;
-	linked_list_invoke_t *method;
+	void (**method)(void*);
 
 	while (current)
 	{
 		method = current->value + offset;
-		(*method)(current->value, d1, d2, d3, d4, d5);
+		(*method)(current->value);
 		current = current->next;
 	}
 }
 
 METHOD(linked_list_t, invoke_function, void,
-	private_linked_list_t *this, linked_list_invoke_t fn,
-	void *d1, void *d2, void *d3, void *d4, void *d5)
+	private_linked_list_t *this, linked_list_invoke_t fn, ...)
 {
 	element_t *current = this->first;
+	va_list args;
 
 	while (current)
 	{
-		fn(current->value, d1, d2, d3, d4, d5);
+		va_start(args, fn);
+		fn(current->value, args);
+		va_end(args);
 		current = current->next;
 	}
 }
@@ -542,7 +574,7 @@ linked_list_t *linked_list_create()
 			.reset_enumerator = (void*)_reset_enumerator,
 			.get_first = _get_first,
 			.get_last = _get_last,
-			.find_first = (void*)_find_first,
+			.find_first = _find_first,
 			.insert_first = _insert_first,
 			.insert_last = _insert_last,
 			.insert_before = (void*)_insert_before,
@@ -550,8 +582,8 @@ linked_list_t *linked_list_create()
 			.remove_last = _remove_last,
 			.remove = _remove_,
 			.remove_at = (void*)_remove_at,
-			.invoke_offset = (void*)_invoke_offset,
-			.invoke_function = (void*)_invoke_function,
+			.invoke_offset = _invoke_offset,
+			.invoke_function = _invoke_function,
 			.clone_offset = _clone_offset,
 			.equals_offset = _equals_offset,
 			.equals_function = _equals_function,
diff --git a/src/libstrongswan/collections/linked_list.h b/src/libstrongswan/collections/linked_list.h
index 0b73079..246b9a5 100644
--- a/src/libstrongswan/collections/linked_list.h
+++ b/src/libstrongswan/collections/linked_list.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007-2015 Tobias Brunner
+ * Copyright (C) 2007-2017 Tobias Brunner
  * Copyright (C) 2005-2008 Martin Willi
  * Copyright (C) 2005 Jan Hutter
  * Hochschule fuer Technik Rapperswil
@@ -28,23 +28,30 @@ typedef struct linked_list_t linked_list_t;
 #include <collections/enumerator.h>
 
 /**
- * Method to match elements in a linked list (used in find_* functions)
+ * Function to match elements in a linked list
  *
  * @param item			current list item
- * @param ...			user supplied data (only pointers, at most 5)
+ * @param args			user supplied data
+ * @return				TRUE, if the item matched, FALSE otherwise
+ */
+typedef bool (*linked_list_match_t)(void *item, va_list args);
+
+/**
+ * Helper function to match a string in a linked list of strings
+ *
+ * @param item			list item (char*)
+ * @param args			user supplied data (char*)
  * @return
- *						- TRUE, if the item matched
- *						- FALSE, otherwise
  */
-typedef bool (*linked_list_match_t)(void *item, ...);
+bool linked_list_match_str(void *item, va_list args);
 
 /**
- * Method to be invoked on elements in a linked list (used in invoke_* functions)
+ * Function to be invoked on elements in a linked list
  *
  * @param item			current list item
- * @param ...			user supplied data (only pointers, at most 5)
+ * @param args			user supplied data
  */
-typedef void (*linked_list_invoke_t)(void *item, ...);
+typedef void (*linked_list_invoke_t)(void *item, va_list args);
 
 /**
  * Class implementing a double linked list.
@@ -167,21 +174,20 @@ struct linked_list_t {
 	 *
 	 * The first object passed to the match function is the current list item,
 	 * followed by the user supplied data.
-	 * If the supplied function returns TRUE this function returns SUCCESS, and
-	 * the current object is returned in the third parameter, otherwise,
+	 * If the supplied function returns TRUE so does this function, and the
+	 * current object is returned in the third parameter (if given), otherwise,
 	 * the next item is checked.
 	 *
 	 * If match is NULL, *item and the current object are compared.
 	 *
-	 * @warning Only use pointers as user supplied data.
-	 *
 	 * @param match			comparison function to call on each object, or NULL
-	 * @param item			the list item, if found
-	 * @param ...			user data to supply to match function (limited to 5 arguments)
-	 * @return				SUCCESS if found, NOT_FOUND otherwise
+	 * @param item			the list item, if found, or NULL
+	 * @param ...			user data to supply to match function
+	 * @return				TRUE if found, FALSE otherwise (or if neither match,
+	 *						nor item is supplied)
 	 */
-	status_t (*find_first) (linked_list_t *this, linked_list_match_t match,
-							void **item, ...);
+	bool (*find_first)(linked_list_t *this, linked_list_match_t match,
+					   void **item, ...);
 
 	/**
 	 * Invoke a method on all of the contained objects.
@@ -192,22 +198,18 @@ struct linked_list_t {
 	 * which can be evalutated at compile time using the offsetof
 	 * macro, e.g.: list->invoke(list, offsetof(object_t, method));
 	 *
-	 * @warning Only use pointers as user supplied data.
-	 *
 	 * @param offset	offset of the method to invoke on objects
-	 * @param ...		user data to supply to called function (limited to 5 arguments)
 	 */
-	void (*invoke_offset) (linked_list_t *this, size_t offset, ...);
+	void (*invoke_offset)(linked_list_t *this, size_t offset);
 
 	/**
 	 * Invoke a function on all of the contained objects.
 	 *
-	 * @warning Only use pointers as user supplied data.
-	 *
-	 * @param function	offset of the method to invoke on objects
-	 * @param ...		user data to supply to called function (limited to 5 arguments)
+	 * @param function	function to call for each object
+	 * @param ...		user data to supply to called function
 	 */
-	void (*invoke_function) (linked_list_t *this, linked_list_invoke_t function, ...);
+	void (*invoke_function)(linked_list_t *this, linked_list_invoke_t function,
+							...);
 
 	/**
 	 * Clones a list and its objects using the objects' clone method.
diff --git a/src/libstrongswan/credentials/auth_cfg.c b/src/libstrongswan/credentials/auth_cfg.c
index 8a3e659..a9c8b39 100644
--- a/src/libstrongswan/credentials/auth_cfg.c
+++ b/src/libstrongswan/credentials/auth_cfg.c
@@ -146,12 +146,14 @@ typedef struct {
 	bool enumerated[AUTH_RULE_MAX];
 } entry_enumerator_t;
 
-/**
- * enumerate function for item_enumerator_t
- */
-static bool enumerate(entry_enumerator_t *this, auth_rule_t *type, void **value)
+METHOD(enumerator_t, enumerate, bool,
+	entry_enumerator_t *this, va_list args)
 {
+	auth_rule_t *type;
 	entry_t *entry;
+	void **value;
+
+	VA_ARGS_VGET(args, type, value);
 
 	while (this->inner->enumerate(this->inner, &entry))
 	{
@@ -174,10 +176,8 @@ static bool enumerate(entry_enumerator_t *this, auth_rule_t *type, void **value)
 	return FALSE;
 }
 
-/**
- * destroy function for item_enumerator_t
- */
-static void entry_enumerator_destroy(entry_enumerator_t *this)
+METHOD(enumerator_t, entry_enumerator_destroy, void,
+	entry_enumerator_t *this)
 {
 	this->inner->destroy(this->inner);
 	free(this);
@@ -190,8 +190,9 @@ METHOD(auth_cfg_t, create_enumerator, enumerator_t*,
 
 	INIT(enumerator,
 		.public = {
-			.enumerate = (void*)enumerate,
-			.destroy = (void*)entry_enumerator_destroy,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _enumerate,
+			.destroy = _entry_enumerator_destroy,
 		},
 		.inner = array_create_enumerator(this->entries),
 	);
diff --git a/src/libstrongswan/credentials/credential_factory.c b/src/libstrongswan/credentials/credential_factory.c
index 94c7820..07e6ea3 100644
--- a/src/libstrongswan/credentials/credential_factory.c
+++ b/src/libstrongswan/credentials/credential_factory.c
@@ -163,17 +163,23 @@ METHOD(credential_factory_t, create, void*,
 	return construct;
 }
 
-/**
- * Filter function for builder enumerator
- */
-static bool builder_filter(void *null, entry_t **entry, credential_type_t *type,
-						   void *dummy1, int *subtype)
+CALLBACK(builder_filter, bool,
+	void *null, enumerator_t *orig, va_list args)
 {
-	if ((*entry)->final)
+	entry_t *entry;
+	credential_type_t *type;
+	int *subtype;
+
+	VA_ARGS_VGET(args, type, subtype);
+
+	while (orig->enumerate(orig, &entry))
 	{
-		*type = (*entry)->type;
-		*subtype = (*entry)->subtype;
-		return TRUE;
+		if (entry->final)
+		{
+			*type = entry->type;
+			*subtype = entry->subtype;
+			return TRUE;
+		}
 	}
 	return FALSE;
 }
@@ -184,7 +190,7 @@ METHOD(credential_factory_t, create_builder_enumerator, enumerator_t*,
 	this->lock->read_lock(this->lock);
 	return enumerator_create_filter(
 				this->constructors->create_enumerator(this->constructors),
-				(void*)builder_filter, this->lock, (void*)this->lock->unlock);
+				builder_filter, this->lock, (void*)this->lock->unlock);
 }
 
 METHOD(credential_factory_t, destroy, void,
diff --git a/src/libstrongswan/credentials/credential_manager.c b/src/libstrongswan/credentials/credential_manager.c
index 95c5cd7..0a8d3d1 100644
--- a/src/libstrongswan/credentials/credential_manager.c
+++ b/src/libstrongswan/credentials/credential_manager.c
@@ -155,8 +155,12 @@ METHOD(credential_manager_t, call_hook, void,
 }
 
 METHOD(enumerator_t, sets_enumerate, bool,
-	sets_enumerator_t *this, credential_set_t **set)
+	sets_enumerator_t *this, va_list args)
 {
+	credential_set_t **set;
+
+	VA_ARGS_VGET(args, set);
+
 	if (this->exclusive)
 	{
 		if (this->exclusive->enumerate(this->exclusive, set))
@@ -166,19 +170,19 @@ METHOD(enumerator_t, sets_enumerate, bool,
 			return TRUE;
 		}
 	}
-	if (this->global)
+	if (this->local)
 	{
-		if (this->global->enumerate(this->global, set))
+		if (this->local->enumerate(this->local, set))
 		{
 			return TRUE;
 		}
-		/* end of global sets, look for local */
-		this->global->destroy(this->global);
-		this->global = NULL;
+		/* end of local sets, look for global */
+		this->local->destroy(this->local);
+		this->local = NULL;
 	}
-	if (this->local)
+	if (this->global)
 	{
-		return this->local->enumerate(this->local, set);
+		return this->global->enumerate(this->global, set);
 	}
 	return FALSE;
 }
@@ -202,7 +206,8 @@ static enumerator_t *create_sets_enumerator(private_credential_manager_t *this)
 
 	INIT(enumerator,
 		.public = {
-			.enumerate = (void*)_sets_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _sets_enumerate,
 			.destroy = _sets_destroy,
 		},
 	);
@@ -807,11 +812,12 @@ static bool verify_trust_chain(private_credential_manager_t *this,
 	return trusted;
 }
 
-/**
- * List find match function for certificates
- */
-static bool cert_equals(certificate_t *a, certificate_t *b)
+CALLBACK(cert_equals, bool,
+	certificate_t *a, va_list args)
 {
+	certificate_t *b;
+
+	VA_ARGS_VGET(args, b);
 	return a->equals(a, b);
 }
 
@@ -840,9 +846,12 @@ typedef struct {
 } trusted_enumerator_t;
 
 METHOD(enumerator_t, trusted_enumerate, bool,
-	trusted_enumerator_t *this, certificate_t **cert, auth_cfg_t **auth)
+	trusted_enumerator_t *this, va_list args)
 {
-	certificate_t *current;
+	certificate_t *current, **cert;
+	auth_cfg_t **auth;
+
+	VA_ARGS_VGET(args, cert, auth);
 
 	DESTROY_IF(this->auth);
 	this->auth = auth_cfg_create();
@@ -888,8 +897,7 @@ METHOD(enumerator_t, trusted_enumerate, bool,
 			continue;
 		}
 
-		if (this->failed->find_first(this->failed, (void*)cert_equals,
-									 NULL, current) == SUCCESS)
+		if (this->failed->find_first(this->failed, cert_equals, NULL, current))
 		{	/* check each candidate only once */
 			continue;
 		}
@@ -931,7 +939,8 @@ METHOD(credential_manager_t, create_trusted_enumerator, enumerator_t*,
 
 	INIT(enumerator,
 		.public = {
-			.enumerate = (void*)_trusted_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _trusted_enumerate,
 			.destroy = _trusted_destroy,
 		},
 		.this = this,
@@ -960,9 +969,13 @@ typedef struct {
 } public_enumerator_t;
 
 METHOD(enumerator_t, public_enumerate, bool,
-	public_enumerator_t *this, public_key_t **key, auth_cfg_t **auth)
+	public_enumerator_t *this, va_list args)
 {
 	certificate_t *cert;
+	public_key_t **key;
+	auth_cfg_t **auth;
+
+	VA_ARGS_VGET(args, key, auth);
 
 	while (this->inner->enumerate(this->inner, &cert, auth))
 	{
@@ -1001,7 +1014,8 @@ METHOD(credential_manager_t, create_public_enumerator, enumerator_t*,
 
 	INIT(enumerator,
 		.public = {
-			.enumerate = (void*)_public_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _public_enumerate,
 			.destroy = _public_destroy,
 		},
 		.inner = create_trusted_enumerator(this, type, id, online),
diff --git a/src/libstrongswan/credentials/keys/public_key.c b/src/libstrongswan/credentials/keys/public_key.c
index 2c76ad6..87f7e66 100644
--- a/src/libstrongswan/credentials/keys/public_key.c
+++ b/src/libstrongswan/credentials/keys/public_key.c
@@ -272,8 +272,12 @@ typedef struct  {
 } private_enumerator_t;
 
 METHOD(enumerator_t, signature_schemes_enumerate, bool,
-	private_enumerator_t *this, signature_scheme_t *scheme)
+	private_enumerator_t *this, va_list args)
 {
+	signature_scheme_t *scheme;
+
+	VA_ARGS_VGET(args, scheme);
+
 	while (++this->index < countof(scheme_map))
 	{
 		if (this->type == scheme_map[this->index].type &&
@@ -296,7 +300,8 @@ enumerator_t *signature_schemes_for_key(key_type_t type, int size)
 
 	INIT(this,
 		.public = {
-			.enumerate = (void*)_signature_schemes_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _signature_schemes_enumerate,
 			.destroy = (void*)free,
 		},
 		.index = -1,
diff --git a/src/libstrongswan/credentials/sets/auth_cfg_wrapper.c b/src/libstrongswan/credentials/sets/auth_cfg_wrapper.c
index 8393d5b..1cd4b9d 100644
--- a/src/libstrongswan/credentials/sets/auth_cfg_wrapper.c
+++ b/src/libstrongswan/credentials/sets/auth_cfg_wrapper.c
@@ -112,15 +112,15 @@ static bool fetch_cert(wrapper_enumerator_t *enumerator,
 	return TRUE;
 }
 
-/**
- * enumerate function for wrapper_enumerator_t
- */
-static bool enumerate(wrapper_enumerator_t *this, certificate_t **cert)
+METHOD(enumerator_t, enumerate, bool,
+	wrapper_enumerator_t *this, va_list args)
 {
 	auth_rule_t rule;
-	certificate_t *current;
+	certificate_t *current, **cert;
 	public_key_t *public;
 
+	VA_ARGS_VGET(args, cert);
+
 	while (this->inner->enumerate(this->inner, &rule, &current))
 	{
 		if (rule == AUTH_HELPER_IM_HASH_URL ||
@@ -164,10 +164,8 @@ static bool enumerate(wrapper_enumerator_t *this, certificate_t **cert)
 	return FALSE;
 }
 
-/**
- * destroy function for wrapper_enumerator_t
- */
-static void wrapper_enumerator_destroy(wrapper_enumerator_t *this)
+METHOD(enumerator_t, wrapper_enumerator_destroy, void,
+	wrapper_enumerator_t *this)
 {
 	this->inner->destroy(this->inner);
 	free(this);
@@ -183,14 +181,18 @@ METHOD(credential_set_t, create_enumerator, enumerator_t*,
 	{
 		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;
+	INIT(enumerator,
+		.public = {
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _enumerate,
+			.destroy = _wrapper_enumerator_destroy,
+		},
+		.auth = this->auth,
+		.cert = cert,
+		.key = key,
+		.id = id,
+		.inner = this->auth->create_enumerator(this->auth),
+	);
 	return &enumerator->public;
 }
 
diff --git a/src/libstrongswan/credentials/sets/callback_cred.c b/src/libstrongswan/credentials/sets/callback_cred.c
index bff33f0..0d72452 100644
--- a/src/libstrongswan/credentials/sets/callback_cred.c
+++ b/src/libstrongswan/credentials/sets/callback_cred.c
@@ -60,9 +60,12 @@ typedef struct {
 } shared_enumerator_t;
 
 METHOD(enumerator_t, shared_enumerate, bool,
-	shared_enumerator_t *this, shared_key_t **out,
-	id_match_t *match_me, id_match_t *match_other)
+	shared_enumerator_t *this, va_list args)
 {
+	shared_key_t **out;
+	id_match_t *match_me, *match_other;
+
+	VA_ARGS_VGET(args, out, match_me, match_other);
 	DESTROY_IF(this->current);
 	this->current = this->this->cb.shared(this->this->data, this->type,
 								this->me, this->other, match_me, match_other);
@@ -89,7 +92,8 @@ METHOD(credential_set_t, create_shared_enumerator, enumerator_t*,
 
 	INIT(enumerator,
 		.public = {
-			.enumerate = (void*)_shared_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _shared_enumerate,
 			.destroy = _shared_destroy,
 		},
 		.this = this,
diff --git a/src/libstrongswan/credentials/sets/cert_cache.c b/src/libstrongswan/credentials/sets/cert_cache.c
index 24fdb19..92d5efd 100644
--- a/src/libstrongswan/credentials/sets/cert_cache.c
+++ b/src/libstrongswan/credentials/sets/cert_cache.c
@@ -252,13 +252,14 @@ typedef struct {
 	int locked;
 } cert_enumerator_t;
 
-/**
- * filter function for certs enumerator
- */
-static bool cert_enumerate(cert_enumerator_t *this, certificate_t **out)
+METHOD(enumerator_t, cert_enumerate, bool,
+	cert_enumerator_t *this, va_list args)
 {
 	public_key_t *public;
 	relation_t *rel;
+	certificate_t **out;
+
+	VA_ARGS_VGET(args, out);
 
 	if (this->locked >= 0)
 	{
@@ -311,10 +312,8 @@ static bool cert_enumerate(cert_enumerator_t *this, certificate_t **out)
 	return FALSE;
 }
 
-/**
- * clean up enumeration data
- */
-static void cert_enumerator_destroy(cert_enumerator_t *this)
+METHOD(enumerator_t, cert_enumerator_destroy, void,
+	cert_enumerator_t *this)
 {
 	relation_t *rel;
 
@@ -336,16 +335,19 @@ METHOD(credential_set_t, create_enumerator, enumerator_t*,
 	{
 		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;
-
+	INIT(enumerator,
+		.public = {
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _cert_enumerate,
+			.destroy = _cert_enumerator_destroy,
+		},
+		.cert = cert,
+		.key = key,
+		.id = id,
+		.relations = this->relations,
+		.index = -1,
+		.locked = -1,
+	);
 	return &enumerator->public;
 }
 
diff --git a/src/libstrongswan/credentials/sets/mem_cred.c b/src/libstrongswan/credentials/sets/mem_cred.c
index 53e035f..4d594e4 100644
--- a/src/libstrongswan/credentials/sets/mem_cred.c
+++ b/src/libstrongswan/credentials/sets/mem_cred.c
@@ -74,25 +74,27 @@ typedef struct {
 	identification_t *id;
 } cert_data_t;
 
-/**
- * destroy cert_data
- */
-static void cert_data_destroy(cert_data_t *data)
+CALLBACK(cert_data_destroy, void,
+	cert_data_t *data)
 {
 	data->lock->unlock(data->lock);
 	free(data);
 }
 
-/**
- * filter function for certs enumerator
- */
-static bool certs_filter(cert_data_t *data, certificate_t **in, certificate_t **out)
+CALLBACK(certs_filter, bool,
+	cert_data_t *data, enumerator_t *orig, va_list args)
 {
 	public_key_t *public;
-	certificate_t *cert = *in;
+	certificate_t *cert, **out;
+
+	VA_ARGS_VGET(args, out);
 
-	if (data->cert == CERT_ANY || data->cert == cert->get_type(cert))
+	while (orig->enumerate(orig, &cert))
 	{
+		if (data->cert != CERT_ANY && data->cert != cert->get_type(cert))
+		{
+			continue;
+		}
 		public = cert->get_public_key(cert);
 		if (public)
 		{
@@ -102,7 +104,7 @@ static bool certs_filter(cert_data_t *data, certificate_t **in, certificate_t **
 											data->id->get_encoding(data->id)))
 				{
 					public->destroy(public);
-					*out = *in;
+					*out = cert;
 					return TRUE;
 				}
 			}
@@ -110,11 +112,11 @@ static bool certs_filter(cert_data_t *data, certificate_t **in, certificate_t **
 		}
 		else if (data->key != KEY_ANY)
 		{
-			return FALSE;
+			continue;
 		}
-		if (data->id == NULL || cert->has_subject(cert, data->id))
+		if (!data->id || cert->has_subject(cert, data->id))
 		{
-			*out = *in;
+			*out = cert;
 			return TRUE;
 		}
 	}
@@ -143,12 +145,16 @@ METHOD(credential_set_t, create_cert_enumerator, enumerator_t*,
 	{
 		enumerator = this->untrusted->create_enumerator(this->untrusted);
 	}
-	return enumerator_create_filter(enumerator, (void*)certs_filter, data,
-									(void*)cert_data_destroy);
+	return enumerator_create_filter(enumerator, certs_filter, data,
+									cert_data_destroy);
 }
 
-static bool certificate_equals(certificate_t *item, certificate_t *cert)
+CALLBACK(certificate_equals, bool,
+	certificate_t *item, va_list args)
 {
+	certificate_t *cert;
+
+	VA_ARGS_VGET(args, cert);
 	return item->equals(item, cert);
 }
 
@@ -161,9 +167,8 @@ static certificate_t *add_cert_internal(private_mem_cred_t *this, bool trusted,
 {
 	certificate_t *cached;
 	this->lock->write_lock(this->lock);
-	if (this->untrusted->find_first(this->untrusted,
-									(linked_list_match_t)certificate_equals,
-									(void**)&cached, cert) == SUCCESS)
+	if (this->untrusted->find_first(this->untrusted, certificate_equals,
+									(void**)&cached, cert))
 	{
 		cert->destroy(cert);
 		cert = cached->get_ref(cached);
@@ -199,9 +204,8 @@ METHOD(mem_cred_t, get_cert_ref, certificate_t*,
 	certificate_t *cached;
 
 	this->lock->read_lock(this->lock);
-	if (this->untrusted->find_first(this->untrusted,
-									(linked_list_match_t)certificate_equals,
-									(void**)&cached, cert) == SUCCESS)
+	if (this->untrusted->find_first(this->untrusted, certificate_equals,
+									(void**)&cached, cert))
 	{
 		cert->destroy(cert);
 		cert = cached->get_ref(cached);
@@ -301,30 +305,30 @@ typedef struct {
 	identification_t *id;
 } key_data_t;
 
-/**
- * Destroy key enumerator data
- */
-static void key_data_destroy(key_data_t *data)
+CALLBACK(key_data_destroy, void,
+	key_data_t *data)
 {
 	data->lock->unlock(data->lock);
 	free(data);
 }
 
-/**
- * filter function for private key enumerator
- */
-static bool key_filter(key_data_t *data, private_key_t **in, private_key_t **out)
+CALLBACK(key_filter, bool,
+	key_data_t *data, enumerator_t *orig, va_list args)
 {
-	private_key_t *key;
+	private_key_t *key, **out;
+
+	VA_ARGS_VGET(args, out);
 
-	key = *in;
-	if (data->type == KEY_ANY || data->type == key->get_type(key))
+	while (orig->enumerate(orig, &key))
 	{
-		if (data->id == NULL ||
-			key->has_fingerprint(key, data->id->get_encoding(data->id)))
+		if (data->type == KEY_ANY || data->type == key->get_type(key))
 		{
-			*out = key;
-			return TRUE;
+			if (data->id == NULL ||
+				key->has_fingerprint(key, data->id->get_encoding(data->id)))
+			{
+				*out = key;
+				return TRUE;
+			}
 		}
 	}
 	return FALSE;
@@ -342,7 +346,7 @@ METHOD(credential_set_t, create_private_enumerator, enumerator_t*,
 	);
 	this->lock->read_lock(this->lock);
 	return enumerator_create_filter(this->keys->create_enumerator(this->keys),
-							(void*)key_filter, data, (void*)key_data_destroy);
+									key_filter, data, key_data_destroy);
 }
 
 METHOD(mem_cred_t, add_key, void,
@@ -468,10 +472,8 @@ typedef struct {
 	shared_key_type_t type;
 } shared_data_t;
 
-/**
- * free shared key enumerator data and unlock list
- */
-static void shared_data_destroy(shared_data_t *data)
+CALLBACK(shared_data_destroy, void,
+	shared_data_t *data)
 {
 	data->lock->unlock(data->lock);
 	free(data);
@@ -499,44 +501,47 @@ static id_match_t has_owner(shared_entry_t *entry, identification_t *owner)
 	return best;
 }
 
-/**
- * enumerator filter function for shared entries
- */
-static bool shared_filter(shared_data_t *data,
-						  shared_entry_t **in, shared_key_t **out,
-						  void **unused1, id_match_t *me,
-						  void **unused2, id_match_t *other)
+CALLBACK(shared_filter, bool,
+	shared_data_t *data, enumerator_t *orig, va_list args)
 {
 	id_match_t my_match = ID_MATCH_NONE, other_match = ID_MATCH_NONE;
-	shared_entry_t *entry = *in;
+	shared_entry_t *entry;
+	shared_key_t **out;
+	id_match_t *me, *other;
 
-	if (data->type != SHARED_ANY &&
-		entry->shared->get_type(entry->shared) != data->type)
-	{
-		return FALSE;
-	}
-	if (data->me)
-	{
-		my_match = has_owner(entry, data->me);
-	}
-	if (data->other)
-	{
-		other_match = has_owner(entry, data->other);
-	}
-	if ((data->me || data->other) && (!my_match && !other_match))
-	{
-		return FALSE;
-	}
-	*out = entry->shared;
-	if (me)
-	{
-		*me = my_match;
-	}
-	if (other)
+	VA_ARGS_VGET(args, out, me, other);
+
+	while (orig->enumerate(orig, &entry))
 	{
-		*other = other_match;
+		if (data->type != SHARED_ANY &&
+			entry->shared->get_type(entry->shared) != data->type)
+		{
+			continue;
+		}
+		if (data->me)
+		{
+			my_match = has_owner(entry, data->me);
+		}
+		if (data->other)
+		{
+			other_match = has_owner(entry, data->other);
+		}
+		if ((data->me || data->other) && (!my_match && !other_match))
+		{
+			continue;
+		}
+		*out = entry->shared;
+		if (me)
+		{
+			*me = my_match;
+		}
+		if (other)
+		{
+			*other = other_match;
+		}
+		return TRUE;
 	}
-	return TRUE;
+	return FALSE;
 }
 
 METHOD(credential_set_t, create_shared_enumerator, enumerator_t*,
@@ -554,7 +559,7 @@ METHOD(credential_set_t, create_shared_enumerator, enumerator_t*,
 	data->lock->read_lock(data->lock);
 	return enumerator_create_filter(
 						this->shared->create_enumerator(this->shared),
-						(void*)shared_filter, data, (void*)shared_data_destroy);
+						shared_filter, data, shared_data_destroy);
 }
 
 METHOD(mem_cred_t, add_shared_unique, void,
@@ -648,23 +653,27 @@ METHOD(mem_cred_t, remove_shared_unique, void,
 	this->lock->unlock(this->lock);
 }
 
-/**
- * Filter unique ids of shared keys (ingore secrets without unique id)
- */
-static bool unique_filter(void *unused,
-						  shared_entry_t **in, char **id)
+CALLBACK(unique_filter, bool,
+	void *unused, enumerator_t *orig, va_list args)
 {
-	shared_entry_t *entry = *in;
+	shared_entry_t *entry;
+	char **id;
 
-	if (!entry->id)
-	{
-		return FALSE;
-	}
-	if (id)
+	VA_ARGS_VGET(args, id);
+
+	while (orig->enumerate(orig, &entry))
 	{
-		*id = entry->id;
+		if (!entry->id)
+		{
+			continue;
+		}
+		if (id)
+		{
+			*id = entry->id;
+		}
+		return TRUE;
 	}
-	return TRUE;
+	return FALSE;
 }
 
 METHOD(mem_cred_t, create_unique_shared_enumerator, enumerator_t*,
@@ -673,7 +682,7 @@ METHOD(mem_cred_t, create_unique_shared_enumerator, enumerator_t*,
 	this->lock->read_lock(this->lock);
 	return enumerator_create_filter(
 								this->shared->create_enumerator(this->shared),
-								(void*)unique_filter, this->lock,
+								unique_filter, this->lock,
 								(void*)this->lock->unlock);
 }
 
@@ -721,30 +730,35 @@ typedef struct {
 	rwlock_t *lock;
 } cdp_data_t;
 
-/**
- * Clean up CDP enumerator data
- */
-static void cdp_data_destroy(cdp_data_t *data)
+CALLBACK(cdp_data_destroy, void,
+	cdp_data_t *data)
 {
 	data->lock->unlock(data->lock);
 	free(data);
 }
 
-/**
- * CDP enumerator filter
- */
-static bool cdp_filter(cdp_data_t *data, cdp_t **cdp, char **uri)
+CALLBACK(cdp_filter, bool,
+	cdp_data_t *data, enumerator_t *orig, va_list args)
 {
-	if (data->type != CERT_ANY && data->type != (*cdp)->type)
-	{
-		return FALSE;
-	}
-	if (data->id && !(*cdp)->id->matches((*cdp)->id, data->id))
+	cdp_t *cdp;
+	char **uri;
+
+	VA_ARGS_VGET(args, uri);
+
+	while (orig->enumerate(orig, &cdp))
 	{
-		return FALSE;
+		if (data->type != CERT_ANY && data->type != cdp->type)
+		{
+			continue;
+		}
+		if (data->id && !cdp->id->matches(cdp->id, data->id))
+		{
+			continue;
+		}
+		*uri = cdp->uri;
+		return TRUE;
 	}
-	*uri = (*cdp)->uri;
-	return TRUE;
+	return FALSE;
 }
 
 METHOD(credential_set_t, create_cdp_enumerator, enumerator_t*,
@@ -759,7 +773,7 @@ METHOD(credential_set_t, create_cdp_enumerator, enumerator_t*,
 	);
 	this->lock->read_lock(this->lock);
 	return enumerator_create_filter(this->cdps->create_enumerator(this->cdps),
-							(void*)cdp_filter, data, (void*)cdp_data_destroy);
+									cdp_filter, data, cdp_data_destroy);
 
 }
 
diff --git a/src/libstrongswan/credentials/sets/mem_cred.h b/src/libstrongswan/credentials/sets/mem_cred.h
index 1355152..f55c3cc 100644
--- a/src/libstrongswan/credentials/sets/mem_cred.h
+++ b/src/libstrongswan/credentials/sets/mem_cred.h
@@ -62,7 +62,7 @@ struct mem_cred_t {
 	/**
 	 * Get an existing reference to the same certificate.
 	 *
-	 * Searches for the same certficate in the set, and returns a reference
+	 * Searches for the same certificate in the set, and returns a reference
 	 * to it, destroying the passed certificate. If the passed certificate
 	 * is not found, it is just returned.
 	 *
diff --git a/src/libstrongswan/credentials/sets/ocsp_response_wrapper.c b/src/libstrongswan/credentials/sets/ocsp_response_wrapper.c
index 151d692..12d3f81 100644
--- a/src/libstrongswan/credentials/sets/ocsp_response_wrapper.c
+++ b/src/libstrongswan/credentials/sets/ocsp_response_wrapper.c
@@ -49,14 +49,15 @@ typedef struct {
 	identification_t *id;
 } wrapper_enumerator_t;
 
-/**
- * enumerate function wrapper_enumerator_t
- */
-static bool enumerate(wrapper_enumerator_t *this, certificate_t **cert)
+METHOD(enumerator_t, enumerate, bool,
+	wrapper_enumerator_t *this, va_list args)
 {
-	certificate_t *current;
+	certificate_t *current, **cert;
 	public_key_t *public;
 
+
+	VA_ARGS_VGET(args, cert);
+
 	while (this->inner->enumerate(this->inner, &current))
 	{
 		if (this->cert != CERT_ANY && this->cert != current->get_type(current))
@@ -85,10 +86,8 @@ static bool enumerate(wrapper_enumerator_t *this, certificate_t **cert)
 	return FALSE;
 }
 
-/**
- * destroy function for wrapper_enumerator_t
- */
-static void enumerator_destroy(wrapper_enumerator_t *this)
+METHOD(enumerator_t, enumerator_destroy, void,
+	wrapper_enumerator_t *this)
 {
 	this->inner->destroy(this->inner);
 	free(this);
@@ -105,13 +104,17 @@ METHOD(credential_set_t, create_enumerator, enumerator_t*,
 		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;
+	INIT(enumerator,
+		.public = {
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _enumerate,
+			.destroy = _enumerator_destroy,
+		},
+		.cert = cert,
+		.key = key,
+		.id = id,
+		.inner = this->response->create_cert_enumerator(this->response),
+	);
 	return &enumerator->public;
 }
 
diff --git a/src/libstrongswan/crypto/crypto_factory.c b/src/libstrongswan/crypto/crypto_factory.c
index bab59a0..096bcbc 100644
--- a/src/libstrongswan/crypto/crypto_factory.c
+++ b/src/libstrongswan/crypto/crypto_factory.c
@@ -811,51 +811,66 @@ METHOD(crypto_factory_t, remove_dh, void,
 	this->lock->unlock(this->lock);
 }
 
-/**
- * match algorithms of an entry?
- */
-static bool entry_match(entry_t *a, entry_t *b)
+CALLBACK(entry_match, bool,
+	entry_t *a, va_list args)
 {
+	entry_t *b;
+
+	VA_ARGS_VGET(args, b);
 	return a->algo == b->algo;
 }
 
-/**
- * check for uniqueness of an entry
- */
-static bool unique_check(linked_list_t *list, entry_t **in, entry_t **out)
+CALLBACK(unique_check, bool,
+	linked_list_t *list, enumerator_t *orig, va_list args)
 {
-	if (list->find_first(list, (void*)entry_match, NULL, *in) == SUCCESS)
+	entry_t *entry, **out;
+
+	VA_ARGS_VGET(args, out);
+
+	while (orig->enumerate(orig, &entry))
 	{
-		return FALSE;
+		if (list->find_first(list, entry_match, NULL, entry))
+		{
+			continue;
+		}
+		*out = entry;
+		list->insert_last(list, entry);
+		return TRUE;
 	}
-	*out = *in;
-	list->insert_last(list, *in);
-	return TRUE;
+	return FALSE;
 }
 
 /**
  * create an enumerator over entry->algo in list with locking and unique check
  */
 static enumerator_t *create_enumerator(private_crypto_factory_t *this,
-									   linked_list_t *list, void *filter)
+									linked_list_t *list,
+									bool (*filter)(void*,enumerator_t*,va_list))
 {
 	this->lock->read_lock(this->lock);
 	return enumerator_create_filter(
 				enumerator_create_filter(
-					list->create_enumerator(list), (void*)unique_check,
+					list->create_enumerator(list), unique_check,
 					linked_list_create(), (void*)list->destroy),
 				filter,	this->lock, (void*)this->lock->unlock);
 }
 
-/**
- * Filter function to enumerate algorithm, not entry
- */
-static bool crypter_filter(void *n, entry_t **entry, encryption_algorithm_t *algo,
-						   void *i2, const char **plugin_name)
+CALLBACK(crypter_filter, bool,
+	void *n, enumerator_t *orig, va_list args)
 {
-	*algo = (*entry)->algo;
-	*plugin_name = (*entry)->plugin_name;
-	return TRUE;
+	entry_t *entry;
+	encryption_algorithm_t *algo;
+	const char **plugin_name;
+
+	VA_ARGS_VGET(args, algo, plugin_name);
+
+	if (orig->enumerate(orig, &entry))
+	{
+		*algo = entry->algo;
+		*plugin_name = entry->plugin_name;
+		return TRUE;
+	}
+	return FALSE;
 }
 
 METHOD(crypto_factory_t, create_crypter_enumerator, enumerator_t*,
@@ -870,15 +885,22 @@ METHOD(crypto_factory_t, create_aead_enumerator, enumerator_t*,
 	return create_enumerator(this, this->aeads, crypter_filter);
 }
 
-/**
- * Filter function to enumerate algorithm, not entry
- */
-static bool signer_filter(void *n, entry_t **entry, integrity_algorithm_t *algo,
-						  void *i2, const char **plugin_name)
+CALLBACK(signer_filter, bool,
+	void *n, enumerator_t *orig, va_list args)
 {
-	*algo = (*entry)->algo;
-	*plugin_name = (*entry)->plugin_name;
-	return TRUE;
+	entry_t *entry;
+	integrity_algorithm_t *algo;
+	const char **plugin_name;
+
+	VA_ARGS_VGET(args, algo, plugin_name);
+
+	if (orig->enumerate(orig, &entry))
+	{
+		*algo = entry->algo;
+		*plugin_name = entry->plugin_name;
+		return TRUE;
+	}
+	return FALSE;
 }
 
 METHOD(crypto_factory_t, create_signer_enumerator, enumerator_t*,
@@ -887,15 +909,22 @@ METHOD(crypto_factory_t, create_signer_enumerator, enumerator_t*,
 	return create_enumerator(this, this->signers, signer_filter);
 }
 
-/**
- * Filter function to enumerate algorithm, not entry
- */
-static bool hasher_filter(void *n, entry_t **entry, hash_algorithm_t *algo,
-						  void *i2, const char **plugin_name)
+CALLBACK(hasher_filter, bool,
+	void *n, enumerator_t *orig, va_list args)
 {
-	*algo = (*entry)->algo;
-	*plugin_name = (*entry)->plugin_name;
-	return TRUE;
+	entry_t *entry;
+	hash_algorithm_t *algo;
+	const char **plugin_name;
+
+	VA_ARGS_VGET(args, algo, plugin_name);
+
+	if (orig->enumerate(orig, &entry))
+	{
+		*algo = entry->algo;
+		*plugin_name = entry->plugin_name;
+		return TRUE;
+	}
+	return FALSE;
 }
 
 METHOD(crypto_factory_t, create_hasher_enumerator, enumerator_t*,
@@ -904,15 +933,22 @@ METHOD(crypto_factory_t, create_hasher_enumerator, enumerator_t*,
 	return create_enumerator(this, this->hashers, hasher_filter);
 }
 
-/**
- * Filter function to enumerate algorithm, not entry
- */
-static bool prf_filter(void *n, entry_t **entry, pseudo_random_function_t *algo,
-					   void *i2, const char **plugin_name)
+CALLBACK(prf_filter, bool,
+	void *n, enumerator_t *orig, va_list args)
 {
-	*algo = (*entry)->algo;
-	*plugin_name = (*entry)->plugin_name;
-	return TRUE;
+	entry_t *entry;
+	pseudo_random_function_t *algo;
+	const char **plugin_name;
+
+	VA_ARGS_VGET(args, algo, plugin_name);
+
+	if (orig->enumerate(orig, &entry))
+	{
+		*algo = entry->algo;
+		*plugin_name = entry->plugin_name;
+		return TRUE;
+	}
+	return FALSE;
 }
 
 METHOD(crypto_factory_t, create_prf_enumerator, enumerator_t*,
@@ -921,15 +957,22 @@ METHOD(crypto_factory_t, create_prf_enumerator, enumerator_t*,
 	return create_enumerator(this, this->prfs, prf_filter);
 }
 
-/**
- * Filter function to enumerate algorithm, not entry
- */
-static bool xof_filter(void *n, entry_t **entry, ext_out_function_t *algo,
-					   void *i2, const char **plugin_name)
+CALLBACK(xof_filter, bool,
+	void *n, enumerator_t *orig, va_list args)
 {
-	*algo = (*entry)->algo;
-	*plugin_name = (*entry)->plugin_name;
-	return TRUE;
+	entry_t *entry;
+	ext_out_function_t *algo;
+	const char **plugin_name;
+
+	VA_ARGS_VGET(args, algo, plugin_name);
+
+	if (orig->enumerate(orig, &entry))
+	{
+		*algo = entry->algo;
+		*plugin_name = entry->plugin_name;
+		return TRUE;
+	}
+	return FALSE;
 }
 
 METHOD(crypto_factory_t, create_xof_enumerator, enumerator_t*,
@@ -938,15 +981,22 @@ METHOD(crypto_factory_t, create_xof_enumerator, enumerator_t*,
 	return create_enumerator(this, this->xofs, xof_filter);
 }
 
-/**
- * Filter function to enumerate group, not entry
- */
-static bool dh_filter(void *n, entry_t **entry, diffie_hellman_group_t *group,
-					  void *i2, const char **plugin_name)
+CALLBACK(dh_filter, bool,
+	void *n, enumerator_t *orig, va_list args)
 {
-	*group = (*entry)->algo;
-	*plugin_name = (*entry)->plugin_name;
-	return TRUE;
+	entry_t *entry;
+	diffie_hellman_group_t *algo;
+	const char **plugin_name;
+
+	VA_ARGS_VGET(args, algo, plugin_name);
+
+	if (orig->enumerate(orig, &entry))
+	{
+		*algo = entry->algo;
+		*plugin_name = entry->plugin_name;
+		return TRUE;
+	}
+	return FALSE;
 }
 
 METHOD(crypto_factory_t, create_dh_enumerator, enumerator_t*,
@@ -955,15 +1005,22 @@ METHOD(crypto_factory_t, create_dh_enumerator, enumerator_t*,
 	return create_enumerator(this, this->dhs, dh_filter);
 }
 
-/**
- * Filter function to enumerate strength, not entry
- */
-static bool rng_filter(void *n, entry_t **entry, rng_quality_t *quality,
-					   void *i2, const char **plugin_name)
+CALLBACK(rng_filter, bool,
+	void *n, enumerator_t *orig, va_list args)
 {
-	*quality = (*entry)->algo;
-	*plugin_name = (*entry)->plugin_name;
-	return TRUE;
+	entry_t *entry;
+	rng_quality_t *algo;
+	const char **plugin_name;
+
+	VA_ARGS_VGET(args, algo, plugin_name);
+
+	if (orig->enumerate(orig, &entry))
+	{
+		*algo = entry->algo;
+		*plugin_name = entry->plugin_name;
+		return TRUE;
+	}
+	return FALSE;
 }
 
 METHOD(crypto_factory_t, create_rng_enumerator, enumerator_t*,
@@ -972,13 +1029,20 @@ METHOD(crypto_factory_t, create_rng_enumerator, enumerator_t*,
 	return create_enumerator(this, this->rngs, rng_filter);
 }
 
-/**
- * Filter function to enumerate plugin name, not entry
- */
-static bool nonce_gen_filter(void *n, entry_t **entry, const char **plugin_name)
+CALLBACK(nonce_gen_filter, bool,
+	void *n, enumerator_t *orig, va_list args)
 {
-	*plugin_name = (*entry)->plugin_name;
-	return TRUE;
+	entry_t *entry;
+	const char **plugin_name;
+
+	VA_ARGS_VGET(args, plugin_name);
+
+	if (orig->enumerate(orig, &entry))
+	{
+		*plugin_name = entry->plugin_name;
+		return TRUE;
+	}
+	return FALSE;
 }
 
 METHOD(crypto_factory_t, create_nonce_gen_enumerator, enumerator_t*,
@@ -1026,9 +1090,14 @@ typedef struct {
 } verify_enumerator_t;
 
 METHOD(enumerator_t, verify_enumerate, bool,
-	verify_enumerator_t *this, u_int *alg, const char **plugin, bool *valid)
+	verify_enumerator_t *this, va_list args)
 {
+	const char **plugin;
 	entry_t *entry;
+	u_int *alg;
+	bool *valid;
+
+	VA_ARGS_VGET(args, alg, plugin, valid);
 
 	if (!this->inner->enumerate(this->inner, &entry))
 	{
@@ -1123,7 +1192,8 @@ METHOD(crypto_factory_t, create_verify_enumerator, enumerator_t*,
 	}
 	INIT(enumerator,
 		.public = {
-			.enumerate = (void*)_verify_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _verify_enumerate,
 			.destroy = _verify_destroy,
 		},
 		.inner = inner,
diff --git a/src/libstrongswan/crypto/hashers/hash_algorithm_set.c b/src/libstrongswan/crypto/hashers/hash_algorithm_set.c
index 93b67cb..4087fe1 100644
--- a/src/libstrongswan/crypto/hashers/hash_algorithm_set.c
+++ b/src/libstrongswan/crypto/hashers/hash_algorithm_set.c
@@ -71,17 +71,26 @@ METHOD(hash_algorithm_set_t, count, int,
 	return array_count(this->algorithms);
 }
 
-static bool hash_filter(void *data, void **in, hash_algorithm_t *out)
+CALLBACK(hash_filter, bool,
+	void *data, enumerator_t *orig, va_list args)
 {
-	*out = **(hash_algorithm_t**)in;
-	return TRUE;
+	hash_algorithm_t *algo, *out;
+
+	VA_ARGS_VGET(args, out);
+
+	if (orig->enumerate(orig, &algo))
+	{
+		*out = *algo;
+		return TRUE;
+	}
+	return FALSE;
 }
 
 METHOD(hash_algorithm_set_t, create_enumerator, enumerator_t*,
 	private_hash_algorithm_set_t *this)
 {
 	return enumerator_create_filter(array_create_enumerator(this->algorithms),
-									(void*)hash_filter, NULL, NULL);
+									hash_filter, NULL, NULL);
 }
 
 METHOD(hash_algorithm_set_t, destroy, void,
diff --git a/src/libstrongswan/library.c b/src/libstrongswan/library.c
index 4f79dcc..7944b93 100644
--- a/src/libstrongswan/library.c
+++ b/src/libstrongswan/library.c
@@ -94,6 +94,13 @@ void library_add_namespace(char *ns)
 }
 
 /**
+ * Register plugins if built statically
+ */
+#ifdef STATIC_PLUGIN_CONSTRUCTORS
+#include "plugin_constructors.c"
+#endif
+
+/**
  * library instance
  */
 library_t *lib = NULL;
@@ -241,6 +248,8 @@ static bool equals(char *a, char *b)
  */
 #define MEMWIPE_WIPE_WORDS 16
 
+#ifndef NO_CHECK_MEMWIPE
+
 /**
  * Write magic to memory, and try to clear it with memwipe()
  */
@@ -281,6 +290,8 @@ static bool check_memwipe()
 	return TRUE;
 }
 
+#endif
+
 /*
  * see header file
  */
@@ -387,10 +398,12 @@ bool library_init(char *settings, const char *namespace)
 	this->public.streams = stream_manager_create();
 	this->public.plugins = plugin_loader_create();
 
+#ifndef NO_CHECK_MEMWIPE
 	if (!check_memwipe())
 	{
 		return FALSE;
 	}
+#endif
 
 	if (lib->settings->get_bool(lib->settings,
 								"%s.integrity_test", FALSE, lib->ns))
diff --git a/src/libstrongswan/math/libnttfft/Makefile.in b/src/libstrongswan/math/libnttfft/Makefile.in
index ff41f9b..93bd935 100644
--- a/src/libstrongswan/math/libnttfft/Makefile.in
+++ b/src/libstrongswan/math/libnttfft/Makefile.in
@@ -349,6 +349,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -371,6 +372,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/math/libnttfft/tests/Makefile.in b/src/libstrongswan/math/libnttfft/tests/Makefile.in
index 4f85449..80ecd3e 100644
--- a/src/libstrongswan/math/libnttfft/tests/Makefile.in
+++ b/src/libstrongswan/math/libnttfft/tests/Makefile.in
@@ -353,6 +353,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -375,6 +376,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/networking/tun_device.c b/src/libstrongswan/networking/tun_device.c
index de92555..86951f1 100644
--- a/src/libstrongswan/networking/tun_device.c
+++ b/src/libstrongswan/networking/tun_device.c
@@ -21,7 +21,16 @@
 #include <utils/debug.h>
 #include <threading/thread.h>
 
-#if !defined(__APPLE__) && !defined(__linux__) && !defined(HAVE_NET_IF_TUN_H)
+#if defined(__APPLE__)
+#include "TargetConditionals.h"
+#if !TARGET_OS_OSX
+#define TUN_DEVICE_NOT_SUPPORTED
+#endif
+#elif !defined(__linux__) && !defined(HAVE_NET_IF_TUN_H)
+#define TUN_DEVICE_NOT_SUPPORTED
+#endif
+
+#ifdef TUN_DEVICE_NOT_SUPPORTED
 
 tun_device_t *tun_device_create(const char *name_tmpl)
 {
@@ -481,10 +490,25 @@ static bool init_tun(private_tun_device_t *this, const char *name_tmpl)
 	strncpy(this->if_name, ifr.ifr_name, IFNAMSIZ);
 	return TRUE;
 
-#else /* !IFF_TUN */
+#elif defined(__FreeBSD__)
+
+	if (name_tmpl)
+	{
+		DBG1(DBG_LIB, "arbitrary naming of TUN devices is not supported");
+	}
+
+	this->tunfd = open("/dev/tun", O_RDWR);
+	if (this->tunfd < 0)
+	{
+		DBG1(DBG_LIB, "failed to open /dev/tun: %s", strerror(errno));
+		return FALSE;
+	}
+	fdevname_r(this->tunfd, this->if_name, IFNAMSIZ);
+	return TRUE;
+
+#else /* !__FreeBSD__ */
 
-	/* this works on FreeBSD and might also work on Linux with older TUN
-	 * driver versions (no IFF_TUN) */
+	/* this might work on Linux with older TUN driver versions (no IFF_TUN) */
 	char devname[IFNAMSIZ];
 	/* the same process is allowed to open a device again, but that's not what
 	 * we want (unless we previously closed a device, which we don't know at
diff --git a/src/libstrongswan/plugins/acert/Makefile.in b/src/libstrongswan/plugins/acert/Makefile.in
index ee69a89..1dcc048 100644
--- a/src/libstrongswan/plugins/acert/Makefile.in
+++ b/src/libstrongswan/plugins/acert/Makefile.in
@@ -356,6 +356,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -378,6 +379,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/aes/Makefile.in b/src/libstrongswan/plugins/aes/Makefile.in
index 0a8046b..2b16ae7 100644
--- a/src/libstrongswan/plugins/aes/Makefile.in
+++ b/src/libstrongswan/plugins/aes/Makefile.in
@@ -355,6 +355,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -377,6 +378,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/aesni/Makefile.in b/src/libstrongswan/plugins/aesni/Makefile.in
index ceb8676..d32e7f5 100644
--- a/src/libstrongswan/plugins/aesni/Makefile.in
+++ b/src/libstrongswan/plugins/aesni/Makefile.in
@@ -358,6 +358,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/af_alg/Makefile.in b/src/libstrongswan/plugins/af_alg/Makefile.in
index bad31ca..e931402 100644
--- a/src/libstrongswan/plugins/af_alg/Makefile.in
+++ b/src/libstrongswan/plugins/af_alg/Makefile.in
@@ -359,6 +359,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -381,6 +382,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/af_alg/af_alg_ops.c b/src/libstrongswan/plugins/af_alg/af_alg_ops.c
index 7e12930..2fa6872 100644
--- a/src/libstrongswan/plugins/af_alg/af_alg_ops.c
+++ b/src/libstrongswan/plugins/af_alg/af_alg_ops.c
@@ -107,7 +107,7 @@ METHOD(af_alg_ops_t, hash, bool,
 	return TRUE;
 }
 
-METHOD(af_alg_ops_t, crypt, bool,
+METHOD(af_alg_ops_t, crypt_, bool,
 	private_af_alg_ops_t *this, uint32_t type, chunk_t iv, chunk_t data,
 	char *out)
 {
@@ -224,7 +224,7 @@ af_alg_ops_t *af_alg_ops_create(char *type, char *alg)
 		.public = {
 			.hash = _hash,
 			.reset = _reset,
-			.crypt = _crypt,
+			.crypt = _crypt_,
 			.set_key = _set_key,
 			.destroy = _destroy,
 		},
diff --git a/src/libstrongswan/plugins/agent/Makefile.in b/src/libstrongswan/plugins/agent/Makefile.in
index cd9036b..a4e7e29 100644
--- a/src/libstrongswan/plugins/agent/Makefile.in
+++ b/src/libstrongswan/plugins/agent/Makefile.in
@@ -357,6 +357,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -379,6 +380,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/bliss/Makefile.in b/src/libstrongswan/plugins/bliss/Makefile.in
index 918a018..a6caf7b 100644
--- a/src/libstrongswan/plugins/bliss/Makefile.in
+++ b/src/libstrongswan/plugins/bliss/Makefile.in
@@ -380,6 +380,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -402,6 +403,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/bliss/tests/Makefile.in b/src/libstrongswan/plugins/bliss/tests/Makefile.in
index 1964f19..5dbaf9b 100644
--- a/src/libstrongswan/plugins/bliss/tests/Makefile.in
+++ b/src/libstrongswan/plugins/bliss/tests/Makefile.in
@@ -359,6 +359,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -381,6 +382,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/blowfish/Makefile.in b/src/libstrongswan/plugins/blowfish/Makefile.in
index c2bc5ac..0876475 100644
--- a/src/libstrongswan/plugins/blowfish/Makefile.in
+++ b/src/libstrongswan/plugins/blowfish/Makefile.in
@@ -358,6 +358,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/ccm/Makefile.in b/src/libstrongswan/plugins/ccm/Makefile.in
index f0065d0..5f768ec 100644
--- a/src/libstrongswan/plugins/ccm/Makefile.in
+++ b/src/libstrongswan/plugins/ccm/Makefile.in
@@ -355,6 +355,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -377,6 +378,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/chapoly/Makefile.in b/src/libstrongswan/plugins/chapoly/Makefile.in
index 3e1d634..12ad6f1 100644
--- a/src/libstrongswan/plugins/chapoly/Makefile.in
+++ b/src/libstrongswan/plugins/chapoly/Makefile.in
@@ -370,6 +370,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -392,6 +393,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/cmac/Makefile.in b/src/libstrongswan/plugins/cmac/Makefile.in
index 77d68bd..c6bb24a 100644
--- a/src/libstrongswan/plugins/cmac/Makefile.in
+++ b/src/libstrongswan/plugins/cmac/Makefile.in
@@ -355,6 +355,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -377,6 +378,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/constraints/Makefile.in b/src/libstrongswan/plugins/constraints/Makefile.in
index edd519f..aa2fd79 100644
--- a/src/libstrongswan/plugins/constraints/Makefile.in
+++ b/src/libstrongswan/plugins/constraints/Makefile.in
@@ -358,6 +358,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/ctr/Makefile.in b/src/libstrongswan/plugins/ctr/Makefile.in
index a9d0b2e..d112676 100644
--- a/src/libstrongswan/plugins/ctr/Makefile.in
+++ b/src/libstrongswan/plugins/ctr/Makefile.in
@@ -355,6 +355,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -377,6 +378,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/curl/Makefile.in b/src/libstrongswan/plugins/curl/Makefile.in
index 996d258..2aedb2f 100644
--- a/src/libstrongswan/plugins/curl/Makefile.in
+++ b/src/libstrongswan/plugins/curl/Makefile.in
@@ -355,6 +355,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -377,6 +378,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/curve25519/Makefile.in b/src/libstrongswan/plugins/curve25519/Makefile.in
index 1fa2b17..616f3d8 100644
--- a/src/libstrongswan/plugins/curve25519/Makefile.in
+++ b/src/libstrongswan/plugins/curve25519/Makefile.in
@@ -362,6 +362,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -384,6 +385,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/des/Makefile.in b/src/libstrongswan/plugins/des/Makefile.in
index b6cedd8..c3f3775 100644
--- a/src/libstrongswan/plugins/des/Makefile.in
+++ b/src/libstrongswan/plugins/des/Makefile.in
@@ -355,6 +355,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -377,6 +378,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/dnskey/Makefile.in b/src/libstrongswan/plugins/dnskey/Makefile.in
index 347c697..26c69e2 100644
--- a/src/libstrongswan/plugins/dnskey/Makefile.in
+++ b/src/libstrongswan/plugins/dnskey/Makefile.in
@@ -358,6 +358,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/files/Makefile.in b/src/libstrongswan/plugins/files/Makefile.in
index 10cbc6e..d8c7dae 100644
--- a/src/libstrongswan/plugins/files/Makefile.in
+++ b/src/libstrongswan/plugins/files/Makefile.in
@@ -356,6 +356,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -378,6 +379,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/fips_prf/Makefile.in b/src/libstrongswan/plugins/fips_prf/Makefile.in
index 8b5e162..45934d7 100644
--- a/src/libstrongswan/plugins/fips_prf/Makefile.in
+++ b/src/libstrongswan/plugins/fips_prf/Makefile.in
@@ -357,6 +357,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -379,6 +380,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/gcm/Makefile.in b/src/libstrongswan/plugins/gcm/Makefile.in
index 0f3878f..5d6c1a4 100644
--- a/src/libstrongswan/plugins/gcm/Makefile.in
+++ b/src/libstrongswan/plugins/gcm/Makefile.in
@@ -355,6 +355,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -377,6 +378,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/gcrypt/Makefile.in b/src/libstrongswan/plugins/gcrypt/Makefile.in
index ef246f9..26930dc 100644
--- a/src/libstrongswan/plugins/gcrypt/Makefile.in
+++ b/src/libstrongswan/plugins/gcrypt/Makefile.in
@@ -359,6 +359,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -381,6 +382,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/gmp/Makefile.in b/src/libstrongswan/plugins/gmp/Makefile.in
index de8f8fe..2fcdce7 100644
--- a/src/libstrongswan/plugins/gmp/Makefile.in
+++ b/src/libstrongswan/plugins/gmp/Makefile.in
@@ -356,6 +356,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -378,6 +379,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c b/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c
index 2b2c7f2..32a72ac 100644
--- a/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c
+++ b/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c
@@ -475,7 +475,7 @@ gmp_rsa_public_key_t *gmp_rsa_public_key_load(key_type_t type, va_list args)
 		}
 		break;
 	}
-	if (!e.ptr || !n.ptr)
+	if (!e.len || !n.len || (n.ptr[n.len-1] & 0x01) == 0)
 	{
 		return NULL;
 	}
@@ -506,5 +506,10 @@ gmp_rsa_public_key_t *gmp_rsa_public_key_load(key_type_t type, va_list args)
 
 	this->k = (mpz_sizeinbase(this->n, 2) + 7) / BITS_PER_BYTE;
 
+	if (!mpz_sgn(this->e))
+	{
+		destroy(this);
+		return NULL;
+	}
 	return &this->public;
 }
diff --git a/src/libstrongswan/plugins/hmac/Makefile.in b/src/libstrongswan/plugins/hmac/Makefile.in
index 3a87fcc..aa64015 100644
--- a/src/libstrongswan/plugins/hmac/Makefile.in
+++ b/src/libstrongswan/plugins/hmac/Makefile.in
@@ -355,6 +355,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -377,6 +378,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/keychain/Makefile.in b/src/libstrongswan/plugins/keychain/Makefile.in
index d113d9e..c9e4e40 100644
--- a/src/libstrongswan/plugins/keychain/Makefile.in
+++ b/src/libstrongswan/plugins/keychain/Makefile.in
@@ -358,6 +358,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/ldap/Makefile.in b/src/libstrongswan/plugins/ldap/Makefile.in
index 2005aaf..1f4d447 100644
--- a/src/libstrongswan/plugins/ldap/Makefile.in
+++ b/src/libstrongswan/plugins/ldap/Makefile.in
@@ -355,6 +355,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -377,6 +378,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/md4/Makefile.in b/src/libstrongswan/plugins/md4/Makefile.in
index dad5327..eb9426c 100644
--- a/src/libstrongswan/plugins/md4/Makefile.in
+++ b/src/libstrongswan/plugins/md4/Makefile.in
@@ -355,6 +355,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -377,6 +378,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/md5/Makefile.in b/src/libstrongswan/plugins/md5/Makefile.in
index 5f1ced2..eaafd9f 100644
--- a/src/libstrongswan/plugins/md5/Makefile.in
+++ b/src/libstrongswan/plugins/md5/Makefile.in
@@ -355,6 +355,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -377,6 +378,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/mgf1/Makefile.in b/src/libstrongswan/plugins/mgf1/Makefile.in
index 42904a7..991c542 100644
--- a/src/libstrongswan/plugins/mgf1/Makefile.in
+++ b/src/libstrongswan/plugins/mgf1/Makefile.in
@@ -355,6 +355,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -377,6 +378,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/mysql/Makefile.in b/src/libstrongswan/plugins/mysql/Makefile.in
index b617557..d549f2e 100644
--- a/src/libstrongswan/plugins/mysql/Makefile.in
+++ b/src/libstrongswan/plugins/mysql/Makefile.in
@@ -357,6 +357,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -379,6 +380,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/mysql/mysql_database.c b/src/libstrongswan/plugins/mysql/mysql_database.c
index 871cc59..211eba7 100644
--- a/src/libstrongswan/plugins/mysql/mysql_database.c
+++ b/src/libstrongswan/plugins/mysql/mysql_database.c
@@ -403,10 +403,8 @@ typedef struct {
 	unsigned long *length;
 } mysql_enumerator_t;
 
-/**
- * create a mysql enumerator
- */
-static void mysql_enumerator_destroy(mysql_enumerator_t *this)
+METHOD(enumerator_t, mysql_enumerator_destroy, void,
+	mysql_enumerator_t *this)
 {
 	int columns, i;
 
@@ -434,13 +432,10 @@ static void mysql_enumerator_destroy(mysql_enumerator_t *this)
 	free(this);
 }
 
-/**
- * Implementation of database.query().enumerate
- */
-static bool mysql_enumerator_enumerate(mysql_enumerator_t *this, ...)
+METHOD(enumerator_t, mysql_enumerator_enumerate, bool,
+	mysql_enumerator_t *this, va_list args)
 {
 	int i, columns;
-	va_list args;
 
 	columns = mysql_stmt_field_count(this->stmt);
 
@@ -477,7 +472,6 @@ static bool mysql_enumerator_enumerate(mysql_enumerator_t *this, ...)
 			return FALSE;
 	}
 
-	va_start(args, this);
 	for (i = 0; i < columns; i++)
 	{
 		switch (this->bind[i].buffer_type)
@@ -526,7 +520,6 @@ static bool mysql_enumerator_enumerate(mysql_enumerator_t *this, ...)
 				break;
 		}
 	}
-	va_end(args);
 	return TRUE;
 }
 
@@ -552,9 +545,9 @@ METHOD(database_t, query, enumerator_t*,
 
 		INIT(enumerator,
 			.public = {
-				.enumerate = (void*)mysql_enumerator_enumerate,
-				.destroy = (void*)mysql_enumerator_destroy,
-
+				.enumerate = enumerator_enumerate_default,
+				.venumerate = _mysql_enumerator_enumerate,
+				.destroy = _mysql_enumerator_destroy,
 			},
 			.db = this,
 			.stmt = stmt,
diff --git a/src/libstrongswan/plugins/newhope/Makefile.in b/src/libstrongswan/plugins/newhope/Makefile.in
index 24857b3..a884b30 100644
--- a/src/libstrongswan/plugins/newhope/Makefile.in
+++ b/src/libstrongswan/plugins/newhope/Makefile.in
@@ -364,6 +364,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -386,6 +387,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/newhope/tests/Makefile.in b/src/libstrongswan/plugins/newhope/tests/Makefile.in
index 884a2eb..80fcf4d 100644
--- a/src/libstrongswan/plugins/newhope/tests/Makefile.in
+++ b/src/libstrongswan/plugins/newhope/tests/Makefile.in
@@ -356,6 +356,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -378,6 +379,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/nonce/Makefile.in b/src/libstrongswan/plugins/nonce/Makefile.in
index 8e04841..783eaf4 100644
--- a/src/libstrongswan/plugins/nonce/Makefile.in
+++ b/src/libstrongswan/plugins/nonce/Makefile.in
@@ -356,6 +356,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -378,6 +379,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/ntru/Makefile.in b/src/libstrongswan/plugins/ntru/Makefile.in
index c47f90b..41ec4ce 100644
--- a/src/libstrongswan/plugins/ntru/Makefile.in
+++ b/src/libstrongswan/plugins/ntru/Makefile.in
@@ -357,6 +357,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -379,6 +380,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/openssl/Makefile.in b/src/libstrongswan/plugins/openssl/Makefile.in
index 798ee5f..9c05236 100644
--- a/src/libstrongswan/plugins/openssl/Makefile.in
+++ b/src/libstrongswan/plugins/openssl/Makefile.in
@@ -365,6 +365,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -387,6 +388,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/openssl/openssl_crl.c b/src/libstrongswan/plugins/openssl/openssl_crl.c
index 20bac6b..61cf3e8 100644
--- a/src/libstrongswan/plugins/openssl/openssl_crl.c
+++ b/src/libstrongswan/plugins/openssl/openssl_crl.c
@@ -142,8 +142,14 @@ typedef struct {
 
 
 METHOD(enumerator_t, crl_enumerate, bool,
-	crl_enumerator_t *this, chunk_t *serial, time_t *date, crl_reason_t *reason)
+	crl_enumerator_t *this, va_list args)
 {
+	crl_reason_t *reason;
+	chunk_t *serial;
+	time_t *date;
+
+	VA_ARGS_VGET(args, serial, date, reason);
+
 	if (this->i < this->num)
 	{
 		X509_REVOKED *revoked;
@@ -188,7 +194,8 @@ METHOD(crl_t, create_enumerator, enumerator_t*,
 
 	INIT(enumerator,
 		.public = {
-			.enumerate = (void*)_crl_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _crl_enumerate,
 			.destroy = (void*)free,
 		},
 		.stack = X509_CRL_get_REVOKED(this->crl),
diff --git a/src/libstrongswan/plugins/openssl/openssl_pkcs7.c b/src/libstrongswan/plugins/openssl/openssl_pkcs7.c
index 5752d96..83ac8df 100644
--- a/src/libstrongswan/plugins/openssl/openssl_pkcs7.c
+++ b/src/libstrongswan/plugins/openssl/openssl_pkcs7.c
@@ -136,8 +136,12 @@ METHOD(enumerator_t, cert_destroy, void,
 }
 
 METHOD(enumerator_t, cert_enumerate, bool,
-	cert_enumerator_t *this, certificate_t **out)
+	cert_enumerator_t *this, va_list args)
 {
+	certificate_t **out;
+
+	VA_ARGS_VGET(args, out);
+
 	if (!this->certs)
 	{
 		return FALSE;
@@ -176,7 +180,8 @@ METHOD(pkcs7_t, create_cert_enumerator, enumerator_t*,
 	{
 		INIT(enumerator,
 			.public = {
-				.enumerate = (void*)_cert_enumerate,
+				.enumerate = enumerator_enumerate_default,
+				.venumerate = _cert_enumerate,
 				.destroy = _cert_destroy,
 			},
 			.certs = CMS_get1_certs(this->cms),
@@ -320,8 +325,12 @@ static bool verify_digest(CMS_ContentInfo *cms, CMS_SignerInfo *si, int hash_oid
 }
 
 METHOD(enumerator_t, signature_enumerate, bool,
-	signature_enumerator_t *this, auth_cfg_t **out)
+	signature_enumerator_t *this, va_list args)
 {
+	auth_cfg_t **out;
+
+	VA_ARGS_VGET(args, out);
+
 	if (!this->signers)
 	{
 		return FALSE;
@@ -382,7 +391,8 @@ METHOD(container_t, create_signature_enumerator, enumerator_t*,
 
 		INIT(enumerator,
 			.public = {
-				.enumerate = (void*)_signature_enumerate,
+				.enumerate = enumerator_enumerate_default,
+				.venumerate = _signature_enumerate,
 				.destroy = _signature_destroy,
 			},
 			.cms = this->cms,
diff --git a/src/libstrongswan/plugins/padlock/Makefile.in b/src/libstrongswan/plugins/padlock/Makefile.in
index 1fe0e7b..b717495 100644
--- a/src/libstrongswan/plugins/padlock/Makefile.in
+++ b/src/libstrongswan/plugins/padlock/Makefile.in
@@ -358,6 +358,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/pem/Makefile.in b/src/libstrongswan/plugins/pem/Makefile.in
index e3d7c77..8ff3dd0 100644
--- a/src/libstrongswan/plugins/pem/Makefile.in
+++ b/src/libstrongswan/plugins/pem/Makefile.in
@@ -356,6 +356,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -378,6 +379,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/pem/pem_builder.c b/src/libstrongswan/plugins/pem/pem_builder.c
index 719a2a6..ec90fb0 100644
--- a/src/libstrongswan/plugins/pem/pem_builder.c
+++ b/src/libstrongswan/plugins/pem/pem_builder.c
@@ -61,7 +61,7 @@ static bool find_boundary(char* tag, chunk_t *line)
 
 	if (!present("-----", line) ||
 		!present(tag, line) ||
-		*line->ptr != ' ')
+		!line->len || *line->ptr != ' ')
 	{
 		return FALSE;
 	}
@@ -250,7 +250,7 @@ static status_t pem_to_bin(chunk_t *blob, bool *pgp)
 				{
 					continue;
 				}
-				if (match("Proc-Type", &name) && *value.ptr == '4')
+				if (match("Proc-Type", &name) && value.len && *value.ptr == '4')
 				{
 					encrypted = TRUE;
 				}
@@ -306,7 +306,7 @@ static status_t pem_to_bin(chunk_t *blob, bool *pgp)
 				}
 
 				/* check for PGP armor checksum */
-				if (*data.ptr == '=')
+				if (data.len && *data.ptr == '=')
 				{
 					*pgp = TRUE;
 					data.ptr++;
diff --git a/src/libstrongswan/plugins/pgp/Makefile.in b/src/libstrongswan/plugins/pgp/Makefile.in
index 5523402..3ffafd0 100644
--- a/src/libstrongswan/plugins/pgp/Makefile.in
+++ b/src/libstrongswan/plugins/pgp/Makefile.in
@@ -356,6 +356,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -378,6 +379,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/pkcs1/Makefile.in b/src/libstrongswan/plugins/pkcs1/Makefile.in
index 3cdc731..cbf2276 100644
--- a/src/libstrongswan/plugins/pkcs1/Makefile.in
+++ b/src/libstrongswan/plugins/pkcs1/Makefile.in
@@ -357,6 +357,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -379,6 +380,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/pkcs11/Makefile.in b/src/libstrongswan/plugins/pkcs11/Makefile.in
index f4fffd3..ca7b5a8 100644
--- a/src/libstrongswan/plugins/pkcs11/Makefile.in
+++ b/src/libstrongswan/plugins/pkcs11/Makefile.in
@@ -360,6 +360,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -382,6 +383,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/pkcs11/pkcs11_creds.c b/src/libstrongswan/plugins/pkcs11/pkcs11_creds.c
index e65f3a0..b157554 100644
--- a/src/libstrongswan/plugins/pkcs11/pkcs11_creds.c
+++ b/src/libstrongswan/plugins/pkcs11/pkcs11_creds.c
@@ -153,30 +153,32 @@ static bool load_certificates(private_pkcs11_creds_t *this)
 	return TRUE;
 }
 
-/**
- * filter function for certs enumerator
- */
-static bool certs_filter(identification_t *id,
-						 certificate_t **in, certificate_t **out)
+CALLBACK(certs_filter, bool,
+	identification_t *id, enumerator_t *orig, va_list args)
 {
 	public_key_t *public;
-	certificate_t *cert = *in;
+	certificate_t *cert, **out;
 
-	if (id == NULL || cert->has_subject(cert, id))
-	{
-		*out = *in;
-		return TRUE;
-	}
-	public = cert->get_public_key(cert);
-	if (public)
+	VA_ARGS_VGET(args, out);
+
+	while (orig->enumerate(orig, &cert))
 	{
-		if (public->has_fingerprint(public, id->get_encoding(id)))
+		if (id == NULL || cert->has_subject(cert, id))
 		{
-			public->destroy(public);
-			*out = *in;
+			*out = cert;
 			return TRUE;
 		}
-		public->destroy(public);
+		public = cert->get_public_key(cert);
+		if (public)
+		{
+			if (public->has_fingerprint(public, id->get_encoding(id)))
+			{
+				public->destroy(public);
+				*out = cert;
+				return TRUE;
+			}
+			public->destroy(public);
+		}
 	}
 	return FALSE;
 }
@@ -199,7 +201,7 @@ METHOD(credential_set_t, create_cert_enumerator, enumerator_t*,
 	{
 		inner = this->untrusted->create_enumerator(this->untrusted);
 	}
-	return enumerator_create_filter(inner, (void*)certs_filter, id, NULL);
+	return enumerator_create_filter(inner, certs_filter, id, NULL);
 }
 
 METHOD(pkcs11_creds_t, get_library, pkcs11_library_t*,
diff --git a/src/libstrongswan/plugins/pkcs11/pkcs11_library.c b/src/libstrongswan/plugins/pkcs11/pkcs11_library.c
index dc8a1f1..89ae196 100644
--- a/src/libstrongswan/plugins/pkcs11/pkcs11_library.c
+++ b/src/libstrongswan/plugins/pkcs11/pkcs11_library.c
@@ -719,12 +719,14 @@ static bool get_attributes(object_enumerator_t *this, CK_OBJECT_HANDLE object)
 }
 
 METHOD(enumerator_t, object_enumerate, bool,
-	object_enumerator_t *this, CK_OBJECT_HANDLE *out)
+	object_enumerator_t *this, va_list args)
 {
-	CK_OBJECT_HANDLE object;
+	CK_OBJECT_HANDLE object, *out;
 	CK_ULONG found;
 	CK_RV rv;
 
+	VA_ARGS_VGET(args, out);
+
 	if (!this->object)
 	{
 		rv = this->lib->f->C_FindObjects(this->session, &object, 1, &found);
@@ -786,7 +788,8 @@ METHOD(pkcs11_library_t, create_object_enumerator, enumerator_t*,
 
 	INIT(enumerator,
 		.public = {
-			.enumerate = (void*)_object_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _object_enumerate,
 			.destroy = _object_destroy,
 		},
 		.session = session,
@@ -806,7 +809,8 @@ METHOD(pkcs11_library_t, create_object_attr_enumerator, enumerator_t*,
 
 	INIT(enumerator,
 		.public = {
-			.enumerate = (void*)_object_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _object_enumerate,
 			.destroy = _object_destroy,
 		},
 		.session = session,
@@ -838,11 +842,14 @@ typedef struct {
 } mechanism_enumerator_t;
 
 METHOD(enumerator_t, enumerate_mech, bool,
-	mechanism_enumerator_t *this, CK_MECHANISM_TYPE* type,
-	CK_MECHANISM_INFO *info)
+	mechanism_enumerator_t *this, va_list args)
 {
+	CK_MECHANISM_INFO *info;
+	CK_MECHANISM_TYPE *type;
 	CK_RV rv;
 
+	VA_ARGS_VGET(args, type, info);
+
 	if (this->current >= this->count)
 	{
 		return FALSE;
@@ -876,7 +883,8 @@ METHOD(pkcs11_library_t, create_mechanism_enumerator, enumerator_t*,
 
 	INIT(enumerator,
 		.public = {
-			.enumerate = (void*)_enumerate_mech,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _enumerate_mech,
 			.destroy = _destroy_mech,
 		},
 		.lib = &this->public,
diff --git a/src/libstrongswan/plugins/pkcs11/pkcs11_manager.c b/src/libstrongswan/plugins/pkcs11/pkcs11_manager.c
index 96c4a18..31bcb0d 100644
--- a/src/libstrongswan/plugins/pkcs11/pkcs11_manager.c
+++ b/src/libstrongswan/plugins/pkcs11/pkcs11_manager.c
@@ -265,8 +265,13 @@ typedef struct {
 } token_enumerator_t;
 
 METHOD(enumerator_t, enumerate_token, bool,
-	token_enumerator_t *this, pkcs11_library_t **out, CK_SLOT_ID *slot)
+	token_enumerator_t *this, va_list args)
 {
+	pkcs11_library_t **out;
+	CK_SLOT_ID *slot;
+
+	VA_ARGS_VGET(args, out, slot);
+
 	if (this->current >= this->count)
 	{
 		free(this->slots);
@@ -301,7 +306,8 @@ METHOD(pkcs11_manager_t, create_token_enumerator, enumerator_t*,
 
 	INIT(enumerator,
 		.public = {
-			.enumerate = (void*)_enumerate_token,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _enumerate_token,
 			.destroy = _destroy_token,
 		},
 		.inner = this->libs->create_enumerator(this->libs),
diff --git a/src/libstrongswan/plugins/pkcs12/Makefile.in b/src/libstrongswan/plugins/pkcs12/Makefile.in
index 72996f1..73f15d2 100644
--- a/src/libstrongswan/plugins/pkcs12/Makefile.in
+++ b/src/libstrongswan/plugins/pkcs12/Makefile.in
@@ -357,6 +357,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -379,6 +380,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/pkcs7/Makefile.in b/src/libstrongswan/plugins/pkcs7/Makefile.in
index 6224b1b..3bf44de 100644
--- a/src/libstrongswan/plugins/pkcs7/Makefile.in
+++ b/src/libstrongswan/plugins/pkcs7/Makefile.in
@@ -359,6 +359,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -381,6 +382,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/pkcs7/pkcs7_signed_data.c b/src/libstrongswan/plugins/pkcs7/pkcs7_signed_data.c
index d224ef3..413c3ff 100644
--- a/src/libstrongswan/plugins/pkcs7/pkcs7_signed_data.c
+++ b/src/libstrongswan/plugins/pkcs7/pkcs7_signed_data.c
@@ -179,7 +179,7 @@ typedef struct {
 } signature_enumerator_t;
 
 METHOD(enumerator_t, enumerate, bool,
-	signature_enumerator_t *this, auth_cfg_t **out)
+	signature_enumerator_t *this, va_list args)
 {
 	signerinfo_t *info;
 	signature_scheme_t scheme;
@@ -187,11 +187,13 @@ METHOD(enumerator_t, enumerate, bool,
 	enumerator_t *enumerator;
 	certificate_t *cert;
 	public_key_t *key;
-	auth_cfg_t *auth;
+	auth_cfg_t *auth, **out;
 	chunk_t chunk, hash, content;
 	hasher_t *hasher;
 	bool valid;
 
+	VA_ARGS_VGET(args, out);
+
 	while (this->inner->enumerate(this->inner, &info))
 	{
 		/* clean up previous round */
@@ -300,7 +302,8 @@ METHOD(container_t, create_signature_enumerator, enumerator_t*,
 
 	INIT(enumerator,
 		.public = {
-			.enumerate = (void*)_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _enumerate,
 			.destroy = _enumerator_destroy,
 		},
 		.inner = this->signerinfos->create_enumerator(this->signerinfos),
diff --git a/src/libstrongswan/plugins/pkcs8/Makefile.in b/src/libstrongswan/plugins/pkcs8/Makefile.in
index 475de08..2066d87 100644
--- a/src/libstrongswan/plugins/pkcs8/Makefile.in
+++ b/src/libstrongswan/plugins/pkcs8/Makefile.in
@@ -356,6 +356,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -378,6 +379,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/plugin_constructors.py b/src/libstrongswan/plugins/plugin_constructors.py
new file mode 100644
index 0000000..d9c40e3
--- /dev/null
+++ b/src/libstrongswan/plugins/plugin_constructors.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2017 Tobias Brunner
+# HSR 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.
+
+import sys
+from argparse import ArgumentParser
+
+def generate_output(plugins):
+	"""Generate a source file containing plugin constructor registrations"""
+	print("/**")
+	print(" * Register plugin constructors for static libraries")
+	print(" * Created by {0}".format(__file__))
+	print(" */")
+	print("")
+	print("#include <plugins/plugin.h>")
+	print("#include <plugins/plugin_loader.h>")
+	print("")
+
+	for plugin in plugins:
+		print("plugin_t *{0}_plugin_create();".format(plugin.replace('-', '_')))
+
+	print("")
+	print("static void register_plugins() __attribute__ ((constructor));")
+	print("static void register_plugins()")
+	print("{")
+
+	for plugin in plugins:
+		print('	plugin_constructor_register("{0}", {1}_plugin_create);'.format(plugin, plugin.replace('-', '_')))
+
+	print("}")
+
+	print("")
+	print("static void unregister_plugins() __attribute__ ((destructor));")
+	print("static void unregister_plugins()")
+	print("{")
+
+	for plugin in plugins:
+		print('	plugin_constructor_register("{0}", NULL);'.format(plugin))
+
+	print("}")
+	print("")
+
+parser = ArgumentParser(description = "Generate constructor registration for a list of plugins")
+parser.add_argument('plugins', metavar="plugin", nargs="*",
+					help = "name of a plugin for which to generate constructor registration")
+
+
+args = parser.parse_args()
+generate_output(args.plugins);
diff --git a/src/libstrongswan/plugins/plugin_loader.c b/src/libstrongswan/plugins/plugin_loader.c
index e4698fa..42d443b 100644
--- a/src/libstrongswan/plugins/plugin_loader.c
+++ b/src/libstrongswan/plugins/plugin_loader.c
@@ -40,6 +40,13 @@ typedef struct registered_feature_t registered_feature_t;
 typedef struct provided_feature_t provided_feature_t;
 typedef struct plugin_entry_t plugin_entry_t;
 
+#ifdef STATIC_PLUGIN_CONSTRUCTORS
+/**
+ * Statically registered constructors
+ */
+static hashtable_t *plugin_constructors = NULL;
+#endif
+
 /**
  * private data of plugin_loader
  */
@@ -298,6 +305,46 @@ static plugin_t *static_features_create(const char *name,
 	return &this->public;
 }
 
+#ifdef STATIC_PLUGIN_CONSTRUCTORS
+/*
+ * Described in header.
+ */
+void plugin_constructor_register(char *name, void *constructor)
+{
+	bool old = FALSE;
+
+	if (lib && lib->leak_detective)
+	{
+		old = lib->leak_detective->set_state(lib->leak_detective, FALSE);
+	}
+
+	if (!plugin_constructors)
+	{
+		chunk_hash_seed();
+		plugin_constructors = hashtable_create(hashtable_hash_str,
+											   hashtable_equals_str, 32);
+	}
+	if (constructor)
+	{
+		plugin_constructors->put(plugin_constructors, name, constructor);
+	}
+	else
+	{
+		plugin_constructors->remove(plugin_constructors, name);
+		if (!plugin_constructors->get_count(plugin_constructors))
+		{
+			plugin_constructors->destroy(plugin_constructors);
+			plugin_constructors = NULL;
+		}
+	}
+
+	if (lib && lib->leak_detective)
+	{
+		lib->leak_detective->set_state(lib->leak_detective, old);
+	}
+}
+#endif
+
 /**
  * create a plugin
  * returns: NOT_FOUND, if the constructor was not found
@@ -309,7 +356,7 @@ static status_t create_plugin(private_plugin_loader_t *this, void *handle,
 {
 	char create[128];
 	plugin_t *plugin;
-	plugin_constructor_t constructor;
+	plugin_constructor_t constructor = NULL;
 
 	if (snprintf(create, sizeof(create), "%s_plugin_create",
 				 name) >= sizeof(create))
@@ -317,8 +364,17 @@ static status_t create_plugin(private_plugin_loader_t *this, void *handle,
 		return FAILED;
 	}
 	translate(create, "-", "_");
-	constructor = dlsym(handle, create);
-	if (constructor == NULL)
+#ifdef STATIC_PLUGIN_CONSTRUCTORS
+	if (plugin_constructors)
+	{
+		constructor = plugin_constructors->get(plugin_constructors, name);
+	}
+	if (!constructor)
+#endif
+	{
+		constructor = dlsym(handle, create);
+	}
+	if (!constructor)
 	{
 		return NOT_FOUND;
 	}
@@ -409,34 +465,48 @@ static plugin_entry_t *load_plugin(private_plugin_loader_t *this, char *name,
 	return entry;
 }
 
-/**
- * Convert enumerated provided_feature_t to plugin_feature_t
- */
-static bool feature_filter(void *null, provided_feature_t **provided,
-						   plugin_feature_t **feature)
+CALLBACK(feature_filter, bool,
+	void *null, enumerator_t *orig, va_list args)
 {
-	*feature = (*provided)->feature;
-	return (*provided)->loaded;
+	provided_feature_t *provided;
+	plugin_feature_t **feature;
+
+	VA_ARGS_VGET(args, feature);
+
+	while (orig->enumerate(orig, &provided))
+	{
+		if (provided->loaded)
+		{
+			*feature = provided->feature;
+			return TRUE;
+		}
+	}
+	return FALSE;
 }
 
-/**
- * Convert enumerated entries to plugin_t
- */
-static bool plugin_filter(void *null, plugin_entry_t **entry, plugin_t **plugin,
-						  void *in, linked_list_t **list)
+CALLBACK(plugin_filter, bool,
+	void *null, enumerator_t *orig, va_list args)
 {
-	plugin_entry_t *this = *entry;
+	plugin_entry_t *entry;
+	linked_list_t **list;
+	plugin_t **plugin;
+
+	VA_ARGS_VGET(args, plugin, list);
 
-	*plugin = this->plugin;
-	if (list)
+	if (orig->enumerate(orig, &entry))
 	{
-		enumerator_t *features;
-		features = enumerator_create_filter(
-							this->features->create_enumerator(this->features),
-							(void*)feature_filter, NULL, NULL);
-		*list = linked_list_create_from_enumerator(features);
+		*plugin = entry->plugin;
+		if (list)
+		{
+			enumerator_t *features;
+			features = enumerator_create_filter(
+							entry->features->create_enumerator(entry->features),
+							feature_filter, NULL, NULL);
+			*list = linked_list_create_from_enumerator(features);
+		}
+		return TRUE;
 	}
-	return TRUE;
+	return FALSE;
 }
 
 METHOD(plugin_loader_t, create_plugin_enumerator, enumerator_t*,
@@ -444,7 +514,7 @@ METHOD(plugin_loader_t, create_plugin_enumerator, enumerator_t*,
 {
 	return enumerator_create_filter(
 							this->plugins->create_enumerator(this->plugins),
-							(void*)plugin_filter, NULL, NULL);
+							plugin_filter, NULL, NULL);
 }
 
 METHOD(plugin_loader_t, has_feature, bool,
@@ -536,18 +606,14 @@ static void load_provided(private_plugin_loader_t *this,
 						  provided_feature_t *provided,
 						  int level);
 
-/**
- * Used to find a loaded feature
- */
-static bool is_feature_loaded(provided_feature_t *item)
+CALLBACK(is_feature_loaded, bool,
+	provided_feature_t *item, va_list args)
 {
 	return item->loaded;
 }
 
-/**
- * Used to find a loadable feature
- */
-static bool is_feature_loadable(provided_feature_t *item)
+CALLBACK(is_feature_loadable, bool,
+	provided_feature_t *item, va_list args)
 {
 	return !item->loading && !item->loaded && !item->failed;
 }
@@ -560,8 +626,7 @@ static bool loaded_feature_matches(registered_feature_t *a,
 {
 	if (plugin_feature_matches(a->feature, b->feature))
 	{
-		return b->plugins->find_first(b->plugins, (void*)is_feature_loaded,
-									  NULL) == SUCCESS;
+		return b->plugins->find_first(b->plugins, is_feature_loaded, NULL);
 	}
 	return FALSE;
 }
@@ -574,8 +639,7 @@ static bool loadable_feature_equals(registered_feature_t *a,
 {
 	if (plugin_feature_equals(a->feature, b->feature))
 	{
-		return b->plugins->find_first(b->plugins, (void*)is_feature_loadable,
-									  NULL) == SUCCESS;
+		return b->plugins->find_first(b->plugins, is_feature_loadable, NULL);
 	}
 	return FALSE;
 }
@@ -588,8 +652,7 @@ static bool loadable_feature_matches(registered_feature_t *a,
 {
 	if (plugin_feature_matches(a->feature, b->feature))
 	{
-		return b->plugins->find_first(b->plugins, (void*)is_feature_loadable,
-									  NULL) == SUCCESS;
+		return b->plugins->find_first(b->plugins, is_feature_loadable, NULL);
 	}
 	return FALSE;
 }
@@ -674,9 +737,11 @@ static bool load_dependencies(private_plugin_loader_t *this,
 
 		if (!find_compatible_feature(this, &provided->feature[i]))
 		{
-			char *name, *provide, *depend;
 			bool soft = provided->feature[i].kind == FEATURE_SDEPEND;
 
+#ifndef USE_FUZZING
+			char *name, *provide, *depend;
+
 			name = provided->entry->plugin->get_name(provided->entry->plugin);
 			provide = plugin_feature_get_string(&provided->feature[0]);
 			depend = plugin_feature_get_string(&provided->feature[i]);
@@ -697,6 +762,8 @@ static bool load_dependencies(private_plugin_loader_t *this,
 			}
 			free(provide);
 			free(depend);
+#endif /* !USE_FUZZING */
+
 			if (soft)
 			{	/* it's ok if we can't resolve soft dependencies */
 				continue;
@@ -716,8 +783,6 @@ static void load_feature(private_plugin_loader_t *this,
 {
 	if (load_dependencies(this, provided, level))
 	{
-		char *name, *provide;
-
 		if (plugin_feature_load(provided->entry->plugin, provided->feature,
 								provided->reg))
 		{
@@ -727,6 +792,9 @@ static void load_feature(private_plugin_loader_t *this,
 			return;
 		}
 
+#ifndef USE_FUZZING
+		char *name, *provide;
+
 		name = provided->entry->plugin->get_name(provided->entry->plugin);
 		provide = plugin_feature_get_string(&provided->feature[0]);
 		if (provided->entry->critical)
@@ -740,6 +808,7 @@ static void load_feature(private_plugin_loader_t *this,
 				 provide, name);
 		}
 		free(provide);
+#endif /* !USE_FUZZING */
 	}
 	else
 	{	/* TODO: we could check the current level and set a different flag when
@@ -759,13 +828,16 @@ static void load_provided(private_plugin_loader_t *this,
 						  provided_feature_t *provided,
 						  int level)
 {
-	char *name, *provide;
 	int indent = level * 2;
 
 	if (provided->loaded || provided->failed)
 	{
 		return;
 	}
+
+#ifndef USE_FUZZING
+	char *name, *provide;
+
 	name = provided->entry->plugin->get_name(provided->entry->plugin);
 	provide = plugin_feature_get_string(provided->feature);
 	if (provided->loading)
@@ -778,6 +850,12 @@ static void load_provided(private_plugin_loader_t *this,
 	DBG3(DBG_LIB, "%*sloading feature %s in plugin '%s'",
 		 indent, "", provide, name);
 	free(provide);
+#else
+	if (provided->loading)
+	{
+		return;
+	}
+#endif /* USE_FUZZING */
 
 	provided->loading = TRUE;
 	load_feature(this, provided, level + 1);
@@ -926,8 +1004,8 @@ static void purge_plugins(private_plugin_loader_t *this)
 		{	/* feature interface not supported */
 			continue;
 		}
-		if (entry->features->find_first(entry->features,
-									(void*)is_feature_loaded, NULL) != SUCCESS)
+		if (!entry->features->find_first(entry->features, is_feature_loaded,
+										 NULL))
 		{
 			DBG2(DBG_LIB, "unloading plugin '%s' without loaded features",
 				 entry->plugin->get_name(entry->plugin));
@@ -977,6 +1055,15 @@ static bool find_plugin(char *path, char *name, char *buf, char **file)
 	return FALSE;
 }
 
+CALLBACK(find_plugin_cb, bool,
+	char *path, va_list args)
+{
+	char *name, *buf, **file;
+
+	VA_ARGS_VGET(args, name, buf, file);
+	return find_plugin(path, name, buf, file);
+}
+
 /**
  * Used to sort plugins by priority
  */
@@ -1024,14 +1111,20 @@ static int plugin_priority_cmp(const plugin_priority_t *a,
 	return diff;
 }
 
-/**
- * Convert enumerated plugin_priority_t to a plugin name
- */
-static bool plugin_priority_filter(void *null, plugin_priority_t **prio,
-						   char **name)
+CALLBACK(plugin_priority_filter, bool,
+	void *null, enumerator_t *orig, va_list args)
 {
-	*name = (*prio)->name;
-	return TRUE;
+	plugin_priority_t *prio;
+	char **name;
+
+	VA_ARGS_VGET(args, name);
+
+	if (orig->enumerate(orig, &prio))
+	{
+		*name = prio->name;
+		return TRUE;
+	}
+	return FALSE;
 }
 
 /**
@@ -1071,7 +1164,7 @@ static char *modular_pluginlist(char *list)
 	else
 	{
 		enumerator = enumerator_create_filter(array_create_enumerator(given),
-									(void*)plugin_priority_filter, NULL, NULL);
+										plugin_priority_filter, NULL, NULL);
 		load_def = TRUE;
 	}
 	while (enumerator->enumerate(enumerator, &plugin))
@@ -1153,8 +1246,8 @@ METHOD(plugin_loader_t, load_plugins, bool,
 		}
 		if (this->paths)
 		{
-			this->paths->find_first(this->paths, (void*)find_plugin, NULL,
-									token, buf, &file);
+			this->paths->find_first(this->paths, find_plugin_cb, NULL, token,
+									buf, &file);
 		}
 		if (!file)
 		{
diff --git a/src/libstrongswan/plugins/plugin_loader.h b/src/libstrongswan/plugins/plugin_loader.h
index 6be6a90..92a8606 100644
--- a/src/libstrongswan/plugins/plugin_loader.h
+++ b/src/libstrongswan/plugins/plugin_loader.h
@@ -168,4 +168,14 @@ plugin_loader_t *plugin_loader_create();
  */
 void plugin_loader_add_plugindirs(char *basedir, char *plugins);
 
+#ifdef STATIC_PLUGIN_CONSTRUCTORS
+/**
+ * Register a plugin constructor in case of static builds.
+ *
+ * @param name         name of the plugin
+ * @param constructor  constructor to register (set to NULL to unregister)
+ */
+void plugin_constructor_register(char *name, void *constructor);
+#endif
+
 #endif /** PLUGIN_LOADER_H_ @}*/
diff --git a/src/libstrongswan/plugins/pubkey/Makefile.in b/src/libstrongswan/plugins/pubkey/Makefile.in
index 4b0b13e..04888cd 100644
--- a/src/libstrongswan/plugins/pubkey/Makefile.in
+++ b/src/libstrongswan/plugins/pubkey/Makefile.in
@@ -357,6 +357,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -379,6 +380,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/random/Makefile.in b/src/libstrongswan/plugins/random/Makefile.in
index 1cf00a5..940c557 100644
--- a/src/libstrongswan/plugins/random/Makefile.in
+++ b/src/libstrongswan/plugins/random/Makefile.in
@@ -357,6 +357,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -379,6 +380,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/rc2/Makefile.in b/src/libstrongswan/plugins/rc2/Makefile.in
index a57e15b..c432cf8 100644
--- a/src/libstrongswan/plugins/rc2/Makefile.in
+++ b/src/libstrongswan/plugins/rc2/Makefile.in
@@ -355,6 +355,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -377,6 +378,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/rdrand/Makefile.in b/src/libstrongswan/plugins/rdrand/Makefile.in
index a5d76c1..849c896 100644
--- a/src/libstrongswan/plugins/rdrand/Makefile.in
+++ b/src/libstrongswan/plugins/rdrand/Makefile.in
@@ -357,6 +357,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -379,6 +380,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/revocation/Makefile.in b/src/libstrongswan/plugins/revocation/Makefile.in
index cfbbcd8..5840c7d 100644
--- a/src/libstrongswan/plugins/revocation/Makefile.in
+++ b/src/libstrongswan/plugins/revocation/Makefile.in
@@ -358,6 +358,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/sha1/Makefile.in b/src/libstrongswan/plugins/sha1/Makefile.in
index 8e3301e..fa596e6 100644
--- a/src/libstrongswan/plugins/sha1/Makefile.in
+++ b/src/libstrongswan/plugins/sha1/Makefile.in
@@ -356,6 +356,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -378,6 +379,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/sha2/Makefile.in b/src/libstrongswan/plugins/sha2/Makefile.in
index 045d6e0..6e3d6a3 100644
--- a/src/libstrongswan/plugins/sha2/Makefile.in
+++ b/src/libstrongswan/plugins/sha2/Makefile.in
@@ -355,6 +355,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -377,6 +378,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/sha3/Makefile.in b/src/libstrongswan/plugins/sha3/Makefile.in
index 9fc0a1a..2c24934 100644
--- a/src/libstrongswan/plugins/sha3/Makefile.in
+++ b/src/libstrongswan/plugins/sha3/Makefile.in
@@ -356,6 +356,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -378,6 +379,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/soup/Makefile.in b/src/libstrongswan/plugins/soup/Makefile.in
index 5179004..02e3987 100644
--- a/src/libstrongswan/plugins/soup/Makefile.in
+++ b/src/libstrongswan/plugins/soup/Makefile.in
@@ -356,6 +356,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -378,6 +379,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/sqlite/Makefile.in b/src/libstrongswan/plugins/sqlite/Makefile.in
index 8ffc4aa..5e23cb9 100644
--- a/src/libstrongswan/plugins/sqlite/Makefile.in
+++ b/src/libstrongswan/plugins/sqlite/Makefile.in
@@ -358,6 +358,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/sqlite/sqlite_database.c b/src/libstrongswan/plugins/sqlite/sqlite_database.c
index 0a35e30..9f87421 100644
--- a/src/libstrongswan/plugins/sqlite/sqlite_database.c
+++ b/src/libstrongswan/plugins/sqlite/sqlite_database.c
@@ -174,10 +174,8 @@ typedef struct {
 	private_sqlite_database_t *database;
 } sqlite_enumerator_t;
 
-/**
- * destroy a sqlite enumerator
- */
-static void sqlite_enumerator_destroy(sqlite_enumerator_t *this)
+METHOD(enumerator_t, sqlite_enumerator_destroy, void,
+	sqlite_enumerator_t *this)
 {
 	sqlite3_finalize(this->stmt);
 	if (!is_threadsave())
@@ -188,13 +186,10 @@ static void sqlite_enumerator_destroy(sqlite_enumerator_t *this)
 	free(this);
 }
 
-/**
- * Implementation of database.query().enumerate
- */
-static bool sqlite_enumerator_enumerate(sqlite_enumerator_t *this, ...)
+METHOD(enumerator_t, sqlite_enumerator_enumerate, bool,
+	sqlite_enumerator_t *this, va_list args)
 {
 	int i;
-	va_list args;
 
 	switch (sqlite3_step(this->stmt))
 	{
@@ -207,7 +202,7 @@ static bool sqlite_enumerator_enumerate(sqlite_enumerator_t *this, ...)
 		case SQLITE_DONE:
 			return FALSE;
 	}
-	va_start(args, this);
+
 	for (i = 0; i < this->count; i++)
 	{
 		switch (this->columns[i])
@@ -245,11 +240,9 @@ static bool sqlite_enumerator_enumerate(sqlite_enumerator_t *this, ...)
 			}
 			default:
 				DBG1(DBG_LIB, "invalid result type supplied");
-				va_end(args);
 				return FALSE;
 		}
 	}
-	va_end(args);
 	return TRUE;
 }
 
@@ -270,13 +263,17 @@ METHOD(database_t, query, enumerator_t*,
 	stmt = run(this, sql, &args);
 	if (stmt)
 	{
-		enumerator = malloc_thing(sqlite_enumerator_t);
-		enumerator->public.enumerate = (void*)sqlite_enumerator_enumerate;
-		enumerator->public.destroy = (void*)sqlite_enumerator_destroy;
-		enumerator->stmt = stmt;
-		enumerator->count = sqlite3_column_count(stmt);
+		INIT(enumerator,
+			.public = {
+				.enumerate = enumerator_enumerate_default,
+				.venumerate = _sqlite_enumerator_enumerate,
+				.destroy = _sqlite_enumerator_destroy,
+			},
+			.stmt = stmt,
+			.count = sqlite3_column_count(stmt),
+			.database = this,
+		);
 		enumerator->columns = malloc(sizeof(db_type_t) * enumerator->count);
-		enumerator->database = this;
 		for (i = 0; i < enumerator->count; i++)
 		{
 			enumerator->columns[i] = va_arg(args, db_type_t);
diff --git a/src/libstrongswan/plugins/sshkey/Makefile.in b/src/libstrongswan/plugins/sshkey/Makefile.in
index 8528b87..a666399 100644
--- a/src/libstrongswan/plugins/sshkey/Makefile.in
+++ b/src/libstrongswan/plugins/sshkey/Makefile.in
@@ -358,6 +358,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/test_vectors/Makefile.in b/src/libstrongswan/plugins/test_vectors/Makefile.in
index 27741dd..33c5720 100644
--- a/src/libstrongswan/plugins/test_vectors/Makefile.in
+++ b/src/libstrongswan/plugins/test_vectors/Makefile.in
@@ -376,6 +376,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -398,6 +399,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/unbound/Makefile.in b/src/libstrongswan/plugins/unbound/Makefile.in
index 4822283..15c8c27 100644
--- a/src/libstrongswan/plugins/unbound/Makefile.in
+++ b/src/libstrongswan/plugins/unbound/Makefile.in
@@ -358,6 +358,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/winhttp/Makefile.in b/src/libstrongswan/plugins/winhttp/Makefile.in
index 9a26a98..b417d6e 100644
--- a/src/libstrongswan/plugins/winhttp/Makefile.in
+++ b/src/libstrongswan/plugins/winhttp/Makefile.in
@@ -358,6 +358,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/x509/Makefile.in b/src/libstrongswan/plugins/x509/Makefile.in
index 8d7f9a8..e1ed6b7 100644
--- a/src/libstrongswan/plugins/x509/Makefile.in
+++ b/src/libstrongswan/plugins/x509/Makefile.in
@@ -357,6 +357,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -379,6 +380,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/plugins/x509/x509_ac.c b/src/libstrongswan/plugins/x509/x509_ac.c
index aea8eb5..ba45928 100644
--- a/src/libstrongswan/plugins/x509/x509_ac.c
+++ b/src/libstrongswan/plugins/x509/x509_ac.c
@@ -1,9 +1,8 @@
 /*
  * Copyright (C) 2002 Ueli Galizzi, Ariane Seiler
  * Copyright (C) 2003 Martin Berner, Lukas Suter
- * Copyright (C) 2002-2014 Andreas Steffen
+ * Copyright (C) 2002-2017 Andreas Steffen
  * Copyright (C) 2009 Martin Willi
- *
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -177,7 +176,7 @@ static chunk_t ASN1_noRevAvail_ext = chunk_from_chars(
 /**
  * declaration of function implemented in x509_cert.c
  */
-extern void x509_parse_generalNames(chunk_t blob, int level0, bool implicit,
+extern bool x509_parse_generalNames(chunk_t blob, int level0, bool implicit,
 									linked_list_t *list);
 /**
  * parses a directoryName
@@ -191,7 +190,11 @@ static bool parse_directoryName(chunk_t blob, int level, bool implicit,
 	linked_list_t *list;
 
 	list = linked_list_create();
-	x509_parse_generalNames(blob, level, implicit, list);
+	if (!x509_parse_generalNames(blob, level, implicit, list))
+	{
+		list->destroy(list);
+		return FALSE;
+	}
 
 	enumerator = list->create_enumerator(list);
 	while (enumerator->enumerate(enumerator, &directoryName))
@@ -801,20 +804,27 @@ METHOD(ac_t, get_authKeyIdentifier, chunk_t,
 	return this->authKeyIdentifier;
 }
 
-/**
- * Filter function for attribute enumeration
- */
-static bool attr_filter(void *null, group_t **in, ac_group_type_t *type,
-						void *in2, chunk_t *out)
+CALLBACK(attr_filter, bool,
+	void *null, enumerator_t *orig, va_list args)
 {
-	if ((*in)->type == AC_GROUP_TYPE_STRING &&
-		!chunk_printable((*in)->value, NULL, 0))
-	{	/* skip non-printable strings */
-		return FALSE;
+	group_t *group;
+	ac_group_type_t *type;
+	chunk_t *out;
+
+	VA_ARGS_VGET(args, type, out);
+
+	while (orig->enumerate(orig, &group))
+	{
+		if (group->type == AC_GROUP_TYPE_STRING &&
+			!chunk_printable(group->value, NULL, 0))
+		{	/* skip non-printable strings */
+			continue;
+		}
+		*type = group->type;
+		*out = group->value;
+		return TRUE;
 	}
-	*type = (*in)->type;
-	*out = (*in)->value;
-	return TRUE;
+	return FALSE;
 }
 
 METHOD(ac_t, create_group_enumerator, enumerator_t*,
@@ -822,7 +832,7 @@ METHOD(ac_t, create_group_enumerator, enumerator_t*,
 {
 	return enumerator_create_filter(
 							this->groups->create_enumerator(this->groups),
-							(void*)attr_filter, NULL, NULL);
+							attr_filter, NULL, NULL);
 }
 
 METHOD(certificate_t, get_type, certificate_type_t,
diff --git a/src/libstrongswan/plugins/x509/x509_cert.c b/src/libstrongswan/plugins/x509/x509_cert.c
index b77c5db..974e687 100644
--- a/src/libstrongswan/plugins/x509/x509_cert.c
+++ b/src/libstrongswan/plugins/x509/x509_cert.c
@@ -2,10 +2,10 @@
  * Copyright (C) 2000 Andreas Hess, Patric Lichtsteiner, Roger Wegmann
  * Copyright (C) 2001 Marco Bertossa, Andreas Schleiss
  * Copyright (C) 2002 Mario Strasser
- * Copyright (C) 2000-2006 Andreas Steffen
+ * Copyright (C) 2000-2017 Andreas Steffen
  * Copyright (C) 2006-2009 Martin Willi
  * Copyright (C) 2008 Tobias Brunner
- * Hochschule fuer Technik Rapperswil
+ * HSR 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
@@ -218,6 +218,29 @@ struct private_x509_cert_t {
 };
 
 /**
+ * Convert a generalName to a string
+ */
+static bool gn_to_string(identification_t *id, char **uri)
+{
+	int len;
+
+#ifdef USE_FUZZING
+	chunk_t proper;
+	chunk_printable(id->get_encoding(id), &proper, '?');
+	len = asprintf(uri, "%.*s", (int)proper.len, proper.ptr);
+	chunk_free(&proper);
+#else
+	len = asprintf(uri, "%Y", id);
+#endif
+	if (!len)
+	{
+		free(*uri);
+		return FALSE;
+	}
+	return len > 0;
+}
+
+/**
  * Destroy a CertificateDistributionPoint
  */
 static void crl_uri_destroy(x509_cdp_t *this)
@@ -280,13 +303,14 @@ static const asn1Object_t basicConstraintsObjects[] = {
 /**
  * Extracts the basicConstraints extension
  */
-static void parse_basicConstraints(chunk_t blob, int level0,
+static bool parse_basicConstraints(chunk_t blob, int level0,
 								   private_x509_cert_t *this)
 {
 	asn1_parser_t *parser;
 	chunk_t object;
 	int objectID;
 	bool isCA = FALSE;
+	bool success;
 
 	parser = asn1_parser_create(basicConstraintsObjects, blob);
 	parser->set_top_level(parser, level0);
@@ -313,7 +337,10 @@ static void parse_basicConstraints(chunk_t blob, int level0,
 				break;
 		}
 	}
+	success = parser->success(parser);
 	parser->destroy(parser);
+
+	return success;
 }
 
 /**
@@ -502,11 +529,14 @@ static const asn1Object_t generalNamesObjects[] = {
 /**
  * Extracts one or several GNs and puts them into a chained list
  */
-void x509_parse_generalNames(chunk_t blob, int level0, bool implicit, linked_list_t *list)
+bool x509_parse_generalNames(chunk_t blob, int level0, bool implicit,
+							 linked_list_t *list)
 {
 	asn1_parser_t *parser;
 	chunk_t object;
+	identification_t *gn;
 	int objectID;
+	bool success = FALSE;
 
 	parser = asn1_parser_create(generalNamesObjects, blob);
 	parser->set_top_level(parser, level0);
@@ -516,16 +546,20 @@ void x509_parse_generalNames(chunk_t blob, int level0, bool implicit, linked_lis
 	{
 		if (objectID == GENERAL_NAMES_GN)
 		{
-			identification_t *gn = parse_generalName(object,
-											parser->get_level(parser)+1);
-
-			if (gn)
+			gn = parse_generalName(object, parser->get_level(parser)+1);
+			if (!gn)
 			{
-				list->insert_last(list, (void *)gn);
+				goto end;
 			}
+			list->insert_last(list, (void *)gn);
 		}
 	}
+	success = parser->success(parser);
+
+end:
 	parser->destroy(parser);
+
+	return success;
 }
 
 /**
@@ -579,6 +613,7 @@ chunk_t x509_parse_authorityKeyIdentifier(chunk_t blob, int level0,
 		}
 	}
 	parser->destroy(parser);
+
 	return authKeyIdentifier;
 }
 
@@ -599,13 +634,14 @@ static const asn1Object_t authInfoAccessObjects[] = {
 /**
  * Extracts an authorityInfoAcess location
  */
-static void parse_authorityInfoAccess(chunk_t blob, int level0,
+static bool parse_authorityInfoAccess(chunk_t blob, int level0,
 									  private_x509_cert_t *this)
 {
 	asn1_parser_t *parser;
 	chunk_t object;
 	int objectID;
 	int accessMethod = OID_UNKNOWN;
+	bool success = FALSE;
 
 	parser = asn1_parser_create(authInfoAccessObjects, blob);
 	parser->set_top_level(parser, level0);
@@ -636,7 +672,7 @@ static void parse_authorityInfoAccess(chunk_t blob, int level0,
 							}
 							DBG2(DBG_ASN, "  '%Y'", id);
 							if (accessMethod == OID_OCSP &&
-								asprintf(&uri, "%Y", id) > 0)
+								gn_to_string(id, &uri))
 							{
 								this->ocsp_uris->insert_last(this->ocsp_uris, uri);
 							}
@@ -653,9 +689,12 @@ static void parse_authorityInfoAccess(chunk_t blob, int level0,
 				break;
 		}
 	}
+	success = parser->success(parser);
 
 end:
 	parser->destroy(parser);
+
+	return success;
 }
 
 /**
@@ -726,12 +765,13 @@ static const asn1Object_t extendedKeyUsageObjects[] = {
 /**
  * Extracts extendedKeyUsage OIDs
  */
-static void parse_extendedKeyUsage(chunk_t blob, int level0,
+static bool parse_extendedKeyUsage(chunk_t blob, int level0,
 								   private_x509_cert_t *this)
 {
 	asn1_parser_t *parser;
 	chunk_t object;
 	int objectID;
+	bool success;
 
 	parser = asn1_parser_create(extendedKeyUsageObjects, blob);
 	parser->set_top_level(parser, level0);
@@ -762,27 +802,30 @@ static void parse_extendedKeyUsage(chunk_t blob, int level0,
 			}
 		}
 	}
+	success = parser->success(parser);
 	parser->destroy(parser);
+
+	return success;
 }
 
 /**
  * ASN.1 definition of crlDistributionPoints
  */
 static const asn1Object_t crlDistributionPointsObjects[] = {
-	{ 0, "crlDistributionPoints",	ASN1_SEQUENCE,		ASN1_LOOP			}, /*  0 */
-	{ 1,   "DistributionPoint",		ASN1_SEQUENCE,		ASN1_NONE			}, /*  1 */
-	{ 2,     "distributionPoint",	ASN1_CONTEXT_C_0,	ASN1_OPT|ASN1_LOOP	}, /*  2 */
-	{ 3,       "fullName",			ASN1_CONTEXT_C_0,	ASN1_OPT|ASN1_OBJ	}, /*  3 */
-	{ 3,       "end choice",		ASN1_EOC,			ASN1_END			}, /*  4 */
-	{ 3,       "nameRelToCRLIssuer",ASN1_CONTEXT_C_1,	ASN1_OPT|ASN1_BODY	}, /*  5 */
-	{ 3,       "end choice",		ASN1_EOC,			ASN1_END			}, /*  6 */
-	{ 2,     "end opt",				ASN1_EOC,			ASN1_END			}, /*  7 */
-	{ 2,     "reasons",				ASN1_CONTEXT_C_1,	ASN1_OPT|ASN1_BODY	}, /*  8 */
-	{ 2,     "end opt",				ASN1_EOC,			ASN1_END			}, /*  9 */
-	{ 2,     "crlIssuer",			ASN1_CONTEXT_C_2,	ASN1_OPT|ASN1_OBJ	}, /* 10 */
-	{ 2,     "end opt",				ASN1_EOC,			ASN1_END			}, /* 11 */
-	{ 0, "end loop",				ASN1_EOC,			ASN1_END			}, /* 12 */
-	{ 0, "exit",					ASN1_EOC,			ASN1_EXIT			}
+	{ 0, "crlDistributionPoints",   ASN1_SEQUENCE,    ASN1_LOOP            }, /*  0 */
+	{ 1,   "DistributionPoint",     ASN1_SEQUENCE,    ASN1_NONE            }, /*  1 */
+	{ 2,     "distributionPoint",   ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_CHOICE }, /*  2 */
+	{ 3,       "fullName",          ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_OBJ    }, /*  3 */
+	{ 3,       "end choice",        ASN1_EOC,         ASN1_END|ASN1_CH     }, /*  4 */
+	{ 3,       "nameRelToCRLIssuer",ASN1_CONTEXT_C_1, ASN1_OPT|ASN1_BODY   }, /*  5 */
+	{ 3,       "end choice",        ASN1_EOC,         ASN1_END|ASN1_CH     }, /*  6 */
+	{ 2,     "end opt/choices",     ASN1_EOC,         ASN1_END|ASN1_CHOICE }, /*  7 */
+	{ 2,     "reasons",             ASN1_CONTEXT_C_1, ASN1_OPT|ASN1_BODY   }, /*  8 */
+	{ 2,     "end opt",             ASN1_EOC,         ASN1_END             }, /*  9 */
+	{ 2,     "crlIssuer",           ASN1_CONTEXT_C_2, ASN1_OPT|ASN1_OBJ    }, /* 10 */
+	{ 2,     "end opt",             ASN1_EOC,         ASN1_END             }, /* 11 */
+	{ 0, "end loop",                ASN1_EOC,         ASN1_END             }, /* 12 */
+	{ 0, "exit",                    ASN1_EOC,         ASN1_EXIT            }
 };
 #define CRL_DIST_POINTS				 1
 #define CRL_DIST_POINTS_FULLNAME	 3
@@ -801,7 +844,7 @@ static void add_cdps(linked_list_t *list, linked_list_t *uris,
 
 	while (uris->remove_last(uris, (void**)&id) == SUCCESS)
 	{
-		if (asprintf(&uri, "%Y", id) > 0)
+		if (gn_to_string(id, &uri))
 		{
 			if (issuers->get_count(issuers))
 			{
@@ -836,13 +879,14 @@ static void add_cdps(linked_list_t *list, linked_list_t *uris,
 /**
  * Extracts one or several crlDistributionPoints into a list
  */
-void x509_parse_crlDistributionPoints(chunk_t blob, int level0,
+bool x509_parse_crlDistributionPoints(chunk_t blob, int level0,
 									  linked_list_t *list)
 {
 	linked_list_t *uris, *issuers;
 	asn1_parser_t *parser;
 	chunk_t object;
 	int objectID;
+	bool success = FALSE;
 
 	uris = linked_list_create();
 	issuers = linked_list_create();
@@ -857,37 +901,45 @@ void x509_parse_crlDistributionPoints(chunk_t blob, int level0,
 				add_cdps(list, uris, issuers);
 				break;
 			case CRL_DIST_POINTS_FULLNAME:
-				x509_parse_generalNames(object, parser->get_level(parser) + 1,
-										TRUE, uris);
+				if (!x509_parse_generalNames(object,
+								parser->get_level(parser) + 1, TRUE, uris))
+				{
+					goto end;
+				}
 				break;
 			case CRL_DIST_POINTS_ISSUER:
-				x509_parse_generalNames(object, parser->get_level(parser) + 1,
-										TRUE, issuers);
+				if (!x509_parse_generalNames(object,
+								parser->get_level(parser) + 1, TRUE, issuers))
+				{
+					goto end;
+				}
 				break;
 			default:
 				break;
 		}
 	}
-	parser->destroy(parser);
-
+	success = parser->success(parser);
 	add_cdps(list, uris, issuers);
 
-	uris->destroy(uris);
-	issuers->destroy(issuers);
+end:
+	parser->destroy(parser);
+	uris->destroy_offset(uris, offsetof(identification_t, destroy));
+	issuers->destroy_offset(issuers, offsetof(identification_t, destroy));
+
+	return success;
 }
 
 /**
  * ASN.1 definition of nameConstraints
  */
 static const asn1Object_t nameConstraintsObjects[] = {
-	{ 0, "nameConstraints",			ASN1_SEQUENCE,		ASN1_LOOP			}, /*  0 */
+	{ 0, "nameConstraints",			ASN1_SEQUENCE,		ASN1_NONE			}, /*  0 */
 	{ 1,   "permittedSubtrees",		ASN1_CONTEXT_C_0,	ASN1_OPT|ASN1_LOOP	}, /*  1 */
 	{ 2,     "generalSubtree",		ASN1_SEQUENCE,		ASN1_BODY			}, /*  2 */
 	{ 1,   "end loop",				ASN1_EOC,			ASN1_END			}, /*  3 */
 	{ 1,   "excludedSubtrees",		ASN1_CONTEXT_C_1,	ASN1_OPT|ASN1_LOOP	}, /*  4 */
 	{ 2,     "generalSubtree",		ASN1_SEQUENCE,		ASN1_BODY			}, /*  5 */
 	{ 1,   "end loop",				ASN1_EOC,			ASN1_END			}, /*  6 */
-	{ 0, "end loop",				ASN1_EOC,			ASN1_END			}, /*  7 */
 	{ 0, "exit",					ASN1_EOC,			ASN1_EXIT			}
 };
 #define NAME_CONSTRAINT_PERMITTED 2
@@ -896,13 +948,14 @@ static const asn1Object_t nameConstraintsObjects[] = {
 /**
  * Parse permitted/excluded nameConstraints
  */
-static void parse_nameConstraints(chunk_t blob, int level0,
+static bool parse_nameConstraints(chunk_t blob, int level0,
 								  private_x509_cert_t *this)
 {
 	asn1_parser_t *parser;
 	identification_t *id;
 	chunk_t object;
 	int objectID;
+	bool success = FALSE;
 
 	parser = asn1_parser_create(nameConstraintsObjects, blob);
 	parser->set_top_level(parser, level0);
@@ -913,59 +966,69 @@ static void parse_nameConstraints(chunk_t blob, int level0,
 		{
 			case NAME_CONSTRAINT_PERMITTED:
 				id = parse_generalName(object, parser->get_level(parser) + 1);
-				if (id)
+				if (!id)
 				{
-					this->permitted_names->insert_last(this->permitted_names, id);
+					goto end;
 				}
+				this->permitted_names->insert_last(this->permitted_names, id);
 				break;
 			case NAME_CONSTRAINT_EXCLUDED:
 				id = parse_generalName(object, parser->get_level(parser) + 1);
-				if (id)
+				if (!id)
 				{
-					this->excluded_names->insert_last(this->excluded_names, id);
+					goto end;
 				}
+				this->excluded_names->insert_last(this->excluded_names, id);
 				break;
 			default:
 				break;
 		}
 	}
+	success = parser->success(parser);
+
+end:
 	parser->destroy(parser);
+
+	return success;
 }
 
 /**
  * ASN.1 definition of a certificatePolicies extension
  */
 static const asn1Object_t certificatePoliciesObject[] = {
-	{ 0, "certificatePolicies",		ASN1_SEQUENCE,	ASN1_LOOP			}, /*  0 */
-	{ 1,   "policyInformation",		ASN1_SEQUENCE,	ASN1_NONE			}, /*  1 */
-	{ 2,     "policyId",			ASN1_OID,		ASN1_BODY			}, /*  2 */
-	{ 2,     "qualifiers",			ASN1_SEQUENCE,	ASN1_OPT|ASN1_LOOP	}, /*  3 */
-	{ 3,       "qualifierInfo",		ASN1_SEQUENCE,	ASN1_NONE			}, /*  4 */
-	{ 4,         "qualifierId",		ASN1_OID,		ASN1_BODY			}, /*  5 */
-	{ 4,         "cPSuri",			ASN1_IA5STRING,	ASN1_OPT|ASN1_BODY	}, /*  6 */
-	{ 4,         "end choice",		ASN1_EOC,		ASN1_END			}, /*  7 */
-	{ 4,         "userNotice",		ASN1_SEQUENCE,	ASN1_OPT|ASN1_BODY	}, /*  8 */
-	{ 5,           "explicitText",	ASN1_EOC,		ASN1_RAW			}, /*  9 */
-	{ 4,         "end choice",		ASN1_EOC,		ASN1_END			}, /* 10 */
-	{ 2,      "end opt/loop",		ASN1_EOC,		ASN1_END			}, /* 12 */
-	{ 0, "end loop",				ASN1_EOC,		ASN1_END			}, /* 13 */
-	{ 0, "exit",					ASN1_EOC,		ASN1_EXIT			}
+	{ 0, "certificatePolicies",      ASN1_SEQUENCE,  ASN1_LOOP            }, /*  0 */
+	{ 1,   "policyInformation",      ASN1_SEQUENCE,  ASN1_NONE            }, /*  1 */
+	{ 2,     "policyId",             ASN1_OID,       ASN1_BODY            }, /*  2 */
+	{ 2,     "qualifiers",           ASN1_SEQUENCE,  ASN1_OPT|ASN1_LOOP   }, /*  3 */
+	{ 3,       "qualifierInfo",      ASN1_SEQUENCE,  ASN1_NONE            }, /*  4 */
+	{ 4,         "qualifierId",      ASN1_OID,       ASN1_BODY            }, /*  5 */
+	{ 4,         "qualifier",        ASN1_EOC,       ASN1_CHOICE          }, /*  6 */
+	{ 5,           "cPSuri",         ASN1_IA5STRING, ASN1_OPT|ASN1_BODY   }, /*  7 */
+	{ 5,           "end choice",     ASN1_EOC,       ASN1_END|ASN1_CH     }, /*  8 */
+	{ 5,           "userNotice",     ASN1_SEQUENCE,  ASN1_OPT|ASN1_BODY   }, /*  9 */
+	{ 6,             "explicitText", ASN1_EOC,       ASN1_RAW             }, /* 10 */
+	{ 5,           "end choice",     ASN1_EOC,       ASN1_END|ASN1_CH     }, /* 11 */
+	{ 4,         "end choices",      ASN1_EOC,       ASN1_END|ASN1_CHOICE }, /* 12 */
+	{ 2,     "end opt/loop",         ASN1_EOC,       ASN1_END             }, /* 13 */
+	{ 0, "end loop",                 ASN1_EOC,       ASN1_END             }, /* 14 */
+	{ 0, "exit",                     ASN1_EOC,       ASN1_EXIT            }
 };
-#define CERT_POLICY_ID				2
-#define CERT_POLICY_QUALIFIER_ID	5
-#define CERT_POLICY_CPS_URI			6
-#define CERT_POLICY_EXPLICIT_TEXT	9
+#define CERT_POLICY_ID              2
+#define CERT_POLICY_QUALIFIER_ID    5
+#define CERT_POLICY_CPS_URI         7
+#define CERT_POLICY_EXPLICIT_TEXT  10
 
 /**
  * Parse certificatePolicies
  */
-static void parse_certificatePolicies(chunk_t blob, int level0,
+static bool parse_certificatePolicies(chunk_t blob, int level0,
 									  private_x509_cert_t *this)
 {
 	x509_cert_policy_t *policy = NULL;
 	asn1_parser_t *parser;
 	chunk_t object;
 	int objectID, qualifier = OID_UNKNOWN;
+	bool success;
 
 	parser = asn1_parser_create(certificatePoliciesObject, blob);
 	parser->set_top_level(parser, level0);
@@ -998,7 +1061,10 @@ static void parse_certificatePolicies(chunk_t blob, int level0,
 				break;
 		}
 	}
+	success = parser->success(parser);
 	parser->destroy(parser);
+
+	return success;
 }
 
 /**
@@ -1019,13 +1085,14 @@ static const asn1Object_t policyMappingsObjects[] = {
 /**
  * Parse policyMappings
  */
-static void parse_policyMappings(chunk_t blob, int level0,
+static bool parse_policyMappings(chunk_t blob, int level0,
 								 private_x509_cert_t *this)
 {
 	x509_policy_mapping_t *map = NULL;
 	asn1_parser_t *parser;
 	chunk_t object;
 	int objectID;
+	bool success;
 
 	parser = asn1_parser_create(policyMappingsObjects, blob);
 	parser->set_top_level(parser, level0);
@@ -1054,7 +1121,10 @@ static void parse_policyMappings(chunk_t blob, int level0,
 				break;
 		}
 	}
+	success = parser->success(parser);
 	parser->destroy(parser);
+
+	return success;
 }
 
 /**
@@ -1076,12 +1146,13 @@ static const asn1Object_t policyConstraintsObjects[] = {
 /**
  * Parse policyConstraints
  */
-static void parse_policyConstraints(chunk_t blob, int level0,
+static bool parse_policyConstraints(chunk_t blob, int level0,
 									private_x509_cert_t *this)
 {
 	asn1_parser_t *parser;
 	chunk_t object;
 	int objectID;
+	bool success;
 
 	parser = asn1_parser_create(policyConstraintsObjects, blob);
 	parser->set_top_level(parser, level0);
@@ -1100,34 +1171,41 @@ static void parse_policyConstraints(chunk_t blob, int level0,
 				break;
 		}
 	}
+	success = parser->success(parser);
 	parser->destroy(parser);
+
+	return success;
 }
 
 /**
  * ASN.1 definition of ipAddrBlocks according to RFC 3779
  */
 static const asn1Object_t ipAddrBlocksObjects[] = {
-	{ 0, "ipAddrBlocks",			ASN1_SEQUENCE,		ASN1_LOOP			}, /*  0 */
-	{ 1,   "ipAddressFamily",		ASN1_SEQUENCE,		ASN1_NONE			}, /*  1 */
-	{ 2,     "addressFamily",		ASN1_OCTET_STRING,	ASN1_BODY			}, /*  2 */
-	{ 2,     "inherit",				ASN1_NULL,			ASN1_OPT|ASN1_NONE	}, /*  3 */
-	{ 2,     "end choice",			ASN1_EOC,			ASN1_END			}, /*  4 */
-	{ 2,     "addressesOrRanges",	ASN1_SEQUENCE,		ASN1_OPT|ASN1_LOOP	}, /*  5 */
-	{ 3,       "addressPrefix",		ASN1_BIT_STRING,	ASN1_OPT|ASN1_BODY  }, /*  6 */
-	{ 3,       "end choice",		ASN1_EOC,			ASN1_END			}, /*  7 */
-	{ 3,       "addressRange",		ASN1_SEQUENCE,		ASN1_OPT|ASN1_NONE	}, /*  8 */
-	{ 4,         "min",				ASN1_BIT_STRING,	ASN1_BODY			}, /*  9 */
-	{ 4,         "max",				ASN1_BIT_STRING,	ASN1_BODY			}, /* 10 */
-	{ 3,       "end choice",		ASN1_EOC,			ASN1_END			}, /* 11 */
-	{ 2,     "end opt/loop",		ASN1_EOC,			ASN1_END			}, /* 12 */
-	{ 0, "end loop",				ASN1_EOC,			ASN1_END			}, /* 13 */
-	{ 0, "exit",					ASN1_EOC,			ASN1_EXIT			}
+	{ 0, "ipAddrBlocks",            ASN1_SEQUENCE,     ASN1_LOOP            }, /*  0 */
+	{ 1,   "ipAddressFamily",       ASN1_SEQUENCE,     ASN1_NONE            }, /*  1 */
+	{ 2,     "addressFamily",       ASN1_OCTET_STRING, ASN1_BODY            }, /*  2 */
+	{ 2,     "ipAddressChoice",     ASN1_EOC,          ASN1_CHOICE          }, /*  3 */
+	{ 3,       "inherit",           ASN1_NULL,         ASN1_OPT             }, /*  4 */
+	{ 3,       "end choice",        ASN1_EOC,          ASN1_END|ASN1_CH     }, /*  5 */
+	{ 3,       "addressesOrRanges", ASN1_SEQUENCE,     ASN1_OPT|ASN1_LOOP   }, /*  6 */
+	{ 4,         "addressOrRange",  ASN1_EOC,          ASN1_CHOICE          }, /*  7 */
+	{ 5,           "addressPrefix", ASN1_BIT_STRING,   ASN1_OPT|ASN1_BODY   }, /*  8 */
+	{ 5,           "end choice",    ASN1_EOC,          ASN1_END|ASN1_CH     }, /*  9 */
+	{ 5,           "addressRange",  ASN1_SEQUENCE,     ASN1_OPT             }, /* 10 */
+	{ 6,             "min",         ASN1_BIT_STRING,   ASN1_BODY            }, /* 11 */
+	{ 6,             "max",         ASN1_BIT_STRING,   ASN1_BODY            }, /* 12 */
+	{ 5,           "end choice",    ASN1_EOC,          ASN1_END|ASN1_CH     }, /* 13 */
+	{ 4,         "end choices",     ASN1_EOC,          ASN1_END|ASN1_CHOICE }, /* 14 */
+	{ 3,       "end loop/choice",   ASN1_EOC,          ASN1_END|ASN1_CH     }, /* 15 */
+	{ 2,     "end choices",         ASN1_EOC,          ASN1_END|ASN1_CHOICE }, /* 16 */
+	{ 0, "end loop",                ASN1_EOC,          ASN1_END             }, /* 17 */
+	{ 0, "exit",                    ASN1_EOC,          ASN1_EXIT            }
 };
 #define IP_ADDR_BLOCKS_FAMILY       2
-#define IP_ADDR_BLOCKS_INHERIT      3
-#define IP_ADDR_BLOCKS_PREFIX       6
-#define IP_ADDR_BLOCKS_MIN          9
-#define IP_ADDR_BLOCKS_MAX         10
+#define IP_ADDR_BLOCKS_INHERIT      4
+#define IP_ADDR_BLOCKS_PREFIX       8
+#define IP_ADDR_BLOCKS_MIN         11
+#define IP_ADDR_BLOCKS_MAX         12
 
 static bool check_address_object(ts_type_t ts_type, chunk_t object)
 {
@@ -1171,7 +1249,7 @@ static bool check_address_object(ts_type_t ts_type, chunk_t object)
 	return TRUE;
 }
 
-static void parse_ipAddrBlocks(chunk_t blob, int level0,
+static bool parse_ipAddrBlocks(chunk_t blob, int level0,
 							   private_x509_cert_t *this)
 {
 	asn1_parser_t *parser;
@@ -1179,6 +1257,7 @@ static void parse_ipAddrBlocks(chunk_t blob, int level0,
 	ts_type_t ts_type = 0;
 	traffic_selector_t *ts;
 	int objectID;
+	bool success = FALSE;
 
 	parser = asn1_parser_create(ipAddrBlocksObjects, blob);
 	parser->set_top_level(parser, level0);
@@ -1240,10 +1319,13 @@ static void parse_ipAddrBlocks(chunk_t blob, int level0,
 				break;
 		}
 	}
+	success = parser->success(parser);
 	this->flags |= X509_IP_ADDR_BLOCKS;
 
 end:
 	parser->destroy(parser);
+
+	return success;
 }
 
 /**
@@ -1387,43 +1469,74 @@ static bool parse_certificate(private_x509_cert_t *this)
 						this->subjectKeyIdentifier = object;
 						break;
 					case OID_SUBJECT_ALT_NAME:
-						x509_parse_generalNames(object, level, FALSE,
-												this->subjectAltNames);
+						if (!x509_parse_generalNames(object, level, FALSE,
+													 this->subjectAltNames))
+						{
+							goto end;
+						}
 						break;
 					case OID_BASIC_CONSTRAINTS:
-						parse_basicConstraints(object, level, this);
+						if (!parse_basicConstraints(object, level, this))
+						{
+							goto end;
+						}
 						break;
 					case OID_CRL_DISTRIBUTION_POINTS:
-						x509_parse_crlDistributionPoints(object, level,
-														 this->crl_uris);
+						if (!x509_parse_crlDistributionPoints(object, level,
+															  this->crl_uris))
+						{
+							goto end;
+						}
 						break;
 					case OID_AUTHORITY_KEY_ID:
-						this->authKeyIdentifier = x509_parse_authorityKeyIdentifier(object,
-														level, &this->authKeySerialNumber);
+						chunk_free(&this->authKeyIdentifier);
+						this->authKeyIdentifier = x509_parse_authorityKeyIdentifier(
+									object, level, &this->authKeySerialNumber);
 						break;
 					case OID_AUTHORITY_INFO_ACCESS:
-						parse_authorityInfoAccess(object, level, this);
+						if (!parse_authorityInfoAccess(object, level, this))
+						{
+							goto end;
+						}
 						break;
 					case OID_KEY_USAGE:
 						parse_keyUsage(object, this);
 						break;
 					case OID_EXTENDED_KEY_USAGE:
-						parse_extendedKeyUsage(object, level, this);
+						if (!parse_extendedKeyUsage(object, level, this))
+						{
+							goto end;
+						}
 						break;
 					case OID_IP_ADDR_BLOCKS:
-						parse_ipAddrBlocks(object, level, this);
+						if (!parse_ipAddrBlocks(object, level, this))
+						{
+							goto end;
+						}
 						break;
 					case OID_NAME_CONSTRAINTS:
-						parse_nameConstraints(object, level, this);
+						if (!parse_nameConstraints(object, level, this))
+						{
+							goto end;
+						}
 						break;
 					case OID_CERTIFICATE_POLICIES:
-						parse_certificatePolicies(object, level, this);
+						if (!parse_certificatePolicies(object, level, this))
+						{
+							goto end;
+						}
 						break;
 					case OID_POLICY_MAPPINGS:
-						parse_policyMappings(object, level, this);
+						if (!parse_policyMappings(object, level, this))
+						{
+							goto end;
+						}
 						break;
 					case OID_POLICY_CONSTRAINTS:
-						parse_policyConstraints(object, level, this);
+						if (!parse_policyConstraints(object, level, this))
+						{
+							goto end;
+						}
 						break;
 					case OID_INHIBIT_ANY_POLICY:
 						if (!asn1_parse_simple_object(&object, ASN1_INTEGER,
diff --git a/src/libstrongswan/plugins/x509/x509_crl.c b/src/libstrongswan/plugins/x509/x509_crl.c
index 4d7e7bd..d8913ad 100644
--- a/src/libstrongswan/plugins/x509/x509_crl.c
+++ b/src/libstrongswan/plugins/x509/x509_crl.c
@@ -1,6 +1,7 @@
 /*
  * Copyright (C) 2008-2009 Martin Willi
- * Hochschule fuer Technik Rapperswil
+ * Copyright (C) 2017 Andreas Steffen
+ * HSR 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
@@ -149,7 +150,7 @@ extern chunk_t x509_parse_authorityKeyIdentifier(chunk_t blob, int level0,
 /**
  * from x509_cert
  */
-extern void x509_parse_crlDistributionPoints(chunk_t blob, int level0,
+extern bool x509_parse_crlDistributionPoints(chunk_t blob, int level0,
 											 linked_list_t *list);
 
 /**
@@ -309,8 +310,11 @@ static bool parse(private_x509_crl_t *this)
 						this->crlNumber = object;
 						break;
 					case OID_FRESHEST_CRL:
-						x509_parse_crlDistributionPoints(object, level,
-														 this->crl_uris);
+						if (!x509_parse_crlDistributionPoints(object, level,
+															  this->crl_uris))
+						{
+							goto end;
+						}
 						break;
 					case OID_DELTA_CRL_INDICATOR:
 						if (!asn1_parse_simple_object(&object, ASN1_INTEGER,
@@ -360,25 +364,33 @@ end:
 	return success;
 }
 
-/**
- * enumerator filter callback for create_enumerator
- */
-static bool filter(void *data, revoked_t **revoked, chunk_t *serial, void *p2,
-				   time_t *date, void *p3, crl_reason_t *reason)
+CALLBACK(filter, bool,
+	void *data, enumerator_t *orig, va_list args)
 {
-	if (serial)
-	{
-		*serial = (*revoked)->serial;
-	}
-	if (date)
-	{
-		*date = (*revoked)->date;
-	}
-	if (reason)
+	revoked_t *revoked;
+	crl_reason_t *reason;
+	chunk_t *serial;
+	time_t *date;
+
+	VA_ARGS_VGET(args, serial, date, reason);
+
+	if (orig->enumerate(orig, &revoked))
 	{
-		*reason = (*revoked)->reason;
+		if (serial)
+		{
+			*serial = revoked->serial;
+		}
+		if (date)
+		{
+			*date = revoked->date;
+		}
+		if (reason)
+		{
+			*reason = revoked->reason;
+		}
+		return TRUE;
 	}
-	return TRUE;
+	return FALSE;
 }
 
 METHOD(crl_t, get_serial, chunk_t,
@@ -418,7 +430,7 @@ METHOD(crl_t, create_enumerator, enumerator_t*,
 {
 	return enumerator_create_filter(
 								this->revoked->create_enumerator(this->revoked),
-								(void*)filter, NULL, NULL);
+								filter, NULL, NULL);
 }
 
 METHOD(certificate_t, get_type, certificate_type_t,
diff --git a/src/libstrongswan/plugins/x509/x509_ocsp_response.c b/src/libstrongswan/plugins/x509/x509_ocsp_response.c
index b46af30..140e9bf 100644
--- a/src/libstrongswan/plugins/x509/x509_ocsp_response.c
+++ b/src/libstrongswan/plugins/x509/x509_ocsp_response.c
@@ -228,32 +228,38 @@ METHOD(ocsp_response_t, create_cert_enumerator, enumerator_t*,
 	return this->certs->create_enumerator(this->certs);
 }
 
-/**
- * enumerator filter callback for create_response_enumerator
- */
-static bool filter(void *data, single_response_t **response,
-				   chunk_t *serialNumber,
-				   void *p2, cert_validation_t *status,
-				   void *p3, time_t *revocationTime,
-				   void *p4, crl_reason_t *revocationReason)
+CALLBACK(filter, bool,
+	void *data, enumerator_t *orig, va_list args)
 {
-	if (serialNumber)
-	{
-		*serialNumber = (*response)->serialNumber;
-	}
-	if (status)
-	{
-		*status = (*response)->status;
-	}
-	if (revocationTime)
-	{
-		*revocationTime = (*response)->revocationTime;
-	}
-	if (revocationReason)
+	single_response_t *response;
+	cert_validation_t *status;
+	crl_reason_t *revocationReason;
+	chunk_t *serialNumber;
+	time_t *revocationTime;
+
+	VA_ARGS_VGET(args, serialNumber, status, revocationTime, revocationReason);
+
+	if (orig->enumerate(orig, &response))
 	{
-		*revocationReason = (*response)->revocationReason;
+		if (serialNumber)
+		{
+			*serialNumber = response->serialNumber;
+		}
+		if (status)
+		{
+			*status = response->status;
+		}
+		if (revocationTime)
+		{
+			*revocationTime = response->revocationTime;
+		}
+		if (revocationReason)
+		{
+			*revocationReason = response->revocationReason;
+		}
+		return TRUE;
 	}
-	return TRUE;
+	return FALSE;
 }
 
 METHOD(ocsp_response_t, create_response_enumerator, enumerator_t*,
@@ -261,7 +267,7 @@ METHOD(ocsp_response_t, create_response_enumerator, enumerator_t*,
 {
 	return enumerator_create_filter(
 				this->responses->create_enumerator(this->responses),
-				(void*)filter, NULL, NULL);
+				filter, NULL, NULL);
 }
 
 /**
diff --git a/src/libstrongswan/plugins/x509/x509_pkcs10.c b/src/libstrongswan/plugins/x509/x509_pkcs10.c
index 20561f7..e39e24b 100644
--- a/src/libstrongswan/plugins/x509/x509_pkcs10.c
+++ b/src/libstrongswan/plugins/x509/x509_pkcs10.c
@@ -1,7 +1,6 @@
 /*
  * Copyright (C) 2005 Jan Hutter, Martin Willi
- * Copyright (C) 2009 Andreas Steffen
- *
+ * Copyright (C) 2009-2017 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -101,7 +100,8 @@ struct private_x509_pkcs10_t {
 /**
  * Imported from x509_cert.c
  */
-extern void x509_parse_generalNames(chunk_t blob, int level0, bool implicit, linked_list_t *list);
+extern bool x509_parse_generalNames(chunk_t blob, int level0, bool implicit,
+									linked_list_t *list);
 extern chunk_t x509_build_subjectAltNames(linked_list_t *list);
 
 METHOD(certificate_t, get_type, certificate_type_t,
@@ -290,8 +290,11 @@ static bool parse_extension_request(private_x509_pkcs10_t *this, chunk_t blob, i
 				switch (extn_oid)
 				{
 					case OID_SUBJECT_ALT_NAME:
-						x509_parse_generalNames(object, level, FALSE,
-												this->subjectAltNames);
+						if (!x509_parse_generalNames(object, level, FALSE,
+													 this->subjectAltNames))
+						{
+							goto end;
+						}
 						break;
 					default:
 						break;
@@ -303,7 +306,10 @@ static bool parse_extension_request(private_x509_pkcs10_t *this, chunk_t blob, i
 		}
 	}
 	success = parser->success(parser);
+
+end:
 	parser->destroy(parser);
+
 	return success;
 }
 
diff --git a/src/libstrongswan/plugins/xcbc/Makefile.in b/src/libstrongswan/plugins/xcbc/Makefile.in
index 78f9268..a231308 100644
--- a/src/libstrongswan/plugins/xcbc/Makefile.in
+++ b/src/libstrongswan/plugins/xcbc/Makefile.in
@@ -355,6 +355,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -377,6 +378,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/processing/processor.c b/src/libstrongswan/processing/processor.c
index 27e5ab5..bd8d534 100644
--- a/src/libstrongswan/processing/processor.c
+++ b/src/libstrongswan/processing/processor.c
@@ -429,7 +429,15 @@ METHOD(processor_t, execute_job, void,
 METHOD(processor_t, set_threads, void,
 	private_processor_t *this, u_int count)
 {
+	int i;
+
 	this->mutex->lock(this->mutex);
+	for (i = 0; i < JOB_PRIO_MAX; i++)
+	{
+		this->prio_threads[i] = lib->settings->get_int(lib->settings,
+						"%s.processor.priority_threads.%N", 0, lib->ns,
+						job_priority_names, i);
+	}
 	if (count > this->total_threads)
 	{	/* increase thread count */
 		worker_thread_t *worker;
@@ -551,13 +559,10 @@ processor_t *processor_create()
 		.job_added = condvar_create(CONDVAR_TYPE_DEFAULT),
 		.thread_terminated = condvar_create(CONDVAR_TYPE_DEFAULT),
 	);
+
 	for (i = 0; i < JOB_PRIO_MAX; i++)
 	{
 		this->jobs[i] = linked_list_create();
-		this->prio_threads[i] = lib->settings->get_int(lib->settings,
-						"%s.processor.priority_threads.%N", 0, lib->ns,
-						job_priority_names, i);
 	}
-
 	return &this->public;
 }
diff --git a/src/libstrongswan/settings/settings.c b/src/libstrongswan/settings/settings.c
index b00e819..2a92d52 100644
--- a/src/libstrongswan/settings/settings.c
+++ b/src/libstrongswan/settings/settings.c
@@ -744,10 +744,8 @@ typedef struct {
 	hashtable_t *seen;
 } enumerator_data_t;
 
-/**
- * Destroy enumerator data
- */
-static void enumerator_destroy(enumerator_data_t *this)
+CALLBACK(enumerator_destroy, void,
+	enumerator_data_t *this)
 {
 	this->settings->lock->unlock(this->settings->lock);
 	this->seen->destroy(this->seen);
@@ -755,18 +753,25 @@ static void enumerator_destroy(enumerator_data_t *this)
 	free(this);
 }
 
-/**
- * Enumerate section names, not sections
- */
-static bool section_filter(hashtable_t *seen, section_t **in, char **out)
+CALLBACK(section_filter, bool,
+	hashtable_t *seen, enumerator_t *orig, va_list args)
 {
-	*out = (*in)->name;
-	if (seen->get(seen, *out))
+	section_t *section;
+	char **out;
+
+	VA_ARGS_VGET(args, out);
+
+	while (orig->enumerate(orig, &section))
 	{
-		return FALSE;
+		if (seen->get(seen, section->name))
+		{
+			continue;
+		}
+		*out = section->name;
+		seen->put(seen, section->name, section->name);
+		return TRUE;
 	}
-	seen->put(seen, *out, *out);
-	return TRUE;
+	return FALSE;
 }
 
 /**
@@ -776,8 +781,8 @@ static enumerator_t *section_enumerator(section_t *section,
 										enumerator_data_t *data)
 {
 	return enumerator_create_filter(
-			array_create_enumerator(section->sections_order),
-				(void*)section_filter, data->seen, NULL);
+							array_create_enumerator(section->sections_order),
+							section_filter, data->seen, NULL);
 }
 
 METHOD(settings_t, create_section_enumerator, enumerator_t*,
@@ -803,23 +808,29 @@ METHOD(settings_t, create_section_enumerator, enumerator_t*,
 		.seen = hashtable_create(hashtable_hash_str, hashtable_equals_str, 8),
 	);
 	return enumerator_create_nested(array_create_enumerator(sections),
-					(void*)section_enumerator, data, (void*)enumerator_destroy);
+						(void*)section_enumerator, data, enumerator_destroy);
 }
 
-/**
- * Enumerate key and values, not kv_t entries
- */
-static bool kv_filter(hashtable_t *seen, kv_t **in, char **key,
-					  void *none, char **value)
+CALLBACK(kv_filter, bool,
+	hashtable_t *seen, enumerator_t *orig, va_list args)
 {
-	*key = (*in)->key;
-	if (seen->get(seen, *key) || !(*in)->value)
+	kv_t *kv;
+	char **key, **value;
+
+	VA_ARGS_VGET(args, key, value);
+
+	while (orig->enumerate(orig, &kv))
 	{
-		return FALSE;
+		if (seen->get(seen, kv->key) || !kv->value)
+		{
+			continue;
+		}
+		*key = kv->key;
+		*value = kv->value;
+		seen->put(seen, kv->key, kv->key);
+		return TRUE;
 	}
-	*value = (*in)->value;
-	seen->put(seen, *key, *key);
-	return TRUE;
+	return FALSE;
 }
 
 /**
@@ -828,7 +839,7 @@ static bool kv_filter(hashtable_t *seen, kv_t **in, char **key,
 static enumerator_t *kv_enumerator(section_t *section, enumerator_data_t *data)
 {
 	return enumerator_create_filter(array_create_enumerator(section->kv_order),
-					(void*)kv_filter, data->seen, NULL);
+									kv_filter, data->seen, NULL);
 }
 
 METHOD(settings_t, create_key_value_enumerator, enumerator_t*,
diff --git a/src/libstrongswan/tests/Makefile.in b/src/libstrongswan/tests/Makefile.in
index f4c607c..279e179 100644
--- a/src/libstrongswan/tests/Makefile.in
+++ b/src/libstrongswan/tests/Makefile.in
@@ -396,6 +396,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -418,6 +419,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libstrongswan/tests/suites/test_asn1_parser.c b/src/libstrongswan/tests/suites/test_asn1_parser.c
index 973562b..ebbe7dd 100644
--- a/src/libstrongswan/tests/suites/test_asn1_parser.c
+++ b/src/libstrongswan/tests/suites/test_asn1_parser.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 Andreas Steffen
+ * Copyright (C) 2014-2017 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -250,6 +250,7 @@ START_TEST(test_asn1_parser_option)
 				i3 = *object.ptr;
 				break;
 			default:
+
 				break;
 		}
 	}
@@ -264,6 +265,105 @@ START_TEST(test_asn1_parser_option)
 }
 END_TEST
 
+/*******************************************************************************
+ * choice
+ */
+
+typedef struct {
+	int i1, i2, i3, i4;
+	chunk_t blob;
+} choice_test_t;
+
+static const asn1Object_t choiceObjects[] = {
+	{ 0, "choiceObject",      ASN1_EOC,          ASN1_CHOICE          }, /*  0 */
+	{ 1,   "choiceA",         ASN1_CONTEXT_C_0,  ASN1_OPT|ASN1_CHOICE }, /*  1 */
+	{ 2,     "choice1",       ASN1_OCTET_STRING, ASN1_OPT|ASN1_BODY   }, /*  2 */
+	{ 2,     "end choice1",   ASN1_EOC,          ASN1_END|ASN1_CH     }, /*  3 */
+	{ 2,     "choice2",       ASN1_INTEGER,      ASN1_OPT|ASN1_BODY   }, /*  4 */
+	{ 2,     "end choice2",   ASN1_EOC,          ASN1_END|ASN1_CH     }, /*  5 */
+	{ 1,   "end choiceA",     ASN1_EOC,          ASN1_END|ASN1_CHOICE|
+	                                             ASN1_CH              }, /*  6 */
+	{ 1,   "choiceB",         ASN1_SEQUENCE,     ASN1_OPT|ASN1_LOOP   }, /*  7 */
+	{ 2,     "choiceObject",  ASN1_EOC,          ASN1_CHOICE          }, /*  8 */
+	{ 3,       "choice3",     ASN1_INTEGER,      ASN1_OPT|ASN1_BODY   }, /*  9 */
+	{ 3,       "end choice3", ASN1_EOC,          ASN1_END|ASN1_CH     }, /* 10 */
+	{ 3,       "choice4",     ASN1_OCTET_STRING, ASN1_OPT|ASN1_BODY   }, /* 11 */
+	{ 3,       "end choice4", ASN1_EOC,          ASN1_END|ASN1_CH     }, /* 12 */
+	{ 2,     "end choices",   ASN1_EOC,          ASN1_END|ASN1_CHOICE }, /* 13 */
+	{ 1,   "end loop/choice", ASN1_EOC,          ASN1_END|ASN1_CH     }, /* 14 */
+	{ 0, "end choices",       ASN1_EOC,          ASN1_END|ASN1_CHOICE }, /* 15 */
+	{ 0, "exit",              ASN1_EOC,          ASN1_EXIT            }
+};
+
+choice_test_t choice_tests[] = {
+	{ 0, 0, 0, 0, { NULL, 0 } },
+	{ 0, 0, 0, 0, chunk_from_chars(0xA0, 0x00) },
+	{ 1, 0, 0, 0, chunk_from_chars(0xA0, 0x03, 0x04, 0x01, 0x01) },
+	{ 1, 0, 0, 0, chunk_from_chars(0xA0, 0x06, 0x04, 0x01, 0x01,
+	                                           0x02, 0x01, 0x02) },
+	{ 0, 2, 0, 0, chunk_from_chars(0xA0, 0x03, 0x02, 0x01, 0x02) },
+	{ 0, 2, 0, 0, chunk_from_chars(0xA0, 0x03, 0x02, 0x01, 0x02,
+	                               0x30, 0x03, 0x02, 0x01, 0x03) },
+	{ 0, 0, 0, 0, chunk_from_chars(0xA0, 0x04, 0x03, 0x02, 0x00, 0x04) },
+	{ 0, 0, 3, 0, chunk_from_chars(0x30, 0x03, 0x02, 0x01, 0x03) },
+	{ 0, 0, 0, 4, chunk_from_chars(0x30, 0x03, 0x04, 0x01, 0x04) },
+	{ 0, 0, 3, 4, chunk_from_chars(0x30, 0x06, 0x04, 0x01, 0x04,
+	                                           0x02, 0x01, 0x03) },
+	{ 0, 0, 3, 4, chunk_from_chars(0x30, 0x06, 0x02, 0x01, 0x03,
+	                                           0x04, 0x01, 0x04) },
+	{ 0, 0, 6, 0, chunk_from_chars(0x30, 0x06, 0x02, 0x01, 0x03,
+	                                           0x02, 0x01, 0x03) },
+	{ 0, 0, 0, 8, chunk_from_chars(0x30, 0x06, 0x04, 0x01, 0x04,
+	                                           0x04, 0x01, 0x04) },
+	{ 0, 0, 0, 0, chunk_from_chars(0x30, 0x04, 0x03, 0x02, 0x00, 0x04) },
+	{ 0, 0, 0, 0, chunk_from_chars(0x03, 0x02, 0x00, 0x04) }
+};
+
+START_TEST(test_asn1_parser_choice)
+{
+	asn1_parser_t *parser;
+	chunk_t object;
+	int objectID, i1 = 0, i2 = 0, i3 = 0, i4 = 0;
+	bool success;
+
+	parser = asn1_parser_create(choiceObjects, choice_tests[_i].blob);
+	while (parser->iterate(parser, &objectID, &object))
+	{
+		switch (objectID)
+		{
+			case 2:
+				i1 += *object.ptr;
+				break;
+			case 4:
+				i2 += *object.ptr;
+				break;
+			case 9:
+				i3 += *object.ptr;
+				break;
+			case 11:
+				i4 += *object.ptr;
+				break;
+			default:
+
+				break;
+		}
+	}
+	success = parser->success(parser);
+	parser->destroy(parser);
+
+	ck_assert(success == (choice_tests[_i].i1 ||
+						  choice_tests[_i].i2 ||
+						  choice_tests[_i].i3 ||
+						  choice_tests[_i].i4 ));
+
+	ck_assert(i1 == choice_tests[_i].i1 &&
+			  i2 == choice_tests[_i].i2 &&
+			  i3 == choice_tests[_i].i3 &&
+			  i4 == choice_tests[_i].i4 );
+}
+END_TEST
+
+
 Suite *asn1_parser_suite_create()
 {
 	Suite *s;
@@ -287,5 +387,9 @@ Suite *asn1_parser_suite_create()
 	tcase_add_loop_test(tc, test_asn1_parser_option, 0, countof(option_tests));
 	suite_add_tcase(s, tc);
 
+	tc = tcase_create("choice");
+	tcase_add_loop_test(tc, test_asn1_parser_choice, 0, countof(choice_tests));
+	suite_add_tcase(s, tc);
+
 	return s;
 }
diff --git a/src/libstrongswan/tests/suites/test_enumerator.c b/src/libstrongswan/tests/suites/test_enumerator.c
index 9bd6d24..b781ae9 100644
--- a/src/libstrongswan/tests/suites/test_enumerator.c
+++ b/src/libstrongswan/tests/suites/test_enumerator.c
@@ -104,25 +104,45 @@ static void destroy_data(void *data)
  * filtered test
  */
 
-static bool filter(int *data, int **v, int *vo, int **w, int *wo,
-				   int **x, int *xo, int **y, int *yo, int **z, int *zo)
+CALLBACK(filter, bool,
+	int *data, enumerator_t *orig, va_list args)
 {
-	int val = **v;
+	int *item, *vo, *wo, *xo, *yo, *zo;
 
-	*vo = val++;
-	*wo = val++;
-	*xo = val++;
-	*yo = val++;
-	*zo = val++;
-	fail_if(data != (void*)101, "data does not match '101' in filter function");
-	return TRUE;
+	VA_ARGS_VGET(args, vo, wo, xo, yo, zo);
+
+	if (orig->enumerate(orig, &item))
+	{
+		int val = *item;
+		*vo = val++;
+		*wo = val++;
+		*xo = val++;
+		*yo = val++;
+		*zo = val++;
+		fail_if(data != (void*)101, "data does not match '101' in filter function");
+		return TRUE;
+	}
+	return FALSE;
 }
 
-static bool filter_odd(void *data, int **item, int *out)
+CALLBACK(filter_odd, bool,
+	void *data, enumerator_t *orig, va_list args)
 {
+	int *item, *out;
+
+	VA_ARGS_VGET(args, out);
+
 	fail_if(data != (void*)101, "data does not match '101' in filter function");
-	*out = **item;
-	return **item % 2 == 0;
+
+	while (orig->enumerate(orig, &item))
+	{
+		if (*item % 2 == 0)
+		{
+			*out = *item;
+			return TRUE;
+		}
+	}
+	return FALSE;
 }
 
 START_TEST(test_filtered)
@@ -136,7 +156,7 @@ START_TEST(test_filtered)
 
 	round = 1;
 	enumerator = enumerator_create_filter(list->create_enumerator(list),
-									(void*)filter, (void*)101, destroy_data);
+										  filter, (void*)101, destroy_data);
 	while (enumerator->enumerate(enumerator, &v, &w, &x, &y, &z))
 	{
 		ck_assert_int_eq(v, round);
@@ -166,7 +186,7 @@ START_TEST(test_filtered_filter)
 	/* should also work without destructor, so set this manually */
 	destroy_data_called = 1;
 	enumerator = enumerator_create_filter(list->create_enumerator(list),
-										 (void*)filter_odd, (void*)101, NULL);
+										  filter_odd, (void*)101, NULL);
 	while (enumerator->enumerate(enumerator, &x))
 	{
 		ck_assert(x % 2 == 0);
diff --git a/src/libstrongswan/tests/suites/test_linked_list.c b/src/libstrongswan/tests/suites/test_linked_list.c
index 7a16181..aa1e042 100644
--- a/src/libstrongswan/tests/suites/test_linked_list.c
+++ b/src/libstrongswan/tests/suites/test_linked_list.c
@@ -183,26 +183,48 @@ END_TEST
  * find
  */
 
-static bool match_a_b(void *item, void *a, void *b)
+CALLBACK(find_a_b, bool,
+	void *item, va_list args)
 {
+	void *a, *b;
+
+	VA_ARGS_VGET(args, a, b);
 	ck_assert(a == (void*)1);
 	ck_assert(b == (void*)2);
 	return item == a || item == b;
 }
 
+CALLBACK(find_a, bool,
+	void *item, va_list args)
+{
+	void *a;
+
+	VA_ARGS_VGET(args, a);
+	return match_a(item, a);
+}
+
+CALLBACK(find_b, bool,
+	void *item, va_list args)
+{
+	void *b;
+
+	VA_ARGS_VGET(args, b);
+	return match_b(item, b);
+}
+
 START_TEST(test_find)
 {
 	void *a = (void*)1, *b = (void*)2;
 
-	ck_assert(list->find_first(list, NULL, &a) == NOT_FOUND);
+	ck_assert(!list->find_first(list, NULL, &a));
 	list->insert_last(list, a);
-	ck_assert(list->find_first(list, NULL, &a) == SUCCESS);
-	ck_assert(list->find_first(list, NULL, &b) == NOT_FOUND);
+	ck_assert(list->find_first(list, NULL, &a));
+	ck_assert(!list->find_first(list, NULL, &b));
 	list->insert_last(list, b);
-	ck_assert(list->find_first(list, NULL, &a) == SUCCESS);
-	ck_assert(list->find_first(list, NULL, &b) == SUCCESS);
+	ck_assert(list->find_first(list, NULL, &a));
+	ck_assert(list->find_first(list, NULL, &b));
 
-	ck_assert(list->find_first(list, NULL, NULL) == NOT_FOUND);
+	ck_assert(!list->find_first(list, NULL, NULL));
 }
 END_TEST
 
@@ -210,29 +232,57 @@ START_TEST(test_find_callback)
 {
 	void *a = (void*)1, *b = (void*)2, *x = NULL;
 
-	ck_assert(list->find_first(list, (linked_list_match_t)match_a_b, &x, a, b) == NOT_FOUND);
+	ck_assert(!list->find_first(list, find_a_b, &x, a, b));
 	list->insert_last(list, a);
-	ck_assert(list->find_first(list, (linked_list_match_t)match_a, NULL, a) == SUCCESS);
+	ck_assert(list->find_first(list, find_a, NULL, a));
 	x = NULL;
-	ck_assert(list->find_first(list, (linked_list_match_t)match_a, &x, a) == SUCCESS);
+	ck_assert(list->find_first(list, find_a, &x, a));
 	ck_assert(a == x);
-	ck_assert(list->find_first(list, (linked_list_match_t)match_b, &x, b) == NOT_FOUND);
+	ck_assert(!list->find_first(list, find_b, &x, b));
 	ck_assert(a == x);
 	x = NULL;
-	ck_assert(list->find_first(list, (linked_list_match_t)match_a_b, &x, a, b) == SUCCESS);
+	ck_assert(list->find_first(list, find_a_b, &x, a, b));
 	ck_assert(a == x);
 
 	list->insert_last(list, b);
-	ck_assert(list->find_first(list, (linked_list_match_t)match_a, &x, a) == SUCCESS);
+	ck_assert(list->find_first(list, find_a, &x, a));
 	ck_assert(a == x);
-	ck_assert(list->find_first(list, (linked_list_match_t)match_b, &x, b) == SUCCESS);
+	ck_assert(list->find_first(list, find_b, &x, b));
 	ck_assert(b == x);
 	x = NULL;
-	ck_assert(list->find_first(list, (linked_list_match_t)match_a_b, &x, a, b) == SUCCESS);
+	ck_assert(list->find_first(list, find_a_b, &x, a, b));
 	ck_assert(a == x);
 }
 END_TEST
 
+CALLBACK(find_args, bool,
+	void *item, va_list args)
+{
+	uint64_t d, e;
+	level_t c;
+	int *a, b;
+
+	VA_ARGS_VGET(args, a, b, c, d, e);
+	ck_assert_int_eq(*a, 1);
+	ck_assert_int_eq(b, 2);
+	ck_assert_int_eq(c, LEVEL_PRIVATE);
+	ck_assert_int_eq(d, UINT64_MAX);
+	ck_assert_int_eq(e, UINT64_MAX-1);
+	return item == a;
+}
+
+START_TEST(test_find_callback_args)
+{
+	int a = 1, b = 2, *x;
+	uint64_t d = UINT64_MAX;
+
+	list->insert_last(list, &a);
+	ck_assert(list->find_first(list, find_args, (void**)&x, &a, b,
+							   LEVEL_PRIVATE, d, UINT64_MAX-1));
+	ck_assert_int_eq(a, *x);
+}
+END_TEST
+
 /*******************************************************************************
  * invoke
  */
@@ -241,11 +291,16 @@ typedef struct invoke_t invoke_t;
 
 struct invoke_t {
 	int val;
-	void (*invoke)(invoke_t *item, void *a, void *b, void *c, void *d, int *sum);
+	void (*invoke)(invoke_t *item);
 };
 
-static void invoke(intptr_t item, void *a, void *b, void *c, void *d, int *sum)
+CALLBACK(invoke, void,
+	intptr_t item, va_list args)
 {
+	void *a, *b, *c, *d;
+	int *sum;
+
+	VA_ARGS_VGET(args, a, b, c, d, sum);
 	ck_assert_int_eq((uintptr_t)a, 1);
 	ck_assert_int_eq((uintptr_t)b, 2);
 	ck_assert_int_eq((uintptr_t)c, 3);
@@ -253,9 +308,9 @@ static void invoke(intptr_t item, void *a, void *b, void *c, void *d, int *sum)
 	*sum += item;
 }
 
-static void invoke_offset(invoke_t *item, void *a, void *b, void *c, void *d, int *sum)
+static void invoke_offset(invoke_t *item)
 {
-	invoke(item->val, a, b, c, d, sum);
+	item->val++;
 }
 
 START_TEST(test_invoke_function)
@@ -267,8 +322,7 @@ START_TEST(test_invoke_function)
 	list->insert_last(list, (void*)3);
 	list->insert_last(list, (void*)4);
 	list->insert_last(list, (void*)5);
-	list->invoke_function(list, (linked_list_invoke_t)invoke,
-						  (uintptr_t)1, (uintptr_t)2,
+	list->invoke_function(list, invoke, (uintptr_t)1, (uintptr_t)2,
 						  (uintptr_t)3, (uintptr_t)4, &sum);
 	ck_assert_int_eq(sum, 15);
 }
@@ -282,17 +336,19 @@ START_TEST(test_invoke_offset)
 		{ .val = 3, .invoke = invoke_offset, },
 		{ .val = 4, .invoke = invoke_offset, },
 		{ .val = 5, .invoke = invoke_offset, },
-	};
-	int i, sum = 0;
+	}, *item;
+	int i;
 
 	for (i = 0; i < countof(items); i++)
 	{
 		list->insert_last(list, &items[i]);
 	}
-	list->invoke_offset(list, offsetof(invoke_t, invoke),
-						(uintptr_t)1, (uintptr_t)2,
-						(uintptr_t)3, (uintptr_t)4, &sum);
-	ck_assert_int_eq(sum, 15);
+	list->invoke_offset(list, offsetof(invoke_t, invoke));
+	i = 2;
+	while (list->remove_first(list, (void**)&item) == SUCCESS)
+	{
+		ck_assert_int_eq(item->val, i++);
+	}
 }
 END_TEST
 
@@ -458,6 +514,7 @@ Suite *linked_list_suite_create()
 	tcase_add_checked_fixture(tc, setup_list, teardown_list);
 	tcase_add_test(tc, test_find);
 	tcase_add_test(tc, test_find_callback);
+	tcase_add_test(tc, test_find_callback_args);
 	suite_add_tcase(s, tc);
 
 	tc = tcase_create("invoke");
diff --git a/src/libstrongswan/tests/test_suite.h b/src/libstrongswan/tests/test_suite.h
index 66c6846..97c1b42 100644
--- a/src/libstrongswan/tests/test_suite.h
+++ b/src/libstrongswan/tests/test_suite.h
@@ -298,7 +298,7 @@ void test_fail_if_worker_failed();
 	chunk_t _a = (chunk_t)a; \
 	chunk_t _b = (chunk_t)b; \
 	test_fail_if_worker_failed(); \
-	if (_a.len != _b.len || !memeq(a.ptr, b.ptr, a.len)) \
+	if (_a.len != _b.len || !memeq(_a.ptr, _b.ptr, _a.len)) \
 	{ \
 		test_fail_msg(__FILE__, __LINE__, \
 					  #a " != " #b " (\"%#B\" != \"%#B\")", &_a, &_b); \
diff --git a/src/libstrongswan/utils/backtrace.c b/src/libstrongswan/utils/backtrace.c
index 6dd68d6..18b1916 100644
--- a/src/libstrongswan/utils/backtrace.c
+++ b/src/libstrongswan/utils/backtrace.c
@@ -668,8 +668,12 @@ typedef struct {
 } frame_enumerator_t;
 
 METHOD(enumerator_t, frame_enumerate, bool,
-	frame_enumerator_t *this, void **addr)
+	frame_enumerator_t *this, va_list args)
 {
+	void **addr;
+
+	VA_ARGS_VGET(args, addr);
+
 	if (this->i < this->bt->frame_count)
 	{
 		*addr = this->bt->frames[this->i++];
@@ -685,7 +689,8 @@ METHOD(backtrace_t, create_frame_enumerator, enumerator_t*,
 
 	INIT(enumerator,
 		.public = {
-			.enumerate = (void*)_frame_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _frame_enumerate,
 			.destroy = (void*)free,
 		},
 		.bt = this,
diff --git a/src/libstrongswan/utils/chunk.c b/src/libstrongswan/utils/chunk.c
index 0c50ab7..8f4b7ef 100644
--- a/src/libstrongswan/utils/chunk.c
+++ b/src/libstrongswan/utils/chunk.c
@@ -643,7 +643,7 @@ chunk_t chunk_from_base64(chunk_t base64, char *buf)
 		outlen += 3;
 		for (j = 0; j < 4; j++)
 		{
-			if (*pos == '=')
+			if (*pos == '=' && outlen > 0)
 			{
 				outlen--;
 			}
diff --git a/src/libstrongswan/utils/identification.c b/src/libstrongswan/utils/identification.c
index 384bd6c..1a47690 100644
--- a/src/libstrongswan/utils/identification.c
+++ b/src/libstrongswan/utils/identification.c
@@ -136,9 +136,12 @@ typedef struct {
 } rdn_enumerator_t;
 
 METHOD(enumerator_t, rdn_enumerate, bool,
-	rdn_enumerator_t *this, chunk_t *oid, u_char *type, chunk_t *data)
+	rdn_enumerator_t *this, va_list args)
 {
-	chunk_t rdn;
+	chunk_t rdn, *oid, *data;
+	u_char *type;
+
+	VA_ARGS_VGET(args, oid, type, data);
 
 	/* a DN contains one or more SET, each containing one or more SEQUENCES,
 	 * each containing a OID/value RDN */
@@ -173,7 +176,8 @@ static enumerator_t* create_rdn_enumerator(chunk_t dn)
 
 	INIT(e,
 		.public = {
-			.enumerate = (void*)_rdn_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _rdn_enumerate,
 			.destroy = (void*)free,
 		},
 	);
@@ -199,10 +203,11 @@ typedef struct {
 } rdn_part_enumerator_t;
 
 METHOD(enumerator_t, rdn_part_enumerate, bool,
-	rdn_part_enumerator_t *this, id_part_t *type, chunk_t *data)
+	rdn_part_enumerator_t *this, va_list args)
 {
 	int i, known_oid, strtype;
-	chunk_t oid, inner_data;
+	chunk_t oid, inner_data, *data;
+	id_part_t *type;
 	static const struct {
 		int oid;
 		id_part_t type;
@@ -228,6 +233,8 @@ METHOD(enumerator_t, rdn_part_enumerate, bool,
 		{OID_EMPLOYEE_NUMBER,	ID_PART_RDN_EN},
 	};
 
+	VA_ARGS_VGET(args, type, data);
+
 	while (this->inner->enumerate(this->inner, &oid, &strtype, &inner_data))
 	{
 		known_oid = asn1_known_oid(oid);
@@ -263,7 +270,8 @@ METHOD(identification_t, create_part_enumerator, enumerator_t*,
 			INIT(e,
 				.inner = create_rdn_enumerator(this->encoded),
 				.public = {
-					.enumerate = (void*)_rdn_part_enumerate,
+					.enumerate = enumerator_enumerate_default,
+					.venumerate = _rdn_part_enumerate,
 					.destroy = _rdn_part_enumerator_destroy,
 				},
 			);
diff --git a/src/libstrongswan/utils/leak_detective.c b/src/libstrongswan/utils/leak_detective.c
index ad67c03..1dfeea5 100644
--- a/src/libstrongswan/utils/leak_detective.c
+++ b/src/libstrongswan/utils/leak_detective.c
@@ -606,6 +606,9 @@ static char *whitelist[] = {
 	"system__tasking__stages__create_task",
 	/* in case external threads call into our code */
 	"thread_current_id",
+	/* FHH IMCs and IMVs */
+	"TNC_IMC_NotifyConnectionChange",
+	"TNC_IMV_NotifyConnectionChange",
 };
 
 /**
diff --git a/src/libstrongswan/utils/utils.h b/src/libstrongswan/utils/utils.h
index 0aed842..33b8d19 100644
--- a/src/libstrongswan/utils/utils.h
+++ b/src/libstrongswan/utils/utils.h
@@ -1,7 +1,7 @@
 /*
- * Copyright (C) 2008-2015 Tobias Brunner
+ * Copyright (C) 2008-2017 Tobias Brunner
  * Copyright (C) 2008 Martin Willi
- * Hochschule fuer Technik Rapperswil
+ * HSR 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
@@ -28,6 +28,7 @@
 #include <stddef.h>
 #include <sys/time.h>
 #include <string.h>
+#include <stdarg.h>
 
 #ifdef HAVE_SYS_PARAM_H
 #include <sys/param.h>
@@ -141,6 +142,49 @@ void utils_deinit();
 #define __VA_ARGS_DISPATCH(func, num) func ## num
 
 /**
+ * Assign variadic arguments to the given variables.
+ *
+ * @note The order and types of the variables are significant and must match the
+ * variadic arguments passed to the function that calls this macro exactly.
+ *
+ * @param last		the last argument before ... in the function that calls this
+ * @param ...		variable names
+ */
+#define VA_ARGS_GET(last, ...) ({ \
+	va_list _va_args_get_ap; \
+	va_start(_va_args_get_ap, last); \
+	_VA_ARGS_GET_ASGN(__VA_ARGS__) \
+	va_end(_va_args_get_ap); \
+})
+
+/**
+ * Assign variadic arguments from a va_list to the given variables.
+ *
+ * @note The order and types of the variables are significant and must match the
+ * variadic arguments passed to the function that calls this macro exactly.
+ *
+ * @param list		the va_list variable in the function that calls this
+ * @param ...		variable names
+ */
+#define VA_ARGS_VGET(list, ...) ({ \
+	va_list _va_args_get_ap; \
+	va_copy(_va_args_get_ap, list); \
+	_VA_ARGS_GET_ASGN(__VA_ARGS__) \
+	va_end(_va_args_get_ap); \
+})
+
+#define _VA_ARGS_GET_ASGN(...) VA_ARGS_DISPATCH(_VA_ARGS_GET_ASGN, __VA_ARGS__)(__VA_ARGS__)
+#define _VA_ARGS_GET_ASGN1(v1) __VA_ARGS_GET_ASGN(v1)
+#define _VA_ARGS_GET_ASGN2(v1,v2) __VA_ARGS_GET_ASGN(v1) __VA_ARGS_GET_ASGN(v2)
+#define _VA_ARGS_GET_ASGN3(v1,v2,v3) __VA_ARGS_GET_ASGN(v1) __VA_ARGS_GET_ASGN(v2) \
+	__VA_ARGS_GET_ASGN(v3)
+#define _VA_ARGS_GET_ASGN4(v1,v2,v3,v4) __VA_ARGS_GET_ASGN(v1) __VA_ARGS_GET_ASGN(v2) \
+	__VA_ARGS_GET_ASGN(v3) __VA_ARGS_GET_ASGN(v4)
+#define _VA_ARGS_GET_ASGN5(v1,v2,v3,v4,v5) __VA_ARGS_GET_ASGN(v1) __VA_ARGS_GET_ASGN(v2) \
+	__VA_ARGS_GET_ASGN(v3) __VA_ARGS_GET_ASGN(v4) __VA_ARGS_GET_ASGN(v5)
+#define __VA_ARGS_GET_ASGN(v) v = va_arg(_va_args_get_ap, typeof(v));
+
+/**
  * Macro to allocate a sized type.
  */
 #define malloc_thing(thing) ((thing*)malloc(sizeof(thing)))
diff --git a/src/libtls/Makefile.in b/src/libtls/Makefile.in
index 197ffc4..ee1d7fc 100644
--- a/src/libtls/Makefile.in
+++ b/src/libtls/Makefile.in
@@ -408,6 +408,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -430,6 +431,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libtls/tests/Makefile.in b/src/libtls/tests/Makefile.in
index 22eb099..8c87e1d 100644
--- a/src/libtls/tests/Makefile.in
+++ b/src/libtls/tests/Makefile.in
@@ -352,6 +352,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -374,6 +375,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libtls/tls_crypto.c b/src/libtls/tls_crypto.c
index 84b511f..05ae62b 100644
--- a/src/libtls/tls_crypto.c
+++ b/src/libtls/tls_crypto.c
@@ -1296,28 +1296,32 @@ static struct {
 	{ ECP_192_BIT, TLS_SECP192R1},
 };
 
-/**
- * Filter EC groups, add TLS curve
- */
-static bool group_filter(void *null,
-						diffie_hellman_group_t *in, diffie_hellman_group_t *out,
-						void* dummy1, tls_named_curve_t *curve)
+CALLBACK(group_filter, bool,
+	void *null, enumerator_t *orig, va_list args)
 {
+	diffie_hellman_group_t group, *out;
+	tls_named_curve_t *curve;
+	char *plugin;
 	int i;
 
-	for (i = 0; i < countof(curves); i++)
+	VA_ARGS_VGET(args, out, curve);
+
+	while (orig->enumerate(orig, &group, &plugin))
 	{
-		if (curves[i].group == *in)
+		for (i = 0; i < countof(curves); i++)
 		{
-			if (out)
-			{
-				*out = curves[i].group;
-			}
-			if (curve)
+			if (curves[i].group == group)
 			{
-				*curve = curves[i].curve;
+				if (out)
+				{
+					*out = curves[i].group;
+				}
+				if (curve)
+				{
+					*curve = curves[i].curve;
+				}
+				return TRUE;
 			}
-			return TRUE;
 		}
 	}
 	return FALSE;
@@ -1327,8 +1331,8 @@ METHOD(tls_crypto_t, create_ec_enumerator, enumerator_t*,
 	private_tls_crypto_t *this)
 {
 	return enumerator_create_filter(
-					lib->crypto->create_dh_enumerator(lib->crypto),
-					(void*)group_filter, NULL, NULL);
+							lib->crypto->create_dh_enumerator(lib->crypto),
+							group_filter, NULL, NULL);
 }
 
 METHOD(tls_crypto_t, set_protection, void,
diff --git a/src/libtnccs/Makefile.am b/src/libtnccs/Makefile.am
index 7a630fe..ff7b54f 100644
--- a/src/libtnccs/Makefile.am
+++ b/src/libtnccs/Makefile.am
@@ -26,6 +26,15 @@ tnc/tnccs/tnccs_manager.h tnc/tnccs/tnccs_manager.c
 
 EXTRA_DIST = Android.mk
 
+if STATIC_PLUGIN_CONSTRUCTORS
+BUILT_SOURCES = $(srcdir)/plugin_constructors.c
+CLEANFILES = $(srcdir)/plugin_constructors.c
+
+$(srcdir)/plugin_constructors.c: $(top_srcdir)/src/libstrongswan/plugins/plugin_constructors.py
+		$(AM_V_GEN) \
+		$(PYTHON) $(top_srcdir)/src/libstrongswan/plugins/plugin_constructors.py ${t_plugins} > $@
+endif
+
 # build optional plugins
 ########################
 
diff --git a/src/libtnccs/Makefile.in b/src/libtnccs/Makefile.in
index a22a631..653d841 100644
--- a/src/libtnccs/Makefile.in
+++ b/src/libtnccs/Makefile.in
@@ -412,6 +412,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -434,6 +435,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
@@ -521,6 +523,8 @@ tnc/tnccs/tnccs.h tnc/tnccs/tnccs.c \
 tnc/tnccs/tnccs_manager.h tnc/tnccs/tnccs_manager.c
 
 EXTRA_DIST = Android.mk
+ at STATIC_PLUGIN_CONSTRUCTORS_TRUE@BUILT_SOURCES = $(srcdir)/plugin_constructors.c
+ at STATIC_PLUGIN_CONSTRUCTORS_TRUE@CLEANFILES = $(srcdir)/plugin_constructors.c
 @MONOLITHIC_FALSE at SUBDIRS = . $(am__append_2) $(am__append_4) \
 @MONOLITHIC_FALSE@	$(am__append_6) $(am__append_8) \
 @MONOLITHIC_FALSE@	$(am__append_10) $(am__append_12)
@@ -530,7 +534,8 @@ EXTRA_DIST = Android.mk
 @MONOLITHIC_TRUE at SUBDIRS = $(am__append_2) $(am__append_4) \
 @MONOLITHIC_TRUE@	$(am__append_6) $(am__append_8) \
 @MONOLITHIC_TRUE@	$(am__append_10) $(am__append_12)
-all: all-recursive
+all: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) all-recursive
 
 .SUFFIXES:
 .SUFFIXES: .c .lo .o .obj
@@ -832,14 +837,16 @@ distdir: $(DISTFILES)
 	  fi; \
 	done
 check-am: all-am
-check: check-recursive
+check: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) check-recursive
 all-am: Makefile $(LTLIBRARIES)
 installdirs: installdirs-recursive
 installdirs-am:
 	for dir in "$(DESTDIR)$(ipseclibdir)"; do \
 	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
 	done
-install: install-recursive
+install: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) install-recursive
 install-exec: install-exec-recursive
 install-data: install-data-recursive
 uninstall: uninstall-recursive
@@ -861,6 +868,7 @@ install-strip:
 mostlyclean-generic:
 
 clean-generic:
+	-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
 
 distclean-generic:
 	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
@@ -875,6 +883,7 @@ distclean-generic:
 maintainer-clean-generic:
 	@echo "This command is intended for maintainers to use"
 	@echo "it deletes files that may require special tools to rebuild."
+	-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
 clean: clean-recursive
 
 clean-am: clean-generic clean-ipseclibLTLIBRARIES clean-libtool \
@@ -946,7 +955,8 @@ ps-am:
 
 uninstall-am: uninstall-ipseclibLTLIBRARIES
 
-.MAKE: $(am__recursive_targets) install-am install-strip
+.MAKE: $(am__recursive_targets) all check install install-am \
+	install-strip
 
 .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
 	check-am clean clean-generic clean-ipseclibLTLIBRARIES \
@@ -967,6 +977,10 @@ uninstall-am: uninstall-ipseclibLTLIBRARIES
 .PRECIOUS: Makefile
 
 
+ at STATIC_PLUGIN_CONSTRUCTORS_TRUE@$(srcdir)/plugin_constructors.c: $(top_srcdir)/src/libstrongswan/plugins/plugin_constructors.py
+ at STATIC_PLUGIN_CONSTRUCTORS_TRUE@		$(AM_V_GEN) \
+ at STATIC_PLUGIN_CONSTRUCTORS_TRUE@		$(PYTHON) $(top_srcdir)/src/libstrongswan/plugins/plugin_constructors.py ${t_plugins} > $@
+
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
 .NOEXPORT:
diff --git a/src/libtnccs/plugins/tnc_imc/Makefile.in b/src/libtnccs/plugins/tnc_imc/Makefile.in
index 2d04cc1..84dbf14 100644
--- a/src/libtnccs/plugins/tnc_imc/Makefile.in
+++ b/src/libtnccs/plugins/tnc_imc/Makefile.in
@@ -360,6 +360,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -382,6 +383,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libtnccs/plugins/tnc_imv/Makefile.in b/src/libtnccs/plugins/tnc_imv/Makefile.in
index cfdd73c..5fd128f 100644
--- a/src/libtnccs/plugins/tnc_imv/Makefile.in
+++ b/src/libtnccs/plugins/tnc_imv/Makefile.in
@@ -361,6 +361,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -383,6 +384,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libtnccs/plugins/tnc_imv/tnc_imv_recommendations.c b/src/libtnccs/plugins/tnc_imv/tnc_imv_recommendations.c
index a9dbb2b..9c6307d 100644
--- a/src/libtnccs/plugins/tnc_imv/tnc_imv_recommendations.c
+++ b/src/libtnccs/plugins/tnc_imv/tnc_imv_recommendations.c
@@ -320,31 +320,33 @@ METHOD(recommendations_t, set_reason_language, TNC_Result,
 	return found ? TNC_RESULT_SUCCESS : TNC_RESULT_INVALID_PARAMETER;
 }
 
-/**
- * Enumerate reason and reason_language, not recommendation entries
- */
-static bool reason_filter(void *null, recommendation_entry_t **entry,
-						 TNC_IMVID *id, void *i2, chunk_t *reason, void *i3,
-						 chunk_t *reason_language)
+CALLBACK(reason_filter, bool,
+	void *null, enumerator_t *orig, va_list args)
 {
-	if ((*entry)->reason.len)
-	{
-		*id = (*entry)->id;
-		*reason = (*entry)->reason;
-		*reason_language = (*entry)->reason_language;
-		return TRUE;
-	}
-	else
+	recommendation_entry_t *entry;
+	TNC_IMVID *id;
+	chunk_t *reason, *reason_language;
+
+	VA_ARGS_VGET(args, id, reason, reason_language);
+
+	while (orig->enumerate(orig, &entry))
 	{
-		return FALSE;
+		if (entry->reason.len)
+		{
+			*id = entry->id;
+			*reason = entry->reason;
+			*reason_language = entry->reason_language;
+			return TRUE;
+		}
 	}
+	return FALSE;
 }
 
 METHOD(recommendations_t, create_reason_enumerator, enumerator_t*,
 	private_tnc_imv_recommendations_t *this)
 {
 	return enumerator_create_filter(this->recs->create_enumerator(this->recs),
-					(void*)reason_filter, NULL, NULL);
+									reason_filter, NULL, NULL);
 }
 
 METHOD(recommendations_t, destroy, void,
diff --git a/src/libtnccs/plugins/tnc_tnccs/Makefile.in b/src/libtnccs/plugins/tnc_tnccs/Makefile.in
index 094d3be..acddd84 100644
--- a/src/libtnccs/plugins/tnc_tnccs/Makefile.in
+++ b/src/libtnccs/plugins/tnc_tnccs/Makefile.in
@@ -360,6 +360,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -382,6 +383,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libtnccs/plugins/tnccs_11/Makefile.in b/src/libtnccs/plugins/tnccs_11/Makefile.in
index d816d6b..b6b8074 100644
--- a/src/libtnccs/plugins/tnccs_11/Makefile.in
+++ b/src/libtnccs/plugins/tnccs_11/Makefile.in
@@ -370,6 +370,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -392,6 +393,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libtnccs/plugins/tnccs_11/tnccs_11_plugin.c b/src/libtnccs/plugins/tnccs_11/tnccs_11_plugin.c
index f534af0..191adbb 100644
--- a/src/libtnccs/plugins/tnccs_11/tnccs_11_plugin.c
+++ b/src/libtnccs/plugins/tnccs_11/tnccs_11_plugin.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 Andreas Steffen
+ * Copyright (C) 2010-2017 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -17,6 +17,7 @@
 #include "tnccs_11.h"
 
 #include <tnc/tnccs/tnccs_manager.h>
+#include <libxml/parser.h>
 
 METHOD(plugin_t, get_name, char*,
 	tnccs_11_plugin_t *this)
@@ -39,6 +40,7 @@ METHOD(plugin_t, get_features, int,
 METHOD(plugin_t, destroy, void,
 	tnccs_11_plugin_t *this)
 {
+	xmlCleanupParser();
 	free(this);
 }
 
@@ -56,6 +58,7 @@ plugin_t *tnccs_11_plugin_create()
 			.destroy = _destroy,
 		},
 	);
+	xmlInitParser();
 
 	return &this->plugin;
 }
diff --git a/src/libtnccs/plugins/tnccs_20/Makefile.in b/src/libtnccs/plugins/tnccs_20/Makefile.in
index a64288f..2a1d327 100644
--- a/src/libtnccs/plugins/tnccs_20/Makefile.in
+++ b/src/libtnccs/plugins/tnccs_20/Makefile.in
@@ -373,6 +373,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -395,6 +396,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libtnccs/plugins/tnccs_dynamic/Makefile.in b/src/libtnccs/plugins/tnccs_dynamic/Makefile.in
index 043e64d..65201dd 100644
--- a/src/libtnccs/plugins/tnccs_dynamic/Makefile.in
+++ b/src/libtnccs/plugins/tnccs_dynamic/Makefile.in
@@ -360,6 +360,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -382,6 +383,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libtnccs/tnc/tnc.c b/src/libtnccs/tnc/tnc.c
index 80ba61c..9627be8 100644
--- a/src/libtnccs/tnc/tnc.c
+++ b/src/libtnccs/tnc/tnc.c
@@ -55,6 +55,13 @@ struct private_tnc_t {
 };
 
 /**
+ * Register plugins if built statically
+ */
+#ifdef STATIC_PLUGIN_CONSTRUCTORS
+#include "plugin_constructors.c"
+#endif
+
+/**
  * Single instance of tnc_t.
  */
 tnc_t *tnc;
diff --git a/src/libtncif/Makefile.in b/src/libtncif/Makefile.in
index 77c950a..2432a70 100644
--- a/src/libtncif/Makefile.in
+++ b/src/libtncif/Makefile.in
@@ -322,6 +322,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -344,6 +345,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libtpmtss/Makefile.am b/src/libtpmtss/Makefile.am
index c7ac39a..5f3a97a 100644
--- a/src/libtpmtss/Makefile.am
+++ b/src/libtpmtss/Makefile.am
@@ -33,6 +33,15 @@ else
 SUBDIRS = .
 endif
 
+if STATIC_PLUGIN_CONSTRUCTORS
+BUILT_SOURCES = $(srcdir)/plugin_constructors.c
+CLEANFILES = $(srcdir)/plugin_constructors.c
+
+$(srcdir)/plugin_constructors.c: $(top_srcdir)/src/libstrongswan/plugins/plugin_constructors.py
+		$(AM_V_GEN) \
+		$(PYTHON) $(top_srcdir)/src/libstrongswan/plugins/plugin_constructors.py ${p_plugins} > $@
+endif
+
 if USE_TPM
   SUBDIRS += plugins/tpm
 if MONOLITHIC
diff --git a/src/libtpmtss/Makefile.in b/src/libtpmtss/Makefile.in
index 1a19fb5..405d717 100644
--- a/src/libtpmtss/Makefile.in
+++ b/src/libtpmtss/Makefile.in
@@ -400,6 +400,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -422,6 +423,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
@@ -508,7 +510,10 @@ libtpmtss_la_SOURCES = \
 
 @MONOLITHIC_FALSE at SUBDIRS = . $(am__append_3)
 @MONOLITHIC_TRUE at SUBDIRS = $(am__append_3)
-all: all-recursive
+ at STATIC_PLUGIN_CONSTRUCTORS_TRUE@BUILT_SOURCES = $(srcdir)/plugin_constructors.c
+ at STATIC_PLUGIN_CONSTRUCTORS_TRUE@CLEANFILES = $(srcdir)/plugin_constructors.c
+all: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) all-recursive
 
 .SUFFIXES:
 .SUFFIXES: .c .lo .o .obj
@@ -777,14 +782,16 @@ distdir: $(DISTFILES)
 	  fi; \
 	done
 check-am: all-am
-check: check-recursive
+check: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) check-recursive
 all-am: Makefile $(LTLIBRARIES)
 installdirs: installdirs-recursive
 installdirs-am:
 	for dir in "$(DESTDIR)$(ipseclibdir)"; do \
 	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
 	done
-install: install-recursive
+install: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) install-recursive
 install-exec: install-exec-recursive
 install-data: install-data-recursive
 uninstall: uninstall-recursive
@@ -806,6 +813,7 @@ install-strip:
 mostlyclean-generic:
 
 clean-generic:
+	-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
 
 distclean-generic:
 	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
@@ -814,6 +822,7 @@ distclean-generic:
 maintainer-clean-generic:
 	@echo "This command is intended for maintainers to use"
 	@echo "it deletes files that may require special tools to rebuild."
+	-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
 clean: clean-recursive
 
 clean-am: clean-generic clean-ipseclibLTLIBRARIES clean-libtool \
@@ -885,7 +894,8 @@ ps-am:
 
 uninstall-am: uninstall-ipseclibLTLIBRARIES
 
-.MAKE: $(am__recursive_targets) install-am install-strip
+.MAKE: $(am__recursive_targets) all check install install-am \
+	install-strip
 
 .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
 	check-am clean clean-generic clean-ipseclibLTLIBRARIES \
@@ -906,6 +916,10 @@ uninstall-am: uninstall-ipseclibLTLIBRARIES
 .PRECIOUS: Makefile
 
 
+ at STATIC_PLUGIN_CONSTRUCTORS_TRUE@$(srcdir)/plugin_constructors.c: $(top_srcdir)/src/libstrongswan/plugins/plugin_constructors.py
+ at STATIC_PLUGIN_CONSTRUCTORS_TRUE@		$(AM_V_GEN) \
+ at STATIC_PLUGIN_CONSTRUCTORS_TRUE@		$(PYTHON) $(top_srcdir)/src/libstrongswan/plugins/plugin_constructors.py ${p_plugins} > $@
+
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
 .NOEXPORT:
diff --git a/src/libtpmtss/plugins/tpm/Makefile.in b/src/libtpmtss/plugins/tpm/Makefile.in
index 9e2641b..eb9489e 100644
--- a/src/libtpmtss/plugins/tpm/Makefile.in
+++ b/src/libtpmtss/plugins/tpm/Makefile.in
@@ -357,6 +357,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -379,6 +380,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/libtpmtss/tpm_tss.c b/src/libtpmtss/tpm_tss.c
index b7b970c..42a3418 100644
--- a/src/libtpmtss/tpm_tss.c
+++ b/src/libtpmtss/tpm_tss.c
@@ -18,6 +18,13 @@
 #include "tpm_tss_trousers.h"
 
 /**
+ * Register plugins if built statically
+ */
+#ifdef STATIC_PLUGIN_CONSTRUCTORS
+#include "plugin_constructors.c"
+#endif
+
+/**
  * Described in header.
  */
 void libtpmtss_init(void)
diff --git a/src/manager/Makefile.in b/src/manager/Makefile.in
index 8b0a402..58c247e 100644
--- a/src/manager/Makefile.in
+++ b/src/manager/Makefile.in
@@ -374,6 +374,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -396,6 +397,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/manager/xml.c b/src/manager/xml.c
index bf5bbbf..0aee5f6 100644
--- a/src/manager/xml.c
+++ b/src/manager/xml.c
@@ -67,8 +67,13 @@ typedef struct {
 } child_enum_t;
 
 METHOD(enumerator_t, child_enumerate, bool,
-	child_enum_t *e, private_xml_t **child, char **name, char **value)
+	child_enum_t *e, va_list args)
 {
+	private_xml_t **child;
+	char **name, **value;
+
+	VA_ARGS_VGET(args, child, name, value);
+
 	while (e->node && e->node->type != XML_ELEMENT_NODE)
 	{
 		e->node = e->node->next;
@@ -120,7 +125,8 @@ METHOD(xml_t, children, enumerator_t*,
 	child_enum_t *ce;
 	INIT(ce,
 		.e = {
-			.enumerate = (void*)_child_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _child_enumerate,
 			.destroy = _child_destroy,
 		},
 		.child = {
diff --git a/src/medsrv/Makefile.in b/src/medsrv/Makefile.in
index 249728b..7561ad9 100644
--- a/src/medsrv/Makefile.in
+++ b/src/medsrv/Makefile.in
@@ -363,6 +363,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -385,6 +386,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/pki/Makefile.in b/src/pki/Makefile.in
index 72d554a..ed95d81 100644
--- a/src/pki/Makefile.in
+++ b/src/pki/Makefile.in
@@ -376,6 +376,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -398,6 +399,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/pki/commands/issue.c b/src/pki/commands/issue.c
index b0399c7..e41c56d 100644
--- a/src/pki/commands/issue.c
+++ b/src/pki/commands/issue.c
@@ -406,6 +406,7 @@ static int issue()
 		goto end;
 	}
 	public->destroy(public);
+	public = NULL;
 
 	if (hex)
 	{
diff --git a/src/pki/commands/signcrl.c b/src/pki/commands/signcrl.c
index 6bccf1b..25a3aac 100644
--- a/src/pki/commands/signcrl.c
+++ b/src/pki/commands/signcrl.c
@@ -61,16 +61,24 @@ static void revoked_destroy(revoked_t *revoked)
 	free(revoked);
 }
 
-/**
- * Filter for revoked enumerator
- */
-static bool filter(void *data, revoked_t **revoked, chunk_t *serial, void *p2,
-				   time_t *date, void *p3, crl_reason_t *reason)
+CALLBACK(filter, bool,
+	void *data, enumerator_t *orig, va_list args)
 {
-	*serial = (*revoked)->serial;
-	*date = (*revoked)->date;
-	*reason = (*revoked)->reason;
-	return TRUE;
+	revoked_t *revoked;
+	crl_reason_t *reason;
+	chunk_t *serial;
+	time_t *date;
+
+	VA_ARGS_VGET(args, serial, date, reason);
+
+	if (orig->enumerate(orig, &revoked))
+	{
+		*serial = revoked->serial;
+		*date = revoked->date;
+		*reason = revoked->reason;
+		return TRUE;
+	}
+	return FALSE;
 }
 
 /**
@@ -392,7 +400,7 @@ static int sign_crl()
 	chunk_increment(crl_serial);
 
 	enumerator = enumerator_create_filter(list->create_enumerator(list),
-										  (void*)filter, NULL, NULL);
+										  filter, NULL, NULL);
 	crl = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509_CRL,
 			BUILD_SIGNING_KEY, private, BUILD_SIGNING_CERT, ca,
 			BUILD_SERIAL, crl_serial,
diff --git a/src/pki/man/Makefile.in b/src/pki/man/Makefile.in
index e40aca3..a469f8b 100644
--- a/src/pki/man/Makefile.in
+++ b/src/pki/man/Makefile.in
@@ -313,6 +313,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -335,6 +336,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/pool/Makefile.in b/src/pool/Makefile.in
index d67830e..415de55 100644
--- a/src/pool/Makefile.in
+++ b/src/pool/Makefile.in
@@ -358,6 +358,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -380,6 +381,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/pt-tls-client/Makefile.in b/src/pt-tls-client/Makefile.in
index 2c87f5f..7912c60 100644
--- a/src/pt-tls-client/Makefile.in
+++ b/src/pt-tls-client/Makefile.in
@@ -327,6 +327,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -349,6 +350,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/scepclient/Makefile.in b/src/scepclient/Makefile.in
index 47b0c8c..9b2023f 100644
--- a/src/scepclient/Makefile.in
+++ b/src/scepclient/Makefile.in
@@ -355,6 +355,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -377,6 +378,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/starter/Makefile.in b/src/starter/Makefile.in
index 3c89b0c..97a0713 100644
--- a/src/starter/Makefile.in
+++ b/src/starter/Makefile.in
@@ -400,6 +400,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -422,6 +423,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/starter/args.c b/src/starter/args.c
index 0874cc7..477a520 100644
--- a/src/starter/args.c
+++ b/src/starter/args.c
@@ -110,6 +110,7 @@ static const char *LST_authby[] = {
 
 static const char *LST_fragmentation[] = {
 	"no",
+	"accept",
 	"yes",
 	"force",
 	 NULL
@@ -164,6 +165,7 @@ static const token_info_t token_info[] =
 	{ ARG_TIME, offsetof(starter_conn_t, dpd_timeout), NULL                        },
 	{ ARG_ENUM, offsetof(starter_conn_t, dpd_action), LST_dpd_action               },
 	{ ARG_ENUM, offsetof(starter_conn_t, close_action), LST_dpd_action             },
+	{ ARG_ENUM, offsetof(starter_conn_t, sha256_96), LST_bool                      },
 	{ ARG_TIME, offsetof(starter_conn_t, inactivity), NULL                         },
 	{ ARG_MISC, 0, NULL  /* KW_MODECONFIG */                                       },
 	{ ARG_MISC, 0, NULL  /* KW_XAUTH */                                            },
diff --git a/src/starter/confread.h b/src/starter/confread.h
index 45f34ce..8ee730d 100644
--- a/src/starter/confread.h
+++ b/src/starter/confread.h
@@ -65,6 +65,7 @@ typedef enum {
 typedef enum {
 		/* same as in ike_cfg.h */
 		FRAGMENTATION_NO,
+		FRAGMENTATION_ACCEPT,
 		FRAGMENTATION_YES,
 		FRAGMENTATION_FORCE,
 } fragmentation_t;
@@ -161,6 +162,8 @@ struct starter_conn {
 
 		dpd_action_t    close_action;
 
+		bool            sha256_96;
+
 		time_t          inactivity;
 
 		bool            me_mediation;
diff --git a/src/starter/keywords.c b/src/starter/keywords.c
index 762c5d9..505b660 100644
--- a/src/starter/keywords.c
+++ b/src/starter/keywords.c
@@ -54,7 +54,7 @@ struct kw_entry {
     kw_token_t token;
 };
 
-#define TOTAL_KEYWORDS 139
+#define TOTAL_KEYWORDS 140
 #define MIN_WORD_LENGTH 2
 #define MAX_WORD_LENGTH 17
 #define MIN_HASH_VALUE 9
@@ -80,7 +80,7 @@ hash (str, len)
       258, 258, 258, 258, 258, 258, 258, 258, 258, 258,
       258, 258, 258, 258, 258, 258, 258, 258, 258, 258,
       258, 258, 258, 258, 258, 258, 258, 258, 258,  14,
-      129, 258, 258, 258, 258, 258, 258, 258, 258, 258,
+      129, 258, 258, 258,   4, 258, 258, 258, 258, 258,
       258, 258, 258, 258, 258, 258, 258, 258, 258, 258,
       258, 258, 258, 258, 258, 258, 258, 258, 258, 258,
       258, 258, 258, 258, 258, 258, 258, 258, 258, 258,
@@ -202,6 +202,7 @@ static const struct kw_entry wordlist[] =
     {"klipsdebug",        KW_SETUP_DEPRECATED},
     {"ldapbase",          KW_CA_DEPRECATED},
     {"overridemtu",       KW_SETUP_DEPRECATED},
+    {"sha256_96",         KW_SHA256_96},
     {"ocspuri1",          KW_OCSPURI},
     {"dpdtimeout",        KW_DPDTIMEOUT},
     {"aaa_identity",      KW_AAA_IDENTITY},
@@ -278,20 +279,20 @@ static const short lookup[] =
      48,  49,  50,  51,  52,  53,  54,  55,  56,  57,
      58,  59,  -1,  -1,  60,  61,  62,  -1,  63,  -1,
      64,  -1,  65,  66,  67,  68,  69,  70,  71,  72,
-     -1,  73,  74,  75,  76,  77,  78,  -1,  79,  -1,
-     -1,  80,  81,  -1,  82,  -1,  -1,  83,  84,  85,
-     86,  87,  88,  -1,  89,  -1,  90,  91,  -1,  92,
-     93,  -1,  94,  95,  -1,  96,  -1,  -1,  97,  98,
-     99, 100,  -1, 101,  -1, 102, 103, 104,  -1, 105,
-    106, 107, 108, 109, 110, 111, 112, 113, 114, 115,
-     -1, 116,  -1, 117,  -1, 118,  -1,  -1, 119, 120,
-     -1,  -1,  -1,  -1,  -1, 121,  -1, 122,  -1, 123,
-    124, 125,  -1,  -1,  -1,  -1,  -1, 126,  -1,  -1,
-     -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1, 127,  -1,
-     -1, 128, 129,  -1, 130,  -1, 131,  -1,  -1,  -1,
-     -1,  -1,  -1, 132,  -1, 133,  -1, 134, 135,  -1,
-     -1,  -1,  -1, 136,  -1,  -1,  -1,  -1,  -1,  -1,
-    137,  -1,  -1,  -1,  -1,  -1,  -1, 138
+     -1,  73,  74,  75,  76,  77,  78,  79,  80,  -1,
+     -1,  81,  82,  -1,  83,  -1,  -1,  84,  85,  86,
+     87,  88,  89,  -1,  90,  -1,  91,  92,  -1,  93,
+     94,  -1,  95,  96,  -1,  97,  -1,  -1,  98,  99,
+    100, 101,  -1, 102,  -1, 103, 104, 105,  -1, 106,
+    107, 108, 109, 110, 111, 112, 113, 114, 115, 116,
+     -1, 117,  -1, 118,  -1, 119,  -1,  -1, 120, 121,
+     -1,  -1,  -1,  -1,  -1, 122,  -1, 123,  -1, 124,
+    125, 126,  -1,  -1,  -1,  -1,  -1, 127,  -1,  -1,
+     -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1, 128,  -1,
+     -1, 129, 130,  -1, 131,  -1, 132,  -1,  -1,  -1,
+     -1,  -1,  -1, 133,  -1, 134,  -1, 135, 136,  -1,
+     -1,  -1,  -1, 137,  -1,  -1,  -1,  -1,  -1,  -1,
+    138,  -1,  -1,  -1,  -1,  -1,  -1, 139
   };
 
 #ifdef __GNUC__
diff --git a/src/starter/keywords.h b/src/starter/keywords.h
index 94af493..0cb46a7 100644
--- a/src/starter/keywords.h
+++ b/src/starter/keywords.h
@@ -64,6 +64,7 @@ enum kw_token_t {
 	KW_DPDTIMEOUT,
 	KW_DPDACTION,
 	KW_CLOSEACTION,
+	KW_SHA256_96,
 	KW_INACTIVITY,
 	KW_MODECONFIG,
 	KW_XAUTH,
diff --git a/src/starter/keywords.txt b/src/starter/keywords.txt
index ee0bd31..3f92dc8 100644
--- a/src/starter/keywords.txt
+++ b/src/starter/keywords.txt
@@ -61,6 +61,7 @@ dpddelay,          KW_DPDDELAY
 dpdtimeout,        KW_DPDTIMEOUT
 dpdaction,         KW_DPDACTION
 closeaction,       KW_CLOSEACTION
+sha256_96,         KW_SHA256_96
 inactivity,        KW_INACTIVITY
 modeconfig,        KW_MODECONFIG
 xauth,             KW_XAUTH
diff --git a/src/starter/parser/conf_parser.c b/src/starter/parser/conf_parser.c
index 6d1c54d..66e0ae8 100644
--- a/src/starter/parser/conf_parser.c
+++ b/src/starter/parser/conf_parser.c
@@ -158,10 +158,13 @@ typedef struct {
 } dictionary_enumerator_t;
 
 METHOD(enumerator_t, dictionary_enumerate, bool,
-	dictionary_enumerator_t *this, char **key, char **value)
+	dictionary_enumerator_t *this, va_list args)
 {
 	setting_t *setting;
 	section_t *parent;
+	char **key, **value;
+
+	VA_ARGS_VGET(args, key, value);
 
 	while (TRUE)
 	{
@@ -221,7 +224,8 @@ METHOD(dictionary_t, dictionary_create_enumerator, enumerator_t*,
 
 	INIT(enumerator,
 		.public = {
-			.enumerate = (void*)_dictionary_enumerate,
+			.enumerate = enumerator_enumerate_default,
+			.venumerate = _dictionary_enumerate,
 			.destroy = _dictionary_enumerator_destroy,
 		},
 		.seen = hashtable_create(hashtable_hash_str, hashtable_equals_str, 8),
@@ -290,24 +294,43 @@ static dictionary_t *section_dictionary_create(private_conf_parser_t *parser,
 	return &this->public;
 }
 
-static bool conn_filter(void *unused, section_t **section, char **name)
+CALLBACK(conn_filter, bool,
+	void *unused, enumerator_t *orig, va_list args)
 {
-	if (streq((*section)->name, "%default"))
+	section_t *section;
+	char **name;
+
+	VA_ARGS_VGET(args, name);
+
+	while (orig->enumerate(orig, &section))
 	{
-		return FALSE;
+		if (!streq(section->name, "%default"))
+		{
+			*name = section->name;
+			return TRUE;
+		}
 	}
-	*name = (*section)->name;
-	return TRUE;
+	return FALSE;
 }
 
-static bool ca_filter(void *unused, void *key, char **name, section_t **section)
+CALLBACK(ca_filter, bool,
+	void *unused, enumerator_t *orig, va_list args)
 {
-	if (streq((*section)->name, "%default"))
+	void *key;
+	section_t *section;
+	char **name;
+
+	VA_ARGS_VGET(args, name);
+
+	while (orig->enumerate(orig, &key, &section))
 	{
-		return FALSE;
+		if (!streq(section->name, "%default"))
+		{
+			*name = section->name;
+			return TRUE;
+		}
 	}
-	*name = (*section)->name;
-	return TRUE;
+	return FALSE;
 }
 
 METHOD(conf_parser_t, get_sections, enumerator_t*,
@@ -317,12 +340,12 @@ METHOD(conf_parser_t, get_sections, enumerator_t*,
 	{
 		case CONF_PARSER_CONN:
 			return enumerator_create_filter(
-						array_create_enumerator(this->conns_order),
-						(void*)conn_filter, NULL, NULL);
+									array_create_enumerator(this->conns_order),
+									conn_filter, NULL, NULL);
 		case CONF_PARSER_CA:
 			return enumerator_create_filter(
-						this->cas->create_enumerator(this->cas),
-						(void*)ca_filter, NULL, NULL);
+									this->cas->create_enumerator(this->cas),
+									ca_filter, NULL, NULL);
 		case CONF_PARSER_CONFIG_SETUP:
 		default:
 			return enumerator_create_empty();
diff --git a/src/starter/starterstroke.c b/src/starter/starterstroke.c
index b92c00c..90af937 100644
--- a/src/starter/starterstroke.c
+++ b/src/starter/starterstroke.c
@@ -220,6 +220,7 @@ int starter_stroke_add_conn(starter_config_t *cfg, starter_conn_t *conn)
 	msg->add_conn.dpd.timeout = conn->dpd_timeout;
 	msg->add_conn.dpd.action = conn->dpd_action;
 	msg->add_conn.close_action = conn->close_action;
+	msg->add_conn.sha256_96 = conn->sha256_96;
 	msg->add_conn.inactivity = conn->inactivity;
 	msg->add_conn.ikeme.mediation = conn->me_mediation;
 	push_string(&msg, add_conn.ikeme.mediated_by, conn->me_mediated_by);
diff --git a/src/starter/tests/Makefile.in b/src/starter/tests/Makefile.in
index 8e9028a..6ce8bda 100644
--- a/src/starter/tests/Makefile.in
+++ b/src/starter/tests/Makefile.in
@@ -352,6 +352,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -374,6 +375,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/stroke/Makefile.in b/src/stroke/Makefile.in
index fff0a5e..6af83d9 100644
--- a/src/stroke/Makefile.in
+++ b/src/stroke/Makefile.in
@@ -326,6 +326,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -348,6 +349,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/stroke/stroke_msg.h b/src/stroke/stroke_msg.h
index a3b911d..60ea002 100644
--- a/src/stroke/stroke_msg.h
+++ b/src/stroke/stroke_msg.h
@@ -302,6 +302,7 @@ struct stroke_msg_t {
 			} mark_in, mark_out;
 			stroke_end_t me, other;
 			uint32_t replay_window;
+			bool sha256_96;
 		} add_conn;
 
 		/* data for STR_ADD_CA */
diff --git a/src/swanctl/Makefile.in b/src/swanctl/Makefile.in
index 7e2a1da..b5313a3 100644
--- a/src/swanctl/Makefile.in
+++ b/src/swanctl/Makefile.in
@@ -375,6 +375,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -397,6 +398,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/src/swanctl/commands/load_creds.c b/src/swanctl/commands/load_creds.c
index 848d851..d854106 100644
--- a/src/swanctl/commands/load_creds.c
+++ b/src/swanctl/commands/load_creds.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 Tobias Brunner
+ * Copyright (C) 2016-2017 Tobias Brunner
  * Copyright (C) 2015 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
@@ -34,8 +34,6 @@
 
 #include <vici_cert_info.h>
 
-#define HASH_SIZE_SHA1_HEX (2 * HASH_SIZE_SHA1)
-
 /**
  * Context used to track loaded secrets
  */
@@ -144,6 +142,7 @@ static bool load_key(load_ctx_t *ctx, char *dir, char *type, chunk_t data)
 	vici_req_t *req;
 	vici_res_t *res;
 	bool ret = TRUE;
+	char *id;
 
 	req = vici_begin("load-key");
 
@@ -178,6 +177,8 @@ static bool load_key(load_ctx_t *ctx, char *dir, char *type, chunk_t data)
 	else
 	{
 		printf("loaded %s key from '%s'\n", type, dir);
+		id = vici_find_str(res, "", "id");
+		free(ctx->keys->remove(ctx->keys, id));
 	}
 	vici_free_res(res);
 	return ret;
@@ -190,8 +191,7 @@ static bool load_key_anytype(load_ctx_t *ctx, char *path,
 							 private_key_t *private)
 {
 	bool loaded = FALSE;
-	chunk_t encoding, keyid;
-	char hex[HASH_SIZE_SHA1_HEX + 1];
+	chunk_t encoding;
 
 	if (!private->get_encoding(private, PRIVKEY_ASN1_DER, &encoding))
 	{
@@ -213,13 +213,6 @@ static bool load_key_anytype(load_ctx_t *ctx, char *path,
 			fprintf(stderr, "unsupported key type in '%s'\n", path);
 			break;
 	}
-
-	if (loaded &&
-		private->get_fingerprint(private, KEYID_PUBKEY_SHA1, &keyid) &&
-		snprintf(hex, sizeof(hex), "%+B", &keyid) == HASH_SIZE_SHA1_HEX)
-	{
-		free(ctx->keys->remove(ctx->keys, hex));
-	}
 	chunk_clear(&encoding);
 	return loaded;
 }
@@ -408,7 +401,7 @@ static void* decrypt_with_config(load_ctx_t *ctx, char *name, char *type,
 /**
  * Try to decrypt and load a private key
  */
-static bool load_encrypted_key(load_ctx_t *ctx,  char *rel, char *path,
+static bool load_encrypted_key(load_ctx_t *ctx, char *rel, char *path,
 							   char *type, chunk_t data)
 {
 	private_key_t *private;
diff --git a/src/swanctl/swanctl.conf b/src/swanctl/swanctl.conf
index 789b128..b2045a3 100644
--- a/src/swanctl/swanctl.conf
+++ b/src/swanctl/swanctl.conf
@@ -47,7 +47,7 @@
         # Timeout for DPD checks (IKEV1 only).
         # dpd_timeout = 0s
 
-        # Use IKE UDP datagram fragmentation.  (yes, no or force).
+        # Use IKE UDP datagram fragmentation.  (yes, accept, no or force).
         # fragmentation = yes
 
         # Send certificate requests payloads (yes or no).
@@ -227,6 +227,9 @@
                 # ESP proposals to offer for the CHILD_SA.
                 # esp_proposals = default
 
+                # Use incorrect 96-bit truncation for HMAC-SHA-256.
+                # sha256_96 = no
+
                 # Local traffic selectors to include in CHILD_SA.
                 # local_ts = dynamic
 
@@ -308,6 +311,10 @@
                 # IPsec replay window to configure for this CHILD_SA.
                 # replay_window = 32
 
+                # Enable hardware offload for this CHILD_SA, if supported by the
+                # IPsec implementation.
+                # hw_offload = no
+
                 # Action to perform after loading the configuration (none, trap,
                 # start).
                 # start_action = none
diff --git a/src/swanctl/swanctl.conf.5.main b/src/swanctl/swanctl.conf.5.main
index 6e1e9ad..9f4044d 100644
--- a/src/swanctl/swanctl.conf.5.main
+++ b/src/swanctl/swanctl.conf.5.main
@@ -168,18 +168,29 @@ Use IKE fragmentation (proprietary IKEv1 extension or RFC 7383 IKEv2
 fragmentation).  Acceptable  values  are
 .RI "" "yes" ""
 (the        default),
+.RI "" "accept" ","
 .RI "" "force" ""
 and
 .RI "" "no" "."
-Fragmented IKE messages sent by a peer are always accepted irrespective of
-the  value  of  this option. If set to
+If set to
 .RI "" "yes" ","
-and the peer supports it,
-oversized IKE messages will be sent in fragments.  If set  to
+and the peer     supports it, oversized IKE
+messages will be sent in fragments. If set to
+.RI "" "accept" ","
+support for
+fragmentation is announced to the peer but the daemon does not send its own
+messages in fragments.  If set to
 .RI "" "force" ""
-(only
-supported  for IKEv1) the initial IKE message will already be fragmented if
-required.
+(only supported for IKEv1) the initial
+IKE message will already be fragmented if required. Finally, setting the option
+to
+.RI "" "no" ""
+will disable announcing support for this feature.
+
+Note that fragmented IKE messages sent by a peer are always accepted
+irrespective of the value of this option (even when set to
+.RI "" "no" ")."
+
 
 .TP
 .BR connections.<conn>.send_certreq " [yes]"
@@ -786,6 +797,14 @@ interoperability. If no algorithms are specified for AH nor ESP, the
 set of algorithms for ESP is included.
 
 .TP
+.BR connections.<conn>.children.<child>.sha256_96 " [no]"
+HMAC\-SHA\-256 is used with 128\-bit truncation with IPsec. For compatibility with
+implementations that incorrectly use 96\-bit truncation this option may be
+enabled to configure the shorter truncation length in the kernel.  This is not
+negotiated, so this only works with peers that use the incorrect truncation
+length (or have this option enabled).
+
+.TP
 .BR connections.<conn>.children.<child>.local_ts " [dynamic]"
 Comma separated list of local traffic selectors to include in CHILD_SA. Each
 selector is a CIDR subnet definition, followed by an optional proto/port
@@ -1065,6 +1084,11 @@ default of 32 are supported using the Netlink backend only, a value of 0
 disables IPsec replay protection.
 
 .TP
+.BR connections.<conn>.children.<child>.hw_offload " [no]"
+Enable hardware offload for this CHILD_SA, if supported by the IPsec
+implementation.
+
+.TP
 .BR connections.<conn>.children.<child>.start_action " [none]"
 Action to perform after loading the configuration. The default of
 .RI "" "none" ""
diff --git a/src/swanctl/swanctl.opt b/src/swanctl/swanctl.opt
index bdd9217..7e204db 100644
--- a/src/swanctl/swanctl.opt
+++ b/src/swanctl/swanctl.opt
@@ -154,15 +154,19 @@ connections.<conn>.dpd_timeout = 0s
 	specified; this option has no effect on connections using IKE2.
 
 connections.<conn>.fragmentation = yes
-	Use IKE UDP datagram fragmentation.  (_yes_, _no_ or _force_).
+	Use IKE UDP datagram fragmentation.  (_yes_, _accept_, _no_ or _force_).
 
 	Use IKE fragmentation (proprietary IKEv1 extension or RFC 7383 IKEv2
-	fragmentation).  Acceptable  values  are _yes_ (the	default), _force_ and
-	_no_. Fragmented IKE messages sent by a peer are always accepted
-	irrespective of  the  value  of  this option. If set to _yes_, and the peer
-	supports it, oversized IKE messages will be sent in fragments.  If set  to
-	_force_  (only  supported  for IKEv1) the initial IKE message will already
-	be fragmented if required.
+	fragmentation).  Acceptable  values  are _yes_ (the	default), _accept_,
+	_force_ and _no_. If set to _yes_, and the peer	supports it, oversized IKE
+	messages will be sent in fragments. If set to _accept_, support for
+	fragmentation is announced to the peer but the daemon does not send its own
+	messages in fragments.  If set to _force_ (only supported for IKEv1) the
+	initial IKE message will already be fragmented if required. Finally, setting
+	the option to _no_ will disable announcing support for this feature.
+
+	Note that fragmented IKE messages sent by a peer are always accepted
+	irrespective of the value of this option (even when set to _no_).
 
 connections.<conn>.send_certreq = yes
 	Send certificate requests payloads (_yes_ or _no_).
@@ -647,6 +651,15 @@ connections.<conn>.children.<child>.esp_proposals = default
 	for interoperability. If no algorithms are specified for AH nor ESP,
 	the _default_ set of algorithms for ESP is included.
 
+connections.<conn>.children.<child>.sha256_96 = no
+	Use incorrect 96-bit truncation for HMAC-SHA-256.
+
+	HMAC-SHA-256 is used with 128-bit truncation with IPsec. For compatibility
+	with implementations that incorrectly use 96-bit truncation this option may
+	be enabled to configure the shorter truncation length in the kernel.  This
+	is not negotiated, so this only works with peers that use the incorrect
+	truncation length (or have this option enabled).
+
 connections.<conn>.children.<child>.local_ts = dynamic
 	Local traffic selectors to include in CHILD_SA.
 
@@ -884,6 +897,10 @@ connections.<conn>.children.<child>.replay_window = 32
 	default of 32 are supported using the Netlink backend only, a value of 0
 	disables IPsec replay protection.
 
+connections.<conn>.children.<child>.hw_offload = no
+	Enable hardware offload for this CHILD_SA, if supported by the IPsec
+	implementation.
+
 connections.<conn>.children.<child>.start_action = none
 	Action to perform after loading the configuration (_none_, _trap_, _start_).
 
diff --git a/testing/Makefile.in b/testing/Makefile.in
index 495fbeb..af153d3 100644
--- a/testing/Makefile.in
+++ b/testing/Makefile.in
@@ -272,6 +272,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 fips_mode = @fips_mode@
+fuzz_plugins = @fuzz_plugins@
 gtk_CFLAGS = @gtk_CFLAGS@
 gtk_LIBS = @gtk_LIBS@
 host = @host@
@@ -294,6 +295,7 @@ json_CFLAGS = @json_CFLAGS@
 json_LIBS = @json_LIBS@
 libdir = @libdir@
 libexecdir = @libexecdir@
+libfuzzer = @libfuzzer@
 libiptc_CFLAGS = @libiptc_CFLAGS@
 libiptc_LIBS = @libiptc_LIBS@
 linux_headers = @linux_headers@
diff --git a/testing/config/kernel/config-4.11 b/testing/config/kernel/config-4.11
new file mode 100644
index 0000000..49cebfb
--- /dev/null
+++ b/testing/config/kernel/config-4.11
@@ -0,0 +1,2575 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Linux/x86 4.11.0 Kernel Configuration
+#
+CONFIG_64BIT=y
+CONFIG_X86_64=y
+CONFIG_X86=y
+CONFIG_INSTRUCTION_DECODER=y
+CONFIG_OUTPUT_FORMAT="elf64-x86-64"
+CONFIG_ARCH_DEFCONFIG="arch/x86/configs/x86_64_defconfig"
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_MMU=y
+CONFIG_ARCH_MMAP_RND_BITS_MIN=28
+CONFIG_ARCH_MMAP_RND_BITS_MAX=32
+CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=8
+CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=16
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NEED_SG_DMA_LENGTH=y
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ARCH_HAS_CPU_RELAX=y
+CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y
+CONFIG_HAVE_SETUP_PER_CPU_AREA=y
+CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y
+CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y
+CONFIG_ARCH_WANT_GENERAL_HUGETLB=y
+CONFIG_ZONE_DMA32=y
+CONFIG_AUDIT_ARCH=y
+CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING=y
+CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
+CONFIG_ARCH_SUPPORTS_UPROBES=y
+CONFIG_FIX_EARLYCON_MEM=y
+CONFIG_PGTABLE_LEVELS=4
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_IRQ_WORK=y
+CONFIG_BUILDTIME_EXTABLE_SORT=y
+CONFIG_THREAD_INFO_IN_TASK=y
+
+#
+# General setup
+#
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_CROSS_COMPILE=""
+# CONFIG_COMPILE_TEST is not set
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_BZIP2=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_XZ=y
+CONFIG_HAVE_KERNEL_LZO=y
+CONFIG_HAVE_KERNEL_LZ4=y
+CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_BZIP2 is not set
+# CONFIG_KERNEL_LZMA is not set
+# CONFIG_KERNEL_XZ is not set
+# CONFIG_KERNEL_LZO is not set
+# CONFIG_KERNEL_LZ4 is not set
+CONFIG_DEFAULT_HOSTNAME="(none)"
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
+CONFIG_CROSS_MEMORY_ATTACH=y
+CONFIG_FHANDLE=y
+CONFIG_USELIB=y
+# CONFIG_AUDIT is not set
+CONFIG_HAVE_ARCH_AUDITSYSCALL=y
+
+#
+# IRQ subsystem
+#
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_IRQ_DOMAIN=y
+CONFIG_IRQ_DOMAIN_HIERARCHY=y
+CONFIG_GENERIC_MSI_IRQ=y
+CONFIG_GENERIC_MSI_IRQ_DOMAIN=y
+CONFIG_IRQ_FORCED_THREADING=y
+CONFIG_SPARSE_IRQ=y
+CONFIG_CLOCKSOURCE_WATCHDOG=y
+CONFIG_ARCH_CLOCKSOURCE_DATA=y
+CONFIG_CLOCKSOURCE_VALIDATE_LAST_CYCLE=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
+CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+
+#
+# Timers subsystem
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ_COMMON=y
+# CONFIG_HZ_PERIODIC is not set
+CONFIG_NO_HZ_IDLE=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+
+#
+# CPU/Task time and stats accounting
+#
+CONFIG_TICK_CPU_ACCOUNTING=y
+# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set
+# CONFIG_IRQ_TIME_ACCOUNTING is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TINY_RCU=y
+# CONFIG_RCU_EXPERT is not set
+CONFIG_SRCU=y
+# CONFIG_TASKS_RCU is not set
+# CONFIG_RCU_STALL_COMMON is not set
+# CONFIG_TREE_RCU_TRACE is not set
+CONFIG_BUILD_BIN2C=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=13
+CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y
+CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y
+CONFIG_ARCH_SUPPORTS_INT128=y
+CONFIG_CGROUPS=y
+CONFIG_PAGE_COUNTER=y
+CONFIG_MEMCG=y
+CONFIG_MEMCG_SWAP=y
+CONFIG_MEMCG_SWAP_ENABLED=y
+CONFIG_BLK_CGROUP=y
+# CONFIG_DEBUG_BLK_CGROUP is not set
+CONFIG_CGROUP_WRITEBACK=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_CFS_BANDWIDTH=y
+# CONFIG_RT_GROUP_SCHED is not set
+CONFIG_CGROUP_PIDS=y
+# CONFIG_CGROUP_RDMA is not set
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CPUSETS=y
+CONFIG_PROC_PID_CPUSET=y
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_CGROUP_PERF=y
+# CONFIG_CGROUP_DEBUG is not set
+CONFIG_SOCK_CGROUP_DATA=y
+# CONFIG_CHECKPOINT_RESTORE is not set
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_NET_NS is not set
+# CONFIG_SCHED_AUTOGROUP is not set
+# CONFIG_SYSFS_DEPRECATED is not set
+# CONFIG_RELAY is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_SYSCTL_EXCEPTION_TRACE=y
+CONFIG_HAVE_PCSPKR_PLATFORM=y
+CONFIG_BPF=y
+# CONFIG_EXPERT is not set
+CONFIG_MULTIUSER=y
+CONFIG_SGETMASK_SYSCALL=y
+CONFIG_SYSFS_SYSCALL=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_POSIX_TIMERS=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_ABSOLUTE_PERCPU is not set
+CONFIG_KALLSYMS_BASE_RELATIVE=y
+CONFIG_PRINTK=y
+CONFIG_PRINTK_NMI=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_PCSPKR_PLATFORM=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+# CONFIG_BPF_SYSCALL is not set
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_ADVISE_SYSCALLS=y
+# CONFIG_USERFAULTFD is not set
+CONFIG_PCI_QUIRKS=y
+CONFIG_MEMBARRIER=y
+# CONFIG_EMBEDDED is not set
+CONFIG_HAVE_PERF_EVENTS=y
+# CONFIG_PC104 is not set
+
+#
+# Kernel Performance Events And Counters
+#
+CONFIG_PERF_EVENTS=y
+# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_COMPAT_BRK=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLAB_FREELIST_RANDOM is not set
+# CONFIG_SYSTEM_DATA_VERIFICATION is not set
+# CONFIG_PROFILING is not set
+CONFIG_HAVE_OPROFILE=y
+CONFIG_OPROFILE_NMI_TIMER=y
+# CONFIG_JUMP_LABEL is not set
+# CONFIG_UPROBES is not set
+# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
+CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
+CONFIG_ARCH_USE_BUILTIN_BSWAP=y
+CONFIG_HAVE_IOREMAP_PROT=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_OPTPROBES=y
+CONFIG_HAVE_KPROBES_ON_FTRACE=y
+CONFIG_HAVE_NMI=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_HAVE_DMA_CONTIGUOUS=y
+CONFIG_GENERIC_SMP_IDLE_THREAD=y
+CONFIG_ARCH_HAS_SET_MEMORY=y
+CONFIG_ARCH_WANTS_DYNAMIC_TASK_STRUCT=y
+CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+CONFIG_HAVE_HW_BREAKPOINT=y
+CONFIG_HAVE_MIXED_BREAKPOINTS_REGS=y
+CONFIG_HAVE_USER_RETURN_NOTIFIER=y
+CONFIG_HAVE_PERF_EVENTS_NMI=y
+CONFIG_HAVE_PERF_REGS=y
+CONFIG_HAVE_PERF_USER_STACK_DUMP=y
+CONFIG_HAVE_ARCH_JUMP_LABEL=y
+CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y
+CONFIG_HAVE_CMPXCHG_LOCAL=y
+CONFIG_HAVE_CMPXCHG_DOUBLE=y
+CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
+CONFIG_SECCOMP_FILTER=y
+CONFIG_HAVE_GCC_PLUGINS=y
+# CONFIG_GCC_PLUGINS is not set
+CONFIG_HAVE_CC_STACKPROTECTOR=y
+CONFIG_CC_STACKPROTECTOR=y
+# CONFIG_CC_STACKPROTECTOR_NONE is not set
+CONFIG_CC_STACKPROTECTOR_REGULAR=y
+# CONFIG_CC_STACKPROTECTOR_STRONG is not set
+CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES=y
+CONFIG_HAVE_CONTEXT_TRACKING=y
+CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
+CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
+CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y
+CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD=y
+CONFIG_HAVE_ARCH_HUGE_VMAP=y
+CONFIG_HAVE_ARCH_SOFT_DIRTY=y
+CONFIG_MODULES_USE_ELF_RELA=y
+CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK=y
+CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
+CONFIG_HAVE_ARCH_MMAP_RND_BITS=y
+CONFIG_HAVE_EXIT_THREAD=y
+CONFIG_ARCH_MMAP_RND_BITS=28
+CONFIG_HAVE_COPY_THREAD_TLS=y
+CONFIG_HAVE_STACK_VALIDATION=y
+# CONFIG_HAVE_ARCH_HASH is not set
+# CONFIG_ISA_BUS_API is not set
+# CONFIG_CPU_NO_EFFICIENT_FFS is not set
+CONFIG_HAVE_ARCH_VMAP_STACK=y
+CONFIG_VMAP_STACK=y
+# CONFIG_ARCH_OPTIONAL_KERNEL_RWX is not set
+# CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT is not set
+CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y
+CONFIG_STRICT_KERNEL_RWX=y
+CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y
+
+#
+# GCOV-based kernel profiling
+#
+CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y
+# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+# CONFIG_MODULES is not set
+CONFIG_MODULES_TREE_LOOKUP=y
+CONFIG_BLOCK=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_BSGLIB is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+# CONFIG_BLK_DEV_ZONED is not set
+# CONFIG_BLK_DEV_THROTTLING is not set
+# CONFIG_BLK_CMDLINE_PARSER is not set
+# CONFIG_BLK_WBT is not set
+# CONFIG_BLK_SED_OPAL is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_EFI_PARTITION=y
+CONFIG_BLK_MQ_PCI=y
+CONFIG_BLK_MQ_VIRTIO=y
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_CFQ_GROUP_IOSCHED is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+CONFIG_MQ_IOSCHED_DEADLINE=y
+CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
+CONFIG_INLINE_READ_UNLOCK=y
+CONFIG_INLINE_READ_UNLOCK_IRQ=y
+CONFIG_INLINE_WRITE_UNLOCK=y
+CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
+CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y
+CONFIG_ARCH_USE_QUEUED_SPINLOCKS=y
+CONFIG_ARCH_USE_QUEUED_RWLOCKS=y
+CONFIG_FREEZER=y
+
+#
+# Processor type and features
+#
+CONFIG_ZONE_DMA=y
+# CONFIG_SMP is not set
+CONFIG_X86_FEATURE_NAMES=y
+CONFIG_X86_FAST_FEATURE_TESTS=y
+CONFIG_X86_MPPARSE=y
+# CONFIG_GOLDFISH is not set
+# CONFIG_INTEL_RDT_A is not set
+CONFIG_X86_EXTENDED_PLATFORM=y
+# CONFIG_X86_GOLDFISH is not set
+# CONFIG_X86_INTEL_MID is not set
+# CONFIG_X86_INTEL_LPSS is not set
+# CONFIG_X86_AMD_PLATFORM_DEVICE is not set
+CONFIG_IOSF_MBI=y
+CONFIG_SCHED_OMIT_FRAME_POINTER=y
+# CONFIG_HYPERVISOR_GUEST is not set
+CONFIG_NO_BOOTMEM=y
+# CONFIG_MK8 is not set
+# CONFIG_MPSC is not set
+CONFIG_MCORE2=y
+# CONFIG_MATOM is not set
+# CONFIG_GENERIC_CPU is not set
+CONFIG_X86_INTERNODE_CACHE_SHIFT=6
+CONFIG_X86_L1_CACHE_SHIFT=6
+CONFIG_X86_INTEL_USERCOPY=y
+CONFIG_X86_USE_PPRO_CHECKSUM=y
+CONFIG_X86_P6_NOP=y
+CONFIG_X86_TSC=y
+CONFIG_X86_CMPXCHG64=y
+CONFIG_X86_CMOV=y
+CONFIG_X86_MINIMUM_CPU_FAMILY=64
+CONFIG_X86_DEBUGCTLMSR=y
+CONFIG_CPU_SUP_INTEL=y
+CONFIG_CPU_SUP_AMD=y
+CONFIG_CPU_SUP_CENTAUR=y
+CONFIG_HPET_TIMER=y
+CONFIG_DMI=y
+CONFIG_GART_IOMMU=y
+# CONFIG_CALGARY_IOMMU is not set
+CONFIG_SWIOTLB=y
+CONFIG_IOMMU_HELPER=y
+CONFIG_NR_CPUS=1
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_UP_LATE_INIT=y
+CONFIG_X86_LOCAL_APIC=y
+CONFIG_X86_IO_APIC=y
+# CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS is not set
+# CONFIG_X86_MCE is not set
+
+#
+# Performance monitoring
+#
+CONFIG_PERF_EVENTS_INTEL_UNCORE=y
+CONFIG_PERF_EVENTS_INTEL_RAPL=y
+CONFIG_PERF_EVENTS_INTEL_CSTATE=y
+# CONFIG_PERF_EVENTS_AMD_POWER is not set
+# CONFIG_VM86 is not set
+CONFIG_X86_16BIT=y
+CONFIG_X86_ESPFIX64=y
+CONFIG_X86_VSYSCALL_EMULATION=y
+# CONFIG_I8K is not set
+CONFIG_MICROCODE=y
+CONFIG_MICROCODE_INTEL=y
+# CONFIG_MICROCODE_AMD is not set
+CONFIG_MICROCODE_OLD_INTERFACE=y
+# CONFIG_X86_MSR is not set
+# CONFIG_X86_CPUID is not set
+CONFIG_ARCH_PHYS_ADDR_T_64BIT=y
+CONFIG_ARCH_DMA_ADDR_T_64BIT=y
+CONFIG_X86_DIRECT_GBPAGES=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_DEFAULT=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_ARCH_MEMORY_PROBE=y
+CONFIG_ARCH_PROC_KCORE_TEXT=y
+CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_SPARSEMEM_MANUAL=y
+CONFIG_SPARSEMEM=y
+CONFIG_HAVE_MEMORY_PRESENT=y
+CONFIG_SPARSEMEM_EXTREME=y
+CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y
+CONFIG_SPARSEMEM_ALLOC_MEM_MAP_TOGETHER=y
+CONFIG_SPARSEMEM_VMEMMAP=y
+CONFIG_HAVE_MEMBLOCK=y
+CONFIG_HAVE_MEMBLOCK_NODE_MAP=y
+CONFIG_ARCH_DISCARD_MEMBLOCK=y
+CONFIG_MEMORY_ISOLATION=y
+CONFIG_HAVE_BOOTMEM_INFO_NODE=y
+CONFIG_MEMORY_HOTPLUG=y
+CONFIG_MEMORY_HOTPLUG_SPARSE=y
+# CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE is not set
+CONFIG_MEMORY_HOTREMOVE=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK=y
+CONFIG_MEMORY_BALLOON=y
+# CONFIG_COMPACTION is not set
+CONFIG_MIGRATION=y
+CONFIG_PHYS_ADDR_T_64BIT=y
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+# CONFIG_TRANSPARENT_HUGEPAGE is not set
+CONFIG_NEED_PER_CPU_KM=y
+# CONFIG_CLEANCACHE is not set
+# CONFIG_FRONTSWAP is not set
+# CONFIG_CMA is not set
+# CONFIG_ZPOOL is not set
+# CONFIG_ZBUD is not set
+# CONFIG_ZSMALLOC is not set
+CONFIG_GENERIC_EARLY_IOREMAP=y
+CONFIG_ARCH_SUPPORTS_DEFERRED_STRUCT_PAGE_INIT=y
+# CONFIG_DEFERRED_STRUCT_PAGE_INIT is not set
+# CONFIG_IDLE_PAGE_TRACKING is not set
+# CONFIG_ZONE_DEVICE is not set
+CONFIG_ARCH_USES_HIGH_VMA_FLAGS=y
+CONFIG_ARCH_HAS_PKEYS=y
+# CONFIG_X86_PMEM_LEGACY is not set
+# CONFIG_X86_CHECK_BIOS_CORRUPTION is not set
+CONFIG_X86_RESERVE_LOW=64
+CONFIG_MTRR=y
+CONFIG_MTRR_SANITIZER=y
+CONFIG_MTRR_SANITIZER_ENABLE_DEFAULT=0
+CONFIG_MTRR_SANITIZER_SPARE_REG_NR_DEFAULT=1
+CONFIG_X86_PAT=y
+CONFIG_ARCH_USES_PG_UNCACHED=y
+CONFIG_ARCH_RANDOM=y
+CONFIG_X86_SMAP=y
+# CONFIG_X86_INTEL_MPX is not set
+CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS=y
+# CONFIG_EFI is not set
+CONFIG_SECCOMP=y
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_SCHED_HRTICK=y
+# CONFIG_KEXEC is not set
+# CONFIG_KEXEC_FILE is not set
+# CONFIG_CRASH_DUMP is not set
+CONFIG_PHYSICAL_START=0x1000000
+CONFIG_RELOCATABLE=y
+# CONFIG_RANDOMIZE_BASE is not set
+CONFIG_PHYSICAL_ALIGN=0x1000000
+# CONFIG_LEGACY_VSYSCALL_NATIVE is not set
+CONFIG_LEGACY_VSYSCALL_EMULATE=y
+# CONFIG_LEGACY_VSYSCALL_NONE is not set
+# CONFIG_CMDLINE_BOOL is not set
+CONFIG_MODIFY_LDT_SYSCALL=y
+CONFIG_HAVE_LIVEPATCH=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
+
+#
+# Power management and ACPI options
+#
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+# CONFIG_HIBERNATION is not set
+CONFIG_PM_SLEEP=y
+# CONFIG_PM_AUTOSLEEP is not set
+# CONFIG_PM_WAKELOCKS is not set
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_CLK=y
+# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set
+CONFIG_ACPI=y
+CONFIG_ACPI_LEGACY_TABLES_LOOKUP=y
+CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC=y
+CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT=y
+# CONFIG_ACPI_DEBUGGER is not set
+CONFIG_ACPI_SLEEP=y
+# CONFIG_ACPI_PROCFS_POWER is not set
+CONFIG_ACPI_REV_OVERRIDE_POSSIBLE=y
+# CONFIG_ACPI_EC_DEBUGFS is not set
+CONFIG_ACPI_AC=y
+CONFIG_ACPI_BATTERY=y
+CONFIG_ACPI_BUTTON=y
+CONFIG_ACPI_FAN=y
+# CONFIG_ACPI_DOCK is not set
+CONFIG_ACPI_CPU_FREQ_PSS=y
+CONFIG_ACPI_PROCESSOR_CSTATE=y
+CONFIG_ACPI_PROCESSOR_IDLE=y
+CONFIG_ACPI_PROCESSOR=y
+# CONFIG_ACPI_PROCESSOR_AGGREGATOR is not set
+CONFIG_ACPI_THERMAL=y
+# CONFIG_ACPI_CUSTOM_DSDT is not set
+CONFIG_ARCH_HAS_ACPI_TABLE_UPGRADE=y
+# CONFIG_ACPI_DEBUG is not set
+# CONFIG_ACPI_PCI_SLOT is not set
+CONFIG_X86_PM_TIMER=y
+# CONFIG_ACPI_CONTAINER is not set
+# CONFIG_ACPI_HOTPLUG_MEMORY is not set
+CONFIG_ACPI_HOTPLUG_IOAPIC=y
+# CONFIG_ACPI_SBS is not set
+# CONFIG_ACPI_HED is not set
+# CONFIG_ACPI_REDUCED_HARDWARE_ONLY is not set
+# CONFIG_ACPI_NFIT is not set
+CONFIG_HAVE_ACPI_APEI=y
+CONFIG_HAVE_ACPI_APEI_NMI=y
+# CONFIG_ACPI_APEI is not set
+# CONFIG_DPTF_POWER is not set
+# CONFIG_PMIC_OPREGION is not set
+# CONFIG_ACPI_CONFIGFS is not set
+# CONFIG_SFI is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# CPU Idle
+#
+CONFIG_CPU_IDLE=y
+CONFIG_CPU_IDLE_GOV_LADDER=y
+CONFIG_CPU_IDLE_GOV_MENU=y
+# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
+# CONFIG_INTEL_IDLE is not set
+
+#
+# Bus options (PCI etc.)
+#
+CONFIG_PCI=y
+CONFIG_PCI_DIRECT=y
+# CONFIG_PCI_MMCONFIG is not set
+CONFIG_PCI_DOMAINS=y
+# CONFIG_PCIEPORTBUS is not set
+CONFIG_PCI_BUS_ADDR_T_64BIT=y
+CONFIG_PCI_MSI=y
+CONFIG_PCI_MSI_IRQ_DOMAIN=y
+# CONFIG_PCI_DEBUG is not set
+# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set
+# CONFIG_PCI_STUB is not set
+CONFIG_HT_IRQ=y
+# CONFIG_PCI_IOV is not set
+# CONFIG_PCI_PRI is not set
+# CONFIG_PCI_PASID is not set
+CONFIG_PCI_LABEL=y
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# DesignWare PCI Core Support
+#
+# CONFIG_PCIE_DW_PLAT is not set
+
+#
+# PCI host controller drivers
+#
+# CONFIG_VMD is not set
+CONFIG_ISA_DMA_API=y
+CONFIG_AMD_NB=y
+# CONFIG_PCCARD is not set
+# CONFIG_RAPIDIO is not set
+# CONFIG_X86_SYSFB is not set
+
+#
+# Executable file formats / Emulations
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_ELFCORE=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_BINFMT_SCRIPT=y
+# CONFIG_HAVE_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+CONFIG_COREDUMP=y
+# CONFIG_IA32_EMULATION is not set
+# CONFIG_X86_X32 is not set
+CONFIG_X86_DEV_DMA_OPS=y
+CONFIG_NET=y
+CONFIG_NET_INGRESS=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_DIAG is not set
+CONFIG_UNIX=y
+# CONFIG_UNIX_DIAG is not set
+CONFIG_XFRM=y
+CONFIG_XFRM_ALGO=y
+CONFIG_XFRM_USER=y
+CONFIG_XFRM_SUB_POLICY=y
+CONFIG_XFRM_MIGRATE=y
+CONFIG_XFRM_STATISTICS=y
+CONFIG_XFRM_IPCOMP=y
+CONFIG_NET_KEY=y
+CONFIG_NET_KEY_MIGRATE=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+CONFIG_IP_ADVANCED_ROUTER=y
+# CONFIG_IP_FIB_TRIE_STATS is not set
+CONFIG_IP_MULTIPLE_TABLES=y
+# CONFIG_IP_ROUTE_MULTIPATH is not set
+# CONFIG_IP_ROUTE_VERBOSE is not set
+CONFIG_IP_ROUTE_CLASSID=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE_DEMUX is not set
+CONFIG_NET_IP_TUNNEL=y
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_NET_IPVTI is not set
+CONFIG_NET_UDP_TUNNEL=y
+# CONFIG_NET_FOU is not set
+CONFIG_INET_AH=y
+CONFIG_INET_ESP=y
+# CONFIG_INET_ESP_OFFLOAD is not set
+CONFIG_INET_IPCOMP=y
+CONFIG_INET_XFRM_TUNNEL=y
+CONFIG_INET_TUNNEL=y
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_INET_UDP_DIAG is not set
+# CONFIG_INET_RAW_DIAG is not set
+# CONFIG_INET_DIAG_DESTROY is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+CONFIG_IPV6=y
+# CONFIG_IPV6_ROUTER_PREF is not set
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+# CONFIG_INET6_ESP_OFFLOAD is not set
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+# CONFIG_IPV6_ILA is not set
+CONFIG_INET6_XFRM_TUNNEL=y
+CONFIG_INET6_TUNNEL=y
+CONFIG_INET6_XFRM_MODE_TRANSPORT=y
+CONFIG_INET6_XFRM_MODE_TUNNEL=y
+CONFIG_INET6_XFRM_MODE_BEET=y
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+# CONFIG_IPV6_VTI is not set
+# CONFIG_IPV6_SIT is not set
+CONFIG_IPV6_TUNNEL=y
+# CONFIG_IPV6_FOU is not set
+# CONFIG_IPV6_FOU_TUNNEL is not set
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+# CONFIG_IPV6_MROUTE is not set
+# CONFIG_IPV6_SEG6_LWTUNNEL is not set
+# CONFIG_IPV6_SEG6_HMAC is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NET_PTP_CLASSIFY is not set
+# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_NETFILTER_ADVANCED=y
+
+#
+# Core Netfilter Configuration
+#
+CONFIG_NETFILTER_INGRESS=y
+CONFIG_NETFILTER_NETLINK=y
+# CONFIG_NETFILTER_NETLINK_ACCT is not set
+CONFIG_NETFILTER_NETLINK_QUEUE=y
+CONFIG_NETFILTER_NETLINK_LOG=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_LOG_COMMON=y
+# CONFIG_NF_LOG_NETDEV is not set
+CONFIG_NF_CONNTRACK_MARK=y
+# CONFIG_NF_CONNTRACK_ZONES is not set
+CONFIG_NF_CONNTRACK_PROCFS=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+# CONFIG_NF_CONNTRACK_TIMEOUT is not set
+# CONFIG_NF_CONNTRACK_TIMESTAMP is not set
+# CONFIG_NF_CT_PROTO_DCCP is not set
+# CONFIG_NF_CT_PROTO_SCTP is not set
+CONFIG_NF_CT_PROTO_UDPLITE=y
+# CONFIG_NF_CONNTRACK_AMANDA is not set
+# CONFIG_NF_CONNTRACK_FTP is not set
+# CONFIG_NF_CONNTRACK_H323 is not set
+# CONFIG_NF_CONNTRACK_IRC is not set
+# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set
+# CONFIG_NF_CONNTRACK_SNMP is not set
+# CONFIG_NF_CONNTRACK_PPTP is not set
+CONFIG_NF_CONNTRACK_SANE=y
+# CONFIG_NF_CONNTRACK_SIP is not set
+# CONFIG_NF_CONNTRACK_TFTP is not set
+CONFIG_NF_CT_NETLINK=y
+# CONFIG_NF_CT_NETLINK_TIMEOUT is not set
+# CONFIG_NETFILTER_NETLINK_GLUE_CT is not set
+CONFIG_NF_NAT=y
+CONFIG_NF_NAT_NEEDED=y
+CONFIG_NF_NAT_PROTO_UDPLITE=y
+# CONFIG_NF_NAT_AMANDA is not set
+# CONFIG_NF_NAT_FTP is not set
+# CONFIG_NF_NAT_IRC is not set
+# CONFIG_NF_NAT_SIP is not set
+# CONFIG_NF_NAT_TFTP is not set
+CONFIG_NF_NAT_REDIRECT=y
+# CONFIG_NF_TABLES is not set
+CONFIG_NETFILTER_XTABLES=y
+
+#
+# Xtables combined modules
+#
+CONFIG_NETFILTER_XT_MARK=y
+CONFIG_NETFILTER_XT_CONNMARK=y
+CONFIG_NETFILTER_XT_SET=y
+
+#
+# Xtables targets
+#
+# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_CT=y
+CONFIG_NETFILTER_XT_TARGET_DSCP=y
+CONFIG_NETFILTER_XT_TARGET_HL=y
+# CONFIG_NETFILTER_XT_TARGET_HMARK is not set
+# CONFIG_NETFILTER_XT_TARGET_IDLETIMER is not set
+CONFIG_NETFILTER_XT_TARGET_LOG=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_NAT=y
+CONFIG_NETFILTER_XT_TARGET_NETMAP=y
+CONFIG_NETFILTER_XT_TARGET_NFLOG=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=y
+# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set
+CONFIG_NETFILTER_XT_TARGET_REDIRECT=y
+# CONFIG_NETFILTER_XT_TARGET_TEE is not set
+# CONFIG_NETFILTER_XT_TARGET_TPROXY is not set
+CONFIG_NETFILTER_XT_TARGET_TRACE=y
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=y
+# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set
+
+#
+# Xtables matches
+#
+CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=y
+# CONFIG_NETFILTER_XT_MATCH_BPF is not set
+# CONFIG_NETFILTER_XT_MATCH_CGROUP is not set
+CONFIG_NETFILTER_XT_MATCH_CLUSTER=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=y
+# CONFIG_NETFILTER_XT_MATCH_CONNLABEL is not set
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+# CONFIG_NETFILTER_XT_MATCH_CPU is not set
+CONFIG_NETFILTER_XT_MATCH_DCCP=y
+CONFIG_NETFILTER_XT_MATCH_DEVGROUP=y
+CONFIG_NETFILTER_XT_MATCH_DSCP=y
+CONFIG_NETFILTER_XT_MATCH_ECN=y
+CONFIG_NETFILTER_XT_MATCH_ESP=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_HL=y
+# CONFIG_NETFILTER_XT_MATCH_IPCOMP is not set
+# CONFIG_NETFILTER_XT_MATCH_IPRANGE is not set
+CONFIG_NETFILTER_XT_MATCH_L2TP=y
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+# CONFIG_NETFILTER_XT_MATCH_NFACCT is not set
+# CONFIG_NETFILTER_XT_MATCH_OSF is not set
+# CONFIG_NETFILTER_XT_MATCH_OWNER is not set
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set
+CONFIG_NETFILTER_XT_MATCH_REALM=y
+# CONFIG_NETFILTER_XT_MATCH_RECENT is not set
+CONFIG_NETFILTER_XT_MATCH_SCTP=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=y
+# CONFIG_NETFILTER_XT_MATCH_TIME is not set
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_IP_SET=y
+CONFIG_IP_SET_MAX=256
+CONFIG_IP_SET_BITMAP_IP=y
+CONFIG_IP_SET_BITMAP_IPMAC=y
+CONFIG_IP_SET_BITMAP_PORT=y
+CONFIG_IP_SET_HASH_IP=y
+# CONFIG_IP_SET_HASH_IPMARK is not set
+CONFIG_IP_SET_HASH_IPPORT=y
+CONFIG_IP_SET_HASH_IPPORTIP=y
+CONFIG_IP_SET_HASH_IPPORTNET=y
+# CONFIG_IP_SET_HASH_IPMAC is not set
+# CONFIG_IP_SET_HASH_MAC is not set
+# CONFIG_IP_SET_HASH_NETPORTNET is not set
+CONFIG_IP_SET_HASH_NET=y
+# CONFIG_IP_SET_HASH_NETNET is not set
+CONFIG_IP_SET_HASH_NETPORT=y
+# CONFIG_IP_SET_HASH_NETIFACE is not set
+CONFIG_IP_SET_LIST_SET=y
+# CONFIG_IP_VS is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_NF_DEFRAG_IPV4=y
+CONFIG_NF_CONNTRACK_IPV4=y
+# CONFIG_NF_SOCKET_IPV4 is not set
+# CONFIG_NF_DUP_IPV4 is not set
+# CONFIG_NF_LOG_ARP is not set
+CONFIG_NF_LOG_IPV4=y
+CONFIG_NF_REJECT_IPV4=y
+CONFIG_NF_NAT_IPV4=y
+CONFIG_NF_NAT_MASQUERADE_IPV4=y
+# CONFIG_NF_NAT_PPTP is not set
+# CONFIG_NF_NAT_H323 is not set
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+# CONFIG_IP_NF_MATCH_RPFILTER is not set
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+# CONFIG_IP_NF_TARGET_SYNPROXY is not set
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_TARGET_CLUSTERIP=y
+CONFIG_IP_NF_TARGET_ECN=y
+CONFIG_IP_NF_TARGET_TTL=y
+CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+
+#
+# IPv6: Netfilter Configuration
+#
+CONFIG_NF_DEFRAG_IPV6=y
+CONFIG_NF_CONNTRACK_IPV6=y
+# CONFIG_NF_SOCKET_IPV6 is not set
+# CONFIG_NF_DUP_IPV6 is not set
+CONFIG_NF_REJECT_IPV6=y
+CONFIG_NF_LOG_IPV6=y
+CONFIG_NF_NAT_IPV6=y
+CONFIG_NF_NAT_MASQUERADE_IPV6=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_MATCH_AH=y
+CONFIG_IP6_NF_MATCH_EUI64=y
+CONFIG_IP6_NF_MATCH_FRAG=y
+CONFIG_IP6_NF_MATCH_OPTS=y
+CONFIG_IP6_NF_MATCH_HL=y
+CONFIG_IP6_NF_MATCH_IPV6HEADER=y
+CONFIG_IP6_NF_MATCH_MH=y
+# CONFIG_IP6_NF_MATCH_RPFILTER is not set
+CONFIG_IP6_NF_MATCH_RT=y
+CONFIG_IP6_NF_TARGET_HL=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+# CONFIG_IP6_NF_TARGET_SYNPROXY is not set
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
+# CONFIG_IP6_NF_NAT is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+CONFIG_L2TP=y
+# CONFIG_L2TP_V3 is not set
+# CONFIG_BRIDGE is not set
+CONFIG_HAVE_NET_DSA=y
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_PHONET is not set
+# CONFIG_6LOWPAN is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+# CONFIG_BATMAN_ADV is not set
+# CONFIG_OPENVSWITCH is not set
+# CONFIG_VSOCKETS is not set
+# CONFIG_NETLINK_DIAG is not set
+# CONFIG_MPLS is not set
+# CONFIG_HSR is not set
+# CONFIG_NET_SWITCHDEV is not set
+# CONFIG_NET_L3_MASTER_DEV is not set
+# CONFIG_NET_NCSI is not set
+CONFIG_CGROUP_NET_PRIO=y
+CONFIG_CGROUP_NET_CLASSID=y
+CONFIG_NET_RX_BUSY_POLL=y
+CONFIG_BQL=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+# CONFIG_AF_KCM is not set
+# CONFIG_STREAM_PARSER is not set
+CONFIG_FIB_RULES=y
+CONFIG_WIRELESS=y
+# CONFIG_CFG80211 is not set
+# CONFIG_LIB80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_STA_HASH_MAX_SIZE=0
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+CONFIG_NET_9P=y
+CONFIG_NET_9P_VIRTIO=y
+# CONFIG_NET_9P_DEBUG is not set
+# CONFIG_CAIF is not set
+# CONFIG_CEPH_LIB is not set
+# CONFIG_NFC is not set
+# CONFIG_PSAMPLE is not set
+# CONFIG_NET_IFE is not set
+# CONFIG_LWTUNNEL is not set
+CONFIG_DST_CACHE=y
+CONFIG_GRO_CELLS=y
+# CONFIG_NET_DEVLINK is not set
+CONFIG_MAY_USE_DEVLINK=y
+CONFIG_HAVE_EBPF_JIT=y
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_FW_LOADER_USER_HELPER_FALLBACK is not set
+CONFIG_ALLOW_DEV_COREDUMP=y
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_DEBUG_TEST_DRIVER_REMOVE is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_GENERIC_CPU_DEVICES is not set
+CONFIG_GENERIC_CPU_AUTOPROBE=y
+# CONFIG_DMA_SHARED_BUFFER is not set
+
+#
+# Bus devices
+#
+# CONFIG_CONNECTOR is not set
+# CONFIG_MTD is not set
+# CONFIG_OF is not set
+CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
+# CONFIG_PARPORT is not set
+CONFIG_PNP=y
+CONFIG_PNP_DEBUG_MESSAGES=y
+
+#
+# Protocols
+#
+CONFIG_PNPACPI=y
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_NULL_BLK is not set
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_DRBD is not set
+CONFIG_BLK_DEV_NBD=y
+# CONFIG_BLK_DEV_SKD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_VIRTIO_BLK=y
+# CONFIG_VIRTIO_BLK_SCSI is not set
+# CONFIG_BLK_DEV_HD is not set
+# CONFIG_BLK_DEV_RBD is not set
+# CONFIG_BLK_DEV_RSXX is not set
+# CONFIG_BLK_DEV_NVME is not set
+# CONFIG_NVME_FC is not set
+
+#
+# Misc devices
+#
+# CONFIG_SENSORS_LIS3LV02D is not set
+# CONFIG_DUMMY_IRQ is not set
+# CONFIG_IBM_ASM is not set
+# CONFIG_PHANTOM is not set
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_HP_ILO is not set
+# CONFIG_SRAM is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
+
+#
+# Texas Instruments shared transport line discipline
+#
+
+#
+# Altera FPGA firmware download module
+#
+# CONFIG_INTEL_MEI is not set
+# CONFIG_INTEL_MEI_ME is not set
+# CONFIG_INTEL_MEI_TXE is not set
+# CONFIG_VMWARE_VMCI is not set
+
+#
+# Intel MIC Bus Driver
+#
+# CONFIG_INTEL_MIC_BUS is not set
+
+#
+# SCIF Bus Driver
+#
+# CONFIG_SCIF_BUS is not set
+
+#
+# VOP Bus Driver
+#
+# CONFIG_VOP_BUS is not set
+
+#
+# Intel MIC Host Driver
+#
+
+#
+# Intel MIC Card Driver
+#
+
+#
+# SCIF Driver
+#
+
+#
+# Intel MIC Coprocessor State Management (COSM) Drivers
+#
+
+#
+# VOP Driver
+#
+# CONFIG_GENWQE is not set
+# CONFIG_ECHO is not set
+# CONFIG_CXL_BASE is not set
+# CONFIG_CXL_AFU_DRIVER_OPS is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI_MOD=y
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_FIREWIRE is not set
+# CONFIG_FIREWIRE_NOSY is not set
+# CONFIG_MACINTOSH_DRIVERS is not set
+CONFIG_NETDEVICES=y
+CONFIG_NET_CORE=y
+# CONFIG_BONDING is not set
+CONFIG_DUMMY=y
+# CONFIG_EQUALIZER is not set
+# CONFIG_NET_TEAM is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_VXLAN is not set
+# CONFIG_GENEVE is not set
+# CONFIG_GTP is not set
+CONFIG_MACSEC=y
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+CONFIG_TUN=y
+# CONFIG_TUN_VNET_CROSS_LE is not set
+# CONFIG_VETH is not set
+CONFIG_VIRTIO_NET=y
+# CONFIG_NLMON is not set
+# CONFIG_ARCNET is not set
+
+#
+# CAIF transport drivers
+#
+
+#
+# Distributed Switch Architecture drivers
+#
+CONFIG_ETHERNET=y
+CONFIG_NET_VENDOR_3COM=y
+# CONFIG_VORTEX is not set
+# CONFIG_TYPHOON is not set
+CONFIG_NET_VENDOR_ADAPTEC=y
+# CONFIG_ADAPTEC_STARFIRE is not set
+CONFIG_NET_VENDOR_AGERE=y
+# CONFIG_ET131X is not set
+CONFIG_NET_VENDOR_ALACRITECH=y
+# CONFIG_SLICOSS is not set
+CONFIG_NET_VENDOR_ALTEON=y
+# CONFIG_ACENIC is not set
+# CONFIG_ALTERA_TSE is not set
+CONFIG_NET_VENDOR_AMAZON=y
+# CONFIG_ENA_ETHERNET is not set
+CONFIG_NET_VENDOR_AMD=y
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD_XGBE is not set
+# CONFIG_AMD_XGBE_HAVE_ECC is not set
+CONFIG_NET_VENDOR_AQUANTIA=y
+# CONFIG_AQTION is not set
+# CONFIG_NET_VENDOR_ARC is not set
+CONFIG_NET_VENDOR_ATHEROS=y
+# CONFIG_ATL2 is not set
+# CONFIG_ATL1 is not set
+# CONFIG_ATL1E is not set
+# CONFIG_ATL1C is not set
+# CONFIG_ALX is not set
+# CONFIG_NET_VENDOR_AURORA is not set
+CONFIG_NET_CADENCE=y
+# CONFIG_MACB is not set
+CONFIG_NET_VENDOR_BROADCOM=y
+# CONFIG_B44 is not set
+# CONFIG_BCMGENET is not set
+# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2X is not set
+# CONFIG_BNXT is not set
+CONFIG_NET_VENDOR_BROCADE=y
+# CONFIG_BNA is not set
+CONFIG_NET_VENDOR_CAVIUM=y
+# CONFIG_THUNDER_NIC_PF is not set
+# CONFIG_THUNDER_NIC_VF is not set
+# CONFIG_THUNDER_NIC_BGX is not set
+# CONFIG_THUNDER_NIC_RGX is not set
+# CONFIG_LIQUIDIO is not set
+# CONFIG_LIQUIDIO_VF is not set
+CONFIG_NET_VENDOR_CHELSIO=y
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_CHELSIO_T3 is not set
+# CONFIG_CHELSIO_T4 is not set
+# CONFIG_CHELSIO_T4VF is not set
+CONFIG_NET_VENDOR_CISCO=y
+# CONFIG_ENIC is not set
+# CONFIG_CX_ECAT is not set
+# CONFIG_DNET is not set
+CONFIG_NET_VENDOR_DEC=y
+# CONFIG_NET_TULIP is not set
+CONFIG_NET_VENDOR_DLINK=y
+# CONFIG_DL2K is not set
+# CONFIG_SUNDANCE is not set
+CONFIG_NET_VENDOR_EMULEX=y
+# CONFIG_BE2NET is not set
+CONFIG_NET_VENDOR_EZCHIP=y
+CONFIG_NET_VENDOR_EXAR=y
+# CONFIG_S2IO is not set
+# CONFIG_VXGE is not set
+CONFIG_NET_VENDOR_HP=y
+# CONFIG_HP100 is not set
+CONFIG_NET_VENDOR_INTEL=y
+# CONFIG_E100 is not set
+# CONFIG_E1000 is not set
+# CONFIG_E1000E is not set
+# CONFIG_IGB is not set
+# CONFIG_IGBVF is not set
+# CONFIG_IXGB is not set
+# CONFIG_IXGBE is not set
+# CONFIG_IXGBEVF is not set
+# CONFIG_I40E is not set
+# CONFIG_I40EVF is not set
+# CONFIG_FM10K is not set
+CONFIG_NET_VENDOR_I825XX=y
+# CONFIG_JME is not set
+CONFIG_NET_VENDOR_MARVELL=y
+# CONFIG_MVMDIO is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+CONFIG_NET_VENDOR_MELLANOX=y
+# CONFIG_MLX4_EN is not set
+# CONFIG_MLX4_CORE is not set
+# CONFIG_MLX5_CORE is not set
+# CONFIG_MLXSW_CORE is not set
+CONFIG_NET_VENDOR_MICREL=y
+# CONFIG_KS8851_MLL is not set
+# CONFIG_KSZ884X_PCI is not set
+CONFIG_NET_VENDOR_MYRI=y
+# CONFIG_MYRI10GE is not set
+# CONFIG_FEALNX is not set
+CONFIG_NET_VENDOR_NATSEMI=y
+# CONFIG_NATSEMI is not set
+# CONFIG_NS83820 is not set
+CONFIG_NET_VENDOR_NETRONOME=y
+# CONFIG_NFP is not set
+CONFIG_NET_VENDOR_8390=y
+# CONFIG_NE2K_PCI is not set
+CONFIG_NET_VENDOR_NVIDIA=y
+# CONFIG_FORCEDETH is not set
+CONFIG_NET_VENDOR_OKI=y
+# CONFIG_ETHOC is not set
+CONFIG_NET_PACKET_ENGINE=y
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+CONFIG_NET_VENDOR_QLOGIC=y
+# CONFIG_QLA3XXX is not set
+# CONFIG_QLCNIC is not set
+# CONFIG_QLGE is not set
+# CONFIG_NETXEN_NIC is not set
+# CONFIG_QED is not set
+CONFIG_NET_VENDOR_QUALCOMM=y
+# CONFIG_QCOM_EMAC is not set
+CONFIG_NET_VENDOR_REALTEK=y
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_R8169 is not set
+CONFIG_NET_VENDOR_RENESAS=y
+CONFIG_NET_VENDOR_RDC=y
+# CONFIG_R6040 is not set
+CONFIG_NET_VENDOR_ROCKER=y
+CONFIG_NET_VENDOR_SAMSUNG=y
+# CONFIG_SXGBE_ETH is not set
+CONFIG_NET_VENDOR_SEEQ=y
+CONFIG_NET_VENDOR_SILAN=y
+# CONFIG_SC92031 is not set
+CONFIG_NET_VENDOR_SIS=y
+# CONFIG_SIS900 is not set
+# CONFIG_SIS190 is not set
+CONFIG_NET_VENDOR_SOLARFLARE=y
+# CONFIG_SFC is not set
+# CONFIG_SFC_FALCON is not set
+CONFIG_NET_VENDOR_SMSC=y
+# CONFIG_EPIC100 is not set
+# CONFIG_SMSC911X is not set
+# CONFIG_SMSC9420 is not set
+CONFIG_NET_VENDOR_STMICRO=y
+# CONFIG_STMMAC_ETH is not set
+CONFIG_NET_VENDOR_SUN=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NIU is not set
+CONFIG_NET_VENDOR_TEHUTI=y
+# CONFIG_TEHUTI is not set
+CONFIG_NET_VENDOR_TI=y
+# CONFIG_TI_CPSW_ALE is not set
+# CONFIG_TLAN is not set
+CONFIG_NET_VENDOR_VIA=y
+# CONFIG_VIA_RHINE is not set
+# CONFIG_VIA_VELOCITY is not set
+CONFIG_NET_VENDOR_WIZNET=y
+# CONFIG_WIZNET_W5100 is not set
+# CONFIG_WIZNET_W5300 is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_NET_SB1000 is not set
+# CONFIG_PHYLIB is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Host-side USB support is needed for USB Network Adapter support
+#
+CONFIG_WLAN=y
+CONFIG_WLAN_VENDOR_ADMTEK=y
+CONFIG_WLAN_VENDOR_ATH=y
+# CONFIG_ATH_DEBUG is not set
+# CONFIG_ATH5K_PCI is not set
+CONFIG_WLAN_VENDOR_ATMEL=y
+CONFIG_WLAN_VENDOR_BROADCOM=y
+CONFIG_WLAN_VENDOR_CISCO=y
+CONFIG_WLAN_VENDOR_INTEL=y
+CONFIG_WLAN_VENDOR_INTERSIL=y
+# CONFIG_HOSTAP is not set
+# CONFIG_PRISM54 is not set
+CONFIG_WLAN_VENDOR_MARVELL=y
+CONFIG_WLAN_VENDOR_MEDIATEK=y
+CONFIG_WLAN_VENDOR_RALINK=y
+CONFIG_WLAN_VENDOR_REALTEK=y
+CONFIG_WLAN_VENDOR_RSI=y
+CONFIG_WLAN_VENDOR_ST=y
+CONFIG_WLAN_VENDOR_TI=y
+CONFIG_WLAN_VENDOR_ZYDAS=y
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+# CONFIG_WAN is not set
+# CONFIG_VMXNET3 is not set
+# CONFIG_FUJITSU_ES is not set
+# CONFIG_ISDN is not set
+# CONFIG_NVM is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+# CONFIG_INPUT_SPARSEKMAP is not set
+# CONFIG_INPUT_MATRIXKMAP is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
+# CONFIG_KEYBOARD_SAMSUNG is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+CONFIG_MOUSE_PS2_ALPS=y
+CONFIG_MOUSE_PS2_BYD=y
+CONFIG_MOUSE_PS2_LOGIPS2PP=y
+CONFIG_MOUSE_PS2_SYNAPTICS=y
+CONFIG_MOUSE_PS2_CYPRESS=y
+CONFIG_MOUSE_PS2_LIFEBOOK=y
+CONFIG_MOUSE_PS2_TRACKPOINT=y
+# CONFIG_MOUSE_PS2_ELANTECH is not set
+# CONFIG_MOUSE_PS2_SENTELIC is not set
+# CONFIG_MOUSE_PS2_TOUCHKIT is not set
+CONFIG_MOUSE_PS2_FOCALTECH=y
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_APPLETOUCH is not set
+# CONFIG_MOUSE_BCM5974 is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_MOUSE_SYNAPTICS_USB is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+# CONFIG_RMI4_CORE is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y
+CONFIG_SERIO_I8042=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_SERIO_ALTERA_PS2 is not set
+# CONFIG_SERIO_PS2MULT is not set
+# CONFIG_SERIO_ARC_PS2 is not set
+# CONFIG_USERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_TTY=y
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_VT_CONSOLE_SLEEP=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_NOZOMI is not set
+# CONFIG_N_GSM is not set
+# CONFIG_TRACE_SINK is not set
+CONFIG_DEVMEM=y
+CONFIG_DEVKMEM=y
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_UARTLITE is not set
+# CONFIG_SERIAL_JSM is not set
+# CONFIG_SERIAL_SCCNXP is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
+# CONFIG_SERIAL_ARC is not set
+# CONFIG_SERIAL_RP2 is not set
+# CONFIG_SERIAL_FSL_LPUART is not set
+# CONFIG_SERIAL_DEV_BUS is not set
+CONFIG_HVC_DRIVER=y
+CONFIG_VIRTIO_CONSOLE=y
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_MWAVE is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_HPET is not set
+# CONFIG_HANGCHECK_TIMER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+CONFIG_DEVPORT=y
+# CONFIG_XILLYBUS is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+# CONFIG_SPI is not set
+# CONFIG_SPMI is not set
+# CONFIG_HSI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+
+#
+# PPS generators support
+#
+
+#
+# PTP clock support
+#
+# CONFIG_PTP_1588_CLOCK is not set
+
+#
+# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
+#
+# CONFIG_GPIOLIB is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_AVS is not set
+# CONFIG_POWER_RESET is not set
+CONFIG_POWER_SUPPLY=y
+# CONFIG_POWER_SUPPLY_DEBUG is not set
+# CONFIG_PDA_POWER is not set
+# CONFIG_TEST_POWER is not set
+# CONFIG_BATTERY_DS2780 is not set
+# CONFIG_BATTERY_DS2781 is not set
+# CONFIG_BATTERY_BQ27XXX is not set
+# CONFIG_CHARGER_MAX8903 is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Native drivers
+#
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_ABITUGURU3 is not set
+# CONFIG_SENSORS_K8TEMP is not set
+# CONFIG_SENSORS_K10TEMP is not set
+# CONFIG_SENSORS_FAM15H_POWER is not set
+# CONFIG_SENSORS_APPLESMC is not set
+# CONFIG_SENSORS_DELL_SMM is not set
+# CONFIG_SENSORS_I5K_AMB is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_I5500 is not set
+# CONFIG_SENSORS_CORETEMP is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_MAX197 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_NTC_THERMISTOR is not set
+# CONFIG_SENSORS_NCT6683 is not set
+# CONFIG_SENSORS_NCT6775 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_SCH56XX_COMMON is not set
+# CONFIG_SENSORS_VIA_CPUTEMP is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_VT8231 is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+
+#
+# ACPI drivers
+#
+# CONFIG_SENSORS_ACPI_POWER is not set
+# CONFIG_SENSORS_ATK0110 is not set
+CONFIG_THERMAL=y
+CONFIG_THERMAL_HWMON=y
+# CONFIG_THERMAL_WRITABLE_TRIPS is not set
+CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
+# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set
+# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set
+# CONFIG_THERMAL_DEFAULT_GOV_POWER_ALLOCATOR is not set
+# CONFIG_THERMAL_GOV_FAIR_SHARE is not set
+CONFIG_THERMAL_GOV_STEP_WISE=y
+# CONFIG_THERMAL_GOV_BANG_BANG is not set
+# CONFIG_THERMAL_GOV_USER_SPACE is not set
+# CONFIG_THERMAL_GOV_POWER_ALLOCATOR is not set
+# CONFIG_THERMAL_EMULATION is not set
+# CONFIG_INTEL_POWERCLAMP is not set
+# CONFIG_INTEL_SOC_DTS_THERMAL is not set
+
+#
+# ACPI INT340X thermal drivers
+#
+# CONFIG_INT340X_THERMAL is not set
+# CONFIG_INTEL_PCH_THERMAL is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+CONFIG_BCMA_POSSIBLE=y
+
+#
+# Broadcom specific AMBA
+#
+# CONFIG_BCMA is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_CROS_EC is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_INTEL_QUARK_I2C_GPIO is not set
+# CONFIG_LPC_ICH is not set
+# CONFIG_LPC_SCH is not set
+# CONFIG_MFD_INTEL_LPSS_ACPI is not set
+# CONFIG_MFD_INTEL_LPSS_PCI is not set
+# CONFIG_MFD_JANZ_CMODIO is not set
+# CONFIG_MFD_KEMPLD is not set
+# CONFIG_MFD_MT6397 is not set
+# CONFIG_MFD_RDC321X is not set
+# CONFIG_MFD_RTSX_PCI is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_ABX500_CORE is not set
+# CONFIG_MFD_SYSCON is not set
+# CONFIG_MFD_TI_AM335X_TSCADC is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_VX855 is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+# CONFIG_AGP is not set
+CONFIG_VGA_ARB=y
+CONFIG_VGA_ARB_MAX_GPUS=16
+# CONFIG_VGA_SWITCHEROO is not set
+# CONFIG_DRM is not set
+
+#
+# ACP (Audio CoProcessor) Configuration
+#
+# CONFIG_DRM_LIB_RANDOM is not set
+
+#
+# Frame buffer Devices
+#
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+
+#
+# Console display driver support
+#
+CONFIG_VGA_CONSOLE=y
+# CONFIG_VGACON_SOFT_SCROLLBACK is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_DUMMY_CONSOLE_COLUMNS=80
+CONFIG_DUMMY_CONSOLE_ROWS=25
+CONFIG_SOUND=y
+# CONFIG_SOUND_OSS_CORE is not set
+# CONFIG_SND is not set
+# CONFIG_SOUND_PRIME is not set
+
+#
+# HID support
+#
+CONFIG_HID=y
+# CONFIG_HID_BATTERY_STRENGTH is not set
+# CONFIG_HIDRAW is not set
+# CONFIG_UHID is not set
+CONFIG_HID_GENERIC=y
+
+#
+# Special HID drivers
+#
+CONFIG_HID_A4TECH=y
+# CONFIG_HID_ACRUX is not set
+CONFIG_HID_APPLE=y
+# CONFIG_HID_AUREAL is not set
+CONFIG_HID_BELKIN=y
+CONFIG_HID_CHERRY=y
+CONFIG_HID_CHICONY=y
+# CONFIG_HID_CMEDIA is not set
+CONFIG_HID_CYPRESS=y
+# CONFIG_HID_DRAGONRISE is not set
+# CONFIG_HID_EMS_FF is not set
+# CONFIG_HID_ELECOM is not set
+CONFIG_HID_EZKEY=y
+# CONFIG_HID_GEMBIRD is not set
+# CONFIG_HID_GFRM is not set
+# CONFIG_HID_KEYTOUCH is not set
+# CONFIG_HID_KYE is not set
+# CONFIG_HID_WALTOP is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_ICADE is not set
+# CONFIG_HID_TWINHAN is not set
+CONFIG_HID_KENSINGTON=y
+# CONFIG_HID_LCPOWER is not set
+# CONFIG_HID_LENOVO is not set
+CONFIG_HID_LOGITECH=y
+# CONFIG_HID_LOGITECH_HIDPP is not set
+# CONFIG_LOGITECH_FF is not set
+# CONFIG_LOGIRUMBLEPAD2_FF is not set
+# CONFIG_LOGIG940_FF is not set
+# CONFIG_LOGIWHEELS_FF is not set
+# CONFIG_HID_MAGICMOUSE is not set
+# CONFIG_HID_MAYFLASH is not set
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MONTEREY=y
+# CONFIG_HID_MULTITOUCH is not set
+# CONFIG_HID_ORTEK is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_PICOLCD is not set
+CONFIG_HID_PLANTRONICS=y
+# CONFIG_HID_PRIMAX is not set
+# CONFIG_HID_SAITEK is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SPEEDLINK is not set
+# CONFIG_HID_STEELSERIES is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_HID_RMI is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
+# CONFIG_HID_TIVO is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_UDRAW_PS3 is not set
+# CONFIG_HID_WACOM is not set
+# CONFIG_HID_XINMO is not set
+# CONFIG_HID_ZEROPLUS is not set
+# CONFIG_HID_ZYDACRON is not set
+# CONFIG_HID_SENSOR_HUB is not set
+# CONFIG_HID_ALPS is not set
+
+#
+# Intel ISH HID support
+#
+# CONFIG_INTEL_ISH_HID is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB is not set
+
+#
+# USB port drivers
+#
+
+#
+# USB Physical Layer drivers
+#
+# CONFIG_USB_PHY is not set
+# CONFIG_NOP_USB_XCEIV is not set
+# CONFIG_USB_GADGET is not set
+# CONFIG_USB_ULPI_BUS is not set
+# CONFIG_UWB is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_INFINIBAND is not set
+CONFIG_EDAC_ATOMIC_SCRUB=y
+CONFIG_EDAC_SUPPORT=y
+# CONFIG_EDAC is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_MC146818_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+
+#
+# DMABUF options
+#
+# CONFIG_SYNC_FILE is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+# CONFIG_VIRT_DRIVERS is not set
+CONFIG_VIRTIO=y
+
+#
+# Virtio drivers
+#
+CONFIG_VIRTIO_PCI=y
+CONFIG_VIRTIO_PCI_LEGACY=y
+CONFIG_VIRTIO_BALLOON=y
+# CONFIG_VIRTIO_INPUT is not set
+CONFIG_VIRTIO_MMIO=y
+# CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES is not set
+
+#
+# Microsoft Hyper-V guest support
+#
+# CONFIG_STAGING is not set
+CONFIG_X86_PLATFORM_DEVICES=y
+# CONFIG_ACERHDF is not set
+# CONFIG_DELL_SMO8800 is not set
+# CONFIG_FUJITSU_TABLET is not set
+# CONFIG_HP_ACCEL is not set
+# CONFIG_HP_WIRELESS is not set
+# CONFIG_SENSORS_HDAPS is not set
+# CONFIG_INTEL_MENLOW is not set
+# CONFIG_ASUS_WIRELESS is not set
+# CONFIG_ACPI_WMI is not set
+# CONFIG_TOPSTAR_LAPTOP is not set
+# CONFIG_TOSHIBA_BT_RFKILL is not set
+# CONFIG_TOSHIBA_HAPS is not set
+# CONFIG_ACPI_CMPC is not set
+# CONFIG_INTEL_HID_EVENT is not set
+# CONFIG_INTEL_VBTN is not set
+# CONFIG_INTEL_IPS is not set
+# CONFIG_INTEL_PMC_CORE is not set
+# CONFIG_IBM_RTL is not set
+# CONFIG_SAMSUNG_Q10 is not set
+# CONFIG_INTEL_RST is not set
+# CONFIG_INTEL_SMARTCONNECT is not set
+# CONFIG_PVPANIC is not set
+# CONFIG_INTEL_PMC_IPC is not set
+# CONFIG_SURFACE_PRO3_BUTTON is not set
+# CONFIG_INTEL_PUNIT_IPC is not set
+# CONFIG_MLX_PLATFORM is not set
+# CONFIG_MLX_CPLD_PLATFORM is not set
+CONFIG_PMC_ATOM=y
+# CONFIG_CHROME_PLATFORMS is not set
+CONFIG_CLKDEV_LOOKUP=y
+CONFIG_HAVE_CLK_PREPARE=y
+CONFIG_COMMON_CLK=y
+
+#
+# Common Clock Framework
+#
+# CONFIG_COMMON_CLK_NXP is not set
+# CONFIG_COMMON_CLK_PXA is not set
+# CONFIG_COMMON_CLK_PIC32 is not set
+
+#
+# Hardware Spinlock drivers
+#
+
+#
+# Clock Source drivers
+#
+CONFIG_CLKEVT_I8253=y
+CONFIG_I8253_LOCK=y
+CONFIG_CLKBLD_I8253=y
+# CONFIG_ATMEL_PIT is not set
+# CONFIG_SH_TIMER_CMT is not set
+# CONFIG_SH_TIMER_MTU2 is not set
+# CONFIG_SH_TIMER_TMU is not set
+# CONFIG_EM_TIMER_STI is not set
+# CONFIG_MAILBOX is not set
+CONFIG_IOMMU_SUPPORT=y
+
+#
+# Generic IOMMU Pagetable Support
+#
+# CONFIG_AMD_IOMMU is not set
+# CONFIG_INTEL_IOMMU is not set
+# CONFIG_IRQ_REMAP is not set
+
+#
+# Remoteproc drivers
+#
+# CONFIG_REMOTEPROC is not set
+
+#
+# Rpmsg drivers
+#
+
+#
+# SOC (System On Chip) specific Drivers
+#
+
+#
+# Broadcom SoC drivers
+#
+# CONFIG_SUNXI_SRAM is not set
+# CONFIG_SOC_TI is not set
+# CONFIG_SOC_ZTE is not set
+# CONFIG_PM_DEVFREQ is not set
+# CONFIG_EXTCON is not set
+# CONFIG_MEMORY is not set
+# CONFIG_IIO is not set
+# CONFIG_NTB is not set
+# CONFIG_VME_BUS is not set
+# CONFIG_PWM is not set
+CONFIG_ARM_GIC_MAX_NR=1
+# CONFIG_IPACK_BUS is not set
+# CONFIG_RESET_CONTROLLER is not set
+# CONFIG_FMC is not set
+
+#
+# PHY Subsystem
+#
+# CONFIG_GENERIC_PHY is not set
+# CONFIG_PHY_PXA_28NM_HSIC is not set
+# CONFIG_PHY_PXA_28NM_USB2 is not set
+# CONFIG_BCM_KONA_USB2_PHY is not set
+# CONFIG_POWERCAP is not set
+# CONFIG_MCB is not set
+
+#
+# Performance monitor support
+#
+# CONFIG_RAS is not set
+# CONFIG_THUNDERBOLT is not set
+
+#
+# Android
+#
+# CONFIG_ANDROID is not set
+# CONFIG_LIBNVDIMM is not set
+# CONFIG_NVMEM is not set
+# CONFIG_STM is not set
+# CONFIG_INTEL_TH is not set
+
+#
+# FPGA Configuration Support
+#
+# CONFIG_FPGA is not set
+
+#
+# FSI support
+#
+# CONFIG_FSI is not set
+
+#
+# Firmware Drivers
+#
+# CONFIG_EDD is not set
+CONFIG_FIRMWARE_MEMMAP=y
+# CONFIG_DELL_RBU is not set
+# CONFIG_DCDBAS is not set
+CONFIG_DMIID=y
+# CONFIG_DMI_SYSFS is not set
+CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK=y
+# CONFIG_ISCSI_IBFT_FIND is not set
+# CONFIG_FW_CFG_SYSFS is not set
+# CONFIG_GOOGLE_FIRMWARE is not set
+# CONFIG_EFI_DEV_PATH_PARSER is not set
+
+#
+# Tegra firmware driver
+#
+
+#
+# File systems
+#
+CONFIG_DCACHE_WORD_ACCESS=y
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_EXT4_FS=y
+# CONFIG_EXT4_FS_POSIX_ACL is not set
+# CONFIG_EXT4_FS_SECURITY is not set
+# CONFIG_EXT4_ENCRYPTION is not set
+# CONFIG_EXT4_DEBUG is not set
+CONFIG_JBD2=y
+# CONFIG_JBD2_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+CONFIG_REISERFS_FS=y
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_REISERFS_FS_XATTR is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+# CONFIG_F2FS_FS is not set
+# CONFIG_FS_DAX is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_EXPORTFS=y
+# CONFIG_EXPORTFS_BLOCK_OPS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_MANDATORY_FILE_LOCKING=y
+# CONFIG_FS_ENCRYPTION is not set
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_FANOTIFY is not set
+CONFIG_QUOTA=y
+# CONFIG_QUOTA_NETLINK_INTERFACE is not set
+CONFIG_PRINT_QUOTA_WARNING=y
+# CONFIG_QUOTA_DEBUG is not set
+# CONFIG_QFMT_V1 is not set
+# CONFIG_QFMT_V2 is not set
+CONFIG_QUOTACTL=y
+CONFIG_AUTOFS4_FS=y
+# CONFIG_FUSE_FS is not set
+# CONFIG_OVERLAY_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+# CONFIG_PROC_CHILDREN is not set
+CONFIG_KERNFS=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_TMPFS_XATTR is not set
+# CONFIG_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_ARCH_HAS_GIGANTIC_PAGE=y
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ORANGEFS_FS is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX6FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_PSTORE is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+# CONFIG_NFS_FS is not set
+# CONFIG_NFSD is not set
+# CONFIG_CEPH_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+CONFIG_9P_FS=y
+CONFIG_9P_FS_POSIX_ACL=y
+# CONFIG_9P_FS_SECURITY is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_MAC_ROMAN is not set
+# CONFIG_NLS_MAC_CELTIC is not set
+# CONFIG_NLS_MAC_CENTEURO is not set
+# CONFIG_NLS_MAC_CROATIAN is not set
+# CONFIG_NLS_MAC_CYRILLIC is not set
+# CONFIG_NLS_MAC_GAELIC is not set
+# CONFIG_NLS_MAC_GREEK is not set
+# CONFIG_NLS_MAC_ICELAND is not set
+# CONFIG_NLS_MAC_INUIT is not set
+# CONFIG_NLS_MAC_ROMANIAN is not set
+# CONFIG_NLS_MAC_TURKISH is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+
+#
+# printk and dmesg options
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_CONSOLE_LOGLEVEL_DEFAULT=7
+CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4
+# CONFIG_BOOT_PRINTK_DELAY is not set
+
+#
+# Compile-time checks and compiler options
+#
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_INFO_REDUCED is not set
+# CONFIG_DEBUG_INFO_SPLIT is not set
+# CONFIG_DEBUG_INFO_DWARF4 is not set
+# CONFIG_GDB_SCRIPTS is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_READABLE_ASM is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_PAGE_OWNER is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_SECTION_MISMATCH is not set
+CONFIG_SECTION_MISMATCH_WARN_ONLY=y
+CONFIG_ARCH_WANT_FRAME_POINTERS=y
+CONFIG_FRAME_POINTER=y
+# CONFIG_STACK_VALIDATION is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
+# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_DEBUG_KERNEL=y
+
+#
+# Memory Debugging
+#
+# CONFIG_PAGE_EXTENSION is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
+# CONFIG_PAGE_POISONING is not set
+CONFIG_DEBUG_RODATA_TEST=y
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_HAVE_DEBUG_KMEMLEAK=y
+# CONFIG_DEBUG_KMEMLEAK is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_VM is not set
+CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y
+# CONFIG_DEBUG_VIRTUAL is not set
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_HAVE_DEBUG_STACKOVERFLOW=y
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+CONFIG_HAVE_ARCH_KMEMCHECK=y
+CONFIG_HAVE_ARCH_KASAN=y
+# CONFIG_KASAN is not set
+CONFIG_ARCH_HAS_KCOV=y
+# CONFIG_KCOV is not set
+# CONFIG_DEBUG_SHIRQ is not set
+
+#
+# Debug Lockups and Hangs
+#
+# CONFIG_LOCKUP_DETECTOR is not set
+CONFIG_DETECT_HUNG_TASK=y
+CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
+# CONFIG_WQ_WATCHDOG is not set
+# CONFIG_PANIC_ON_OOPS is not set
+CONFIG_PANIC_ON_OOPS_VALUE=0
+CONFIG_PANIC_TIMEOUT=0
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_SCHED_INFO is not set
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_SCHED_STACK_END_CHECK is not set
+# CONFIG_DEBUG_TIMEKEEPING is not set
+
+#
+# Lock Debugging (spinlocks, mutexes, etc...)
+#
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_ATOMIC_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_LOCK_TORTURE_TEST is not set
+# CONFIG_WW_MUTEX_SELFTEST is not set
+# CONFIG_STACKTRACE is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_PI_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
+
+#
+# RCU Debugging
+#
+# CONFIG_PROVE_RCU is not set
+# CONFIG_SPARSE_RCU_POINTER is not set
+# CONFIG_TORTURE_TEST is not set
+# CONFIG_RCU_PERF_TEST is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_TRACE is not set
+# CONFIG_RCU_EQS_DEBUG is not set
+# CONFIG_DEBUG_WQ_FORCE_RR_CPU is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_NOTIFIER_ERROR_INJECTION is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+CONFIG_USER_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
+CONFIG_HAVE_FENTRY=y
+CONFIG_HAVE_C_RECORDMCOUNT=y
+CONFIG_TRACING_SUPPORT=y
+CONFIG_FTRACE=y
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_HWLAT_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
+# CONFIG_FTRACE_SYSCALLS is not set
+# CONFIG_TRACER_SNAPSHOT is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_UPROBE_EVENTS is not set
+# CONFIG_PROBE_EVENTS is not set
+# CONFIG_MMIOTRACE is not set
+# CONFIG_HIST_TRIGGERS is not set
+# CONFIG_TRACEPOINT_BENCHMARK is not set
+
+#
+# Runtime Testing
+#
+# CONFIG_TEST_LIST_SORT is not set
+# CONFIG_TEST_SORT is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_RBTREE_TEST is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
+# CONFIG_TEST_HEXDUMP is not set
+# CONFIG_TEST_STRING_HELPERS is not set
+# CONFIG_TEST_KSTRTOX is not set
+# CONFIG_TEST_PRINTF is not set
+# CONFIG_TEST_BITMAP is not set
+# CONFIG_TEST_UUID is not set
+# CONFIG_TEST_RHASHTABLE is not set
+# CONFIG_TEST_HASH is not set
+# CONFIG_PROVIDE_OHCI1394_DMA_INIT is not set
+# CONFIG_DMA_API_DEBUG is not set
+# CONFIG_TEST_FIRMWARE is not set
+# CONFIG_TEST_UDELAY is not set
+# CONFIG_MEMTEST is not set
+# CONFIG_BUG_ON_DATA_CORRUPTION is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+CONFIG_ARCH_HAS_UBSAN_SANITIZE_ALL=y
+# CONFIG_ARCH_WANTS_UBSAN_NO_NULL is not set
+# CONFIG_UBSAN is not set
+CONFIG_ARCH_HAS_DEVMEM_IS_ALLOWED=y
+# CONFIG_STRICT_DEVMEM is not set
+CONFIG_X86_VERBOSE_BOOTUP=y
+CONFIG_EARLY_PRINTK=y
+# CONFIG_EARLY_PRINTK_DBGP is not set
+# CONFIG_X86_PTDUMP_CORE is not set
+# CONFIG_X86_PTDUMP is not set
+# CONFIG_DEBUG_WX is not set
+CONFIG_DOUBLEFAULT=y
+# CONFIG_DEBUG_TLBFLUSH is not set
+# CONFIG_IOMMU_DEBUG is not set
+# CONFIG_IOMMU_STRESS is not set
+CONFIG_HAVE_MMIOTRACE_SUPPORT=y
+CONFIG_IO_DELAY_TYPE_0X80=0
+CONFIG_IO_DELAY_TYPE_0XED=1
+CONFIG_IO_DELAY_TYPE_UDELAY=2
+CONFIG_IO_DELAY_TYPE_NONE=3
+CONFIG_IO_DELAY_0X80=y
+# CONFIG_IO_DELAY_0XED is not set
+# CONFIG_IO_DELAY_UDELAY is not set
+# CONFIG_IO_DELAY_NONE is not set
+CONFIG_DEFAULT_IO_DELAY_TYPE=0
+# CONFIG_CPA_DEBUG is not set
+# CONFIG_OPTIMIZE_INLINING is not set
+# CONFIG_DEBUG_ENTRY is not set
+# CONFIG_DEBUG_NMI_SELFTEST is not set
+CONFIG_X86_DEBUG_FPU=y
+# CONFIG_PUNIT_ATOM_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY_DMESG_RESTRICT is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y
+CONFIG_HAVE_ARCH_HARDENED_USERCOPY=y
+# CONFIG_HARDENED_USERCOPY is not set
+# CONFIG_STATIC_USERMODEHELPER is not set
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_DEFAULT_SECURITY=""
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_RNG_DEFAULT=y
+CONFIG_CRYPTO_AKCIPHER2=y
+CONFIG_CRYPTO_KPP2=y
+CONFIG_CRYPTO_KPP=y
+CONFIG_CRYPTO_ACOMP2=y
+# CONFIG_CRYPTO_RSA is not set
+CONFIG_CRYPTO_DH=y
+CONFIG_CRYPTO_ECDH=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+CONFIG_CRYPTO_USER=y
+CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
+CONFIG_CRYPTO_GF128MUL=y
+CONFIG_CRYPTO_NULL=y
+CONFIG_CRYPTO_NULL2=y
+CONFIG_CRYPTO_WORKQUEUE=y
+CONFIG_CRYPTO_CRYPTD=y
+CONFIG_CRYPTO_MCRYPTD=y
+CONFIG_CRYPTO_AUTHENC=y
+CONFIG_CRYPTO_ABLK_HELPER=y
+CONFIG_CRYPTO_SIMD=y
+CONFIG_CRYPTO_GLUE_HELPER_X86=y
+
+#
+# Authenticated Encryption with Associated Data
+#
+CONFIG_CRYPTO_CCM=y
+CONFIG_CRYPTO_GCM=y
+CONFIG_CRYPTO_CHACHA20POLY1305=y
+CONFIG_CRYPTO_SEQIV=y
+CONFIG_CRYPTO_ECHAINIV=y
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_CTR=y
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=y
+CONFIG_CRYPTO_LRW=y
+CONFIG_CRYPTO_PCBC=y
+CONFIG_CRYPTO_XTS=y
+# CONFIG_CRYPTO_KEYWRAP is not set
+
+#
+# Hash modes
+#
+CONFIG_CRYPTO_CMAC=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_XCBC=y
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+CONFIG_CRYPTO_CRC32C=y
+# CONFIG_CRYPTO_CRC32C_INTEL is not set
+# CONFIG_CRYPTO_CRC32 is not set
+# CONFIG_CRYPTO_CRC32_PCLMUL is not set
+# CONFIG_CRYPTO_CRCT10DIF is not set
+CONFIG_CRYPTO_GHASH=y
+CONFIG_CRYPTO_POLY1305=y
+CONFIG_CRYPTO_POLY1305_X86_64=y
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_MICHAEL_MIC=y
+CONFIG_CRYPTO_RMD128=y
+CONFIG_CRYPTO_RMD160=y
+CONFIG_CRYPTO_RMD256=y
+CONFIG_CRYPTO_RMD320=y
+CONFIG_CRYPTO_SHA1=y
+# CONFIG_CRYPTO_SHA1_SSSE3 is not set
+CONFIG_CRYPTO_SHA256_SSSE3=y
+CONFIG_CRYPTO_SHA512_SSSE3=y
+# CONFIG_CRYPTO_SHA1_MB is not set
+CONFIG_CRYPTO_SHA256_MB=y
+CONFIG_CRYPTO_SHA512_MB=y
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_SHA512=y
+CONFIG_CRYPTO_SHA3=y
+CONFIG_CRYPTO_TGR192=y
+CONFIG_CRYPTO_WP512=y
+# CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL is not set
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=y
+# CONFIG_CRYPTO_AES_TI is not set
+CONFIG_CRYPTO_AES_X86_64=y
+CONFIG_CRYPTO_AES_NI_INTEL=y
+CONFIG_CRYPTO_ANUBIS=y
+CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_BLOWFISH=y
+CONFIG_CRYPTO_BLOWFISH_COMMON=y
+CONFIG_CRYPTO_BLOWFISH_X86_64=y
+CONFIG_CRYPTO_CAMELLIA=y
+CONFIG_CRYPTO_CAMELLIA_X86_64=y
+CONFIG_CRYPTO_CAMELLIA_AESNI_AVX_X86_64=y
+CONFIG_CRYPTO_CAMELLIA_AESNI_AVX2_X86_64=y
+CONFIG_CRYPTO_CAST_COMMON=y
+CONFIG_CRYPTO_CAST5=y
+CONFIG_CRYPTO_CAST5_AVX_X86_64=y
+CONFIG_CRYPTO_CAST6=y
+CONFIG_CRYPTO_CAST6_AVX_X86_64=y
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_DES3_EDE_X86_64 is not set
+CONFIG_CRYPTO_FCRYPT=y
+CONFIG_CRYPTO_KHAZAD=y
+CONFIG_CRYPTO_SALSA20=y
+CONFIG_CRYPTO_SALSA20_X86_64=y
+CONFIG_CRYPTO_CHACHA20=y
+CONFIG_CRYPTO_CHACHA20_X86_64=y
+CONFIG_CRYPTO_SEED=y
+CONFIG_CRYPTO_SERPENT=y
+CONFIG_CRYPTO_SERPENT_SSE2_X86_64=y
+CONFIG_CRYPTO_SERPENT_AVX_X86_64=y
+CONFIG_CRYPTO_SERPENT_AVX2_X86_64=y
+CONFIG_CRYPTO_TEA=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_TWOFISH_COMMON=y
+CONFIG_CRYPTO_TWOFISH_X86_64=y
+CONFIG_CRYPTO_TWOFISH_X86_64_3WAY=y
+CONFIG_CRYPTO_TWOFISH_AVX_X86_64=y
+
+#
+# Compression
+#
+CONFIG_CRYPTO_DEFLATE=y
+CONFIG_CRYPTO_LZO=y
+CONFIG_CRYPTO_842=y
+CONFIG_CRYPTO_LZ4=y
+CONFIG_CRYPTO_LZ4HC=y
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_DRBG_MENU=y
+CONFIG_CRYPTO_DRBG_HMAC=y
+CONFIG_CRYPTO_DRBG_HASH=y
+CONFIG_CRYPTO_DRBG_CTR=y
+CONFIG_CRYPTO_DRBG=y
+CONFIG_CRYPTO_JITTERENTROPY=y
+CONFIG_CRYPTO_USER_API=y
+CONFIG_CRYPTO_USER_API_HASH=y
+CONFIG_CRYPTO_USER_API_SKCIPHER=y
+# CONFIG_CRYPTO_USER_API_RNG is not set
+CONFIG_CRYPTO_USER_API_AEAD=y
+# CONFIG_CRYPTO_HW is not set
+
+#
+# Certificates for signature checking
+#
+CONFIG_HAVE_KVM=y
+CONFIG_VIRTUALIZATION=y
+# CONFIG_KVM is not set
+# CONFIG_VHOST_NET is not set
+# CONFIG_VHOST_CROSS_ENDIAN_LEGACY is not set
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_HAVE_ARCH_BITREVERSE is not set
+CONFIG_RATIONAL=y
+CONFIG_GENERIC_STRNCPY_FROM_USER=y
+CONFIG_GENERIC_STRNLEN_USER=y
+CONFIG_GENERIC_NET_UTILS=y
+CONFIG_GENERIC_FIND_FIRST_BIT=y
+CONFIG_GENERIC_PCI_IOMAP=y
+CONFIG_GENERIC_IOMAP=y
+CONFIG_GENERIC_IO=y
+CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
+CONFIG_ARCH_HAS_FAST_MULTIPLIER=y
+CONFIG_CRC_CCITT=y
+CONFIG_CRC16=y
+# CONFIG_CRC_T10DIF is not set
+CONFIG_CRC_ITU_T=y
+CONFIG_CRC32=y
+# CONFIG_CRC32_SELFTEST is not set
+CONFIG_CRC32_SLICEBY8=y
+# CONFIG_CRC32_SLICEBY4 is not set
+# CONFIG_CRC32_SARWATE is not set
+# CONFIG_CRC32_BIT is not set
+CONFIG_CRC7=y
+CONFIG_LIBCRC32C=y
+# CONFIG_CRC8 is not set
+# CONFIG_AUDIT_ARCH_COMPAT_GENERIC is not set
+# CONFIG_RANDOM32_SELFTEST is not set
+CONFIG_842_COMPRESS=y
+CONFIG_842_DECOMPRESS=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_LZ4_COMPRESS=y
+CONFIG_LZ4HC_COMPRESS=y
+CONFIG_LZ4_DECOMPRESS=y
+# CONFIG_XZ_DEC is not set
+# CONFIG_XZ_DEC_BCJ is not set
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=y
+CONFIG_TEXTSEARCH_BM=y
+CONFIG_TEXTSEARCH_FSM=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT_MAP=y
+CONFIG_HAS_DMA=y
+# CONFIG_DMA_NOOP_OPS is not set
+# CONFIG_DMA_VIRT_OPS is not set
+CONFIG_DQL=y
+CONFIG_NLATTR=y
+CONFIG_CLZ_TAB=y
+# CONFIG_CORDIC is not set
+# CONFIG_DDR is not set
+# CONFIG_IRQ_POLL is not set
+CONFIG_MPILIB=y
+# CONFIG_SG_SPLIT is not set
+# CONFIG_SG_POOL is not set
+CONFIG_ARCH_HAS_SG_CHAIN=y
+CONFIG_ARCH_HAS_PMEM_API=y
+CONFIG_ARCH_HAS_MMIO_FLUSH=y
+CONFIG_SBITMAP=y
diff --git a/testing/hosts/default/etc/ip6tables.rules b/testing/hosts/default/etc/ip6tables.rules
index 6a2c6af..bcb8684 100644
--- a/testing/hosts/default/etc/ip6tables.rules
+++ b/testing/hosts/default/etc/ip6tables.rules
@@ -28,7 +28,7 @@
 -A INPUT  -p icmpv6 --icmpv6-type neighbor-advertisement -j ACCEPT
 -A OUTPUT -p icmpv6 --icmpv6-type neighbor-advertisement -j ACCEPT
 
-# allow crl and certficate fetch from winnetou
+# allow crl and certificate fetch from winnetou
 -A INPUT  -i eth0 -p tcp --sport 80 -s fec0::15 -j ACCEPT
 -A OUTPUT -o eth0 -p tcp --dport 80 -d fec0::15 -j ACCEPT
 
diff --git a/testing/hosts/default/etc/strongswan.conf.testing b/testing/hosts/default/etc/strongswan.conf.testing
index 55efbe7..b623550 100644
--- a/testing/hosts/default/etc/strongswan.conf.testing
+++ b/testing/hosts/default/etc/strongswan.conf.testing
@@ -2,6 +2,11 @@ charon {
   retransmit_tries = 2
   retransmit_timeout = 1.0
   retransmit_base = 1
+  plugins {
+    kernel-netlink {
+      xfrm_acq_expires = 60
+    }
+  }
 }
 
-include strongswan.conf
\ No newline at end of file
+include strongswan.conf
diff --git a/testing/hosts/default/usr/local/bin/service b/testing/hosts/default/usr/local/bin/service
new file mode 100755
index 0000000..c5db4f6
--- /dev/null
+++ b/testing/hosts/default/usr/local/bin/service
@@ -0,0 +1,22 @@
+#!/bin/bash
+#
+# LEAK_DETECTIVE_LOG is set for automated runs, however, `service` strips
+# the environment. This wrapper is used to set the variable for the charon
+# init script.
+
+ORIG=/usr/sbin/service
+CONF=/etc/default/charon
+
+if [[ "$1" != "charon" ]]; then
+	$ORIG "$@"
+fi
+
+if [[ "$2" == "start" && -n $LEAK_DETECTIVE_LOG ]]; then
+	echo "export LEAK_DETECTIVE_LOG=$LEAK_DETECTIVE_LOG" >> $CONF
+fi
+
+$ORIG "$@"
+
+if [[ "$2" == "stop" ]]; then
+	sed -i '/LEAK_DETECTIVE_LOG/d' $CONF 2>/dev/null
+fi
diff --git a/testing/scripts/recipes/013_strongswan.mk b/testing/scripts/recipes/013_strongswan.mk
index 5c4fdd8..a5b2d80 100644
--- a/testing/scripts/recipes/013_strongswan.mk
+++ b/testing/scripts/recipes/013_strongswan.mk
@@ -28,6 +28,7 @@ CONFIG_OPTS = \
 	--enable-eap-aka-3gpp2 \
 	--enable-eap-sim \
 	--enable-eap-sim-file \
+	--enable-eap-simaka-sql \
 	--enable-eap-md5 \
 	--enable-md4 \
 	--enable-eap-mschapv2 \
diff --git a/testing/testing.conf b/testing/testing.conf
index 1a30977..eeb69ea 100644
--- a/testing/testing.conf
+++ b/testing/testing.conf
@@ -24,14 +24,14 @@ fi
 : ${TESTDIR=/srv/strongswan-testing}
 
 # Kernel configuration
-: ${KERNELVERSION=4.10.6}
+: ${KERNELVERSION=4.10.17}
 : ${KERNEL=linux-$KERNELVERSION}
 : ${KERNELTARBALL=$KERNEL.tar.xz}
 : ${KERNELCONFIG=$DIR/../config/kernel/config-4.10}
 : ${KERNELPATCH=ha-4.4-abicompat.patch.bz2}
 
 # strongSwan version used in tests
-: ${SWANVERSION=5.5.2}
+: ${SWANVERSION=5.5.3}
 
 # Build directory where the guest kernel and images will be built
 : ${BUILDDIR=$TESTDIR/build}
diff --git a/testing/tests/ikev2/rw-eap-aka-sql-rsa/description.txt b/testing/tests/ikev2/rw-eap-aka-sql-rsa/description.txt
new file mode 100644
index 0000000..a7410c1
--- /dev/null
+++ b/testing/tests/ikev2/rw-eap-aka-sql-rsa/description.txt
@@ -0,0 +1,9 @@
+At the outset the gateway authenticates itself to the client by sending an
+IKEv2 <b>RSA signature</b> accompanied by a certificate.
+The roadwarrior <b>carol</b> sets up a connection to gateway <b>moon</b>.
+<b>carol</b> uses the <i>Extensible Authentication Protocol</i>
+in association with the <i>Authentication and Key Agreement</i> protocol
+(<b>EAP-AKA</b>) to authenticate against the gateway. In this scenario,
+quintuplets from the SQL database /etc/ipsec.d/ipsec.db are used instead
+of a physical USIM card on the client <b>carol</b>. The USIM provider on
+gateway <b>moon</b> also stores the quintuplets in an SQL database.
diff --git a/testing/tests/ikev2/rw-eap-aka-sql-rsa/evaltest.dat b/testing/tests/ikev2/rw-eap-aka-sql-rsa/evaltest.dat
new file mode 100644
index 0000000..b31a468
--- /dev/null
+++ b/testing/tests/ikev2/rw-eap-aka-sql-rsa/evaltest.dat
@@ -0,0 +1,14 @@
+carol::cat /var/log/daemon.log::authentication of 'moon.strongswan.org' with RSA.* successful::YES
+carol::cat /var/log/daemon.log::server requested EAP_AKA authentication::YES
+carol::cat /var/log/daemon.log::authentication of 'moon.strongswan.org' with EAP successful::YES
+moon:: cat /var/log/daemon.log::EAP method EAP_AKA succeeded, MSK established
+moon:: cat /var/log/daemon.log::authentication of 'carol at strongswan.org' with EAP successful::YES
+moon:: ipsec status 2> /dev/null::rw-eap.*ESTABLISHED.*moon.strongswan.org.*carol at strongswan.org::YES
+carol::ipsec status 2> /dev/null::home.*ESTABLISHED.*carol at strongswan.org.*moon.strongswan.org::YES
+moon:: ipsec status 2> /dev/null::rw-eap.*INSTALLED, TUNNEL::YES
+carol::ipsec status 2> /dev/null::home.*INSTALLED, TUNNEL::YES
+carol::ping -c 1 PH_IP_ALICE::64 bytes from PH_IP_ALICE: icmp_.eq=1::YES
+moon::tcpdump::IP carol.strongswan.org > moon.strongswan.org: ESP::YES
+moon::tcpdump::IP moon.strongswan.org > carol.strongswan.org: ESP::YES
+
+
diff --git a/testing/tests/ikev2/rw-eap-aka-sql-rsa/hosts/carol/etc/ipsec.conf b/testing/tests/ikev2/rw-eap-aka-sql-rsa/hosts/carol/etc/ipsec.conf
new file mode 100644
index 0000000..ade0c7c
--- /dev/null
+++ b/testing/tests/ikev2/rw-eap-aka-sql-rsa/hosts/carol/etc/ipsec.conf
@@ -0,0 +1,21 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+config setup
+
+conn %default
+	ikelifetime=60m
+	keylife=20m
+	rekeymargin=3m
+	keyingtries=1
+	keyexchange=ikev2
+
+conn home
+	left=PH_IP_CAROL
+	leftid=carol at strongswan.org
+	leftfirewall=yes
+	leftauth=eap
+	right=PH_IP_MOON
+	rightid=@moon.strongswan.org
+	rightsubnet=10.1.0.0/16
+	rightauth=pubkey
+	auto=add
diff --git a/testing/tests/ikev2/rw-eap-aka-sql-rsa/hosts/carol/etc/ipsec.d/data.sql b/testing/tests/ikev2/rw-eap-aka-sql-rsa/hosts/carol/etc/ipsec.d/data.sql
new file mode 100644
index 0000000..038c454
--- /dev/null
+++ b/testing/tests/ikev2/rw-eap-aka-sql-rsa/hosts/carol/etc/ipsec.d/data.sql
@@ -0,0 +1,9 @@
+INSERT INTO quintuplets
+  (id, used, rand, autn, ck, ik, res) VALUES
+  ('carol at strongswan.org', 0,
+     X'00112233445566778899AABBCCDDEEFF',
+     X'112233445566778899AABBCCDDEEFF00',
+     X'2233445566778899AABBCCDDEEFF0011',
+     X'33445566778899AABBCCDDEEFF001122',
+     X'00112233445566778899'
+  );
diff --git a/testing/tests/ikev2/rw-eap-aka-sql-rsa/hosts/carol/etc/ipsec.d/tables.sql b/testing/tests/ikev2/rw-eap-aka-sql-rsa/hosts/carol/etc/ipsec.d/tables.sql
new file mode 100644
index 0000000..301f2bf
--- /dev/null
+++ b/testing/tests/ikev2/rw-eap-aka-sql-rsa/hosts/carol/etc/ipsec.d/tables.sql
@@ -0,0 +1,10 @@
+DROP TABLE IF EXISTS quintuplets;
+CREATE TABLE quintuplets (
+    id TEXT NOT NULL,
+    used INTEGER NOT NULL,
+    rand BLOB NOT NULL,
+    autn BLOB NOT NULL,
+    ck BLOB NOT NULL,
+    ik BLOB NOT NULL,
+    res BLOB NOT NULL
+);
diff --git a/testing/tests/ikev2/rw-eap-aka-sql-rsa/hosts/carol/etc/ipsec.secrets b/testing/tests/ikev2/rw-eap-aka-sql-rsa/hosts/carol/etc/ipsec.secrets
new file mode 100644
index 0000000..ddd4956
--- /dev/null
+++ b/testing/tests/ikev2/rw-eap-aka-sql-rsa/hosts/carol/etc/ipsec.secrets
@@ -0,0 +1 @@
+# /etc/ipsec.secrets - strongSwan IPsec secrets file
diff --git a/testing/tests/ikev2/rw-eap-aka-sql-rsa/hosts/carol/etc/strongswan.conf b/testing/tests/ikev2/rw-eap-aka-sql-rsa/hosts/carol/etc/strongswan.conf
new file mode 100644
index 0000000..81d2c8e
--- /dev/null
+++ b/testing/tests/ikev2/rw-eap-aka-sql-rsa/hosts/carol/etc/strongswan.conf
@@ -0,0 +1,11 @@
+# /etc/strongswan.conf - strongSwan configuration file
+
+charon {
+  load = random nonce aes sha1 sha2 pem pkcs1 curve25519 gmp x509 curl revocation hmac stroke kernel-netlink socket-default sqlite fips-prf eap-aka eap-simaka-sql updown
+
+  plugins {
+    eap-simaka-sql {
+      database = sqlite:///etc/ipsec.d/ipsec.db
+    }
+  }
+}
diff --git a/testing/tests/ikev2/rw-eap-aka-sql-rsa/hosts/moon/etc/ipsec.conf b/testing/tests/ikev2/rw-eap-aka-sql-rsa/hosts/moon/etc/ipsec.conf
new file mode 100644
index 0000000..0875bed
--- /dev/null
+++ b/testing/tests/ikev2/rw-eap-aka-sql-rsa/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,23 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+config setup
+
+conn %default
+	ikelifetime=60m
+	keylife=20m
+	rekeymargin=3m
+	keyingtries=1
+	keyexchange=ikev2
+
+conn rw-eap
+	left=PH_IP_MOON
+	leftsubnet=10.1.0.0/16
+	leftid=@moon.strongswan.org
+	leftcert=moonCert.pem
+	leftauth=pubkey
+	leftfirewall=yes
+	right=%any
+	rightid=*@strongswan.org
+	rightsendcert=never
+	rightauth=eap-aka
+	auto=add
diff --git a/testing/tests/ikev2/rw-eap-aka-sql-rsa/hosts/moon/etc/ipsec.d/data.sql b/testing/tests/ikev2/rw-eap-aka-sql-rsa/hosts/moon/etc/ipsec.d/data.sql
new file mode 100644
index 0000000..038c454
--- /dev/null
+++ b/testing/tests/ikev2/rw-eap-aka-sql-rsa/hosts/moon/etc/ipsec.d/data.sql
@@ -0,0 +1,9 @@
+INSERT INTO quintuplets
+  (id, used, rand, autn, ck, ik, res) VALUES
+  ('carol at strongswan.org', 0,
+     X'00112233445566778899AABBCCDDEEFF',
+     X'112233445566778899AABBCCDDEEFF00',
+     X'2233445566778899AABBCCDDEEFF0011',
+     X'33445566778899AABBCCDDEEFF001122',
+     X'00112233445566778899'
+  );
diff --git a/testing/tests/ikev2/rw-eap-aka-sql-rsa/hosts/moon/etc/ipsec.d/tables.sql b/testing/tests/ikev2/rw-eap-aka-sql-rsa/hosts/moon/etc/ipsec.d/tables.sql
new file mode 100644
index 0000000..301f2bf
--- /dev/null
+++ b/testing/tests/ikev2/rw-eap-aka-sql-rsa/hosts/moon/etc/ipsec.d/tables.sql
@@ -0,0 +1,10 @@
+DROP TABLE IF EXISTS quintuplets;
+CREATE TABLE quintuplets (
+    id TEXT NOT NULL,
+    used INTEGER NOT NULL,
+    rand BLOB NOT NULL,
+    autn BLOB NOT NULL,
+    ck BLOB NOT NULL,
+    ik BLOB NOT NULL,
+    res BLOB NOT NULL
+);
diff --git a/testing/tests/ikev2/rw-eap-aka-sql-rsa/hosts/moon/etc/strongswan.conf b/testing/tests/ikev2/rw-eap-aka-sql-rsa/hosts/moon/etc/strongswan.conf
new file mode 100644
index 0000000..81d2c8e
--- /dev/null
+++ b/testing/tests/ikev2/rw-eap-aka-sql-rsa/hosts/moon/etc/strongswan.conf
@@ -0,0 +1,11 @@
+# /etc/strongswan.conf - strongSwan configuration file
+
+charon {
+  load = random nonce aes sha1 sha2 pem pkcs1 curve25519 gmp x509 curl revocation hmac stroke kernel-netlink socket-default sqlite fips-prf eap-aka eap-simaka-sql updown
+
+  plugins {
+    eap-simaka-sql {
+      database = sqlite:///etc/ipsec.d/ipsec.db
+    }
+  }
+}
diff --git a/testing/tests/ikev2/rw-eap-aka-sql-rsa/posttest.dat b/testing/tests/ikev2/rw-eap-aka-sql-rsa/posttest.dat
new file mode 100644
index 0000000..046d4cf
--- /dev/null
+++ b/testing/tests/ikev2/rw-eap-aka-sql-rsa/posttest.dat
@@ -0,0 +1,4 @@
+moon::ipsec stop
+carol::ipsec stop
+moon::iptables-restore < /etc/iptables.flush
+carol::iptables-restore < /etc/iptables.flush
diff --git a/testing/tests/ikev2/rw-eap-aka-sql-rsa/pretest.dat b/testing/tests/ikev2/rw-eap-aka-sql-rsa/pretest.dat
new file mode 100644
index 0000000..e3d7998
--- /dev/null
+++ b/testing/tests/ikev2/rw-eap-aka-sql-rsa/pretest.dat
@@ -0,0 +1,9 @@
+moon::iptables-restore < /etc/iptables.rules
+carol::iptables-restore < /etc/iptables.rules
+carol::cd /etc/ipsec.d; cat tables.sql data.sql > ipsec.sql; cat ipsec.sql | sqlite3 ipsec.db
+moon::cd /etc/ipsec.d; cat tables.sql data.sql > ipsec.sql; cat ipsec.sql | sqlite3 ipsec.db
+moon::ipsec start
+carol::ipsec start
+moon::expect-connection rw-eap
+carol::expect-connection home
+carol::ipsec up home
diff --git a/testing/tests/ikev2/rw-eap-aka-sql-rsa/test.conf b/testing/tests/ikev2/rw-eap-aka-sql-rsa/test.conf
new file mode 100644
index 0000000..e093d43
--- /dev/null
+++ b/testing/tests/ikev2/rw-eap-aka-sql-rsa/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# guest instances used for this test
+
+# All guest instances that are required for this test
+#
+VIRTHOSTS="alice carol moon"
+
+# Corresponding block diagram
+#
+DIAGRAM="a-m-c.png"
+
+# Guest instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS="moon"
+
+# Guest instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol"
diff --git a/testing/tests/ikev2/two-certs/evaltest.dat b/testing/tests/ikev2/two-certs/evaltest.dat
index 422c76e..4160110 100644
--- a/testing/tests/ikev2/two-certs/evaltest.dat
+++ b/testing/tests/ikev2/two-certs/evaltest.dat
@@ -2,7 +2,7 @@ moon:: cat /var/log/daemon.log::using certificate.*OU=Research, CN=carol at strongs
 moon:: ipsec status 2> /dev/null::alice.*INSTALLED, TUNNEL::YES
 carol::ipsec status 2> /dev/null::alice.*ESTABLISHED.*carol at strongswan.org.*moon.strongswan.org::YES
 carol::ping -c 1 PH_IP_ALICE::64 bytes from PH_IP_ALICE: icmp_.eq=1::YES
-moon:: cat /var/log/daemon.log::signature validation failed, looking for another key::YES
+moon:: cat /var/log/daemon.log::signature validation failed, looking for another key::NO
 moon:: cat /var/log/daemon.log::using certificate.*OU=Research, SN=002, CN=carol at strongswan.org::YES
 moon:: ipsec status 2> /dev/null::venus.*INSTALLED, TUNNEL::YES
 carol::ipsec status 2> /dev/null::venus.*ESTABLISHED.*carol at strongswan.org.*moon.strongswan.org::YES
diff --git a/testing/tests/swanctl/rw-eap-aka-sql-rsa/description.txt b/testing/tests/swanctl/rw-eap-aka-sql-rsa/description.txt
new file mode 100644
index 0000000..a7410c1
--- /dev/null
+++ b/testing/tests/swanctl/rw-eap-aka-sql-rsa/description.txt
@@ -0,0 +1,9 @@
+At the outset the gateway authenticates itself to the client by sending an
+IKEv2 <b>RSA signature</b> accompanied by a certificate.
+The roadwarrior <b>carol</b> sets up a connection to gateway <b>moon</b>.
+<b>carol</b> uses the <i>Extensible Authentication Protocol</i>
+in association with the <i>Authentication and Key Agreement</i> protocol
+(<b>EAP-AKA</b>) to authenticate against the gateway. In this scenario,
+quintuplets from the SQL database /etc/ipsec.d/ipsec.db are used instead
+of a physical USIM card on the client <b>carol</b>. The USIM provider on
+gateway <b>moon</b> also stores the quintuplets in an SQL database.
diff --git a/testing/tests/swanctl/rw-eap-aka-sql-rsa/evaltest.dat b/testing/tests/swanctl/rw-eap-aka-sql-rsa/evaltest.dat
new file mode 100644
index 0000000..b529b4b
--- /dev/null
+++ b/testing/tests/swanctl/rw-eap-aka-sql-rsa/evaltest.dat
@@ -0,0 +1,10 @@
+carol::cat /var/log/daemon.log::authentication of 'moon.strongswan.org' with RSA.* successful::YES
+carol::cat /var/log/daemon.log::server requested EAP_AKA authentication::YES
+carol::cat /var/log/daemon.log::authentication of 'moon.strongswan.org' with EAP successful::YES
+moon:: cat /var/log/daemon.log::EAP method EAP_AKA succeeded, MSK established
+moon:: cat /var/log/daemon.log::authentication of 'carol at strongswan.org' with EAP successful::YES
+carol::ping -c 1 PH_IP_ALICE::64 bytes from PH_IP_ALICE: icmp_.eq=1::YES
+carol::swanctl --list-sas --raw 2> /dev/null::home.*version=2 state=ESTABLISHED local-host=192.168.0.100 local-port=4500 local-id=carol at strongswan.org remote-host=192.168.0.1 remote-port=4500 remote-id=moon.strongswan.org initiator=yes.*encr-alg=AES_CBC encr-keysize=128 integ-alg=HMAC_SHA2_256_128 prf-alg=PRF_HMAC_SHA2_256 dh-group=CURVE_25519.*child-sas.*home.*state=INSTALLED mode=TUNNEL.*ESP.*encr-alg=AES_GCM_16 encr-keysize=128.*local-ts=\[192.168.0.100/32] remote-ts=\[10.1.0.0/16]::YES
+moon:: swanctl --list-sas --ike-id 1 --raw 2> /dev/null::rw-eap.*version=2 state=ESTABLISHED local-host=192.168.0.1 local-port=4500 local-id=moon.strongswan.org remote-host=192.168.0.100 remote-port=4500 remote-id=carol at strongswan.org.*encr-alg=AES_CBC encr-keysize=128 integ-alg=HMAC_SHA2_256_128 prf-alg=PRF_HMAC_SHA2_256 dh-group=CURVE_25519.*child-sas.*net.*reqid=1 state=INSTALLED mode=TUNNEL.*ESP.*encr-alg=AES_GCM_16 encr-keysize=128.*local-ts=\[10.1.0.0/16] remote-ts=\[192.168.0.100/ [...]
+moon::tcpdump::IP carol.strongswan.org > moon.strongswan.org: ESP::YES
+moon::tcpdump::IP moon.strongswan.org > carol.strongswan.org: ESP::YES
diff --git a/testing/tests/swanctl/rw-eap-aka-sql-rsa/hosts/carol/etc/ipsec.d/data.sql b/testing/tests/swanctl/rw-eap-aka-sql-rsa/hosts/carol/etc/ipsec.d/data.sql
new file mode 100644
index 0000000..038c454
--- /dev/null
+++ b/testing/tests/swanctl/rw-eap-aka-sql-rsa/hosts/carol/etc/ipsec.d/data.sql
@@ -0,0 +1,9 @@
+INSERT INTO quintuplets
+  (id, used, rand, autn, ck, ik, res) VALUES
+  ('carol at strongswan.org', 0,
+     X'00112233445566778899AABBCCDDEEFF',
+     X'112233445566778899AABBCCDDEEFF00',
+     X'2233445566778899AABBCCDDEEFF0011',
+     X'33445566778899AABBCCDDEEFF001122',
+     X'00112233445566778899'
+  );
diff --git a/testing/tests/swanctl/rw-eap-aka-sql-rsa/hosts/carol/etc/ipsec.d/tables.sql b/testing/tests/swanctl/rw-eap-aka-sql-rsa/hosts/carol/etc/ipsec.d/tables.sql
new file mode 100644
index 0000000..301f2bf
--- /dev/null
+++ b/testing/tests/swanctl/rw-eap-aka-sql-rsa/hosts/carol/etc/ipsec.d/tables.sql
@@ -0,0 +1,10 @@
+DROP TABLE IF EXISTS quintuplets;
+CREATE TABLE quintuplets (
+    id TEXT NOT NULL,
+    used INTEGER NOT NULL,
+    rand BLOB NOT NULL,
+    autn BLOB NOT NULL,
+    ck BLOB NOT NULL,
+    ik BLOB NOT NULL,
+    res BLOB NOT NULL
+);
diff --git a/testing/tests/swanctl/rw-eap-aka-sql-rsa/hosts/carol/etc/strongswan.conf b/testing/tests/swanctl/rw-eap-aka-sql-rsa/hosts/carol/etc/strongswan.conf
new file mode 100644
index 0000000..dd99cdb
--- /dev/null
+++ b/testing/tests/swanctl/rw-eap-aka-sql-rsa/hosts/carol/etc/strongswan.conf
@@ -0,0 +1,19 @@
+# /etc/strongswan.conf - strongSwan configuration file
+
+swanctl {
+  load = pem pkcs1 x509 revocation constraints pubkey openssl random 
+}
+
+charon {
+  load = random nonce aes sha1 sha2 pem pkcs1 curve25519 gmp x509 curl revocation hmac vici kernel-netlink socket-default sqlite fips-prf eap-aka eap-simaka-sql updown
+
+  start-scripts {
+    creds = /usr/local/sbin/swanctl --load-creds 
+    conns = /usr/local/sbin/swanctl --load-conns
+  } 
+  plugins {
+    eap-simaka-sql {
+      database = sqlite:///etc/ipsec.d/ipsec.db
+    }
+  }
+}
diff --git a/testing/tests/swanctl/rw-eap-aka-sql-rsa/hosts/carol/etc/swanctl/swanctl.conf b/testing/tests/swanctl/rw-eap-aka-sql-rsa/hosts/carol/etc/swanctl/swanctl.conf
new file mode 100755
index 0000000..0466032
--- /dev/null
+++ b/testing/tests/swanctl/rw-eap-aka-sql-rsa/hosts/carol/etc/swanctl/swanctl.conf
@@ -0,0 +1,26 @@
+connections {
+
+   home {
+      local_addrs  = 192.168.0.100
+      remote_addrs = 192.168.0.1 
+
+      local {
+         auth = eap
+         id = carol at strongswan.org
+      }
+      remote {
+         auth = pubkey 
+         id = moon.strongswan.org 
+      }
+      children {
+         home {
+            remote_ts = 10.1.0.0/16 
+
+            updown = /usr/local/libexec/ipsec/_updown iptables
+            esp_proposals = aes128gcm128-x25519
+         }
+      }
+      version = 2
+      proposals = aes128-sha256-x25519
+   }
+}
diff --git a/testing/tests/swanctl/rw-eap-aka-sql-rsa/hosts/moon/etc/ipsec.d/data.sql b/testing/tests/swanctl/rw-eap-aka-sql-rsa/hosts/moon/etc/ipsec.d/data.sql
new file mode 100644
index 0000000..038c454
--- /dev/null
+++ b/testing/tests/swanctl/rw-eap-aka-sql-rsa/hosts/moon/etc/ipsec.d/data.sql
@@ -0,0 +1,9 @@
+INSERT INTO quintuplets
+  (id, used, rand, autn, ck, ik, res) VALUES
+  ('carol at strongswan.org', 0,
+     X'00112233445566778899AABBCCDDEEFF',
+     X'112233445566778899AABBCCDDEEFF00',
+     X'2233445566778899AABBCCDDEEFF0011',
+     X'33445566778899AABBCCDDEEFF001122',
+     X'00112233445566778899'
+  );
diff --git a/testing/tests/swanctl/rw-eap-aka-sql-rsa/hosts/moon/etc/ipsec.d/tables.sql b/testing/tests/swanctl/rw-eap-aka-sql-rsa/hosts/moon/etc/ipsec.d/tables.sql
new file mode 100644
index 0000000..301f2bf
--- /dev/null
+++ b/testing/tests/swanctl/rw-eap-aka-sql-rsa/hosts/moon/etc/ipsec.d/tables.sql
@@ -0,0 +1,10 @@
+DROP TABLE IF EXISTS quintuplets;
+CREATE TABLE quintuplets (
+    id TEXT NOT NULL,
+    used INTEGER NOT NULL,
+    rand BLOB NOT NULL,
+    autn BLOB NOT NULL,
+    ck BLOB NOT NULL,
+    ik BLOB NOT NULL,
+    res BLOB NOT NULL
+);
diff --git a/testing/tests/swanctl/rw-eap-aka-sql-rsa/hosts/moon/etc/strongswan.conf b/testing/tests/swanctl/rw-eap-aka-sql-rsa/hosts/moon/etc/strongswan.conf
new file mode 100644
index 0000000..dd99cdb
--- /dev/null
+++ b/testing/tests/swanctl/rw-eap-aka-sql-rsa/hosts/moon/etc/strongswan.conf
@@ -0,0 +1,19 @@
+# /etc/strongswan.conf - strongSwan configuration file
+
+swanctl {
+  load = pem pkcs1 x509 revocation constraints pubkey openssl random 
+}
+
+charon {
+  load = random nonce aes sha1 sha2 pem pkcs1 curve25519 gmp x509 curl revocation hmac vici kernel-netlink socket-default sqlite fips-prf eap-aka eap-simaka-sql updown
+
+  start-scripts {
+    creds = /usr/local/sbin/swanctl --load-creds 
+    conns = /usr/local/sbin/swanctl --load-conns
+  } 
+  plugins {
+    eap-simaka-sql {
+      database = sqlite:///etc/ipsec.d/ipsec.db
+    }
+  }
+}
diff --git a/testing/tests/swanctl/rw-eap-aka-sql-rsa/hosts/moon/etc/swanctl/swanctl.conf b/testing/tests/swanctl/rw-eap-aka-sql-rsa/hosts/moon/etc/swanctl/swanctl.conf
new file mode 100755
index 0000000..53efd8d
--- /dev/null
+++ b/testing/tests/swanctl/rw-eap-aka-sql-rsa/hosts/moon/etc/swanctl/swanctl.conf
@@ -0,0 +1,26 @@
+connections {
+
+   rw-eap {
+      local_addrs  = 192.168.0.1
+
+      local {
+         auth = pubkey 
+         certs = moonCert.pem
+         id = moon.strongswan.org
+      }
+      remote {
+         auth = eap-aka
+      }
+      children {
+         net {
+            local_ts  = 10.1.0.0/16 
+
+            updown = /usr/local/libexec/ipsec/_updown iptables
+            esp_proposals = aes128gcm128-x25519
+         }
+      }
+      version = 2
+      send_certreq = no
+      proposals = aes128-sha256-x25519
+   }
+}
diff --git a/testing/tests/swanctl/rw-eap-aka-sql-rsa/posttest.dat b/testing/tests/swanctl/rw-eap-aka-sql-rsa/posttest.dat
new file mode 100644
index 0000000..2fc2bbb
--- /dev/null
+++ b/testing/tests/swanctl/rw-eap-aka-sql-rsa/posttest.dat
@@ -0,0 +1,5 @@
+carol::swanctl --terminate --ike home
+carol::service charon stop 2> /dev/null
+moon::service charon stop 2> /dev/null
+moon::iptables-restore < /etc/iptables.flush
+carol::iptables-restore < /etc/iptables.flush
diff --git a/testing/tests/swanctl/rw-eap-aka-sql-rsa/pretest.dat b/testing/tests/swanctl/rw-eap-aka-sql-rsa/pretest.dat
new file mode 100644
index 0000000..3842250
--- /dev/null
+++ b/testing/tests/swanctl/rw-eap-aka-sql-rsa/pretest.dat
@@ -0,0 +1,10 @@
+moon::iptables-restore < /etc/iptables.rules
+carol::iptables-restore < /etc/iptables.rules
+carol::cd /etc/ipsec.d; cat tables.sql data.sql > ipsec.sql; cat ipsec.sql | sqlite3 ipsec.db
+moon::cd /etc/ipsec.d; cat tables.sql data.sql > ipsec.sql; cat ipsec.sql | sqlite3 ipsec.db
+carol::cd /etc/swanctl; rm rsa/* x509/*
+moon::service charon start 2> /dev/null
+carol::service charon start 2> /dev/null
+moon::expect-connection rw-eap
+carol::expect-connection home
+carol::swanctl --initiate --child home 2> /dev/null
diff --git a/testing/tests/swanctl/rw-eap-aka-sql-rsa/test.conf b/testing/tests/swanctl/rw-eap-aka-sql-rsa/test.conf
new file mode 100644
index 0000000..97b89cb
--- /dev/null
+++ b/testing/tests/swanctl/rw-eap-aka-sql-rsa/test.conf
@@ -0,0 +1,25 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# guest instances used for this test
+
+# All guest instances that are required for this test
+#
+VIRTHOSTS="alice carol moon"
+
+# Corresponding block diagram
+#
+DIAGRAM="a-m-c.png"
+
+# Guest instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS="moon"
+
+# Guest instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol"
+
+# charon controlled by swanctl
+#
+SWANCTL=1
diff --git a/testing/tests/swanctl/rw-eap-md5-id-rsa/description.txt b/testing/tests/swanctl/rw-eap-md5-id-rsa/description.txt
new file mode 100644
index 0000000..cf399bc
--- /dev/null
+++ b/testing/tests/swanctl/rw-eap-md5-id-rsa/description.txt
@@ -0,0 +1,9 @@
+The roadwarrior <b>carol</b> sets up a connection to gateway <b>moon</b>.
+At the outset the gateway authenticates itself to the client by sending
+an IKEv2 <b>RSA signature</b> accompanied by a certificate.
+<b>carol</b> then uses the <i>Extensible Authentication Protocol</i>
+in association with an  <i>MD5</i> challenge and response protocol
+(<b>EAP-MD5</b>) to authenticate against the gateway <b>moon</b>.
+In addition to her IKEv2 identity which defaults to her IP address,
+roadwarrior <b>carol</b> uses the EAP identity <b>carol</b>.
+
diff --git a/testing/tests/swanctl/rw-eap-md5-id-rsa/evaltest.dat b/testing/tests/swanctl/rw-eap-md5-id-rsa/evaltest.dat
new file mode 100644
index 0000000..4558813
--- /dev/null
+++ b/testing/tests/swanctl/rw-eap-md5-id-rsa/evaltest.dat
@@ -0,0 +1,11 @@
+carol::cat /var/log/daemon.log::authentication of 'moon.strongswan.org' with RSA.* successful::YES
+carol::cat /var/log/daemon.log::server requested EAP_MD5 authentication::YES
+carol::cat /var/log/daemon.log::authentication of 'moon.strongswan.org' with EAP successful::YES
+moon:: cat /var/log/daemon.log::received EAP identity.*carol
+moon:: cat /var/log/daemon.log::EAP method EAP_MD5 succeeded, no MSK established
+moon:: cat /var/log/daemon.log::authentication of '192.168.0.100' with EAP successful::YES
+carol::ping -c 1 PH_IP_ALICE::64 bytes from PH_IP_ALICE: icmp_.eq=1::YES
+carol::swanctl --list-sas --raw 2> /dev/null::home.*version=2 state=ESTABLISHED local-host=192.168.0.100 local-port=4500 local-id=192.168.0.100 remote-host=192.168.0.1 remote-port=4500 remote-id=moon.strongswan.org initiator=yes.*encr-alg=AES_CBC encr-keysize=128 integ-alg=HMAC_SHA2_256_128 prf-alg=PRF_HMAC_SHA2_256 dh-group=CURVE_25519.*child-sas.*home.*state=INSTALLED mode=TUNNEL.*ESP.*encr-alg=AES_GCM_16 encr-keysize=128.*local-ts=\[192.168.0.100/32] remote-ts=\[10.1.0.0/16]::YES
+moon:: swanctl --list-sas --ike-id 1 --raw 2> /dev/null::rw-eap.*version=2 state=ESTABLISHED local-host=192.168.0.1 local-port=4500 local-id=moon.strongswan.org remote-host=192.168.0.100 remote-port=4500 remote-id=192.168.0.100.*encr-alg=AES_CBC encr-keysize=128 integ-alg=HMAC_SHA2_256_128 prf-alg=PRF_HMAC_SHA2_256 dh-group=CURVE_25519.*child-sas.*net.*reqid=1 state=INSTALLED mode=TUNNEL.*ESP.*encr-alg=AES_GCM_16 encr-keysize=128.*local-ts=\[10.1.0.0/16] remote-ts=\[192.168.0.100/32]::YES
+moon::tcpdump::IP carol.strongswan.org > moon.strongswan.org: ESP::YES
+moon::tcpdump::IP moon.strongswan.org > carol.strongswan.org: ESP::YES
diff --git a/testing/tests/swanctl/rw-eap-md5-id-rsa/hosts/carol/etc/strongswan.conf b/testing/tests/swanctl/rw-eap-md5-id-rsa/hosts/carol/etc/strongswan.conf
new file mode 100644
index 0000000..4b8e68e
--- /dev/null
+++ b/testing/tests/swanctl/rw-eap-md5-id-rsa/hosts/carol/etc/strongswan.conf
@@ -0,0 +1,14 @@
+# /etc/strongswan.conf - strongSwan configuration file
+
+swanctl {
+  load = pem pkcs1 x509 revocation constraints pubkey openssl random 
+}
+
+charon {
+  load = random nonce aes md5 sha1 sha2 pem pkcs1 curve25519 gmp x509 curl revocation hmac vici kernel-netlink socket-default eap-identity eap-md5 updown
+
+  start-scripts {
+    creds = /usr/local/sbin/swanctl --load-creds 
+    conns = /usr/local/sbin/swanctl --load-conns
+  } 
+}
diff --git a/testing/tests/swanctl/rw-eap-md5-id-rsa/hosts/carol/etc/swanctl/swanctl.conf b/testing/tests/swanctl/rw-eap-md5-id-rsa/hosts/carol/etc/swanctl/swanctl.conf
new file mode 100755
index 0000000..1b5c5d9
--- /dev/null
+++ b/testing/tests/swanctl/rw-eap-md5-id-rsa/hosts/carol/etc/swanctl/swanctl.conf
@@ -0,0 +1,34 @@
+connections {
+
+   home {
+      local_addrs  = 192.168.0.100
+      remote_addrs = 192.168.0.1 
+
+      local {
+         auth = eap
+         eap_id = carol
+      }
+      remote {
+         auth = pubkey 
+         id = moon.strongswan.org 
+      }
+      children {
+         home {
+            remote_ts = 10.1.0.0/16 
+
+            updown = /usr/local/libexec/ipsec/_updown iptables
+            esp_proposals = aes128gcm128-x25519
+         }
+      }
+      version = 2
+      proposals = aes128-sha256-x25519
+   }
+}
+
+secrets {
+
+   eap-carol {
+      id = carol
+      secret = Ar3etTnp
+   }
+}
diff --git a/testing/tests/swanctl/rw-eap-md5-id-rsa/hosts/moon/etc/strongswan.conf b/testing/tests/swanctl/rw-eap-md5-id-rsa/hosts/moon/etc/strongswan.conf
new file mode 100644
index 0000000..4b8e68e
--- /dev/null
+++ b/testing/tests/swanctl/rw-eap-md5-id-rsa/hosts/moon/etc/strongswan.conf
@@ -0,0 +1,14 @@
+# /etc/strongswan.conf - strongSwan configuration file
+
+swanctl {
+  load = pem pkcs1 x509 revocation constraints pubkey openssl random 
+}
+
+charon {
+  load = random nonce aes md5 sha1 sha2 pem pkcs1 curve25519 gmp x509 curl revocation hmac vici kernel-netlink socket-default eap-identity eap-md5 updown
+
+  start-scripts {
+    creds = /usr/local/sbin/swanctl --load-creds 
+    conns = /usr/local/sbin/swanctl --load-conns
+  } 
+}
diff --git a/testing/tests/swanctl/rw-eap-md5-id-rsa/hosts/moon/etc/swanctl/swanctl.conf b/testing/tests/swanctl/rw-eap-md5-id-rsa/hosts/moon/etc/swanctl/swanctl.conf
new file mode 100755
index 0000000..827b43b
--- /dev/null
+++ b/testing/tests/swanctl/rw-eap-md5-id-rsa/hosts/moon/etc/swanctl/swanctl.conf
@@ -0,0 +1,40 @@
+connections {
+
+   rw-eap {
+      local_addrs  = 192.168.0.1
+
+      local {
+         auth = pubkey 
+         certs = moonCert.pem
+         id = moon.strongswan.org
+      }
+      remote {
+         auth = eap-md5
+         eap_id = %any
+      }
+      children {
+         net {
+            local_ts  = 10.1.0.0/16 
+
+            updown = /usr/local/libexec/ipsec/_updown iptables
+            esp_proposals = aes128gcm128-x25519
+         }
+      }
+      version = 2
+      send_certreq = no
+      proposals = aes128-sha256-x25519
+   }
+}
+
+secrets {
+
+   eap-carol {
+      id = carol
+      secret = Ar3etTnp
+   }
+   eap-dave {
+      id = dave
+      secret = W7R0g3do
+   }
+}
+
diff --git a/testing/tests/swanctl/rw-eap-md5-id-rsa/posttest.dat b/testing/tests/swanctl/rw-eap-md5-id-rsa/posttest.dat
new file mode 100644
index 0000000..2fc2bbb
--- /dev/null
+++ b/testing/tests/swanctl/rw-eap-md5-id-rsa/posttest.dat
@@ -0,0 +1,5 @@
+carol::swanctl --terminate --ike home
+carol::service charon stop 2> /dev/null
+moon::service charon stop 2> /dev/null
+moon::iptables-restore < /etc/iptables.flush
+carol::iptables-restore < /etc/iptables.flush
diff --git a/testing/tests/swanctl/rw-eap-md5-id-rsa/pretest.dat b/testing/tests/swanctl/rw-eap-md5-id-rsa/pretest.dat
new file mode 100644
index 0000000..96c1ed1
--- /dev/null
+++ b/testing/tests/swanctl/rw-eap-md5-id-rsa/pretest.dat
@@ -0,0 +1,8 @@
+moon::iptables-restore < /etc/iptables.rules
+carol::iptables-restore < /etc/iptables.rules
+carol::cd /etc/swanctl; rm rsa/* x509/*
+moon::service charon start 2> /dev/null
+carol::service charon start 2> /dev/null
+moon::expect-connection rw-eap
+carol::expect-connection home
+carol::swanctl --initiate --child home 2> /dev/null
diff --git a/testing/tests/swanctl/rw-eap-md5-id-rsa/test.conf b/testing/tests/swanctl/rw-eap-md5-id-rsa/test.conf
new file mode 100644
index 0000000..97b89cb
--- /dev/null
+++ b/testing/tests/swanctl/rw-eap-md5-id-rsa/test.conf
@@ -0,0 +1,25 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# guest instances used for this test
+
+# All guest instances that are required for this test
+#
+VIRTHOSTS="alice carol moon"
+
+# Corresponding block diagram
+#
+DIAGRAM="a-m-c.png"
+
+# Guest instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS="moon"
+
+# Guest instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol"
+
+# charon controlled by swanctl
+#
+SWANCTL=1

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-swan/strongswan.git



More information about the Pkg-swan-devel mailing list