[Pkg-swan-devel] [strongswan] 02/10: Imported Upstream version 5.3.3

Yves-Alexis Perez corsac at moszumanska.debian.org
Wed Nov 4 19:42:36 UTC 2015


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

corsac pushed a commit to annotated tag v5.3.3-1
in repository strongswan.

commit 27902f634ea544c1f077b19a26ca8c81b67059f3
Author: Yves-Alexis Perez <corsac at debian.org>
Date:   Thu Oct 22 11:43:58 2015 +0200

    Imported Upstream version 5.3.3
---
 Android.common.mk                                  |    2 +-
 NEWS                                               |   46 +
 conf/Makefile.am                                   |    2 +
 conf/Makefile.in                                   |    2 +
 conf/options/charon.conf                           |    4 +-
 conf/options/charon.opt                            |    4 +-
 conf/options/imcv.conf                             |    3 +
 conf/options/imcv.opt                              |    3 +
 conf/options/starter.conf                          |    3 -
 conf/options/starter.opt                           |    3 -
 conf/plugins/eap-radius.conf                       |    6 +-
 conf/plugins/eap-radius.opt                        |    6 +-
 conf/plugins/imc-hcd.conf                          |    8 +
 conf/plugins/imc-hcd.opt                           |   71 +
 conf/plugins/kernel-netlink.conf                   |    2 +-
 conf/plugins/kernel-netlink.opt                    |    2 +-
 conf/plugins/osx-attr.conf                         |   12 +
 conf/plugins/osx-attr.opt                          |    3 +
 conf/plugins/stroke.conf                           |    5 +
 conf/plugins/stroke.opt                            |    5 +
 conf/strongswan.conf.5.main                        |  133 +-
 config.h.in                                        |    6 +
 configure                                          |  190 +-
 configure.ac                                       |   42 +-
 man/ipsec.conf.5.in                                |   64 +-
 src/_updown/_updown.in                             |   10 +-
 src/charon-cmd/cmd/cmd_connection.c                |    2 +-
 src/charon-tkm/src/tkm/tkm_encoder.c~              |  106 -
 src/charon-tkm/tests/tests.c                       |    4 +-
 src/conftest/actions.c                             |    2 +-
 src/include/Makefile.am                            |    3 +-
 src/include/Makefile.in                            |    3 +-
 src/include/linux/netlink.h                        |  212 +-
 src/include/linux/rtnetlink.h                      |  707 ++----
 src/include/linux/types.h                          |  172 --
 src/ipsec/_ipsec.8                                 |    2 +-
 src/libcharon/config/ike_cfg.c                     |   47 +
 src/libcharon/config/ike_cfg.h                     |   17 +-
 src/libcharon/control/controller.c                 |   54 +-
 src/libcharon/control/controller.h                 |    5 +-
 src/libcharon/daemon.c                             |    4 +
 src/libcharon/encoding/payloads/fragment_payload.c |    2 +-
 .../encoding/payloads/proposal_substructure.c      |   11 +
 src/libcharon/network/receiver.c                   |   16 +-
 src/libcharon/plugins/eap_radius/eap_radius.c      |   13 +-
 .../plugins/eap_radius/eap_radius_accounting.c     |   28 +-
 src/libcharon/plugins/eap_tnc/eap_tnc.c            |    4 +
 src/libcharon/plugins/eap_ttls/eap_ttls_peer.c     |    9 +-
 .../plugins/error_notify/error_notify_listener.c   |    8 +-
 src/libcharon/plugins/ha/ha_ctl.c                  |   85 +-
 src/libcharon/plugins/ha/ha_dispatcher.c           |   12 +-
 src/libcharon/plugins/ha/ha_ike.c                  |    1 +
 src/libcharon/plugins/ha/ha_kernel.c               |   21 +-
 src/libcharon/plugins/load_tester/load_tester.c    |    1 +
 .../plugins/load_tester/load_tester_control.c      |    2 +-
 .../plugins/load_tester/load_tester_plugin.c       |    2 +-
 src/libcharon/plugins/medcli/medcli_config.c       |    2 +-
 src/libcharon/plugins/osx_attr/osx_attr_handler.c  |   30 +-
 src/libcharon/plugins/smp/smp.c                    |    2 +-
 src/libcharon/plugins/sql/sql_config.c             |   11 +-
 src/libcharon/plugins/sql/sql_logger.c             |    1 +
 src/libcharon/plugins/stroke/stroke_ca.c           |  238 +-
 src/libcharon/plugins/stroke/stroke_ca.h           |   30 +-
 src/libcharon/plugins/stroke/stroke_config.c       |   83 +-
 src/libcharon/plugins/stroke/stroke_control.c      |    4 +-
 src/libcharon/plugins/stroke/stroke_cred.c         |  257 +--
 src/libcharon/plugins/stroke/stroke_cred.h         |   15 +-
 src/libcharon/plugins/stroke/stroke_list.c         |    2 +-
 src/libcharon/plugins/stroke/stroke_socket.c       |    4 +-
 .../tnc_ifmap/tnc_ifmap_renew_session_job.h        |    2 +-
 src/libcharon/plugins/uci/uci_control.c            |    2 +-
 src/libcharon/plugins/updown/updown_listener.c     |   18 +-
 src/libcharon/plugins/vici/Makefile.am             |    1 +
 src/libcharon/plugins/vici/Makefile.in             |    4 +-
 src/libcharon/plugins/vici/README.md               |  124 ++
 src/libcharon/plugins/vici/python/LICENSE          |    2 +
 .../plugins/vici/python/vici/exception.py          |    3 +
 src/libcharon/plugins/vici/python/vici/session.py  |  138 +-
 src/libcharon/plugins/vici/ruby/lib/vici.rb        |    6 +-
 src/libcharon/plugins/vici/suites/test_message.c   |   31 +
 src/libcharon/plugins/vici/vici_authority.c        |  750 +++++++
 src/libcharon/plugins/vici/vici_authority.h        |   62 +
 src/libcharon/plugins/vici/vici_config.c           |   67 +-
 src/libcharon/plugins/vici/vici_config.h           |    8 +-
 src/libcharon/plugins/vici/vici_control.c          |   11 +-
 src/libcharon/plugins/vici/vici_cred.c             |    7 +
 src/libcharon/plugins/vici/vici_cred.h             |    8 +
 src/libcharon/plugins/vici/vici_logger.c           |   48 +-
 src/libcharon/plugins/vici/vici_message.c          |   40 +
 src/libcharon/plugins/vici/vici_message.h          |   25 +-
 src/libcharon/plugins/vici/vici_plugin.c           |   16 +-
 src/libcharon/plugins/vici/vici_query.c            |   87 +-
 .../plugins/whitelist/whitelist_listener.c         |    2 +-
 .../processing/jobs/initiate_mediation_job.c       |    4 +-
 .../processing/jobs/process_message_job.c          |   14 +-
 src/libcharon/processing/jobs/rekey_child_sa_job.c |    5 +-
 src/libcharon/processing/jobs/start_action_job.c   |    2 +-
 src/libcharon/sa/child_sa.c                        |   15 +-
 src/libcharon/sa/eap/eap_method.c                  |    3 +-
 src/libcharon/sa/ike_sa.c                          |   43 +-
 src/libcharon/sa/ike_sa_id.c                       |    4 +-
 src/libcharon/sa/ike_sa_manager.c                  |   67 +-
 src/libcharon/sa/ike_sa_manager.h                  |    9 +-
 src/libcharon/sa/ikev1/phase1.c                    |    2 +-
 src/libcharon/sa/ikev1/task_manager_v1.c           |   35 +-
 src/libcharon/sa/ikev1/tasks/quick_mode.c          |   26 +-
 src/libcharon/sa/ikev1/tasks/quick_mode.h          |   11 +
 .../sa/ikev2/authenticators/eap_authenticator.c    |    9 +
 .../sa/ikev2/authenticators/pubkey_authenticator.c |    2 +-
 src/libcharon/sa/ikev2/keymat_v2.c                 |    2 +
 src/libcharon/sa/ikev2/tasks/child_create.c        |   36 +-
 src/libcharon/sa/ikev2/tasks/child_rekey.c         |   18 +-
 src/libcharon/sa/ikev2/tasks/ike_rekey.c           |   34 +-
 src/libcharon/sa/shunt_manager.c                   |   71 +-
 src/libcharon/sa/shunt_manager.h                   |    6 +
 src/libcharon/sa/trap_manager.c                    |  276 ++-
 src/libcharon/tests/Makefile.am                    |    4 +
 src/libcharon/tests/Makefile.in                    |   40 +
 src/libcharon/tests/libcharon_tests.c              |   18 +-
 src/libcharon/tests/libcharon_tests.h              |    2 +
 src/libcharon/tests/suites/test_ike_cfg.c          |  118 +
 src/libcharon/tests/suites/test_message_chapoly.c  |  138 ++
 .../plugins/kernel_netlink/kernel_netlink_ipsec.c  |   53 +-
 .../plugins/kernel_netlink/kernel_netlink_net.c    |   40 +-
 .../plugins/kernel_netlink/kernel_netlink_shared.c |   16 +-
 .../plugins/kernel_pfkey/kernel_pfkey_ipsec.c      |  118 +-
 .../plugins/kernel_pfroute/kernel_pfroute_net.c    |   17 +
 src/libhydra/tests/hydra_tests.c                   |    4 +-
 src/libimcv/Android.mk                             |    7 +-
 src/libimcv/Makefile.am                            |   15 +-
 src/libimcv/Makefile.in                            |   74 +-
 .../generic_attr_bool.c}                           |   80 +-
 src/libimcv/generic/generic_attr_bool.h            |   67 +
 .../generic_attr_chunk.c}                          |   65 +-
 src/libimcv/generic/generic_attr_chunk.h           |   60 +
 .../generic_attr_string.c}                         |   66 +-
 .../generic_attr_string.h}                         |   35 +-
 src/libimcv/ietf/ietf_attr.c                       |   13 +-
 src/libimcv/ietf/ietf_attr_default_pwd_enabled.h   |   65 -
 src/libimcv/ietf/ietf_attr_fwd_enabled.c           |   11 +-
 src/libimcv/ietf/ietf_attr_fwd_enabled.h           |    9 +-
 src/libimcv/ietf/ietf_attr_port_filter.c           |   10 +-
 src/libimcv/ietf/ietf_attr_port_filter.h           |    8 +-
 src/libimcv/imc/imc_msg.c                          |   30 +-
 src/libimcv/imc/imc_os_info.c                      |   11 +-
 src/libimcv/imc/imc_os_info.h                      |    9 +-
 src/libimcv/imcv.c                                 |    7 +-
 src/libimcv/imcv.h                                 |    3 +
 src/libimcv/imv/imv_msg.c                          |   28 +-
 src/libimcv/ita/ita_attr.c                         |    5 +-
 src/libimcv/pa_tnc/pa_tnc_msg.c                    |   10 +-
 src/libimcv/pa_tnc/pa_tnc_msg.h                    |    9 +-
 src/libimcv/plugins/imc_hcd/Makefile.am            |   16 +
 .../plugins/imc_hcd}/Makefile.in                   |  311 +--
 src/libimcv/plugins/imc_hcd/imc_hcd.c              |  791 +++++++
 src/libimcv/plugins/imc_hcd/imc_hcd_state.c        |  176 ++
 src/libimcv/plugins/imc_hcd/imc_hcd_state.h        |   50 +
 src/libimcv/plugins/imc_os/imc_os.c                |   24 +-
 src/libimcv/plugins/imc_scanner/imc_scanner.c      |    7 +-
 src/libimcv/plugins/imc_swid/imc_swid.c            |    6 +-
 .../imv_attestation/imv_attestation_agent.c        |    8 +-
 src/libimcv/plugins/imv_hcd/Makefile.am            |   18 +
 .../plugins/imv_hcd}/Makefile.in                   |  315 +--
 .../plugins/imv_hcd/imv_hcd.c}                     |   14 +-
 src/libimcv/plugins/imv_hcd/imv_hcd_agent.c        |  680 ++++++
 .../plugins/imv_hcd/imv_hcd_agent.h}               |   33 +-
 src/libimcv/plugins/imv_hcd/imv_hcd_state.c        |  350 +++
 src/libimcv/plugins/imv_hcd/imv_hcd_state.h        |  120 ++
 src/libimcv/plugins/imv_os/imv_os_agent.c          |   19 +-
 src/libimcv/plugins/imv_os/pacman.c                |   21 +-
 .../plugins/imv_scanner/imv_scanner_agent.c        |    4 +-
 src/libimcv/plugins/imv_swid/imv_swid_agent.c      |    6 +-
 src/libimcv/pwg/pwg_attr.c                         |  123 ++
 src/libimcv/pwg/pwg_attr.h                         |   75 +
 .../pwg_attr_vendor_smi_code.c}                    |   91 +-
 .../pwg_attr_vendor_smi_code.h}                    |   37 +-
 src/libimcv/seg/seg_contract.c                     |    6 +-
 src/libimcv/seg/seg_contract.h                     |    6 +-
 src/libimcv/seg/seg_env.c                          |   15 +-
 src/libimcv/seg/seg_env.h                          |    5 +-
 src/libimcv/suites/test_imcv_seg.c                 |   15 +-
 src/libipsec/Makefile.am                           |    9 +-
 src/libipsec/Makefile.in                           |    8 +-
 src/libipsec/esp_context.c                         |    1 +
 src/libipsec/tests/Makefile.am                     |   21 +
 src/{libcharon => libipsec}/tests/Makefile.in      |  120 +-
 .../tls_tests.c => libipsec/tests/ipsec_tests.c}   |   14 +-
 .../tests/ipsec_tests.h}                           |    6 +-
 src/libipsec/tests/suites/test_chapoly.c           |  136 ++
 src/libpttls/pt_tls_client.c                       |    1 +
 src/libradius/radius_message.c                     |    9 +-
 src/libradius/radius_message.h                     |    5 +
 src/libstrongswan/Makefile.am                      |    9 +-
 src/libstrongswan/Makefile.in                      |   65 +-
 src/libstrongswan/asn1/asn1.c                      |    2 +-
 src/libstrongswan/credentials/auth_cfg.c           |   39 +-
 .../credentials/certificates/ocsp_request.h        |    2 +-
 .../credentials/certificates/ocsp_response.h       |    2 +-
 src/libstrongswan/credentials/sets/mem_cred.c      |   58 +-
 src/libstrongswan/credentials/sets/mem_cred.h      |   12 +-
 src/libstrongswan/crypto/crypters/crypter.c        |    8 +-
 src/libstrongswan/crypto/crypters/crypter.h        |    1 +
 src/libstrongswan/crypto/iv/iv_gen.c               |    1 +
 .../crypto/proposal/proposal_keywords_static.c     |  295 ++-
 .../crypto/proposal/proposal_keywords_static.txt   |    1 +
 src/libstrongswan/networking/host.c                |    4 +
 src/libstrongswan/pen/pen.c                        |    6 +-
 src/libstrongswan/pen/pen.h                        |    3 +-
 .../plugins/bliss/bliss_private_key.c              |   18 +-
 src/libstrongswan/plugins/bliss/bliss_public_key.c |   19 +-
 src/libstrongswan/plugins/bliss/bliss_utils.c      |   83 +-
 src/libstrongswan/plugins/bliss/bliss_utils.h      |   10 +-
 src/libstrongswan/plugins/chapoly/Makefile.am      |   29 +
 .../plugins/{test_vectors => chapoly}/Makefile.in  |  246 +--
 src/libstrongswan/plugins/chapoly/chapoly_aead.c   |  333 +++
 src/libstrongswan/plugins/chapoly/chapoly_aead.h   |   52 +
 .../chapoly/chapoly_drv.c}                         |   46 +-
 src/libstrongswan/plugins/chapoly/chapoly_drv.h    |  113 +
 .../plugins/chapoly/chapoly_drv_portable.c         |  454 ++++
 .../plugins/chapoly/chapoly_drv_portable.h}        |   21 +-
 .../plugins/chapoly/chapoly_drv_ssse3.c            |  867 ++++++++
 .../plugins/chapoly/chapoly_drv_ssse3.h}           |   21 +-
 src/libstrongswan/plugins/chapoly/chapoly_plugin.c |   75 +
 .../chapoly/chapoly_plugin.h}                      |   29 +-
 src/libstrongswan/plugins/des/des_crypter.c        |    2 +-
 .../plugins/padlock/padlock_sha1_hasher.h          |    2 +-
 .../plugins/pkcs11/pkcs11_public_key.c             |   11 +-
 src/libstrongswan/plugins/plugin_feature.c         |   18 +-
 src/libstrongswan/plugins/plugin_feature.h         |   10 +-
 src/libstrongswan/plugins/test_vectors/Makefile.am |    1 +
 src/libstrongswan/plugins/test_vectors/Makefile.in |   14 +-
 .../plugins/test_vectors/test_vectors.h            |    4 +
 .../test_vectors/test_vectors/chacha20poly1305.c   |  107 +
 src/libstrongswan/selectors/traffic_selector.c     |    3 +-
 src/libstrongswan/settings/settings.c              |   69 +-
 src/libstrongswan/settings/settings.h              |   54 +
 src/libstrongswan/settings/settings_lexer.c        |  233 +-
 src/libstrongswan/settings/settings_lexer.l        |   19 +-
 src/libstrongswan/settings/settings_parser.c       |  171 +-
 src/libstrongswan/settings/settings_parser.h       |    8 +-
 src/libstrongswan/settings/settings_parser.y       |   39 +-
 src/libstrongswan/tests/suites/test_chunk.c        |    2 +-
 src/libstrongswan/tests/suites/test_host.c         |    6 +
 .../tests/suites/test_identification.c             |   91 +-
 src/libstrongswan/tests/suites/test_settings.c     |  172 +-
 .../tests/suites/test_traffic_selector.c           |  594 ++++-
 src/libstrongswan/tests/test_runner.c              |    2 +-
 src/libstrongswan/tests/test_suite.c               |    2 +-
 src/libstrongswan/tests/tests.c                    |    4 +-
 src/libstrongswan/utils/capabilities.c             |   60 +-
 src/libstrongswan/utils/identification.c           |   48 +-
 src/libstrongswan/utils/identification.h           |   15 +-
 .../utils/printf_hook/printf_hook_builtin.c        |    3 +-
 .../utils/printf_hook/printf_hook_builtin.h        |    2 +-
 .../utils/printf_hook/printf_hook_vstr.h           |    2 +-
 src/libstrongswan/utils/utils.c                    |  107 +-
 src/libstrongswan/utils/utils/string.c             |    2 +-
 src/libtls/tests/tls_tests.c                       |    4 +-
 src/libtnccs/plugins/tnc_tnccs/tnc_tnccs_manager.c |    8 +-
 src/libtncif/tncif_pa_subtypes.c                   |   57 +-
 src/libtncif/tncif_pa_subtypes.h                   |   31 +-
 src/pki/Makefile.am                                |    9 +-
 src/pki/Makefile.in                                |   39 +-
 src/pki/command.h                                  |    2 +-
 src/pki/commands/dn.c                              |  146 ++
 src/pki/commands/issue.c                           |   35 +-
 src/pki/man/Makefile.am                            |   11 +-
 src/pki/man/Makefile.in                            |   37 +-
 src/pki/man/pki---dn.1.in                          |   56 +
 src/pki/man/pki---issue.1.in                       |    5 +-
 src/pki/man/pki.1.in                               |    6 +-
 src/starter/netkey.c                               |   13 -
 src/starter/netkey.h                               |    1 -
 src/starter/parser/conf_parser.h                   |    2 +-
 src/starter/parser/lexer.c                         |  266 ++-
 src/starter/parser/lexer.l                         |   11 +-
 src/starter/parser/parser.c                        |   62 +-
 src/starter/parser/parser.h                        |    6 +-
 src/starter/parser/parser.y                        |    2 +-
 src/starter/starter.c                              |    1 -
 src/starter/starterstroke.c                        |    1 +
 src/starter/tests/suites/test_parser.c             |    3 +
 src/stroke/stroke.c                                |    1 +
 src/swanctl/Makefile.am                            |    4 +-
 src/swanctl/Makefile.in                            |   12 +-
 src/swanctl/command.c                              |    2 +-
 src/swanctl/command.h                              |    2 +-
 src/swanctl/commands/list_authorities.c            |  169 ++
 src/swanctl/commands/list_certs.c                  |    5 +-
 src/swanctl/commands/load_all.c                    |    8 +-
 src/swanctl/commands/load_authorities.c            |  365 ++++
 .../commands/load_authorities.h}                   |   16 +-
 src/swanctl/swanctl.8.in                           |    8 +-
 src/swanctl/swanctl.conf                           |   25 +
 src/swanctl/swanctl.conf.5.main                    |   37 +
 src/swanctl/swanctl.opt                            |   38 +
 testing/config/kernel/config-4.1                   | 2201 +++++++++++++++++++
 testing/config/kernel/config-4.2                   | 2266 ++++++++++++++++++++
 testing/config/kvm/moon.xml                        |    5 +
 testing/config/kvm/sun.xml                         |    5 +
 testing/do-tests                                   |   81 +-
 testing/hosts/alice/etc/raddb/certs/aaaCert.pem    |   34 +-
 testing/hosts/alice/etc/raddb/certs/aaaKey.pem     |   50 +-
 .../etc/openssl/bliss/strongswan_blissCert.der     |  Bin 2094 -> 2086 bytes
 testing/hosts/winnetou/etc/openssl/index.txt       |    3 +-
 testing/hosts/winnetou/etc/openssl/index.txt.old   |    3 +-
 testing/hosts/winnetou/etc/openssl/newcerts/33.pem |   25 +
 .../hosts/winnetou/etc/openssl/research/index.txt  |    3 +-
 .../winnetou/etc/openssl/research/index.txt.old    |    3 +-
 .../winnetou/etc/openssl/research/newcerts/0C.pem} |   18 +-
 testing/hosts/winnetou/etc/openssl/research/serial |    2 +-
 .../hosts/winnetou/etc/openssl/research/serial.old |    2 +-
 testing/hosts/winnetou/etc/openssl/sales/index.txt |    3 +-
 .../hosts/winnetou/etc/openssl/sales/index.txt.old |    3 +-
 .../winnetou/etc/openssl/sales/newcerts/0A.pem}    |   16 +-
 testing/hosts/winnetou/etc/openssl/sales/serial    |    2 +-
 .../hosts/winnetou/etc/openssl/sales/serial.old    |    2 +-
 testing/hosts/winnetou/etc/openssl/serial          |    2 +-
 testing/hosts/winnetou/etc/openssl/serial.old      |    2 +-
 testing/scripts/build-guestkernel                  |   26 +-
 testing/scripts/function.sh                        |    2 +-
 testing/scripts/recipes/013_strongswan.mk          |    3 +
 testing/start-testing                              |    1 +
 testing/testing.conf                               |    8 +-
 testing/tests/ha/both-active/evaltest.dat          |    4 +-
 .../ha/both-active/hosts/alice/etc/iptables.rules  |    4 +-
 .../ha/both-active/hosts/alice/etc/strongswan.conf |    3 +-
 .../ha/both-active/hosts/moon/etc/iptables.rules   |    4 +-
 .../ha/both-active/hosts/moon/etc/strongswan.conf  |    3 +-
 testing/tests/ha/both-active/pretest.dat           |    1 +
 .../ikev1/nat-virtual-ip/hosts/moon/etc/nat_updown |   10 +-
 .../ikev2/alg-chacha20poly1305/description.txt     |    5 +
 .../tests/ikev2/alg-chacha20poly1305/evaltest.dat  |   13 +
 .../hosts/carol/etc/ipsec.conf                     |   22 +
 .../hosts/carol/etc/strongswan.conf                |    7 +
 .../alg-chacha20poly1305/hosts/moon/etc/ipsec.conf |   21 +
 .../hosts/moon/etc/strongswan.conf                 |    7 +
 .../tests/ikev2/alg-chacha20poly1305/posttest.dat  |    4 +
 .../pretest.dat                                    |    5 +-
 .../alg-chacha20poly1305}/test.conf                |    3 +-
 .../ikev2/mult-auth-rsa-eap-sim-id/pretest.dat     |    2 +
 .../etc/ipsec.d/cacerts/research_by_salesCert.pem  |   16 +-
 .../etc/ipsec.d/cacerts/sales_by_researchCert.pem  |   18 +-
 .../ikev2/nat-rw-mark/hosts/sun/etc/mark_updown    |   10 +-
 .../ikev2/nat-virtual-ip/hosts/moon/etc/nat_updown |   10 +-
 .../net2net-same-nets/hosts/sun/etc/mark_updown    |   10 +-
 .../tests/ikev2/rw-eap-sim-id-radius/pretest.dat   |    1 +
 .../tests/ikev2/rw-eap-sim-only-radius/pretest.dat |    2 +
 .../hosts/alice/etc/freeradius/modules/sim_files   |    3 +
 testing/tests/ikev2/rw-eap-sim-radius/pretest.dat  |    2 +
 testing/tests/ikev2/rw-eap-sim-radius/test.conf    |    4 +
 .../ikev2/rw-mark-in-out/hosts/sun/etc/mark_updown |   10 +-
 .../etc/ipsec.d/cacerts/strongswan_blissCert.der   |  Bin 2094 -> 2086 bytes
 .../hosts/carol/etc/ipsec.d/certs/carolCert.der    |  Bin 2172 -> 2175 bytes
 .../etc/ipsec.d/cacerts/strongswan_blissCert.der   |  Bin 2094 -> 2086 bytes
 .../hosts/dave/etc/ipsec.d/certs/daveCert.der      |  Bin 2173 -> 2179 bytes
 .../etc/ipsec.d/cacerts/strongswan_blissCert.der   |  Bin 2094 -> 2086 bytes
 .../hosts/moon/etc/ipsec.d/certs/moonCert.der      |  Bin 2190 -> 2200 bytes
 testing/tests/ikev2/trap-any/description.txt       |    7 +
 testing/tests/ikev2/trap-any/evaltest.dat          |   33 +
 .../ikev2/trap-any/hosts/carol/etc/ipsec.conf      |   16 +
 .../ikev2/trap-any/hosts/carol/etc/ipsec.secrets   |    1 +
 .../ikev2/trap-any/hosts/carol/etc/strongswan.conf |    6 +
 .../tests/ikev2/trap-any/hosts/dave/etc/ipsec.conf |   18 +
 .../ikev2/trap-any/hosts/dave/etc/ipsec.secrets    |    1 +
 .../ikev2/trap-any/hosts/dave/etc/strongswan.conf  |    6 +
 .../tests/ikev2/trap-any/hosts/moon/etc/ipsec.conf |   24 +
 .../ikev2/trap-any/hosts/moon/etc/ipsec.secrets    |    1 +
 .../ikev2/trap-any/hosts/moon/etc/strongswan.conf  |    6 +
 .../tests/ikev2/trap-any/hosts/sun/etc/ipsec.conf  |   25 +
 .../ikev2/trap-any/hosts/sun/etc/ipsec.secrets     |    1 +
 .../ikev2/trap-any/hosts/sun/etc/strongswan.conf   |    6 +
 testing/tests/ikev2/trap-any/posttest.dat          |    4 +
 testing/tests/ikev2/trap-any/pretest.dat           |    5 +
 .../{rw-eap-sim-radius => trap-any}/test.conf      |    8 +-
 testing/tests/ipv6/host2host-ikev1/test.conf       |    4 +
 testing/tests/ipv6/host2host-ikev2/test.conf       |    4 +
 testing/tests/ipv6/net2net-ikev1/test.conf         |    4 +
 testing/tests/ipv6/net2net-ikev2/test.conf         |    4 +
 .../tests/ipv6/net2net-ip4-in-ip6-ikev1/test.conf  |    4 +
 .../tests/ipv6/net2net-ip4-in-ip6-ikev2/test.conf  |    4 +
 .../tests/ipv6/net2net-ip6-in-ip4-ikev1/test.conf  |    4 +
 .../tests/ipv6/net2net-ip6-in-ip4-ikev2/test.conf  |    4 +
 testing/tests/ipv6/net2net-rfc3779-ikev2/test.conf |    4 +
 testing/tests/ipv6/rw-compress-ikev2/test.conf     |    4 +
 testing/tests/ipv6/rw-ikev1/test.conf              |    4 +
 testing/tests/ipv6/rw-ikev2/test.conf              |    4 +
 testing/tests/ipv6/rw-ip6-in-ip4-ikev1/test.conf   |    4 +
 testing/tests/ipv6/rw-ip6-in-ip4-ikev2/test.conf   |    4 +
 testing/tests/ipv6/rw-psk-ikev1/test.conf          |    4 +
 testing/tests/ipv6/rw-psk-ikev2/test.conf          |    4 +
 testing/tests/ipv6/rw-rfc3779-ikev2/test.conf      |    4 +
 testing/tests/ipv6/transport-ikev1/test.conf       |    4 +
 testing/tests/ipv6/transport-ikev2/test.conf       |    4 +
 .../libipsec/host2host-cert/hosts/moon/etc/updown  |   10 +-
 .../libipsec/host2host-cert/hosts/sun/etc/updown   |   10 +-
 .../libipsec/net2net-3des/hosts/moon/etc/updown    |   10 +-
 .../libipsec/net2net-3des/hosts/sun/etc/updown     |   10 +-
 .../libipsec/net2net-cert/hosts/moon/etc/updown    |   10 +-
 .../libipsec/net2net-cert/hosts/sun/etc/updown     |   10 +-
 .../libipsec/rw-suite-b/hosts/carol/etc/updown     |   10 +-
 .../libipsec/rw-suite-b/hosts/dave/etc/updown      |   10 +-
 .../libipsec/rw-suite-b/hosts/moon/etc/updown      |   10 +-
 .../behind-same-nat/hosts/venus/etc/ipsec.conf     |    4 +-
 .../hosts/carol/etc/ipsec.d/data.sql~              |  190 --
 .../hosts/dave/etc/ipsec.d/data.sql~               |  193 --
 testing/tests/swanctl/frags-ipv4/description.txt   |   13 +
 testing/tests/swanctl/frags-ipv4/evaltest.dat      |   19 +
 .../frags-ipv4/hosts/carol/etc/strongswan.conf     |   16 +
 .../hosts/carol/etc/swanctl/swanctl.conf           |   33 +
 .../frags-ipv4/hosts/dave/etc/strongswan.conf      |   16 +
 .../frags-ipv4/hosts/dave/etc/swanctl/swanctl.conf |   34 +
 .../frags-ipv4/hosts/moon/etc/strongswan.conf      |   16 +
 .../frags-ipv4/hosts/moon/etc/swanctl/swanctl.conf |   31 +
 testing/tests/swanctl/frags-ipv4/posttest.dat      |    8 +
 .../swanctl/{rw-cert => frags-ipv4}/pretest.dat    |    6 -
 .../frags-ipv4}/test.conf                          |    4 +
 testing/tests/swanctl/frags-ipv6/description.txt   |   12 +
 testing/tests/swanctl/frags-ipv6/evaltest.dat      |   19 +
 .../frags-ipv6/hosts/carol/etc/strongswan.conf     |   17 +
 .../hosts/carol/etc/swanctl/swanctl.conf           |   40 +
 .../frags-ipv6/hosts/dave/etc/strongswan.conf      |   17 +
 .../frags-ipv6/hosts/dave/etc/swanctl/swanctl.conf |   41 +
 .../frags-ipv6/hosts/moon/etc/strongswan.conf      |   17 +
 .../frags-ipv6/hosts/moon/etc/swanctl/swanctl.conf |   38 +
 testing/tests/swanctl/frags-ipv6/posttest.dat      |   14 +
 testing/tests/swanctl/frags-ipv6/pretest.dat       |   15 +
 .../swanctl/{ip-pool-db => frags-ipv6}/test.conf   |    8 +
 testing/tests/swanctl/ip-pool-db/description.txt   |    6 +-
 .../ip-pool-db/hosts/carol/etc/strongswan.conf     |    7 +-
 .../ip-pool-db/hosts/dave/etc/strongswan.conf      |    7 +-
 .../ip-pool-db/hosts/moon/etc/strongswan.conf      |    7 +-
 testing/tests/swanctl/ip-pool-db/pretest.dat       |    6 -
 testing/tests/swanctl/ip-pool-db/test.conf         |    4 +
 testing/tests/swanctl/ip-pool/description.txt      |   11 +-
 .../ip-pool/hosts/carol/etc/strongswan.conf        |    7 +-
 .../swanctl/ip-pool/hosts/dave/etc/strongswan.conf |    7 +-
 .../swanctl/ip-pool/hosts/moon/etc/strongswan.conf |    8 +-
 testing/tests/swanctl/ip-pool/pretest.dat          |    7 -
 testing/tests/swanctl/ip-pool/test.conf            |    4 +
 .../tests/swanctl/multi-level-ca/description.txt   |    7 +
 testing/tests/swanctl/multi-level-ca/evaltest.dat  |   19 +
 .../multi-level-ca/hosts/carol/etc/strongswan.conf |   14 +
 .../hosts/carol/etc/swanctl/rsa/carolKey.pem       |   27 +
 .../hosts/carol/etc/swanctl/swanctl.conf           |   31 +
 .../hosts/carol/etc/swanctl/x509/carolCert.pem     |   25 +
 .../carol/etc/swanctl/x509ca/researchCert.pem      |   23 +
 .../multi-level-ca/hosts/dave/etc/strongswan.conf  |   14 +
 .../hosts/dave/etc/swanctl/rsa/daveKey.pem         |   27 +
 .../hosts/dave/etc/swanctl/swanctl.conf            |   31 +
 .../hosts/dave/etc/swanctl/x509/daveCert.pem       |   24 +
 .../hosts/dave/etc/swanctl/x509ca/salesCert.pem    |   22 +
 .../multi-level-ca/hosts/moon/etc/ipsec.conf       |   31 +
 .../multi-level-ca/hosts/moon/etc/strongswan.conf  |   15 +
 .../hosts/moon/etc/swanctl/swanctl.conf            |   58 +
 .../hosts/moon/etc/swanctl/x509ca/researchCert.pem |   23 +
 .../hosts/moon/etc/swanctl/x509ca/salesCert.pem    |   22 +
 testing/tests/swanctl/multi-level-ca/posttest.dat  |    8 +
 testing/tests/swanctl/multi-level-ca/pretest.dat   |    8 +
 .../multi-level-ca}/test.conf                      |   10 +-
 .../net2net-cert/hosts/moon/etc/strongswan.conf    |    7 +-
 .../net2net-cert/hosts/sun/etc/strongswan.conf     |    7 +-
 testing/tests/swanctl/net2net-cert/pretest.dat     |    4 -
 testing/tests/swanctl/net2net-cert/test.conf       |    4 +
 .../net2net-route/hosts/moon/etc/strongswan.conf   |    7 +-
 .../net2net-route/hosts/sun/etc/strongswan.conf    |    7 +-
 testing/tests/swanctl/net2net-route/pretest.dat    |    4 -
 testing/tests/swanctl/net2net-route/test.conf      |    4 +
 .../net2net-start/hosts/moon/etc/strongswan.conf   |    7 +-
 .../net2net-start/hosts/sun/etc/strongswan.conf    |    7 +-
 testing/tests/swanctl/net2net-start/pretest.dat    |    5 -
 testing/tests/swanctl/net2net-start/test.conf      |    4 +
 .../tests/swanctl/ocsp-multi-level/description.txt |   10 +
 .../tests/swanctl/ocsp-multi-level/evaltest.dat    |   26 +
 .../hosts/carol/etc/strongswan.conf                |   15 +
 .../hosts/carol/etc/swanctl/rsa/carolKey.pem       |   27 +
 .../hosts/carol/etc/swanctl/swanctl.conf           |   39 +
 .../hosts/carol/etc/swanctl/x509/carolCert.pem     |   25 +
 .../carol/etc/swanctl/x509ca/researchCert.pem      |   23 +
 .../hosts/dave/etc/strongswan.conf                 |   15 +
 .../hosts/dave/etc/swanctl/rsa/daveKey.pem         |   27 +
 .../hosts/dave/etc/swanctl/swanctl.conf            |   39 +
 .../hosts/dave/etc/swanctl/x509/daveCert.pem       |   24 +
 .../hosts/dave/etc/swanctl/x509ca/salesCert.pem    |   22 +
 .../ocsp-multi-level/hosts/moon/etc/ipsec.conf     |   31 +
 .../hosts/moon/etc/strongswan.conf                 |   15 +
 .../hosts/moon/etc/swanctl/swanctl.conf            |   68 +
 .../hosts/moon/etc/swanctl/x509ca/researchCert.pem |   23 +
 .../hosts/moon/etc/swanctl/x509ca/salesCert.pem    |   22 +
 .../tests/swanctl/ocsp-multi-level/posttest.dat    |    8 +
 testing/tests/swanctl/ocsp-multi-level/pretest.dat |    8 +
 .../ocsp-multi-level}/test.conf                    |   10 +-
 testing/tests/swanctl/rw-cert/evaltest.dat         |    4 +-
 .../rw-cert/hosts/carol/etc/strongswan.conf        |    7 +-
 .../swanctl/rw-cert/hosts/dave/etc/strongswan.conf |    7 +-
 .../swanctl/rw-cert/hosts/moon/etc/strongswan.conf |    7 +-
 testing/tests/swanctl/rw-cert/pretest.dat          |    6 -
 testing/tests/swanctl/rw-cert/test.conf            |    4 +
 .../tests/swanctl/rw-hash-and-url/description.txt  |    6 +
 .../{rw-cert => rw-hash-and-url}/evaltest.dat      |    8 +-
 .../hosts/carol}/etc/strongswan.conf               |   10 +-
 .../hosts/carol/etc/swanctl/swanctl.conf           |   40 +
 .../hosts/dave}/etc/strongswan.conf                |   10 +-
 .../hosts/dave/etc/swanctl/swanctl.conf            |   40 +
 .../hosts/moon/etc/strongswan.conf                 |   10 +-
 .../hosts/moon/etc/swanctl/swanctl.conf            |   38 +
 testing/tests/swanctl/rw-hash-and-url/posttest.dat |    8 +
 .../{rw-cert => rw-hash-and-url}/pretest.dat       |    6 -
 .../rw-hash-and-url}/test.conf                     |    4 +
 .../rw-psk-fqdn/hosts/carol/etc/strongswan.conf    |    7 +-
 .../rw-psk-fqdn/hosts/dave/etc/strongswan.conf     |    7 +-
 .../rw-psk-fqdn/hosts/moon/etc/strongswan.conf     |    7 +-
 testing/tests/swanctl/rw-psk-fqdn/pretest.dat      |    6 -
 testing/tests/swanctl/rw-psk-fqdn/test.conf        |    4 +
 .../rw-psk-ipv4/hosts/carol/etc/strongswan.conf    |    7 +-
 .../rw-psk-ipv4/hosts/dave/etc/strongswan.conf     |    7 +-
 .../rw-psk-ipv4/hosts/moon/etc/strongswan.conf     |    7 +-
 testing/tests/swanctl/rw-psk-ipv4/pretest.dat      |    6 -
 testing/tests/swanctl/rw-psk-ipv4/test.conf        |    4 +
 testing/tests/tnc/tnccs-20-hcd-eap/description.txt |   11 +
 testing/tests/tnc/tnccs-20-hcd-eap/evaltest.dat    |   19 +
 .../alice/etc/apache2/sites-available/default      |   26 +
 .../tnccs-20-hcd-eap/hosts/alice/etc/ipsec.conf    |    9 +
 .../hosts/alice/etc/ipsec.d/certs/aaaCert.pem      |   25 +
 .../hosts/alice/etc/ipsec.d/private/aaaKey.pem     |   27 +
 .../tnccs-20-hcd-eap/hosts/alice/etc/ipsec.secrets |    3 +
 .../tnccs-20-hcd-eap/hosts/alice/etc/pts/data1.sql |   61 +
 .../hosts/alice/etc/strongTNC/settings.ini         |   19 +
 .../hosts/alice/etc/strongswan.conf                |   35 +
 .../tnccs-20-hcd-eap/hosts/alice/etc/tnc_config    |    3 +
 .../tnccs-20-hcd-eap/hosts/carol/etc/ipsec.conf    |   24 +
 .../hosts/carol/etc/strongswan.conf                |  158 ++
 .../tnccs-20-hcd-eap/hosts/carol/etc/tnc_config    |    4 +
 .../tnc/tnccs-20-hcd-eap/hosts/dave/etc/ipsec.conf |   24 +
 .../hosts/dave/etc/strongswan.conf                 |  117 +
 .../tnc/tnccs-20-hcd-eap/hosts/dave/etc/tnc_config |    4 +
 .../tnc/tnccs-20-hcd-eap/hosts/moon/etc/ipsec.conf |   33 +
 .../tnccs-20-hcd-eap/hosts/moon/etc/ipsec.secrets  |    3 +
 .../tnccs-20-hcd-eap/hosts/moon/etc/iptables.rules |   36 +
 .../hosts/moon/etc/strongswan.conf                 |   14 +
 testing/tests/tnc/tnccs-20-hcd-eap/posttest.dat    |    8 +
 testing/tests/tnc/tnccs-20-hcd-eap/pretest.dat     |   17 +
 .../tnccs-20-hcd-eap}/test.conf                    |   10 +-
 .../hosts/alice/etc/ipsec.d/certs/aaaCert.pem      |   34 +-
 .../hosts/alice/etc/ipsec.d/private/aaaKey.pem     |   50 +-
 .../hosts/alice/etc/ipsec.d/certs/aaaCert.pem      |   34 +-
 .../hosts/alice/etc/ipsec.d/private/aaaKey.pem     |   50 +-
 .../hosts/alice/etc/strongswan.conf~               |   34 -
 548 files changed, 20236 insertions(+), 4398 deletions(-)

diff --git a/Android.common.mk b/Android.common.mk
index 3a7a043..33b993e 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.3.2"
+strongswan_VERSION := "5.3.3"
 
diff --git a/NEWS b/NEWS
index e0cfb7e..0940dff 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,49 @@
+strongswan-5.3.3
+----------------
+
+- Added support for the ChaCha20/Poly1305 AEAD cipher specified in RFC 7539 and
+  RFC 7634 using the chacha20poly1305 ike/esp proposal keyword. The new chapoly
+  plugin implements the cipher, if possible SSE-accelerated on x86/x64
+  architectures. It is usable both in IKEv2 and the strongSwan libipsec ESP
+  backend. On Linux 4.2 or newer the kernel-netlink plugin can configure the
+  cipher for ESP SAs.
+
+- The vici interface now supports the configuration of auxiliary certification
+  authority information as CRL and OCSP URIs.
+
+- In the bliss plugin the c_indices derivation using a SHA-512 based random
+  oracle has been fixed, generalized and standardized by employing the MGF1 mask
+  generation function with SHA-512. As a consequence BLISS signatures unsing the
+  improved oracle are not compatible with the earlier implementation.
+
+- Support for auto=route with right=%any for transport mode connections has
+  been added (the ikev2/trap-any scenario provides examples).
+
+- The starter daemon does not flush IPsec policies and SAs anymore when it is
+  stopped.  Already existing duplicate policies are now overwritten by the IKE
+  daemon when it installs its policies.
+
+- Init limits (like charon.init_limit_half_open) can now optionally be enforced
+  when initiating SAs via VICI. For this, IKE_SAs initiated by the daemon are
+  now also counted as half-open SAs, which, as a side-effect, fixes the status
+  output while connecting (e.g. in ipsec status).
+
+- Symmetric configuration of EAP methods in left|rightauth is now possible when
+  mutual EAP-only authentication is used (previously, the client had to
+  configure rightauth=eap or rightauth=any, which prevented it from using this
+  same config as responder).
+
+- The initiator flag in the IKEv2 header is compared again (wasn't the case
+  since 5.0.0) and packets that have the flag set incorrectly are again ignored.
+
+- Implemented a demo Hardcopy Device IMC/IMV pair based on the "Hardcopy
+  Device Health Assessment Trusted Network Connect Binding" (HCD-TNC) 
+  document drafted by the IEEE Printer Working Group (PWG).
+
+- Fixed IF-M segmentation which failed in the presence of multiple small
+  attributes in front of a huge attribute to be segmented.
+
+
 strongswan-5.3.2
 ----------------
 
diff --git a/conf/Makefile.am b/conf/Makefile.am
index 7cee0cb..72d9f25 100644
--- a/conf/Makefile.am
+++ b/conf/Makefile.am
@@ -52,6 +52,7 @@ plugins = \
 	plugins/gcrypt.opt \
 	plugins/ha.opt \
 	plugins/imc-attestation.opt \
+	plugins/imc-hcd.opt \
 	plugins/imc-os.opt \
 	plugins/imc-scanner.opt \
 	plugins/imc-swid.opt \
@@ -71,6 +72,7 @@ plugins = \
 	plugins/lookip.opt \
 	plugins/ntru.opt \
 	plugins/openssl.opt \
+	plugins/osx-attr.opt \
 	plugins/pkcs11.opt \
 	plugins/radattr.opt \
 	plugins/random.opt \
diff --git a/conf/Makefile.in b/conf/Makefile.in
index fb3082b..e6781b1 100644
--- a/conf/Makefile.in
+++ b/conf/Makefile.in
@@ -434,6 +434,7 @@ plugins = \
 	plugins/gcrypt.opt \
 	plugins/ha.opt \
 	plugins/imc-attestation.opt \
+	plugins/imc-hcd.opt \
 	plugins/imc-os.opt \
 	plugins/imc-scanner.opt \
 	plugins/imc-swid.opt \
@@ -453,6 +454,7 @@ plugins = \
 	plugins/lookip.opt \
 	plugins/ntru.opt \
 	plugins/openssl.opt \
+	plugins/osx-attr.opt \
 	plugins/pkcs11.opt \
 	plugins/radattr.opt \
 	plugins/random.opt \
diff --git a/conf/options/charon.conf b/conf/options/charon.conf
index bd8e299..5f27b08 100644
--- a/conf/options/charon.conf
+++ b/conf/options/charon.conf
@@ -176,8 +176,8 @@ charon {
     # Number of times to retransmit a packet before giving up.
     # retransmit_tries = 5
 
-    # Interval to use when retrying to initiate an IKE_SA (e.g. if DNS
-    # resolution failed), 0 to disable retries.
+    # Interval in seconds to use when retrying to initiate an IKE_SA (e.g. if
+    # DNS resolution failed), 0 to disable retries.
     # retry_initiate_interval = 0
 
     # Initiate CHILD_SA within existing IKE_SAs.
diff --git a/conf/options/charon.opt b/conf/options/charon.opt
index bbc50ba..5d137ae 100644
--- a/conf/options/charon.opt
+++ b/conf/options/charon.opt
@@ -271,8 +271,8 @@ charon.retransmit_tries = 5
 	Number of times to retransmit a packet before giving up.
 
 charon.retry_initiate_interval = 0
-	Interval to use when retrying to initiate an IKE_SA (e.g. if DNS resolution
-	failed), 0 to disable retries.
+	Interval in seconds to use when retrying to initiate an IKE_SA (e.g. if DNS
+	resolution failed), 0 to disable retries.
 
 charon.reuse_ikesa = yes
 	Initiate CHILD_SA within existing IKE_SAs.
diff --git a/conf/options/imcv.conf b/conf/options/imcv.conf
index 92016ef..bc1f183 100644
--- a/conf/options/imcv.conf
+++ b/conf/options/imcv.conf
@@ -16,6 +16,9 @@ charon {
 
         os_info {
 
+            # Manually set whether a default password is enabled
+            # default_password_enabled = no
+
             # Manually set the name of the client OS (e.g. Ubuntu).
             # name =
 
diff --git a/conf/options/imcv.opt b/conf/options/imcv.opt
index a249a7b..33ab74b 100644
--- a/conf/options/imcv.opt
+++ b/conf/options/imcv.opt
@@ -15,6 +15,9 @@ charon.imcv.os_info.name =
 charon.imcv.os_info.version =
 	Manually set the version of the client OS (e.g. 12.04 i686).
 
+charon.imcv.os_info.default_password_enabled = no
+	Manually set whether a default password is enabled
+
 charon.imcv.policy_script = ipsec _imv_policy
 	Script called for each TNC connection to generate IMV policies.
 
diff --git a/conf/options/starter.conf b/conf/options/starter.conf
index 447397b..5cdcbfd 100644
--- a/conf/options/starter.conf
+++ b/conf/options/starter.conf
@@ -3,9 +3,6 @@ starter {
     # Location of the ipsec.conf file
     # config_file = ${sysconfdir}/ipsec.conf
 
-    # Plugins to load in starter.
-    # load =
-
     # Disable charon plugin load option warning.
     # load_warning = yes
 
diff --git a/conf/options/starter.opt b/conf/options/starter.opt
index 54689e9..f719b1c 100644
--- a/conf/options/starter.opt
+++ b/conf/options/starter.opt
@@ -1,8 +1,5 @@
 starter.config_file = ${sysconfdir}/ipsec.conf
 	Location of the ipsec.conf file
 
-starter.load =
-	Plugins to load in starter.
-
 starter.load_warning = yes
 	Disable charon plugin load option warning.
diff --git a/conf/plugins/eap-radius.conf b/conf/plugins/eap-radius.conf
index b98b195..e81041b 100644
--- a/conf/plugins/eap-radius.conf
+++ b/conf/plugins/eap-radius.conf
@@ -7,12 +7,12 @@ eap-radius {
     # updates.
     # accounting_close_on_timeout = yes
 
-    # Interval for interim RADIUS accounting updates, if not specified by the
-    # RADIUS server in the Access-Accept message.
+    # Interval in seconds for interim RADIUS accounting updates, if not
+    # specified by the RADIUS server in the Access-Accept message.
     # accounting_interval = 0
 
     # If enabled, accounting is disabled unless an IKE_SA has at least one
-    # virtual IP.
+    # virtual IP. Only for IKEv2, for IKEv1 a virtual IP is strictly necessary.
     # accounting_requires_vip = no
 
     # Use class attributes in Access-Accept messages as group membership
diff --git a/conf/plugins/eap-radius.opt b/conf/plugins/eap-radius.opt
index 2a6786d..929931a 100644
--- a/conf/plugins/eap-radius.opt
+++ b/conf/plugins/eap-radius.opt
@@ -6,12 +6,12 @@ charon.plugins.eap-radius.accounting_close_on_timeout = yes
 	updates.
 
 charon.plugins.eap-radius.accounting_interval = 0
-	Interval for interim RADIUS accounting updates, if not specified by the
-	RADIUS server in the Access-Accept message.
+	Interval in seconds for interim RADIUS accounting updates, if not specified
+	by the RADIUS server in the Access-Accept message.
 
 charon.plugins.eap-radius.accounting_requires_vip = no
 	If enabled, accounting is disabled unless an IKE_SA has at least one
-	virtual IP.
+	virtual IP. Only for IKEv2, for IKEv1 a virtual IP is strictly necessary.
 
 charon.plugins.eap-radius.class_group = no
 	Use class attributes in Access-Accept messages as group membership
diff --git a/conf/plugins/imc-hcd.conf b/conf/plugins/imc-hcd.conf
new file mode 100644
index 0000000..b4a5080
--- /dev/null
+++ b/conf/plugins/imc-hcd.conf
@@ -0,0 +1,8 @@
+imc-hcd {
+
+    # Whether to load the plugin. Can also be an integer to increase the
+    # priority of this plugin.
+    load = yes
+
+}
+
diff --git a/conf/plugins/imc-hcd.opt b/conf/plugins/imc-hcd.opt
new file mode 100644
index 0000000..d69b06c
--- /dev/null
+++ b/conf/plugins/imc-hcd.opt
@@ -0,0 +1,71 @@
+libimcv.plugins.imc-hcd.push_info = yes
+	Send quadruple info without being prompted.
+
+libimcv.plugins.imc-hcd.subtypes
+	Section to define PWG HCD PA subtypes.
+
+libimcv.plugins.imc-hcd.subtypes.<section>
+	Defines a PWG HCD PA subtype section. Recognized subtype section names are
+    _system_, _control_, _marker_, _finisher_, _interface_ and _scanner_.
+
+libimcv.plugins.imc-hcd.subtypes.<section>.attributes_natural_language = en
+	Variable length natural language tag conforming to RFC 5646 specifies
+	the language to be used in the health assessment message of a given subtype.
+
+libimcv.plugins.imc-hcd.subtypes.<section>.<sw_type>
+	Defines a software type section. Recognized software type section names are
+	_firmware_, _resident_application_ and _user_application_.
+
+libimcv.plugins.imc-hcd.subtypes.<section>.<sw_type>.<software>
+	Defines a software section having an arbitrary name.
+
+libimcv.plugins.imc-hcd.subtypes.<section>.<sw_type>.<software>.name
+	Name of the software installed on the hardcopy device.
+
+libimcv.plugins.imc-hcd.subtypes.<section>.<sw_type>.<software>.patches
+	String describing all patches applied to the given software on this
+	hardcopy device. The individual patches are separated by a newline
+	character '\\n'.
+
+libimcv.plugins.imc-hcd.subtypes.<section>.<sw_type>.<software>.string_version
+	String describing the version of the given software on this hardcopy device.
+
+libimcv.plugins.imc-hcd.subtypes.<section>.<sw_type>.<software>.version
+	Hex-encoded version string with a length of 16 octets consisting of the
+	fields major version number (4 octets), minor version number (4 octets),
+	build number (4 octets), service pack major number (2 octets) and service
+	pack minor number (2 octets).
+
+libimcv.plugins.imc-hcd.subtypes.system.certification_state
+	Hex-encoded certification state.
+
+libimcv.plugins.imc-hcd.subtypes.system.configuration_state
+	Hex-encoded configuration state.
+
+libimcv.plugins.imc-hcd.subtypes.system.machine_type_model
+	String specifying the machine type and model of the hardcopy device.
+
+libimcv.plugins.imc-hcd.subtypes.system.pstn_fax_enabled = no
+	Specifies if a PSTN facsimile interface is installed and enabled on the
+	hardcopy device.
+
+libimcv.plugins.imc-hcd.subtypes.system.time_source
+	String specifying the hostname of the network time server used by the
+	hardcopy device.
+
+libimcv.plugins.imc-hcd.subtypes.system.user_application_enabled = no
+	Specifies if users can dynamically download and execute applications on
+	the hardcopy device.
+
+libimcv.plugins.imc-hcd.subtypes.system.user_application_persistence_enabled = no
+	Specifies if user dynamically downloaded applications can persist outside
+	the boundaries of a single job on the hardcopy device.
+
+libimcv.plugins.imc-hcd.subtypes.system.vendor_name
+	String specifying the manufacturer of the hardcopy device.
+
+libimcv.plugins.imc-hcd.subtypes.system.vendor_smi_code
+	Integer specifying the globally unique 24-bit SMI code assigned to the
+	manufacturer of the hardcopy device.
+
+
diff --git a/conf/plugins/kernel-netlink.conf b/conf/plugins/kernel-netlink.conf
index 6ea341f..3997dc7 100644
--- a/conf/plugins/kernel-netlink.conf
+++ b/conf/plugins/kernel-netlink.conf
@@ -1,7 +1,7 @@
 kernel-netlink {
 
     # Buffer size for received Netlink messages.
-    # buflen = 4096
+    # buflen = <min(PAGE_SIZE, 8192)>
 
     # Firewall mark to set on the routing rule that directs traffic to our
     # routing table.
diff --git a/conf/plugins/kernel-netlink.opt b/conf/plugins/kernel-netlink.opt
index 4338a5f..6adefd8 100644
--- a/conf/plugins/kernel-netlink.opt
+++ b/conf/plugins/kernel-netlink.opt
@@ -1,4 +1,4 @@
-charon.plugins.kernel-netlink.buflen = 4096
+charon.plugins.kernel-netlink.buflen = <min(PAGE_SIZE, 8192)>
 	Buffer size for received Netlink messages.
 
 charon.plugins.kernel-netlink.fwmark =
diff --git a/conf/plugins/osx-attr.conf b/conf/plugins/osx-attr.conf
new file mode 100644
index 0000000..e20b41b
--- /dev/null
+++ b/conf/plugins/osx-attr.conf
@@ -0,0 +1,12 @@
+osx-attr {
+
+    # Whether DNS servers are appended to existing entries, instead of replacing
+    # them.
+    # append = yes
+
+    # Whether to load the plugin. Can also be an integer to increase the
+    # priority of this plugin.
+    load = yes
+
+}
+
diff --git a/conf/plugins/osx-attr.opt b/conf/plugins/osx-attr.opt
new file mode 100644
index 0000000..70bd197
--- /dev/null
+++ b/conf/plugins/osx-attr.opt
@@ -0,0 +1,3 @@
+charon.plugins.osx-attr.append = yes
+	Whether DNS servers are appended to existing entries, instead of replacing
+	them.
diff --git a/conf/plugins/stroke.conf b/conf/plugins/stroke.conf
index 3d8ee0a..ea6d87b 100644
--- a/conf/plugins/stroke.conf
+++ b/conf/plugins/stroke.conf
@@ -1,5 +1,10 @@
 stroke {
 
+    # Analyze addresses/hostnames in left|right to detect which side is local
+    # and swap configuration options if necessary. If disabled left is always
+    # local.
+    # allow_swap = yes
+
     # Treat certificates in ipsec.d/cacerts and ipsec.conf ca sections as CA
     # certificates even if they don't contain a CA basic constraint.
     # ignore_missing_ca_basic_constraint = no
diff --git a/conf/plugins/stroke.opt b/conf/plugins/stroke.opt
index 4b49b1f..ad5e62d 100644
--- a/conf/plugins/stroke.opt
+++ b/conf/plugins/stroke.opt
@@ -1,3 +1,8 @@
+charon.plugins.stroke.allow_swap = yes
+	Analyze addresses/hostnames in _left|right_ to detect which side is local
+	and swap configuration options if necessary. If disabled _left_ is always
+	_local_.
+
 charon.plugins.stroke.ignore_missing_ca_basic_constraint = no
 	Treat certificates in ipsec.d/cacerts and ipsec.conf ca sections as CA
 	certificates even if they don't contain a CA basic constraint.
diff --git a/conf/strongswan.conf.5.main b/conf/strongswan.conf.5.main
index b81b58c..559efcb 100644
--- a/conf/strongswan.conf.5.main
+++ b/conf/strongswan.conf.5.main
@@ -240,6 +240,10 @@ Global IMV policy database URI. If it contains a password, make sure to adjust
 the permissions of the config file accordingly.
 
 .TP
+.BR charon.imcv.os_info.default_password_enabled " [no]"
+Manually set whether a default password is enabled
+
+.TP
 .BR charon.imcv.os_info.name " []"
 Manually set the name of the client OS (e.g. Ubuntu).
 
@@ -536,12 +540,13 @@ Close the IKE_SA if there is a timeout during interim RADIUS accounting updates.
 
 .TP
 .BR charon.plugins.eap-radius.accounting_interval " [0]"
-Interval for interim RADIUS accounting updates, if not specified by the RADIUS
-server in the Access\-Accept message.
+Interval in seconds for interim RADIUS accounting updates, if not specified by
+the RADIUS server in the Access\-Accept message.
 
 .TP
 .BR charon.plugins.eap-radius.accounting_requires_vip " [no]"
 If enabled, accounting is disabled unless an IKE_SA has at least one virtual IP.
+Only for IKEv2, for IKEv1 a virtual IP is strictly necessary.
 
 .TP
 .BR charon.plugins.eap-radius.class_group " [no]"
@@ -853,7 +858,7 @@ plugins can be used
 to circumvent that problem.
 
 .TP
-.BR charon.plugins.kernel-netlink.buflen " [4096]"
+.BR charon.plugins.kernel-netlink.buflen " [<min(PAGE_SIZE, 8192)>]"
 Buffer size for received Netlink messages.
 
 .TP
@@ -1147,6 +1152,10 @@ ENGINE ID to use in the OpenSSL plugin.
 Set OpenSSL FIPS mode: disabled(0), enabled(1), Suite B enabled(2).
 
 .TP
+.BR charon.plugins.osx-attr.append " [yes]"
+Whether DNS servers are appended to existing entries, instead of replacing them.
+
+.TP
 .BR charon.plugins.pkcs11.load_certs " [yes]"
 Whether to load certificates from tokens.
 
@@ -1246,6 +1255,17 @@ adjust the permissions of the config file accordingly.
 Loglevel for logging to SQL database.
 
 .TP
+.BR charon.plugins.stroke.allow_swap " [yes]"
+Analyze addresses/hostnames in
+.RI "" "left|right" ""
+to detect which side is local and
+swap configuration options if necessary. If disabled
+.RI "" "left" ""
+is always
+.RI "" "local" "."
+
+
+.TP
 .BR charon.plugins.stroke.ignore_missing_ca_basic_constraint " [no]"
 Treat certificates in ipsec.d/cacerts and ipsec.conf ca sections as CA
 certificates even if they don't contain a CA basic constraint.
@@ -1512,8 +1532,8 @@ Number of times to retransmit a packet before giving up.
 
 .TP
 .BR charon.retry_initiate_interval " [0]"
-Interval to use when retrying to initiate an IKE_SA (e.g. if DNS resolution
-failed), 0 to disable retries.
+Interval in seconds to use when retrying to initiate an IKE_SA (e.g. if DNS
+resolution failed), 0 to disable retries.
 
 .TP
 .BR charon.reuse_ikesa " [yes]"
@@ -1747,6 +1767,105 @@ Whether to send pcr_before and pcr_after info.
 Use Quote2 AIK signature instead of Quote signature.
 
 .TP
+.BR libimcv.plugins.imc-hcd.push_info " [yes]"
+Send quadruple info without being prompted.
+
+.TP
+.BR libimcv.plugins.imc-hcd.subtypes " []"
+Section to define PWG HCD PA subtypes.
+
+.TP
+.BR libimcv.plugins.imc-hcd.subtypes.<section> " []"
+Defines a PWG HCD PA subtype section. Recognized subtype section names are
+.RI "" "system" ","
+.RI "" "control" ","
+.RI "" "marker" ","
+.RI "" "finisher" ","
+.RI "" "interface" ""
+and
+.RI "" "scanner" "."
+
+
+.TP
+.BR libimcv.plugins.imc-hcd.subtypes.<section>.<sw_type> " []"
+Defines a software type section. Recognized software type section names are
+.RI "" "firmware" ","
+.RI "" "resident_application" ""
+and
+.RI "" "user_application" "."
+
+
+.TP
+.BR libimcv.plugins.imc-hcd.subtypes.<section>.<sw_type>.<software> " []"
+Defines a software section having an arbitrary name.
+
+.TP
+.BR libimcv.plugins.imc-hcd.subtypes.<section>.<sw_type>.<software>.name " []"
+Name of the software installed on the hardcopy device.
+
+.TP
+.BR libimcv.plugins.imc-hcd.subtypes.<section>.<sw_type>.<software>.patches " []"
+String describing all patches applied to the given software on this hardcopy
+device. The individual patches are separated by a newline character '\\n'.
+
+.TP
+.BR libimcv.plugins.imc-hcd.subtypes.<section>.<sw_type>.<software>.string_version " []"
+String describing the version of the given software on this hardcopy device.
+
+.TP
+.BR libimcv.plugins.imc-hcd.subtypes.<section>.<sw_type>.<software>.version " []"
+Hex\-encoded version string with a length of 16 octets consisting of the fields
+major version number (4 octets), minor version number (4 octets), build number
+(4 octets), service pack major number (2 octets) and service pack minor number
+(2 octets).
+
+.TP
+.BR libimcv.plugins.imc-hcd.subtypes.<section>.attributes_natural_language " [en]"
+Variable length natural language tag conforming to RFC 5646 specifies the
+language to be used in the health assessment message of a given subtype.
+
+.TP
+.BR libimcv.plugins.imc-hcd.subtypes.system.certification_state " []"
+Hex\-encoded certification state.
+
+.TP
+.BR libimcv.plugins.imc-hcd.subtypes.system.configuration_state " []"
+Hex\-encoded configuration state.
+
+.TP
+.BR libimcv.plugins.imc-hcd.subtypes.system.machine_type_model " []"
+String specifying the machine type and model of the hardcopy device.
+
+.TP
+.BR libimcv.plugins.imc-hcd.subtypes.system.pstn_fax_enabled " [no]"
+Specifies if a PSTN facsimile interface is installed and enabled on the hardcopy
+device.
+
+.TP
+.BR libimcv.plugins.imc-hcd.subtypes.system.time_source " []"
+String specifying the hostname of the network time server used by the hardcopy
+device.
+
+.TP
+.BR libimcv.plugins.imc-hcd.subtypes.system.user_application_enabled " [no]"
+Specifies if users can dynamically download and execute applications on the
+hardcopy device.
+
+.TP
+.BR libimcv.plugins.imc-hcd.subtypes.system.user_application_persistence_enabled " [no]"
+Specifies if user dynamically downloaded applications can persist outside the
+boundaries of a single job on the hardcopy device.
+
+.TP
+.BR libimcv.plugins.imc-hcd.subtypes.system.vendor_name " []"
+String specifying the manufacturer of the hardcopy device.
+
+.TP
+.BR libimcv.plugins.imc-hcd.subtypes.system.vendor_smi_code " []"
+Integer specifying the globally unique 24\-bit SMI code assigned to the
+manufacturer of the hardcopy device.
+
+.TP
 .BR libimcv.plugins.imc-os.device_cert " []"
 Manually set the path to the client device certificate (e.g.
 /etc/pts/aikCert.der)
@@ -1945,10 +2064,6 @@ Plugins to load in ipsec scepclient tool.
 Location of the ipsec.conf file
 
 .TP
-.BR starter.load " []"
-Plugins to load in starter.
-
-.TP
 .BR starter.load_warning " [yes]"
 Disable charon plugin load option warning.
 
diff --git a/config.h.in b/config.h.in
index 7633409..729ddf0 100644
--- a/config.h.in
+++ b/config.h.in
@@ -55,6 +55,9 @@
    don't. */
 #undef HAVE_DECL_STRERROR_R
 
+/* Define to 1 if you have the `dirfd' function. */
+#undef HAVE_DIRFD
+
 /* have dladdr() */
 #undef HAVE_DLADDR
 
@@ -248,6 +251,9 @@
 /* Define to 1 if you have the <sys/stat.h> header file. */
 #undef HAVE_SYS_STAT_H
 
+/* Define to 1 if you have the <sys/syscall.h> header file. */
+#undef HAVE_SYS_SYSCALL_H
+
 /* Define to 1 if you have the <sys/types.h> header file. */
 #undef HAVE_SYS_TYPES_H
 
diff --git a/configure b/configure
index 8aa47c9..59a74cc 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.3.2.
+# Generated by GNU Autoconf 2.69 for strongSwan 5.3.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.3.2'
-PACKAGE_STRING='strongSwan 5.3.2'
+PACKAGE_VERSION='5.3.3'
+PACKAGE_STRING='strongSwan 5.3.3'
 PACKAGE_BUGREPORT=''
 PACKAGE_URL=''
 
@@ -759,6 +759,10 @@ USE_SOCKET_DYNAMIC_FALSE
 USE_SOCKET_DYNAMIC_TRUE
 USE_SOCKET_DEFAULT_FALSE
 USE_SOCKET_DEFAULT_TRUE
+USE_IMV_HCD_FALSE
+USE_IMV_HCD_TRUE
+USE_IMC_HCD_FALSE
+USE_IMC_HCD_TRUE
 USE_IMV_SWID_FALSE
 USE_IMV_SWID_TRUE
 USE_IMC_SWID_FALSE
@@ -911,6 +915,8 @@ USE_CCM_FALSE
 USE_CCM_TRUE
 USE_CTR_FALSE
 USE_CTR_TRUE
+USE_CHAPOLY_FALSE
+USE_CHAPOLY_TRUE
 USE_PKCS11_FALSE
 USE_PKCS11_TRUE
 USE_KEYCHAIN_FALSE
@@ -1064,6 +1070,8 @@ xml_LIBS
 xml_CFLAGS
 soup_LIBS
 soup_CFLAGS
+USE_X86X64_FALSE
+USE_X86X64_TRUE
 PLUGIN_CFLAGS
 USE_WINDOWS_FALSE
 USE_WINDOWS_TRUE
@@ -1270,6 +1278,7 @@ enable_af_alg
 enable_bliss
 enable_blowfish
 enable_ccm
+enable_chapoly
 enable_cmac
 enable_ctr
 enable_des
@@ -1374,6 +1383,8 @@ enable_imc_attestation
 enable_imv_attestation
 enable_imc_swid
 enable_imv_swid
+enable_imc_hcd
+enable_imv_hcd
 enable_tnc_ifmap
 enable_tnc_imc
 enable_tnc_imv
@@ -2018,7 +2029,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.3.2 to adapt to many kinds of systems.
+\`configure' configures strongSwan 5.3.3 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -2088,7 +2099,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of strongSwan 5.3.2:";;
+     short | recursive ) echo "Configuration of strongSwan 5.3.3:";;
    esac
   cat <<\_ACEOF
 
@@ -2103,6 +2114,7 @@ Optional Features:
   --enable-bliss          enable BLISS software implementation plugin.
   --enable-blowfish       enable Blowfish software implementation plugin.
   --enable-ccm            enables the CCM AEAD wrapper crypto plugin.
+  --enable-chapoly        enables the ChaCha20/Poly1305 AEAD plugin.
   --disable-cmac          disable CMAC crypto implementation plugin.
   --enable-ctr            enables the Counter Mode wrapper crypto plugin.
   --disable-des           disable DES/3DES software implementation plugin.
@@ -2234,6 +2246,8 @@ Optional Features:
                           enable IMV attestation module.
   --enable-imc-swid       enable IMC swid module.
   --enable-imv-swid       enable IMV swid module.
+  --enable-imc-hcd        enable IMC hcd module.
+  --enable-imv-hcd        enable IMV hcd module.
   --enable-tnc-ifmap      enable TNC IF-MAP module. Requires libxml
   --enable-tnc-imc        enable TNC IMC module.
   --enable-tnc-imv        enable TNC IMV module.
@@ -2526,7 +2540,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-strongSwan configure 5.3.2
+strongSwan configure 5.3.3
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -3048,7 +3062,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.3.2, which was
+It was created by strongSwan $as_me 5.3.3, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -3911,7 +3925,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='strongswan'
- VERSION='5.3.2'
+ VERSION='5.3.3'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -4844,6 +4858,22 @@ fi
 
 	disabled_by_default=${disabled_by_default}" ccm"
 
+# Check whether --enable-chapoly was given.
+if test "${enable_chapoly+set}" = set; then :
+  enableval=$enable_chapoly; chapoly_given=true
+		if test x$enableval = xyes; then
+			chapoly=true
+		 else
+			chapoly=false
+		fi
+else
+  chapoly=false
+		chapoly_given=false
+
+fi
+
+	disabled_by_default=${disabled_by_default}" chapoly"
+
 # Check whether --enable-cmac was given.
 if test "${enable_cmac+set}" = set; then :
   enableval=$enable_cmac; cmac_given=true
@@ -6516,6 +6546,38 @@ fi
 
 	disabled_by_default=${disabled_by_default}" imv_swid"
 
+# Check whether --enable-imc-hcd was given.
+if test "${enable_imc_hcd+set}" = set; then :
+  enableval=$enable_imc_hcd; imc_hcd_given=true
+		if test x$enableval = xyes; then
+			imc_hcd=true
+		 else
+			imc_hcd=false
+		fi
+else
+  imc_hcd=false
+		imc_hcd_given=false
+
+fi
+
+	disabled_by_default=${disabled_by_default}" imc_hcd"
+
+# Check whether --enable-imv-hcd was given.
+if test "${enable_imv_hcd+set}" = set; then :
+  enableval=$enable_imv_hcd; imv_hcd_given=true
+		if test x$enableval = xyes; then
+			imv_hcd=true
+		 else
+			imv_hcd=false
+		fi
+else
+  imv_hcd=false
+		imv_hcd_given=false
+
+fi
+
+	disabled_by_default=${disabled_by_default}" imv_hcd"
+
 # Check whether --enable-tnc-ifmap was given.
 if test "${enable_tnc_ifmap+set}" = set; then :
   enableval=$enable_tnc_ifmap; tnc_ifmap_given=true
@@ -17206,7 +17268,7 @@ if test x$eap_tls = xtrue -o x$eap_ttls = xtrue -o x$eap_peap = xtrue -o x$tnc_t
 	tls=true;
 fi
 
-if test x$imc_test = xtrue -o x$imv_test = xtrue -o x$imc_scanner = xtrue -o x$imv_scanner = xtrue -o x$imc_os = xtrue -o x$imv_os = xtrue -o x$imc_attestation = xtrue -o x$imv_attestation = xtrue -o x$imc_swid = xtrue -o x$imv_swid = xtrue; then
+if test x$imc_test = xtrue -o x$imv_test = xtrue -o x$imc_scanner = xtrue -o x$imv_scanner = xtrue -o x$imc_os = xtrue -o x$imv_os = xtrue -o x$imc_attestation = xtrue -o x$imv_attestation = xtrue -o x$imc_swid = xtrue -o x$imv_swid = xtrue -o x$imc_hcd = xtrue -o x$imv_hcd = xtrue; then
 	imcv=true;
 fi
 
@@ -18129,7 +18191,7 @@ $as_echo "#define HAVE_QSORT_R /**/" >>confdefs.h
 		# set -Werror so that we get an error for "argument ... has
 		# incompatible pointer type" warnings
 		save_CFLAGS="$CFLAGS"
-		CFLAGS="$CFLAGS -Werror"
+		CFLAGS="$CFLAGS -Werror -Wno-unused-parameter"
 		{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU-style qsort_r" >&5
 $as_echo_n "checking for GNU-style qsort_r... " >&6; }
 		cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -18207,7 +18269,7 @@ _ACEOF
 fi
 done
 
-for ac_func in fmemopen funopen mmap memrchr setlinebuf strptime
+for ac_func in fmemopen funopen mmap memrchr setlinebuf strptime dirfd
 do :
   as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
 ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
@@ -18239,7 +18301,7 @@ else
 fi
 
 
-for ac_header in sys/sockio.h glob.h net/if_tun.h
+for ac_header in sys/sockio.h sys/syscall.h glob.h net/if_tun.h
 do :
   as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
 ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
@@ -18801,6 +18863,44 @@ $as_echo "no" >&6; }
 fi
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking x86/x64 target" >&5
+$as_echo_n "checking x86/x64 target... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+		 #if !defined(__i386__) && !defined(__x86_64__)
+		 # error not on x86/x64
+		 #endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+		x86x64=true
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ if test "x$x86x64" = xtrue; then
+  USE_X86X64_TRUE=
+  USE_X86X64_FALSE='#'
+else
+  USE_X86X64_TRUE='#'
+  USE_X86X64_FALSE=
+fi
+
+
 if test x$printf_hooks = xvstr; then
 	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lvstr" >&5
 $as_echo_n "checking for main in -lvstr... " >&6; }
@@ -22183,6 +22283,15 @@ if test x$keychain = xtrue; then
 
 	fi
 
+if test x$chapoly = xtrue; then
+		s_plugins=${s_plugins}" chapoly"
+		charon_plugins=${charon_plugins}" chapoly"
+		scripts_plugins=${scripts_plugins}" chapoly"
+		nm_plugins=${nm_plugins}" chapoly"
+		cmd_plugins=${cmd_plugins}" chapoly"
+
+	fi
+
 if test x$xcbc = xtrue; then
 		s_plugins=${s_plugins}" xcbc"
 		charon_plugins=${charon_plugins}" xcbc"
@@ -23162,6 +23271,14 @@ else
   USE_PKCS11_FALSE=
 fi
 
+ if test x$chapoly = xtrue; then
+  USE_CHAPOLY_TRUE=
+  USE_CHAPOLY_FALSE='#'
+else
+  USE_CHAPOLY_TRUE='#'
+  USE_CHAPOLY_FALSE=
+fi
+
  if test x$ctr = xtrue; then
   USE_CTR_TRUE=
   USE_CTR_FALSE='#'
@@ -23773,6 +23890,22 @@ else
   USE_IMV_SWID_FALSE=
 fi
 
+ if test x$imc_hcd = xtrue; then
+  USE_IMC_HCD_TRUE=
+  USE_IMC_HCD_FALSE='#'
+else
+  USE_IMC_HCD_TRUE='#'
+  USE_IMC_HCD_FALSE=
+fi
+
+ if test x$imv_hcd = xtrue; then
+  USE_IMV_HCD_TRUE=
+  USE_IMV_HCD_FALSE='#'
+else
+  USE_IMV_HCD_TRUE='#'
+  USE_IMV_HCD_FALSE=
+fi
+
  if test x$socket_default = xtrue; then
   USE_SOCKET_DEFAULT_TRUE=
   USE_SOCKET_DEFAULT_FALSE='#'
@@ -24366,14 +24499,14 @@ 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/plugins/aes/Makefile src/libstrongswan/plugins/cmac/Makefile src/libstrongswan/plugins/des/Makefile src/libstrongswan/plugins/blowfish/Makefile src/libstrongswan/plugins/rc2/Makefile src/libstrongswan/plugins/md4/Makefile src/libstrongswan/plugins/md5/Makefile src/libstrongswa [...]
+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/plugins/aes/Makefile src/libstrongswan/plugins/cmac/Makefile src/libstrongswan/plugins/des/Makefile src/libstrongswan/plugins/blowfish/Makefile src/libstrongswan/plugins/rc2/Makefile src/libstrongswan/plugins/md4/Makefile src/libstrongswan/plugins/md5/Makefile src/libstrongswa [...]
 
 
 # =================
 #  build man pages
 # =================
 
-ac_config_files="$ac_config_files conf/strongswan.conf.5.head conf/strongswan.conf.5.tail man/ipsec.conf.5 man/ipsec.secrets.5 src/charon-cmd/charon-cmd.8 src/pki/man/pki.1 src/pki/man/pki---gen.1 src/pki/man/pki---issue.1 src/pki/man/pki---keyid.1 src/pki/man/pki---pkcs7.1 src/pki/man/pki---pkcs12.1 src/pki/man/pki---print.1 src/pki/man/pki---pub.1 src/pki/man/pki---req.1 src/pki/man/pki---self.1 src/pki/man/pki---signcrl.1 src/pki/man/pki---acert.1 src/pki/man/pki---verify.1 src/swanct [...]
+ac_config_files="$ac_config_files conf/strongswan.conf.5.head conf/strongswan.conf.5.tail man/ipsec.conf.5 man/ipsec.secrets.5 src/charon-cmd/charon-cmd.8 src/pki/man/pki.1 src/pki/man/pki---acert.1 src/pki/man/pki---dn.1 src/pki/man/pki---gen.1 src/pki/man/pki---issue.1 src/pki/man/pki---keyid.1 src/pki/man/pki---pkcs12.1 src/pki/man/pki---pkcs7.1 src/pki/man/pki---print.1 src/pki/man/pki---pub.1 src/pki/man/pki---req.1 src/pki/man/pki---self.1 src/pki/man/pki---signcrl.1 src/pki/man/pk [...]
 
 
 cat >confcache <<\_ACEOF
@@ -24518,6 +24651,10 @@ if test -z "${USE_WINDOWS_TRUE}" && test -z "${USE_WINDOWS_FALSE}"; then
   as_fn_error $? "conditional \"USE_WINDOWS\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
+if test -z "${USE_X86X64_TRUE}" && test -z "${USE_X86X64_FALSE}"; then
+  as_fn_error $? "conditional \"USE_X86X64\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
 if test -z "${USE_DEV_HEADERS_TRUE}" && test -z "${USE_DEV_HEADERS_FALSE}"; then
   as_fn_error $? "conditional \"USE_DEV_HEADERS\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
@@ -24710,6 +24847,10 @@ if test -z "${USE_PKCS11_TRUE}" && test -z "${USE_PKCS11_FALSE}"; then
   as_fn_error $? "conditional \"USE_PKCS11\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
+if test -z "${USE_CHAPOLY_TRUE}" && test -z "${USE_CHAPOLY_FALSE}"; then
+  as_fn_error $? "conditional \"USE_CHAPOLY\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
 if test -z "${USE_CTR_TRUE}" && test -z "${USE_CTR_FALSE}"; then
   as_fn_error $? "conditional \"USE_CTR\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
@@ -25014,6 +25155,14 @@ if test -z "${USE_IMV_SWID_TRUE}" && test -z "${USE_IMV_SWID_FALSE}"; then
   as_fn_error $? "conditional \"USE_IMV_SWID\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
+if test -z "${USE_IMC_HCD_TRUE}" && test -z "${USE_IMC_HCD_FALSE}"; then
+  as_fn_error $? "conditional \"USE_IMC_HCD\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${USE_IMV_HCD_TRUE}" && test -z "${USE_IMV_HCD_FALSE}"; then
+  as_fn_error $? "conditional \"USE_IMV_HCD\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
 if test -z "${USE_SOCKET_DEFAULT_TRUE}" && test -z "${USE_SOCKET_DEFAULT_FALSE}"; then
   as_fn_error $? "conditional \"USE_SOCKET_DEFAULT\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
@@ -25663,7 +25812,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.3.2, which was
+This file was extended by strongSwan $as_me 5.3.3, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -25729,7 +25878,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.3.2
+strongSwan config.status 5.3.3
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
@@ -26191,6 +26340,7 @@ do
     "src/libstrongswan/plugins/agent/Makefile") CONFIG_FILES="$CONFIG_FILES src/libstrongswan/plugins/agent/Makefile" ;;
     "src/libstrongswan/plugins/keychain/Makefile") CONFIG_FILES="$CONFIG_FILES src/libstrongswan/plugins/keychain/Makefile" ;;
     "src/libstrongswan/plugins/pkcs11/Makefile") CONFIG_FILES="$CONFIG_FILES src/libstrongswan/plugins/pkcs11/Makefile" ;;
+    "src/libstrongswan/plugins/chapoly/Makefile") CONFIG_FILES="$CONFIG_FILES src/libstrongswan/plugins/chapoly/Makefile" ;;
     "src/libstrongswan/plugins/ctr/Makefile") CONFIG_FILES="$CONFIG_FILES src/libstrongswan/plugins/ctr/Makefile" ;;
     "src/libstrongswan/plugins/ccm/Makefile") CONFIG_FILES="$CONFIG_FILES src/libstrongswan/plugins/ccm/Makefile" ;;
     "src/libstrongswan/plugins/gcm/Makefile") CONFIG_FILES="$CONFIG_FILES src/libstrongswan/plugins/gcm/Makefile" ;;
@@ -26206,6 +26356,7 @@ do
     "src/libhydra/plugins/kernel_pfroute/Makefile") CONFIG_FILES="$CONFIG_FILES src/libhydra/plugins/kernel_pfroute/Makefile" ;;
     "src/libhydra/tests/Makefile") CONFIG_FILES="$CONFIG_FILES src/libhydra/tests/Makefile" ;;
     "src/libipsec/Makefile") CONFIG_FILES="$CONFIG_FILES src/libipsec/Makefile" ;;
+    "src/libipsec/tests/Makefile") CONFIG_FILES="$CONFIG_FILES src/libipsec/tests/Makefile" ;;
     "src/libsimaka/Makefile") CONFIG_FILES="$CONFIG_FILES src/libsimaka/Makefile" ;;
     "src/libtls/Makefile") CONFIG_FILES="$CONFIG_FILES src/libtls/Makefile" ;;
     "src/libtls/tests/Makefile") CONFIG_FILES="$CONFIG_FILES src/libtls/tests/Makefile" ;;
@@ -26230,6 +26381,8 @@ do
     "src/libimcv/plugins/imv_attestation/Makefile") CONFIG_FILES="$CONFIG_FILES src/libimcv/plugins/imv_attestation/Makefile" ;;
     "src/libimcv/plugins/imc_swid/Makefile") CONFIG_FILES="$CONFIG_FILES src/libimcv/plugins/imc_swid/Makefile" ;;
     "src/libimcv/plugins/imv_swid/Makefile") CONFIG_FILES="$CONFIG_FILES src/libimcv/plugins/imv_swid/Makefile" ;;
+    "src/libimcv/plugins/imc_hcd/Makefile") CONFIG_FILES="$CONFIG_FILES src/libimcv/plugins/imc_hcd/Makefile" ;;
+    "src/libimcv/plugins/imv_hcd/Makefile") CONFIG_FILES="$CONFIG_FILES src/libimcv/plugins/imv_hcd/Makefile" ;;
     "src/charon/Makefile") CONFIG_FILES="$CONFIG_FILES src/charon/Makefile" ;;
     "src/charon-nm/Makefile") CONFIG_FILES="$CONFIG_FILES src/charon-nm/Makefile" ;;
     "src/charon-tkm/Makefile") CONFIG_FILES="$CONFIG_FILES src/charon-tkm/Makefile" ;;
@@ -26333,17 +26486,18 @@ do
     "man/ipsec.secrets.5") CONFIG_FILES="$CONFIG_FILES man/ipsec.secrets.5" ;;
     "src/charon-cmd/charon-cmd.8") CONFIG_FILES="$CONFIG_FILES src/charon-cmd/charon-cmd.8" ;;
     "src/pki/man/pki.1") CONFIG_FILES="$CONFIG_FILES src/pki/man/pki.1" ;;
+    "src/pki/man/pki---acert.1") CONFIG_FILES="$CONFIG_FILES src/pki/man/pki---acert.1" ;;
+    "src/pki/man/pki---dn.1") CONFIG_FILES="$CONFIG_FILES src/pki/man/pki---dn.1" ;;
     "src/pki/man/pki---gen.1") CONFIG_FILES="$CONFIG_FILES src/pki/man/pki---gen.1" ;;
     "src/pki/man/pki---issue.1") CONFIG_FILES="$CONFIG_FILES src/pki/man/pki---issue.1" ;;
     "src/pki/man/pki---keyid.1") CONFIG_FILES="$CONFIG_FILES src/pki/man/pki---keyid.1" ;;
-    "src/pki/man/pki---pkcs7.1") CONFIG_FILES="$CONFIG_FILES src/pki/man/pki---pkcs7.1" ;;
     "src/pki/man/pki---pkcs12.1") CONFIG_FILES="$CONFIG_FILES src/pki/man/pki---pkcs12.1" ;;
+    "src/pki/man/pki---pkcs7.1") CONFIG_FILES="$CONFIG_FILES src/pki/man/pki---pkcs7.1" ;;
     "src/pki/man/pki---print.1") CONFIG_FILES="$CONFIG_FILES src/pki/man/pki---print.1" ;;
     "src/pki/man/pki---pub.1") CONFIG_FILES="$CONFIG_FILES src/pki/man/pki---pub.1" ;;
     "src/pki/man/pki---req.1") CONFIG_FILES="$CONFIG_FILES src/pki/man/pki---req.1" ;;
     "src/pki/man/pki---self.1") CONFIG_FILES="$CONFIG_FILES src/pki/man/pki---self.1" ;;
     "src/pki/man/pki---signcrl.1") CONFIG_FILES="$CONFIG_FILES src/pki/man/pki---signcrl.1" ;;
-    "src/pki/man/pki---acert.1") CONFIG_FILES="$CONFIG_FILES src/pki/man/pki---acert.1" ;;
     "src/pki/man/pki---verify.1") CONFIG_FILES="$CONFIG_FILES src/pki/man/pki---verify.1" ;;
     "src/swanctl/swanctl.8") CONFIG_FILES="$CONFIG_FILES src/swanctl/swanctl.8" ;;
     "src/swanctl/swanctl.conf.5.head") CONFIG_FILES="$CONFIG_FILES src/swanctl/swanctl.conf.5.head" ;;
diff --git a/configure.ac b/configure.ac
index 65098d7..ffd0929 100644
--- a/configure.ac
+++ b/configure.ac
@@ -19,7 +19,7 @@
 #  initialize & set some vars
 # ============================
 
-AC_INIT([strongSwan],[5.3.2])
+AC_INIT([strongSwan],[5.3.3])
 AM_INIT_AUTOMAKE(m4_esyscmd([
 	echo tar-ustar
 	echo subdir-objects
@@ -127,6 +127,7 @@ ARG_ENABL_SET([af-alg],         [enable AF_ALG crypto interface to Linux Crypto
 ARG_ENABL_SET([bliss],          [enable BLISS software implementation plugin.])
 ARG_ENABL_SET([blowfish],       [enable Blowfish software implementation plugin.])
 ARG_ENABL_SET([ccm],            [enables the CCM AEAD wrapper crypto plugin.])
+ARG_ENABL_SET([chapoly],        [enables the ChaCha20/Poly1305 AEAD plugin.])
 ARG_DISBL_SET([cmac],           [disable CMAC crypto implementation plugin.])
 ARG_ENABL_SET([ctr],            [enables the Counter Mode wrapper crypto plugin.])
 ARG_DISBL_SET([des],            [disable DES/3DES software implementation plugin.])
@@ -239,6 +240,8 @@ ARG_ENABL_SET([imc-attestation],[enable IMC attestation module.])
 ARG_ENABL_SET([imv-attestation],[enable IMV attestation module.])
 ARG_ENABL_SET([imc-swid],       [enable IMC swid module.])
 ARG_ENABL_SET([imv-swid],       [enable IMV swid module.])
+ARG_ENABL_SET([imc-hcd],        [enable IMC hcd module.])
+ARG_ENABL_SET([imv-hcd],        [enable IMV hcd module.])
 ARG_ENABL_SET([tnc-ifmap],      [enable TNC IF-MAP module. Requires libxml])
 ARG_ENABL_SET([tnc-imc],        [enable TNC IMC module.])
 ARG_ENABL_SET([tnc-imv],        [enable TNC IMV module.])
@@ -404,7 +407,7 @@ if test x$eap_tls = xtrue -o x$eap_ttls = xtrue -o x$eap_peap = xtrue -o x$tnc_t
 	tls=true;
 fi
 
-if test x$imc_test = xtrue -o x$imv_test = xtrue -o x$imc_scanner = xtrue -o x$imv_scanner = xtrue -o x$imc_os = xtrue -o x$imv_os = xtrue -o x$imc_attestation = xtrue -o x$imv_attestation = xtrue -o x$imc_swid = xtrue -o x$imv_swid = xtrue; then
+if test x$imc_test = xtrue -o x$imv_test = xtrue -o x$imc_scanner = xtrue -o x$imv_scanner = xtrue -o x$imc_os = xtrue -o x$imv_os = xtrue -o x$imc_attestation = xtrue -o x$imv_attestation = xtrue -o x$imc_swid = xtrue -o x$imv_swid = xtrue -o x$imc_hcd = xtrue -o x$imv_hcd = xtrue; then
 	imcv=true;
 fi
 
@@ -552,7 +555,7 @@ AC_CHECK_FUNC(
 		# set -Werror so that we get an error for "argument ... has
 		# incompatible pointer type" warnings
 		save_CFLAGS="$CFLAGS"
-		CFLAGS="$CFLAGS -Werror"
+		CFLAGS="$CFLAGS -Werror -Wno-unused-parameter"
 		AC_MSG_CHECKING([for GNU-style qsort_r])
 		AC_COMPILE_IFELSE(
 			[AC_LANG_PROGRAM(
@@ -582,7 +585,7 @@ AC_CHECK_FUNC(
 )
 
 AC_CHECK_FUNCS(prctl mallinfo getpass closefrom getpwnam_r getgrnam_r getpwuid_r)
-AC_CHECK_FUNCS(fmemopen funopen mmap memrchr setlinebuf strptime)
+AC_CHECK_FUNCS(fmemopen funopen mmap memrchr setlinebuf strptime dirfd)
 
 AC_CHECK_FUNC([syslog], [
 	AC_DEFINE([HAVE_SYSLOG], [], [have syslog(3) and friends])
@@ -590,7 +593,7 @@ AC_CHECK_FUNC([syslog], [
 ])
 AM_CONDITIONAL(USE_SYSLOG, [test "x$syslog" = xtrue])
 
-AC_CHECK_HEADERS(sys/sockio.h glob.h net/if_tun.h)
+AC_CHECK_HEADERS(sys/sockio.h sys/syscall.h glob.h net/if_tun.h)
 AC_CHECK_HEADERS(net/pfkeyv2.h netipsec/ipsec.h netinet6/ipsec.h linux/udp.h)
 AC_CHECK_HEADERS([netinet/ip6.h linux/fib_rules.h], [], [],
 [
@@ -838,6 +841,22 @@ AC_COMPILE_IFELSE(
 	]
 )
 
+AC_MSG_CHECKING([x86/x64 target])
+AC_COMPILE_IFELSE(
+	[AC_LANG_PROGRAM(
+		[], [[
+		 #if !defined(__i386__) && !defined(__x86_64__)
+		 # error not on x86/x64
+		 #endif
+		]])],
+	[
+		x86x64=true
+		AC_MSG_RESULT([yes])
+	],
+	[AC_MSG_RESULT([no])]
+)
+AM_CONDITIONAL(USE_X86X64, [test "x$x86x64" = xtrue])
+
 if test x$printf_hooks = xvstr; then
 	AC_CHECK_LIB([vstr],[main],[LIBS="$LIBS"],[AC_MSG_ERROR([Vstr string library not found])],[])
 	AC_DEFINE([USE_VSTR], [], [use Vstr string library for printf hooks])
@@ -1293,6 +1312,7 @@ ADD_PLUGIN([fips-prf],             [s charon nm cmd])
 ADD_PLUGIN([gmp],                  [s charon scepclient pki scripts manager medsrv attest nm cmd aikgen])
 ADD_PLUGIN([agent],                [s charon nm cmd])
 ADD_PLUGIN([keychain],             [s charon cmd])
+ADD_PLUGIN([chapoly],              [s charon scripts nm cmd])
 ADD_PLUGIN([xcbc],                 [s charon nm cmd])
 ADD_PLUGIN([cmac],                 [s charon nm cmd])
 ADD_PLUGIN([hmac],                 [s charon pki scripts nm cmd])
@@ -1449,6 +1469,7 @@ AM_CONDITIONAL(USE_GCRYPT, test x$gcrypt = xtrue)
 AM_CONDITIONAL(USE_AGENT, test x$agent = xtrue)
 AM_CONDITIONAL(USE_KEYCHAIN, test x$keychain = xtrue)
 AM_CONDITIONAL(USE_PKCS11, test x$pkcs11 = xtrue)
+AM_CONDITIONAL(USE_CHAPOLY, test x$chapoly = xtrue)
 AM_CONDITIONAL(USE_CTR, test x$ctr = xtrue)
 AM_CONDITIONAL(USE_CCM, test x$ccm = xtrue)
 AM_CONDITIONAL(USE_GCM, test x$gcm = xtrue)
@@ -1528,6 +1549,8 @@ AM_CONDITIONAL(USE_IMC_ATTESTATION, test x$imc_attestation = xtrue)
 AM_CONDITIONAL(USE_IMV_ATTESTATION, test x$imv_attestation = xtrue)
 AM_CONDITIONAL(USE_IMC_SWID, test x$imc_swid = xtrue)
 AM_CONDITIONAL(USE_IMV_SWID, test x$imv_swid = xtrue)
+AM_CONDITIONAL(USE_IMC_HCD, test x$imc_hcd = xtrue)
+AM_CONDITIONAL(USE_IMV_HCD, test x$imv_hcd = xtrue)
 AM_CONDITIONAL(USE_SOCKET_DEFAULT, test x$socket_default = xtrue)
 AM_CONDITIONAL(USE_SOCKET_DYNAMIC, test x$socket_dynamic = xtrue)
 AM_CONDITIONAL(USE_SOCKET_WIN, test x$socket_win = xtrue)
@@ -1698,6 +1721,7 @@ AC_CONFIG_FILES([
 	src/libstrongswan/plugins/agent/Makefile
 	src/libstrongswan/plugins/keychain/Makefile
 	src/libstrongswan/plugins/pkcs11/Makefile
+	src/libstrongswan/plugins/chapoly/Makefile
 	src/libstrongswan/plugins/ctr/Makefile
 	src/libstrongswan/plugins/ccm/Makefile
 	src/libstrongswan/plugins/gcm/Makefile
@@ -1713,6 +1737,7 @@ AC_CONFIG_FILES([
 	src/libhydra/plugins/kernel_pfroute/Makefile
 	src/libhydra/tests/Makefile
 	src/libipsec/Makefile
+	src/libipsec/tests/Makefile
 	src/libsimaka/Makefile
 	src/libtls/Makefile
 	src/libtls/tests/Makefile
@@ -1737,6 +1762,8 @@ AC_CONFIG_FILES([
 	src/libimcv/plugins/imv_attestation/Makefile
 	src/libimcv/plugins/imc_swid/Makefile
 	src/libimcv/plugins/imv_swid/Makefile
+	src/libimcv/plugins/imc_hcd/Makefile
+	src/libimcv/plugins/imv_hcd/Makefile
 	src/charon/Makefile
 	src/charon-nm/Makefile
 	src/charon-tkm/Makefile
@@ -1847,17 +1874,18 @@ AC_CONFIG_FILES([
 	man/ipsec.secrets.5
 	src/charon-cmd/charon-cmd.8
 	src/pki/man/pki.1
+	src/pki/man/pki---acert.1
+	src/pki/man/pki---dn.1
 	src/pki/man/pki---gen.1
 	src/pki/man/pki---issue.1
 	src/pki/man/pki---keyid.1
-	src/pki/man/pki---pkcs7.1
 	src/pki/man/pki---pkcs12.1
+	src/pki/man/pki---pkcs7.1
 	src/pki/man/pki---print.1
 	src/pki/man/pki---pub.1
 	src/pki/man/pki---req.1
 	src/pki/man/pki---self.1
 	src/pki/man/pki---signcrl.1
-	src/pki/man/pki---acert.1
 	src/pki/man/pki---verify.1
 	src/swanctl/swanctl.8
 	src/swanctl/swanctl.conf.5.head
diff --git a/man/ipsec.conf.5.in b/man/ipsec.conf.5.in
index 6501217..6ddb057 100644
--- a/man/ipsec.conf.5.in
+++ b/man/ipsec.conf.5.in
@@ -762,15 +762,24 @@ is configured the identity has to be confirmed by the certificate.
 
 Can be an IP address, a fully-qualified domain name, an email address or a
 Distinguished Name for which the ID type is determined automatically and the
-string is converted to the appropriate encoding. To enforce a specific identity
-type, a prefix may be used, followed by a colon (:). If the number sign (#)
-follows the colon, the remaining data is interpreted as hex encoding, otherwise
-the string is used as-is as the identification data. Note that this implies
-that no conversion is performed for non-string identities. For example,
+string is converted to the appropriate encoding. The rules for this conversion
+are described in IDENTITY PARSING below.
+
+In certain special situations the identity parsing above might be inadequate
+or produce the wrong result. Examples are the need to encode a FQDN as KEY_ID or
+the string parser being unable to produce the correct binary ASN.1 encoding of
+a certificate's DN.  For these situations it is possible to enforce a specific
+identity type and to provide the binary encoding of the identity. To do this a
+prefix may be used, followed by a colon (:). If the number sign (#) follows the
+colon, the remaining data is interpreted as hex encoding, otherwise the string
+is used as is as the identification data.
+.BR Note :
+The latter implies that no conversion is performed for non-string identities.
+For example,
 \fIipv4:10.0.0.1\fP does not create a valid ID_IPV4_ADDR IKE identity, as it
 does not get converted to binary 0x0a000001. Instead, one could use
 \fIipv4:#0a000001\fP to get a valid identity, but just using the implicit type
-with automatic conversion is usually simpler. The same applies to the ASN1
+with automatic conversion is usually simpler. The same applies to the ASN.1
 encoded types. The following prefixes are known:
 .BR ipv4 ,
 .BR ipv6 ,
@@ -1289,6 +1298,48 @@ and the value
 .B keep
 to reject new IKE_SA setups and keep the duplicate established earlier.
 
+.SH IDENTITY PARSING
+The type and binary encoding of identity strings specified in \fIleftid\fR
+are detected as follows:
+.IP \[bu]
+If the string value contains an equal sign (=) it is assumed to be a
+Distinguished Name, with RDNs separated by commas (,) \fIor\fR slashes (/ - the string
+must start with a slash to use this syntax). An attempt is made to create a
+binary ASN.1 encoding from this string. If that fails the type is set to KEY_ID
+with the literal string value adopted as encoding.
+.IP \[bu]
+If the string value contains an @ the type depends on the position of that
+character:
+.RS
+.IP \[bu]
+If the string begins with @# the type is set to KEY_ID and the string following
+that prefix is assumed to be the hex-encoded binary value of the identity.
+.IP \[bu]
+If the string begins with @@ the type is set to USER_FQDN and the encoding is
+the literal string after that prefix.
+.IP \[bu]
+If the string begins with @ the type is set to FQDN and the encoding is the
+literal string after that prefix.
+.IP \[bu]
+All remaining strings containing an @ are assumed to be of type USER_FQDN/RFC822
+with the literal string value as encoding.
+.RE
+.IP \[bu]
+If the value does not contain any @ or = characters it is parsed as follows:
+.RS
+.IP \[bu]
+If the value is an empty string, or equals %any[6], 0.0.0.0, ::, or * the
+type is set to ID_ANY, which matches any other identity.
+.IP \[bu]
+If the value contains a colon (:) it is assumed to be an IPv6 address. But if
+parsing the address and converting it to its binary encoding fails the type is
+set to KEY_ID and the encoding is the literal value.
+.IP \[bu]
+For all other strings an attempt at parsing them as IPv4 addresses is made. If
+that fails the type is set to FQDN and the literal value is adopted as
+encoding (this is where domain names and simple names end up).
+.RE
+
 .SH SA EXPIRY/REKEY
 The IKE SAs and IPsec SAs negotiated by the daemon can be configured to expire
 after a specific amount of time. For IPsec SAs this can also happen after a
@@ -1365,6 +1416,7 @@ must not exceed the original limit. For example, specifying
 .B margintime = 30m
 in the default configuration is a bad idea as there is a chance that the rekey
 time equals zero and, thus, rekeying gets disabled.
+
 .SH FILES
 .nf
 /etc/ipsec.conf
diff --git a/src/_updown/_updown.in b/src/_updown/_updown.in
index 4090fe0..6e7abca 100644
--- a/src/_updown/_updown.in
+++ b/src/_updown/_updown.in
@@ -71,7 +71,7 @@
 #       PLUTO_MY_SOURCEIP6_$i
 #              contains IPv4/IPv6 virtual IP received from a responder,
 #              $i enumerates from 1 to the number of IP per address family.
-#              PLUTO_MY_SOURCEIP is a legacy variable and equals to the first
+#              PLUTO_MY_SOURCEIP is a legacy variable and equal to the first
 #              virtual IP, IPv4 or IPv6.
 #
 #       PLUTO_MY_PROTOCOL
@@ -94,6 +94,14 @@
 #              the peer's own IP address / max (where  max  is  32
 #              for IPv4 and 128 for IPv6).
 #
+#       PLUTO_PEER_SOURCEIP
+#       PLUTO_PEER_SOURCEIP4_$i
+#       PLUTO_PEER_SOURCEIP6_$i
+#              contains IPv4/IPv6 virtual IP sent to an initiator,
+#              $i enumerates from 1 to the number of IP per address family.
+#              PLUTO_PEER_SOURCEIP is a legacy variable and equal to the first
+#              virtual IP, IPv4 or IPv6.
+#
 #       PLUTO_PEER_PROTOCOL
 #              is the IP protocol that will be transported.
 #
diff --git a/src/charon-cmd/cmd/cmd_connection.c b/src/charon-cmd/cmd/cmd_connection.c
index 2c0b7b9..0c6a504 100644
--- a/src/charon-cmd/cmd/cmd_connection.c
+++ b/src/charon-cmd/cmd/cmd_connection.c
@@ -434,7 +434,7 @@ static job_requeue_t initiate(private_cmd_connection_t *this)
 	child_cfg = create_child_cfg(this, peer_cfg);
 
 	if (charon->controller->initiate(charon->controller, peer_cfg, child_cfg,
-									 controller_cb_empty, NULL, 0) != SUCCESS)
+								controller_cb_empty, NULL, 0, FALSE) != SUCCESS)
 	{
 		terminate(pid);
 	}
diff --git a/src/charon-tkm/src/tkm/tkm_encoder.c~ b/src/charon-tkm/src/tkm/tkm_encoder.c~
deleted file mode 100644
index 145615f..0000000
--- a/src/charon-tkm/src/tkm/tkm_encoder.c~
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2013 Reto Buerki
- * Copyright (C) 2013 Adrian-Ken Rueegsegger
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * for more details.
- */
-
-#include <utils/debug.h>
-#include <asn1/asn1.h>
-#include <asn1/oid.h>
-
-#include "tkm_encoder.h"
-
-/**
- * Build the SHA1 hash of pubkey(info) ASN.1 data.
- */
-static bool hash_pubkey(chunk_t pubkey, chunk_t *hash)
-{
-	hasher_t *hasher;
-
-	hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
-	if (!hasher || !hasher->allocate_hash(hasher, pubkey, hash))
-	{
-		DBG1(DBG_LIB, "SHA1 hash algorithm not supported, "
-			 "fingerprinting failed");
-		DESTROY_IF(hasher);
-		chunk_free(&pubkey);
-		return FALSE;
-	}
-	hasher->destroy(hasher);
-	chunk_free(&pubkey);
-	return TRUE;
-}
-
-/**
- * Encode the public key blob into subjectPublicKeyInfo.
- */
-static bool build_pub_info(chunk_t *encoding, va_list args)
-{
-	chunk_t blob;
-
-	if (cred_encoding_args(args, CRED_PART_RSA_PUB_ASN1_DER, &blob,
-						   CRED_PART_END))
-	{
-		*encoding = asn1_wrap(ASN1_SEQUENCE, "mm",
-							  asn1_algorithmIdentifier(OID_RSA_ENCRYPTION),
-							  asn1_bitstring("c", blob, 0));
-		return TRUE;
-	}
-	return FALSE;
-}
-
-/**
- * Build the fingerprint of the subjectPublicKeyInfo object.
- */
-static bool build_info_sha1(chunk_t *encoding, va_list args)
-{
-	chunk_t pubkey;
-
-	if (build_pub_info(&pubkey, args))
-	{
-		return hash_pubkey(pubkey, encoding);
-	}
-	return FALSE;
-}
-
-/**
- * Build the fingerprint of the subjectPublicKey object.
- */
-static bool build_sha1(chunk_t *encoding, va_list args)
-{
-	chunk_t blob;
-
-	if (cred_encoding_args(args, CRED_PART_RSA_PUB_ASN1_DER, &blob,
-						   CRED_PART_END))
-	{
-		return hash_pubkey(chunk_clone(blob), encoding);
-	}
-	return FALSE;
-}
-
-/**
- * See header.
- */
-bool tkm_encoder_encode(cred_encoding_type_t type, chunk_t *encoding,
-						va_list args)
-{
-	switch (type)
-	{
-		case KEYID_PUBKEY_INFO_SHA1:
-			return build_info_sha1(encoding, args);
-		case KEYID_PUBKEY_SHA1:
-			return build_sha1(encoding, args);
-		default:
-			return FALSE;
-	}
-}
diff --git a/src/charon-tkm/tests/tests.c b/src/charon-tkm/tests/tests.c
index 669f4d5..ac152b6 100644
--- a/src/charon-tkm/tests/tests.c
+++ b/src/charon-tkm/tests/tests.c
@@ -36,8 +36,8 @@
 static test_configuration_t tests[] = {
 #define TEST_SUITE(x) \
 	{ .suite = x, },
-#define TEST_SUITE_DEPEND(x, type, args) \
-	{ .suite = x, .feature = PLUGIN_DEPENDS(type, args) },
+#define TEST_SUITE_DEPEND(x, type, ...) \
+	{ .suite = x, .feature = PLUGIN_DEPENDS(type, __VA_ARGS__) },
 #include "tests.h"
 	{ .suite = NULL, }
 };
diff --git a/src/conftest/actions.c b/src/conftest/actions.c
index 474672c..256b63d 100644
--- a/src/conftest/actions.c
+++ b/src/conftest/actions.c
@@ -65,7 +65,7 @@ static job_requeue_t initiate(char *config)
 	{
 		DBG1(DBG_CFG, "initiating IKE_SA for CHILD_SA config '%s'", config);
 		charon->controller->initiate(charon->controller, peer_cfg, child_cfg,
-									 NULL, NULL, 0);
+									 NULL, NULL, 0, FALSE);
 	}
 	else
 	{
diff --git a/src/include/Makefile.am b/src/include/Makefile.am
index 5de7131..0284c09 100644
--- a/src/include/Makefile.am
+++ b/src/include/Makefile.am
@@ -1,3 +1,2 @@
 EXTRA_DIST = linux/if_alg.h linux/ipsec.h linux/netlink.h linux/rtnetlink.h \
-             linux/pfkeyv2.h linux/udp.h linux/xfrm.h linux/types.h \
-             sys/queue.h
+             linux/pfkeyv2.h linux/udp.h linux/xfrm.h sys/queue.h
diff --git a/src/include/Makefile.in b/src/include/Makefile.in
index 64be6ac..e2c3cd0 100644
--- a/src/include/Makefile.in
+++ b/src/include/Makefile.in
@@ -343,8 +343,7 @@ 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/xfrm.h linux/types.h \
-             sys/queue.h
+             linux/pfkeyv2.h linux/udp.h linux/xfrm.h sys/queue.h
 
 all: all-am
 
diff --git a/src/include/linux/netlink.h b/src/include/linux/netlink.h
index 1aeee62..777a1b7 100644
--- a/src/include/linux/netlink.h
+++ b/src/include/linux/netlink.h
@@ -1,14 +1,15 @@
-#ifndef __LINUX_NETLINK_H
-#define __LINUX_NETLINK_H
+#ifndef _UAPI__LINUX_NETLINK_H
+#define _UAPI__LINUX_NETLINK_H
 
-#include <linux/socket.h> /* for sa_family_t */
+#include <linux/kernel.h>
+#include <linux/socket.h> /* for __kernel_sa_family_t */
 #include <linux/types.h>
 
 #define NETLINK_ROUTE		0	/* Routing/device hook				*/
-#define NETLINK_W1		1	/* 1-wire subsystem				*/
+#define NETLINK_UNUSED		1	/* Unused number				*/
 #define NETLINK_USERSOCK	2	/* Reserved for user mode socket protocols 	*/
-#define NETLINK_FIREWALL	3	/* Firewalling hook				*/
-#define NETLINK_INET_DIAG	4	/* INET socket monitoring			*/
+#define NETLINK_FIREWALL	3	/* Unused number, formerly ip_queue		*/
+#define NETLINK_SOCK_DIAG	4	/* socket monitoring				*/
 #define NETLINK_NFLOG		5	/* netfilter/iptables ULOG */
 #define NETLINK_XFRM		6	/* ipsec */
 #define NETLINK_SELINUX		7	/* SELinux event notifications */
@@ -21,24 +22,29 @@
 #define NETLINK_DNRTMSG		14	/* DECnet routing messages */
 #define NETLINK_KOBJECT_UEVENT	15	/* Kernel messages to userspace */
 #define NETLINK_GENERIC		16
+/* leave room for NETLINK_DM (DM Events) */
+#define NETLINK_SCSITRANSPORT	18	/* SCSI Transports */
+#define NETLINK_ECRYPTFS	19
+#define NETLINK_RDMA		20
+#define NETLINK_CRYPTO		21	/* Crypto layer */
+
+#define NETLINK_INET_DIAG	NETLINK_SOCK_DIAG
 
 #define MAX_LINKS 32
 
-struct sockaddr_nl
-{
-	sa_family_t	nl_family;	/* AF_NETLINK	*/
+struct sockaddr_nl {
+	__kernel_sa_family_t	nl_family;	/* AF_NETLINK	*/
 	unsigned short	nl_pad;		/* zero		*/
-	__u32		nl_pid;		/* process pid	*/
+	__u32		nl_pid;		/* port ID	*/
 	__u32		nl_groups;	/* multicast groups mask */
 };
 
-struct nlmsghdr
-{
+struct nlmsghdr {
 	__u32		nlmsg_len;	/* Length of message including header */
 	__u16		nlmsg_type;	/* Message content */
 	__u16		nlmsg_flags;	/* Additional flags */
 	__u32		nlmsg_seq;	/* Sequence number */
-	__u32		nlmsg_pid;	/* Sending process PID */
+	__u32		nlmsg_pid;	/* Sending process port ID */
 };
 
 /* Flags values */
@@ -47,6 +53,7 @@ struct nlmsghdr
 #define NLM_F_MULTI		2	/* Multipart message, terminated by NLMSG_DONE */
 #define NLM_F_ACK		4	/* Reply with ack, with zero or error code */
 #define NLM_F_ECHO		8	/* Echo this request 		*/
+#define NLM_F_DUMP_INTR		16	/* Dump was inconsistent due to sequence change */
 
 /* Modifiers to GET request */
 #define NLM_F_ROOT	0x100	/* specify tree	root	*/
@@ -69,10 +76,10 @@ struct nlmsghdr
    Check		NLM_F_EXCL
  */
 
-#define NLMSG_ALIGNTO	4
+#define NLMSG_ALIGNTO	4U
 #define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) )
 #define NLMSG_HDRLEN	 ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr)))
-#define NLMSG_LENGTH(len) ((len)+NLMSG_ALIGN(NLMSG_HDRLEN))
+#define NLMSG_LENGTH(len) ((len) + NLMSG_HDRLEN)
 #define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len))
 #define NLMSG_DATA(nlh)  ((void*)(((char*)nlh) + NLMSG_LENGTH(0)))
 #define NLMSG_NEXT(nlh,len)	 ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \
@@ -89,21 +96,54 @@ struct nlmsghdr
 
 #define NLMSG_MIN_TYPE		0x10	/* < 0x10: reserved control messages */
 
-struct nlmsgerr
-{
+struct nlmsgerr {
 	int		error;
 	struct nlmsghdr msg;
 };
 
-#define NETLINK_ADD_MEMBERSHIP	1
-#define NETLINK_DROP_MEMBERSHIP	2
-#define NETLINK_PKTINFO		3
-
-struct nl_pktinfo
-{
+#define NETLINK_ADD_MEMBERSHIP		1
+#define NETLINK_DROP_MEMBERSHIP		2
+#define NETLINK_PKTINFO			3
+#define NETLINK_BROADCAST_ERROR		4
+#define NETLINK_NO_ENOBUFS		5
+#define NETLINK_RX_RING			6
+#define NETLINK_TX_RING			7
+#define NETLINK_LISTEN_ALL_NSID		8
+#define NETLINK_LIST_MEMBERSHIPS	9
+
+struct nl_pktinfo {
 	__u32	group;
 };
 
+struct nl_mmap_req {
+	unsigned int	nm_block_size;
+	unsigned int	nm_block_nr;
+	unsigned int	nm_frame_size;
+	unsigned int	nm_frame_nr;
+};
+
+struct nl_mmap_hdr {
+	unsigned int	nm_status;
+	unsigned int	nm_len;
+	__u32		nm_group;
+	/* credentials */
+	__u32		nm_pid;
+	__u32		nm_uid;
+	__u32		nm_gid;
+};
+
+enum nl_mmap_status {
+	NL_MMAP_STATUS_UNUSED,
+	NL_MMAP_STATUS_RESERVED,
+	NL_MMAP_STATUS_VALID,
+	NL_MMAP_STATUS_COPY,
+	NL_MMAP_STATUS_SKIP,
+};
+
+#define NL_MMAP_MSG_ALIGNMENT		NLMSG_ALIGNTO
+#define NL_MMAP_MSG_ALIGN(sz)		__ALIGN_KERNEL(sz, NL_MMAP_MSG_ALIGNMENT)
+#define NL_MMAP_HDRLEN			NL_MMAP_MSG_ALIGN(sizeof(struct nl_mmap_hdr))
+
 #define NET_MAJOR 36		/* Major 36 is reserved for networking 						*/
 
 enum {
@@ -120,122 +160,28 @@ enum {
  *  <-------------- nlattr->nla_len -------------->
  */
 
-struct nlattr
-{
+struct nlattr {
 	__u16           nla_len;
 	__u16           nla_type;
 };
 
-#define NLA_ALIGNTO		4
-#define NLA_ALIGN(len)		(((len) + NLA_ALIGNTO - 1) & ~(NLA_ALIGNTO - 1))
-#define NLA_HDRLEN		((int) NLA_ALIGN(sizeof(struct nlattr)))
-
-#ifdef __KERNEL__
-
-#include <linux/capability.h>
-#include <linux/skbuff.h>
-
-struct netlink_skb_parms
-{
-	struct ucred		creds;		/* Skb credentials	*/
-	__u32			pid;
-	__u32			dst_pid;
-	__u32			dst_group;
-	kernel_cap_t		eff_cap;
-	__u32			loginuid;	/* Login (audit) uid */
-	__u32			sid;		/* SELinux security id */
-};
-
-#define NETLINK_CB(skb)		(*(struct netlink_skb_parms*)&((skb)->cb))
-#define NETLINK_CREDS(skb)	(&NETLINK_CB((skb)).creds)
-
-
-extern struct sock *netlink_kernel_create(int unit, unsigned int groups, void (*input)(struct sock *sk, int len), struct module *module);
-extern void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err);
-extern int netlink_has_listeners(struct sock *sk, unsigned int group);
-extern int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 pid, int nonblock);
-extern int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, __u32 pid,
-			     __u32 group, gfp_t allocation);
-extern void netlink_set_err(struct sock *ssk, __u32 pid, __u32 group, int code);
-extern int netlink_register_notifier(struct notifier_block *nb);
-extern int netlink_unregister_notifier(struct notifier_block *nb);
-
-/* finegrained unicast helpers: */
-struct sock *netlink_getsockbyfilp(struct file *filp);
-int netlink_attachskb(struct sock *sk, struct sk_buff *skb, int nonblock,
-		long timeo, struct sock *ssk);
-void netlink_detachskb(struct sock *sk, struct sk_buff *skb);
-int netlink_sendskb(struct sock *sk, struct sk_buff *skb, int protocol);
-
 /*
- *	skb should fit one page. This choice is good for headerless malloc.
+ * nla_type (16 bits)
+ * +---+---+-------------------------------+
+ * | N | O | Attribute Type                |
+ * +---+---+-------------------------------+
+ * N := Carries nested attributes
+ * O := Payload stored in network byte order
+ *
+ * Note: The N and O flag are mutually exclusive.
  */
-#define NLMSG_GOODORDER 0
-#define NLMSG_GOODSIZE (SKB_MAX_ORDER(0, NLMSG_GOODORDER))
-
-
-struct netlink_callback
-{
-	struct sk_buff	*skb;
-	struct nlmsghdr	*nlh;
-	int		(*dump)(struct sk_buff * skb, struct netlink_callback *cb);
-	int		(*done)(struct netlink_callback *cb);
-	int		family;
-	long		args[5];
-};
-
-struct netlink_notify
-{
-	int pid;
-	int protocol;
-};
-
-static __inline__ struct nlmsghdr *
-__nlmsg_put(struct sk_buff *skb, __u32 pid, __u32 seq, int type, int len, int flags)
-{
-	struct nlmsghdr *nlh;
-	int size = NLMSG_LENGTH(len);
-
-	nlh = (struct nlmsghdr*)skb_put(skb, NLMSG_ALIGN(size));
-	nlh->nlmsg_type = type;
-	nlh->nlmsg_len = size;
-	nlh->nlmsg_flags = flags;
-	nlh->nlmsg_pid = pid;
-	nlh->nlmsg_seq = seq;
-	memset(NLMSG_DATA(nlh) + len, 0, NLMSG_ALIGN(size) - size);
-	return nlh;
-}
-
-#define NLMSG_NEW(skb, pid, seq, type, len, flags) \
-({	if (skb_tailroom(skb) < (int)NLMSG_SPACE(len)) \
-		goto nlmsg_failure; \
-	__nlmsg_put(skb, pid, seq, type, len, flags); })
+#define NLA_F_NESTED		(1 << 15)
+#define NLA_F_NET_BYTEORDER	(1 << 14)
+#define NLA_TYPE_MASK		~(NLA_F_NESTED | NLA_F_NET_BYTEORDER)
 
-#define NLMSG_PUT(skb, pid, seq, type, len) \
-	NLMSG_NEW(skb, pid, seq, type, len, 0)
-
-#define NLMSG_NEW_ANSWER(skb, cb, type, len, flags) \
-	NLMSG_NEW(skb, NETLINK_CB((cb)->skb).pid, \
-		  (cb)->nlh->nlmsg_seq, type, len, flags)
-
-#define NLMSG_END(skb, nlh) \
-({	(nlh)->nlmsg_len = (skb)->tail - (unsigned char *) (nlh); \
-	(skb)->len; })
-
-#define NLMSG_CANCEL(skb, nlh) \
-({	skb_trim(skb, (unsigned char *) (nlh) - (skb)->data); \
-	-1; })
-
-extern int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
-			      struct nlmsghdr *nlh,
-			      int (*dump)(struct sk_buff *skb, struct netlink_callback*),
-			      int (*done)(struct netlink_callback*));
-
-
-#define NL_NONROOT_RECV 0x1
-#define NL_NONROOT_SEND 0x2
-extern void netlink_set_nonroot(int protocol, unsigned flag);
+#define NLA_ALIGNTO		4
+#define NLA_ALIGN(len)		(((len) + NLA_ALIGNTO - 1) & ~(NLA_ALIGNTO - 1))
+#define NLA_HDRLEN		((int) NLA_ALIGN(sizeof(struct nlattr)))
 
-#endif /* __KERNEL__ */
 
-#endif	/* __LINUX_NETLINK_H */
+#endif /* _UAPI__LINUX_NETLINK_H */
diff --git a/src/include/linux/rtnetlink.h b/src/include/linux/rtnetlink.h
index 56835d8..56f36a1 100644
--- a/src/include/linux/rtnetlink.h
+++ b/src/include/linux/rtnetlink.h
@@ -1,7 +1,17 @@
-#ifndef __LINUX_RTNETLINK_H
-#define __LINUX_RTNETLINK_H
+#ifndef _UAPI__LINUX_RTNETLINK_H
+#define _UAPI__LINUX_RTNETLINK_H
 
 #include "netlink.h"
+#include <linux/if_link.h>
+#include <linux/if_addr.h>
+#include <linux/neighbour.h>
+
+/* rtnetlink families. Values up to 127 are reserved for real address
+ * families, values above 128 may be used arbitrarily.
+ */
+#define RTNL_FAMILY_IPMR		128
+#define RTNL_FAMILY_IP6MR		129
+#define RTNL_FAMILY_MAX			129
 
 /****
  *		Routing/neighbour discovery messages.
@@ -80,8 +90,6 @@ enum {
 
 	RTM_NEWPREFIX	= 52,
 #define RTM_NEWPREFIX	RTM_NEWPREFIX
-	RTM_GETPREFIX	= 54,
-#define RTM_GETPREFIX	RTM_GETPREFIX
 
 	RTM_GETMULTICAST = 58,
 #define RTM_GETMULTICAST RTM_GETMULTICAST
@@ -96,6 +104,40 @@ enum {
 	RTM_SETNEIGHTBL,
 #define RTM_SETNEIGHTBL	RTM_SETNEIGHTBL
 
+	RTM_NEWNDUSEROPT = 68,
+#define RTM_NEWNDUSEROPT RTM_NEWNDUSEROPT
+
+	RTM_NEWADDRLABEL = 72,
+#define RTM_NEWADDRLABEL RTM_NEWADDRLABEL
+	RTM_DELADDRLABEL,
+#define RTM_DELADDRLABEL RTM_DELADDRLABEL
+	RTM_GETADDRLABEL,
+#define RTM_GETADDRLABEL RTM_GETADDRLABEL
+
+	RTM_GETDCB = 78,
+#define RTM_GETDCB RTM_GETDCB
+	RTM_SETDCB,
+#define RTM_SETDCB RTM_SETDCB
+
+	RTM_NEWNETCONF = 80,
+#define RTM_NEWNETCONF RTM_NEWNETCONF
+	RTM_GETNETCONF = 82,
+#define RTM_GETNETCONF RTM_GETNETCONF
+
+	RTM_NEWMDB = 84,
+#define RTM_NEWMDB RTM_NEWMDB
+	RTM_DELMDB = 85,
+#define RTM_DELMDB RTM_DELMDB
+	RTM_GETMDB = 86,
+#define RTM_GETMDB RTM_GETMDB
+
+	RTM_NEWNSID = 88,
+#define RTM_NEWNSID RTM_NEWNSID
+	RTM_DELNSID = 89,
+#define RTM_DELNSID RTM_DELNSID
+	RTM_GETNSID = 90,
+#define RTM_GETNSID RTM_GETNSID
+
 	__RTM_MAX,
 #define RTM_MAX		(((__RTM_MAX + 3) & ~3) - 1)
 };
@@ -110,8 +152,7 @@ enum {
    with attribute type.
  */
 
-struct rtattr
-{
+struct rtattr {
 	unsigned short	rta_len;
 	unsigned short	rta_type;
 };
@@ -137,8 +178,7 @@ struct rtattr
  *		Definitions used in routing table administration.
  ****/
 
-struct rtmsg
-{
+struct rtmsg {
 	unsigned char		rtm_family;
 	unsigned char		rtm_dst_len;
 	unsigned char		rtm_src_len;
@@ -154,8 +194,7 @@ struct rtmsg
 
 /* rtm_type */
 
-enum
-{
+enum {
 	RTN_UNSPEC,
 	RTN_UNICAST,		/* Gateway or direct route	*/
 	RTN_LOCAL,		/* Accept locally		*/
@@ -200,6 +239,9 @@ enum
 #define RTPROT_DNROUTED	13	/* DECnet routing daemon */
 #define RTPROT_XORP	14	/* XORP */
 #define RTPROT_NTK	15	/* Netsukuku */
+#define RTPROT_DHCP	16      /* DHCP client */
+#define RTPROT_MROUTED	17      /* Multicast daemon */
+#define RTPROT_BABEL	42      /* Babel daemon */
 
 /* rtm_scope
 
@@ -212,8 +254,7 @@ enum
    could be assigned a value between UNIVERSE and LINK.
 */
 
-enum rt_scope_t
-{
+enum rt_scope_t {
 	RT_SCOPE_UNIVERSE=0,
 /* User defined values  */
 	RT_SCOPE_SITE=200,
@@ -231,23 +272,20 @@ enum rt_scope_t
 
 /* Reserved table identifiers */
 
-enum rt_class_t
-{
+enum rt_class_t {
 	RT_TABLE_UNSPEC=0,
 /* User defined values */
+	RT_TABLE_COMPAT=252,
 	RT_TABLE_DEFAULT=253,
 	RT_TABLE_MAIN=254,
 	RT_TABLE_LOCAL=255,
-	__RT_TABLE_MAX
+	RT_TABLE_MAX=0xFFFFFFFF
 };
-#define RT_TABLE_MAX (__RT_TABLE_MAX - 1)
-
 
 
 /* Routing message attributes */
 
-enum rtattr_type_t
-{
+enum rtattr_type_t {
 	RTA_UNSPEC,
 	RTA_DST,
 	RTA_SRC,
@@ -258,12 +296,17 @@ enum rtattr_type_t
 	RTA_PREFSRC,
 	RTA_METRICS,
 	RTA_MULTIPATH,
-	RTA_PROTOINFO,
+	RTA_PROTOINFO, /* no longer used */
 	RTA_FLOW,
 	RTA_CACHEINFO,
-	RTA_SESSION,
-	RTA_MP_ALGO,
+	RTA_SESSION, /* no longer used */
+	RTA_MP_ALGO, /* no longer used */
 	RTA_TABLE,
+	RTA_MARK,
+	RTA_MFC_STATS,
+	RTA_VIA,
+	RTA_NEWDST,
+	RTA_PREF,
 	__RTA_MAX
 };
 
@@ -281,8 +324,7 @@ enum rtattr_type_t
  * and rtt for different paths from multipath.
  */
 
-struct rtnexthop
-{
+struct rtnexthop {
 	unsigned short		rtnh_len;
 	unsigned char		rtnh_flags;
 	unsigned char		rtnh_hops;
@@ -294,6 +336,10 @@ struct rtnexthop
 #define RTNH_F_DEAD		1	/* Nexthop is dead (used by multipath)	*/
 #define RTNH_F_PERVASIVE	2	/* Do recursive gateway lookup	*/
 #define RTNH_F_ONLINK		4	/* Gateway is forced on link	*/
+#define RTNH_F_OFFLOAD		8	/* offloaded route */
+#define RTNH_F_LINKDOWN		16	/* carrier-down on nexthop */
+
+#define RTNH_COMPARE_MASK	(RTNH_F_DEAD | RTNH_F_LINKDOWN)
 
 /* Macros to handle hexthops */
 
@@ -306,10 +352,15 @@ struct rtnexthop
 #define RTNH_SPACE(len)	RTNH_ALIGN(RTNH_LENGTH(len))
 #define RTNH_DATA(rtnh)   ((struct rtattr*)(((char*)(rtnh)) + RTNH_LENGTH(0)))
 
+/* RTA_VIA */
+struct rtvia {
+	__kernel_sa_family_t	rtvia_family;
+	__u8			rtvia_addr[0];
+};
+
 /* RTM_CACHEINFO */
 
-struct rta_cacheinfo
-{
+struct rta_cacheinfo {
 	__u32	rta_clntref;
 	__u32	rta_lastuse;
 	__s32	rta_expires;
@@ -324,8 +375,7 @@ struct rta_cacheinfo
 
 /* RTM_METRICS --- array of struct rtattr with types of RTAX_* */
 
-enum
-{
+enum {
 	RTAX_UNSPEC,
 #define RTAX_UNSPEC RTAX_UNSPEC
 	RTAX_LOCK,
@@ -352,6 +402,14 @@ enum
 #define RTAX_INITCWND RTAX_INITCWND
 	RTAX_FEATURES,
 #define RTAX_FEATURES RTAX_FEATURES
+	RTAX_RTO_MIN,
+#define RTAX_RTO_MIN RTAX_RTO_MIN
+	RTAX_INITRWND,
+#define RTAX_INITRWND RTAX_INITRWND
+	RTAX_QUICKACK,
+#define RTAX_QUICKACK RTAX_QUICKACK
+	RTAX_CC_ALGO,
+#define RTAX_CC_ALGO RTAX_CC_ALGO
 	__RTAX_MAX
 };
 
@@ -362,8 +420,7 @@ enum
 #define RTAX_FEATURE_TIMESTAMP	0x00000004
 #define RTAX_FEATURE_ALLFRAG	0x00000008
 
-struct rta_session
-{
+struct rta_session {
 	__u8	proto;
 	__u8	pad1;
 	__u16	pad2;
@@ -384,232 +441,17 @@ struct rta_session
 	} u;
 };
 
-
-/*********************************************************
- *		Interface address.
- ****/
-
-struct ifaddrmsg
-{
-	unsigned char	ifa_family;
-	unsigned char	ifa_prefixlen;	/* The prefix length		*/
-	unsigned char	ifa_flags;	/* Flags			*/
-	unsigned char	ifa_scope;	/* See above			*/
-	int		ifa_index;	/* Link index			*/
-};
-
-enum
-{
-	IFA_UNSPEC,
-	IFA_ADDRESS,
-	IFA_LOCAL,
-	IFA_LABEL,
-	IFA_BROADCAST,
-	IFA_ANYCAST,
-	IFA_CACHEINFO,
-	IFA_MULTICAST,
-	__IFA_MAX
-};
-
-#define IFA_MAX (__IFA_MAX - 1)
-
-/* ifa_flags */
-
-#define IFA_F_SECONDARY		0x01
-#define IFA_F_TEMPORARY		IFA_F_SECONDARY
-
-#define IFA_F_DEPRECATED	0x20
-#define IFA_F_TENTATIVE		0x40
-#define IFA_F_PERMANENT		0x80
-
-struct ifa_cacheinfo
-{
-	__u32	ifa_prefered;
-	__u32	ifa_valid;
-	__u32	cstamp; /* created timestamp, hundredths of seconds */
-	__u32	tstamp; /* updated timestamp, hundredths of seconds */
-};
-
-
-#define IFA_RTA(r)  ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))))
-#define IFA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifaddrmsg))
-
-/*
-   Important comment:
-   IFA_ADDRESS is prefix address, rather than local interface address.
-   It makes no difference for normally configured broadcast interfaces,
-   but for point-to-point IFA_ADDRESS is DESTINATION address,
-   local address is supplied in IFA_LOCAL attribute.
- */
-
-/**************************************************************
- *		Neighbour discovery.
- ****/
-
-struct ndmsg
-{
-	unsigned char	ndm_family;
-	unsigned char	ndm_pad1;
-	unsigned short	ndm_pad2;
-	int		ndm_ifindex;	/* Link index			*/
-	__u16		ndm_state;
-	__u8		ndm_flags;
-	__u8		ndm_type;
-};
-
-enum
-{
-	NDA_UNSPEC,
-	NDA_DST,
-	NDA_LLADDR,
-	NDA_CACHEINFO,
-	NDA_PROBES,
-	__NDA_MAX
-};
-
-#define NDA_MAX (__NDA_MAX - 1)
-
-#define NDA_RTA(r)  ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg))))
-#define NDA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ndmsg))
-
-/*
- *	Neighbor Cache Entry Flags
- */
-
-#define NTF_PROXY	0x08	/* == ATF_PUBL */
-#define NTF_ROUTER	0x80
-
-/*
- *	Neighbor Cache Entry States.
- */
-
-#define NUD_INCOMPLETE	0x01
-#define NUD_REACHABLE	0x02
-#define NUD_STALE	0x04
-#define NUD_DELAY	0x08
-#define NUD_PROBE	0x10
-#define NUD_FAILED	0x20
-
-/* Dummy states */
-#define NUD_NOARP	0x40
-#define NUD_PERMANENT	0x80
-#define NUD_NONE	0x00
-
-
-struct nda_cacheinfo
-{
-	__u32		ndm_confirmed;
-	__u32		ndm_used;
-	__u32		ndm_updated;
-	__u32		ndm_refcnt;
-};
-
-
-/*****************************************************************
- *		Neighbour tables specific messages.
- *
- * To retrieve the neighbour tables send RTM_GETNEIGHTBL with the
- * NLM_F_DUMP flag set. Every neighbour table configuration is
- * spread over multiple messages to avoid running into message
- * size limits on systems with many interfaces. The first message
- * in the sequence transports all not device specific data such as
- * statistics, configuration, and the default parameter set.
- * This message is followed by 0..n messages carrying device
- * specific parameter sets.
- * Although the ordering should be sufficient, NDTA_NAME can be
- * used to identify sequences. The initial message can be identified
- * by checking for NDTA_CONFIG. The device specific messages do
- * not contain this TLV but have NDTPA_IFINDEX set to the
- * corresponding interface index.
- *
- * To change neighbour table attributes, send RTM_SETNEIGHTBL
- * with NDTA_NAME set. Changeable attribute include NDTA_THRESH[1-3],
- * NDTA_GC_INTERVAL, and all TLVs in NDTA_PARMS unless marked
- * otherwise. Device specific parameter sets can be changed by
- * setting NDTPA_IFINDEX to the interface index of the corresponding
- * device.
- ****/
-
-struct ndt_stats
-{
-	__u64		ndts_allocs;
-	__u64		ndts_destroys;
-	__u64		ndts_hash_grows;
-	__u64		ndts_res_failed;
-	__u64		ndts_lookups;
-	__u64		ndts_hits;
-	__u64		ndts_rcv_probes_mcast;
-	__u64		ndts_rcv_probes_ucast;
-	__u64		ndts_periodic_gc_runs;
-	__u64		ndts_forced_gc_runs;
-};
-
-enum {
-	NDTPA_UNSPEC,
-	NDTPA_IFINDEX,			/* __u32, unchangeable */
-	NDTPA_REFCNT,			/* __u32, read-only */
-	NDTPA_REACHABLE_TIME,		/* __u64, read-only, msecs */
-	NDTPA_BASE_REACHABLE_TIME,	/* __u64, msecs */
-	NDTPA_RETRANS_TIME,		/* __u64, msecs */
-	NDTPA_GC_STALETIME,		/* __u64, msecs */
-	NDTPA_DELAY_PROBE_TIME,		/* __u64, msecs */
-	NDTPA_QUEUE_LEN,		/* __u32 */
-	NDTPA_APP_PROBES,		/* __u32 */
-	NDTPA_UCAST_PROBES,		/* __u32 */
-	NDTPA_MCAST_PROBES,		/* __u32 */
-	NDTPA_ANYCAST_DELAY,		/* __u64, msecs */
-	NDTPA_PROXY_DELAY,		/* __u64, msecs */
-	NDTPA_PROXY_QLEN,		/* __u32 */
-	NDTPA_LOCKTIME,			/* __u64, msecs */
-	__NDTPA_MAX
-};
-#define NDTPA_MAX (__NDTPA_MAX - 1)
-
-struct ndtmsg
-{
-	__u8		ndtm_family;
-	__u8		ndtm_pad1;
-	__u16		ndtm_pad2;
-};
-
-struct ndt_config
-{
-	__u16		ndtc_key_len;
-	__u16		ndtc_entry_size;
-	__u32		ndtc_entries;
-	__u32		ndtc_last_flush;	/* delta to now in msecs */
-	__u32		ndtc_last_rand;		/* delta to now in msecs */
-	__u32		ndtc_hash_rnd;
-	__u32		ndtc_hash_mask;
-	__u32		ndtc_hash_chain_gc;
-	__u32		ndtc_proxy_qlen;
-};
-
-enum {
-	NDTA_UNSPEC,
-	NDTA_NAME,			/* char *, unchangeable */
-	NDTA_THRESH1,			/* __u32 */
-	NDTA_THRESH2,			/* __u32 */
-	NDTA_THRESH3,			/* __u32 */
-	NDTA_CONFIG,			/* struct ndt_config, read-only */
-	NDTA_PARMS,			/* nested TLV NDTPA_* */
-	NDTA_STATS,			/* struct ndt_stats, read-only */
-	NDTA_GC_INTERVAL,		/* __u64, msecs */
-	__NDTA_MAX
+struct rta_mfc_stats {
+	__u64	mfcs_packets;
+	__u64	mfcs_bytes;
+	__u64	mfcs_wrong_if;
 };
-#define NDTA_MAX (__NDTA_MAX - 1)
-
-#define NDTA_RTA(r) ((struct rtattr*)(((char*)(r)) + \
-		     NLMSG_ALIGN(sizeof(struct ndtmsg))))
-#define NDTA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ndtmsg))
-
 
 /****
  *		General form of address family dependent message.
  ****/
 
-struct rtgenmsg
-{
+struct rtgenmsg {
 	unsigned char		rtgen_family;
 };
 
@@ -622,8 +464,7 @@ struct rtgenmsg
  * on network protocol.
  */
 
-struct ifinfomsg
-{
+struct ifinfomsg {
 	unsigned char	ifi_family;
 	unsigned char	__ifi_pad;
 	unsigned short	ifi_type;		/* ARPHRD_* */
@@ -636,8 +477,7 @@ struct ifinfomsg
  *		prefix information
  ****/
 
-struct prefixmsg
-{
+struct prefixmsg {
 	unsigned char	prefix_family;
 	unsigned char	prefix_pad1;
 	unsigned short	prefix_pad2;
@@ -658,151 +498,17 @@ enum
 
 #define PREFIX_MAX	(__PREFIX_MAX - 1)
 
-struct prefix_cacheinfo
-{
+struct prefix_cacheinfo {
 	__u32	preferred_time;
 	__u32	valid_time;
 };
 
-/* The struct should be in sync with struct net_device_stats */
-struct rtnl_link_stats
-{
-	__u32	rx_packets;		/* total packets received	*/
-	__u32	tx_packets;		/* total packets transmitted	*/
-	__u32	rx_bytes;		/* total bytes received 	*/
-	__u32	tx_bytes;		/* total bytes transmitted	*/
-	__u32	rx_errors;		/* bad packets received		*/
-	__u32	tx_errors;		/* packet transmit problems	*/
-	__u32	rx_dropped;		/* no space in linux buffers	*/
-	__u32	tx_dropped;		/* no space available in linux	*/
-	__u32	multicast;		/* multicast packets received	*/
-	__u32	collisions;
-
-	/* detailed rx_errors: */
-	__u32	rx_length_errors;
-	__u32	rx_over_errors;		/* receiver ring buff overflow	*/
-	__u32	rx_crc_errors;		/* recved pkt with crc error	*/
-	__u32	rx_frame_errors;	/* recv'd frame alignment error */
-	__u32	rx_fifo_errors;		/* recv'r fifo overrun		*/
-	__u32	rx_missed_errors;	/* receiver missed packet	*/
-
-	/* detailed tx_errors */
-	__u32	tx_aborted_errors;
-	__u32	tx_carrier_errors;
-	__u32	tx_fifo_errors;
-	__u32	tx_heartbeat_errors;
-	__u32	tx_window_errors;
-
-	/* for cslip etc */
-	__u32	rx_compressed;
-	__u32	tx_compressed;
-};
-
-/* The struct should be in sync with struct ifmap */
-struct rtnl_link_ifmap
-{
-	__u64	mem_start;
-	__u64	mem_end;
-	__u64	base_addr;
-	__u16	irq;
-	__u8	dma;
-	__u8	port;
-};
-
-enum
-{
-	IFLA_UNSPEC,
-	IFLA_ADDRESS,
-	IFLA_BROADCAST,
-	IFLA_IFNAME,
-	IFLA_MTU,
-	IFLA_LINK,
-	IFLA_QDISC,
-	IFLA_STATS,
-	IFLA_COST,
-#define IFLA_COST IFLA_COST
-	IFLA_PRIORITY,
-#define IFLA_PRIORITY IFLA_PRIORITY
-	IFLA_MASTER,
-#define IFLA_MASTER IFLA_MASTER
-	IFLA_WIRELESS,		/* Wireless Extension event - see wireless.h */
-#define IFLA_WIRELESS IFLA_WIRELESS
-	IFLA_PROTINFO,		/* Protocol specific information for a link */
-#define IFLA_PROTINFO IFLA_PROTINFO
-	IFLA_TXQLEN,
-#define IFLA_TXQLEN IFLA_TXQLEN
-	IFLA_MAP,
-#define IFLA_MAP IFLA_MAP
-	IFLA_WEIGHT,
-#define IFLA_WEIGHT IFLA_WEIGHT
-	IFLA_OPERSTATE,
-	IFLA_LINKMODE,
-	__IFLA_MAX
-};
-
-
-#define IFLA_MAX (__IFLA_MAX - 1)
-
-#define IFLA_RTA(r)  ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg))))
-#define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg))
-
-/* ifi_flags.
-
-   IFF_* flags.
-
-   The only change is:
-   IFF_LOOPBACK, IFF_BROADCAST and IFF_POINTOPOINT are
-   more not changeable by user. They describe link media
-   characteristics and set by device driver.
-
-   Comments:
-   - Combination IFF_BROADCAST|IFF_POINTOPOINT is invalid
-   - If neither of these three flags are set;
-     the interface is NBMA.
-
-   - IFF_MULTICAST does not mean anything special:
-   multicasts can be used on all not-NBMA links.
-   IFF_MULTICAST means that this media uses special encapsulation
-   for multicast frames. Apparently, all IFF_POINTOPOINT and
-   IFF_BROADCAST devices are able to use multicasts too.
- */
-
-/* IFLA_LINK.
-   For usual devices it is equal ifi_index.
-   If it is a "virtual interface" (f.e. tunnel), ifi_link
-   can point to real physical interface (f.e. for bandwidth calculations),
-   or maybe 0, what means, that real media is unknown (usual
-   for IPIP tunnels, when route to endpoint is allowed to change)
- */
-
-/* Subtype attributes for IFLA_PROTINFO */
-enum
-{
-	IFLA_INET6_UNSPEC,
-	IFLA_INET6_FLAGS,	/* link flags			*/
-	IFLA_INET6_CONF,	/* sysctl parameters		*/
-	IFLA_INET6_STATS,	/* statistics			*/
-	IFLA_INET6_MCAST,	/* MC things. What of them?	*/
-	IFLA_INET6_CACHEINFO,	/* time values and max reasm size */
-	__IFLA_INET6_MAX
-};
-
-#define IFLA_INET6_MAX	(__IFLA_INET6_MAX - 1)
-
-struct ifla_cacheinfo
-{
-	__u32	max_reasm_len;
-	__u32	tstamp;		/* ipv6InterfaceTable updated timestamp */
-	__u32	reachable_time;
-	__u32	retrans_time;
-};
 
 /*****************************************************************
  *		Traffic control messages.
  ****/
 
-struct tcmsg
-{
+struct tcmsg {
 	unsigned char	tcm_family;
 	unsigned char	tcm__pad1;
 	unsigned short	tcm__pad2;
@@ -812,8 +518,7 @@ struct tcmsg
 	__u32		tcm_info;
 };
 
-enum
-{
+enum {
 	TCA_UNSPEC,
 	TCA_KIND,
 	TCA_OPTIONS,
@@ -822,6 +527,7 @@ enum
 	TCA_RATE,
 	TCA_FCNT,
 	TCA_STATS2,
+	TCA_STAB,
 	__TCA_MAX
 };
 
@@ -830,6 +536,30 @@ enum
 #define TCA_RTA(r)  ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct tcmsg))))
 #define TCA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct tcmsg))
 
+/********************************************************************
+ *		Neighbor Discovery userland options
+ ****/
+
+struct nduseroptmsg {
+	unsigned char	nduseropt_family;
+	unsigned char	nduseropt_pad1;
+	unsigned short	nduseropt_opts_len;	/* Total length of options */
+	int		nduseropt_ifindex;
+	__u8		nduseropt_icmp_type;
+	__u8		nduseropt_icmp_code;
+	unsigned short	nduseropt_pad2;
+	unsigned int	nduseropt_pad3;
+	/* Followed by one or more ND options */
+};
+
+enum {
+	NDUSEROPT_UNSPEC,
+	NDUSEROPT_SRCADDR,
+	__NDUSEROPT_MAX
+};
+
+#define NDUSEROPT_MAX	(__NDUSEROPT_MAX - 1)
+
 #ifndef __KERNEL__
 /* RTnetlink multicast groups - backwards compatibility for userspace */
 #define RTMGRP_LINK		1
@@ -886,17 +616,37 @@ enum rtnetlink_groups {
 	RTNLGRP_NOP2,
 	RTNLGRP_DECnet_ROUTE,
 #define RTNLGRP_DECnet_ROUTE	RTNLGRP_DECnet_ROUTE
-	RTNLGRP_NOP3,
+	RTNLGRP_DECnet_RULE,
+#define RTNLGRP_DECnet_RULE	RTNLGRP_DECnet_RULE
 	RTNLGRP_NOP4,
 	RTNLGRP_IPV6_PREFIX,
 #define RTNLGRP_IPV6_PREFIX	RTNLGRP_IPV6_PREFIX
+	RTNLGRP_IPV6_RULE,
+#define RTNLGRP_IPV6_RULE	RTNLGRP_IPV6_RULE
+	RTNLGRP_ND_USEROPT,
+#define RTNLGRP_ND_USEROPT	RTNLGRP_ND_USEROPT
+	RTNLGRP_PHONET_IFADDR,
+#define RTNLGRP_PHONET_IFADDR	RTNLGRP_PHONET_IFADDR
+	RTNLGRP_PHONET_ROUTE,
+#define RTNLGRP_PHONET_ROUTE	RTNLGRP_PHONET_ROUTE
+	RTNLGRP_DCB,
+#define RTNLGRP_DCB		RTNLGRP_DCB
+	RTNLGRP_IPV4_NETCONF,
+#define RTNLGRP_IPV4_NETCONF	RTNLGRP_IPV4_NETCONF
+	RTNLGRP_IPV6_NETCONF,
+#define RTNLGRP_IPV6_NETCONF	RTNLGRP_IPV6_NETCONF
+	RTNLGRP_MDB,
+#define RTNLGRP_MDB		RTNLGRP_MDB
+	RTNLGRP_MPLS_ROUTE,
+#define RTNLGRP_MPLS_ROUTE	RTNLGRP_MPLS_ROUTE
+	RTNLGRP_NSID,
+#define RTNLGRP_NSID		RTNLGRP_NSID
 	__RTNLGRP_MAX
 };
 #define RTNLGRP_MAX	(__RTNLGRP_MAX - 1)
 
 /* TC action piece */
-struct tcamsg
-{
+struct tcamsg {
 	unsigned char	tca_family;
 	unsigned char	tca__pad1;
 	unsigned short	tca__pad2;
@@ -906,168 +656,13 @@ struct tcamsg
 #define TCA_ACT_TAB 1 /* attr type must be >=1 */
 #define TCAA_MAX 1
 
-/* End of information exported to user level */
-
-#ifdef __KERNEL__
-
-#include <linux/config.h>
-#include <linux/mutex.h>
-
-extern size_t rtattr_strlcpy(char *dest, const struct rtattr *rta, size_t size);
-static __inline__ int rtattr_strcmp(const struct rtattr *rta, const char *str)
-{
-	int len = strlen(str) + 1;
-	return len > rta->rta_len || memcmp(RTA_DATA(rta), str, len);
-}
-
-extern int rtattr_parse(struct rtattr *tb[], int maxattr, struct rtattr *rta, int len);
-
-#define rtattr_parse_nested(tb, max, rta) \
-	rtattr_parse((tb), (max), RTA_DATA((rta)), RTA_PAYLOAD((rta)))
-
-extern struct sock *rtnl;
-
-struct rtnetlink_link
-{
-	int (*doit)(struct sk_buff *, struct nlmsghdr*, void *attr);
-	int (*dumpit)(struct sk_buff *, struct netlink_callback *cb);
-};
-
-extern struct rtnetlink_link * rtnetlink_links[NPROTO];
-extern int rtnetlink_send(struct sk_buff *skb, __u32 pid, __u32 group, int echo);
-extern int rtnetlink_put_metrics(struct sk_buff *skb, __u32 *metrics);
+/* New extended info filters for IFLA_EXT_MASK */
+#define RTEXT_FILTER_VF		(1 << 0)
+#define RTEXT_FILTER_BRVLAN	(1 << 1)
+#define RTEXT_FILTER_BRVLAN_COMPRESSED	(1 << 2)
 
-extern void __rta_fill(struct sk_buff *skb, int attrtype, int attrlen, const void *data);
-
-#define RTA_PUT(skb, attrtype, attrlen, data) \
-({	if (unlikely(skb_tailroom(skb) < (int)RTA_SPACE(attrlen))) \
-		 goto rtattr_failure; \
-	__rta_fill(skb, attrtype, attrlen, data); })
-
-#define RTA_APPEND(skb, attrlen, data) \
-({	if (unlikely(skb_tailroom(skb) < (int)(attrlen))) \
-		goto rtattr_failure; \
-	memcpy(skb_put(skb, attrlen), data, attrlen); })
-
-#define RTA_PUT_NOHDR(skb, attrlen, data) \
-({	RTA_APPEND(skb, RTA_ALIGN(attrlen), data); \
-	memset(skb->tail - (RTA_ALIGN(attrlen) - attrlen), 0, \
-	       RTA_ALIGN(attrlen) - attrlen); })
-
-#define RTA_PUT_U8(skb, attrtype, value) \
-({	__u8 _tmp = (value); \
-	RTA_PUT(skb, attrtype, sizeof(__u8), &_tmp); })
-
-#define RTA_PUT_U16(skb, attrtype, value) \
-({	__u16 _tmp = (value); \
-	RTA_PUT(skb, attrtype, sizeof(__u16), &_tmp); })
-
-#define RTA_PUT_U32(skb, attrtype, value) \
-({	__u32 _tmp = (value); \
-	RTA_PUT(skb, attrtype, sizeof(__u32), &_tmp); })
-
-#define RTA_PUT_U64(skb, attrtype, value) \
-({	__u64 _tmp = (value); \
-	RTA_PUT(skb, attrtype, sizeof(__u64), &_tmp); })
-
-#define RTA_PUT_SECS(skb, attrtype, value) \
-	RTA_PUT_U64(skb, attrtype, (value) / HZ)
-
-#define RTA_PUT_MSECS(skb, attrtype, value) \
-	RTA_PUT_U64(skb, attrtype, jiffies_to_msecs(value))
-
-#define RTA_PUT_STRING(skb, attrtype, value) \
-	RTA_PUT(skb, attrtype, strlen(value) + 1, value)
-
-#define RTA_PUT_FLAG(skb, attrtype) \
-	RTA_PUT(skb, attrtype, 0, NULL);
-
-#define RTA_NEST(skb, type) \
-({	struct rtattr *__start = (struct rtattr *) (skb)->tail; \
-	RTA_PUT(skb, type, 0, NULL); \
-	__start;  })
-
-#define RTA_NEST_END(skb, start) \
-({	(start)->rta_len = ((skb)->tail - (unsigned char *) (start)); \
-	(skb)->len; })
-
-#define RTA_NEST_CANCEL(skb, start) \
-({	if (start) \
-		skb_trim(skb, (unsigned char *) (start) - (skb)->data); \
-	-1; })
-
-#define RTA_GET_U8(rta) \
-({	if (!rta || RTA_PAYLOAD(rta) < sizeof(__u8)) \
-		goto rtattr_failure; \
-	*(__u8 *) RTA_DATA(rta); })
-
-#define RTA_GET_U16(rta) \
-({	if (!rta || RTA_PAYLOAD(rta) < sizeof(__u16)) \
-		goto rtattr_failure; \
-	*(__u16 *) RTA_DATA(rta); })
-
-#define RTA_GET_U32(rta) \
-({	if (!rta || RTA_PAYLOAD(rta) < sizeof(__u32)) \
-		goto rtattr_failure; \
-	*(__u32 *) RTA_DATA(rta); })
-
-#define RTA_GET_U64(rta) \
-({	__u64 _tmp; \
-	if (!rta || RTA_PAYLOAD(rta) < sizeof(__u64)) \
-		goto rtattr_failure; \
-	memcpy(&_tmp, RTA_DATA(rta), sizeof(_tmp)); \
-	_tmp; })
+/* End of information exported to user level */
 
-#define RTA_GET_FLAG(rta) (!!(rta))
 
-#define RTA_GET_SECS(rta) ((unsigned long) RTA_GET_U64(rta) * HZ)
-#define RTA_GET_MSECS(rta) (msecs_to_jiffies((unsigned long) RTA_GET_U64(rta)))
 
-static __inline__ struct rtattr *
-__rta_reserve(struct sk_buff *skb, int attrtype, int attrlen)
-{
-	struct rtattr *rta;
-	int size = RTA_LENGTH(attrlen);
-
-	rta = (struct rtattr*)skb_put(skb, RTA_ALIGN(size));
-	rta->rta_type = attrtype;
-	rta->rta_len = size;
-	memset(RTA_DATA(rta) + attrlen, 0, RTA_ALIGN(size) - size);
-	return rta;
-}
-
-#define __RTA_PUT(skb, attrtype, attrlen) \
-({ 	if (unlikely(skb_tailroom(skb) < (int)RTA_SPACE(attrlen))) \
-		goto rtattr_failure; \
-	__rta_reserve(skb, attrtype, attrlen); })
-
-extern void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change);
-
-/* RTNL is used as a global lock for all changes to network configuration  */
-extern void rtnl_lock(void);
-extern void rtnl_unlock(void);
-extern int rtnl_trylock(void);
-
-extern void rtnetlink_init(void);
-extern void __rtnl_unlock(void);
-
-#define ASSERT_RTNL() do { \
-	if (unlikely(rtnl_trylock())) { \
-		rtnl_unlock(); \
-		printk(KERN_ERR "RTNL: assertion failed at %s (%d)\n", \
-		       __FILE__,  __LINE__); \
-		dump_stack(); \
-	} \
-} while(0)
-
-#define BUG_TRAP(x) do { \
-	if (unlikely(!(x))) { \
-		printk(KERN_ERR "KERNEL: assertion (%s) failed at %s (%d)\n", \
-			#x,  __FILE__ , __LINE__); \
-	} \
-} while(0)
-
-#endif /* __KERNEL__ */
-
-
-#endif	/* __LINUX_RTNETLINK_H */
+#endif /* _UAPI__LINUX_RTNETLINK_H */
diff --git a/src/include/linux/types.h b/src/include/linux/types.h
deleted file mode 100644
index 22cfdc0..0000000
--- a/src/include/linux/types.h
+++ /dev/null
@@ -1,172 +0,0 @@
-#ifndef _LINUX_TYPES_H
-#define _LINUX_TYPES_H
-
-
-#include <linux/posix_types.h>
-#include <asm/types.h>
-
-#ifndef __KERNEL_STRICT_NAMES
-
-typedef __u32 __kernel_dev_t;
-
-typedef __kernel_fd_set		fd_set;
-typedef __kernel_dev_t		dev_t;
-typedef __kernel_ino_t		ino_t;
-typedef __kernel_mode_t		mode_t;
-typedef __kernel_nlink_t	nlink_t;
-typedef __kernel_off_t		off_t;
-typedef __kernel_pid_t		pid_t;
-typedef __kernel_daddr_t	daddr_t;
-typedef __kernel_key_t		key_t;
-typedef __kernel_suseconds_t	suseconds_t;
-typedef __kernel_timer_t	timer_t;
-typedef __kernel_clockid_t	clockid_t;
-typedef __kernel_mqd_t		mqd_t;
-
-typedef __kernel_uid_t		uid_t;
-typedef __kernel_gid_t		gid_t;
-
-#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
-typedef __kernel_loff_t		loff_t;
-#endif
-
-/*
- * The following typedefs are also protected by individual ifdefs for
- * historical reasons:
- */
-#ifndef _SIZE_T
-#define _SIZE_T
-typedef __kernel_size_t		size_t;
-#endif
-
-#ifndef _SSIZE_T
-#define _SSIZE_T
-typedef __kernel_ssize_t	ssize_t;
-#endif
-
-#ifndef _PTRDIFF_T
-#define _PTRDIFF_T
-typedef __kernel_ptrdiff_t	ptrdiff_t;
-#endif
-
-#ifndef _TIME_T
-#define _TIME_T
-typedef __kernel_time_t		time_t;
-#endif
-
-#ifndef _CLOCK_T
-#define _CLOCK_T
-typedef __kernel_clock_t	clock_t;
-#endif
-
-#ifndef _CADDR_T
-#define _CADDR_T
-typedef __kernel_caddr_t	caddr_t;
-#endif
-
-/* bsd */
-typedef unsigned char		u_char;
-typedef unsigned short		u_short;
-typedef unsigned int		u_int;
-typedef unsigned long		u_long;
-
-/* sysv */
-typedef unsigned char		unchar;
-typedef unsigned short		ushort;
-typedef unsigned int		uint;
-typedef unsigned long		ulong;
-
-#ifndef __BIT_TYPES_DEFINED__
-#define __BIT_TYPES_DEFINED__
-
-typedef		__u8		u_int8_t;
-typedef		__s8		int8_t;
-typedef		__u16		u_int16_t;
-typedef		__s16		int16_t;
-typedef		__u32		u_int32_t;
-typedef		__s32		int32_t;
-
-#endif /* !(__BIT_TYPES_DEFINED__) */
-
-typedef		__u8		uint8_t;
-typedef		__u16		uint16_t;
-typedef		__u32		uint32_t;
-
-#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
-typedef		__u64		uint64_t;
-typedef		__u64		u_int64_t;
-typedef		__s64		int64_t;
-#endif
-
-/* this is a special 64bit data type that is 8-byte aligned */
-#define aligned_u64 unsigned long long __attribute__((aligned(8)))
-#define aligned_be64 __be64 __attribute__((aligned(8)))
-#define aligned_le64 __le64 __attribute__((aligned(8)))
-
-/**
- * The type used for indexing onto a disc or disc partition.
- *
- * Linux always considers sectors to be 512 bytes long independently
- * of the devices real block size.
- */
-#ifdef CONFIG_LBD
-typedef u64 sector_t;
-#else
-typedef unsigned long sector_t;
-#endif
-
-/*
- * The type of the inode's block count.
- */
-#ifdef CONFIG_LSF
-typedef u64 blkcnt_t;
-#else
-typedef unsigned long blkcnt_t;
-#endif
-
-/*
- * The type of an index into the pagecache.  Use a #define so asm/types.h
- * can override it.
- */
-#ifndef pgoff_t
-#define pgoff_t unsigned long
-#endif
-
-#endif /* __KERNEL_STRICT_NAMES */
-
-/*
- * Below are truly Linux-specific types that should never collide with
- * any application/library that wants linux/types.h.
- */
-
-#ifdef __CHECKER__
-#define __bitwise__ __attribute__((bitwise))
-#else
-#define __bitwise__
-#endif
-#ifdef __CHECK_ENDIAN__
-#define __bitwise __bitwise__
-#else
-#define __bitwise
-#endif
-
-typedef __u16 __bitwise __le16;
-typedef __u16 __bitwise __be16;
-typedef __u32 __bitwise __le32;
-typedef __u32 __bitwise __be32;
-#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
-typedef __u64 __bitwise __le64;
-typedef __u64 __bitwise __be64;
-#endif
-typedef __u16 __bitwise __sum16;
-typedef __u32 __bitwise __wsum;
-
-
-struct ustat {
-	__kernel_daddr_t	f_tfree;
-	__kernel_ino_t		f_tinode;
-	char			f_fname[6];
-	char			f_fpack[6];
-};
-
-#endif /* _LINUX_TYPES_H */
diff --git a/src/ipsec/_ipsec.8 b/src/ipsec/_ipsec.8
index f9c54f8..9795451 100644
--- a/src/ipsec/_ipsec.8
+++ b/src/ipsec/_ipsec.8
@@ -1,4 +1,4 @@
-.TH IPSEC 8 "2013-10-29" "5.3.1dr1" "strongSwan"
+.TH IPSEC 8 "2013-10-29" "5.3.3dr5" "strongSwan"
 .
 .SH NAME
 .
diff --git a/src/libcharon/config/ike_cfg.c b/src/libcharon/config/ike_cfg.c
index 9464ceb..dee9e4c 100644
--- a/src/libcharon/config/ike_cfg.c
+++ b/src/libcharon/config/ike_cfg.c
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2012-2015 Tobias Brunner
  * Copyright (C) 2005-2007 Martin Willi
  * Copyright (C) 2005 Jan Hutter
  * Hochschule fuer Technik Rapperswil
@@ -513,6 +514,52 @@ static void parse_addresses(char *str, linked_list_t *hosts,
 /**
  * Described in header.
  */
+int ike_cfg_get_family(ike_cfg_t *cfg, bool local)
+{
+	private_ike_cfg_t *this = (private_ike_cfg_t*)cfg;
+	enumerator_t *enumerator;
+	host_t *host;
+	char *str;
+	int family = AF_UNSPEC;
+
+	if (local)
+	{
+		enumerator = this->my_hosts->create_enumerator(this->my_hosts);
+	}
+	else
+	{
+		enumerator = this->other_hosts->create_enumerator(this->other_hosts);
+	}
+	while (enumerator->enumerate(enumerator, &str))
+	{
+		if (streq(str, "%any"))
+		{	/* ignore %any as its family is undetermined */
+			continue;
+		}
+		host = host_create_from_string(str, 0);
+		if (host)
+		{
+			if (family == AF_UNSPEC)
+			{
+				family = host->get_family(host);
+			}
+			else if (family != host->get_family(host))
+			{
+				/* more than one address family defined */
+				family = AF_UNSPEC;
+				host->destroy(host);
+				break;
+			}
+		}
+		DESTROY_IF(host);
+	}
+	enumerator->destroy(enumerator);
+	return family;
+}
+
+/**
+ * Described in header.
+ */
 ike_cfg_t *ike_cfg_create(ike_version_t version, bool certreq, bool force_encap,
 						  char *me, u_int16_t my_port,
 						  char *other, u_int16_t other_port,
diff --git a/src/libcharon/config/ike_cfg.h b/src/libcharon/config/ike_cfg.h
index adfcabf..a72960f 100644
--- a/src/libcharon/config/ike_cfg.h
+++ b/src/libcharon/config/ike_cfg.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 Tobias Brunner
+ * Copyright (C) 2012-2015 Tobias Brunner
  * Copyright (C) 2005-2007 Martin Willi
  * Copyright (C) 2005 Jan Hutter
  * Hochschule fuer Technik Rapperswil
@@ -160,7 +160,7 @@ struct ike_cfg_t {
 	 *
 	 * Returned list and its proposals must be destroyed after use.
 	 *
-	 * @return 				list containing all the proposals
+	 * @return				list containing all the proposals
 	 */
 	linked_list_t* (*get_proposals) (ike_cfg_t *this);
 
@@ -247,11 +247,22 @@ struct ike_cfg_t {
  * @param other_port		IKE port to use as dest, 500 uses IKEv2 port floating
  * @param fragmentation		use IKEv1 fragmentation
  * @param dscp				DSCP value to send IKE packets with
- * @return 					ike_cfg_t object.
+ * @return					ike_cfg_t object.
  */
 ike_cfg_t *ike_cfg_create(ike_version_t version, bool certreq, bool force_encap,
 						  char *me, u_int16_t my_port,
 						  char *other, u_int16_t other_port,
 						  fragmentation_t fragmentation, u_int8_t dscp);
 
+/**
+ * Determine the address family of the local or remtoe address(es).  If multiple
+ * families are configured AF_UNSPEC is returned.  %any is ignored (%any4|6 are
+ * not though).
+ *
+ * @param this				ike config to check
+ * @param local				TRUE to check local addresses, FALSE for remote
+ * @return					address family of address(es) if distinct
+ */
+int ike_cfg_get_family(ike_cfg_t *this, bool local);
+
 #endif /** IKE_CFG_H_ @}*/
diff --git a/src/libcharon/control/controller.c b/src/libcharon/control/controller.c
index fd8349e..6dd54b4 100644
--- a/src/libcharon/control/controller.c
+++ b/src/libcharon/control/controller.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011-2012 Tobias Brunner
+ * Copyright (C) 2011-2015 Tobias Brunner
  * Copyright (C) 2007-2011 Martin Willi
  * Copyright (C) 2011 revosec AG
  * Hochschule fuer Technik Rapperswil
@@ -116,6 +116,11 @@ struct interface_listener_t {
 	 * spinlock to update the IKE_SA handle properly
 	 */
 	spinlock_t *lock;
+
+	/**
+	 * whether to check limits
+	 */
+	bool limits;
 };
 
 
@@ -358,7 +363,6 @@ METHOD(job_t, initiate_execute, job_requeue_t,
 		listener->child_cfg->destroy(listener->child_cfg);
 		peer_cfg->destroy(peer_cfg);
 		listener->status = FAILED;
-		/* release listener */
 		listener_done(listener);
 		return JOB_REQUEUE_NONE;
 	}
@@ -372,6 +376,49 @@ METHOD(job_t, initiate_execute, job_requeue_t,
 	}
 	peer_cfg->destroy(peer_cfg);
 
+	if (listener->limits && ike_sa->get_state(ike_sa) == IKE_CREATED)
+	{	/* only check if we are not reusing an IKE_SA */
+		u_int half_open, limit_half_open, limit_job_load;
+
+		half_open = charon->ike_sa_manager->get_half_open_count(
+										charon->ike_sa_manager, NULL, FALSE);
+		limit_half_open = lib->settings->get_int(lib->settings,
+										"%s.init_limit_half_open", 0, lib->ns);
+		limit_job_load = lib->settings->get_int(lib->settings,
+										"%s.init_limit_job_load", 0, lib->ns);
+		if (limit_half_open && half_open >= limit_half_open)
+		{
+			DBG1(DBG_IKE, "abort IKE_SA initiation, half open IKE_SA count of "
+				 "%d exceeds limit of %d", half_open, limit_half_open);
+			charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
+														ike_sa);
+			listener->child_cfg->destroy(listener->child_cfg);
+			listener->status = INVALID_STATE;
+			listener_done(listener);
+			return JOB_REQUEUE_NONE;
+		}
+		if (limit_job_load)
+		{
+			u_int jobs = 0, i;
+
+			for (i = 0; i < JOB_PRIO_MAX; i++)
+			{
+				jobs += lib->processor->get_job_load(lib->processor, i);
+			}
+			if (jobs > limit_job_load)
+			{
+				DBG1(DBG_IKE, "abort IKE_SA initiation, job load of %d exceeds "
+					 "limit of %d", jobs, limit_job_load);
+				charon->ike_sa_manager->checkin_and_destroy(
+												charon->ike_sa_manager, ike_sa);
+				listener->child_cfg->destroy(listener->child_cfg);
+				listener->status = INVALID_STATE;
+				listener_done(listener);
+				return JOB_REQUEUE_NONE;
+			}
+		}
+	}
+
 	if (ike_sa->initiate(ike_sa, listener->child_cfg, 0, NULL, NULL) == SUCCESS)
 	{
 		if (!listener->logger.callback)
@@ -391,7 +438,7 @@ METHOD(job_t, initiate_execute, job_requeue_t,
 
 METHOD(controller_t, initiate, status_t,
 	private_controller_t *this, peer_cfg_t *peer_cfg, child_cfg_t *child_cfg,
-	controller_cb_t callback, void *param, u_int timeout)
+	controller_cb_t callback, void *param, u_int timeout, bool limits)
 {
 	interface_job_t *job;
 	status_t status;
@@ -414,6 +461,7 @@ METHOD(controller_t, initiate, status_t,
 			.child_cfg = child_cfg,
 			.peer_cfg = peer_cfg,
 			.lock = spinlock_create(),
+			.limits = limits,
 		},
 		.public = {
 			.execute = _initiate_execute,
diff --git a/src/libcharon/control/controller.h b/src/libcharon/control/controller.h
index 02f4ebb..5ffeac5 100644
--- a/src/libcharon/control/controller.h
+++ b/src/libcharon/control/controller.h
@@ -82,15 +82,18 @@ struct controller_t {
 	 * @param cb			logging callback
 	 * @param param			parameter to include in each call of cb
 	 * @param timeout		timeout in ms to wait for callbacks, 0 to disable
+	 * @param limits		whether to check limits regarding IKE_SA initiation
 	 * @return
 	 *						- SUCCESS, if CHILD_SA established
 	 *						- FAILED, if setup failed
 	 *						- NEED_MORE, if callback returned FALSE
 	 *						- OUT_OF_RES if timed out
+	 *						- INVALID_STATE if limits prevented initiation
 	 */
 	status_t (*initiate)(controller_t *this,
 						 peer_cfg_t *peer_cfg, child_cfg_t *child_cfg,
-						 controller_cb_t callback, void *param, u_int timeout);
+						 controller_cb_t callback, void *param, u_int timeout,
+						 bool limits);
 
 	/**
 	 * Terminate an IKE_SA and all of its CHILD_SAs.
diff --git a/src/libcharon/daemon.c b/src/libcharon/daemon.c
index b1b8f57..316be76 100644
--- a/src/libcharon/daemon.c
+++ b/src/libcharon/daemon.c
@@ -462,6 +462,10 @@ static void destroy(private_daemon_t *this)
 	{
 		this->public.traps->flush(this->public.traps);
 	}
+	if (this->public.shunts)
+	{
+		this->public.shunts->flush(this->public.shunts);
+	}
 	if (this->public.sender)
 	{
 		this->public.sender->flush(this->public.sender);
diff --git a/src/libcharon/encoding/payloads/fragment_payload.c b/src/libcharon/encoding/payloads/fragment_payload.c
index b861fcc..7f158f5 100644
--- a/src/libcharon/encoding/payloads/fragment_payload.c
+++ b/src/libcharon/encoding/payloads/fragment_payload.c
@@ -222,4 +222,4 @@ fragment_payload_t *fragment_payload_create_from_data(u_int8_t num, bool last,
 	this->data = chunk_clone(data);
 	this->payload_length = get_header_length(this) + data.len;
 	return &this->public;
-}
\ No newline at end of file
+}
diff --git a/src/libcharon/encoding/payloads/proposal_substructure.c b/src/libcharon/encoding/payloads/proposal_substructure.c
index 48dcfeb..65ce667 100644
--- a/src/libcharon/encoding/payloads/proposal_substructure.c
+++ b/src/libcharon/encoding/payloads/proposal_substructure.c
@@ -914,6 +914,11 @@ static void add_to_proposal_v1_ike(proposal_t *proposal,
 
 	if (encr != ENCR_UNDEFINED)
 	{
+		if (encr == ENCR_AES_CBC && !key_length)
+		{	/* some implementations don't send a Key Length attribute for
+			 * AES-128, early drafts of RFC 3602 allowed that */
+			key_length = 128;
+		}
 		proposal->add_algorithm(proposal, ENCRYPTION_ALGORITHM, encr, key_length);
 	}
 }
@@ -962,6 +967,12 @@ static void add_to_proposal_v1(proposal_t *proposal,
 									transform->get_transform_id(transform));
 		if (encr)
 		{
+			if (encr == ENCR_AES_CBC && !key_length)
+			{	/* some implementations don't send a Key Length attribute for
+				 * AES-128, early drafts of RFC 3602 allowed that for IKE, some
+				 * also seem to do it for ESP */
+				key_length = 128;
+			}
 			proposal->add_algorithm(proposal, ENCRYPTION_ALGORITHM, encr,
 									key_length);
 		}
diff --git a/src/libcharon/network/receiver.c b/src/libcharon/network/receiver.c
index 6902c48..a2f2016 100644
--- a/src/libcharon/network/receiver.c
+++ b/src/libcharon/network/receiver.c
@@ -322,16 +322,18 @@ 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;
+	u_int half_open, half_open_r;
 	u_int32_t now;
 
 	now = time_monotonic(NULL);
 	half_open = charon->ike_sa_manager->get_half_open_count(
-										charon->ike_sa_manager, NULL);
+										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, now) && !check_cookie(this, message))
+		cookie_required(this, half_open_r, now) && !check_cookie(this, message))
 	{
 		chunk_t cookie;
 
@@ -372,7 +374,7 @@ static bool drop_ike_sa_init(private_receiver_t *this, message_t *message)
 	/* check if peer has too many IKE_SAs half open */
 	if (this->block_threshold &&
 		charon->ike_sa_manager->get_half_open_count(charon->ike_sa_manager,
-				message->get_source(message)) >= this->block_threshold)
+				message->get_source(message), TRUE) >= this->block_threshold)
 	{
 		DBG1(DBG_NET, "ignoring IKE_SA setup from %H, "
 			 "peer too aggressive", message->get_source(message));
@@ -381,7 +383,7 @@ static bool drop_ike_sa_init(private_receiver_t *this, message_t *message)
 
 	/* check if global half open IKE_SA limit reached */
 	if (this->init_limit_half_open &&
-		half_open >= this->init_limit_half_open)
+	    half_open >= this->init_limit_half_open)
 	{
 		DBG1(DBG_NET, "ignoring IKE_SA setup from %H, half open IKE_SA "
 			 "count of %d exceeds limit of %d", message->get_source(message),
@@ -542,7 +544,9 @@ static job_requeue_t receive_packets(private_receiver_t *this)
 	if (message->get_request(message) &&
 		message->get_exchange_type(message) == IKE_SA_INIT)
 	{
-		if (this->initiator_only || drop_ike_sa_init(this, message))
+		id = message->get_ike_sa_id(message);
+		if (this->initiator_only || !id->is_initiator(id) ||
+			drop_ike_sa_init(this, message))
 		{
 			message->destroy(message);
 			return JOB_REQUEUE_DIRECT;
diff --git a/src/libcharon/plugins/eap_radius/eap_radius.c b/src/libcharon/plugins/eap_radius/eap_radius.c
index 60d12dc..237f065 100644
--- a/src/libcharon/plugins/eap_radius/eap_radius.c
+++ b/src/libcharon/plugins/eap_radius/eap_radius.c
@@ -434,6 +434,9 @@ static void add_nameserver_attribute(eap_radius_provider_t *provider,
 		case 31: /* MS-Secondary-NBNS-Server */
 			provider->add_attribute(provider, id, INTERNAL_IP4_NBNS, data);
 			break;
+		case RAT_FRAMED_IPV6_DNS_SERVER:
+			provider->add_attribute(provider, id, INTERNAL_IP6_DNS, data);
+			break;
 	}
 }
 
@@ -515,9 +518,10 @@ static void process_cfg_attributes(radius_message_t *msg)
 		enumerator = msg->create_enumerator(msg);
 		while (enumerator->enumerate(enumerator, &type, &data))
 		{
-			if (type == RAT_FRAMED_IP_ADDRESS && data.len == 4)
+			if ((type == RAT_FRAMED_IP_ADDRESS && data.len == 4) ||
+				(type == RAT_FRAMED_IPV6_ADDRESS && data.len == 16))
 			{
-				host = host_create_from_chunk(AF_INET, data, 0);
+				host = host_create_from_chunk(AF_UNSPEC, data, 0);
 				if (host)
 				{
 					provider->add_framed_ip(provider,
@@ -529,6 +533,11 @@ static void process_cfg_attributes(radius_message_t *msg)
 				provider->add_attribute(provider, ike_sa->get_unique_id(ike_sa),
 										INTERNAL_IP4_NETMASK, data);
 			}
+			else if (type == RAT_FRAMED_IPV6_DNS_SERVER && data.len == 16)
+			{
+				add_nameserver_attribute(provider,
+									ike_sa->get_unique_id(ike_sa), type, data);
+			}
 		}
 		enumerator->destroy(enumerator);
 
diff --git a/src/libcharon/plugins/eap_radius/eap_radius_accounting.c b/src/libcharon/plugins/eap_radius/eap_radius_accounting.c
index cef1930..4b72603 100644
--- a/src/libcharon/plugins/eap_radius/eap_radius_accounting.c
+++ b/src/libcharon/plugins/eap_radius/eap_radius_accounting.c
@@ -447,10 +447,8 @@ static void add_ike_sa_parameters(private_eap_radius_accounting_t *this,
 							 vip->get_address(vip));
 				break;
 			case AF_INET6:
-				/* we currently assign /128 prefixes, only (reserved, length) */
-				data = chunk_from_chars(0, 128);
-				data = chunk_cata("cc", data, vip->get_address(vip));
-				message->add(message, RAT_FRAMED_IPV6_PREFIX, data);
+				message->add(message, RAT_FRAMED_IPV6_ADDRESS,
+							 vip->get_address(vip));
 				break;
 			default:
 				break;
@@ -694,6 +692,11 @@ static void send_start(private_eap_radius_accounting_t *this, ike_sa_t *ike_sa)
 
 	entry = get_or_create_entry(this, ike_sa->get_id(ike_sa),
 								ike_sa->get_unique_id(ike_sa));
+	if (entry->start_sent)
+	{
+		this->mutex->unlock(this->mutex);
+		return;
+	}
 	entry->start_sent = TRUE;
 
 	message = radius_message_create(RMC_ACCOUNTING_REQUEST);
@@ -860,11 +863,6 @@ METHOD(listener_t, message_hook, bool,
 	if (plain && ike_sa->get_state(ike_sa) == IKE_ESTABLISHED &&
 		!incoming && !message->get_request(message))
 	{
-		if (ike_sa->get_version(ike_sa) == IKEV1 &&
-			message->get_exchange_type(message) == TRANSACTION)
-		{
-			send_start(this, ike_sa);
-		}
 		if (ike_sa->get_version(ike_sa) == IKEV2 &&
 			message->get_exchange_type(message) == IKE_AUTH)
 		{
@@ -874,6 +872,17 @@ METHOD(listener_t, message_hook, bool,
 	return TRUE;
 }
 
+METHOD(listener_t, assign_vips, bool,
+	private_eap_radius_accounting_t *this, ike_sa_t *ike_sa, bool assign)
+{
+	/* start accounting as soon as the virtual IP is set */
+	if (assign && ike_sa->get_version(ike_sa) == IKEV1)
+	{
+		send_start(this, ike_sa);
+	}
+	return TRUE;
+}
+
 METHOD(listener_t, ike_rekey, bool,
 	private_eap_radius_accounting_t *this, ike_sa_t *old, ike_sa_t *new)
 {
@@ -1003,6 +1012,7 @@ eap_radius_accounting_t *eap_radius_accounting_create()
 				.ike_updown = _ike_updown,
 				.ike_rekey = _ike_rekey,
 				.message = _message_hook,
+				.assign_vips = _assign_vips,
 				.child_updown = _child_updown,
 				.child_rekey = _child_rekey,
 				.children_migrate = _children_migrate,
diff --git a/src/libcharon/plugins/eap_tnc/eap_tnc.c b/src/libcharon/plugins/eap_tnc/eap_tnc.c
index f70f47e..350001b 100644
--- a/src/libcharon/plugins/eap_tnc/eap_tnc.c
+++ b/src/libcharon/plugins/eap_tnc/eap_tnc.c
@@ -335,6 +335,10 @@ static eap_tnc_t *eap_tnc_create(identification_t *server,
 		free(this);
 		return NULL;
 	}
+	if (!is_server)
+	{
+		tnccs->set_auth_type(tnccs, TNC_AUTH_X509_CERT);
+	}
 	this->tnccs = tnccs->get_ref(tnccs);
 	this->tls_eap = tls_eap_create(type, &tnccs->tls,
 								   EAP_TNC_MAX_MESSAGE_LEN,
diff --git a/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c b/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c
index 66c9dee..e0b59a6 100644
--- a/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c
+++ b/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c
@@ -112,6 +112,13 @@ METHOD(tls_application_t, process, status_t,
 				eap_data = avp_data;
 				break;
 			}
+			else if (eap_len > reader->remaining(reader) + avp_data.len)
+			{
+				/* rough size check, ignoring AVP headers in remaining data */
+				DBG1(DBG_IKE, "EAP packet too large for EAP-TTLS AVP(s)");
+				chunk_free(&avp_data);
+				return FAILED;
+			}
 			else if (avp_data.len == MAX_RADIUS_ATTRIBUTE_SIZE)
 			{
 				/* non-standard: EAP packet segmented into multiple AVPs */
@@ -128,7 +135,7 @@ METHOD(tls_application_t, process, status_t,
 
 		if (avp_data.len > eap_data.len - eap_pos)
 		{
-			DBG1(DBG_IKE, "AVP size to large to fit into EAP packet");
+			DBG1(DBG_IKE, "AVP size too large to fit into EAP packet");
 			chunk_free(&avp_data);
 			chunk_free(&eap_data);
 			return FAILED;
diff --git a/src/libcharon/plugins/error_notify/error_notify_listener.c b/src/libcharon/plugins/error_notify/error_notify_listener.c
index 13860fe..f7a1f49 100644
--- a/src/libcharon/plugins/error_notify/error_notify_listener.c
+++ b/src/libcharon/plugins/error_notify/error_notify_listener.c
@@ -96,13 +96,13 @@ METHOD(listener_t, alert, bool,
 		case ALERT_PROPOSAL_MISMATCH_IKE:
 			msg.type = htonl(ERROR_NOTIFY_PROPOSAL_MISMATCH_IKE);
 			list = va_arg(args, linked_list_t*);
-			snprintf(msg.str, sizeof(msg.str), "the received IKE_SA poposals "
+			snprintf(msg.str, sizeof(msg.str), "the received IKE_SA proposals "
 					 "did not match: %#P", list);
 			break;
 		case ALERT_PROPOSAL_MISMATCH_CHILD:
 			msg.type = htonl(ERROR_NOTIFY_PROPOSAL_MISMATCH_CHILD);
 			list = va_arg(args, linked_list_t*);
-			snprintf(msg.str, sizeof(msg.str), "the received CHILD_SA poposals "
+			snprintf(msg.str, sizeof(msg.str), "the received CHILD_SA proposals "
 					 "did not match: %#P", list);
 			break;
 		case ALERT_TS_MISMATCH:
@@ -153,14 +153,14 @@ METHOD(listener_t, alert, bool,
 			msg.type = htonl(ERROR_NOTIFY_CERT_EXPIRED);
 			cert = va_arg(args, certificate_t*);
 			cert->get_validity(cert, NULL, &not_before, &not_after);
-			snprintf(msg.str, sizeof(msg.str), "certificiate expired: '%Y' "
+			snprintf(msg.str, sizeof(msg.str), "certificate expired: '%Y' "
 					 "(valid from %T to %T)", cert->get_subject(cert),
 					 &not_before, TRUE, &not_after, TRUE);
 			break;
 		case ALERT_CERT_REVOKED:
 			msg.type = htonl(ERROR_NOTIFY_CERT_REVOKED);
 			cert = va_arg(args, certificate_t*);
-			snprintf(msg.str, sizeof(msg.str), "certificiate revoked: '%Y'",
+			snprintf(msg.str, sizeof(msg.str), "certificate revoked: '%Y'",
 					 cert->get_subject(cert));
 			break;
 		case ALERT_CERT_NO_ISSUER:
diff --git a/src/libcharon/plugins/ha/ha_ctl.c b/src/libcharon/plugins/ha/ha_ctl.c
index a954997..54302e8 100644
--- a/src/libcharon/plugins/ha/ha_ctl.c
+++ b/src/libcharon/plugins/ha/ha_ctl.c
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2015 Tobias Brunner
  * Copyright (C) 2008 Martin Willi
  * Hochschule fuer Technik Rapperswil
  *
@@ -51,6 +52,41 @@ struct private_ha_ctl_t {
 };
 
 /**
+ * Change the permissions of the control FIFO, returns TRUE on success
+ */
+static bool change_fifo_permissions()
+{
+	if (chown(HA_FIFO, lib->caps->get_uid(lib->caps),
+			  lib->caps->get_gid(lib->caps)) != 0)
+	{
+		DBG1(DBG_CFG, "changing HA FIFO permissions failed: %s",
+			 strerror(errno));
+		return FALSE;
+	}
+	return TRUE;
+}
+
+/**
+ * Deletes and creates the control FIFO, returns TRUE on success
+ */
+static bool recreate_fifo()
+{
+	mode_t old;
+	bool success = TRUE;
+
+	unlink(HA_FIFO);
+	old = umask(S_IRWXO);
+	if (mkfifo(HA_FIFO, S_IRUSR | S_IWUSR) != 0)
+	{
+		DBG1(DBG_CFG, "creating HA FIFO %s failed: %s", HA_FIFO,
+			 strerror(errno));
+		success = FALSE;
+	}
+	umask(old);
+	return success && change_fifo_permissions();
+}
+
+/**
  * FIFO dispatching function
  */
 static job_requeue_t dispatch_fifo(private_ha_ctl_t *this)
@@ -59,13 +95,26 @@ static job_requeue_t dispatch_fifo(private_ha_ctl_t *this)
 	bool oldstate;
 	char buf[8];
 	u_int segment;
+	struct stat sb;
 
 	oldstate = thread_cancelability(TRUE);
 	fifo = open(HA_FIFO, O_RDONLY);
 	thread_cancelability(oldstate);
-	if (fifo == -1)
+	if (fifo == -1 || fstat(fifo, &sb) != 0 || !S_ISFIFO(sb.st_mode))
 	{
-		DBG1(DBG_CFG, "opening HA fifo failed: %s", strerror(errno));
+		if (fifo == -1 && errno != ENOENT)
+		{
+			DBG1(DBG_CFG, "opening HA FIFO failed: %s", strerror(errno));
+		}
+		else
+		{
+			DBG1(DBG_CFG, "%s is not a FIFO, recreate it", HA_FIFO);
+			recreate_fifo();
+		}
+		if (fifo != -1)
+		{
+			close(fifo);
+		}
 		sleep(1);
 		return JOB_REQUEUE_FAIR;
 	}
@@ -100,6 +149,7 @@ static job_requeue_t dispatch_fifo(private_ha_ctl_t *this)
 METHOD(ha_ctl_t, destroy, void,
 	private_ha_ctl_t *this)
 {
+	unlink(HA_FIFO);
 	free(this);
 }
 
@@ -109,7 +159,7 @@ METHOD(ha_ctl_t, destroy, void,
 ha_ctl_t *ha_ctl_create(ha_segments_t *segments, ha_cache_t *cache)
 {
 	private_ha_ctl_t *this;
-	mode_t old;
+	struct stat sb;
 
 	INIT(this,
 		.public = {
@@ -119,20 +169,30 @@ ha_ctl_t *ha_ctl_create(ha_segments_t *segments, ha_cache_t *cache)
 		.cache = cache,
 	);
 
-	if (access(HA_FIFO, R_OK|W_OK) != 0)
+	if (stat(HA_FIFO, &sb) == 0)
 	{
-		old = umask(S_IRWXO);
-		if (mkfifo(HA_FIFO, S_IRUSR | S_IWUSR) != 0)
+		if (!S_ISFIFO(sb.st_mode))
 		{
-			DBG1(DBG_CFG, "creating HA FIFO %s failed: %s",
-				 HA_FIFO, strerror(errno));
+			DBG1(DBG_CFG, "%s is not a FIFO, recreate it", HA_FIFO);
+			recreate_fifo();
+		}
+		else if (access(HA_FIFO, R_OK|W_OK) != 0)
+		{
+			DBG1(DBG_CFG, "accessing HA FIFO %s denied, recreate it", HA_FIFO);
+			recreate_fifo();
+		}
+		else
+		{
+			change_fifo_permissions();
 		}
-		umask(old);
 	}
-	if (chown(HA_FIFO, lib->caps->get_uid(lib->caps),
-			  lib->caps->get_gid(lib->caps)) != 0)
+	else if (errno == ENOENT)
 	{
-		DBG1(DBG_CFG, "changing HA FIFO permissions failed: %s",
+		recreate_fifo();
+	}
+	else
+	{
+		DBG1(DBG_CFG, "accessing HA FIFO %s failed: %s", HA_FIFO,
 			 strerror(errno));
 	}
 
@@ -141,4 +201,3 @@ ha_ctl_t *ha_ctl_create(ha_segments_t *segments, ha_cache_t *cache)
 			this, NULL, (callback_job_cancel_t)return_false, JOB_PRIO_CRITICAL));
 	return &this->public;
 }
-
diff --git a/src/libcharon/plugins/ha/ha_dispatcher.c b/src/libcharon/plugins/ha/ha_dispatcher.c
index 31eeb93..afa0993 100644
--- a/src/libcharon/plugins/ha/ha_dispatcher.c
+++ b/src/libcharon/plugins/ha/ha_dispatcher.c
@@ -135,6 +135,7 @@ static void process_ike_add(private_ha_dispatcher_t *this, ha_message_t *message
 	chunk_t nonce_i = chunk_empty, nonce_r = chunk_empty;
 	chunk_t secret = chunk_empty, old_skd = chunk_empty;
 	chunk_t dh_local = chunk_empty, dh_remote = chunk_empty, psk = chunk_empty;
+	host_t *other = NULL;
 	bool ok = FALSE;
 
 	enumerator = message->create_attribute_enumerator(message);
@@ -150,6 +151,9 @@ static void process_ike_add(private_ha_dispatcher_t *this, ha_message_t *message
 				old_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
 														  value.ike_sa_id);
 				break;
+			case HA_REMOTE_ADDR:
+				other = value.host->clone(value.host);
+				break;
 			case HA_IKE_VERSION:
 				version = value.u8;
 				break;
@@ -252,6 +256,11 @@ static void process_ike_add(private_ha_dispatcher_t *this, ha_message_t *message
 												charon->ike_sa_manager, old_sa);
 				old_sa = NULL;
 			}
+			if (other)
+			{
+				ike_sa->set_other_host(ike_sa, other);
+				other = NULL;
+			}
 			ike_sa->set_state(ike_sa, IKE_CONNECTING);
 			ike_sa->set_proposal(ike_sa, proposal);
 			this->cache->cache(this->cache, ike_sa, message);
@@ -270,6 +279,7 @@ static void process_ike_add(private_ha_dispatcher_t *this, ha_message_t *message
 	{
 		charon->ike_sa_manager->checkin(charon->ike_sa_manager, old_sa);
 	}
+	DESTROY_IF(other);
 	DESTROY_IF(message);
 }
 
@@ -637,7 +647,7 @@ static void process_child_add(private_ha_dispatcher_t *this,
 	u_int32_t inbound_spi = 0, outbound_spi = 0;
 	u_int16_t inbound_cpi = 0, outbound_cpi = 0;
 	u_int8_t mode = MODE_TUNNEL, ipcomp = 0;
-	u_int16_t encr = ENCR_UNDEFINED, integ = AUTH_UNDEFINED, len = 0;
+	u_int16_t encr = 0, integ = 0, len = 0;
 	u_int16_t esn = NO_EXT_SEQ_NUMBERS;
 	u_int seg_i, seg_o;
 	chunk_t nonce_i = chunk_empty, nonce_r = chunk_empty, secret = chunk_empty;
diff --git a/src/libcharon/plugins/ha/ha_ike.c b/src/libcharon/plugins/ha/ha_ike.c
index 6b4b53c..7492dd0 100644
--- a/src/libcharon/plugins/ha/ha_ike.c
+++ b/src/libcharon/plugins/ha/ha_ike.c
@@ -138,6 +138,7 @@ METHOD(listener_t, ike_keys, bool,
 			m->add_attribute(m, HA_PSK, shared->get_key(shared));
 		}
 	}
+	m->add_attribute(m, HA_REMOTE_ADDR, ike_sa->get_other_host(ike_sa));
 
 	this->socket->push(this->socket, m);
 	this->cache->cache(this->cache, ike_sa, m);
diff --git a/src/libcharon/plugins/ha/ha_kernel.c b/src/libcharon/plugins/ha/ha_kernel.c
index eed89e0..bd43dc3 100644
--- a/src/libcharon/plugins/ha/ha_kernel.c
+++ b/src/libcharon/plugins/ha/ha_kernel.c
@@ -36,6 +36,8 @@ typedef enum {
 	JHASH_LOOKUP2,
 	/* new variant, http://burtleburtle.net/bob/c/lookup3.c, since 2.6.37 */
 	JHASH_LOOKUP3,
+	/* variant with different init values, since 4.1 */
+	JHASH_LOOKUP3_1,
 } jhash_version_t;
 
 typedef struct private_ha_kernel_t private_ha_kernel_t;
@@ -88,8 +90,15 @@ static jhash_version_t get_jhash_version()
 				}
 				/* FALL */
 			case 2:
-				DBG1(DBG_CFG, "detected Linux %d.%d, using new jhash", a, b);
-				return JHASH_LOOKUP3;
+				if (a < 4 || (a == 4 && b == 0))
+				{
+					DBG1(DBG_CFG, "detected Linux %d.%d, using new jhash",
+						 a, b);
+					return JHASH_LOOKUP3;
+				}
+				DBG1(DBG_CFG, "detected Linux %d.%d, using new jhash with "
+					 "updated init values", a, b);
+				return JHASH_LOOKUP3_1;
 			default:
 				break;
 		}
@@ -126,6 +135,14 @@ static u_int32_t jhash(jhash_version_t version, u_int32_t a, u_int32_t b)
 			b -= c; b -= a; b ^= (a << 10);
 			c -= a; c -= b; c ^= (b >> 15);
 			break;
+		case JHASH_LOOKUP3_1:
+			/* changed with 4.1: # of 32-bit words shifted by 2 and c is
+			 * initialized. we only use the two word variant with SPIs, so it's
+			 * unlikely that b is 0 in that case */
+			c += ((b ? 2 : 1) << 2) + 0xdeadbeef;
+			a += ((b ? 2 : 1) << 2);
+			b += ((b ? 2 : 1) << 2);
+			/* FALL */
 		case JHASH_LOOKUP3:
 			a += 0xdeadbeef;
 			b += 0xdeadbeef;
diff --git a/src/libcharon/plugins/load_tester/load_tester.c b/src/libcharon/plugins/load_tester/load_tester.c
index b7b971e..f5a998e 100644
--- a/src/libcharon/plugins/load_tester/load_tester.c
+++ b/src/libcharon/plugins/load_tester/load_tester.c
@@ -21,6 +21,7 @@
 #include <stddef.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <errno.h>
 
 /**
diff --git a/src/libcharon/plugins/load_tester/load_tester_control.c b/src/libcharon/plugins/load_tester/load_tester_control.c
index 5f089f5..24076d4 100644
--- a/src/libcharon/plugins/load_tester/load_tester_control.c
+++ b/src/libcharon/plugins/load_tester/load_tester_control.c
@@ -239,7 +239,7 @@ static bool on_accept(private_load_tester_control_t *this, stream_t *io)
 
 		switch (charon->controller->initiate(charon->controller,
 										peer_cfg, child_cfg->get_ref(child_cfg),
-										(void*)initiate_cb, listener, 0))
+										(void*)initiate_cb, listener, 0, FALSE))
 		{
 			case NEED_MORE:
 				/* Callback returns FALSE once it got track of this IKE_SA.
diff --git a/src/libcharon/plugins/load_tester/load_tester_plugin.c b/src/libcharon/plugins/load_tester/load_tester_plugin.c
index e684f22..c7380b9 100644
--- a/src/libcharon/plugins/load_tester/load_tester_plugin.c
+++ b/src/libcharon/plugins/load_tester/load_tester_plugin.c
@@ -152,7 +152,7 @@ static job_requeue_t do_load_test(private_load_tester_plugin_t *this)
 
 		charon->controller->initiate(charon->controller,
 					peer_cfg, child_cfg->get_ref(child_cfg),
-					NULL, NULL, 0);
+					NULL, NULL, 0, FALSE);
 		if (s)
 		{
 			sleep(s);
diff --git a/src/libcharon/plugins/medcli/medcli_config.c b/src/libcharon/plugins/medcli/medcli_config.c
index 1fb57b9..25b1383 100644
--- a/src/libcharon/plugins/medcli/medcli_config.c
+++ b/src/libcharon/plugins/medcli/medcli_config.c
@@ -314,7 +314,7 @@ static job_requeue_t initiate_config(peer_cfg_t *peer_cfg)
 		peer_cfg->get_ref(peer_cfg);
 		enumerator->destroy(enumerator);
 		charon->controller->initiate(charon->controller,
-									 peer_cfg, child_cfg, NULL, NULL, 0);
+									 peer_cfg, child_cfg, NULL, NULL, 0, FALSE);
 	}
 	else
 	{
diff --git a/src/libcharon/plugins/osx_attr/osx_attr_handler.c b/src/libcharon/plugins/osx_attr/osx_attr_handler.c
index d974b57..6baf76d 100644
--- a/src/libcharon/plugins/osx_attr/osx_attr_handler.c
+++ b/src/libcharon/plugins/osx_attr/osx_attr_handler.c
@@ -31,6 +31,16 @@ struct private_osx_attr_handler_t {
 	 * Public interface
 	 */
 	osx_attr_handler_t public;
+
+	/**
+	 * Backup of original DNS servers, before we mess with it
+	 */
+	CFMutableArrayRef original;
+
+	/**
+	 * Append DNS servers to existing entries, instead of replacing
+	 */
+	bool append;
 };
 
 /**
@@ -110,7 +120,8 @@ static CFMutableArrayRef get_array_from_dict(CFDictionaryRef dict,
 /**
  * Add/Remove a DNS server to the configuration
  */
-static bool manage_dns(int family, chunk_t data, bool add)
+static bool manage_dns(private_osx_attr_handler_t *this,
+					   int family, chunk_t data, bool add)
 {
 	SCDynamicStoreRef store;
 	CFStringRef path, dns;
@@ -138,6 +149,11 @@ static bool manage_dns(int family, chunk_t data, bool add)
 		dns = CFStringCreateWithCString(NULL, buf, kCFStringEncodingUTF8);
 		if (add)
 		{
+			if (!this->append && !this->original)
+			{	/* backup orignal config, start with empty set */
+				this->original = arr;
+				arr = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+			}
 			DBG1(DBG_CFG, "installing %s as DNS server", buf);
 			CFArrayInsertValueAtIndex(arr, 0, dns);
 		}
@@ -150,6 +166,12 @@ static bool manage_dns(int family, chunk_t data, bool add)
 				DBG1(DBG_CFG, "removing %s from DNS servers (%d)", buf, i);
 				CFArrayRemoveValueAtIndex(arr, i);
 			}
+			if (!this->append && this->original && CFArrayGetCount(arr) == 0)
+			{	/* restore original config */
+				CFRelease(arr);
+				arr = this->original;
+				this->original = NULL;
+			}
 		}
 		CFRelease(dns);
 		CFDictionarySetValue(dict, CFSTR("ServerAddresses"), arr);
@@ -175,7 +197,7 @@ METHOD(attribute_handler_t, handle, bool,
 	switch (type)
 	{
 		case INTERNAL_IP4_DNS:
-			return manage_dns(AF_INET, data, TRUE);
+			return manage_dns(this, AF_INET, data, TRUE);
 		default:
 			return FALSE;
 	}
@@ -188,7 +210,7 @@ METHOD(attribute_handler_t, release, void,
 	switch (type)
 	{
 		case INTERNAL_IP4_DNS:
-			manage_dns(AF_INET, data, FALSE);
+			manage_dns(this, AF_INET, data, FALSE);
 			break;
 		default:
 			break;
@@ -240,6 +262,8 @@ osx_attr_handler_t *osx_attr_handler_create()
 			},
 			.destroy = _destroy,
 		},
+		.append = lib->settings->get_bool(lib->settings,
+								"%s.plugins.osx-attr.append", TRUE, lib->ns),
 	);
 
 	return &this->public;
diff --git a/src/libcharon/plugins/smp/smp.c b/src/libcharon/plugins/smp/smp.c
index 04bf382..2aa061f 100644
--- a/src/libcharon/plugins/smp/smp.c
+++ b/src/libcharon/plugins/smp/smp.c
@@ -488,7 +488,7 @@ static void request_control_initiate(xmlTextReaderPtr reader,
 			{
 				status = charon->controller->initiate(charon->controller,
 							peer, child, (controller_cb_t)xml_callback,
-							writer, 0);
+							writer, 0, FALSE);
 			}
 			else
 			{
diff --git a/src/libcharon/plugins/sql/sql_config.c b/src/libcharon/plugins/sql/sql_config.c
index c47c7c0..ce24d18 100644
--- a/src/libcharon/plugins/sql/sql_config.c
+++ b/src/libcharon/plugins/sql/sql_config.c
@@ -324,6 +324,14 @@ static peer_cfg_t *get_peer_cfg_by_id(private_sql_config_t *this, int id)
 }
 
 /**
+ * Check if the two IDs match (the first one is optional)
+ */
+static inline bool id_matches(identification_t *id, identification_t *sql_id)
+{
+	return !id || id->matches(id, sql_id) || sql_id->matches(sql_id, id);
+}
+
+/**
  * Build a peer config from an SQL query
  */
 static peer_cfg_t *build_peer_cfg(private_sql_config_t *this, enumerator_t *e,
@@ -352,8 +360,7 @@ static peer_cfg_t *build_peer_cfg(private_sql_config_t *this, enumerator_t *e,
 
 		local_id = identification_create_from_encoding(l_type, l_data);
 		remote_id = identification_create_from_encoding(r_type, r_data);
-		if ((me && !me->matches(me, local_id)) ||
-			(other && !other->matches(other, remote_id)))
+		if (!id_matches(me, local_id) || !id_matches(other, remote_id))
 		{
 			local_id->destroy(local_id);
 			remote_id->destroy(remote_id);
diff --git a/src/libcharon/plugins/sql/sql_logger.c b/src/libcharon/plugins/sql/sql_logger.c
index 9a7a6e0..0fa06ea 100644
--- a/src/libcharon/plugins/sql/sql_logger.c
+++ b/src/libcharon/plugins/sql/sql_logger.c
@@ -120,6 +120,7 @@ METHOD(logger_t, get_level, level_t,
 METHOD(sql_logger_t, destroy, void,
 	private_sql_logger_t *this)
 {
+	this->recursive->destroy(this->recursive);
 	free(this);
 }
 
diff --git a/src/libcharon/plugins/stroke/stroke_ca.c b/src/libcharon/plugins/stroke/stroke_ca.c
index b470b81..13ed41e 100644
--- a/src/libcharon/plugins/stroke/stroke_ca.c
+++ b/src/libcharon/plugins/stroke/stroke_ca.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 Tobias Brunner
+ * Copyright (C) 2008-2015 Tobias Brunner
  * Copyright (C) 2008 Martin Willi
  * Hochschule fuer Technik Rapperswil
  *
@@ -24,6 +24,13 @@
 #include <daemon.h>
 
 typedef struct private_stroke_ca_t private_stroke_ca_t;
+typedef struct ca_section_t ca_section_t;
+typedef struct ca_cert_t ca_cert_t;
+
+/**
+ * Provided by stroke_cred.c
+ */
+certificate_t *stroke_load_ca_cert(char *filename);
 
 /**
  * private data of stroke_ca
@@ -41,17 +48,16 @@ struct private_stroke_ca_t {
 	rwlock_t *lock;
 
 	/**
-	 * list of starters CA sections and its certificates (ca_section_t)
+	 * list of CA sections and their certificates (ca_section_t)
 	 */
 	linked_list_t *sections;
 
 	/**
-	 * stroke credentials, stores our CA certificates
+	 * list of all loaded CA certificates (ca_cert_t)
 	 */
-	stroke_cred_t *cred;
+	linked_list_t *certs;
 };
 
-typedef struct ca_section_t ca_section_t;
 
 /**
  * loaded ipsec.conf CA sections
@@ -64,7 +70,12 @@ struct ca_section_t {
 	char *name;
 
 	/**
-	 * reference to cert in trusted_credential_t
+	 * path/name of the certificate
+	 */
+	char *path;
+
+	/**
+	 * reference to cert
 	 */
 	certificate_t *cert;
 
@@ -90,16 +101,37 @@ struct ca_section_t {
 };
 
 /**
+ * loaded CA certificate
+ */
+struct ca_cert_t {
+
+	/**
+	 * reference to cert
+	 */
+	certificate_t *cert;
+
+	/**
+	 * The number of CA sections referring to this certificate
+	 */
+	u_int count;
+
+	/**
+	 * TRUE if this certificate was automatically loaded
+	 */
+	bool automatic;
+};
+
+/**
  * create a new CA section
  */
-static ca_section_t *ca_section_create(char *name, certificate_t *cert)
+static ca_section_t *ca_section_create(char *name, char *path)
 {
 	ca_section_t *ca = malloc_thing(ca_section_t);
 
 	ca->name = strdup(name);
+	ca->path = strdup(path);
 	ca->crl = linked_list_create();
 	ca->ocsp = linked_list_create();
-	ca->cert = cert;
 	ca->hashes = linked_list_create();
 	ca->certuribase = NULL;
 	return ca;
@@ -115,11 +147,21 @@ static void ca_section_destroy(ca_section_t *this)
 	this->hashes->destroy_offset(this->hashes, offsetof(identification_t, destroy));
 	this->cert->destroy(this->cert);
 	free(this->certuribase);
+	free(this->path);
 	free(this->name);
 	free(this);
 }
 
 /**
+ * Destroy a ca cert entry
+ */
+static void ca_cert_destroy(ca_cert_t *this)
+{
+	this->cert->destroy(this->cert);
+	free(this);
+}
+
+/**
  * Data for the certificate enumerator
  */
 typedef struct {
@@ -141,7 +183,7 @@ static void cert_data_destroy(cert_data_t *data)
 /**
  * filter function for certs enumerator
  */
-static bool certs_filter(cert_data_t *data, ca_section_t **in,
+static bool certs_filter(cert_data_t *data, ca_cert_t **in,
 						 certificate_t **out)
 {
 	public_key_t *public;
@@ -192,7 +234,7 @@ METHOD(credential_set_t, create_cert_enumerator, enumerator_t*,
 	);
 
 	this->lock->read_lock(this->lock);
-	enumerator = this->sections->create_enumerator(this->sections);
+	enumerator = this->certs->create_enumerator(this->certs);
 	return enumerator_create_filter(enumerator, (void*)certs_filter, data,
 									(void*)cert_data_destroy);
 }
@@ -312,6 +354,81 @@ 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)
+{
+	return cert->equals(cert, item->cert);
+}
+
+/**
+ * Match automatically added certificates and remove/destroy them if they are
+ * not referenced by CA sections.
+ */
+static bool remove_auto_certs(ca_cert_t *item, void *not_used)
+{
+	if (item->automatic)
+	{
+		item->automatic = FALSE;
+		if (!item->count)
+		{
+			ca_cert_destroy(item);
+			return TRUE;
+		}
+	}
+	return FALSE;
+}
+
+/**
+ * Find the given certificate that was referenced by a section and remove it
+ * unless it was also loaded automatically or is used by other CA sections.
+ */
+static bool remove_cert(ca_cert_t *item, certificate_t *cert)
+{
+	if (item->count && cert->equals(cert, item->cert))
+	{
+		if (--item->count == 0 && !item->automatic)
+		{
+			ca_cert_destroy(item);
+			return TRUE;
+		}
+	}
+	return FALSE;
+}
+
+/**
+ * Adds a certificate to the certificate store
+ */
+static certificate_t *add_cert_internal(private_stroke_ca_t *this,
+										certificate_t *cert, bool automatic)
+{
+	ca_cert_t *found;
+
+	if (this->certs->find_first(this->certs, (linked_list_match_t)match_cert,
+								(void**)&found, cert) == SUCCESS)
+	{
+		cert->destroy(cert);
+		cert = found->cert->get_ref(found->cert);
+	}
+	else
+	{
+		INIT(found,
+			.cert = cert->get_ref(cert)
+		);
+		this->certs->insert_first(this->certs, found);
+	}
+	if (automatic)
+	{
+		found->automatic = TRUE;
+	}
+	else
+	{
+		found->count++;
+	}
+	return cert;
+}
+
 METHOD(stroke_ca_t, add, void,
 	private_stroke_ca_t *this, stroke_msg_t *msg)
 {
@@ -323,10 +440,10 @@ METHOD(stroke_ca_t, add, void,
 		DBG1(DBG_CFG, "missing cacert parameter");
 		return;
 	}
-	cert = this->cred->load_ca(this->cred, msg->add_ca.cacert);
+	cert = stroke_load_ca_cert(msg->add_ca.cacert);
 	if (cert)
 	{
-		ca = ca_section_create(msg->add_ca.name, cert);
+		ca = ca_section_create(msg->add_ca.name, msg->add_ca.cacert);
 		if (msg->add_ca.crluri)
 		{
 			ca->crl->insert_last(ca->crl, strdup(msg->add_ca.crluri));
@@ -348,6 +465,7 @@ METHOD(stroke_ca_t, add, void,
 			ca->certuribase = strdup(msg->add_ca.certuribase);
 		}
 		this->lock->write_lock(this->lock);
+		ca->cert = add_cert_internal(this, cert, FALSE);
 		this->sections->insert_last(this->sections, ca);
 		this->lock->unlock(this->lock);
 		DBG1(DBG_CFG, "added ca '%s'", msg->add_ca.name);
@@ -372,8 +490,12 @@ METHOD(stroke_ca_t, del, void,
 		ca = NULL;
 	}
 	enumerator->destroy(enumerator);
+	if (ca)
+	{
+		this->certs->remove(this->certs, ca->cert, (void*)remove_cert);
+	}
 	this->lock->unlock(this->lock);
-	if (ca == NULL)
+	if (!ca)
 	{
 		DBG1(DBG_CFG, "no ca named '%s' found\n", msg->del_ca.name);
 		return;
@@ -383,6 +505,88 @@ METHOD(stroke_ca_t, del, void,
 	lib->credmgr->flush_cache(lib->credmgr, CERT_ANY);
 }
 
+METHOD(stroke_ca_t, get_cert_ref, certificate_t*,
+	private_stroke_ca_t *this, certificate_t *cert)
+{
+	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)
+	{
+		cert->destroy(cert);
+		cert = found->cert->get_ref(found->cert);
+	}
+	this->lock->unlock(this->lock);
+	return cert;
+}
+
+METHOD(stroke_ca_t, reload_certs, void,
+	private_stroke_ca_t *this)
+{
+	enumerator_t *enumerator;
+	certificate_t *cert;
+	ca_section_t *ca;
+	certificate_type_t type = CERT_X509;
+
+	/* holding the write lock while loading/parsing certificates is not optimal,
+	 * however, there usually are not that many ca sections configured */
+	this->lock->write_lock(this->lock);
+	if (this->sections->get_count(this->sections))
+	{
+		DBG1(DBG_CFG, "rereading ca certificates in ca sections");
+	}
+	enumerator = this->sections->create_enumerator(this->sections);
+	while (enumerator->enumerate(enumerator, &ca))
+	{
+		cert = stroke_load_ca_cert(ca->path);
+		if (cert)
+		{
+			if (cert->equals(cert, ca->cert))
+			{
+				cert->destroy(cert);
+			}
+			else
+			{
+				this->certs->remove(this->certs, ca->cert, (void*)remove_cert);
+				ca->cert->destroy(ca->cert);
+				ca->cert = add_cert_internal(this, cert, FALSE);
+			}
+		}
+		else
+		{
+			DBG1(DBG_CFG, "failed to reload certificate '%s', removing ca '%s'",
+				 ca->path, ca->name);
+			this->sections->remove_at(this->sections, enumerator);
+			this->certs->remove(this->certs, ca->cert, (void*)remove_cert);
+			ca_section_destroy(ca);
+			type = CERT_ANY;
+		}
+	}
+	enumerator->destroy(enumerator);
+	this->lock->unlock(this->lock);
+	lib->credmgr->flush_cache(lib->credmgr, type);
+}
+
+METHOD(stroke_ca_t, replace_certs, void,
+	private_stroke_ca_t *this, mem_cred_t *certs)
+{
+	enumerator_t *enumerator;
+	certificate_t *cert;
+
+	enumerator = certs->set.create_cert_enumerator(&certs->set, CERT_X509,
+												   KEY_ANY, NULL, TRUE);
+	this->lock->write_lock(this->lock);
+	this->certs->remove(this->certs, NULL, (void*)remove_auto_certs);
+	while (enumerator->enumerate(enumerator, &cert))
+	{
+		cert = add_cert_internal(this, cert->get_ref(cert), TRUE);
+		cert->destroy(cert);
+	}
+	this->lock->unlock(this->lock);
+	enumerator->destroy(enumerator);
+	lib->credmgr->flush_cache(lib->credmgr, CERT_X509);
+}
 /**
  * list crl or ocsp URIs
  */
@@ -501,6 +705,7 @@ METHOD(stroke_ca_t, destroy, void,
 	private_stroke_ca_t *this)
 {
 	this->sections->destroy_function(this->sections, (void*)ca_section_destroy);
+	this->certs->destroy_function(this->certs, (void*)ca_cert_destroy);
 	this->lock->destroy(this->lock);
 	free(this);
 }
@@ -508,7 +713,7 @@ METHOD(stroke_ca_t, destroy, void,
 /*
  * see header file
  */
-stroke_ca_t *stroke_ca_create(stroke_cred_t *cred)
+stroke_ca_t *stroke_ca_create()
 {
 	private_stroke_ca_t *this;
 
@@ -524,12 +729,15 @@ stroke_ca_t *stroke_ca_create(stroke_cred_t *cred)
 			.add = _add,
 			.del = _del,
 			.list = _list,
+			.get_cert_ref = _get_cert_ref,
+			.reload_certs = _reload_certs,
+			.replace_certs = _replace_certs,
 			.check_for_hash_and_url = _check_for_hash_and_url,
 			.destroy = _destroy,
 		},
 		.sections = linked_list_create(),
+		.certs = linked_list_create(),
 		.lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
-		.cred = cred,
 	);
 
 	return &this->public;
diff --git a/src/libcharon/plugins/stroke/stroke_ca.h b/src/libcharon/plugins/stroke/stroke_ca.h
index 21af912..2740006 100644
--- a/src/libcharon/plugins/stroke/stroke_ca.h
+++ b/src/libcharon/plugins/stroke/stroke_ca.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 Tobias Brunner
+ * Copyright (C) 2008-2015 Tobias Brunner
  * Copyright (C) 2008 Martin Willi
  * Hochschule fuer Technik Rapperswil
  *
@@ -23,8 +23,7 @@
 #define STROKE_CA_H_
 
 #include <stroke_msg.h>
-
-#include "stroke_cred.h"
+#include <credentials/sets/mem_cred.h>
 
 typedef struct stroke_ca_t stroke_ca_t;
 
@@ -67,6 +66,29 @@ struct stroke_ca_t {
 	void (*check_for_hash_and_url)(stroke_ca_t *this, certificate_t* cert);
 
 	/**
+	 * Get a reference to a CA certificate if it is already stored,
+	 * otherwise returns the same certificate.
+	 *
+	 * @param cert		certificate to check
+	 * @return			reference to stored CA certifiate, or original
+	 */
+	certificate_t *(*get_cert_ref)(stroke_ca_t *this, certificate_t *cert);
+
+	/**
+	 * Reload CA certificates referenced in CA sections. Flushes the certificate
+	 * cache.
+	 */
+	void (*reload_certs)(stroke_ca_t *this);
+
+	/**
+	 * Replace automatically loaded CA certificates.  Flushes the certificate
+	 * cache.
+	 *
+	 * @param certs		credential set to take certificates from (not modified)
+	 */
+	void (*replace_certs)(stroke_ca_t *this, mem_cred_t *certs);
+
+	/**
 	 * Destroy a stroke_ca instance.
 	 */
 	void (*destroy)(stroke_ca_t *this);
@@ -75,6 +97,6 @@ struct stroke_ca_t {
 /**
  * Create a stroke_ca instance.
  */
-stroke_ca_t *stroke_ca_create(stroke_cred_t *cred);
+stroke_ca_t *stroke_ca_create();
 
 #endif /** STROKE_CA_H_ @}*/
diff --git a/src/libcharon/plugins/stroke/stroke_config.c b/src/libcharon/plugins/stroke/stroke_config.c
index 55ec7cd..f717194 100644
--- a/src/libcharon/plugins/stroke/stroke_config.c
+++ b/src/libcharon/plugins/stroke/stroke_config.c
@@ -184,19 +184,16 @@ static void add_proposals(private_stroke_config_t *this, char *string,
 }
 
 /**
- * Build an IKE config from a stroke message
+ * Check if any addresses in the given string are local
  */
-static ike_cfg_t *build_ike_cfg(private_stroke_config_t *this, stroke_msg_t *msg)
+static bool is_local(char *address, bool any_allowed)
 {
 	enumerator_t *enumerator;
-	stroke_end_t tmp_end;
-	ike_cfg_t *ike_cfg;
 	host_t *host;
-	u_int16_t ikeport;
-	char me[256], other[256], *token;
-	bool swapped = FALSE;;
+	char *token;
+	bool found = FALSE;
 
-	enumerator = enumerator_create_token(msg->add_conn.other.address, ",", " ");
+	enumerator = enumerator_create_token(address, ",", " ");
 	while (enumerator->enumerate(enumerator, &token))
 	{
 		if (!strchr(token, '/'))
@@ -207,40 +204,60 @@ static ike_cfg_t *build_ike_cfg(private_stroke_config_t *this, stroke_msg_t *msg
 				if (hydra->kernel_interface->get_interface(
 										hydra->kernel_interface, host, NULL))
 				{
-					DBG2(DBG_CFG, "left is other host, swapping ends");
-					tmp_end = msg->add_conn.me;
-					msg->add_conn.me = msg->add_conn.other;
-					msg->add_conn.other = tmp_end;
-					swapped = TRUE;
+					found = TRUE;
+				}
+				else if (any_allowed && host->is_anyaddr(host))
+				{
+					found = TRUE;
 				}
 				host->destroy(host);
+				if (found)
+				{
+					break;
+				}
 			}
 		}
 	}
 	enumerator->destroy(enumerator);
+	return found;
+}
 
-	if (!swapped)
+/**
+ * Swap ends if indicated by left|right
+ */
+static void swap_ends(stroke_msg_t *msg)
+{
+	if (!lib->settings->get_bool(lib->settings, "%s.plugins.stroke.allow_swap",
+								 TRUE, lib->ns))
 	{
-		enumerator = enumerator_create_token(msg->add_conn.me.address, ",", " ");
-		while (enumerator->enumerate(enumerator, &token))
-		{
-			if (!strchr(token, '/'))
-			{
-				host = host_create_from_dns(token, 0, 0);
-				if (host)
-				{
-					if (!hydra->kernel_interface->get_interface(
-										hydra->kernel_interface, host, NULL))
-					{
-						DBG1(DBG_CFG, "left nor right host is our side, "
-							 "assuming left=local");
-					}
-					host->destroy(host);
-				}
-			}
-		}
-		enumerator->destroy(enumerator);
+		return;
+	}
+
+	if (is_local(msg->add_conn.other.address, FALSE))
+	{
+		stroke_end_t tmp_end;
+
+		DBG2(DBG_CFG, "left is other host, swapping ends");
+		tmp_end = msg->add_conn.me;
+		msg->add_conn.me = msg->add_conn.other;
+		msg->add_conn.other = tmp_end;
+	}
+	else if (!is_local(msg->add_conn.me.address, TRUE))
+	{
+		DBG1(DBG_CFG, "left nor right host is our side, assuming left=local");
 	}
+}
+
+/**
+ * Build an IKE config from a stroke message
+ */
+static ike_cfg_t *build_ike_cfg(private_stroke_config_t *this, stroke_msg_t *msg)
+{
+	ike_cfg_t *ike_cfg;
+	u_int16_t ikeport;
+	char me[256], other[256];
+
+	swap_ends(msg);
 
 	if (msg->add_conn.me.allow_any)
 	{
diff --git a/src/libcharon/plugins/stroke/stroke_control.c b/src/libcharon/plugins/stroke/stroke_control.c
index 0084fbf..0125d17 100644
--- a/src/libcharon/plugins/stroke/stroke_control.c
+++ b/src/libcharon/plugins/stroke/stroke_control.c
@@ -109,7 +109,7 @@ static void charon_initiate(private_stroke_control_t *this, peer_cfg_t *peer_cfg
 	if (msg->output_verbosity < 0)
 	{
 		charon->controller->initiate(charon->controller, peer_cfg, child_cfg,
-									 NULL, NULL, 0);
+									 NULL, NULL, 0, FALSE);
 	}
 	else
 	{
@@ -118,7 +118,7 @@ static void charon_initiate(private_stroke_control_t *this, peer_cfg_t *peer_cfg
 
 		status = charon->controller->initiate(charon->controller,
 							peer_cfg, child_cfg, (controller_cb_t)stroke_log,
-							&info, this->timeout);
+							&info, this->timeout, FALSE);
 		switch (status)
 		{
 			case SUCCESS:
diff --git a/src/libcharon/plugins/stroke/stroke_cred.c b/src/libcharon/plugins/stroke/stroke_cred.c
index 5e423f1..4292888 100644
--- a/src/libcharon/plugins/stroke/stroke_cred.c
+++ b/src/libcharon/plugins/stroke/stroke_cred.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008-2013 Tobias Brunner
+ * Copyright (C) 2008-2015 Tobias Brunner
  * Copyright (C) 2008 Martin Willi
  * Hochschule fuer Technik Rapperswil
  *
@@ -75,11 +75,6 @@ struct private_stroke_cred_t {
 	mem_cred_t *creds;
 
 	/**
-	 * CA certificates
-	 */
-	mem_cred_t *cacerts;
-
-	/**
 	 * Attribute Authority certificates
 	 */
 	mem_cred_t *aacerts;
@@ -94,6 +89,11 @@ struct private_stroke_cred_t {
 	 * cache CRLs to disk?
 	 */
 	bool cachecrl;
+
+	/**
+	 * CA certificate store
+	 */
+	stroke_ca_t *ca;
 };
 
 /** Length of smartcard specifier parts (module, keyid) */
@@ -182,70 +182,6 @@ static certificate_t *load_from_smartcard(smartcard_format_t format,
 	return cred;
 }
 
-METHOD(stroke_cred_t, load_ca, certificate_t*,
-	private_stroke_cred_t *this, char *filename)
-{
-	certificate_t *cert = NULL;
-	char path[PATH_MAX];
-
-	if (strpfx(filename, "%smartcard"))
-	{
-		smartcard_format_t format;
-		char module[SC_PART_LEN], keyid[SC_PART_LEN];
-		u_int slot;
-
-		format = parse_smartcard(filename, &slot, module, keyid);
-		if (format != SC_FORMAT_INVALID)
-		{
-			cert = (certificate_t*)load_from_smartcard(format,
-							slot, module, keyid, CRED_CERTIFICATE, CERT_X509);
-		}
-	}
-	else
-	{
-		if (*filename == '/')
-		{
-			snprintf(path, sizeof(path), "%s", filename);
-		}
-		else
-		{
-			snprintf(path, sizeof(path), "%s/%s", CA_CERTIFICATE_DIR, filename);
-		}
-
-		if (this->force_ca_cert)
-		{	/* we treat this certificate as a CA certificate even if it has no
-			 * CA basic constraint */
-			cert = lib->creds->create(lib->creds,
-								  CRED_CERTIFICATE, CERT_X509,
-								  BUILD_FROM_FILE, path, BUILD_X509_FLAG, X509_CA,
-								  BUILD_END);
-		}
-		else
-		{
-			cert = lib->creds->create(lib->creds,
-								  CRED_CERTIFICATE, CERT_X509,
-								  BUILD_FROM_FILE, path,
-								  BUILD_END);
-		}
-	}
-	if (cert)
-	{
-		x509_t *x509 = (x509_t*)cert;
-
-		if (!(x509->get_flags(x509) & X509_CA))
-		{
-			DBG1(DBG_CFG, "  ca certificate \"%Y\" misses ca basic constraint, "
-				 "discarded", cert->get_subject(cert));
-			cert->destroy(cert);
-			return NULL;
-		}
-		DBG1(DBG_CFG, "  loaded ca certificate \"%Y\" from '%s'",
-			 cert->get_subject(cert), filename);
-		return this->creds->get_cert_ref(this->creds, cert);
-	}
-	return NULL;
-}
-
 METHOD(stroke_cred_t, load_peer, certificate_t*,
 	private_stroke_cred_t *this, char *filename)
 {
@@ -384,22 +320,52 @@ METHOD(stroke_cred_t, load_pubkey, certificate_t*,
 }
 
 /**
- * Load a CA certificate  from disk
+ * Load a CA certificate, optionally force it to be one
  */
-static void load_x509_ca(private_stroke_cred_t *this, char *file)
+static certificate_t *load_ca_cert(char *filename, bool force_ca_cert)
 {
-	certificate_t *cert;
+	certificate_t *cert = NULL;
+	char path[PATH_MAX];
+
+	if (strpfx(filename, "%smartcard"))
+	{
+		smartcard_format_t format;
+		char module[SC_PART_LEN], keyid[SC_PART_LEN];
+		u_int slot;
 
-	if (this->force_ca_cert)
-	{	/* treat certificate as CA cert even it has no CA basic constraint */
-		cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
-								  BUILD_FROM_FILE, file,
-								  BUILD_X509_FLAG, X509_CA, BUILD_END);
+		format = parse_smartcard(filename, &slot, module, keyid);
+		if (format != SC_FORMAT_INVALID)
+		{
+			cert = (certificate_t*)load_from_smartcard(format,
+							slot, module, keyid, CRED_CERTIFICATE, CERT_X509);
+		}
 	}
 	else
 	{
-		cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
-								  BUILD_FROM_FILE, file, BUILD_END);
+		if (*filename == '/')
+		{
+			snprintf(path, sizeof(path), "%s", filename);
+		}
+		else
+		{
+			snprintf(path, sizeof(path), "%s/%s", CA_CERTIFICATE_DIR, filename);
+		}
+
+		if (force_ca_cert)
+		{	/* we treat this certificate as a CA certificate even if it has no
+			 * CA basic constraint */
+			cert = lib->creds->create(lib->creds,
+								  CRED_CERTIFICATE, CERT_X509,
+								  BUILD_FROM_FILE, path, BUILD_X509_FLAG, X509_CA,
+								  BUILD_END);
+		}
+		else
+		{
+			cert = lib->creds->create(lib->creds,
+								  CRED_CERTIFICATE, CERT_X509,
+								  BUILD_FROM_FILE, path,
+								  BUILD_END);
+		}
 	}
 	if (cert)
 	{
@@ -410,13 +376,41 @@ static void load_x509_ca(private_stroke_cred_t *this, char *file)
 			DBG1(DBG_CFG, "  ca certificate \"%Y\" lacks ca basic constraint, "
 				 "discarded", cert->get_subject(cert));
 			cert->destroy(cert);
+			return NULL;
 		}
-		else
-		{
-			DBG1(DBG_CFG, "  loaded ca certificate \"%Y\" from '%s'",
-				 cert->get_subject(cert), file);
-			this->cacerts->add_cert(this->cacerts, TRUE, cert);
-		}
+		DBG1(DBG_CFG, "  loaded ca certificate \"%Y\" from '%s'",
+			 cert->get_subject(cert), filename);
+		return cert;
+	}
+	return NULL;
+}
+
+/**
+ * Used by stroke_ca.c
+ */
+certificate_t *stroke_load_ca_cert(char *filename)
+{
+	bool force_ca_cert;
+
+	force_ca_cert = lib->settings->get_bool(lib->settings,
+						"%s.plugins.stroke.ignore_missing_ca_basic_constraint",
+						FALSE, lib->ns);
+	return load_ca_cert(filename, force_ca_cert);
+}
+
+/**
+ * Load a CA certificate from disk
+ */
+static void load_x509_ca(private_stroke_cred_t *this, char *file,
+						 mem_cred_t *creds)
+{
+	certificate_t *cert;
+
+	cert = load_ca_cert(file, this->force_ca_cert);
+	if (cert)
+	{
+		cert = this->ca->get_cert_ref(this->ca, cert);
+		creds->add_cert(creds, TRUE, cert);
 	}
 	else
 	{
@@ -427,7 +421,8 @@ static void load_x509_ca(private_stroke_cred_t *this, char *file)
 /**
  * Load AA certificate with flags from disk
  */
-static void load_x509_aa(private_stroke_cred_t *this, char *file)
+static void load_x509_aa(private_stroke_cred_t *this,char *file,
+						 mem_cred_t *creds)
 {
 	certificate_t *cert;
 
@@ -438,7 +433,7 @@ static void load_x509_aa(private_stroke_cred_t *this, char *file)
 	{
 		DBG1(DBG_CFG, "  loaded AA certificate \"%Y\" from '%s'",
 			 cert->get_subject(cert), file);
-		this->aacerts->add_cert(this->aacerts, TRUE, cert);
+		creds->add_cert(creds, TRUE, cert);
 	}
 	else
 	{
@@ -449,7 +444,8 @@ static void load_x509_aa(private_stroke_cred_t *this, char *file)
 /**
  * Load a certificate with flags from disk
  */
-static void load_x509(private_stroke_cred_t *this, char *file, x509_flag_t flag)
+static void load_x509(private_stroke_cred_t *this, char *file, x509_flag_t flag,
+					  mem_cred_t *creds)
 {
 	certificate_t *cert;
 
@@ -461,7 +457,7 @@ static void load_x509(private_stroke_cred_t *this, char *file, x509_flag_t flag)
 	{
 		DBG1(DBG_CFG, "  loaded certificate \"%Y\" from '%s'",
 			 cert->get_subject(cert), file);
-		this->creds->add_cert(this->creds, TRUE, cert);
+		creds->add_cert(creds, TRUE, cert);
 	}
 	else
 	{
@@ -472,7 +468,8 @@ static void load_x509(private_stroke_cred_t *this, char *file, x509_flag_t flag)
 /**
  * Load a CRL from a file
  */
-static void load_x509_crl(private_stroke_cred_t *this, char *file)
+static void load_x509_crl(private_stroke_cred_t *this, char *file,
+						  mem_cred_t *creds)
 {
 	certificate_t *cert;
 
@@ -480,8 +477,8 @@ static void load_x509_crl(private_stroke_cred_t *this, char *file)
 							  BUILD_FROM_FILE, file, BUILD_END);
 	if (cert)
 	{
-		this->creds->add_crl(this->creds, (crl_t*)cert);
 		DBG1(DBG_CFG, "  loaded crl from '%s'",  file);
+		creds->add_crl(creds, (crl_t*)cert);
 	}
 	else
 	{
@@ -492,7 +489,8 @@ static void load_x509_crl(private_stroke_cred_t *this, char *file)
 /**
  * Load an attribute certificate from a file
  */
-static void load_x509_ac(private_stroke_cred_t *this, char *file)
+static void load_x509_ac(private_stroke_cred_t *this, char *file,
+						 mem_cred_t *creds)
 {
 	certificate_t *cert;
 
@@ -501,7 +499,7 @@ static void load_x509_ac(private_stroke_cred_t *this, char *file)
 	if (cert)
 	{
 		DBG1(DBG_CFG, "  loaded attribute certificate from '%s'", file);
-		this->creds->add_cert(this->creds, FALSE, cert);
+		creds->add_cert(creds, FALSE, cert);
 	}
 	else
 	{
@@ -513,7 +511,8 @@ static void load_x509_ac(private_stroke_cred_t *this, char *file)
  * load trusted certificates from a directory
  */
 static void load_certdir(private_stroke_cred_t *this, char *path,
-						 certificate_type_t type, x509_flag_t flag)
+						 certificate_type_t type, x509_flag_t flag,
+						 mem_cred_t *creds)
 {
 	enumerator_t *enumerator;
 	struct stat st;
@@ -534,22 +533,22 @@ static void load_certdir(private_stroke_cred_t *this, char *path,
 				case CERT_X509:
 					if (flag & X509_CA)
 					{
-						load_x509_ca(this, file);
+						load_x509_ca(this, file, creds);
 					}
 					else if (flag & X509_AA)
 					{
-						load_x509_aa(this, file);
+						load_x509_aa(this, file, creds);
 					}
 					else
 					{
-						load_x509(this, file, flag);
+						load_x509(this, file, flag, creds);
 					}
 					break;
 				case CERT_X509_CRL:
-					load_x509_crl(this, file);
+					load_x509_crl(this, file, creds);
 					break;
 				case CERT_X509_AC:
-					load_x509_ac(this, file);
+					load_x509_ac(this, file, creds);
 					break;
 				default:
 					break;
@@ -1348,30 +1347,38 @@ static void load_secrets(private_stroke_cred_t *this, mem_cred_t *secrets,
  */
 static void load_certs(private_stroke_cred_t *this)
 {
+	mem_cred_t *creds;
+
 	DBG1(DBG_CFG, "loading ca certificates from '%s'",
 		 CA_CERTIFICATE_DIR);
-	load_certdir(this, CA_CERTIFICATE_DIR, CERT_X509, X509_CA);
+	creds = mem_cred_create();
+	load_certdir(this, CA_CERTIFICATE_DIR, CERT_X509, X509_CA, creds);
+	this->ca->replace_certs(this->ca, creds);
+	creds->destroy(creds);
 
 	DBG1(DBG_CFG, "loading aa certificates from '%s'",
 		 AA_CERTIFICATE_DIR);
-	load_certdir(this, AA_CERTIFICATE_DIR, CERT_X509, X509_AA);
+	load_certdir(this, AA_CERTIFICATE_DIR, CERT_X509, X509_AA, this->aacerts);
 
 	DBG1(DBG_CFG, "loading ocsp signer certificates from '%s'",
 		 OCSP_CERTIFICATE_DIR);
-	load_certdir(this, OCSP_CERTIFICATE_DIR, CERT_X509, X509_OCSP_SIGNER);
+	load_certdir(this, OCSP_CERTIFICATE_DIR, CERT_X509, X509_OCSP_SIGNER,
+				 this->creds);
 
 	DBG1(DBG_CFG, "loading attribute certificates from '%s'",
 		 ATTR_CERTIFICATE_DIR);
-	load_certdir(this, ATTR_CERTIFICATE_DIR, CERT_X509_AC, 0);
+	load_certdir(this, ATTR_CERTIFICATE_DIR, CERT_X509_AC, 0, this->creds);
 
 	DBG1(DBG_CFG, "loading crls from '%s'",
 		 CRL_DIR);
-	load_certdir(this, CRL_DIR, CERT_X509_CRL, 0);
+	load_certdir(this, CRL_DIR, CERT_X509_CRL, 0, this->creds);
 }
 
 METHOD(stroke_cred_t, reread, void,
 	private_stroke_cred_t *this, stroke_msg_t *msg, FILE *prompt)
 {
+	mem_cred_t *creds;
+
 	if (msg->reread.flags & REREAD_SECRETS)
 	{
 		DBG1(DBG_CFG, "rereading secrets");
@@ -1379,38 +1386,44 @@ METHOD(stroke_cred_t, reread, void,
 	}
 	if (msg->reread.flags & REREAD_CACERTS)
 	{
+		/* first reload certificates in ca sections, so we can refer to them */
+		this->ca->reload_certs(this->ca);
+
 		DBG1(DBG_CFG, "rereading ca certificates from '%s'",
 			 CA_CERTIFICATE_DIR);
-		this->cacerts->clear(this->cacerts);
+		creds = mem_cred_create();
+		load_certdir(this, CA_CERTIFICATE_DIR, CERT_X509, X509_CA, creds);
+		this->ca->replace_certs(this->ca, creds);
+		creds->destroy(creds);
+	}
+	if (msg->reread.flags & REREAD_AACERTS)
+	{
+		DBG1(DBG_CFG, "rereading aa certificates from '%s'",
+			 AA_CERTIFICATE_DIR);
+		creds = mem_cred_create();
+		load_certdir(this, AA_CERTIFICATE_DIR, CERT_X509, X509_AA, creds);
+		this->aacerts->replace_certs(this->aacerts, creds, FALSE);
+		creds->destroy(creds);
 		lib->credmgr->flush_cache(lib->credmgr, CERT_X509);
-		load_certdir(this, CA_CERTIFICATE_DIR, CERT_X509, X509_CA);
 	}
 	if (msg->reread.flags & REREAD_OCSPCERTS)
 	{
 		DBG1(DBG_CFG, "rereading ocsp signer certificates from '%s'",
 			 OCSP_CERTIFICATE_DIR);
 		load_certdir(this, OCSP_CERTIFICATE_DIR, CERT_X509,
-			 X509_OCSP_SIGNER);
-	}
-	if (msg->reread.flags & REREAD_AACERTS)
-	{
-		DBG1(DBG_CFG, "rereading aa certificates from '%s'",
-			 AA_CERTIFICATE_DIR);
-		this->aacerts->clear(this->aacerts);
-		lib->credmgr->flush_cache(lib->credmgr, CERT_X509);
-		load_certdir(this, AA_CERTIFICATE_DIR, CERT_X509, X509_AA);
+			 X509_OCSP_SIGNER, this->creds);
 	}
 	if (msg->reread.flags & REREAD_ACERTS)
 	{
 		DBG1(DBG_CFG, "rereading attribute certificates from '%s'",
 			 ATTR_CERTIFICATE_DIR);
-		load_certdir(this, ATTR_CERTIFICATE_DIR, CERT_X509_AC, 0);
+		load_certdir(this, ATTR_CERTIFICATE_DIR, CERT_X509_AC, 0, this->creds);
 	}
 	if (msg->reread.flags & REREAD_CRLS)
 	{
 		DBG1(DBG_CFG, "rereading crls from '%s'",
 			 CRL_DIR);
-		load_certdir(this, CRL_DIR, CERT_X509_CRL, 0);
+		load_certdir(this, CRL_DIR, CERT_X509_CRL, 0, this->creds);
 	}
 }
 
@@ -1424,10 +1437,8 @@ METHOD(stroke_cred_t, destroy, void,
 	private_stroke_cred_t *this)
 {
 	lib->credmgr->remove_set(lib->credmgr, &this->aacerts->set);
-	lib->credmgr->remove_set(lib->credmgr, &this->cacerts->set);
 	lib->credmgr->remove_set(lib->credmgr, &this->creds->set);
 	this->aacerts->destroy(this->aacerts);
-	this->cacerts->destroy(this->cacerts);
 	this->creds->destroy(this->creds);
 	free(this);
 }
@@ -1435,7 +1446,7 @@ METHOD(stroke_cred_t, destroy, void,
 /*
  * see header file
  */
-stroke_cred_t *stroke_cred_create()
+stroke_cred_t *stroke_cred_create(stroke_ca_t *ca)
 {
 	private_stroke_cred_t *this;
 
@@ -1449,7 +1460,6 @@ stroke_cred_t *stroke_cred_create()
 				.cache_cert = (void*)_cache_cert,
 			},
 			.reread = _reread,
-			.load_ca = _load_ca,
 			.load_peer = _load_peer,
 			.load_pubkey = _load_pubkey,
 			.add_shared = _add_shared,
@@ -1460,12 +1470,11 @@ stroke_cred_t *stroke_cred_create()
 								"%s.plugins.stroke.secrets_file", SECRETS_FILE,
 								lib->ns),
 		.creds = mem_cred_create(),
-		.cacerts = mem_cred_create(),
 		.aacerts = mem_cred_create(),
+		.ca = ca,
 	);
 
 	lib->credmgr->add_set(lib->credmgr, &this->creds->set);
-	lib->credmgr->add_set(lib->credmgr, &this->cacerts->set);
 	lib->credmgr->add_set(lib->credmgr, &this->aacerts->set);
 
 	this->force_ca_cert = lib->settings->get_bool(lib->settings,
diff --git a/src/libcharon/plugins/stroke/stroke_cred.h b/src/libcharon/plugins/stroke/stroke_cred.h
index 9434629..33a0e35 100644
--- a/src/libcharon/plugins/stroke/stroke_cred.h
+++ b/src/libcharon/plugins/stroke/stroke_cred.h
@@ -29,6 +29,8 @@
 #include <credentials/certificates/certificate.h>
 #include <collections/linked_list.h>
 
+#include "stroke_ca.h"
+
 typedef struct stroke_cred_t stroke_cred_t;
 
 /**
@@ -50,17 +52,6 @@ struct stroke_cred_t {
 	void (*reread)(stroke_cred_t *this, stroke_msg_t *msg, FILE *prompt);
 
 	/**
-	 * Load a CA certificate.
-	 *
-	 * This method does not add the loaded CA certificate to the internal
-	 * credentail set, but returns it only.
-	 *
-	 * @param filename		file to load CA cert from
-	 * @return				loaded certificate, or NULL
-	 */
-	certificate_t* (*load_ca)(stroke_cred_t *this, char *filename);
-
-	/**
 	 * Load a peer certificate and serve it through the credential_set.
 	 *
 	 * @param filename		file to load peer cert from
@@ -103,6 +94,6 @@ struct stroke_cred_t {
 /**
  * Create a stroke_cred instance.
  */
-stroke_cred_t *stroke_cred_create();
+stroke_cred_t *stroke_cred_create(stroke_ca_t *ca);
 
 #endif /** STROKE_CRED_H_ @}*/
diff --git a/src/libcharon/plugins/stroke/stroke_list.c b/src/libcharon/plugins/stroke/stroke_list.c
index 68b8232..c7e4c9c 100644
--- a/src/libcharon/plugins/stroke/stroke_list.c
+++ b/src/libcharon/plugins/stroke/stroke_list.c
@@ -647,7 +647,7 @@ METHOD(stroke_list_t, status, void,
 	enumerator->destroy(enumerator);
 
 	half_open = charon->ike_sa_manager->get_half_open_count(
-												charon->ike_sa_manager, NULL);
+										charon->ike_sa_manager, NULL, FALSE);
 	fprintf(out, "Security Associations (%u up, %u connecting):\n",
 		charon->ike_sa_manager->get_count(charon->ike_sa_manager) - half_open,
 		half_open);
diff --git a/src/libcharon/plugins/stroke/stroke_socket.c b/src/libcharon/plugins/stroke/stroke_socket.c
index db7e66f..29563e3 100644
--- a/src/libcharon/plugins/stroke/stroke_socket.c
+++ b/src/libcharon/plugins/stroke/stroke_socket.c
@@ -779,10 +779,10 @@ stroke_socket_t *stroke_socket_create()
 				"%s.plugins.stroke.prevent_loglevel_changes", FALSE, lib->ns),
 	);
 
-	this->cred = stroke_cred_create();
+	this->ca = stroke_ca_create();
+	this->cred = stroke_cred_create(this->ca);
 	this->attribute = stroke_attribute_create();
 	this->handler = stroke_handler_create();
-	this->ca = stroke_ca_create(this->cred);
 	this->config = stroke_config_create(this->ca, this->cred, this->attribute);
 	this->control = stroke_control_create();
 	this->list = stroke_list_create(this->attribute);
diff --git a/src/libcharon/plugins/tnc_ifmap/tnc_ifmap_renew_session_job.h b/src/libcharon/plugins/tnc_ifmap/tnc_ifmap_renew_session_job.h
index 91e8fe4..f1587a1 100644
--- a/src/libcharon/plugins/tnc_ifmap/tnc_ifmap_renew_session_job.h
+++ b/src/libcharon/plugins/tnc_ifmap/tnc_ifmap_renew_session_job.h
@@ -15,7 +15,7 @@
 
 /**
  * @defgroup tnc_ifmap_renew_session_job tnc_ifmap_renew_session_job
- * @{ @ingroup cjobs
+ * @{ @ingroup tnc_ifmap
  */
 
 #ifndef TNC_IFMAP_RENEW_SESSION_JOB_H_
diff --git a/src/libcharon/plugins/uci/uci_control.c b/src/libcharon/plugins/uci/uci_control.c
index cebc389..a7d26e6 100644
--- a/src/libcharon/plugins/uci/uci_control.c
+++ b/src/libcharon/plugins/uci/uci_control.c
@@ -147,7 +147,7 @@ static void initiate(private_uci_control_t *this, char *name)
 		if (enumerator->enumerate(enumerator, &child_cfg) &&
 			charon->controller->initiate(charon->controller, peer_cfg,
 								child_cfg->get_ref(child_cfg),
-								controller_cb_empty, NULL, 0) == SUCCESS)
+								controller_cb_empty, NULL, 0, FALSE) == SUCCESS)
 		{
 			write_fifo(this, "connection '%s' established\n", name);
 		}
diff --git a/src/libcharon/plugins/updown/updown_listener.c b/src/libcharon/plugins/updown/updown_listener.c
index be65d59..96282be 100644
--- a/src/libcharon/plugins/updown/updown_listener.c
+++ b/src/libcharon/plugins/updown/updown_listener.c
@@ -169,31 +169,34 @@ static void push_dns_env(private_updown_listener_t *this, ike_sa_t *ike_sa,
 }
 
 /**
- * Push variables for local virtual IPs
+ * Push variables for local/remote virtual IPs
  */
 static void push_vip_env(private_updown_listener_t *this, ike_sa_t *ike_sa,
-						 char *envp[], u_int count)
+						 char *envp[], u_int count, bool local)
 {
 	enumerator_t *enumerator;
 	host_t *host;
 	int v4 = 0, v6 = 0;
 	bool first = TRUE;
 
-	enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, TRUE);
+	enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, local);
 	while (enumerator->enumerate(enumerator, &host))
 	{
 		if (first)
 		{	/* legacy variable for first VIP */
 			first = FALSE;
-			push_env(envp, count, "PLUTO_MY_SOURCEIP=%H", host);
+			push_env(envp, count, "PLUTO_%s_SOURCEIP=%H",
+					 local ? "MY" : "PEER", host);
 		}
 		switch (host->get_family(host))
 		{
 			case AF_INET:
-				push_env(envp, count, "PLUTO_MY_SOURCEIP4_%d=%H", ++v4, host);
+				push_env(envp, count, "PLUTO_%s_SOURCEIP4_%d=%H",
+						 local ? "MY" : "PEER", ++v4, host);
 				break;
 			case AF_INET6:
-				push_env(envp, count, "PLUTO_MY_SOURCEIP6_%d=%H", ++v6, host);
+				push_env(envp, count, "PLUTO_%s_SOURCEIP6_%d=%H",
+						 local ? "MY" : "PEER", ++v6, host);
 				break;
 			default:
 				continue;
@@ -313,7 +316,8 @@ static void invoke_once(private_updown_listener_t *this, ike_sa_t *ike_sa,
 		push_env(envp, countof(envp), "PLUTO_XAUTH_ID=%Y",
 				 ike_sa->get_other_eap_id(ike_sa));
 	}
-	push_vip_env(this, ike_sa, envp, countof(envp));
+	push_vip_env(this, ike_sa, envp, countof(envp), TRUE);
+	push_vip_env(this, ike_sa, envp, countof(envp), FALSE);
 	mark = config->get_mark(config, TRUE);
 	if (mark.value)
 	{
diff --git a/src/libcharon/plugins/vici/Makefile.am b/src/libcharon/plugins/vici/Makefile.am
index b253960..c99d23e 100644
--- a/src/libcharon/plugins/vici/Makefile.am
+++ b/src/libcharon/plugins/vici/Makefile.am
@@ -23,6 +23,7 @@ libstrongswan_vici_la_SOURCES = \
 	vici_config.h vici_config.c \
 	vici_cred.h vici_cred.c \
 	vici_attribute.h vici_attribute.c \
+	vici_authority.h vici_authority.c \
 	vici_logger.h vici_logger.c \
 	vici_plugin.h vici_plugin.c
 
diff --git a/src/libcharon/plugins/vici/Makefile.in b/src/libcharon/plugins/vici/Makefile.in
index b63226d..1a7870a 100644
--- a/src/libcharon/plugins/vici/Makefile.in
+++ b/src/libcharon/plugins/vici/Makefile.in
@@ -136,7 +136,7 @@ libstrongswan_vici_la_LIBADD =
 am_libstrongswan_vici_la_OBJECTS = vici_socket.lo vici_message.lo \
 	vici_builder.lo vici_dispatcher.lo vici_query.lo \
 	vici_control.lo vici_config.lo vici_cred.lo vici_attribute.lo \
-	vici_logger.lo vici_plugin.lo
+	vici_authority.lo vici_logger.lo vici_plugin.lo
 libstrongswan_vici_la_OBJECTS = $(am_libstrongswan_vici_la_OBJECTS)
 AM_V_lt = $(am__v_lt_ at AM_V@)
 am__v_lt_ = $(am__v_lt_ at AM_DEFAULT_V@)
@@ -543,6 +543,7 @@ libstrongswan_vici_la_SOURCES = \
 	vici_config.h vici_config.c \
 	vici_cred.h vici_cred.c \
 	vici_attribute.h vici_attribute.c \
+	vici_authority.h vici_authority.c \
 	vici_logger.h vici_logger.c \
 	vici_plugin.h vici_plugin.c
 
@@ -736,6 +737,7 @@ distclean-compile:
 
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libvici.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/vici_attribute.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/vici_authority.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/vici_builder.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/vici_config.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/vici_control.Plo at am__quote@
diff --git a/src/libcharon/plugins/vici/README.md b/src/libcharon/plugins/vici/README.md
index 0ce4271..e20e8ab 100644
--- a/src/libcharon/plugins/vici/README.md
+++ b/src/libcharon/plugins/vici/README.md
@@ -259,6 +259,7 @@ Initiates an SA while streaming _control-log_ events.
 	{
 		child = <CHILD_SA configuration name to initiate>
 		timeout = <timeout in seconds before returning>
+		init-limits = <whether limits may prevent initiating the CHILD_SA>
 		loglevel = <loglevel to issue "control-log" events for>
 	} => {
 		success = <yes or no>
@@ -366,6 +367,27 @@ over vici.
 		# completes after streaming list-cert events
 	}
 
+### list-authorities() ###
+
+List currently loaded certification authority information by streaming
+_list-authority_ events.
+
+	{
+		name = <list certification authority of a given name>
+	} => {
+		# completes after streaming list-authority events
+	}
+
+### get-authorities() ###
+
+Return a list of currently loaded certification authority names.
+
+	{} => {
+		authorities = [
+			<list of certification authority names>
+		]
+	}
+
 ### load-conn() ###
 
 Load a single connection definition into the daemon. An existing connection
@@ -442,6 +464,32 @@ credential cache.
 		errmsg = <error string on failure>
 	}
 
+### load-authority() ###
+
+Load a single certification authority definition into the daemon. An existing
+authority with the same name gets replaced.
+
+	{
+		<certification authority name> = {
+			# certification authority parameters
+			# refer to swanctl.conf(5) for details.
+		} => {
+			success = <yes or no>
+			errmsg = <error string on failure>
+		}
+	}
+
+### unload-authority() ###
+
+Unload a previously loaded certification authority definition by name.
+
+	{
+		name = <certification authority name>
+	} => {
+		success = <yes or no>
+		errmsg = <error string on failure>
+	}
+
 ### load-pool() ###
 
 Load an in-memory virtual IP and configuration attribute pool. Existing
@@ -673,6 +721,82 @@ _list-certs_ command.
 		data = <ASN1 encoded certificate data>
 	}
 
+### list-authority ###
+
+The _list-authority_ event is issued to stream loaded certification authority
+information during an active_list-authorities_ command.
+
+	{
+		<certification authority name> = {
+			cacert = <subject distinguished name of CA certificate>
+			crl_uris = [
+				<CRL URI (http, ldap or file)>
+			]
+			ocsp_uris = [
+				<OCSP URI (http)>
+			]
+			cert_uri_base = <base URI for download of hash-and-URL certificates>
+		}
+	}
+
+### ike-updown ###
+
+The _ike-updown_ event is issued when an IKE_SA is established or terminated.
+
+	{
+		up = <yes or no>
+		<IKE_SA config name> = {
+			<same data as in the list-sas event, but without child-sas section>
+		}
+	}
+
+### ike-rekey ###
+
+The _ike-rekey_ event is issued when an IKE_SA is rekeyed.
+
+	{
+		<IKE_SA config name> = {
+			old = {
+				<same data as in the list-sas event, but without child-sas section>
+			}
+			new = {
+				<same data as in the list-sas event, but without child-sas section>
+			}
+		}
+	}
+
+### child-updown ###
+
+The _child-updown_ event is issued when a CHILD_SA is established or terminated.
+
+	{
+		up = <yes or no>
+		<IKE_SA config name> = {
+			<same data as in the list-sas event, but with only the affected
+			 CHILD_SA in the child-sas section>
+		}
+	}
+
+### child-rekey ###
+
+The _child-rekey_ event is issued when a CHILD_SA is rekeyed.
+
+	{
+		<IKE_SA config name> = {
+			<same data as in the list-sas event, but with the child-sas section
+			 as follows>
+			child-sas = {
+				<child-sa-name> = {
+					old = {
+						<same data as in the list-sas event>
+					}
+					new = {
+						<same data as in the list-sas event>
+					}
+				}
+			}
+		}
+	}
 
 # libvici C client library #
 
diff --git a/src/libcharon/plugins/vici/python/LICENSE b/src/libcharon/plugins/vici/python/LICENSE
index 111523c..54f2158 100644
--- a/src/libcharon/plugins/vici/python/LICENSE
+++ b/src/libcharon/plugins/vici/python/LICENSE
@@ -1,4 +1,6 @@
 Copyright (c) 2015 Björn Schuberg
+Copyright (c) 2015 Martin Willi
+Copyright (c) 2015 Tobias Brunner
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
diff --git a/src/libcharon/plugins/vici/python/vici/exception.py b/src/libcharon/plugins/vici/python/vici/exception.py
index 36384e5..757ac51 100644
--- a/src/libcharon/plugins/vici/python/vici/exception.py
+++ b/src/libcharon/plugins/vici/python/vici/exception.py
@@ -8,3 +8,6 @@ class SessionException(Exception):
 
 class CommandException(Exception):
     """Command result exception."""
+
+class EventUnknownException(Exception):
+    """Event unknown exception."""
diff --git a/src/libcharon/plugins/vici/python/vici/session.py b/src/libcharon/plugins/vici/python/vici/session.py
index dee5869..283e3d1 100644
--- a/src/libcharon/plugins/vici/python/vici/session.py
+++ b/src/libcharon/plugins/vici/python/vici/session.py
@@ -1,7 +1,7 @@
 import collections
 import socket
 
-from .exception import SessionException, CommandException
+from .exception import SessionException, CommandException, EventUnknownException
 from .protocol import Transport, Packet, Message
 
 
@@ -197,6 +197,16 @@ class Session(object):
         """
         return self.handler.request("get-pools")
 
+    def listen(self, event_types):
+        """Register and listen for the given events.
+
+        :param event_types: event types to register
+        :type event_types: list
+        :return: generator for streamed event responses as (event_type, dict)
+        :rtype: generator
+        """
+        return self.handler.listen(event_types)
+
 
 class SessionHandler(object):
     """Handles client command execution requests over vici."""
@@ -215,6 +225,32 @@ class SessionHandler(object):
         self.transport.send(packet)
         return Packet.parse(self.transport.receive())
 
+    def _register_unregister(self, event_type, register):
+        """Register or unregister for the given event.
+
+        :param event_type: event to register
+        :type event_type: str
+        :param register: whether to register or unregister
+        :type register: bool
+        """
+        if register:
+            packet = Packet.register_event(event_type)
+        else:
+            packet = Packet.unregister_event(event_type)
+        response = self._communicate(packet)
+        if response.response_type == Packet.EVENT_UNKNOWN:
+            raise EventUnknownException(
+                "Unknown event type '{event}'".format(event=event_type)
+            )
+        elif response.response_type != Packet.EVENT_CONFIRM:
+            raise SessionException(
+                "Unexpected response type {type}, "
+                "expected '{confirm}' (EVENT_CONFIRM)".format(
+                    type=response.response_type,
+                    confirm=Packet.EVENT_CONFIRM,
+                )
+            )
+
     def request(self, command, message=None):
         """Send request with an optional message.
 
@@ -265,57 +301,37 @@ class SessionHandler(object):
         if message is not None:
             message = Message.serialize(message)
 
-        # subscribe to event stream
-        packet = Packet.register_event(event_stream_type)
-        response = self._communicate(packet)
-
-        if response.response_type != Packet.EVENT_CONFIRM:
-            raise SessionException(
-                "Unexpected response type {type}, "
-                "expected '{confirm}' (EVENT_CONFIRM)".format(
-                    type=response.response_type,
-                    confirm=Packet.EVENT_CONFIRM,
-                )
-            )
-
-        # issue command, and read any event messages
-        packet = Packet.request(command, message)
-        self.transport.send(packet)
-        exited = False
-        while True:
-            response = Packet.parse(self.transport.receive())
-            if response.response_type == Packet.EVENT:
-                if not exited:
-                    try:
-                        yield Message.deserialize(response.payload)
-                    except GeneratorExit:
-                        exited = True
-                        pass
+        self._register_unregister(event_stream_type, True);
+
+        try:
+            packet = Packet.request(command, message)
+            self.transport.send(packet)
+            exited = False
+            while True:
+                response = Packet.parse(self.transport.receive())
+                if response.response_type == Packet.EVENT:
+                    if not exited:
+                        try:
+                            yield Message.deserialize(response.payload)
+                        except GeneratorExit:
+                            exited = True
+                            pass
+                else:
+                    break
+
+            if response.response_type == Packet.CMD_RESPONSE:
+                command_response = Message.deserialize(response.payload)
             else:
-                break
-
-        if response.response_type == Packet.CMD_RESPONSE:
-            command_response = Message.deserialize(response.payload)
-        else:
-            raise SessionException(
-                "Unexpected response type {type}, "
-                "expected '{response}' (CMD_RESPONSE)".format(
-                    type=response.response_type,
-                    response=Packet.CMD_RESPONSE
+                raise SessionException(
+                    "Unexpected response type {type}, "
+                    "expected '{response}' (CMD_RESPONSE)".format(
+                        type=response.response_type,
+                        response=Packet.CMD_RESPONSE
+                    )
                 )
-            )
 
-        # unsubscribe from event stream
-        packet = Packet.unregister_event(event_stream_type)
-        response = self._communicate(packet)
-        if response.response_type != Packet.EVENT_CONFIRM:
-            raise SessionException(
-                "Unexpected response type {type}, "
-                "expected '{confirm}' (EVENT_CONFIRM)".format(
-                    type=response.response_type,
-                    confirm=Packet.EVENT_CONFIRM,
-                )
-            )
+        finally:
+            self._register_unregister(event_stream_type, False);
 
         # evaluate command result, if any
         if "success" in command_response:
@@ -325,3 +341,27 @@ class SessionHandler(object):
                         errmsg=command_response["errmsg"]
                     )
                 )
+
+    def listen(self, event_types):
+        """Register and listen for the given events.
+
+        :param event_types: event types to register
+        :type event_types: list
+        :return: generator for streamed event responses as (event_type, dict)
+        :rtype: generator
+        """
+        for event_type in event_types:
+            self._register_unregister(event_type, True)
+
+        try:
+            while True:
+                response = Packet.parse(self.transport.receive())
+                if response.response_type == Packet.EVENT:
+                    try:
+                        yield response.event_type, Message.deserialize(response.payload)
+                    except GeneratorExit:
+                        break
+
+        finally:
+            for event_type in event_types:
+                self._register_unregister(event_type, False)
diff --git a/src/libcharon/plugins/vici/ruby/lib/vici.rb b/src/libcharon/plugins/vici/ruby/lib/vici.rb
index f87e46e..f8169ad 100644
--- a/src/libcharon/plugins/vici/ruby/lib/vici.rb
+++ b/src/libcharon/plugins/vici/ruby/lib/vici.rb
@@ -247,7 +247,11 @@ module Vici
     def recv_all(len)
       encoding = ""
       while encoding.length < len do
-        encoding << @socket.recv(len - encoding.length)
+        data = @socket.recv(len - encoding.length)
+        if data.empty?
+          raise TransportError, "connection closed"
+        end
+        encoding << data
       end
       encoding
     end
diff --git a/src/libcharon/plugins/vici/suites/test_message.c b/src/libcharon/plugins/vici/suites/test_message.c
index e76d273..045e34f 100644
--- a/src/libcharon/plugins/vici/suites/test_message.c
+++ b/src/libcharon/plugins/vici/suites/test_message.c
@@ -1,4 +1,7 @@
 /*
+ * Copyright (C) 2015 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
  * Copyright (C) 2014 Martin Willi
  * Copyright (C) 2014 revosec AG
  *
@@ -355,6 +358,33 @@ START_TEST(test_get_int)
 }
 END_TEST
 
+START_TEST(test_get_bool)
+{
+	vici_message_t *m;
+
+	m = build_getter_msg();
+
+	ck_assert(m->get_bool(m, TRUE, "key1"));
+	ck_assert(m->get_bool(m, FALSE, "key1"));
+
+	ck_assert(m->get_bool(m, TRUE, "section1.key2"));
+	ck_assert(m->get_bool(m, TRUE, "section1.section2.key3"));
+	ck_assert(m->get_bool(m, TRUE, "section1.key4"));
+	ck_assert(m->get_bool(m, TRUE, "key5"));
+	ck_assert(m->get_bool(m, TRUE, "nonexistent"));
+	ck_assert(m->get_bool(m, TRUE, "n.o.n.e.x.i.s.t.e.n.t"));
+
+	ck_assert(!m->get_bool(m, FALSE, "section1.key2"));
+	ck_assert(!m->get_bool(m, FALSE, "section1.section2.key3"));
+	ck_assert(!m->get_bool(m, FALSE, "section1.key4"));
+	ck_assert(!m->get_bool(m, FALSE, "key5"));
+	ck_assert(!m->get_bool(m, FALSE, "nonexistent"));
+	ck_assert(!m->get_bool(m, FALSE, "n.o.n.e.x.i.s.t.e.n.t"));
+
+	m->destroy(m);
+}
+END_TEST
+
 START_TEST(test_get_value)
 {
 	vici_message_t *m;
@@ -400,6 +430,7 @@ Suite *message_suite_create()
 	tc = tcase_create("convenience getters");
 	tcase_add_test(tc, test_get_str);
 	tcase_add_test(tc, test_get_int);
+	tcase_add_test(tc, test_get_bool);
 	tcase_add_test(tc, test_get_value);
 	suite_add_tcase(s, tc);
 
diff --git a/src/libcharon/plugins/vici/vici_authority.c b/src/libcharon/plugins/vici/vici_authority.c
new file mode 100644
index 0000000..94a7f68
--- /dev/null
+++ b/src/libcharon/plugins/vici/vici_authority.c
@@ -0,0 +1,750 @@
+/*
+ * Copyright (C) 2015 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
+ * 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.
+ */
+
+#define _GNU_SOURCE
+
+#include "vici_authority.h"
+#include "vici_builder.h"
+
+#include <threading/rwlock.h>
+#include <collections/linked_list.h>
+#include <credentials/certificates/x509.h>
+#include <utils/debug.h>
+
+#include <stdio.h>
+
+typedef struct private_vici_authority_t private_vici_authority_t;
+
+/**
+ * Private data of an vici_authority_t object.
+ */
+struct private_vici_authority_t {
+
+	/**
+	 * Public vici_authority_t interface.
+	 */
+	vici_authority_t public;
+
+	/**
+	 * Dispatcher
+	 */
+	vici_dispatcher_t *dispatcher;
+
+	/**
+	 * credential backend managed by VICI used for our ca certificates
+	 */
+	vici_cred_t *cred;
+
+	/**
+	 * List of certification authorities
+	 */
+	linked_list_t *authorities;
+
+	/**
+	 * rwlock to lock access to certification authorities
+	 */
+	rwlock_t *lock;
+
+};
+
+typedef struct authority_t authority_t;
+
+/**
+ * loaded certification authorities
+ */
+struct authority_t {
+
+	/**
+	 * Name of the certification authoritiy
+	 */
+	char *name;
+
+	/**
+	 * Reference to CA certificate
+	 */
+	certificate_t *cert;
+
+	/**
+	 * CRL URIs
+	 */
+	linked_list_t *crl_uris;
+
+	/**
+	 * OCSP URIs
+	 */
+	linked_list_t *ocsp_uris;
+
+	/**
+	 * Hashes of certificates issued by this CA
+	 */
+	linked_list_t *hashes;
+
+	/**
+	 * Base URI used for certificates from this CA
+	 */
+	char *cert_uri_base;
+};
+
+/**
+ * create a new certification authority
+ */
+static authority_t *authority_create(char *name)
+{
+	authority_t *authority;
+
+	INIT(authority,
+		.name = strdup(name),
+		.crl_uris = linked_list_create(),
+		.ocsp_uris = linked_list_create(),
+		.hashes = linked_list_create(),
+	);
+
+	return authority;
+}
+
+/**
+ * destroy a certification authority
+ */
+static void authority_destroy(authority_t *this)
+{
+	this->crl_uris->destroy_function(this->crl_uris, free);
+	this->ocsp_uris->destroy_function(this->ocsp_uris, free);
+	this->hashes->destroy_offset(this->hashes, offsetof(identification_t, destroy));
+	DESTROY_IF(this->cert);
+	free(this->cert_uri_base);
+	free(this->name);
+	free(this);
+}
+
+
+/**
+ * Create a (error) reply message
+ */
+static vici_message_t* create_reply(char *fmt, ...)
+{
+	vici_builder_t *builder;
+	va_list args;
+
+	builder = vici_builder_create();
+	builder->add_kv(builder, "success", fmt ? "no" : "yes");
+	if (fmt)
+	{
+		va_start(args, fmt);
+		builder->vadd_kv(builder, "errmsg", fmt, args);
+		va_end(args);
+	}
+	return builder->finalize(builder);
+}
+
+/**
+ * A rule to parse a key/value or list item
+ */
+typedef struct {
+	/** name of the key/value or list */
+	char *name;
+	/** function to parse value */
+	bool (*parse)(void *out, chunk_t value);
+	/** result, passed to parse() */
+	void *out;
+} parse_rule_t;
+
+/**
+ * Parse key/values using a rule-set
+ */
+static bool parse_rules(parse_rule_t *rules, int count, char *name,
+						chunk_t value, vici_message_t **reply)
+{
+	int i;
+
+	for (i = 0; i < count; i++)
+	{
+		if (streq(name, rules[i].name))
+		{
+			if (rules[i].parse(rules[i].out, value))
+			{
+				return TRUE;
+			}
+			*reply = create_reply("invalid value for: %s, authority discarded",
+								  name);
+			return FALSE;
+		}
+	}
+	*reply = create_reply("unknown option: %s, authority discarded", name);
+	return FALSE;
+}
+
+/**
+ * Parse callback data, passed to each callback
+ */
+typedef struct {
+	private_vici_authority_t *this;
+	vici_message_t *reply;
+} request_data_t;
+
+/**
+ * Data associated with an authority load
+ */
+typedef struct {
+	request_data_t *request;
+	authority_t *authority;
+} load_data_t;
+
+/**
+ * Parse a string
+ */
+CALLBACK(parse_string, bool,
+	char **str, chunk_t v)
+{
+	if (!chunk_printable(v, NULL, ' '))
+	{
+		return FALSE;
+	}
+	*str = strndup(v.ptr, v.len);
+
+	return TRUE;
+}
+
+/**
+ * Parse list of URIs
+ */
+CALLBACK(parse_uris, bool,
+	linked_list_t *out, chunk_t v)
+{
+	char *uri;
+
+	if (!chunk_printable(v, NULL, ' '))
+	{
+		return FALSE;
+	}
+	uri = strndup(v.ptr, v.len);
+	out->insert_last(out, uri);
+
+	return TRUE;
+}
+
+/**
+ * Parse a CA certificate
+ */
+CALLBACK(parse_cacert, bool,
+	certificate_t **cacert, chunk_t v)
+{
+	certificate_t *cert;
+	x509_t *x509;
+
+	cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
+										  BUILD_BLOB_PEM, v, BUILD_END);
+	if (!cert)
+	{
+		return create_reply("parsing %N certificate failed",
+							certificate_type_names, CERT_X509);
+	}
+	x509 = (x509_t*)cert;
+
+	if ((x509->get_flags(x509) & X509_CA) != X509_CA)
+	{
+		cert->destroy(cert);
+		return create_reply("certificate without CA flag, rejected");
+	}
+	*cacert = cert;
+
+	return TRUE;
+}
+
+CALLBACK(authority_kv, bool,
+	load_data_t *data, vici_message_t *message, char *name, chunk_t value)
+{
+	parse_rule_t rules[] = {
+		{ "cacert",			parse_cacert, &data->authority->cert	      },
+		{ "cert_uri_base",	parse_string, &data->authority->cert_uri_base },
+	};
+
+	return parse_rules(rules, countof(rules), name, value,
+					   &data->request->reply);
+}
+
+CALLBACK(authority_li, bool,
+	load_data_t *data, vici_message_t *message, char *name, chunk_t value)
+{
+	parse_rule_t rules[] = {
+		{ "crl_uris",	parse_uris, data->authority->crl_uris  },
+		{ "ocsp_uris",	parse_uris, data->authority->ocsp_uris },
+	};
+
+	return parse_rules(rules, countof(rules), name, value,
+					   &data->request->reply);
+}
+
+static void log_authority_data(authority_t *authority)
+{
+	enumerator_t *enumerator;
+	identification_t *subject;
+	bool first = TRUE;
+	char *uri;
+
+	subject = authority->cert->get_subject(authority->cert);
+	DBG2(DBG_CFG, "  cacert = %Y", subject);
+
+	enumerator = authority->crl_uris->create_enumerator(authority->crl_uris);
+	while (enumerator->enumerate(enumerator, &uri))
+	{
+		if (first)
+		{
+			DBG2(DBG_CFG, "  crl_uris = %s", uri);
+			first = FALSE;
+		}
+		else
+		{
+			DBG2(DBG_CFG, "             %s", uri);
+		}
+	}
+	enumerator->destroy(enumerator);
+
+	first = TRUE;
+	enumerator = authority->ocsp_uris->create_enumerator(authority->ocsp_uris);
+	while (enumerator->enumerate(enumerator, &uri))
+	{
+		if (first)
+		{
+			DBG2(DBG_CFG, "  ocsp_uris = %s", uri);
+			first = FALSE;
+		}
+		else
+		{
+			DBG2(DBG_CFG, "              %s", uri);
+		}
+	}
+	enumerator->destroy(enumerator);
+
+	if (authority->cert_uri_base)
+	{
+		DBG2(DBG_CFG, "  cert_uri_base = %s", authority->cert_uri_base);
+	}
+}
+
+CALLBACK(authority_sn, bool,
+	request_data_t *request, vici_message_t *message,
+	vici_parse_context_t *ctx, char *name)
+{
+	enumerator_t *enumerator;
+	linked_list_t *authorities;
+	authority_t *authority;
+	vici_cred_t *cred;
+
+	load_data_t data = {
+		.request = request,
+		.authority = authority_create(name),
+	};
+
+	DBG2(DBG_CFG, " authority %s:", name);
+
+	if (!message->parse(message, ctx, NULL, authority_kv, authority_li, &data) ||
+		!data.authority->cert)
+	{
+		authority_destroy(data.authority);
+		return FALSE;
+	}
+	log_authority_data(data.authority);
+
+	request->this->lock->write_lock(request->this->lock);
+
+	authorities = request->this->authorities;
+	enumerator = authorities->create_enumerator(authorities);
+	while (enumerator->enumerate(enumerator, &authority))
+	{
+		if (streq(authority->name, name))
+		{
+			/* remove the old authority definition */
+			authorities->remove_at(authorities, enumerator);
+			authority_destroy(authority);
+			break;
+		}
+	}
+	enumerator->destroy(enumerator);
+	authorities->insert_last(authorities, data.authority);
+
+	cred = request->this->cred;
+	data.authority->cert = cred->add_cert(cred, data.authority->cert);
+
+	request->this->lock->unlock(request->this->lock);
+
+	return TRUE;
+}
+
+CALLBACK(load_authority, vici_message_t*,
+	private_vici_authority_t *this, char *name, u_int id, vici_message_t *message)
+{
+	request_data_t request = {
+		.this = this,
+	};
+
+	if (!message->parse(message, NULL, authority_sn, NULL, NULL, &request))
+	{
+		if (request.reply)
+		{
+			return request.reply;
+		}
+		return create_reply("parsing request failed");
+	}
+	return create_reply(NULL);
+}
+
+CALLBACK(unload_authority, vici_message_t*,
+	private_vici_authority_t *this, char *name, u_int id, vici_message_t *message)
+{
+	enumerator_t *enumerator;
+	authority_t *authority;
+	char *authority_name;
+	bool found = FALSE;
+
+	authority_name = message->get_str(message, NULL, "name");
+	if (!authority_name)
+	{
+		return create_reply("unload: missing authority name");
+	}
+
+	this->lock->write_lock(this->lock);
+	enumerator = this->authorities->create_enumerator(this->authorities);
+	while (enumerator->enumerate(enumerator, &authority))
+	{
+		if (streq(authority->name, authority_name))
+		{
+			this->authorities->remove_at(this->authorities, enumerator);
+			authority_destroy(authority);
+			found = TRUE;
+			break;
+		}
+	}
+	enumerator->destroy(enumerator);
+	this->lock->unlock(this->lock);
+
+	if (!found)
+	{
+		return create_reply("unload: authority '%s' not found", authority_name);
+	}
+	return create_reply(NULL);
+}
+
+CALLBACK(get_authorities, vici_message_t*,
+	private_vici_authority_t *this, char *name, u_int id,
+	vici_message_t *message)
+{
+	vici_builder_t *builder;
+	enumerator_t *enumerator;
+	authority_t *authority;
+
+	builder = vici_builder_create();
+	builder->begin_list(builder, "authorities");
+
+	this->lock->read_lock(this->lock);
+	enumerator = this->authorities->create_enumerator(this->authorities);
+	while (enumerator->enumerate(enumerator, &authority))
+	{
+		builder->add_li(builder, "%s", authority->name);
+	}
+	enumerator->destroy(enumerator);
+	this->lock->unlock(this->lock);
+
+	builder->end_list(builder);
+
+	return builder->finalize(builder);
+}
+
+CALLBACK(list_authorities, vici_message_t*,
+	private_vici_authority_t *this, char *name, u_int id, vici_message_t *request)
+{
+	enumerator_t *enumerator, *e;
+	authority_t *authority;
+	vici_builder_t *b;
+	char *str, *uri;
+
+	str = request->get_str(request, NULL, "name");
+
+	this->lock->read_lock(this->lock);
+	enumerator = this->authorities->create_enumerator(this->authorities);
+	while (enumerator->enumerate(enumerator, &authority))
+	{
+		if (str && !streq(str, authority->name))
+		{
+			continue;
+		}
+		b = vici_builder_create();
+
+		/* open authority section */
+		b->begin_section(b, authority->name);
+
+		/* subject DN of cacert */
+		b->add_kv(b, "cacert", "%Y",
+					  authority->cert->get_subject(authority->cert));
+
+		/* list of crl_uris */
+		b->begin_list(b, "crl_uris");
+		e = authority->crl_uris->create_enumerator(authority->crl_uris);
+		while (e->enumerate(e, &uri))
+		{
+			b->add_li(b, "%s", uri);
+		}
+		e->destroy(e);
+		b->end_list(b);
+
+		/* list of ocsp_uris */
+		b->begin_list(b, "ocsp_uris");
+		e = authority->ocsp_uris->create_enumerator(authority->ocsp_uris);
+		while (e->enumerate(e, &uri))
+		{
+			b->add_li(b, "%s", uri);
+		}
+		e->destroy(e);
+		b->end_list(b);
+
+		/* cert_uri_base */
+		if (authority->cert_uri_base)
+		{
+			b->add_kv(b, "cert_uri_base", "%s", authority->cert_uri_base);
+		}
+
+		/* close authority and raise event */
+		b->end_section(b);
+		this->dispatcher->raise_event(this->dispatcher, "list-authority", id,
+									  b->finalize(b));
+	}
+	enumerator->destroy(enumerator);
+	this->lock->unlock(this->lock);
+
+	b = vici_builder_create();
+	return b->finalize(b);
+}
+
+static void manage_command(private_vici_authority_t *this,
+						   char *name, vici_command_cb_t cb, bool reg)
+{
+	this->dispatcher->manage_command(this->dispatcher, name,
+									 reg ? cb : NULL, this);
+}
+
+/**
+ * (Un-)register dispatcher functions
+ */
+static void manage_commands(private_vici_authority_t *this, bool reg)
+{
+	this->dispatcher->manage_event(this->dispatcher, "list-authority", reg);
+
+	manage_command(this, "load-authority", load_authority, reg);
+	manage_command(this, "unload-authority", unload_authority, reg);
+	manage_command(this, "get-authorities", get_authorities, reg);
+	manage_command(this, "list-authorities", list_authorities, reg);
+}
+
+/**
+ * data to pass to create_inner_cdp
+ */
+typedef struct {
+	private_vici_authority_t *this;
+	certificate_type_t type;
+	identification_t *id;
+} cdp_data_t;
+
+/**
+ * destroy cdp enumerator data and unlock list
+ */
+static void cdp_data_destroy(cdp_data_t *data)
+{
+	data->this->lock->unlock(data->this->lock);
+	free(data);
+}
+
+/**
+ * inner enumerator constructor for CDP URIs
+ */
+static enumerator_t *create_inner_cdp(authority_t *authority, cdp_data_t *data)
+{
+	public_key_t *public;
+	enumerator_t *enumerator = NULL;
+	linked_list_t *list;
+
+	if (data->type == CERT_X509_OCSP_RESPONSE)
+	{
+		list = authority->ocsp_uris;
+	}
+	else
+	{
+		list = authority->crl_uris;
+	}
+
+	public = authority->cert->get_public_key(authority->cert);
+	if (public)
+	{
+		if (!data->id)
+		{
+			enumerator = list->create_enumerator(list);
+		}
+		else
+		{
+			if (public->has_fingerprint(public, data->id->get_encoding(data->id)))
+			{
+				enumerator = list->create_enumerator(list);
+			}
+		}
+		public->destroy(public);
+	}
+	return enumerator;
+}
+
+/**
+ * inner enumerator constructor for "Hash and URL"
+ */
+static enumerator_t *create_inner_cdp_hashandurl(authority_t *authority,
+												 cdp_data_t *data)
+{
+	enumerator_t *enumerator = NULL, *hash_enum;
+	identification_t *current;
+
+	if (!data->id || !authority->cert_uri_base)
+	{
+		return NULL;
+	}
+
+	hash_enum = authority->hashes->create_enumerator(authority->hashes);
+	while (hash_enum->enumerate(hash_enum, &current))
+	{
+		if (current->matches(current, data->id))
+		{
+			char *url, *hash;
+
+			url = malloc(strlen(authority->cert_uri_base) + 40 + 1);
+			strcpy(url, authority->cert_uri_base);
+			hash = chunk_to_hex(current->get_encoding(current), NULL, FALSE).ptr;
+			strncat(url, hash, 40);
+			free(hash);
+
+			enumerator = enumerator_create_single(url, free);
+			break;
+		}
+	}
+	hash_enum->destroy(hash_enum);
+	return enumerator;
+}
+
+METHOD(credential_set_t, create_cdp_enumerator, enumerator_t*,
+	private_vici_authority_t *this, certificate_type_t type,
+	identification_t *id)
+{
+	cdp_data_t *data;
+
+	switch (type)
+	{	/* we serve CRLs, OCSP responders and URLs for "Hash and URL" */
+		case CERT_X509:
+		case CERT_X509_CRL:
+		case CERT_X509_OCSP_RESPONSE:
+		case CERT_ANY:
+			break;
+		default:
+			return NULL;
+	}
+	data = malloc_thing(cdp_data_t);
+	data->this = this;
+	data->type = type;
+	data->id = id;
+
+	this->lock->read_lock(this->lock);
+
+	return enumerator_create_nested(
+			this->authorities->create_enumerator(this->authorities),
+			(type == CERT_X509) ? (void*)create_inner_cdp_hashandurl :
+			(void*)create_inner_cdp, data, (void*)cdp_data_destroy);
+}
+
+METHOD(vici_authority_t, check_for_hash_and_url, void,
+	private_vici_authority_t *this, certificate_t* cert)
+{
+	authority_t *authority;
+	enumerator_t *enumerator;
+	hasher_t *hasher;
+
+	hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
+	if (hasher == NULL)
+	{
+		DBG1(DBG_CFG, "unable to use hash-and-url: sha1 not supported");
+		return;
+	}
+
+	this->lock->write_lock(this->lock);
+	enumerator = this->authorities->create_enumerator(this->authorities);
+	while (enumerator->enumerate(enumerator, &authority))
+	{
+		if (authority->cert_uri_base &&
+			cert->issued_by(cert, authority->cert, NULL))
+		{
+			chunk_t hash, encoded;
+
+			if (cert->get_encoding(cert, CERT_ASN1_DER, &encoded))
+			{
+				if (hasher->allocate_hash(hasher, encoded, &hash))
+				{
+					authority->hashes->insert_last(authority->hashes,
+						identification_create_from_encoding(ID_KEY_ID, hash));
+					chunk_free(&hash);
+				}
+				chunk_free(&encoded);
+			}
+			break;
+		}
+	}
+	enumerator->destroy(enumerator);
+	this->lock->unlock(this->lock);
+
+	hasher->destroy(hasher);
+}
+
+METHOD(vici_authority_t, destroy, void,
+	private_vici_authority_t *this)
+{
+	manage_commands(this, FALSE);
+
+	this->authorities->destroy_function(this->authorities,
+									   (void*)authority_destroy);
+	this->lock->destroy(this->lock);
+	free(this);
+}
+
+/**
+ * See header
+ */
+vici_authority_t *vici_authority_create(vici_dispatcher_t *dispatcher,
+										vici_cred_t *cred)
+{
+	private_vici_authority_t *this;
+
+	INIT(this,
+		.public = {
+			.set = {
+				.create_private_enumerator = (void*)return_null,
+				.create_cert_enumerator = (void*)return_null,
+				.create_shared_enumerator = (void*)return_null,
+				.create_cdp_enumerator = _create_cdp_enumerator,
+				.cache_cert = (void*)nop,
+			},
+			.check_for_hash_and_url = _check_for_hash_and_url,
+			.destroy = _destroy,
+		},
+		.dispatcher = dispatcher,
+		.cred = cred,
+		.authorities = linked_list_create(),
+		.lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
+	);
+
+	manage_commands(this, TRUE);
+
+	return &this->public;
+}
diff --git a/src/libcharon/plugins/vici/vici_authority.h b/src/libcharon/plugins/vici/vici_authority.h
new file mode 100644
index 0000000..dbeabae
--- /dev/null
+++ b/src/libcharon/plugins/vici/vici_authority.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2015 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
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup vici_authority vici_authority
+ * @{ @ingroup vici
+ */
+
+#ifndef VICI_AUTHORITY_H_
+#define VICI_AUTHORITY_H_
+
+#include "vici_dispatcher.h"
+#include "vici_cred.h"
+
+typedef struct vici_authority_t vici_authority_t;
+
+/**
+ * In-memory certification authority backend, managed by VICI.
+ */
+struct vici_authority_t {
+
+	/**
+	 * Implements credential_set_t
+	 */
+	credential_set_t set;
+
+	/**
+	 * Check if a certificate can be made available through hash and URL.
+	 *
+	 * @param cert		end entity certificate
+	 */
+	void (*check_for_hash_and_url)(vici_authority_t *this, certificate_t* cert);
+
+	/**
+	 * Destroy a vici_authority_t.
+	 */
+	void (*destroy)(vici_authority_t *this);
+};
+
+/**
+ * Create a vici_authority instance.
+ *
+ * @param dispatcher		dispatcher to receive requests from
+ * @param cred				in-memory credential backend managed by VICI
+ * @return					authority backend
+ */
+vici_authority_t *vici_authority_create(vici_dispatcher_t *dispatcher,
+										vici_cred_t *cred);
+
+#endif /** VICI_AUTHORITY_H_ @}*/
diff --git a/src/libcharon/plugins/vici/vici_config.c b/src/libcharon/plugins/vici/vici_config.c
index d232599..ea6d295 100644
--- a/src/libcharon/plugins/vici/vici_config.c
+++ b/src/libcharon/plugins/vici/vici_config.c
@@ -2,6 +2,9 @@
  * Copyright (C) 2014 Martin Willi
  * Copyright (C) 2014 revosec AG
  *
+ * Copyright (C) 2015 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
@@ -93,6 +96,12 @@ struct private_vici_config_t {
 	 * Lock for conns list
 	 */
 	rwlock_t *lock;
+
+	/**
+	 * Auxiliary certification authority information
+	 */
+	vici_authority_t *authority;
+
 };
 
 METHOD(backend_t, create_peer_cfg_enumerator, enumerator_t*,
@@ -382,7 +391,7 @@ typedef struct {
 	char* updown;
 	bool hostaccess;
 	bool ipcomp;
-	bool route;
+	bool policies;
 	ipsec_mode_t mode;
 	u_int32_t replay_window;
 	action_t dpd_action;
@@ -417,6 +426,7 @@ static void log_child_data(child_data_t *data, char *name)
 	DBG2(DBG_CFG, "   hostaccess = %u", data->hostaccess);
 	DBG2(DBG_CFG, "   ipcomp = %u", data->ipcomp);
 	DBG2(DBG_CFG, "   mode = %N", ipsec_mode_names, data->mode);
+	DBG2(DBG_CFG, "   policies = %u", data->policies);
 	if (data->replay_window != REPLAY_UNDEFINED)
 	{
 		DBG2(DBG_CFG, "   replay_window = %u", data->replay_window);
@@ -1040,15 +1050,21 @@ CALLBACK(parse_group, bool,
 /**
  * Parse a certificate; add as auth rule to config
  */
-static bool parse_cert(auth_cfg_t *cfg, auth_rule_t rule, chunk_t v)
+static bool parse_cert(auth_data_t *auth, auth_rule_t rule, chunk_t v)
 {
+	vici_authority_t *authority;
 	certificate_t *cert;
 
 	cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
 							  BUILD_BLOB_PEM, v, BUILD_END);
 	if (cert)
 	{
-		cfg->add(cfg, rule, cert);
+		if (rule == AUTH_RULE_SUBJECT_CERT)
+		{
+			authority = auth->request->this->authority;
+			authority->check_for_hash_and_url(authority, cert);
+		}
+		auth->cfg->add(auth->cfg, rule, cert);
 		return TRUE;
 	}
 	return FALSE;
@@ -1058,18 +1074,18 @@ static bool parse_cert(auth_cfg_t *cfg, auth_rule_t rule, chunk_t v)
  * Parse subject certificates
  */
 CALLBACK(parse_certs, bool,
-	auth_cfg_t *cfg, chunk_t v)
+	auth_data_t *auth, chunk_t v)
 {
-	return parse_cert(cfg, AUTH_RULE_SUBJECT_CERT, v);
+	return parse_cert(auth, AUTH_RULE_SUBJECT_CERT, v);
 }
 
 /**
  * Parse CA certificates
  */
 CALLBACK(parse_cacerts, bool,
-	auth_cfg_t *cfg, chunk_t v)
+	auth_data_t *auth, chunk_t v)
 {
-	return parse_cert(cfg, AUTH_RULE_CA_CERT, v);
+	return parse_cert(auth, AUTH_RULE_CA_CERT, v);
 }
 
 /**
@@ -1234,6 +1250,7 @@ CALLBACK(child_kv, bool,
 		{ "updown",			parse_string,		&child->updown				},
 		{ "hostaccess",		parse_bool,			&child->hostaccess			},
 		{ "mode",			parse_mode,			&child->mode				},
+		{ "policies",		parse_bool,			&child->policies			},
 		{ "replay_window",	parse_uint32,		&child->replay_window		},
 		{ "rekey_time",		parse_time,			&child->lft.time.rekey		},
 		{ "life_time",		parse_time,			&child->lft.time.life		},
@@ -1264,8 +1281,8 @@ CALLBACK(auth_li, bool,
 {
 	parse_rule_t rules[] = {
 		{ "groups",			parse_group,		auth->cfg					},
-		{ "certs",			parse_certs,		auth->cfg					},
-		{ "cacerts",		parse_cacerts,		auth->cfg					},
+		{ "certs",			parse_certs,		auth						},
+		{ "cacerts",		parse_cacerts,		auth						},
 	};
 
 	return parse_rules(rules, countof(rules), name, value,
@@ -1341,6 +1358,7 @@ CALLBACK(children_sn, bool,
 		.local_ts = linked_list_create(),
 		.remote_ts = linked_list_create(),
 		.mode = MODE_TUNNEL,
+		.policies = TRUE,
 		.replay_window = REPLAY_UNDEFINED,
 		.dpd_action = ACTION_NONE,
 		.start_action = ACTION_NONE,
@@ -1352,10 +1370,12 @@ CALLBACK(children_sn, bool,
 				.jitter = LFT_UNDEFINED,
 			},
 			.bytes = {
+				.rekey = LFT_UNDEFINED,
 				.life = LFT_UNDEFINED,
 				.jitter = LFT_UNDEFINED,
 			},
 			.packets = {
+				.rekey = LFT_UNDEFINED,
 				.life = LFT_UNDEFINED,
 				.jitter = LFT_UNDEFINED,
 			},
@@ -1408,6 +1428,15 @@ CALLBACK(children_sn, bool,
 	{
 		child.lft.packets.life = child.lft.packets.rekey * 110 / 100;
 	}
+	/* if no soft lifetime specified, add one at hard lifetime - 10% */
+	if (child.lft.bytes.rekey == LFT_UNDEFINED)
+	{
+		child.lft.bytes.rekey = child.lft.bytes.life * 90 / 100;
+	}
+	if (child.lft.packets.rekey == LFT_UNDEFINED)
+	{
+		child.lft.packets.rekey = child.lft.packets.life * 90 / 100;
+	}
 	/* if no rand time defined, use difference of hard and soft */
 	if (child.lft.time.jitter == LFT_UNDEFINED)
 	{
@@ -1433,6 +1462,8 @@ CALLBACK(children_sn, bool,
 						child.inactivity, child.reqid, &child.mark_in,
 						&child.mark_out, child.tfc);
 
+	cfg->set_mipv6_options(cfg, FALSE, child.policies);
+
 	if (child.replay_window != REPLAY_UNDEFINED)
 	{
 		cfg->set_replay_window(cfg, child.replay_window);
@@ -1558,7 +1589,7 @@ static void run_start_action(private_vici_config_t *this, peer_cfg_t *peer_cfg,
 			DBG1(DBG_CFG, "initiating '%s'", child_cfg->get_name(child_cfg));
 			charon->controller->initiate(charon->controller,
 					peer_cfg->get_ref(peer_cfg), child_cfg->get_ref(child_cfg),
-					NULL, NULL, 0);
+					NULL, NULL, 0, FALSE);
 			break;
 		case ACTION_ROUTE:
 			DBG1(DBG_CFG, "installing '%s'", child_cfg->get_name(child_cfg));
@@ -1958,20 +1989,20 @@ CALLBACK(unload_conn, vici_message_t*,
 {
 	enumerator_t *enumerator;
 	peer_cfg_t *cfg;
+	char *conn_name;
 	bool found = FALSE;
-	char *conn;
 
-	conn = message->get_str(message, NULL, "name");
-	if (!conn)
+	conn_name = message->get_str(message, NULL, "name");
+	if (!conn_name)
 	{
-		return create_reply("missing connection name to unload");
+		return create_reply("unload: missing connection name");
 	}
 
 	this->lock->write_lock(this->lock);
 	enumerator = this->conns->create_enumerator(this->conns);
 	while (enumerator->enumerate(enumerator, &cfg))
 	{
-		if (streq(cfg->get_name(cfg), conn))
+		if (streq(cfg->get_name(cfg), conn_name))
 		{
 			this->conns->remove_at(this->conns, enumerator);
 			cfg->destroy(cfg);
@@ -1984,7 +2015,7 @@ CALLBACK(unload_conn, vici_message_t*,
 
 	if (!found)
 	{
-		return create_reply("connection '%s' not found for unloading", conn);
+		return create_reply("unload: connection '%s' not found", conn_name);
 	}
 	return create_reply(NULL);
 }
@@ -2042,7 +2073,8 @@ METHOD(vici_config_t, destroy, void,
 /**
  * See header
  */
-vici_config_t *vici_config_create(vici_dispatcher_t *dispatcher)
+vici_config_t *vici_config_create(vici_dispatcher_t *dispatcher,
+								  vici_authority_t *authority)
 {
 	private_vici_config_t *this;
 
@@ -2058,6 +2090,7 @@ vici_config_t *vici_config_create(vici_dispatcher_t *dispatcher)
 		.dispatcher = dispatcher,
 		.conns = linked_list_create(),
 		.lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
+		.authority = authority,
 	);
 
 	manage_commands(this, TRUE);
diff --git a/src/libcharon/plugins/vici/vici_config.h b/src/libcharon/plugins/vici/vici_config.h
index 820d5f3..c3245bf 100644
--- a/src/libcharon/plugins/vici/vici_config.h
+++ b/src/libcharon/plugins/vici/vici_config.h
@@ -2,6 +2,9 @@
  * Copyright (C) 2014 Martin Willi
  * Copyright (C) 2014 revosec AG
  *
+ * Copyright (C) 2015 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
@@ -22,6 +25,7 @@
 #define VICI_CONFIG_H_
 
 #include "vici_dispatcher.h"
+#include "vici_authority.h"
 
 #include <config/backend.h>
 
@@ -46,8 +50,10 @@ struct vici_config_t {
  * Create a vici_config instance.
  *
  * @param dispatcher		dispatcher to receive requests from
+ * @param authority			Auxiliary certification authority information
  * @return					config backend
  */
-vici_config_t *vici_config_create(vici_dispatcher_t *dispatcher);
+vici_config_t *vici_config_create(vici_dispatcher_t *dispatcher,
+								  vici_authority_t *authority);
 
 #endif /** VICI_CONFIG_H_ @}*/
diff --git a/src/libcharon/plugins/vici/vici_control.c b/src/libcharon/plugins/vici/vici_control.c
index 01d5036..752007c 100644
--- a/src/libcharon/plugins/vici/vici_control.c
+++ b/src/libcharon/plugins/vici/vici_control.c
@@ -138,7 +138,7 @@ static child_cfg_t* find_child_cfg(char *name, peer_cfg_t **out)
 {
 	enumerator_t *enumerator;
 	peer_cfg_t *peer_cfg;
-	child_cfg_t *child_cfg;
+	child_cfg_t *child_cfg = NULL;
 
 	enumerator = charon->backends->create_peer_cfg_enumerator(
 							charon->backends, NULL, NULL, NULL, NULL, IKE_ANY);
@@ -163,6 +163,7 @@ CALLBACK(initiate, vici_message_t*,
 	peer_cfg_t *peer_cfg;
 	char *child;
 	u_int timeout;
+	bool limits;
 	log_info_t log = {
 		.dispatcher = this->dispatcher,
 		.id = id,
@@ -170,6 +171,7 @@ CALLBACK(initiate, vici_message_t*,
 
 	child = request->get_str(request, NULL, "child");
 	timeout = request->get_int(request, 0, "timeout");
+	limits = request->get_bool(request, FALSE, "init-limits");
 	log.level = request->get_int(request, 1, "loglevel");
 
 	if (!child)
@@ -184,14 +186,17 @@ CALLBACK(initiate, vici_message_t*,
 	{
 		return send_reply(this, "CHILD_SA config '%s' not found", child);
 	}
-	switch (charon->controller->initiate(charon->controller,
-				peer_cfg, child_cfg, (controller_cb_t)log_vici, &log, timeout))
+	switch (charon->controller->initiate(charon->controller, peer_cfg,
+				child_cfg, (controller_cb_t)log_vici, &log, timeout, limits))
 	{
 		case SUCCESS:
 			return send_reply(this, NULL);
 		case OUT_OF_RES:
 			return send_reply(this, "CHILD_SA '%s' not established after %dms",
 							  child, timeout);
+		case INVALID_STATE:
+			return send_reply(this, "establishing CHILD_SA '%s' not possible "
+							  "at the moment due to limits", child);
 		case FAILED:
 		default:
 			return send_reply(this, "establishing CHILD_SA '%s' failed", child);
diff --git a/src/libcharon/plugins/vici/vici_cred.c b/src/libcharon/plugins/vici/vici_cred.c
index d4c02de..ffdc034 100644
--- a/src/libcharon/plugins/vici/vici_cred.c
+++ b/src/libcharon/plugins/vici/vici_cred.c
@@ -294,6 +294,12 @@ static void manage_commands(private_vici_cred_t *this, bool reg)
 	manage_command(this, "load-shared", load_shared, reg);
 }
 
+METHOD(vici_cred_t, add_cert, certificate_t*,
+	private_vici_cred_t *this, certificate_t *cert)
+{
+	return this->creds->get_cert_ref(this->creds, cert);
+}
+
 METHOD(vici_cred_t, destroy, void,
 	private_vici_cred_t *this)
 {
@@ -313,6 +319,7 @@ vici_cred_t *vici_cred_create(vici_dispatcher_t *dispatcher)
 
 	INIT(this,
 		.public = {
+			.add_cert = _add_cert,
 			.destroy = _destroy,
 		},
 		.dispatcher = dispatcher,
diff --git a/src/libcharon/plugins/vici/vici_cred.h b/src/libcharon/plugins/vici/vici_cred.h
index e109a27..8359c0e 100644
--- a/src/libcharon/plugins/vici/vici_cred.h
+++ b/src/libcharon/plugins/vici/vici_cred.h
@@ -31,6 +31,14 @@ typedef struct vici_cred_t vici_cred_t;
 struct vici_cred_t {
 
 	/**
+	 * Add a certificate to the certificate store
+	 *
+	 * @param cert	certificate to be added to store
+	 * @return		reference to certificate or cached copy
+	 */
+	certificate_t* (*add_cert)(vici_cred_t *this, certificate_t *cert);
+
+	/**
 	 * Destroy a vici_cred_t.
 	 */
 	void (*destroy)(vici_cred_t *this);
diff --git a/src/libcharon/plugins/vici/vici_logger.c b/src/libcharon/plugins/vici/vici_logger.c
index cffd65b..6d3584e 100644
--- a/src/libcharon/plugins/vici/vici_logger.c
+++ b/src/libcharon/plugins/vici/vici_logger.c
@@ -18,6 +18,7 @@
 
 #include <daemon.h>
 #include <threading/mutex.h>
+#include <processing/jobs/callback_job.h>
 
 typedef struct private_vici_logger_t private_vici_logger_t;
 
@@ -42,11 +43,54 @@ struct private_vici_logger_t {
 	int recursive;
 
 	/**
+	 * List of messages to raise async events
+	 */
+	linked_list_t *queue;
+
+	/**
 	 * Mutex to synchronize logging
 	 */
 	mutex_t *mutex;
 };
 
+/**
+ * Async callback to raise events for queued messages
+ */
+static job_requeue_t raise_events(private_vici_logger_t *this)
+{
+	vici_message_t *message;
+	u_int count;
+
+	this->mutex->lock(this->mutex);
+	count = this->queue->get_count(this->queue);
+	this->queue->remove_first(this->queue, (void**)&message);
+	this->mutex->unlock(this->mutex);
+
+	if (count > 0)
+	{
+		this->dispatcher->raise_event(this->dispatcher, "log", 0, message);
+	}
+	if (count > 1)
+	{
+		return JOB_REQUEUE_DIRECT;
+	}
+	return JOB_REQUEUE_NONE;
+}
+
+/**
+ * Queue a message for async processing
+ */
+static void queue_messsage(private_vici_logger_t *this, vici_message_t *message)
+{
+	this->queue->insert_last(this->queue, message);
+	if (this->queue->get_count(this->queue) == 1)
+	{
+		lib->processor->queue_job(lib->processor, (job_t*)
+					callback_job_create((callback_job_cb_t)raise_events,
+										this, NULL, NULL));
+	}
+}
+
 METHOD(logger_t, log_, void,
 	private_vici_logger_t *this, debug_t group, level_t level, int thread,
 	ike_sa_t* ike_sa, const char *msg)
@@ -75,7 +119,7 @@ METHOD(logger_t, log_, void,
 		message = builder->finalize(builder);
 		if (message)
 		{
-			this->dispatcher->raise_event(this->dispatcher, "log", 0, message);
+			queue_messsage(this, message);
 		}
 	}
 	this->recursive--;
@@ -101,6 +145,7 @@ METHOD(vici_logger_t, destroy, void,
 	private_vici_logger_t *this)
 {
 	manage_commands(this, FALSE);
+	this->queue->destroy_offset(this->queue, offsetof(vici_message_t, destroy));
 	this->mutex->destroy(this->mutex);
 	free(this);
 }
@@ -121,6 +166,7 @@ vici_logger_t *vici_logger_create(vici_dispatcher_t *dispatcher)
 			.destroy = _destroy,
 		},
 		.dispatcher = dispatcher,
+		.queue = linked_list_create(),
 		.mutex = mutex_create(MUTEX_TYPE_RECURSIVE),
 	);
 
diff --git a/src/libcharon/plugins/vici/vici_message.c b/src/libcharon/plugins/vici/vici_message.c
index e79fbc8..fb6e8a1 100644
--- a/src/libcharon/plugins/vici/vici_message.c
+++ b/src/libcharon/plugins/vici/vici_message.c
@@ -1,4 +1,7 @@
 /*
+ * Copyright (C) 2015 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
  * Copyright (C) 2014 Martin Willi
  * Copyright (C) 2014 revosec AG
  *
@@ -385,6 +388,41 @@ METHOD(vici_message_t, get_int, int,
 	return val;
 }
 
+METHOD(vici_message_t, vget_bool, bool,
+	private_vici_message_t *this, bool def, char *fmt, va_list args)
+{
+	chunk_t value;
+	bool found;
+	char buf[16];
+
+	found = find_value(this, &value, fmt, args);
+	if (found)
+	{
+		if (value.len == 0)
+		{
+			return def;
+		}
+		if (chunk_printable(value, NULL, 0))
+		{
+			snprintf(buf, sizeof(buf), "%.*s", (int)value.len, value.ptr);
+			return settings_value_as_bool(buf, def);
+		}
+	}
+	return def;
+}
+
+METHOD(vici_message_t, get_bool, bool,
+	private_vici_message_t *this, bool def, char *fmt, ...)
+{
+	va_list args;
+	bool val;
+
+	va_start(args, fmt);
+	val = vget_bool(this, def, fmt, args);
+	va_end(args);
+	return val;
+}
+
 METHOD(vici_message_t, vget_value, chunk_t,
 	private_vici_message_t *this, chunk_t def, char *fmt, va_list args)
 {
@@ -633,6 +671,8 @@ vici_message_t *vici_message_create_from_data(chunk_t data, bool cleanup)
 			.vget_str = _vget_str,
 			.get_int = _get_int,
 			.vget_int = _vget_int,
+			.get_bool = _get_bool,
+			.vget_bool = _vget_bool,
 			.get_value = _get_value,
 			.vget_value = _vget_value,
 			.get_encoding = _get_encoding,
diff --git a/src/libcharon/plugins/vici/vici_message.h b/src/libcharon/plugins/vici/vici_message.h
index 1a89cf8..d47e7a0 100644
--- a/src/libcharon/plugins/vici/vici_message.h
+++ b/src/libcharon/plugins/vici/vici_message.h
@@ -1,4 +1,7 @@
 /*
+ * Copyright (C) 2015 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
  * Copyright (C) 2014 Martin Willi
  * Copyright (C) 2014 revosec AG
  *
@@ -15,7 +18,7 @@
 
 /**
  * @defgroup vici_message vici_message
- * @{ @ingroup vici_dispatcher
+ * @{ @ingroup vici
  */
 
 #ifndef VICI_MESSAGE_H_
@@ -138,6 +141,26 @@ struct vici_message_t {
 	int (*vget_int)(vici_message_t *this, int def, char *fmt, va_list args);
 
 	/**
+	 * Get the value of a key/value pair as boolean.
+	 *
+	 * @param def	default value if not found
+	 * @param fmt	printf style format string for key, with sections
+	 * @param ...	arguments to fmt string
+	 * @return		value
+	 */
+	bool (*get_bool)(vici_message_t *this, bool def, char *fmt, ...);
+
+	/**
+	 * Get the value of a key/value pair as boolean, va_list variant
+	 *
+	 * @param def	default value if not found
+	 * @param fmt	printf style format string for key, with sections
+	 * @param args	arguments to fmt string
+	 * @return		value
+	 */
+	bool (*vget_bool)(vici_message_t *this, bool def, char *fmt, va_list args);
+
+	/**
 	 * Get the raw value of a key/value pair.
 	 *
 	 * @param def	default value if not found
diff --git a/src/libcharon/plugins/vici/vici_plugin.c b/src/libcharon/plugins/vici/vici_plugin.c
index 7ae58a3..53ed8cd 100644
--- a/src/libcharon/plugins/vici/vici_plugin.c
+++ b/src/libcharon/plugins/vici/vici_plugin.c
@@ -2,6 +2,9 @@
  * Copyright (C) 2014 Martin Willi
  * Copyright (C) 2014 revosec AG
  *
+ * Copyright (C) 2015 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
@@ -42,6 +45,7 @@
 #include "vici_cred.h"
 #include "vici_config.h"
 #include "vici_attribute.h"
+#include "vici_authority.h"
 #include "vici_logger.h"
 
 #include <library.h>
@@ -80,6 +84,11 @@ struct private_vici_plugin_t {
 	vici_cred_t *cred;
 
 	/**
+	 * Certification Authority backend
+	 */
+	vici_authority_t *authority;
+
+	/**
 	 * Configuration backend
 	 */
 	vici_config_t *config;
@@ -119,7 +128,10 @@ static bool register_vici(private_vici_plugin_t *this,
 			this->query = vici_query_create(this->dispatcher);
 			this->control = vici_control_create(this->dispatcher);
 			this->cred = vici_cred_create(this->dispatcher);
-			this->config = vici_config_create(this->dispatcher);
+			this->authority = vici_authority_create(this->dispatcher,
+													this->cred);
+			lib->credmgr->add_set(lib->credmgr, &this->authority->set);
+			this->config = vici_config_create(this->dispatcher, this->authority);
 			this->attrs = vici_attribute_create(this->dispatcher);
 			this->logger = vici_logger_create(this->dispatcher);
 
@@ -145,6 +157,8 @@ static bool register_vici(private_vici_plugin_t *this,
 		this->logger->destroy(this->logger);
 		this->attrs->destroy(this->attrs);
 		this->config->destroy(this->config);
+		lib->credmgr->remove_set(lib->credmgr, &this->authority->set);
+		this->authority->destroy(this->authority);
 		this->cred->destroy(this->cred);
 		this->control->destroy(this->control);
 		this->query->destroy(this->query);
diff --git a/src/libcharon/plugins/vici/vici_query.c b/src/libcharon/plugins/vici/vici_query.c
index d94d760..98d264f 100644
--- a/src/libcharon/plugins/vici/vici_query.c
+++ b/src/libcharon/plugins/vici/vici_query.c
@@ -929,7 +929,7 @@ CALLBACK(stats, vici_message_t*,
 		charon->ike_sa_manager->get_count(charon->ike_sa_manager));
 	b->add_kv(b, "half-open", "%u",
 		charon->ike_sa_manager->get_half_open_count(charon->ike_sa_manager,
-													NULL));
+													NULL, FALSE));
 	b->end_section(b);
 
 	b->begin_list(b, "plugins");
@@ -1031,7 +1031,9 @@ static void manage_commands(private_vici_query_t *this, bool reg)
 	this->dispatcher->manage_event(this->dispatcher, "list-conn", reg);
 	this->dispatcher->manage_event(this->dispatcher, "list-cert", reg);
 	this->dispatcher->manage_event(this->dispatcher, "ike-updown", reg);
+	this->dispatcher->manage_event(this->dispatcher, "ike-rekey", reg);
 	this->dispatcher->manage_event(this->dispatcher, "child-updown", reg);
+	this->dispatcher->manage_event(this->dispatcher, "child-rekey", reg);
 	manage_command(this, "list-sas", list_sas, reg);
 	manage_command(this, "list-policies", list_policies, reg);
 	manage_command(this, "list-conns", list_conns, reg);
@@ -1054,10 +1056,14 @@ METHOD(listener_t, ike_updown, bool,
 	now = time_monotonic(NULL);
 
 	b = vici_builder_create();
+
+	if (up)
+	{
+		b->add_kv(b, "up", "yes");
+	}
+
 	b->begin_section(b, ike_sa->get_name(ike_sa));
 	list_ike(this, b, ike_sa, now);
-	b->begin_section(b, "child-sas");
-	b->end_section(b);
 	b->end_section(b);
 
 	this->dispatcher->raise_event(this->dispatcher,
@@ -1066,6 +1072,35 @@ METHOD(listener_t, ike_updown, bool,
 	return TRUE;
 }
 
+METHOD(listener_t, ike_rekey, bool,
+	private_vici_query_t *this, ike_sa_t *old, ike_sa_t *new)
+{
+	vici_builder_t *b;
+	time_t now;
+
+	if (!this->dispatcher->has_event_listeners(this->dispatcher, "ike-rekey"))
+	{
+		return TRUE;
+	}
+
+	now = time_monotonic(NULL);
+
+	b = vici_builder_create();
+	b->begin_section(b, old->get_name(old));
+	b->begin_section(b, "old");
+	list_ike(this, b, old, now);
+	b->end_section(b);
+	b->begin_section(b, "new");
+	list_ike(this, b, new, now);
+	b->end_section(b);
+	b->end_section(b);
+
+	this->dispatcher->raise_event(this->dispatcher,
+								  "ike-rekey", 0, b->finalize(b));
+
+	return TRUE;
+}
+
 METHOD(listener_t, child_updown, bool,
 	private_vici_query_t *this, ike_sa_t *ike_sa, child_sa_t *child_sa, bool up)
 {
@@ -1080,6 +1115,11 @@ METHOD(listener_t, child_updown, bool,
 	now = time_monotonic(NULL);
 	b = vici_builder_create();
 
+	if (up)
+	{
+		b->add_kv(b, "up", "yes");
+	}
+
 	b->begin_section(b, ike_sa->get_name(ike_sa));
 	list_ike(this, b, ike_sa, now);
 	b->begin_section(b, "child-sas");
@@ -1097,6 +1137,45 @@ METHOD(listener_t, child_updown, bool,
 	return TRUE;
 }
 
+METHOD(listener_t, child_rekey, bool,
+	private_vici_query_t *this, ike_sa_t *ike_sa, child_sa_t *old,
+	child_sa_t *new)
+{
+	vici_builder_t *b;
+	time_t now;
+
+	if (!this->dispatcher->has_event_listeners(this->dispatcher, "child-rekey"))
+	{
+		return TRUE;
+	}
+
+	now = time_monotonic(NULL);
+	b = vici_builder_create();
+
+	b->begin_section(b, ike_sa->get_name(ike_sa));
+	list_ike(this, b, ike_sa, now);
+	b->begin_section(b, "child-sas");
+
+	b->begin_section(b, old->get_name(old));
+
+	b->begin_section(b, "old");
+	list_child(this, b, old, now);
+	b->end_section(b);
+	b->begin_section(b, "new");
+	list_child(this, b, new, now);
+	b->end_section(b);
+
+	b->end_section(b);
+
+	b->end_section(b);
+	b->end_section(b);
+
+	this->dispatcher->raise_event(this->dispatcher,
+								  "child-rekey", 0, b->finalize(b));
+
+	return TRUE;
+}
+
 METHOD(vici_query_t, destroy, void,
 	private_vici_query_t *this)
 {
@@ -1115,7 +1194,9 @@ vici_query_t *vici_query_create(vici_dispatcher_t *dispatcher)
 		.public = {
 			.listener = {
 				.ike_updown = _ike_updown,
+				.ike_rekey = _ike_rekey,
 				.child_updown = _child_updown,
+				.child_rekey = _child_rekey,
 			},
 			.destroy = _destroy,
 		},
diff --git a/src/libcharon/plugins/whitelist/whitelist_listener.c b/src/libcharon/plugins/whitelist/whitelist_listener.c
index d0357b4..7e5b2f4 100644
--- a/src/libcharon/plugins/whitelist/whitelist_listener.c
+++ b/src/libcharon/plugins/whitelist/whitelist_listener.c
@@ -52,7 +52,7 @@ struct private_whitelist_listener_t {
  */
 static u_int hash(identification_t *key)
 {
-	return chunk_hash(key->get_encoding(key));
+	return key->hash(key, 0);
 }
 
 /**
diff --git a/src/libcharon/processing/jobs/initiate_mediation_job.c b/src/libcharon/processing/jobs/initiate_mediation_job.c
index 17ab830..5b5fb9d 100644
--- a/src/libcharon/processing/jobs/initiate_mediation_job.c
+++ b/src/libcharon/processing/jobs/initiate_mediation_job.c
@@ -119,8 +119,8 @@ METHOD(job_t, initiate, job_requeue_t,
 		/* we need an additional reference because initiate consumes one */
 		mediation_cfg->get_ref(mediation_cfg);
 
-		if (charon->controller->initiate(charon->controller, mediation_cfg,
-				NULL, (controller_cb_t)initiate_callback, this, 0) != SUCCESS)
+		if (charon->controller->initiate(charon->controller, mediation_cfg, NULL,
+				(controller_cb_t)initiate_callback, this, 0, FALSE) != SUCCESS)
 		{
 			mediation_cfg->destroy(mediation_cfg);
 			mediated_cfg->destroy(mediated_cfg);
diff --git a/src/libcharon/processing/jobs/process_message_job.c b/src/libcharon/processing/jobs/process_message_job.c
index a6795e7..31f048d 100644
--- a/src/libcharon/processing/jobs/process_message_job.c
+++ b/src/libcharon/processing/jobs/process_message_job.c
@@ -91,16 +91,26 @@ METHOD(job_t, get_priority, job_priority_t,
 	{
 		case IKE_AUTH:
 			/* IKE auth is rather expensive and often blocking, low priority */
+		case AGGRESSIVE:
+		case ID_PROT:
+			/* AM is basically IKE_SA_INIT/IKE_AUTH combined (without EAP/XAuth)
+			 * MM is similar, but stretched out more */
 			return JOB_PRIO_LOW;
 		case INFORMATIONAL:
+		case INFORMATIONAL_V1:
 			/* INFORMATIONALs are inexpensive, for DPD we should have low
 			 * reaction times */
 			return JOB_PRIO_HIGH;
 		case IKE_SA_INIT:
-		case CREATE_CHILD_SA:
-		default:
 			/* IKE_SA_INIT is expensive, but we will drop them in the receiver
 			 * if we are overloaded */
+		case CREATE_CHILD_SA:
+		case QUICK_MODE:
+			/* these may require DH, but if not they are relatively cheap */
+		case TRANSACTION:
+			/* these are mostly cheap, however, if XAuth via RADIUS is used
+			 * they may block */
+		default:
 			return JOB_PRIO_MEDIUM;
 	}
 }
diff --git a/src/libcharon/processing/jobs/rekey_child_sa_job.c b/src/libcharon/processing/jobs/rekey_child_sa_job.c
index 8f17d39..057876b 100644
--- a/src/libcharon/processing/jobs/rekey_child_sa_job.c
+++ b/src/libcharon/processing/jobs/rekey_child_sa_job.c
@@ -67,7 +67,10 @@ METHOD(job_t, execute, job_requeue_t,
 	}
 	else
 	{
-		ike_sa->rekey_child_sa(ike_sa, this->protocol, this->spi);
+		if (ike_sa->get_state(ike_sa) != IKE_PASSIVE)
+		{
+			ike_sa->rekey_child_sa(ike_sa, this->protocol, this->spi);
+		}
 		charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
 	}
 	return JOB_REQUEUE_NONE;
diff --git a/src/libcharon/processing/jobs/start_action_job.c b/src/libcharon/processing/jobs/start_action_job.c
index 981473b..5e88ac2 100644
--- a/src/libcharon/processing/jobs/start_action_job.c
+++ b/src/libcharon/processing/jobs/start_action_job.c
@@ -61,7 +61,7 @@ METHOD(job_t, execute, job_requeue_t,
 					charon->controller->initiate(charon->controller,
 												 peer_cfg->get_ref(peer_cfg),
 												 child_cfg->get_ref(child_cfg),
-												 NULL, NULL, 0);
+												 NULL, NULL, 0, FALSE);
 					break;
 				case ACTION_ROUTE:
 					DBG1(DBG_JOB, "start action: route '%s'", name);
diff --git a/src/libcharon/sa/child_sa.c b/src/libcharon/sa/child_sa.c
index 94cf07c..73f2ec9 100644
--- a/src/libcharon/sa/child_sa.c
+++ b/src/libcharon/sa/child_sa.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006-2011 Tobias Brunner
+ * Copyright (C) 2006-2015 Tobias Brunner
  * Copyright (C) 2005-2008 Martin Willi
  * Copyright (C) 2006 Daniel Roethlisberger
  * Copyright (C) 2005 Jan Hutter
@@ -106,6 +106,11 @@ struct private_child_sa_t {
 	 */
 	bool reqid_allocated;
 
+	/**
+	 * Is the reqid statically configured
+	 */
+	bool static_reqid;
+
 	/*
 	 * Unique CHILD_SA identifier
 	 */
@@ -698,7 +703,7 @@ METHOD(child_sa_t, install, status_t,
 	this->proposal->get_algorithm(this->proposal, EXTENDED_SEQUENCE_NUMBERS,
 								  &esn, NULL);
 
-	if (!this->reqid_allocated && !this->reqid)
+	if (!this->reqid_allocated && !this->static_reqid)
 	{
 		status = hydra->kernel_interface->alloc_reqid(hydra->kernel_interface,
 							my_ts, other_ts, this->mark_in, this->mark_out,
@@ -826,7 +831,7 @@ METHOD(child_sa_t, add_policies, status_t,
 	traffic_selector_t *my_ts, *other_ts;
 	status_t status = SUCCESS;
 
-	if (!this->reqid_allocated && !this->reqid)
+	if (!this->reqid_allocated && !this->static_reqid)
 	{
 		/* trap policy, get or confirm reqid */
 		status = hydra->kernel_interface->alloc_reqid(
@@ -1305,6 +1310,10 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
 			this->reqid = charon->traps->find_reqid(charon->traps, config);
 		}
 	}
+	else
+	{
+		this->static_reqid = TRUE;
+	}
 
 	/* MIPv6 proxy transport mode sets SA endpoints to TS hosts */
 	if (config->get_mode(config) == MODE_TRANSPORT &&
diff --git a/src/libcharon/sa/eap/eap_method.c b/src/libcharon/sa/eap/eap_method.c
index a05e8c5..9ce6ecf 100644
--- a/src/libcharon/sa/eap/eap_method.c
+++ b/src/libcharon/sa/eap/eap_method.c
@@ -30,7 +30,8 @@ bool eap_method_register(plugin_t *plugin, plugin_feature_t *feature,
 {
 	if (reg)
 	{
-		charon->eap->add_method(charon->eap, feature->arg.eap, 0,
+		charon->eap->add_method(charon->eap, feature->arg.eap.type,
+					feature->arg.eap.vendor,
 					feature->type == FEATURE_EAP_SERVER ? EAP_SERVER : EAP_PEER,
 					(eap_constructor_t)data);
 	}
diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c
index 3aafa4c..dcf9d5f 100644
--- a/src/libcharon/sa/ike_sa.c
+++ b/src/libcharon/sa/ike_sa.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006-2014 Tobias Brunner
+ * Copyright (C) 2006-2015 Tobias Brunner
  * Copyright (C) 2006 Daniel Roethlisberger
  * Copyright (C) 2005-2009 Martin Willi
  * Copyright (C) 2005 Jan Hutter
@@ -487,8 +487,9 @@ METHOD(ike_sa_t, send_keepalive, void,
 	send_keepalive_job_t *job;
 	time_t last_out, now, diff;
 
-	if (!(this->conditions & COND_NAT_HERE) || this->keepalive_interval == 0)
-	{	/* disable keep alives if we are not NATed anymore */
+	if (!(this->conditions & COND_NAT_HERE) || this->keepalive_interval == 0 ||
+		this->state == IKE_PASSIVE)
+	{	/* disable keep alives if we are not NATed anymore, or we are passive */
 		return;
 	}
 
@@ -651,7 +652,7 @@ METHOD(ike_sa_t, get_state, ike_sa_state_t,
 METHOD(ike_sa_t, set_state, void,
 	private_ike_sa_t *this, ike_sa_state_t state)
 {
-	bool trigger_dpd = FALSE;
+	bool trigger_dpd = FALSE, keepalives = FALSE;
 
 	DBG2(DBG_IKE, "IKE_SA %s[%d] state change: %N => %N",
 		 get_name(this), this->unique_id,
@@ -722,6 +723,10 @@ METHOD(ike_sa_t, set_state, void,
 					 * so yet, so prevent that. */
 					this->stats[STAT_INBOUND] = this->stats[STAT_ESTABLISHED];
 				}
+				if (this->state == IKE_PASSIVE)
+				{
+					keepalives = TRUE;
+				}
 			}
 			break;
 		}
@@ -742,6 +747,10 @@ METHOD(ike_sa_t, set_state, void,
 			DBG1(DBG_IKE, "DPD not supported by peer, disabled");
 		}
 	}
+	if (keepalives)
+	{
+		send_keepalive(this);
+	}
 }
 
 METHOD(ike_sa_t, reset, void,
@@ -1200,6 +1209,19 @@ static void resolve_hosts(private_ike_sa_t *this)
 			break;
 	}
 
+	/* if an IP address is set locally, use the same family to resolve remote */
+	if (family == AF_UNSPEC && !this->remote_host)
+	{
+		if (this->local_host)
+		{
+			family = this->local_host->get_family(this->local_host);
+		}
+		else
+		{
+			family = ike_cfg_get_family(this->ike_cfg, TRUE);
+		}
+	}
+
 	if (this->remote_host)
 	{
 		host = this->remote_host->clone(this->remote_host);
@@ -1211,7 +1233,18 @@ static void resolve_hosts(private_ike_sa_t *this)
 	}
 	if (host)
 	{
-		set_other_host(this, host);
+		if (!host->is_anyaddr(host) ||
+			this->other_host->is_anyaddr(this->other_host))
+		{	/* don't set to %any if we currently have an address, but the
+			 * address family might have changed */
+			set_other_host(this, host);
+		}
+		else
+		{	/* reuse the original port as some implementations might not like
+			 * initial IKE messages on other ports */
+			this->other_host->set_port(this->other_host, host->get_port(host));
+			host->destroy(host);
+		}
 	}
 
 	if (this->local_host)
diff --git a/src/libcharon/sa/ike_sa_id.c b/src/libcharon/sa/ike_sa_id.c
index 0f0f1ab..e520864 100644
--- a/src/libcharon/sa/ike_sa_id.c
+++ b/src/libcharon/sa/ike_sa_id.c
@@ -18,7 +18,7 @@
 #include "ike_sa_id.h"
 
 #include <stdio.h>
-
+#include <encoding/payloads/ike_header.h>
 
 typedef struct private_ike_sa_id_t private_ike_sa_id_t;
 
@@ -90,6 +90,8 @@ METHOD(ike_sa_id_t, equals, bool,
 		return FALSE;
 	}
 	return this->ike_version == other->ike_version &&
+		   (this->ike_version == IKEV1_MAJOR_VERSION ||
+			this->is_initiator_flag == other->is_initiator_flag) &&
 		   this->initiator_spi == other->initiator_spi &&
 		   this->responder_spi == other->responder_spi;
 }
diff --git a/src/libcharon/sa/ike_sa_manager.c b/src/libcharon/sa/ike_sa_manager.c
index 938f784..37d6987 100644
--- a/src/libcharon/sa/ike_sa_manager.c
+++ b/src/libcharon/sa/ike_sa_manager.c
@@ -1,7 +1,7 @@
 /*
  * Copyright (C) 2005-2011 Martin Willi
  * Copyright (C) 2011 revosec AG
- * Copyright (C) 2008-2012 Tobias Brunner
+ * Copyright (C) 2008-2015 Tobias Brunner
  * Copyright (C) 2005 Jan Hutter
  * Hochschule fuer Technik Rapperswil
  *
@@ -157,6 +157,8 @@ static bool entry_match_by_id(entry_t *entry, ike_sa_id_t *id)
 	}
 	if ((id->get_responder_spi(id) == 0 ||
 		 entry->ike_sa_id->get_responder_spi(entry->ike_sa_id) == 0) &&
+		(id->get_ike_version(id) == IKEV1_MAJOR_VERSION ||
+		 id->is_initiator(id) == entry->ike_sa_id->is_initiator(entry->ike_sa_id)) &&
 		id->get_initiator_spi(id) == entry->ike_sa_id->get_initiator_spi(entry->ike_sa_id))
 	{
 		/* this is TRUE for IKE_SAs that we initiated but have not yet received a response */
@@ -204,6 +206,9 @@ struct half_open_t {
 
 	/** the number of half-open IKE_SAs with that host */
 	u_int count;
+
+	/** the number of half-open IKE_SAs we responded to with that host */
+	u_int count_responder;
 };
 
 /**
@@ -359,6 +364,11 @@ struct private_ike_sa_manager_t {
 	refcount_t half_open_count;
 
 	/**
+	 * Total number of half-open IKE_SAs as responder.
+	 */
+	refcount_t half_open_count_responder;
+
+	/**
 	 * Hash table with connected_peers_t objects.
 	 */
 	table_item_t **connected_peers_table;
@@ -384,6 +394,11 @@ struct private_ike_sa_manager_t {
 	rng_t *rng;
 
 	/**
+	 * Lock to access the RNG instance
+	 */
+	rwlock_t *rng_lock;
+
+	/**
 	 * reuse existing IKE_SAs in checkout_by_config
 	 */
 	bool reuse_ikesa;
@@ -730,9 +745,11 @@ static void put_half_open(private_ike_sa_manager_t *this, entry_t *entry)
 	table_item_t *item;
 	u_int row, segment;
 	rwlock_t *lock;
+	ike_sa_id_t *ike_id;
 	half_open_t *half_open;
 	chunk_t addr;
 
+	ike_id = entry->ike_sa_id;
 	addr = entry->other->get_address(entry->other);
 	row = chunk_hash(addr) & this->table_mask;
 	segment = row & this->segment_mask;
@@ -745,7 +762,6 @@ static void put_half_open(private_ike_sa_manager_t *this, entry_t *entry)
 
 		if (chunk_equals(addr, half_open->other))
 		{
-			half_open->count++;
 			break;
 		}
 		item = item->next;
@@ -755,7 +771,6 @@ static void put_half_open(private_ike_sa_manager_t *this, entry_t *entry)
 	{
 		INIT(half_open,
 			.other = chunk_clone(addr),
-			.count = 1,
 		);
 		INIT(item,
 			.value = half_open,
@@ -763,8 +778,14 @@ static void put_half_open(private_ike_sa_manager_t *this, entry_t *entry)
 		);
 		this->half_open_table[row] = item;
 	}
-	this->half_open_segments[segment].count++;
+	half_open->count++;
 	ref_get(&this->half_open_count);
+	if (!ike_id->is_initiator(ike_id))
+	{
+		half_open->count_responder++;
+		ref_get(&this->half_open_count_responder);
+	}
+	this->half_open_segments[segment].count++;
 	lock->unlock(lock);
 }
 
@@ -776,8 +797,10 @@ static void remove_half_open(private_ike_sa_manager_t *this, entry_t *entry)
 	table_item_t *item, *prev = NULL;
 	u_int row, segment;
 	rwlock_t *lock;
+	ike_sa_id_t *ike_id;
 	chunk_t addr;
 
+	ike_id = entry->ike_sa_id;
 	addr = entry->other->get_address(entry->other);
 	row = chunk_hash(addr) & this->table_mask;
 	segment = row & this->segment_mask;
@@ -790,6 +813,12 @@ static void remove_half_open(private_ike_sa_manager_t *this, entry_t *entry)
 
 		if (chunk_equals(addr, half_open->other))
 		{
+			if (!ike_id->is_initiator(ike_id))
+			{
+				half_open->count_responder--;
+				ignore_result(ref_put(&this->half_open_count_responder));
+			}
+			ignore_result(ref_put(&this->half_open_count));
 			if (--half_open->count == 0)
 			{
 				if (prev)
@@ -804,7 +833,6 @@ static void remove_half_open(private_ike_sa_manager_t *this, entry_t *entry)
 				free(item);
 			}
 			this->half_open_segments[segment].count--;
-			ignore_result(ref_put(&this->half_open_count));
 			break;
 		}
 		prev = item;
@@ -943,12 +971,14 @@ static u_int64_t get_spi(private_ike_sa_manager_t *this)
 {
 	u_int64_t spi;
 
-	if (this->rng &&
-		this->rng->get_bytes(this->rng, sizeof(spi), (u_int8_t*)&spi))
+	this->rng_lock->read_lock(this->rng_lock);
+	if (!this->rng ||
+		!this->rng->get_bytes(this->rng, sizeof(spi), (u_int8_t*)&spi))
 	{
-		return spi;
+		spi = 0;
 	}
-	return 0;
+	this->rng_lock->unlock(this->rng_lock);
+	return spi;
 }
 
 /**
@@ -1563,7 +1593,6 @@ METHOD(ike_sa_manager_t, checkin, void,
 			put_half_open(this, entry);
 		}
 		else if (!entry->half_open &&
-				 !entry->ike_sa_id->is_initiator(entry->ike_sa_id) &&
 				 ike_sa->get_state(ike_sa) == IKE_CONNECTING)
 		{
 			/* this is a new half-open SA */
@@ -1579,6 +1608,12 @@ METHOD(ike_sa_manager_t, checkin, void,
 		entry = entry_create();
 		entry->ike_sa_id = ike_sa_id->clone(ike_sa_id);
 		entry->ike_sa = ike_sa;
+		if (ike_sa->get_state(ike_sa) == IKE_CONNECTING)
+		{
+			entry->half_open = TRUE;
+			entry->other = other->clone(other);
+			put_half_open(this, entry);
+		}
 		segment = put_entry(this, entry);
 	}
 
@@ -1937,7 +1972,7 @@ METHOD(ike_sa_manager_t, get_count, u_int,
 }
 
 METHOD(ike_sa_manager_t, get_half_open_count, u_int,
-	private_ike_sa_manager_t *this, host_t *ip)
+	private_ike_sa_manager_t *this, host_t *ip, bool responder_only)
 {
 	table_item_t *item;
 	u_int row, segment;
@@ -1959,7 +1994,8 @@ METHOD(ike_sa_manager_t, get_half_open_count, u_int,
 
 			if (chunk_equals(addr, half_open->other))
 			{
-				count = half_open->count;
+				count = responder_only ? half_open->count_responder
+									   : half_open->count;
 				break;
 			}
 			item = item->next;
@@ -1968,7 +2004,8 @@ METHOD(ike_sa_manager_t, get_half_open_count, u_int,
 	}
 	else
 	{
-		count = (u_int)ref_cur(&this->half_open_count);
+		count = responder_only ? (u_int)ref_cur(&this->half_open_count_responder)
+							   : (u_int)ref_cur(&this->half_open_count);
 	}
 	return count;
 }
@@ -2055,8 +2092,10 @@ METHOD(ike_sa_manager_t, flush, void,
 	charon->bus->set_sa(charon->bus, NULL);
 	unlock_all_segments(this);
 
+	this->rng_lock->write_lock(this->rng_lock);
 	this->rng->destroy(this->rng);
 	this->rng = NULL;
+	this->rng_lock->unlock(this->rng_lock);
 }
 
 METHOD(ike_sa_manager_t, destroy, void,
@@ -2081,6 +2120,7 @@ METHOD(ike_sa_manager_t, destroy, void,
 	free(this->connected_peers_segments);
 	free(this->init_hashes_segments);
 
+	this->rng_lock->destroy(this->rng_lock);
 	free(this);
 }
 
@@ -2138,6 +2178,7 @@ ike_sa_manager_t *ike_sa_manager_create()
 		free(this);
 		return NULL;
 	}
+	this->rng_lock = rwlock_create(RWLOCK_TYPE_DEFAULT);
 
 	this->ikesa_limit = lib->settings->get_int(lib->settings,
 											   "%s.ikesa_limit", 0, lib->ns);
diff --git a/src/libcharon/sa/ike_sa_manager.h b/src/libcharon/sa/ike_sa_manager.h
index f259d8e..3ea928e 100644
--- a/src/libcharon/sa/ike_sa_manager.h
+++ b/src/libcharon/sa/ike_sa_manager.h
@@ -216,14 +216,15 @@ struct ike_sa_manager_t {
 	 * To prevent the server from resource exhaustion, cookies and other
 	 * mechanisms are used. The number of half open IKE_SAs is a good
 	 * indicator to see if a peer is flooding the server.
-	 * If a host is supplied, only the number of half open IKE_SAs initiated
-	 * from this IP are counted.
-	 * Only SAs for which we are the responder are counted.
+	 * If a host is supplied, only the number of half open IKE_SAs with this IP
+	 * are counted.
 	 *
 	 * @param ip				NULL for all, IP for half open IKE_SAs with IP
+	 * @param responder_only	TRUE to return only the number of responding SAs
 	 * @return					number of half open IKE_SAs
 	 */
-	u_int (*get_half_open_count) (ike_sa_manager_t *this, host_t *ip);
+	u_int (*get_half_open_count)(ike_sa_manager_t *this, host_t *ip,
+								 bool responder_only);
 
 	/**
 	 * Delete all existing IKE_SAs and destroy them immediately.
diff --git a/src/libcharon/sa/ikev1/phase1.c b/src/libcharon/sa/ikev1/phase1.c
index c968b2a..b7047e8 100644
--- a/src/libcharon/sa/ikev1/phase1.c
+++ b/src/libcharon/sa/ikev1/phase1.c
@@ -404,7 +404,7 @@ static auth_method_t get_pubkey_method(private_phase1_t *this, auth_cfg_t *auth)
 		id = (identification_t*)auth->get(auth, AUTH_RULE_IDENTITY);
 		if (id)
 		{
-			private = lib->credmgr->get_private(lib->credmgr, KEY_ANY, id, NULL);
+			private = lib->credmgr->get_private(lib->credmgr, KEY_ANY, id, auth);
 			if (private)
 			{
 				switch (private->get_type(private))
diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c
index ed547c4..678f99d 100644
--- a/src/libcharon/sa/ikev1/task_manager_v1.c
+++ b/src/libcharon/sa/ikev1/task_manager_v1.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007-2014 Tobias Brunner
+ * Copyright (C) 2007-2015 Tobias Brunner
  * Copyright (C) 2007-2011 Martin Willi
  * Hochschule fuer Technik Rapperswil
  *
@@ -901,6 +901,34 @@ static bool process_dpd(private_task_manager_t *this, message_t *message)
 }
 
 /**
+ * Check if we already have a quick mode task queued for the exchange with the
+ * given message ID
+ */
+static bool have_quick_mode_task(private_task_manager_t *this, u_int32_t mid)
+{
+	enumerator_t *enumerator;
+	quick_mode_t *qm;
+	task_t *task;
+	bool found = FALSE;
+
+	enumerator = this->passive_tasks->create_enumerator(this->passive_tasks);
+	while (enumerator->enumerate(enumerator, &task))
+	{
+		if (task->get_type(task) == TASK_QUICK_MODE)
+		{
+			qm = (quick_mode_t*)task;
+			if (qm->get_mid(qm) == mid)
+			{
+				found = TRUE;
+				break;
+			}
+		}
+	}
+	enumerator->destroy(enumerator);
+	return found;
+}
+
+/**
  * handle an incoming request message
  */
 static status_t process_request(private_task_manager_t *this,
@@ -911,6 +939,7 @@ static status_t process_request(private_task_manager_t *this,
 	bool send_response = FALSE, dpd = FALSE;
 
 	if (message->get_exchange_type(message) == INFORMATIONAL_V1 ||
+		message->get_exchange_type(message) == QUICK_MODE ||
 		this->passive_tasks->get_count(this->passive_tasks) == 0)
 	{	/* create tasks depending on request type, if not already some queued */
 		switch (message->get_exchange_type(message))
@@ -946,6 +975,10 @@ static status_t process_request(private_task_manager_t *this,
 						 "unestablished IKE_SA, ignored");
 					return FAILED;
 				}
+				if (have_quick_mode_task(this, message->get_message_id(message)))
+				{
+					break;
+				}
 				task = (task_t *)quick_mode_create(this->ike_sa, NULL,
 												   NULL, NULL);
 				this->passive_tasks->insert_last(this->passive_tasks, task);
diff --git a/src/libcharon/sa/ikev1/tasks/quick_mode.c b/src/libcharon/sa/ikev1/tasks/quick_mode.c
index 96edfd8..d6a3f2c 100644
--- a/src/libcharon/sa/ikev1/tasks/quick_mode.c
+++ b/src/libcharon/sa/ikev1/tasks/quick_mode.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 Tobias Brunner
+ * Copyright (C) 2012-2015 Tobias Brunner
  * Hochschule fuer Technik Rapperswil
  *
  * Copyright (C) 2011 Martin Willi
@@ -185,6 +185,11 @@ struct private_quick_mode_t {
 	 */
 	bool udp;
 
+	/**
+	 * Message ID of handled quick mode exchange
+	 */
+	u_int32_t mid;
+
 	/** states of quick mode */
 	enum {
 		QM_INIT,
@@ -1019,6 +1024,11 @@ static void check_for_rekeyed_child(private_quick_mode_t *this)
 METHOD(task_t, process_r, status_t,
 	private_quick_mode_t *this, message_t *message)
 {
+	if (this->mid && this->mid != message->get_message_id(message))
+	{	/* not responsible for this quick mode exchange */
+		return NEED_MORE;
+	}
+
 	switch (this->state)
 	{
 		case QM_INIT:
@@ -1188,6 +1198,11 @@ METHOD(task_t, process_r, status_t,
 METHOD(task_t, build_r, status_t,
 	private_quick_mode_t *this, message_t *message)
 {
+	if (this->mid && this->mid != message->get_message_id(message))
+	{	/* not responsible for this quick mode exchange */
+		return NEED_MORE;
+	}
+
 	switch (this->state)
 	{
 		case QM_INIT:
@@ -1242,6 +1257,7 @@ METHOD(task_t, build_r, status_t,
 			add_ts(this, message);
 
 			this->state = QM_NEGOTIATED;
+			this->mid = message->get_message_id(message);
 			return NEED_MORE;
 		}
 		case QM_NEGOTIATED:
@@ -1335,6 +1351,12 @@ METHOD(task_t, get_type, task_type_t,
 	return TASK_QUICK_MODE;
 }
 
+METHOD(quick_mode_t, get_mid, u_int32_t,
+	private_quick_mode_t *this)
+{
+	return this->mid;
+}
+
 METHOD(quick_mode_t, use_reqid, void,
 	private_quick_mode_t *this, u_int32_t reqid)
 {
@@ -1368,6 +1390,7 @@ METHOD(task_t, migrate, void,
 	this->ike_sa = ike_sa;
 	this->keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa);
 	this->state = QM_INIT;
+	this->mid = 0;
 	this->tsi = NULL;
 	this->tsr = NULL;
 	this->proposal = NULL;
@@ -1414,6 +1437,7 @@ quick_mode_t *quick_mode_create(ike_sa_t *ike_sa, child_cfg_t *config,
 				.migrate = _migrate,
 				.destroy = _destroy,
 			},
+			.get_mid = _get_mid,
 			.use_reqid = _use_reqid,
 			.use_marks = _use_marks,
 			.rekey = _rekey,
diff --git a/src/libcharon/sa/ikev1/tasks/quick_mode.h b/src/libcharon/sa/ikev1/tasks/quick_mode.h
index ee9b64d..062d634 100644
--- a/src/libcharon/sa/ikev1/tasks/quick_mode.h
+++ b/src/libcharon/sa/ikev1/tasks/quick_mode.h
@@ -1,4 +1,7 @@
 /*
+ * Copyright (C) 2015 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
  * Copyright (C) 2011 Martin Willi
  * Copyright (C) 2011 revosec AG
  *
@@ -38,6 +41,14 @@ struct quick_mode_t {
 	task_t task;
 
 	/**
+	 * Get the message ID of the quick mode exchange handled by this task as
+	 * responder.
+	 *
+	 * @return				message ID, or 0 (not defined yet or as initiator)
+	 */
+	u_int32_t (*get_mid)(quick_mode_t *this);
+
+	/**
 	 * Use a specific reqid to install this CHILD_SA.
 	 *
 	 * @param reqid			reqid to use
diff --git a/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c b/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c
index f144209..91f6187 100644
--- a/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c
+++ b/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c
@@ -448,6 +448,8 @@ static bool verify_auth(private_eap_authenticator_t *this, message_t *message,
 	identification_t *other_id;
 	auth_cfg_t *auth;
 	keymat_v2_t *keymat;
+	eap_type_t type;
+	u_int32_t vendor;
 
 	auth_payload = (auth_payload_t*)message->get_payload(message,
 														 PLV2_AUTH);
@@ -478,6 +480,13 @@ static bool verify_auth(private_eap_authenticator_t *this, message_t *message,
 	this->auth_complete = TRUE;
 	auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
 	auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP);
+
+	type = this->method->get_type(this->method, &vendor);
+	auth->add(auth, AUTH_RULE_EAP_TYPE, type);
+	if (vendor)
+	{
+		auth->add(auth, AUTH_RULE_EAP_VENDOR, vendor);
+	}
 	return TRUE;
 }
 
diff --git a/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c b/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c
index 151b497..2284a48 100644
--- a/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c
+++ b/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c
@@ -321,7 +321,7 @@ METHOD(authenticator_t, build, status_t,
 	chunk_t auth_data;
 	status_t status;
 	auth_payload_t *auth_payload;
-	auth_method_t auth_method;
+	auth_method_t auth_method = AUTH_NONE;
 
 	id = this->ike_sa->get_my_id(this->ike_sa);
 	auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE);
diff --git a/src/libcharon/sa/ikev2/keymat_v2.c b/src/libcharon/sa/ikev2/keymat_v2.c
index 6fedc8e..fce0840 100644
--- a/src/libcharon/sa/ikev2/keymat_v2.c
+++ b/src/libcharon/sa/ikev2/keymat_v2.c
@@ -112,6 +112,7 @@ static bool derive_ike_aead(private_keymat_v2_t *this, u_int16_t alg,
 		case ENCR_AES_GCM_ICV12:
 		case ENCR_AES_GCM_ICV16:
 			/* RFC 4106 */
+		case ENCR_CHACHA20_POLY1305:
 			salt_size = 4;
 			break;
 		case ENCR_AES_CCM_ICV8:
@@ -527,6 +528,7 @@ METHOD(keymat_v2_t, derive_child_keys, bool,
 			case ENCR_AES_GCM_ICV16:
 			case ENCR_AES_CTR:
 			case ENCR_NULL_AUTH_AES_GMAC:
+			case ENCR_CHACHA20_POLY1305:
 				enc_size += 4;
 				break;
 			default:
diff --git a/src/libcharon/sa/ikev2/tasks/child_create.c b/src/libcharon/sa/ikev2/tasks/child_create.c
index e0f930c..e08f3da 100644
--- a/src/libcharon/sa/ikev2/tasks/child_create.c
+++ b/src/libcharon/sa/ikev2/tasks/child_create.c
@@ -145,6 +145,11 @@ struct private_child_create_t {
 	ipcomp_transform_t ipcomp_received;
 
 	/**
+	 * IPsec protocol
+	 */
+	protocol_id_t proto;
+
+	/**
 	 * Own allocated SPI
 	 */
 	u_int32_t my_spi;
@@ -260,23 +265,23 @@ static bool allocate_spi(private_child_create_t *this)
 {
 	enumerator_t *enumerator;
 	proposal_t *proposal;
-	protocol_id_t proto = PROTO_ESP;
 
 	if (this->initiator)
 	{
+		this->proto = PROTO_ESP;
 		/* we just get a SPI for the first protocol. TODO: If we ever support
 		 * proposal lists with mixed protocols, we'd need multiple SPIs */
 		if (this->proposals->get_first(this->proposals,
 									   (void**)&proposal) == SUCCESS)
 		{
-			proto = proposal->get_protocol(proposal);
+			this->proto = proposal->get_protocol(proposal);
 		}
 	}
 	else
 	{
-		proto = this->proposal->get_protocol(this->proposal);
+		this->proto = this->proposal->get_protocol(this->proposal);
 	}
-	this->my_spi = this->child_sa->alloc_spi(this->child_sa, proto);
+	this->my_spi = this->child_sa->alloc_spi(this->child_sa, this->proto);
 	if (this->my_spi)
 	{
 		if (this->initiator)
@@ -1352,20 +1357,16 @@ METHOD(task_t, build_i_delete, status_t,
 	private_child_create_t *this, message_t *message)
 {
 	message->set_exchange_type(message, INFORMATIONAL);
-	if (this->child_sa && this->proposal)
+	if (this->my_spi && this->proto)
 	{
-		protocol_id_t proto;
 		delete_payload_t *del;
-		u_int32_t spi;
 
-		proto = this->proposal->get_protocol(this->proposal);
-		spi = this->child_sa->get_spi(this->child_sa, TRUE);
-		del = delete_payload_create(PLV2_DELETE, proto);
-		del->add_spi(del, spi);
+		del = delete_payload_create(PLV2_DELETE, this->proto);
+		del->add_spi(del, this->my_spi);
 		message->add_payload(message, (payload_t*)del);
 
 		DBG1(DBG_IKE, "sending DELETE for %N CHILD_SA with SPI %.8x",
-			 protocol_id_names, proto, ntohl(spi));
+			 protocol_id_names, this->proto, ntohl(this->my_spi));
 	}
 	return NEED_MORE;
 }
@@ -1375,9 +1376,13 @@ METHOD(task_t, build_i_delete, status_t,
  */
 static status_t delete_failed_sa(private_child_create_t *this)
 {
-	this->public.task.build = _build_i_delete;
-	this->public.task.process = (void*)return_success;
-	return NEED_MORE;
+	if (this->my_spi && this->proto)
+	{
+		this->public.task.build = _build_i_delete;
+		this->public.task.process = (void*)return_success;
+		return NEED_MORE;
+	}
+	return SUCCESS;
 }
 
 METHOD(task_t, process_i, status_t,
@@ -1596,6 +1601,7 @@ METHOD(task_t, migrate, void,
 	this->tsi = NULL;
 	this->tsr = NULL;
 	this->dh = NULL;
+	this->nonceg = NULL;
 	this->child_sa = NULL;
 	this->mode = MODE_TUNNEL;
 	this->ipcomp = IPCOMP_NONE;
diff --git a/src/libcharon/sa/ikev2/tasks/child_rekey.c b/src/libcharon/sa/ikev2/tasks/child_rekey.c
index c806e19..c7a8a13 100644
--- a/src/libcharon/sa/ikev2/tasks/child_rekey.c
+++ b/src/libcharon/sa/ikev2/tasks/child_rekey.c
@@ -170,13 +170,8 @@ METHOD(task_t, build_i, status_t,
 	}
 	config = this->child_sa->get_config(this->child_sa);
 
-	/* we just need the rekey notify ... */
-	notify = notify_payload_create_from_protocol_and_type(PLV2_NOTIFY,
-													this->protocol, REKEY_SA);
-	notify->set_spi(notify, this->spi);
-	message->add_payload(message, (payload_t*)notify);
 
-	/* ... our CHILD_CREATE task does the hard work for us. */
+	/* our CHILD_CREATE task does the hard work for us */
 	if (!this->child_create)
 	{
 		this->child_create = child_create_create(this->ike_sa,
@@ -194,6 +189,14 @@ METHOD(task_t, build_i, status_t,
 		schedule_delayed_rekey(this);
 		return FAILED;
 	}
+	if (message->get_exchange_type(message) == CREATE_CHILD_SA)
+	{
+		/* don't add the notify if the CHILD_CREATE task changed the exchange */
+		notify = notify_payload_create_from_protocol_and_type(PLV2_NOTIFY,
+													this->protocol, REKEY_SA);
+		notify->set_spi(notify, this->spi);
+		message->add_payload(message, (payload_t*)notify);
+	}
 	this->child_sa->set_state(this->child_sa, CHILD_REKEYING);
 
 	return NEED_MORE;
@@ -334,8 +337,7 @@ METHOD(task_t, process_i, status_t,
 	if (this->child_create->task.process(&this->child_create->task,
 										 message) == NEED_MORE)
 	{
-		/* bad DH group while rekeying, try again */
-		this->child_create->task.migrate(&this->child_create->task, this->ike_sa);
+		/* bad DH group while rekeying, retry, or failure requiring deletion */
 		return NEED_MORE;
 	}
 	if (message->get_payload(message, PLV2_SECURITY_ASSOCIATION) == NULL)
diff --git a/src/libcharon/sa/ikev2/tasks/ike_rekey.c b/src/libcharon/sa/ikev2/tasks/ike_rekey.c
index 1855517..eaba04e 100644
--- a/src/libcharon/sa/ikev2/tasks/ike_rekey.c
+++ b/src/libcharon/sa/ikev2/tasks/ike_rekey.c
@@ -116,7 +116,6 @@ static void establish_new(private_ike_rekey_t *this)
 			lib->processor->queue_job(lib->processor, job);
 		}
 		this->new_sa = NULL;
-		/* set threads active IKE_SA after checkin */
 		charon->bus->set_sa(charon->bus, this->ike_sa);
 	}
 }
@@ -229,9 +228,10 @@ METHOD(task_t, build_r, status_t,
 
 	if (this->ike_init->task.build(&this->ike_init->task, message) == FAILED)
 	{
+		charon->bus->set_sa(charon->bus, this->ike_sa);
 		return SUCCESS;
 	}
-
+	charon->bus->set_sa(charon->bus, this->ike_sa);
 	this->ike_sa->set_state(this->ike_sa, IKE_REKEYING);
 
 	/* rekeying successful, delete the IKE_SA using a subtask */
@@ -335,15 +335,13 @@ METHOD(task_t, process_i, status_t,
 				{
 					charon->ike_sa_manager->checkin(
 								charon->ike_sa_manager, this->new_sa);
-					/* set threads active IKE_SA after checkin */
-					charon->bus->set_sa(charon->bus, this->ike_sa);
 				}
+				charon->bus->set_sa(charon->bus, this->ike_sa);
 				this->new_sa = NULL;
 				establish_new(other);
 				return SUCCESS;
 			}
 		}
-		/* set threads active IKE_SA after checkin */
 		charon->bus->set_sa(charon->bus, this->ike_sa);
 	}
 
@@ -372,9 +370,13 @@ METHOD(ike_rekey_t, collide, void,
 	this->collision = other;
 }
 
-METHOD(task_t, migrate, void,
-	private_ike_rekey_t *this, ike_sa_t *ike_sa)
+/**
+ * Cleanup the task
+ */
+static void cleanup(private_ike_rekey_t *this)
 {
+	ike_sa_t *cur_sa;
+
 	if (this->ike_init)
 	{
 		this->ike_init->task.destroy(&this->ike_init->task);
@@ -383,9 +385,16 @@ METHOD(task_t, migrate, void,
 	{
 		this->ike_delete->task.destroy(&this->ike_delete->task);
 	}
+	cur_sa = charon->bus->get_sa(charon->bus);
 	DESTROY_IF(this->new_sa);
+	charon->bus->set_sa(charon->bus, cur_sa);
 	DESTROY_IF(this->collision);
+}
 
+METHOD(task_t, migrate, void,
+	private_ike_rekey_t *this, ike_sa_t *ike_sa)
+{
+	cleanup(this);
 	this->collision = NULL;
 	this->ike_sa = ike_sa;
 	this->new_sa = NULL;
@@ -396,16 +405,7 @@ METHOD(task_t, migrate, void,
 METHOD(task_t, destroy, void,
 	private_ike_rekey_t *this)
 {
-	if (this->ike_init)
-	{
-		this->ike_init->task.destroy(&this->ike_init->task);
-	}
-	if (this->ike_delete)
-	{
-		this->ike_delete->task.destroy(&this->ike_delete->task);
-	}
-	DESTROY_IF(this->new_sa);
-	DESTROY_IF(this->collision);
+	cleanup(this);
 	free(this);
 }
 
diff --git a/src/libcharon/sa/shunt_manager.c b/src/libcharon/sa/shunt_manager.c
index 73e1abb..1a98443 100644
--- a/src/libcharon/sa/shunt_manager.c
+++ b/src/libcharon/sa/shunt_manager.c
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2015 Tobias Brunner
  * Copyright (C) 2011 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
@@ -18,8 +19,10 @@
 #include <hydra.h>
 #include <daemon.h>
 #include <threading/rwlock.h>
+#include <threading/rwlock_condvar.h>
 #include <collections/linked_list.h>
 
+#define INSTALL_DISABLED ((u_int)~0)
 
 typedef struct private_shunt_manager_t private_shunt_manager_t;
 
@@ -37,6 +40,21 @@ struct private_shunt_manager_t {
 	 * Installed shunts, as child_cfg_t
 	 */
 	linked_list_t *shunts;
+
+	/**
+	 * Lock to safely access the list of shunts
+	 */
+	rwlock_t *lock;
+
+	/**
+	 * Number of threads currently installing shunts, or INSTALL_DISABLED
+	 */
+	u_int installing;
+
+	/**
+	 * Condvar to signal shunt installation
+	 */
+	rwlock_condvar_t *condvar;
 };
 
 /**
@@ -117,9 +135,15 @@ METHOD(shunt_manager_t, install, bool,
 {
 	enumerator_t *enumerator;
 	child_cfg_t *child_cfg;
-	bool found = FALSE;
+	bool found = FALSE, success;
 
 	/* check if not already installed */
+	this->lock->write_lock(this->lock);
+	if (this->installing == INSTALL_DISABLED)
+	{	/* flush() has been called */
+		this->lock->unlock(this->lock);
+		return FALSE;
+	}
 	enumerator = this->shunts->create_enumerator(this->shunts);
 	while (enumerator->enumerate(enumerator, &child_cfg))
 	{
@@ -130,16 +154,29 @@ METHOD(shunt_manager_t, install, bool,
 		}
 	}
 	enumerator->destroy(enumerator);
-
 	if (found)
 	{
 		DBG1(DBG_CFG, "shunt %N policy '%s' already installed",
 			 ipsec_mode_names, child->get_mode(child), child->get_name(child));
+		this->lock->unlock(this->lock);
 		return TRUE;
 	}
 	this->shunts->insert_last(this->shunts, child->get_ref(child));
+	this->installing++;
+	this->lock->unlock(this->lock);
 
-	return install_shunt_policy(child);
+	success = install_shunt_policy(child);
+
+	this->lock->write_lock(this->lock);
+	if (!success)
+	{
+		this->shunts->remove(this->shunts, child, NULL);
+		child->destroy(child);
+	}
+	this->installing--;
+	this->condvar->signal(this->condvar);
+	this->lock->unlock(this->lock);
+	return success;
 }
 
 /**
@@ -215,6 +252,7 @@ METHOD(shunt_manager_t, uninstall, bool,
 	enumerator_t *enumerator;
 	child_cfg_t *child, *found = NULL;
 
+	this->lock->write_lock(this->lock);
 	enumerator = this->shunts->create_enumerator(this->shunts);
 	while (enumerator->enumerate(enumerator, &child))
 	{
@@ -226,6 +264,7 @@ METHOD(shunt_manager_t, uninstall, bool,
 		}
 	}
 	enumerator->destroy(enumerator);
+	this->lock->unlock(this->lock);
 
 	if (!found)
 	{
@@ -239,20 +278,37 @@ METHOD(shunt_manager_t, uninstall, bool,
 METHOD(shunt_manager_t, create_enumerator, enumerator_t*,
 	private_shunt_manager_t *this)
 {
-	return this->shunts->create_enumerator(this->shunts);
+	this->lock->read_lock(this->lock);
+	return enumerator_create_cleaner(
+							this->shunts->create_enumerator(this->shunts),
+							(void*)this->lock->unlock, this->lock);
 }
 
-METHOD(shunt_manager_t, destroy, void,
+METHOD(shunt_manager_t, flush, void,
 	private_shunt_manager_t *this)
 {
 	child_cfg_t *child;
 
+	this->lock->write_lock(this->lock);
+	while (this->installing)
+	{
+		this->condvar->wait(this->condvar, this->lock);
+	}
 	while (this->shunts->remove_last(this->shunts, (void**)&child) == SUCCESS)
 	{
 		uninstall_shunt_policy(child);
 		child->destroy(child);
 	}
-	this->shunts->destroy(this->shunts);
+	this->installing = INSTALL_DISABLED;
+	this->lock->unlock(this->lock);
+}
+
+METHOD(shunt_manager_t, destroy, void,
+	private_shunt_manager_t *this)
+{
+	this->shunts->destroy_offset(this->shunts, offsetof(child_cfg_t, destroy));
+	this->lock->destroy(this->lock);
+	this->condvar->destroy(this->condvar);
 	free(this);
 }
 
@@ -268,9 +324,12 @@ shunt_manager_t *shunt_manager_create()
 			.install = _install,
 			.uninstall = _uninstall,
 			.create_enumerator = _create_enumerator,
+			.flush = _flush,
 			.destroy = _destroy,
 		},
 		.shunts = linked_list_create(),
+		.lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
+		.condvar = rwlock_condvar_create(),
 	);
 
 	return &this->public;
diff --git a/src/libcharon/sa/shunt_manager.h b/src/libcharon/sa/shunt_manager.h
index 28a795d..c43f5db 100644
--- a/src/libcharon/sa/shunt_manager.h
+++ b/src/libcharon/sa/shunt_manager.h
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2015 Tobias Brunner
  * Copyright (C) 2011 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
@@ -56,6 +57,11 @@ struct shunt_manager_t {
 	enumerator_t* (*create_enumerator)(shunt_manager_t *this);
 
 	/**
+	 * Clear any installed shunt.
+	 */
+	void (*flush)(shunt_manager_t *this);
+
+	/**
 	 * Destroy a shunt_manager_t.
 	 */
 	void (*destroy)(shunt_manager_t *this);
diff --git a/src/libcharon/sa/trap_manager.c b/src/libcharon/sa/trap_manager.c
index d6ff3c8..63505c9 100644
--- a/src/libcharon/sa/trap_manager.c
+++ b/src/libcharon/sa/trap_manager.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011-2013 Tobias Brunner
+ * Copyright (C) 2011-2015 Tobias Brunner
  * Copyright (C) 2009 Martin Willi
  * Hochschule fuer Technik Rapperswil
  *
@@ -18,9 +18,12 @@
 
 #include <hydra.h>
 #include <daemon.h>
+#include <threading/mutex.h>
 #include <threading/rwlock.h>
+#include <threading/rwlock_condvar.h>
 #include <collections/linked_list.h>
 
+#define INSTALL_DISABLED ((u_int)~0)
 
 typedef struct private_trap_manager_t private_trap_manager_t;
 typedef struct trap_listener_t trap_listener_t;
@@ -67,6 +70,26 @@ struct private_trap_manager_t {
 	trap_listener_t listener;
 
 	/**
+	 * list of acquires we currently handle
+	 */
+	linked_list_t *acquires;
+
+	/**
+	 * mutex for list of acquires
+	 */
+	mutex_t *mutex;
+
+	/**
+	 * number of threads currently installing trap policies, or INSTALL_DISABLED
+	 */
+	u_int installing;
+
+	/**
+	 * condvar to signal trap policy installation
+	 */
+	rwlock_condvar_t *condvar;
+
+	/**
 	 * Whether to ignore traffic selectors from acquires
 	 */
 	bool ignore_acquire_ts;
@@ -80,23 +103,58 @@ typedef struct {
 	char *name;
 	/** ref to peer_cfg to initiate */
 	peer_cfg_t *peer_cfg;
-	/** ref to instanciated CHILD_SA */
+	/** ref to instantiated CHILD_SA (i.e the trap policy) */
 	child_sa_t *child_sa;
-	/** TRUE if an acquire is pending */
-	bool pending;
+	/** TRUE in case of wildcard Transport Mode SA */
+	bool wildcard;
+} entry_t;
+
+/**
+ * A handled acquire
+ */
+typedef struct {
 	/** pending IKE_SA connecting upon acquire */
 	ike_sa_t *ike_sa;
-} entry_t;
+	/** reqid of pending trap policy */
+	u_int32_t reqid;
+	/** destination address (wildcard case) */
+	host_t *dst;
+} acquire_t;
 
 /**
  * actually uninstall and destroy an installed entry
  */
-static void destroy_entry(entry_t *entry)
+static void destroy_entry(entry_t *this)
+{
+	this->child_sa->destroy(this->child_sa);
+	this->peer_cfg->destroy(this->peer_cfg);
+	free(this->name);
+	free(this);
+}
+
+/**
+ * destroy a cached acquire entry
+ */
+static void destroy_acquire(acquire_t *this)
 {
-	entry->child_sa->destroy(entry->child_sa);
-	entry->peer_cfg->destroy(entry->peer_cfg);
-	free(entry->name);
-	free(entry);
+	DESTROY_IF(this->dst);
+	free(this);
+}
+
+/**
+ * match an acquire entry by reqid
+ */
+static bool acquire_by_reqid(acquire_t *this, u_int32_t *reqid)
+{
+	return this->reqid == *reqid;
+}
+
+/**
+ * match an acquire entry by destination address
+ */
+static bool acquire_by_dst(acquire_t *this, host_t *dst)
+{
+	return this->dst && this->dst->ip_equals(this->dst, dst);
 }
 
 METHOD(trap_manager_t, install, u_int32_t,
@@ -113,32 +171,49 @@ METHOD(trap_manager_t, install, u_int32_t,
 	linked_list_t *proposals;
 	proposal_t *proposal;
 	protocol_id_t proto = PROTO_ESP;
+	bool wildcard = FALSE;
 
 	/* try to resolve addresses */
 	ike_cfg = peer->get_ike_cfg(peer);
 	other = ike_cfg->resolve_other(ike_cfg, AF_UNSPEC);
-	if (!other || other->is_anyaddr(other))
+	if (other && other->is_anyaddr(other) &&
+		child->get_mode(child) == MODE_TRANSPORT)
+	{
+		/* allow wildcard for Transport Mode SAs */
+		me = host_create_any(other->get_family(other));
+		wildcard = TRUE;
+	}
+	else if (!other || other->is_anyaddr(other))
 	{
 		DESTROY_IF(other);
 		DBG1(DBG_CFG, "installing trap failed, remote address unknown");
 		return 0;
 	}
-	me = ike_cfg->resolve_me(ike_cfg, other->get_family(other));
-	if (!me || me->is_anyaddr(me))
+	else
 	{
-		DESTROY_IF(me);
-		me = hydra->kernel_interface->get_source_addr(
-									hydra->kernel_interface, other, NULL);
-		if (!me)
+		me = ike_cfg->resolve_me(ike_cfg, other->get_family(other));
+		if (!me || me->is_anyaddr(me))
 		{
-			DBG1(DBG_CFG, "installing trap failed, local address unknown");
-			other->destroy(other);
-			return 0;
+			DESTROY_IF(me);
+			me = hydra->kernel_interface->get_source_addr(
+										hydra->kernel_interface, other, NULL);
+			if (!me)
+			{
+				DBG1(DBG_CFG, "installing trap failed, local address unknown");
+				other->destroy(other);
+				return 0;
+			}
+			me->set_port(me, ike_cfg->get_my_port(ike_cfg));
 		}
-		me->set_port(me, ike_cfg->get_my_port(ike_cfg));
 	}
 
 	this->lock->write_lock(this->lock);
+	if (this->installing == INSTALL_DISABLED)
+	{	/* flush() has been called */
+		this->lock->unlock(this->lock);
+		me->destroy(me);
+		return 0;
+	}
 	enumerator = this->traps->create_enumerator(this->traps);
 	while (enumerator->enumerate(enumerator, &entry))
 	{
@@ -160,6 +235,7 @@ METHOD(trap_manager_t, install, u_int32_t,
 		{
 			DBG1(DBG_CFG, "CHILD_SA '%s' is already being routed", found->name);
 			this->lock->unlock(this->lock);
+			me->destroy(me);
 			return 0;
 		}
 		/* config might have changed so update everything */
@@ -170,8 +246,10 @@ METHOD(trap_manager_t, install, u_int32_t,
 	INIT(entry,
 		.name = strdup(child->get_name(child)),
 		.peer_cfg = peer->get_ref(peer),
+		.wildcard = wildcard,
 	);
 	this->traps->insert_first(this->traps, entry);
+	this->installing++;
 	/* don't hold lock while creating CHILD_SA and installing policies */
 	this->lock->unlock(this->lock);
 
@@ -220,6 +298,11 @@ METHOD(trap_manager_t, install, u_int32_t,
 	{
 		destroy_entry(found);
 	}
+	this->lock->write_lock(this->lock);
+	/* do this at the end, so entries created temporarily are also destroyed */
+	this->installing--;
+	this->condvar->signal(this->condvar);
+	this->lock->unlock(this->lock);
 	return reqid;
 }
 
@@ -314,9 +397,12 @@ METHOD(trap_manager_t, acquire, void,
 {
 	enumerator_t *enumerator;
 	entry_t *entry, *found = NULL;
+	acquire_t *acquire;
 	peer_cfg_t *peer;
 	child_cfg_t *child;
 	ike_sa_t *ike_sa;
+	host_t *host;
+	bool wildcard, ignore = FALSE;
 
 	this->lock->read_lock(this->lock);
 	enumerator = this->traps->create_enumerator(this->traps);
@@ -333,11 +419,52 @@ METHOD(trap_manager_t, acquire, void,
 
 	if (!found)
 	{
-		DBG1(DBG_CFG, "trap not found, unable to acquire reqid %d",reqid);
+		DBG1(DBG_CFG, "trap not found, unable to acquire reqid %d", reqid);
 		this->lock->unlock(this->lock);
 		return;
 	}
-	if (!cas_bool(&found->pending, FALSE, TRUE))
+	reqid = found->child_sa->get_reqid(found->child_sa);
+	wildcard = found->wildcard;
+
+	this->mutex->lock(this->mutex);
+	if (wildcard)
+	{	/* for wildcard acquires we check that we don't have a pending acquire
+		 * with the same peer */
+		u_int8_t mask;
+
+		dst->to_subnet(dst, &host, &mask);
+		if (this->acquires->find_first(this->acquires, (void*)acquire_by_dst,
+									  (void**)&acquire, host) == SUCCESS)
+		{
+			host->destroy(host);
+			ignore = TRUE;
+		}
+		else
+		{
+			INIT(acquire,
+				.dst = host,
+				.reqid = reqid,
+			);
+			this->acquires->insert_last(this->acquires, acquire);
+		}
+	}
+	else
+	{
+		if (this->acquires->find_first(this->acquires, (void*)acquire_by_reqid,
+									  (void**)&acquire, &reqid) == SUCCESS)
+		{
+			ignore = TRUE;
+		}
+		else
+		{
+			INIT(acquire,
+				.reqid = reqid,
+			);
+			this->acquires->insert_last(this->acquires, acquire);
+		}
+	}
+	this->mutex->unlock(this->mutex);
+	if (ignore)
 	{
 		DBG1(DBG_CFG, "ignoring acquire, connection attempt pending");
 		this->lock->unlock(this->lock);
@@ -346,12 +473,40 @@ METHOD(trap_manager_t, acquire, void,
 	peer = found->peer_cfg->get_ref(found->peer_cfg);
 	child = found->child_sa->get_config(found->child_sa);
 	child = child->get_ref(child);
-	reqid = found->child_sa->get_reqid(found->child_sa);
 	/* don't hold the lock while checking out the IKE_SA */
 	this->lock->unlock(this->lock);
 
-	ike_sa = charon->ike_sa_manager->checkout_by_config(
+	if (wildcard)
+	{	/* the peer config would match IKE_SAs with other peers */
+		ike_sa = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager,
+											peer->get_ike_version(peer), TRUE);
+		if (ike_sa)
+		{
+			ike_cfg_t *ike_cfg;
+			u_int16_t port;
+			u_int8_t mask;
+
+			ike_sa->set_peer_cfg(ike_sa, peer);
+			ike_cfg = ike_sa->get_ike_cfg(ike_sa);
+
+			port = ike_cfg->get_other_port(ike_cfg);
+			dst->to_subnet(dst, &host, &mask);
+			host->set_port(host, port);
+			ike_sa->set_other_host(ike_sa, host);
+
+			port = ike_cfg->get_my_port(ike_cfg);
+			src->to_subnet(src, &host, &mask);
+			host->set_port(host, port);
+			ike_sa->set_my_host(ike_sa, host);
+
+			charon->bus->set_sa(charon->bus, ike_sa);
+		}
+	}
+	else
+	{
+		ike_sa = charon->ike_sa_manager->checkout_by_config(
 											charon->ike_sa_manager, peer);
+	}
 	if (ike_sa)
 	{
 		if (ike_sa->get_peer_cfg(ike_sa) == NULL)
@@ -363,24 +518,29 @@ METHOD(trap_manager_t, acquire, void,
 			 * have a single TS that we can establish in a Quick Mode. */
 			src = dst = NULL;
 		}
+
+		this->mutex->lock(this->mutex);
+		acquire->ike_sa = ike_sa;
+		this->mutex->unlock(this->mutex);
+
 		if (ike_sa->initiate(ike_sa, child, reqid, src, dst) != DESTROY_ME)
 		{
-			/* make sure the entry is still there */
-			this->lock->read_lock(this->lock);
-			if (this->traps->find_first(this->traps, NULL,
-										(void**)&found) == SUCCESS)
-			{
-				found->ike_sa = ike_sa;
-			}
-			this->lock->unlock(this->lock);
 			charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
 		}
 		else
 		{
-			ike_sa->destroy(ike_sa);
-			charon->bus->set_sa(charon->bus, NULL);
+			charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
+														ike_sa);
 		}
 	}
+	else
+	{
+		this->mutex->lock(this->mutex);
+		this->acquires->remove(this->acquires, acquire, NULL);
+		this->mutex->unlock(this->mutex);
+		destroy_acquire(acquire);
+		child->destroy(child);
+	}
 	peer->destroy(peer);
 }
 
@@ -391,26 +551,33 @@ static void complete(private_trap_manager_t *this, ike_sa_t *ike_sa,
 					 child_sa_t *child_sa)
 {
 	enumerator_t *enumerator;
-	entry_t *entry;
+	acquire_t *acquire;
 
-	this->lock->read_lock(this->lock);
-	enumerator = this->traps->create_enumerator(this->traps);
-	while (enumerator->enumerate(enumerator, &entry))
+	this->mutex->lock(this->mutex);
+	enumerator = this->acquires->create_enumerator(this->acquires);
+	while (enumerator->enumerate(enumerator, &acquire))
 	{
-		if (entry->ike_sa != ike_sa)
+		if (!acquire->ike_sa || acquire->ike_sa != ike_sa)
 		{
 			continue;
 		}
-		if (child_sa && child_sa->get_reqid(child_sa) !=
-									entry->child_sa->get_reqid(entry->child_sa))
+		if (child_sa)
 		{
-			continue;
+			if (acquire->dst)
+			{
+				/* since every wildcard acquire results in a separate IKE_SA
+				 * there is no need to compare the destination address */
+			}
+			else if (child_sa->get_reqid(child_sa) != acquire->reqid)
+			{
+				continue;
+			}
 		}
-		entry->ike_sa = NULL;
-		entry->pending = FALSE;
+		this->acquires->remove_at(this->acquires, enumerator);
+		destroy_acquire(acquire);
 	}
 	enumerator->destroy(enumerator);
-	this->lock->unlock(this->lock);
+	this->mutex->unlock(this->mutex);
 }
 
 METHOD(listener_t, ike_state_change, bool,
@@ -444,14 +611,15 @@ METHOD(listener_t, child_state_change, bool,
 METHOD(trap_manager_t, flush, void,
 	private_trap_manager_t *this)
 {
-	linked_list_t *traps;
-	/* since destroying the CHILD_SA results in events which require a read
-	 * lock we cannot destroy the list while holding the write lock */
 	this->lock->write_lock(this->lock);
-	traps = this->traps;
+	while (this->installing)
+	{
+		this->condvar->wait(this->condvar, this->lock);
+	}
+	this->traps->destroy_function(this->traps, (void*)destroy_entry);
 	this->traps = linked_list_create();
+	this->installing = INSTALL_DISABLED;
 	this->lock->unlock(this->lock);
-	traps->destroy_function(traps, (void*)destroy_entry);
 }
 
 METHOD(trap_manager_t, destroy, void,
@@ -459,6 +627,9 @@ METHOD(trap_manager_t, destroy, void,
 {
 	charon->bus->remove_listener(charon->bus, &this->listener.listener);
 	this->traps->destroy_function(this->traps, (void*)destroy_entry);
+	this->acquires->destroy_function(this->acquires, (void*)destroy_acquire);
+	this->condvar->destroy(this->condvar);
+	this->mutex->destroy(this->mutex);
 	this->lock->destroy(this->lock);
 	free(this);
 }
@@ -488,7 +659,10 @@ trap_manager_t *trap_manager_create(void)
 			},
 		},
 		.traps = linked_list_create(),
+		.acquires = linked_list_create(),
+		.mutex = mutex_create(MUTEX_TYPE_DEFAULT),
 		.lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
+		.condvar = rwlock_condvar_create(),
 		.ignore_acquire_ts = lib->settings->get_bool(lib->settings,
 										"%s.ignore_acquire_ts", FALSE, lib->ns),
 	);
diff --git a/src/libcharon/tests/Makefile.am b/src/libcharon/tests/Makefile.am
index c8be285..5fd8ca2 100644
--- a/src/libcharon/tests/Makefile.am
+++ b/src/libcharon/tests/Makefile.am
@@ -3,7 +3,9 @@ TESTS = libcharon_tests
 check_PROGRAMS = $(TESTS)
 
 libcharon_tests_SOURCES = \
+  suites/test_ike_cfg.c \
   suites/test_mem_pool.c \
+  suites/test_message_chapoly.c \
   libcharon_tests.h libcharon_tests.c
 
 libcharon_tests_CFLAGS = \
@@ -11,6 +13,8 @@ libcharon_tests_CFLAGS = \
   -I$(top_srcdir)/src/libhydra \
   -I$(top_srcdir)/src/libstrongswan \
   -I$(top_srcdir)/src/libstrongswan/tests \
+  -DPLUGINDIR=\""$(abs_top_builddir)/src/libstrongswan/plugins\"" \
+  -DPLUGINS=\""${s_plugins}\"" \
   @COVERAGE_CFLAGS@
 
 libcharon_tests_LDFLAGS = @COVERAGE_LDFLAGS@
diff --git a/src/libcharon/tests/Makefile.in b/src/libcharon/tests/Makefile.in
index 7f4f4b2..910aad9 100644
--- a/src/libcharon/tests/Makefile.in
+++ b/src/libcharon/tests/Makefile.in
@@ -102,7 +102,9 @@ CONFIG_CLEAN_VPATH_FILES =
 am__EXEEXT_1 = libcharon_tests$(EXEEXT)
 am__dirstamp = $(am__leading_dot)dirstamp
 am_libcharon_tests_OBJECTS =  \
+	suites/libcharon_tests-test_ike_cfg.$(OBJEXT) \
 	suites/libcharon_tests-test_mem_pool.$(OBJEXT) \
+	suites/libcharon_tests-test_message_chapoly.$(OBJEXT) \
 	libcharon_tests-libcharon_tests.$(OBJEXT)
 libcharon_tests_OBJECTS = $(am_libcharon_tests_OBJECTS)
 libcharon_tests_DEPENDENCIES =  \
@@ -427,7 +429,9 @@ urandom_device = @urandom_device@
 xml_CFLAGS = @xml_CFLAGS@
 xml_LIBS = @xml_LIBS@
 libcharon_tests_SOURCES = \
+  suites/test_ike_cfg.c \
   suites/test_mem_pool.c \
+  suites/test_message_chapoly.c \
   libcharon_tests.h libcharon_tests.c
 
 libcharon_tests_CFLAGS = \
@@ -435,6 +439,8 @@ libcharon_tests_CFLAGS = \
   -I$(top_srcdir)/src/libhydra \
   -I$(top_srcdir)/src/libstrongswan \
   -I$(top_srcdir)/src/libstrongswan/tests \
+  -DPLUGINDIR=\""$(abs_top_builddir)/src/libstrongswan/plugins\"" \
+  -DPLUGINS=\""${s_plugins}\"" \
   @COVERAGE_CFLAGS@
 
 libcharon_tests_LDFLAGS = @COVERAGE_LDFLAGS@
@@ -493,8 +499,12 @@ suites/$(am__dirstamp):
 suites/$(DEPDIR)/$(am__dirstamp):
 	@$(MKDIR_P) suites/$(DEPDIR)
 	@: > suites/$(DEPDIR)/$(am__dirstamp)
+suites/libcharon_tests-test_ike_cfg.$(OBJEXT): suites/$(am__dirstamp) \
+	suites/$(DEPDIR)/$(am__dirstamp)
 suites/libcharon_tests-test_mem_pool.$(OBJEXT):  \
 	suites/$(am__dirstamp) suites/$(DEPDIR)/$(am__dirstamp)
+suites/libcharon_tests-test_message_chapoly.$(OBJEXT):  \
+	suites/$(am__dirstamp) suites/$(DEPDIR)/$(am__dirstamp)
 
 libcharon_tests$(EXEEXT): $(libcharon_tests_OBJECTS) $(libcharon_tests_DEPENDENCIES) $(EXTRA_libcharon_tests_DEPENDENCIES) 
 	@rm -f libcharon_tests$(EXEEXT)
@@ -508,7 +518,9 @@ distclean-compile:
 	-rm -f *.tab.c
 
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcharon_tests-libcharon_tests.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at suites/$(DEPDIR)/libcharon_tests-test_ike_cfg.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at suites/$(DEPDIR)/libcharon_tests-test_mem_pool.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at suites/$(DEPDIR)/libcharon_tests-test_message_chapoly.Po at am__quote@
 
 .c.o:
 @am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
@@ -534,6 +546,20 @@ distclean-compile:
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LTCOMPILE) -c -o $@ $<
 
+suites/libcharon_tests-test_ike_cfg.o: suites/test_ike_cfg.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcharon_tests_CFLAGS) $(CFLAGS) -MT suites/libcharon_tests-test_ike_cfg.o -MD -MP -MF suites/$(DEPDIR)/libcharon_tests-test_ike_cfg.Tpo -c -o suites/libcharon_tests-test_ike_cfg.o `test -f 'suites/test_ike_cfg.c' || echo '$(srcdir)/'`suites/test_ike_cfg.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) suites/$(DEPDIR)/libcharon_tests-test_ike_cfg.Tpo suites/$(DEPDIR)/libcharon_tests-test_ike_cfg.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='suites/test_ike_cfg.c' object='suites/libcharon_tests-test_ike_cfg.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcharon_tests_CFLAGS) $(CFLAGS) -c -o suites/libcharon_tests-test_ike_cfg.o `test -f 'suites/test_ike_cfg.c' || echo '$(srcdir)/'`suites/test_ike_cfg.c
+
+suites/libcharon_tests-test_ike_cfg.obj: suites/test_ike_cfg.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcharon_tests_CFLAGS) $(CFLAGS) -MT suites/libcharon_tests-test_ike_cfg.obj -MD -MP -MF suites/$(DEPDIR)/libcharon_tests-test_ike_cfg.Tpo -c -o suites/libcharon_tests-test_ike_cfg.obj `if test -f 'suites/test_ike_cfg.c'; then $(CYGPATH_W) 'suites/test_ike_cfg.c'; else $(CYGPATH_W) '$(srcdir)/suites/test_ike_cfg.c'; fi`
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) suites/$(DEPDIR)/libcharon_tests-test_ike_cfg.Tpo suites/$(DEPDIR)/libcharon_tests-test_ike_cfg.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='suites/test_ike_cfg.c' object='suites/libcharon_tests-test_ike_cfg.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcharon_tests_CFLAGS) $(CFLAGS) -c -o suites/libcharon_tests-test_ike_cfg.obj `if test -f 'suites/test_ike_cfg.c'; then $(CYGPATH_W) 'suites/test_ike_cfg.c'; else $(CYGPATH_W) '$(srcdir)/suites/test_ike_cfg.c'; fi`
+
 suites/libcharon_tests-test_mem_pool.o: suites/test_mem_pool.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcharon_tests_CFLAGS) $(CFLAGS) -MT suites/libcharon_tests-test_mem_pool.o -MD -MP -MF suites/$(DEPDIR)/libcharon_tests-test_mem_pool.Tpo -c -o suites/libcharon_tests-test_mem_pool.o `test -f 'suites/test_mem_pool.c' || echo '$(srcdir)/'`suites/test_mem_pool.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) suites/$(DEPDIR)/libcharon_tests-test_mem_pool.Tpo suites/$(DEPDIR)/libcharon_tests-test_mem_pool.Po
@@ -548,6 +574,20 @@ suites/libcharon_tests-test_mem_pool.obj: suites/test_mem_pool.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcharon_tests_CFLAGS) $(CFLAGS) -c -o suites/libcharon_tests-test_mem_pool.obj `if test -f 'suites/test_mem_pool.c'; then $(CYGPATH_W) 'suites/test_mem_pool.c'; else $(CYGPATH_W) '$(srcdir)/suites/test_mem_pool.c'; fi`
 
+suites/libcharon_tests-test_message_chapoly.o: suites/test_message_chapoly.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcharon_tests_CFLAGS) $(CFLAGS) -MT suites/libcharon_tests-test_message_chapoly.o -MD -MP -MF suites/$(DEPDIR)/libcharon_tests-test_message_chapoly.Tpo -c -o suites/libcharon_tests-test_message_chapoly.o `test -f 'suites/test_message_chapoly.c' || echo '$(srcdir)/'`suites/test_message_chapoly.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) suites/$(DEPDIR)/libcharon_tests-test_message_chapoly.Tpo suites/$(DEPDIR)/libcharon_tests-test_message_chapoly.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='suites/test_message_chapoly.c' object='suites/libcharon_tests-test_message_chapoly.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcharon_tests_CFLAGS) $(CFLAGS) -c -o suites/libcharon_tests-test_message_chapoly.o `test -f 'suites/test_message_chapoly.c' || echo '$(srcdir)/'`suites/test_message_chapoly.c
+
+suites/libcharon_tests-test_message_chapoly.obj: suites/test_message_chapoly.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcharon_tests_CFLAGS) $(CFLAGS) -MT suites/libcharon_tests-test_message_chapoly.obj -MD -MP -MF suites/$(DEPDIR)/libcharon_tests-test_message_chapoly.Tpo -c -o suites/libcharon_tests-test_message_chapoly.obj `if test -f 'suites/test_message_chapoly.c'; then $(CYGPATH_W) 'suites/test_message_chapoly.c'; else $(CYGPATH_W) '$(srcdir)/suites/test_message_chapoly.c'; fi`
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) suites/$(DEPDIR)/libcharon_tests-test_message_chapoly.Tpo suites/$(DEPDIR)/libcharon_tests-test_message_chapoly.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='suites/test_message_chapoly.c' object='suites/libcharon_tests-test_message_chapoly.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcharon_tests_CFLAGS) $(CFLAGS) -c -o suites/libcharon_tests-test_message_chapoly.obj `if test -f 'suites/test_message_chapoly.c'; then $(CYGPATH_W) 'suites/test_message_chapoly.c'; else $(CYGPATH_W) '$(srcdir)/suites/test_message_chapoly.c'; fi`
+
 libcharon_tests-libcharon_tests.o: libcharon_tests.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcharon_tests_CFLAGS) $(CFLAGS) -MT libcharon_tests-libcharon_tests.o -MD -MP -MF $(DEPDIR)/libcharon_tests-libcharon_tests.Tpo -c -o libcharon_tests-libcharon_tests.o `test -f 'libcharon_tests.c' || echo '$(srcdir)/'`libcharon_tests.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcharon_tests-libcharon_tests.Tpo $(DEPDIR)/libcharon_tests-libcharon_tests.Po
diff --git a/src/libcharon/tests/libcharon_tests.c b/src/libcharon/tests/libcharon_tests.c
index 1ed0f0c..ec96de7 100644
--- a/src/libcharon/tests/libcharon_tests.c
+++ b/src/libcharon/tests/libcharon_tests.c
@@ -27,8 +27,8 @@
 static test_configuration_t tests[] = {
 #define TEST_SUITE(x) \
 	{ .suite = x, },
-#define TEST_SUITE_DEPEND(x, type, args) \
-	{ .suite = x, .feature = PLUGIN_DEPENDS(type, args) },
+#define TEST_SUITE_DEPEND(x, type, ...) \
+	{ .suite = x, .feature = PLUGIN_DEPENDS(type, __VA_ARGS__) },
 #include "libcharon_tests.h"
 	{ .suite = NULL, }
 };
@@ -37,13 +37,27 @@ static bool test_runner_init(bool init)
 {
 	if (init)
 	{
+		char *plugins, *plugindir;
+
 		libhydra_init();
 		libcharon_init();
+
+		plugins = getenv("TESTS_PLUGINS") ?:
+					lib->settings->get_str(lib->settings,
+										"tests.load", PLUGINS);
+		plugindir = lib->settings->get_str(lib->settings,
+										"tests.plugindir", PLUGINDIR);
+		plugin_loader_add_plugindirs(plugindir, plugins);
+		if (!lib->plugins->load(lib->plugins, plugins))
+		{
+			return FALSE;
+		}
 	}
 	else
 	{
 		lib->processor->set_threads(lib->processor, 0);
 		lib->processor->cancel(lib->processor);
+		lib->plugins->unload(lib->plugins);
 		libcharon_deinit();
 		libhydra_deinit();
 	}
diff --git a/src/libcharon/tests/libcharon_tests.h b/src/libcharon/tests/libcharon_tests.h
index dc9681a..fb82bac 100644
--- a/src/libcharon/tests/libcharon_tests.h
+++ b/src/libcharon/tests/libcharon_tests.h
@@ -13,4 +13,6 @@
  * for more details.
  */
 
+TEST_SUITE(ike_cfg_suite_create)
 TEST_SUITE(mem_pool_suite_create)
+TEST_SUITE_DEPEND(message_chapoly_suite_create, AEAD, ENCR_CHACHA20_POLY1305, 32)
diff --git a/src/libcharon/tests/suites/test_ike_cfg.c b/src/libcharon/tests/suites/test_ike_cfg.c
new file mode 100644
index 0000000..8062179
--- /dev/null
+++ b/src/libcharon/tests/suites/test_ike_cfg.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2015 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include "test_suite.h"
+
+#include <config/ike_cfg.h>
+
+static void assert_family(int expected, char *addr, bool local)
+{
+	ike_cfg_t *cfg;
+	int family;
+
+	cfg = ike_cfg_create(IKEV2, FALSE, FALSE, local ? addr : "%any", 500,
+						 local ? "%any" : addr, 500, FRAGMENTATION_NO, 0);
+	family = ike_cfg_get_family(cfg, local);
+	ck_assert_msg(expected == family, "expected family %d != %d (addr: '%s')",
+				  expected, family, addr);
+	cfg->destroy(cfg);
+}
+
+START_TEST(test_get_address_family_empty)
+{
+	assert_family(AF_UNSPEC, "", _i);
+}
+END_TEST
+
+START_TEST(test_get_address_family_addr)
+{
+	assert_family(AF_INET, "192.168.1.1", _i);
+	assert_family(AF_INET6, "fec::1", _i);
+}
+END_TEST
+
+START_TEST(test_get_address_family_multi)
+{
+	assert_family(AF_INET, "192.168.1.1,192.168.2.2", _i);
+	assert_family(AF_INET6, "fec::1,fec::2", _i);
+
+	assert_family(AF_UNSPEC, "192.168.1.1,fec::1", _i);
+	assert_family(AF_UNSPEC, "fec::1,192.168.1.1", _i);
+}
+END_TEST
+
+START_TEST(test_get_address_family_any)
+{
+	assert_family(AF_UNSPEC, "%any", _i);
+
+	assert_family(AF_INET, "%any4", _i);
+	assert_family(AF_INET, "0.0.0.0", _i);
+
+	assert_family(AF_INET6, "%any6", _i);
+	assert_family(AF_INET6, "::", _i);
+
+	assert_family(AF_INET, "192.168.1.1,%any", _i);
+	assert_family(AF_INET, "192.168.1.1,%any4", _i);
+	assert_family(AF_UNSPEC, "192.168.1.1,%any6", _i);
+
+	assert_family(AF_INET6, "fec::1,%any", _i);
+	assert_family(AF_UNSPEC, "fec::1,%any4", _i);
+	assert_family(AF_INET6, "fec::1,%any6", _i);
+}
+END_TEST
+
+START_TEST(test_get_address_family_other)
+{
+	assert_family(AF_INET, "192.168.1.0", _i);
+	assert_family(AF_UNSPEC, "192.168.1.0/24", _i);
+	assert_family(AF_UNSPEC, "192.168.1.0-192.168.1.10", _i);
+
+	assert_family(AF_INET, "192.168.1.0/24,192.168.2.1", _i);
+	assert_family(AF_INET, "192.168.1.0-192.168.1.10,192.168.2.1", _i);
+	assert_family(AF_INET6, "192.168.1.0/24,fec::1", _i);
+	assert_family(AF_INET6, "192.168.1.0-192.168.1.10,fec::1", _i);
+
+	assert_family(AF_INET6, "fec::", _i);
+	assert_family(AF_UNSPEC, "fec::/64", _i);
+	assert_family(AF_UNSPEC, "fec::1-fec::10", _i);
+
+	assert_family(AF_INET6, "fec::/64,fed::1", _i);
+	assert_family(AF_INET6, "fec::1-fec::10,fec::1", _i);
+	assert_family(AF_INET, "fec::/64,192.168.1.1", _i);
+	assert_family(AF_INET, "fec::1-fec::10,192.168.1.1", _i);
+
+	assert_family(AF_UNSPEC, "strongswan.org", _i);
+	assert_family(AF_INET, "192.168.1.0,strongswan.org", _i);
+	assert_family(AF_INET6, "fec::1,strongswan.org", _i);
+}
+END_TEST
+
+Suite *ike_cfg_suite_create()
+{
+	Suite *s;
+	TCase *tc;
+
+	s = suite_create("ike_cfg");
+
+	tc = tcase_create("ike_cfg_get_address_family");
+	tcase_add_loop_test(tc, test_get_address_family_empty, 0, 2);
+	tcase_add_loop_test(tc, test_get_address_family_addr, 0, 2);
+	tcase_add_loop_test(tc, test_get_address_family_multi, 0, 2);
+	tcase_add_loop_test(tc, test_get_address_family_any, 0, 2);
+	tcase_add_loop_test(tc, test_get_address_family_other, 0, 2);
+	suite_add_tcase(s, tc);
+
+	return s;
+}
diff --git a/src/libcharon/tests/suites/test_message_chapoly.c b/src/libcharon/tests/suites/test_message_chapoly.c
new file mode 100644
index 0000000..e871cf6
--- /dev/null
+++ b/src/libcharon/tests/suites/test_message_chapoly.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2015 Martin Willi
+ * Copyright (C) 2015 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include "test_suite.h"
+
+#include <encoding/message.h>
+
+static aead_t *aead;
+
+static iv_gen_t *ivgen;
+
+METHOD(keymat_t, get_version, ike_version_t,
+	keymat_t *this)
+{
+	return IKEV2;
+}
+
+METHOD(keymat_t, get_aead, aead_t*,
+	keymat_t *this, bool in)
+{
+	return aead;
+}
+
+METHOD(aead_t, get_iv_gen, iv_gen_t*,
+	aead_t *this)
+{
+	return ivgen;
+}
+
+METHOD(iv_gen_t, get_iv, bool,
+	iv_gen_t *this, u_int64_t seq, size_t size, u_int8_t *buffer)
+{
+	if (size != 8)
+	{
+		return FALSE;
+	}
+	memcpy(buffer, "\x10\x11\x12\x13\x14\x15\x16\x17", 8);
+	return TRUE;
+}
+
+METHOD(iv_gen_t, allocate_iv, bool,
+	iv_gen_t *this, u_int64_t seq, size_t size, chunk_t *chunk)
+{
+	if (size != 8)
+	{
+		return FALSE;
+	}
+	*chunk = chunk_alloc(size);
+	return get_iv(this, seq, chunk->len, chunk->ptr);
+}
+
+/**
+ * Appendix B draft-ietf-ipsecme-chacha20-poly1305-06
+ */
+START_TEST(test_chacha20poly1305)
+{
+	u_int64_t spii, spir;
+	ike_sa_id_t *id;
+	message_t *m;
+	u_int32_t window = htonl(10);
+	chunk_t chunk, exp;
+	keymat_t keymat = {
+		.get_version = _get_version,
+		.create_dh = (void*)return_null,
+		.create_nonce_gen = (void*)return_null,
+		.get_aead = _get_aead,
+	};
+
+	m = message_create(IKEV2, 0);
+	m->set_exchange_type(m, INFORMATIONAL);
+	htoun64(&spii, 0xc0c1c2c3c4c5c6c7);
+	htoun64(&spir, 0xd0d1d2d3d4d5d6d7);
+	id = ike_sa_id_create(IKEV2, spii, spir, FALSE);
+	m->set_ike_sa_id(m, id);
+	id->destroy(id);
+	m->set_source(m, host_create_from_string("1.2.3.4", 4500));
+	m->set_destination(m, host_create_from_string("4.3.2.1", 4500));
+	m->set_message_id(m, 9);
+	m->add_notify(m, TRUE, SET_WINDOW_SIZE, chunk_from_thing(window));
+
+	aead = lib->crypto->create_aead(lib->crypto, ENCR_CHACHA20_POLY1305, 32, 4);
+	ck_assert(aead);
+	ck_assert(aead->set_key(aead, chunk_from_chars(
+									0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,
+									0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+									0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,
+									0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
+									0xa0,0xa1,0xa2,0xa3)));
+	INIT(ivgen,
+		.get_iv = _get_iv,
+		.allocate_iv = _allocate_iv,
+		.destroy = (void*)free,
+	);
+	aead->get_iv_gen = _get_iv_gen,
+
+	ck_assert(m->generate(m, &keymat, NULL) == SUCCESS);
+	chunk = m->get_packet_data(m);
+	exp = chunk_from_chars(0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,
+						   0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,
+						   0x2e,0x20,0x25,0x00,0x00,0x00,0x00,0x09,
+						   0x00,0x00,0x00,0x45,0x29,0x00,0x00,0x29,
+						   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
+						   0x61,0x03,0x94,0x70,0x1f,0x8d,0x01,0x7f,
+						   0x7c,0x12,0x92,0x48,0x89,0x6b,0x71,0xbf,
+						   0xe2,0x52,0x36,0xef,0xd7,0xcd,0xc6,0x70,
+						   0x66,0x90,0x63,0x15,0xb2);
+	ck_assert_msg(chunk_equals(chunk, exp), "got %B\nexp %B", &chunk, &exp);
+	ivgen->destroy(ivgen);
+	aead->destroy(aead);
+	m->destroy(m);
+}
+END_TEST
+
+Suite *message_chapoly_suite_create()
+{
+	Suite *s;
+	TCase *tc;
+
+	s = suite_create("chapoly");
+
+	tc = tcase_create("ChaCha20Poly1305 IKEv2 encryption");
+	tcase_add_test(tc, test_chacha20poly1305);
+	suite_add_tcase(s, tc);
+
+	return s;
+}
diff --git a/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c
index f22e07d..605476e 100644
--- a/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c
+++ b/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c
@@ -199,6 +199,7 @@ static kernel_algorithm_t encryption_algs[] = {
 /*	{ENCR_CAMELLIA_CCM_ICV16,	"***"				}, */
 	{ENCR_SERPENT_CBC,			"serpent"			},
 	{ENCR_TWOFISH_CBC,			"twofish"			},
+	{ENCR_CHACHA20_POLY1305,	"rfc7539esp(chacha20,poly1305)"},
 };
 
 /**
@@ -734,6 +735,7 @@ static struct xfrm_selector ts2selector(traffic_selector_t *src,
 										traffic_selector_t *dst)
 {
 	struct xfrm_selector sel;
+	u_int16_t port;
 
 	memset(&sel, 0, sizeof(sel));
 	sel.family = (src->get_type(src) == TS_IPV4_ADDR_RANGE) ? AF_INET : AF_INET6;
@@ -746,13 +748,13 @@ static struct xfrm_selector ts2selector(traffic_selector_t *src,
 	if ((sel.proto == IPPROTO_ICMP || sel.proto == IPPROTO_ICMPV6) &&
 		(sel.dport || sel.sport))
 	{
-		/* the ICMP type is encoded in the most significant 8 bits and the ICMP
-		 * code in the least significant 8 bits of the port.  via XFRM we have
-		 * to pass the ICMP type and code in the source and destination port
-		 * fields, respectively.  the port is in network byte order. */
-		u_int16_t port = max(sel.dport, sel.sport);
-		sel.sport = htons(port & 0xff);
-		sel.dport = htons(port >> 8);
+		/* the kernel expects the ICMP type and code in the source and
+		 * destination port fields, respectively. */
+		port = ntohs(max(sel.dport, sel.sport));
+		sel.sport = htons(traffic_selector_icmp_type(port));
+		sel.sport_mask = sel.sport ? ~0 : 0;
+		sel.dport = htons(traffic_selector_icmp_code(port));
+		sel.dport_mask = sel.dport ? ~0 : 0;
 	}
 	sel.ifindex = 0;
 	sel.user = 0;
@@ -1291,6 +1293,7 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
 		case ENCR_AES_GCM_ICV16:
 		case ENCR_NULL_AUTH_AES_GMAC:
 		case ENCR_CAMELLIA_CCM_ICV16:
+		case ENCR_CHACHA20_POLY1305:
 			icv_size += 32;
 			/* FALL */
 		case ENCR_AES_CCM_ICV12:
@@ -2022,23 +2025,36 @@ METHOD(kernel_ipsec_t, flush_sas, status_t,
 	netlink_buf_t request;
 	struct nlmsghdr *hdr;
 	struct xfrm_usersa_flush *flush;
+	struct {
+		u_int8_t proto;
+		char *name;
+	} protos[] = {
+		{ IPPROTO_AH, "AH" },
+		{ IPPROTO_ESP, "ESP" },
+		{ IPPROTO_COMP, "IPComp" },
+	};
+	int i;
 
 	memset(&request, 0, sizeof(request));
 
-	DBG2(DBG_KNL, "flushing all SAD entries");
-
 	hdr = &request.hdr;
 	hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
 	hdr->nlmsg_type = XFRM_MSG_FLUSHSA;
 	hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_flush));
 
 	flush = NLMSG_DATA(hdr);
-	flush->proto = IPSEC_PROTO_ANY;
 
-	if (this->socket_xfrm->send_ack(this->socket_xfrm, hdr) != SUCCESS)
+	for (i = 0; i < countof(protos); i++)
 	{
-		DBG1(DBG_KNL, "unable to flush SAD entries");
-		return FAILED;
+		DBG2(DBG_KNL, "flushing all %s SAD entries", protos[i].name);
+
+		flush->proto = protos[i].proto;
+
+		if (this->socket_xfrm->send_ack(this->socket_xfrm, hdr) != SUCCESS)
+		{
+			DBG1(DBG_KNL, "unable to flush %s SAD entries", protos[i].name);
+			return FAILED;
+		}
 	}
 	return SUCCESS;
 }
@@ -2057,6 +2073,7 @@ static status_t add_policy_internal(private_kernel_netlink_ipsec_t *this,
 	ipsec_sa_t *ipsec = mapping->sa;
 	struct xfrm_userpolicy_info *policy_info;
 	struct nlmsghdr *hdr;
+	status_t status;
 	int i;
 
 	/* clone the policy so we are able to check it out again later */
@@ -2151,7 +2168,14 @@ static status_t add_policy_internal(private_kernel_netlink_ipsec_t *this,
 	}
 	this->mutex->unlock(this->mutex);
 
-	if (this->socket_xfrm->send_ack(this->socket_xfrm, hdr) != SUCCESS)
+	status = this->socket_xfrm->send_ack(this->socket_xfrm, hdr);
+	if (status == ALREADY_DONE && !update)
+	{
+		DBG1(DBG_KNL, "policy already exists, try to update it");
+		hdr->nlmsg_type = XFRM_MSG_UPDPOLICY;
+		status = this->socket_xfrm->send_ack(this->socket_xfrm, hdr);
+	}
+	if (status != SUCCESS)
 	{
 		return FAILED;
 	}
@@ -2560,6 +2584,7 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
 
 	if (!add_mark(hdr, sizeof(request), mark))
 	{
+		this->mutex->unlock(this->mutex);
 		return FAILED;
 	}
 
diff --git a/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c b/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c
index 1515b01..4e5e02d 100644
--- a/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c
+++ b/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c
@@ -491,6 +491,16 @@ struct private_kernel_netlink_net_t {
 	bool rta_prefsrc_for_ipv6;
 
 	/**
+	 * whether marks can be used in route lookups
+	 */
+	bool rta_mark;
+
+	/**
+	 * the mark excluded from the routing rule used for virtual IPs
+	 */
+	mark_t routing_mark;
+
+	/**
 	 * whether to prefer temporary IPv6 addresses over public ones
 	 */
 	bool prefer_temporary_addrs;
@@ -1676,18 +1686,25 @@ static host_t *get_route(private_kernel_netlink_net_t *this, host_t *dest,
 	family = dest->get_family(dest);
 	hdr = &request.hdr;
 	hdr->nlmsg_flags = NLM_F_REQUEST;
-	if (family == AF_INET || this->rta_prefsrc_for_ipv6 ||
-		this->routing_table || match_net)
-	{	/* kernels prior to 3.0 do not support RTA_PREFSRC for IPv6 routes.
-		 * as we want to ignore routes with virtual IPs we cannot use DUMP
-		 * if these routes are not installed in a separate table */
-		hdr->nlmsg_flags |= NLM_F_DUMP;
-	}
 	hdr->nlmsg_type = RTM_GETROUTE;
 	hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
 
 	msg = NLMSG_DATA(hdr);
 	msg->rtm_family = family;
+	if (!match_net && this->rta_mark && this->routing_mark.value)
+	{
+		/* if our routing rule excludes packets with a certain mark we can
+		 * get the preferred route without having to dump all routes */
+		chunk = chunk_from_thing(this->routing_mark.value);
+		netlink_add_attribute(hdr, RTA_MARK, chunk, sizeof(request));
+	}
+	else if (family == AF_INET || this->rta_prefsrc_for_ipv6 ||
+			 this->routing_table || match_net)
+	{	/* kernels prior to 3.0 do not support RTA_PREFSRC for IPv6 routes.
+		 * as we want to ignore routes with virtual IPs we cannot use DUMP
+		 * if these routes are not installed in a separate table */
+		hdr->nlmsg_flags |= NLM_F_DUMP;
+	}
 	if (candidate)
 	{
 		chunk = candidate->get_address(candidate);
@@ -2412,6 +2429,10 @@ static status_t manage_rule(private_kernel_netlink_net_t *this, int nlmsg_type,
 			netlink_add_attribute(hdr, FRA_FWMARK, chunk, sizeof(request));
 			chunk = chunk_from_thing(mark.mask);
 			netlink_add_attribute(hdr, FRA_FWMASK, chunk, sizeof(request));
+			if (msg->rtm_flags & FIB_RULE_INVERT)
+			{
+				this->routing_mark = mark;
+			}
 		}
 #else
 		DBG1(DBG_KNL, "setting firewall mark on routing rule is not supported");
@@ -2435,6 +2456,10 @@ static void check_kernel_features(private_kernel_netlink_net_t *this)
 			case 3:
 				if (a == 2)
 				{
+					if (b == 6 && c >= 36)
+					{
+						this->rta_mark = TRUE;
+					}
 					DBG2(DBG_KNL, "detected Linux %d.%d.%d, no support for "
 						 "RTA_PREFSRC for IPv6 routes", a, b, c);
 					break;
@@ -2443,6 +2468,7 @@ static void check_kernel_features(private_kernel_netlink_net_t *this)
 			case 2:
 				/* only 3.x+ uses two part version numbers */
 				this->rta_prefsrc_for_ipv6 = TRUE;
+				this->rta_mark = TRUE;
 				break;
 			default:
 				break;
diff --git a/src/libhydra/plugins/kernel_netlink/kernel_netlink_shared.c b/src/libhydra/plugins/kernel_netlink/kernel_netlink_shared.c
index b0e3103..f7ce992 100644
--- a/src/libhydra/plugins/kernel_netlink/kernel_netlink_shared.c
+++ b/src/libhydra/plugins/kernel_netlink/kernel_netlink_shared.c
@@ -185,8 +185,8 @@ static ssize_t read_msg(private_netlink_socket_t *this,
 			return -1;
 		}
 	}
-	len = recv(this->socket, buf, buflen, block ? 0 : MSG_DONTWAIT);
-	if (len == buflen)
+	len = recv(this->socket, buf, buflen, MSG_TRUNC|(block ? 0 : MSG_DONTWAIT));
+	if (len > buflen)
 	{
 		DBG1(DBG_KNL, "netlink response exceeds buffer size");
 		return 0;
@@ -571,7 +571,7 @@ netlink_socket_t *netlink_socket_create(int protocol, enum_name_t *names,
 		.protocol = protocol,
 		.names = names,
 		.buflen = lib->settings->get_int(lib->settings,
-							"%s.plugins.kernel-netlink.buflen", 4096, lib->ns),
+							"%s.plugins.kernel-netlink.buflen", 0, lib->ns),
 		.timeout = lib->settings->get_int(lib->settings,
 							"%s.plugins.kernel-netlink.timeout", 0, lib->ns),
 		.retries = lib->settings->get_int(lib->settings,
@@ -582,6 +582,16 @@ netlink_socket_t *netlink_socket_create(int protocol, enum_name_t *names,
 		.parallel = parallel,
 	);
 
+	if (!this->buflen)
+	{
+		long pagesize = sysconf(_SC_PAGESIZE);
+		if (pagesize == -1)
+		{
+			pagesize = 4096;
+		}
+		/* base this on NLMSG_GOODSIZE */
+		this->buflen = min(pagesize, 8192);
+	}
 	if (this->socket == -1)
 	{
 		DBG1(DBG_KNL, "unable to create netlink socket");
diff --git a/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c b/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c
index 3b32ba5..5027e17 100644
--- a/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c
+++ b/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c
@@ -106,6 +106,12 @@
 #define SADB_X_EALG_CASTCBC SADB_X_EALG_CAST128CBC
 #endif
 
+#if !defined(SADB_X_EALG_AES_GCM_ICV8) && defined(SADB_X_EALG_AESGCM8)
+#define SADB_X_EALG_AES_GCM_ICV8 SADB_X_EALG_AESGCM8
+#define SADB_X_EALG_AES_GCM_ICV12 SADB_X_EALG_AESGCM12
+#define SADB_X_EALG_AES_GCM_ICV16 SADB_X_EALG_AESGCM16
+#endif
+
 #ifndef SOL_IP
 #define SOL_IP IPPROTO_IP
 #define SOL_IPV6 IPPROTO_IPV6
@@ -508,15 +514,30 @@ static policy_entry_t *create_policy_entry(traffic_selector_t *src_ts,
 	INIT(policy,
 		.direction = dir,
 	);
+	u_int16_t port;
+	u_int8_t proto;
 
 	src_ts->to_subnet(src_ts, &policy->src.net, &policy->src.mask);
 	dst_ts->to_subnet(dst_ts, &policy->dst.net, &policy->dst.mask);
 
 	/* src or dest proto may be "any" (0), use more restrictive one */
-	policy->src.proto = max(src_ts->get_protocol(src_ts),
-							dst_ts->get_protocol(dst_ts));
-	policy->src.proto = policy->src.proto ? policy->src.proto : IPSEC_PROTO_ANY;
-	policy->dst.proto = policy->src.proto;
+	proto = max(src_ts->get_protocol(src_ts), dst_ts->get_protocol(dst_ts));
+	/* map the ports to ICMP type/code how the Linux kernel expects them, that
+	 * is, type in src, code in dst */
+	if (proto == IPPROTO_ICMP || proto == IPPROTO_ICMPV6)
+	{
+		port = max(policy->src.net->get_port(policy->src.net),
+				   policy->dst.net->get_port(policy->dst.net));
+		policy->src.net->set_port(policy->src.net,
+								  traffic_selector_icmp_type(port));
+		policy->dst.net->set_port(policy->dst.net,
+								  traffic_selector_icmp_code(port));
+	}
+	else if (!proto)
+	{
+		proto = IPSEC_PROTO_ANY;
+	}
+	policy->src.proto = policy->dst.proto = proto;
 
 	return policy;
 }
@@ -826,9 +847,11 @@ static kernel_algorithm_t encryption_algs[] = {
 /*  {ENCR_AES_CCM_ICV8,			SADB_X_EALG_AES_CCM_ICV8	}, */
 /*	{ENCR_AES_CCM_ICV12,		SADB_X_EALG_AES_CCM_ICV12	}, */
 /*	{ENCR_AES_CCM_ICV16,		SADB_X_EALG_AES_CCM_ICV16	}, */
-/*	{ENCR_AES_GCM_ICV8,			SADB_X_EALG_AES_GCM_ICV8	}, */
-/*	{ENCR_AES_GCM_ICV12,		SADB_X_EALG_AES_GCM_ICV12	}, */
-/*	{ENCR_AES_GCM_ICV16,		SADB_X_EALG_AES_GCM_ICV16	}, */
+#ifdef SADB_X_EALG_AES_GCM_ICV8 /* assume the others are defined too */
+	{ENCR_AES_GCM_ICV8,			SADB_X_EALG_AES_GCM_ICV8	},
+	{ENCR_AES_GCM_ICV12,		SADB_X_EALG_AES_GCM_ICV12	},
+	{ENCR_AES_GCM_ICV16,		SADB_X_EALG_AES_GCM_ICV16	},
+#endif
 	{END_OF_LIST,				0							},
 };
 
@@ -942,28 +965,6 @@ static size_t hostcpy(void *dest, host_t *host, bool include_port)
 }
 
 /**
- * Copy a host_t as sockaddr_t to the given memory location and map the port to
- * ICMP/ICMPv6 message type/code as the Linux kernel expects it, that is, the
- * type in the source and the code in the destination address.
- * @return		the number of bytes copied
- */
-static size_t hostcpy_icmp(void *dest, host_t *host, u_int16_t type)
-{
-	size_t len;
-
-	len = hostcpy(dest, host, TRUE);
-	if (type == SADB_EXT_ADDRESS_SRC)
-	{
-		set_port(dest, traffic_selector_icmp_type(host->get_port(host)));
-	}
-	else
-	{
-		set_port(dest, traffic_selector_icmp_code(host->get_port(host)));
-	}
-	return len;
-}
-
-/**
  * add a host to the given sadb_msg
  */
 static void add_addr_ext(struct sadb_msg *msg, host_t *host, u_int16_t type,
@@ -975,14 +976,7 @@ static void add_addr_ext(struct sadb_msg *msg, host_t *host, u_int16_t type,
 	addr->sadb_address_exttype = type;
 	addr->sadb_address_proto = proto;
 	addr->sadb_address_prefixlen = prefixlen;
-	if (proto == IPPROTO_ICMP || proto == IPPROTO_ICMPV6)
-	{
-		len = hostcpy_icmp(addr + 1, host, type);
-	}
-	else
-	{
-		len = hostcpy(addr + 1, host, include_port);
-	}
+	len = hostcpy(addr + 1, host, include_port);
 	addr->sadb_address_len = PFKEY_LEN(sizeof(*addr) + len);
 	PFKEY_EXT_ADD(msg, addr);
 }
@@ -2078,31 +2072,44 @@ METHOD(kernel_ipsec_t, flush_sas, status_t,
 {
 	unsigned char request[PFKEY_BUFFER_SIZE];
 	struct sadb_msg *msg, *out;
+	struct {
+		u_int8_t proto;
+		char *name;
+	} protos[] = {
+		{ SADB_SATYPE_AH, "AH" },
+		{ SADB_SATYPE_ESP, "ESP" },
+		{ SADB_X_SATYPE_IPCOMP, "IPComp" },
+	};
 	size_t len;
+	int i;
 
 	memset(&request, 0, sizeof(request));
 
-	DBG2(DBG_KNL, "flushing all SAD entries");
-
 	msg = (struct sadb_msg*)request;
 	msg->sadb_msg_version = PF_KEY_V2;
 	msg->sadb_msg_type = SADB_FLUSH;
-	msg->sadb_msg_satype = SADB_SATYPE_UNSPEC;
 	msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg));
 
-	if (pfkey_send(this, msg, &out, &len) != SUCCESS)
-	{
-		DBG1(DBG_KNL, "unable to flush SAD entries");
-		return FAILED;
-	}
-	else if (out->sadb_msg_errno)
+	for (i = 0; i < countof(protos); i++)
 	{
-		DBG1(DBG_KNL, "unable to flush SAD entries: %s (%d)",
-					   strerror(out->sadb_msg_errno), out->sadb_msg_errno);
+		DBG2(DBG_KNL, "flushing all %s SAD entries", protos[i].name);
+
+		msg->sadb_msg_satype = protos[i].proto;
+		if (pfkey_send(this, msg, &out, &len) != SUCCESS)
+		{
+			DBG1(DBG_KNL, "unable to flush %s SAD entries", protos[i].name);
+			return FAILED;
+		}
+		else if (out->sadb_msg_errno)
+		{
+			DBG1(DBG_KNL, "unable to flush %s SAD entries: %s (%d)",
+				 protos[i].name, strerror(out->sadb_msg_errno),
+				 out->sadb_msg_errno);
+			free(out);
+			return FAILED;
+		}
 		free(out);
-		return FAILED;
 	}
-	free(out);
 	return SUCCESS;
 }
 
@@ -2357,6 +2364,7 @@ static status_t add_policy_internal(private_kernel_pfkey_ipsec_t *this,
 	pfkey_msg_t response;
 	size_t len;
 	ipsec_mode_t proto_mode;
+	status_t status;
 
 	memset(&request, 0, sizeof(request));
 
@@ -2444,7 +2452,15 @@ static status_t add_policy_internal(private_kernel_pfkey_ipsec_t *this,
 
 	this->mutex->unlock(this->mutex);
 
-	if (pfkey_send(this, msg, &out, &len) != SUCCESS)
+	status = pfkey_send(this, msg, &out, &len);
+	if (status == SUCCESS && !update && out->sadb_msg_errno == EEXIST)
+	{
+		DBG1(DBG_KNL, "policy already exists, try to update it");
+		free(out);
+		msg->sadb_msg_type = SADB_X_SPDUPDATE;
+		status = pfkey_send(this, msg, &out, &len);
+	}
+	if (status != SUCCESS)
 	{
 		return FAILED;
 	}
diff --git a/src/libhydra/plugins/kernel_pfroute/kernel_pfroute_net.c b/src/libhydra/plugins/kernel_pfroute/kernel_pfroute_net.c
index 0f78022..df80c29 100644
--- a/src/libhydra/plugins/kernel_pfroute/kernel_pfroute_net.c
+++ b/src/libhydra/plugins/kernel_pfroute/kernel_pfroute_net.c
@@ -408,6 +408,11 @@ struct private_kernel_pfroute_net_t
 	 * Time in ms to wait for IP addresses to appear/disappear
 	 */
 	int vip_wait;
+
+	/**
+	 * whether to actually install virtual IPs
+	 */
+	bool install_virtual_ip;
 };
 
 
@@ -1197,6 +1202,11 @@ METHOD(kernel_net_t, add_ip, status_t,
 	tun_device_t *tun;
 	bool timeout = FALSE;
 
+	if (!this->install_virtual_ip)
+	{	/* disabled by config */
+		return SUCCESS;
+	}
+
 	tun = tun_device_create(NULL);
 	if (!tun)
 	{
@@ -1271,6 +1281,11 @@ METHOD(kernel_net_t, del_ip, status_t,
 	host_t *addr;
 	bool timeout = FALSE, found = FALSE;
 
+	if (!this->install_virtual_ip)
+	{	/* disabled by config */
+		return SUCCESS;
+	}
+
 	this->lock->write_lock(this->lock);
 	enumerator = this->tuns->create_enumerator(this->tuns);
 	while (enumerator->enumerate(enumerator, &tun))
@@ -1848,6 +1863,8 @@ kernel_pfroute_net_t *kernel_pfroute_net_create()
 		.roam_lock = spinlock_create(),
 		.vip_wait = lib->settings->get_int(lib->settings,
 						"%s.plugins.kernel-pfroute.vip_wait", 1000, lib->ns),
+		.install_virtual_ip = lib->settings->get_bool(lib->settings,
+						"%s.install_virtual_ip", TRUE, lib->ns),
 	);
 	timerclear(&this->last_route_reinstall);
 	timerclear(&this->next_roam);
diff --git a/src/libhydra/tests/hydra_tests.c b/src/libhydra/tests/hydra_tests.c
index 90abd83..0d6387b 100644
--- a/src/libhydra/tests/hydra_tests.c
+++ b/src/libhydra/tests/hydra_tests.c
@@ -26,8 +26,8 @@
 static test_configuration_t tests[] = {
 #define TEST_SUITE(x) \
 	{ .suite = x, },
-#define TEST_SUITE_DEPEND(x, type, args) \
-	{ .suite = x, .feature = PLUGIN_DEPENDS(type, args) },
+#define TEST_SUITE_DEPEND(x, type, ...) \
+	{ .suite = x, .feature = PLUGIN_DEPENDS(type, __VA_ARGS__) },
 #include "hydra_tests.h"
 	{ .suite = NULL, }
 };
diff --git a/src/libimcv/Android.mk b/src/libimcv/Android.mk
index 8269d72..80e2aaa 100644
--- a/src/libimcv/Android.mk
+++ b/src/libimcv/Android.mk
@@ -18,11 +18,13 @@ libimcv_la_SOURCES := \
 	imv/imv_session.h imv/imv_session.c \
 	imv/imv_session_manager.h imv/imv_session_manager.c \
 	imv/imv_workitem.h imv/imv_workitem.c \
+	generic/generic_attr_bool.h generic/generic_attr_bool.c \
+	generic/generic_attr_chunk.h generic/generic_attr_chunk.c \
+	generic/generic_attr_string.h generic/generic_attr_string.c \
 	ietf/ietf_attr.h ietf/ietf_attr.c \
 	ietf/ietf_attr_assess_result.h ietf/ietf_attr_assess_result.c \
 	ietf/ietf_attr_attr_request.h ietf/ietf_attr_attr_request.c \
 	ietf/ietf_attr_fwd_enabled.h ietf/ietf_attr_fwd_enabled.c \
-	ietf/ietf_attr_default_pwd_enabled.h ietf/ietf_attr_default_pwd_enabled.c \
 	ietf/ietf_attr_installed_packages.h ietf/ietf_attr_installed_packages.c \
 	ietf/ietf_attr_numeric_version.h ietf/ietf_attr_numeric_version.c \
 	ietf/ietf_attr_op_status.h ietf/ietf_attr_op_status.c \
@@ -37,7 +39,6 @@ libimcv_la_SOURCES := \
 	ita/ita_attr_get_settings.h ita/ita_attr_get_settings.c \
 	ita/ita_attr_settings.h ita/ita_attr_settings.c \
 	ita/ita_attr_angel.h ita/ita_attr_angel.c \
-	ita/ita_attr_device_id.h ita/ita_attr_device_id.c \
 	os_info/os_info.h os_info/os_info.c \
 	pa_tnc/pa_tnc_attr.h \
 	pa_tnc/pa_tnc_msg.h pa_tnc/pa_tnc_msg.c \
@@ -66,6 +67,8 @@ libimcv_la_SOURCES := \
 	pts/components/ita/ita_comp_tboot.h pts/components/ita/ita_comp_tboot.c \
 	pts/components/ita/ita_comp_tgrub.h pts/components/ita/ita_comp_tgrub.c \
 	pts/components/tcg/tcg_comp_func_name.h pts/components/tcg/tcg_comp_func_name.c \
+	pwg/pwg_attr.h pwg/pwg_attr.c \
+	pwg/pwg_attr_vendor_smi_code.h pwg/pwg_attr_vendor_smi_code.c \
 	seg/seg_contract.h seg/seg_contract.c \
 	seg/seg_contract_manager.h seg/seg_contract_manager.c \
 	seg/seg_env.h seg/seg_env.c \
diff --git a/src/libimcv/Makefile.am b/src/libimcv/Makefile.am
index a613827..7683da3 100644
--- a/src/libimcv/Makefile.am
+++ b/src/libimcv/Makefile.am
@@ -36,11 +36,13 @@ libimcv_la_SOURCES = \
 	imv/imv_session.h imv/imv_session.c \
 	imv/imv_session_manager.h imv/imv_session_manager.c \
 	imv/imv_workitem.h imv/imv_workitem.c \
+	generic/generic_attr_bool.h generic/generic_attr_bool.c \
+	generic/generic_attr_chunk.h generic/generic_attr_chunk.c \
+	generic/generic_attr_string.h generic/generic_attr_string.c \
 	ietf/ietf_attr.h ietf/ietf_attr.c \
 	ietf/ietf_attr_assess_result.h ietf/ietf_attr_assess_result.c \
 	ietf/ietf_attr_attr_request.h ietf/ietf_attr_attr_request.c \
 	ietf/ietf_attr_fwd_enabled.h ietf/ietf_attr_fwd_enabled.c \
-	ietf/ietf_attr_default_pwd_enabled.h ietf/ietf_attr_default_pwd_enabled.c \
 	ietf/ietf_attr_installed_packages.h ietf/ietf_attr_installed_packages.c \
 	ietf/ietf_attr_numeric_version.h ietf/ietf_attr_numeric_version.c \
 	ietf/ietf_attr_op_status.h ietf/ietf_attr_op_status.c \
@@ -55,7 +57,6 @@ libimcv_la_SOURCES = \
 	ita/ita_attr_get_settings.h ita/ita_attr_get_settings.c \
 	ita/ita_attr_settings.h ita/ita_attr_settings.c \
 	ita/ita_attr_angel.h ita/ita_attr_angel.c \
-	ita/ita_attr_device_id.h ita/ita_attr_device_id.c \
 	os_info/os_info.h os_info/os_info.c \
 	pa_tnc/pa_tnc_attr.h \
 	pa_tnc/pa_tnc_msg.h pa_tnc/pa_tnc_msg.c \
@@ -84,6 +85,8 @@ libimcv_la_SOURCES = \
 	pts/components/ita/ita_comp_tboot.h pts/components/ita/ita_comp_tboot.c \
 	pts/components/ita/ita_comp_tgrub.h pts/components/ita/ita_comp_tgrub.c \
 	pts/components/tcg/tcg_comp_func_name.h pts/components/tcg/tcg_comp_func_name.c \
+	pwg/pwg_attr.h pwg/pwg_attr.c \
+	pwg/pwg_attr_vendor_smi_code.h pwg/pwg_attr_vendor_smi_code.c \
 	seg/seg_contract.h seg/seg_contract.c \
 	seg/seg_contract_manager.h seg/seg_contract_manager.c \
 	seg/seg_env.h seg/seg_env.c \
@@ -173,6 +176,14 @@ if USE_IMV_SWID
   SUBDIRS += plugins/imv_swid
 endif
 
+if USE_IMC_HCD
+  SUBDIRS += plugins/imc_hcd
+endif
+
+if USE_IMV_HCD
+  SUBDIRS += plugins/imv_hcd
+endif
+
 TESTS = imcv_tests
 
 check_PROGRAMS = $(TESTS)
diff --git a/src/libimcv/Makefile.in b/src/libimcv/Makefile.in
index 03778a2..ed2934c 100644
--- a/src/libimcv/Makefile.in
+++ b/src/libimcv/Makefile.in
@@ -94,6 +94,8 @@ ipsec_PROGRAMS = imv_policy_manager$(EXEEXT)
 @USE_IMV_ATTESTATION_TRUE at am__append_10 = plugins/imv_attestation
 @USE_IMC_SWID_TRUE at am__append_11 = plugins/imc_swid
 @USE_IMV_SWID_TRUE at am__append_12 = plugins/imv_swid
+ at USE_IMC_HCD_TRUE@am__append_13 = plugins/imc_hcd
+ at USE_IMV_HCD_TRUE@am__append_14 = plugins/imv_hcd
 TESTS = imcv_tests$(EXEEXT)
 check_PROGRAMS = $(am__EXEEXT_1)
 subdir = src/libimcv
@@ -157,10 +159,10 @@ am_libimcv_la_OBJECTS = imcv.lo imc/imc_agent.lo imc/imc_msg.lo \
 	imv/imv_msg.lo imv/imv_lang_string.lo imv/imv_os_info.lo \
 	imv/imv_reason_string.lo imv/imv_remediation_string.lo \
 	imv/imv_session.lo imv/imv_session_manager.lo \
-	imv/imv_workitem.lo ietf/ietf_attr.lo \
-	ietf/ietf_attr_assess_result.lo ietf/ietf_attr_attr_request.lo \
-	ietf/ietf_attr_fwd_enabled.lo \
-	ietf/ietf_attr_default_pwd_enabled.lo \
+	imv/imv_workitem.lo generic/generic_attr_bool.lo \
+	generic/generic_attr_chunk.lo generic/generic_attr_string.lo \
+	ietf/ietf_attr.lo ietf/ietf_attr_assess_result.lo \
+	ietf/ietf_attr_attr_request.lo ietf/ietf_attr_fwd_enabled.lo \
 	ietf/ietf_attr_installed_packages.lo \
 	ietf/ietf_attr_numeric_version.lo ietf/ietf_attr_op_status.lo \
 	ietf/ietf_attr_pa_tnc_error.lo ietf/ietf_attr_port_filter.lo \
@@ -169,8 +171,7 @@ am_libimcv_la_OBJECTS = imcv.lo imc/imc_agent.lo imc/imc_msg.lo \
 	ietf/ietf_attr_string_version.lo ita/ita_attr.lo \
 	ita/ita_attr_command.lo ita/ita_attr_dummy.lo \
 	ita/ita_attr_get_settings.lo ita/ita_attr_settings.lo \
-	ita/ita_attr_angel.lo ita/ita_attr_device_id.lo \
-	os_info/os_info.lo pa_tnc/pa_tnc_msg.lo \
+	ita/ita_attr_angel.lo os_info/os_info.lo pa_tnc/pa_tnc_msg.lo \
 	pa_tnc/pa_tnc_attr_manager.lo pts/pts.lo pts/pts_error.lo \
 	pts/pts_pcr.lo pts/pts_creds.lo pts/pts_database.lo \
 	pts/pts_dh_group.lo pts/pts_file_meas.lo pts/pts_file_meta.lo \
@@ -183,7 +184,8 @@ am_libimcv_la_OBJECTS = imcv.lo imc/imc_agent.lo imc/imc_msg.lo \
 	pts/components/ita/ita_comp_ima.lo \
 	pts/components/ita/ita_comp_tboot.lo \
 	pts/components/ita/ita_comp_tgrub.lo \
-	pts/components/tcg/tcg_comp_func_name.lo seg/seg_contract.lo \
+	pts/components/tcg/tcg_comp_func_name.lo pwg/pwg_attr.lo \
+	pwg/pwg_attr_vendor_smi_code.lo seg/seg_contract.lo \
 	seg/seg_contract_manager.lo seg/seg_env.lo swid/swid_error.lo \
 	swid/swid_inventory.lo swid/swid_tag.lo swid/swid_tag_id.lo \
 	tcg/tcg_attr.lo tcg/pts/tcg_pts_attr_proto_caps.lo \
@@ -344,7 +346,8 @@ am__tty_colors = { \
 DIST_SUBDIRS = . plugins/imc_test plugins/imv_test plugins/imc_scanner \
 	plugins/imv_scanner plugins/imc_os plugins/imv_os \
 	plugins/imc_attestation plugins/imv_attestation \
-	plugins/imc_swid plugins/imv_swid
+	plugins/imc_swid plugins/imv_swid plugins/imc_hcd \
+	plugins/imv_hcd
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 am__relativize = \
   dir0=`pwd`; \
@@ -625,11 +628,13 @@ libimcv_la_SOURCES = \
 	imv/imv_session.h imv/imv_session.c \
 	imv/imv_session_manager.h imv/imv_session_manager.c \
 	imv/imv_workitem.h imv/imv_workitem.c \
+	generic/generic_attr_bool.h generic/generic_attr_bool.c \
+	generic/generic_attr_chunk.h generic/generic_attr_chunk.c \
+	generic/generic_attr_string.h generic/generic_attr_string.c \
 	ietf/ietf_attr.h ietf/ietf_attr.c \
 	ietf/ietf_attr_assess_result.h ietf/ietf_attr_assess_result.c \
 	ietf/ietf_attr_attr_request.h ietf/ietf_attr_attr_request.c \
 	ietf/ietf_attr_fwd_enabled.h ietf/ietf_attr_fwd_enabled.c \
-	ietf/ietf_attr_default_pwd_enabled.h ietf/ietf_attr_default_pwd_enabled.c \
 	ietf/ietf_attr_installed_packages.h ietf/ietf_attr_installed_packages.c \
 	ietf/ietf_attr_numeric_version.h ietf/ietf_attr_numeric_version.c \
 	ietf/ietf_attr_op_status.h ietf/ietf_attr_op_status.c \
@@ -644,7 +649,6 @@ libimcv_la_SOURCES = \
 	ita/ita_attr_get_settings.h ita/ita_attr_get_settings.c \
 	ita/ita_attr_settings.h ita/ita_attr_settings.c \
 	ita/ita_attr_angel.h ita/ita_attr_angel.c \
-	ita/ita_attr_device_id.h ita/ita_attr_device_id.c \
 	os_info/os_info.h os_info/os_info.c \
 	pa_tnc/pa_tnc_attr.h \
 	pa_tnc/pa_tnc_msg.h pa_tnc/pa_tnc_msg.c \
@@ -673,6 +677,8 @@ libimcv_la_SOURCES = \
 	pts/components/ita/ita_comp_tboot.h pts/components/ita/ita_comp_tboot.c \
 	pts/components/ita/ita_comp_tgrub.h pts/components/ita/ita_comp_tgrub.c \
 	pts/components/tcg/tcg_comp_func_name.h pts/components/tcg/tcg_comp_func_name.c \
+	pwg/pwg_attr.h pwg/pwg_attr.c \
+	pwg/pwg_attr_vendor_smi_code.h pwg/pwg_attr_vendor_smi_code.c \
 	seg/seg_contract.h seg/seg_contract.c \
 	seg/seg_contract_manager.h seg/seg_contract_manager.c \
 	seg/seg_env.h seg/seg_env.c \
@@ -721,7 +727,7 @@ imv_policy_manager_LDADD = \
 SUBDIRS = . $(am__append_3) $(am__append_4) $(am__append_5) \
 	$(am__append_6) $(am__append_7) $(am__append_8) \
 	$(am__append_9) $(am__append_10) $(am__append_11) \
-	$(am__append_12)
+	$(am__append_12) $(am__append_13) $(am__append_14)
 imcv_tests_SOURCES = \
 	ita/ita_attr_command.c \
 	pa_tnc/pa_tnc_attr_manager.c \
@@ -842,6 +848,18 @@ imv/imv_session.lo: imv/$(am__dirstamp) imv/$(DEPDIR)/$(am__dirstamp)
 imv/imv_session_manager.lo: imv/$(am__dirstamp) \
 	imv/$(DEPDIR)/$(am__dirstamp)
 imv/imv_workitem.lo: imv/$(am__dirstamp) imv/$(DEPDIR)/$(am__dirstamp)
+generic/$(am__dirstamp):
+	@$(MKDIR_P) generic
+	@: > generic/$(am__dirstamp)
+generic/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) generic/$(DEPDIR)
+	@: > generic/$(DEPDIR)/$(am__dirstamp)
+generic/generic_attr_bool.lo: generic/$(am__dirstamp) \
+	generic/$(DEPDIR)/$(am__dirstamp)
+generic/generic_attr_chunk.lo: generic/$(am__dirstamp) \
+	generic/$(DEPDIR)/$(am__dirstamp)
+generic/generic_attr_string.lo: generic/$(am__dirstamp) \
+	generic/$(DEPDIR)/$(am__dirstamp)
 ietf/$(am__dirstamp):
 	@$(MKDIR_P) ietf
 	@: > ietf/$(am__dirstamp)
@@ -855,8 +873,6 @@ ietf/ietf_attr_attr_request.lo: ietf/$(am__dirstamp) \
 	ietf/$(DEPDIR)/$(am__dirstamp)
 ietf/ietf_attr_fwd_enabled.lo: ietf/$(am__dirstamp) \
 	ietf/$(DEPDIR)/$(am__dirstamp)
-ietf/ietf_attr_default_pwd_enabled.lo: ietf/$(am__dirstamp) \
-	ietf/$(DEPDIR)/$(am__dirstamp)
 ietf/ietf_attr_installed_packages.lo: ietf/$(am__dirstamp) \
 	ietf/$(DEPDIR)/$(am__dirstamp)
 ietf/ietf_attr_numeric_version.lo: ietf/$(am__dirstamp) \
@@ -890,8 +906,6 @@ ita/ita_attr_settings.lo: ita/$(am__dirstamp) \
 	ita/$(DEPDIR)/$(am__dirstamp)
 ita/ita_attr_angel.lo: ita/$(am__dirstamp) \
 	ita/$(DEPDIR)/$(am__dirstamp)
-ita/ita_attr_device_id.lo: ita/$(am__dirstamp) \
-	ita/$(DEPDIR)/$(am__dirstamp)
 os_info/$(am__dirstamp):
 	@$(MKDIR_P) os_info
 	@: > os_info/$(am__dirstamp)
@@ -974,6 +988,15 @@ pts/components/tcg/$(DEPDIR)/$(am__dirstamp):
 pts/components/tcg/tcg_comp_func_name.lo:  \
 	pts/components/tcg/$(am__dirstamp) \
 	pts/components/tcg/$(DEPDIR)/$(am__dirstamp)
+pwg/$(am__dirstamp):
+	@$(MKDIR_P) pwg
+	@: > pwg/$(am__dirstamp)
+pwg/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) pwg/$(DEPDIR)
+	@: > pwg/$(DEPDIR)/$(am__dirstamp)
+pwg/pwg_attr.lo: pwg/$(am__dirstamp) pwg/$(DEPDIR)/$(am__dirstamp)
+pwg/pwg_attr_vendor_smi_code.lo: pwg/$(am__dirstamp) \
+	pwg/$(DEPDIR)/$(am__dirstamp)
 seg/$(am__dirstamp):
 	@$(MKDIR_P) seg
 	@: > seg/$(am__dirstamp)
@@ -1201,6 +1224,8 @@ uninstall-ipsecSCRIPTS:
 
 mostlyclean-compile:
 	-rm -f *.$(OBJEXT)
+	-rm -f generic/*.$(OBJEXT)
+	-rm -f generic/*.lo
 	-rm -f ietf/*.$(OBJEXT)
 	-rm -f ietf/*.lo
 	-rm -f imc/*.$(OBJEXT)
@@ -1221,6 +1246,8 @@ mostlyclean-compile:
 	-rm -f pts/components/ita/*.lo
 	-rm -f pts/components/tcg/*.$(OBJEXT)
 	-rm -f pts/components/tcg/*.lo
+	-rm -f pwg/*.$(OBJEXT)
+	-rm -f pwg/*.lo
 	-rm -f seg/*.$(OBJEXT)
 	-rm -f seg/*.lo
 	-rm -f suites/*.$(OBJEXT)
@@ -1241,10 +1268,12 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/imcv.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/imcv_tests-imcv.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/imcv_tests-imcv_tests.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at generic/$(DEPDIR)/generic_attr_bool.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at generic/$(DEPDIR)/generic_attr_chunk.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at generic/$(DEPDIR)/generic_attr_string.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ietf/$(DEPDIR)/ietf_attr.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ietf/$(DEPDIR)/ietf_attr_assess_result.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ietf/$(DEPDIR)/ietf_attr_attr_request.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ietf/$(DEPDIR)/ietf_attr_default_pwd_enabled.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ietf/$(DEPDIR)/ietf_attr_fwd_enabled.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ietf/$(DEPDIR)/ietf_attr_installed_packages.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ietf/$(DEPDIR)/ietf_attr_numeric_version.Plo at am__quote@
@@ -1274,7 +1303,6 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ita/$(DEPDIR)/ita_attr.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ita/$(DEPDIR)/ita_attr_angel.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ita/$(DEPDIR)/ita_attr_command.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ita/$(DEPDIR)/ita_attr_device_id.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ita/$(DEPDIR)/ita_attr_dummy.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ita/$(DEPDIR)/ita_attr_get_settings.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ita/$(DEPDIR)/ita_attr_settings.Plo at am__quote@
@@ -1302,6 +1330,8 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at pts/components/ita/$(DEPDIR)/ita_comp_tboot.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at pts/components/ita/$(DEPDIR)/ita_comp_tgrub.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at pts/components/tcg/$(DEPDIR)/tcg_comp_func_name.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at pwg/$(DEPDIR)/pwg_attr.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at pwg/$(DEPDIR)/pwg_attr_vendor_smi_code.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at seg/$(DEPDIR)/imcv_tests-seg_contract.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at seg/$(DEPDIR)/imcv_tests-seg_contract_manager.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at seg/$(DEPDIR)/imcv_tests-seg_env.Po at am__quote@
@@ -1508,6 +1538,7 @@ mostlyclean-libtool:
 
 clean-libtool:
 	-rm -rf .libs _libs
+	-rm -rf generic/.libs generic/_libs
 	-rm -rf ietf/.libs ietf/_libs
 	-rm -rf imc/.libs imc/_libs
 	-rm -rf imv/.libs imv/_libs
@@ -1518,6 +1549,7 @@ clean-libtool:
 	-rm -rf pts/components/.libs pts/components/_libs
 	-rm -rf pts/components/ita/.libs pts/components/ita/_libs
 	-rm -rf pts/components/tcg/.libs pts/components/tcg/_libs
+	-rm -rf pwg/.libs pwg/_libs
 	-rm -rf seg/.libs seg/_libs
 	-rm -rf swid/.libs swid/_libs
 	-rm -rf tcg/.libs tcg/_libs
@@ -1829,6 +1861,8 @@ clean-generic:
 distclean-generic:
 	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
 	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+	-rm -f generic/$(DEPDIR)/$(am__dirstamp)
+	-rm -f generic/$(am__dirstamp)
 	-rm -f ietf/$(DEPDIR)/$(am__dirstamp)
 	-rm -f ietf/$(am__dirstamp)
 	-rm -f imc/$(DEPDIR)/$(am__dirstamp)
@@ -1849,6 +1883,8 @@ distclean-generic:
 	-rm -f pts/components/ita/$(am__dirstamp)
 	-rm -f pts/components/tcg/$(DEPDIR)/$(am__dirstamp)
 	-rm -f pts/components/tcg/$(am__dirstamp)
+	-rm -f pwg/$(DEPDIR)/$(am__dirstamp)
+	-rm -f pwg/$(am__dirstamp)
 	-rm -f seg/$(DEPDIR)/$(am__dirstamp)
 	-rm -f seg/$(am__dirstamp)
 	-rm -f suites/$(DEPDIR)/$(am__dirstamp)
@@ -1873,7 +1909,7 @@ clean-am: clean-checkPROGRAMS clean-generic clean-ipsecPROGRAMS \
 	clean-ipseclibLTLIBRARIES clean-libtool mostlyclean-am
 
 distclean: distclean-recursive
-	-rm -rf ./$(DEPDIR) ietf/$(DEPDIR) imc/$(DEPDIR) imv/$(DEPDIR) ita/$(DEPDIR) os_info/$(DEPDIR) pa_tnc/$(DEPDIR) pts/$(DEPDIR) pts/components/$(DEPDIR) pts/components/ita/$(DEPDIR) pts/components/tcg/$(DEPDIR) seg/$(DEPDIR) suites/$(DEPDIR) swid/$(DEPDIR) tcg/$(DEPDIR) tcg/pts/$(DEPDIR) tcg/seg/$(DEPDIR) tcg/swid/$(DEPDIR)
+	-rm -rf ./$(DEPDIR) generic/$(DEPDIR) ietf/$(DEPDIR) imc/$(DEPDIR) imv/$(DEPDIR) ita/$(DEPDIR) os_info/$(DEPDIR) pa_tnc/$(DEPDIR) pts/$(DEPDIR) pts/components/$(DEPDIR) pts/components/ita/$(DEPDIR) pts/components/tcg/$(DEPDIR) pwg/$(DEPDIR) seg/$(DEPDIR) suites/$(DEPDIR) swid/$(DEPDIR) tcg/$(DEPDIR) tcg/pts/$(DEPDIR) tcg/seg/$(DEPDIR) tcg/swid/$(DEPDIR)
 	-rm -f Makefile
 distclean-am: clean-am distclean-compile distclean-generic \
 	distclean-tags
@@ -1920,7 +1956,7 @@ install-ps-am:
 installcheck-am:
 
 maintainer-clean: maintainer-clean-recursive
-	-rm -rf ./$(DEPDIR) ietf/$(DEPDIR) imc/$(DEPDIR) imv/$(DEPDIR) ita/$(DEPDIR) os_info/$(DEPDIR) pa_tnc/$(DEPDIR) pts/$(DEPDIR) pts/components/$(DEPDIR) pts/components/ita/$(DEPDIR) pts/components/tcg/$(DEPDIR) seg/$(DEPDIR) suites/$(DEPDIR) swid/$(DEPDIR) tcg/$(DEPDIR) tcg/pts/$(DEPDIR) tcg/seg/$(DEPDIR) tcg/swid/$(DEPDIR)
+	-rm -rf ./$(DEPDIR) generic/$(DEPDIR) ietf/$(DEPDIR) imc/$(DEPDIR) imv/$(DEPDIR) ita/$(DEPDIR) os_info/$(DEPDIR) pa_tnc/$(DEPDIR) pts/$(DEPDIR) pts/components/$(DEPDIR) pts/components/ita/$(DEPDIR) pts/components/tcg/$(DEPDIR) pwg/$(DEPDIR) seg/$(DEPDIR) suites/$(DEPDIR) swid/$(DEPDIR) tcg/$(DEPDIR) tcg/pts/$(DEPDIR) tcg/seg/$(DEPDIR) tcg/swid/$(DEPDIR)
 	-rm -f Makefile
 maintainer-clean-am: distclean-am maintainer-clean-generic
 
diff --git a/src/libimcv/ietf/ietf_attr_default_pwd_enabled.c b/src/libimcv/generic/generic_attr_bool.c
similarity index 65%
rename from src/libimcv/ietf/ietf_attr_default_pwd_enabled.c
rename to src/libimcv/generic/generic_attr_bool.c
index ee5864d..3f570d9 100644
--- a/src/libimcv/ietf/ietf_attr_default_pwd_enabled.c
+++ b/src/libimcv/generic/generic_attr_bool.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012-2014 Andreas Steffen
+ * Copyright (C) 2015 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -13,36 +13,37 @@
  * for more details.
  */
 
-#include "ietf_attr_default_pwd_enabled.h"
+#include "generic_attr_bool.h"
 
+#include <imcv.h>
 #include <pa_tnc/pa_tnc_msg.h>
 #include <bio/bio_writer.h>
 #include <bio/bio_reader.h>
 #include <utils/debug.h>
 
-typedef struct private_ietf_attr_default_pwd_enabled_t private_ietf_attr_default_pwd_enabled_t;
+typedef struct private_generic_attr_bool_t private_generic_attr_bool_t;
 
 /**
- * PA-TNC Factory Default Password Enabled type (see section 4.2.12 of RFC 5792)
+ * Generic PA-TNC attribute containing boolean status value in 32 bit encoding 
  *
  *                       1                   2                   3
  *   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *  |              Factory Default Password Enabled                 |
+ *  |                        Boolean Value                          |
  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  */
 
-#define DEFAULT_PWD_ENABLED_SIZE	4
+#define ATTR_BOOL_SIZE	4
 
 /**
- * Private data of an ietf_attr_default_pwd_enabled_t object.
+ * Private data of an generic_attr_bool_t object.
  */
-struct private_ietf_attr_default_pwd_enabled_t {
+struct private_generic_attr_bool_t {
 
 	/**
-	 * Public members of ietf_attr_default_pwd_enabled_t
+	 * Public members of generic_attr_bool_t
 	 */
-	ietf_attr_default_pwd_enabled_t public;
+	generic_attr_bool_t public;
 
 	/**
 	 * Vendor-specific attribute type
@@ -65,7 +66,7 @@ struct private_ietf_attr_default_pwd_enabled_t {
 	bool noskip_flag;
 
 	/**
-	 * Factory Default Password Enabled status
+	 * Boolean status value
 	 */
 	bool status;
 
@@ -76,31 +77,31 @@ struct private_ietf_attr_default_pwd_enabled_t {
 };
 
 METHOD(pa_tnc_attr_t, get_type, pen_type_t,
-	private_ietf_attr_default_pwd_enabled_t *this)
+	private_generic_attr_bool_t *this)
 {
 	return this->type;
 }
 
 METHOD(pa_tnc_attr_t, get_value, chunk_t,
-	private_ietf_attr_default_pwd_enabled_t *this)
+	private_generic_attr_bool_t *this)
 {
 	return this->value;
 }
 
 METHOD(pa_tnc_attr_t, get_noskip_flag, bool,
-	private_ietf_attr_default_pwd_enabled_t *this)
+	private_generic_attr_bool_t *this)
 {
 	return this->noskip_flag;
 }
 
 METHOD(pa_tnc_attr_t, set_noskip_flag,void,
-	private_ietf_attr_default_pwd_enabled_t *this, bool noskip)
+	private_generic_attr_bool_t *this, bool noskip)
 {
 	this->noskip_flag = noskip;
 }
 
 METHOD(pa_tnc_attr_t, build, void,
-	private_ietf_attr_default_pwd_enabled_t *this)
+	private_generic_attr_bool_t *this)
 {
 	bio_writer_t *writer;
 
@@ -108,7 +109,7 @@ METHOD(pa_tnc_attr_t, build, void,
 	{
 		return;
 	}
-	writer = bio_writer_create(DEFAULT_PWD_ENABLED_SIZE);
+	writer = bio_writer_create(ATTR_BOOL_SIZE);
 	writer->write_uint32(writer, this->status);
 
 	this->value = writer->extract_buf(writer);
@@ -117,31 +118,36 @@ METHOD(pa_tnc_attr_t, build, void,
 }
 
 METHOD(pa_tnc_attr_t, process, status_t,
-	private_ietf_attr_default_pwd_enabled_t *this, u_int32_t *offset)
+	private_generic_attr_bool_t *this, u_int32_t *offset)
 {
+	enum_name_t *pa_attr_names;
 	bio_reader_t *reader;
 	u_int32_t status;
-
+  
 	*offset = 0;
 
 	if (this->value.len < this->length)
 	{
 		return NEED_MORE;
 	}
-	if (this->value.len != DEFAULT_PWD_ENABLED_SIZE)
+	pa_attr_names = imcv_pa_tnc_attributes->get_names(imcv_pa_tnc_attributes,
+													  this->type.vendor_id);
+
+	if (this->value.len != ATTR_BOOL_SIZE)
 	{
-		DBG1(DBG_TNC, "incorrect size for IETF factory default password "
-					  "enabled attribute");
+		DBG1(DBG_TNC, "incorrect attribute size for %N/%N",
+			 pen_names, this->type.vendor_id, pa_attr_names, this->type.type);
 		return FAILED;
 	}
 	reader = bio_reader_create(this->value);
 	reader->read_uint32(reader, &status);
 	reader->destroy(reader);
 
-	if (status > TRUE)
+	if (status > 1)
 	{
-		DBG1(DBG_TNC, "IETF factory default password enabled field "
-					  "has unknown value %u", status);
+		DBG1(DBG_TNC, "%N/%N attribute contains invalid non-boolean value %u",
+			 pen_names, this->type.vendor_id, pa_attr_names, this->type.type,
+			 status);
 		return FAILED;
 	}
 	this->status = status;
@@ -150,20 +156,20 @@ METHOD(pa_tnc_attr_t, process, status_t,
 }
 
 METHOD(pa_tnc_attr_t, add_segment, void,
-	private_ietf_attr_default_pwd_enabled_t *this, chunk_t segment)
+	private_generic_attr_bool_t *this, chunk_t segment)
 {
 	this->value = chunk_cat("mc", this->value, segment);
 }
 
 METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*,
-	private_ietf_attr_default_pwd_enabled_t *this)
+	private_generic_attr_bool_t *this)
 {
 	ref_get(&this->ref);
 	return &this->public.pa_tnc_attribute;
 }
 
 METHOD(pa_tnc_attr_t, destroy, void,
-	private_ietf_attr_default_pwd_enabled_t *this)
+	private_generic_attr_bool_t *this)
 {
 	if (ref_put(&this->ref))
 	{
@@ -172,8 +178,8 @@ METHOD(pa_tnc_attr_t, destroy, void,
 	}
 }
 
-METHOD(ietf_attr_default_pwd_enabled_t, get_status, bool,
-	private_ietf_attr_default_pwd_enabled_t *this)
+METHOD(generic_attr_bool_t, get_status, bool,
+	private_generic_attr_bool_t *this)
 {
 	return this->status;
 }
@@ -181,9 +187,9 @@ METHOD(ietf_attr_default_pwd_enabled_t, get_status, bool,
 /**
  * Described in header.
  */
-pa_tnc_attr_t *ietf_attr_default_pwd_enabled_create(bool status)
+pa_tnc_attr_t *generic_attr_bool_create(bool status, pen_type_t type)
 {
-	private_ietf_attr_default_pwd_enabled_t *this;
+	private_generic_attr_bool_t *this;
 
 	INIT(this,
 		.public = {
@@ -200,7 +206,7 @@ pa_tnc_attr_t *ietf_attr_default_pwd_enabled_create(bool status)
 			},
 			.get_status = _get_status,
 		},
-		.type = { PEN_IETF, IETF_ATTR_FACTORY_DEFAULT_PWD_ENABLED },
+		.type = type,
 		.status = status,
 		.ref = 1,
 	);
@@ -211,10 +217,10 @@ pa_tnc_attr_t *ietf_attr_default_pwd_enabled_create(bool status)
 /**
  * Described in header.
  */
-pa_tnc_attr_t *ietf_attr_default_pwd_enabled_create_from_data(size_t length,
-															  chunk_t data)
+pa_tnc_attr_t *generic_attr_bool_create_from_data(size_t length, chunk_t data,
+												  pen_type_t type)
 {
-	private_ietf_attr_default_pwd_enabled_t *this;
+	private_generic_attr_bool_t *this;
 
 	INIT(this,
 		.public = {
@@ -231,7 +237,7 @@ pa_tnc_attr_t *ietf_attr_default_pwd_enabled_create_from_data(size_t length,
 			},
 			.get_status = _get_status,
 		},
-		.type = { PEN_IETF, IETF_ATTR_FACTORY_DEFAULT_PWD_ENABLED },
+		.type = type,
 		.length = length,
 		.value = chunk_clone(data),
 		.ref = 1,
diff --git a/src/libimcv/generic/generic_attr_bool.h b/src/libimcv/generic/generic_attr_bool.h
new file mode 100644
index 0000000..93754bf
--- /dev/null
+++ b/src/libimcv/generic/generic_attr_bool.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2015 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
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup generic_attr_bool generic_attr_bool
+ * @{ @ingroup generic_attr
+ */
+
+#ifndef GENERIC_ATTR_BOOL_H_
+#define GENERIC_ATTR_BOOL_H_
+
+typedef struct generic_attr_bool_t generic_attr_bool_t;
+
+#include <pen/pen.h>
+#include "pa_tnc/pa_tnc_attr.h"
+
+/**
+ * Class implementing a generic PA-TNC attribute containing a boolean status
+ * value encoded as a 32 bit unsigned integer (0,1) in network order 
+ */
+struct generic_attr_bool_t {
+
+	/**
+	 * Public PA-TNC attribute interface
+	 */
+	pa_tnc_attr_t pa_tnc_attribute;
+
+	/**
+	 * Gets boolean value
+	 *
+	 * @return				Boolean status value
+	 */
+	bool (*get_status)(generic_attr_bool_t *this);
+
+};
+
+/**
+ * Creates a generic_attr_bool_t object
+ *
+ * @param status			Boolean status value
+ * @param type				Vendor ID / Attribute Type
+ */
+pa_tnc_attr_t* generic_attr_bool_create(bool status, pen_type_t type);
+
+/**
+ * Creates an generic_attr_bool_t object from received data
+ *
+ * @param length			Total length of attribute value
+ * @param value				Unparsed attribute value (might be a segment)
+ * @param type				Vendor ID / Attribute Type
+ */
+pa_tnc_attr_t* generic_attr_bool_create_from_data(size_t length, chunk_t value,
+												  pen_type_t type);
+
+#endif /** GENERIC_ATTR_BOOL_H_ @}*/
diff --git a/src/libimcv/ita/ita_attr_device_id.c b/src/libimcv/generic/generic_attr_chunk.c
similarity index 59%
copy from src/libimcv/ita/ita_attr_device_id.c
copy to src/libimcv/generic/generic_attr_chunk.c
index 2328426..98a5399 100644
--- a/src/libimcv/ita/ita_attr_device_id.c
+++ b/src/libimcv/generic/generic_attr_chunk.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013-2014 Andreas Steffen
+ * Copyright (C) 2015 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -13,24 +13,23 @@
  * for more details.
  */
 
-#include "ita_attr.h"
-#include "ita_attr_device_id.h"
+#include "generic_attr_chunk.h"
 
+#include <imcv.h>
 #include <pen/pen.h>
-
 #include <utils/debug.h>
 
-typedef struct private_ita_attr_device_id_t private_ita_attr_device_id_t;
+typedef struct private_generic_attr_chunk_t private_generic_attr_chunk_t;
 
 /**
- * Private data of an ita_attr_device_id_t object.
+ * Private data of an generic_attr_chunk_t object.
  */
-struct private_ita_attr_device_id_t {
+struct private_generic_attr_chunk_t {
 
 	/**
-	 * Public members of ita_attr_device_id_t
+	 * Public members of generic_attr_chunk_t
 	 */
-	ita_attr_device_id_t public;
+	generic_attr_chunk_t public;
 
 	/**
 	 * Vendor-specific attribute type
@@ -43,6 +42,11 @@ struct private_ita_attr_device_id_t {
 	size_t length;
 
 	/**
+	 * Fixed size of attribute value, set to 0 if dynamic
+	 */
+	size_t size;
+
+	/**
 	 * Attribute value or segment
 	 */
 	chunk_t value;
@@ -59,62 +63,74 @@ struct private_ita_attr_device_id_t {
 };
 
 METHOD(pa_tnc_attr_t, get_type, pen_type_t,
-	private_ita_attr_device_id_t *this)
+	private_generic_attr_chunk_t *this)
 {
 	return this->type;
 }
 
 METHOD(pa_tnc_attr_t, get_value, chunk_t,
-	private_ita_attr_device_id_t *this)
+	private_generic_attr_chunk_t *this)
 {
 	return this->value;
 }
 
 METHOD(pa_tnc_attr_t, get_noskip_flag, bool,
-	private_ita_attr_device_id_t *this)
+	private_generic_attr_chunk_t *this)
 {
 	return this->noskip_flag;
 }
 
 METHOD(pa_tnc_attr_t, set_noskip_flag,void,
-	private_ita_attr_device_id_t *this, bool noskip)
+	private_generic_attr_chunk_t *this, bool noskip)
 {
 	this->noskip_flag = noskip;
 }
 
 METHOD(pa_tnc_attr_t, build, void,
-	private_ita_attr_device_id_t *this)
+	private_generic_attr_chunk_t *this)
 {
 	return;
 }
 
 METHOD(pa_tnc_attr_t, process, status_t,
-	private_ita_attr_device_id_t *this, u_int32_t *offset)
+	private_generic_attr_chunk_t *this, u_int32_t *offset)
 {
+	enum_name_t *pa_attr_names;
 	*offset = 0;
 
 	if (this->value.len < this->length)
 	{
 		return NEED_MORE;
 	}
+	pa_attr_names = imcv_pa_tnc_attributes->get_names(imcv_pa_tnc_attributes,
+													  this->type.vendor_id);
+
+	if ((this->size == 0 && this->value.len > this->length) ||
+		(this->size != 0 && this->value.len != this->size))
+	{
+		DBG1(DBG_TNC, "inconsistent length of %N/%N string attribute",
+			 pen_names, this->type.vendor_id, pa_attr_names, this->type.type);
+		return FAILED;
+	}
+
 	return SUCCESS;
 }
 
 METHOD(pa_tnc_attr_t, add_segment, void,
-	private_ita_attr_device_id_t *this, chunk_t segment)
+	private_generic_attr_chunk_t *this, chunk_t segment)
 {
 	this->value = chunk_cat("mc", this->value, segment);
 }
 
 METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*,
-	private_ita_attr_device_id_t *this)
+	private_generic_attr_chunk_t *this)
 {
 	ref_get(&this->ref);
 	return &this->public.pa_tnc_attribute;
 }
 
 METHOD(pa_tnc_attr_t, destroy, void,
-	private_ita_attr_device_id_t *this)
+	private_generic_attr_chunk_t *this)
 {
 	if (ref_put(&this->ref))
 	{
@@ -126,9 +142,10 @@ METHOD(pa_tnc_attr_t, destroy, void,
 /**
  * Described in header.
  */
-pa_tnc_attr_t *ita_attr_device_id_create_from_data(size_t length, chunk_t value)
+pa_tnc_attr_t *generic_attr_chunk_create_from_data(size_t length, chunk_t value,
+												   size_t size, pen_type_t type)
 {
-	private_ita_attr_device_id_t *this;
+	private_generic_attr_chunk_t *this;
 
 	INIT(this,
 		.public = {
@@ -144,8 +161,9 @@ pa_tnc_attr_t *ita_attr_device_id_create_from_data(size_t length, chunk_t value)
 				.destroy = _destroy,
 			},
 		},
-		.type = { PEN_ITA, ITA_ATTR_DEVICE_ID },
+		.type = type,
 		.length = length,
+		.size = size,
 		.value = chunk_clone(value),
 		.ref = 1,
 	);
@@ -156,8 +174,9 @@ pa_tnc_attr_t *ita_attr_device_id_create_from_data(size_t length, chunk_t value)
 /**
  * Described in header.
  */
-pa_tnc_attr_t *ita_attr_device_id_create(chunk_t value)
+pa_tnc_attr_t *generic_attr_chunk_create(chunk_t value, pen_type_t type)
 {
-	return ita_attr_device_id_create_from_data(value.len, value);
+	return generic_attr_chunk_create_from_data(value.len, value,
+											   value.len, type);
 }
 
diff --git a/src/libimcv/generic/generic_attr_chunk.h b/src/libimcv/generic/generic_attr_chunk.h
new file mode 100644
index 0000000..a9b3a62
--- /dev/null
+++ b/src/libimcv/generic/generic_attr_chunk.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2015 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
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup generic_attr_chunk generic_attr_chunk
+ * @{ @ingroup generic_attr
+ */
+
+#ifndef GENERIC_ATTR_CHUNK_H_
+#define GENERIC_ATTR_CHUNK_H_
+
+typedef struct generic_attr_chunk_t generic_attr_chunk_t;
+
+#include <pen/pen.h>
+#include "pa_tnc/pa_tnc_attr.h"
+
+/**
+ * Class implementing a generic PA-TNC attribute containing a possibly
+ * binary string with either a fixed or variable size
+ */
+struct generic_attr_chunk_t {
+
+	/**
+	 * Public PA-TNC attribute interface
+	 */
+	pa_tnc_attr_t pa_tnc_attribute;
+};
+
+/**
+ * Creates a generic_attr_chunk_t object
+ *
+ * @param string			Non-nul terminated string
+ * @param type				Vendor ID / Attribute Type
+ */
+pa_tnc_attr_t* generic_attr_chunk_create(chunk_t string, pen_type_t type);
+
+/**
+ * Creates an generic_attr_chunk_t object from received data
+ *
+ * @param length			Total length of attribute value
+ * @param value				Unparsed attribute value (might be a segment)
+ * @param size				size in bytes if fixed array or 0 if dynamic size
+ * @param type				Vendor ID / Attribute Type
+ */
+pa_tnc_attr_t* generic_attr_chunk_create_from_data(size_t length, chunk_t value,
+												   size_t size, pen_type_t type);
+
+#endif /** GENERIC_ATTR_CHUNK_H_ @}*/
diff --git a/src/libimcv/ita/ita_attr_device_id.c b/src/libimcv/generic/generic_attr_string.c
similarity index 58%
rename from src/libimcv/ita/ita_attr_device_id.c
rename to src/libimcv/generic/generic_attr_string.c
index 2328426..e63c012 100644
--- a/src/libimcv/ita/ita_attr_device_id.c
+++ b/src/libimcv/generic/generic_attr_string.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013-2014 Andreas Steffen
+ * Copyright (C) 2013-2015 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -13,24 +13,23 @@
  * for more details.
  */
 
-#include "ita_attr.h"
-#include "ita_attr_device_id.h"
+#include "generic_attr_string.h"
 
+#include <imcv.h>
 #include <pen/pen.h>
-
 #include <utils/debug.h>
 
-typedef struct private_ita_attr_device_id_t private_ita_attr_device_id_t;
+typedef struct private_generic_attr_string_t private_generic_attr_string_t;
 
 /**
- * Private data of an ita_attr_device_id_t object.
+ * Private data of an generic_attr_string_t object.
  */
-struct private_ita_attr_device_id_t {
+struct private_generic_attr_string_t {
 
 	/**
-	 * Public members of ita_attr_device_id_t
+	 * Public members of generic_attr_string_t
 	 */
-	ita_attr_device_id_t public;
+	generic_attr_string_t public;
 
 	/**
 	 * Vendor-specific attribute type
@@ -59,62 +58,82 @@ struct private_ita_attr_device_id_t {
 };
 
 METHOD(pa_tnc_attr_t, get_type, pen_type_t,
-	private_ita_attr_device_id_t *this)
+	private_generic_attr_string_t *this)
 {
 	return this->type;
 }
 
 METHOD(pa_tnc_attr_t, get_value, chunk_t,
-	private_ita_attr_device_id_t *this)
+	private_generic_attr_string_t *this)
 {
 	return this->value;
 }
 
 METHOD(pa_tnc_attr_t, get_noskip_flag, bool,
-	private_ita_attr_device_id_t *this)
+	private_generic_attr_string_t *this)
 {
 	return this->noskip_flag;
 }
 
 METHOD(pa_tnc_attr_t, set_noskip_flag,void,
-	private_ita_attr_device_id_t *this, bool noskip)
+	private_generic_attr_string_t *this, bool noskip)
 {
 	this->noskip_flag = noskip;
 }
 
 METHOD(pa_tnc_attr_t, build, void,
-	private_ita_attr_device_id_t *this)
+	private_generic_attr_string_t *this)
 {
 	return;
 }
 
 METHOD(pa_tnc_attr_t, process, status_t,
-	private_ita_attr_device_id_t *this, u_int32_t *offset)
+	private_generic_attr_string_t *this, u_int32_t *offset)
 {
+	enum_name_t *pa_attr_names;
+	u_char *pos;
 	*offset = 0;
 
 	if (this->value.len < this->length)
 	{
 		return NEED_MORE;
 	}
+	pa_attr_names = imcv_pa_tnc_attributes->get_names(imcv_pa_tnc_attributes,
+													  this->type.vendor_id);
+	if (this->value.len > this->length)
+	{
+		DBG1(DBG_TNC, "inconsistent length of %N/%N string attribute",
+			 pen_names, this->type.vendor_id, pa_attr_names, this->type.type);
+		return FAILED;
+	}
+
+	pos = memchr(this->value.ptr, '\0', this->value.len);
+	if (pos)
+	{
+		DBG1(DBG_TNC, "nul termination in %N/%N string attribute",
+			 pen_names, this->type.vendor_id, pa_attr_names, this->type.type);
+		*offset = pos - this->value.ptr;
+		return FAILED;
+	}
+
 	return SUCCESS;
 }
 
 METHOD(pa_tnc_attr_t, add_segment, void,
-	private_ita_attr_device_id_t *this, chunk_t segment)
+	private_generic_attr_string_t *this, chunk_t segment)
 {
 	this->value = chunk_cat("mc", this->value, segment);
 }
 
 METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*,
-	private_ita_attr_device_id_t *this)
+	private_generic_attr_string_t *this)
 {
 	ref_get(&this->ref);
 	return &this->public.pa_tnc_attribute;
 }
 
 METHOD(pa_tnc_attr_t, destroy, void,
-	private_ita_attr_device_id_t *this)
+	private_generic_attr_string_t *this)
 {
 	if (ref_put(&this->ref))
 	{
@@ -126,9 +145,10 @@ METHOD(pa_tnc_attr_t, destroy, void,
 /**
  * Described in header.
  */
-pa_tnc_attr_t *ita_attr_device_id_create_from_data(size_t length, chunk_t value)
+pa_tnc_attr_t *generic_attr_string_create_from_data(size_t length,
+					 				chunk_t value, pen_type_t type)
 {
-	private_ita_attr_device_id_t *this;
+	private_generic_attr_string_t *this;
 
 	INIT(this,
 		.public = {
@@ -144,7 +164,7 @@ pa_tnc_attr_t *ita_attr_device_id_create_from_data(size_t length, chunk_t value)
 				.destroy = _destroy,
 			},
 		},
-		.type = { PEN_ITA, ITA_ATTR_DEVICE_ID },
+		.type = type,
 		.length = length,
 		.value = chunk_clone(value),
 		.ref = 1,
@@ -156,8 +176,8 @@ pa_tnc_attr_t *ita_attr_device_id_create_from_data(size_t length, chunk_t value)
 /**
  * Described in header.
  */
-pa_tnc_attr_t *ita_attr_device_id_create(chunk_t value)
+pa_tnc_attr_t *generic_attr_string_create(chunk_t value, pen_type_t type)
 {
-	return ita_attr_device_id_create_from_data(value.len, value);
+	return generic_attr_string_create_from_data(value.len, value, type);
 }
 
diff --git a/src/libimcv/ita/ita_attr_device_id.h b/src/libimcv/generic/generic_attr_string.h
similarity index 50%
rename from src/libimcv/ita/ita_attr_device_id.h
rename to src/libimcv/generic/generic_attr_string.h
index 94bb778..d830ab4 100644
--- a/src/libimcv/ita/ita_attr_device_id.h
+++ b/src/libimcv/generic/generic_attr_string.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013-2014 Andreas Steffen
+ * Copyright (C) 2015 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -14,43 +14,46 @@
  */
 
 /**
- * @defgroup ita_attr_device_id ita_attr_device_id
- * @{ @ingroup ita_attr
+ * @defgroup generic_attr_string generic_attr_string
+ * @{ @ingroup generic_attr
  */
 
-#ifndef ITA_ATTR_DEVICE_ID_H_
-#define ITA_ATTR_DEVICE_ID_H_
+#ifndef GENERIC_ATTR_STRING_H_
+#define GENERIC_ATTR_STRING_H_
 
-typedef struct ita_attr_device_id_t ita_attr_device_id_t;
+typedef struct generic_attr_string_t generic_attr_string_t;
 
+#include <pen/pen.h>
 #include "pa_tnc/pa_tnc_attr.h"
 
 /**
- * Class implementing the ITA Device ID PA-TNC attribute.
- *
+ * Class implementing a generic PA-TNC attribute containing a non-nul
+ * terminated printable string
  */
-struct ita_attr_device_id_t {
+struct generic_attr_string_t {
 
 	/**
 	 * Public PA-TNC attribute interface
 	 */
 	pa_tnc_attr_t pa_tnc_attribute;
-
 };
 
 /**
- * Creates an ita_attr_device_id_t object
+ * Creates a generic_attr_string_t object
  *
- * @param value				ITA Device ID attribute value
+ * @param string			Non-nul terminated string
+ * @param type				Vendor ID / Attribute Type
  */
-pa_tnc_attr_t* ita_attr_device_id_create(chunk_t value);
+pa_tnc_attr_t* generic_attr_string_create(chunk_t string, pen_type_t type);
 
 /**
- * Creates an ita_attr_device_id_t object from received data
+ * Creates an generic_attr_string_t object from received data
  *
  * @param length			Total length of attribute value
  * @param value				Unparsed attribute value (might be a segment)
+ * @param type				Vendor ID / Attribute Type
  */
-pa_tnc_attr_t* ita_attr_device_id_create_from_data(size_t length, chunk_t value);
+pa_tnc_attr_t* generic_attr_string_create_from_data(size_t length,
+									chunk_t value, pen_type_t type);
 
-#endif /** ITA_ATTR_DEVICE_ID_H_ @}*/
+#endif /** GENERIC_ATTR_STRING_H_ @}*/
diff --git a/src/libimcv/ietf/ietf_attr.c b/src/libimcv/ietf/ietf_attr.c
index 67269af..38b777f 100644
--- a/src/libimcv/ietf/ietf_attr.c
+++ b/src/libimcv/ietf/ietf_attr.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011-2014 Andreas Steffen
+ * Copyright (C) 2011-2015 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -17,7 +17,6 @@
 #include "ietf/ietf_attr_assess_result.h"
 #include "ietf/ietf_attr_attr_request.h"
 #include "ietf/ietf_attr_fwd_enabled.h"
-#include "ietf/ietf_attr_default_pwd_enabled.h"
 #include "ietf/ietf_attr_installed_packages.h"
 #include "ietf/ietf_attr_numeric_version.h"
 #include "ietf/ietf_attr_op_status.h"
@@ -26,6 +25,7 @@
 #include "ietf/ietf_attr_product_info.h"
 #include "ietf/ietf_attr_remediation_instr.h"
 #include "ietf/ietf_attr_string_version.h"
+#include "generic/generic_attr_bool.h"
 
 
 ENUM(ietf_attr_names, IETF_ATTR_TESTING, IETF_ATTR_FACTORY_DEFAULT_PWD_ENABLED,
@@ -63,7 +63,8 @@ pa_tnc_attr_t* ietf_attr_create_from_data(u_int32_t type, size_t length,
 		case IETF_ATTR_OPERATIONAL_STATUS:
 			return ietf_attr_op_status_create_from_data(length, value);
 		case IETF_ATTR_PORT_FILTER:
-			return ietf_attr_port_filter_create_from_data(length, value);
+			return ietf_attr_port_filter_create_from_data(length, value,
+									pen_type_create(PEN_IETF, type));
 		case IETF_ATTR_INSTALLED_PACKAGES:
 			return ietf_attr_installed_packages_create_from_data(length, value);
 		case IETF_ATTR_PA_TNC_ERROR:
@@ -73,9 +74,11 @@ pa_tnc_attr_t* ietf_attr_create_from_data(u_int32_t type, size_t length,
 		case IETF_ATTR_REMEDIATION_INSTRUCTIONS:
 			return ietf_attr_remediation_instr_create_from_data(length, value);
 		case IETF_ATTR_FORWARDING_ENABLED:
-			return ietf_attr_fwd_enabled_create_from_data(length, value);
+			return ietf_attr_fwd_enabled_create_from_data(length, value,
+									pen_type_create(PEN_IETF, type));
 		case IETF_ATTR_FACTORY_DEFAULT_PWD_ENABLED:
-			return ietf_attr_default_pwd_enabled_create_from_data(length, value);
+			return generic_attr_bool_create_from_data(length, value,
+									pen_type_create(PEN_IETF, type));
 		case IETF_ATTR_TESTING:
 		case IETF_ATTR_RESERVED:
 		default:
diff --git a/src/libimcv/ietf/ietf_attr_default_pwd_enabled.h b/src/libimcv/ietf/ietf_attr_default_pwd_enabled.h
deleted file mode 100644
index 3999590..0000000
--- a/src/libimcv/ietf/ietf_attr_default_pwd_enabled.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2012 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
- * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * for more details.
- */
-
-/**
- * @defgroup ietf_attr_default_pwd_enabled ietf_attr_default_pwd_enabled
- * @{ @ingroup ietf_attr
- */
-
-#ifndef IETF_ATTR_PWD_ENABLED_H_
-#define IETF_ATTR_PWD_ENABLED_H_
-
-typedef struct ietf_attr_default_pwd_enabled_t ietf_attr_default_pwd_enabled_t;
-
-#include "ietf_attr.h"
-#include "pa_tnc/pa_tnc_attr.h"
-
-/**
- * Class implementing the IETF PA-TNC Factory Default Password Enabled attribute.
- *
- */
-struct ietf_attr_default_pwd_enabled_t {
-
-	/**
-	 * Public PA-TNC attribute interface
-	 */
-	pa_tnc_attr_t pa_tnc_attribute;
-
-	/**
-	 * Gets the Factory Default Password Enabled status
-	 *
-	 * @return				Factory Default Password Enabled status
-	 */
-	bool (*get_status)(ietf_attr_default_pwd_enabled_t *this);
-
-};
-
-/**
- * Creates an ietf_attr_default_pwd_enabled_t object
- *
- * @param status			Factory Default Password Enabled status
- */
-pa_tnc_attr_t* ietf_attr_default_pwd_enabled_create(bool status);
-
-/**
- * Creates an ietf_attr_default_pwd_enabled_t object from received data
- *
- * @param length			Total length of attribute value
- * @param value				Unparsed attribute value (might be a segment)
- */
-pa_tnc_attr_t* ietf_attr_default_pwd_enabled_create_from_data(size_t length,
-															  chunk_t value);
-
-#endif /** IETF_ATTR_PWD_ENABLED_H_ @}*/
diff --git a/src/libimcv/ietf/ietf_attr_fwd_enabled.c b/src/libimcv/ietf/ietf_attr_fwd_enabled.c
index c00a5ef..876a740 100644
--- a/src/libimcv/ietf/ietf_attr_fwd_enabled.c
+++ b/src/libimcv/ietf/ietf_attr_fwd_enabled.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012-2014 Andreas Steffen
+ * Copyright (C) 2012-2015 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -180,7 +180,8 @@ METHOD(ietf_attr_fwd_enabled_t, get_status, os_fwd_status_t,
 /**
  * Described in header.
  */
-pa_tnc_attr_t *ietf_attr_fwd_enabled_create(os_fwd_status_t fwd_status)
+pa_tnc_attr_t *ietf_attr_fwd_enabled_create(os_fwd_status_t fwd_status,
+											pen_type_t type)
 {
 	private_ietf_attr_fwd_enabled_t *this;
 
@@ -199,7 +200,7 @@ pa_tnc_attr_t *ietf_attr_fwd_enabled_create(os_fwd_status_t fwd_status)
 			},
 			.get_status = _get_status,
 		},
-		.type = { PEN_IETF, IETF_ATTR_FORWARDING_ENABLED },
+		.type = type,
 		.fwd_status = fwd_status,
 		.ref = 1,
 	);
@@ -211,7 +212,7 @@ pa_tnc_attr_t *ietf_attr_fwd_enabled_create(os_fwd_status_t fwd_status)
  * Described in header.
  */
 pa_tnc_attr_t *ietf_attr_fwd_enabled_create_from_data(size_t length,
-													  chunk_t data)
+										chunk_t data, pen_type_t type)
 {
 	private_ietf_attr_fwd_enabled_t *this;
 
@@ -230,7 +231,7 @@ pa_tnc_attr_t *ietf_attr_fwd_enabled_create_from_data(size_t length,
 			},
 			.get_status = _get_status,
 		},
-		.type = { PEN_IETF, IETF_ATTR_FORWARDING_ENABLED },
+		.type = type,
 		.length = length,
 		.value = chunk_clone(data),
 		.ref = 1,
diff --git a/src/libimcv/ietf/ietf_attr_fwd_enabled.h b/src/libimcv/ietf/ietf_attr_fwd_enabled.h
index 3d55436..39abb0a 100644
--- a/src/libimcv/ietf/ietf_attr_fwd_enabled.h
+++ b/src/libimcv/ietf/ietf_attr_fwd_enabled.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012-2014 Andreas Steffen
+ * Copyright (C) 2012-2015 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -51,16 +51,19 @@ struct ietf_attr_fwd_enabled_t {
  * Creates an ietf_attr_fwd_enabled_t object
  *
  * @param fwd_status		Forwarding Enabled status
+ * @param type				Vendor ID / Attribute Type
  */
-pa_tnc_attr_t* ietf_attr_fwd_enabled_create(os_fwd_status_t fwd_status);
+pa_tnc_attr_t* ietf_attr_fwd_enabled_create(os_fwd_status_t fwd_status,
+											pen_type_t type);
 
 /**
  * Creates an ietf_attr_fwd_enabled_t object from received data
  *
  * @param length			Total length of attribute value
  * @param value				Unparsed attribute value (might be a segment)
+ * @param type				Vendor ID / Attribute Type
  */
 pa_tnc_attr_t* ietf_attr_fwd_enabled_create_from_data(size_t length,
-													  chunk_t value);
+										chunk_t value, pen_type_t type);
 
 #endif /** IETF_ATTR_FWD_ENABLED_H_ @}*/
diff --git a/src/libimcv/ietf/ietf_attr_port_filter.c b/src/libimcv/ietf/ietf_attr_port_filter.c
index 4682440..6f7ff54 100644
--- a/src/libimcv/ietf/ietf_attr_port_filter.c
+++ b/src/libimcv/ietf/ietf_attr_port_filter.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011-2014 Andreas Steffen
+ * Copyright (C) 2011-2015 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -236,7 +236,7 @@ METHOD(ietf_attr_port_filter_t, create_port_enumerator, enumerator_t*,
 /**
  * Described in header.
  */
-pa_tnc_attr_t *ietf_attr_port_filter_create(void)
+pa_tnc_attr_t *ietf_attr_port_filter_create(pen_type_t type)
 {
 	private_ietf_attr_port_filter_t *this;
 
@@ -256,7 +256,7 @@ pa_tnc_attr_t *ietf_attr_port_filter_create(void)
 			.add_port = _add_port,
 			.create_port_enumerator = _create_port_enumerator,
 		},
-		.type = { PEN_IETF, IETF_ATTR_PORT_FILTER },
+		.type = type,
 		.ports = linked_list_create(),
 		.ref = 1,
 	);
@@ -268,7 +268,7 @@ pa_tnc_attr_t *ietf_attr_port_filter_create(void)
  * Described in header.
  */
 pa_tnc_attr_t *ietf_attr_port_filter_create_from_data(size_t length,
-													  chunk_t data)
+										chunk_t data, pen_type_t type)
 {
 	private_ietf_attr_port_filter_t *this;
 
@@ -288,7 +288,7 @@ pa_tnc_attr_t *ietf_attr_port_filter_create_from_data(size_t length,
 			.add_port = _add_port,
 			.create_port_enumerator = _create_port_enumerator,
 		},
-		.type = {PEN_IETF, IETF_ATTR_PORT_FILTER },
+		.type = type,
 		.length = length,
 		.value = chunk_clone(data),
 		.ports = linked_list_create(),
diff --git a/src/libimcv/ietf/ietf_attr_port_filter.h b/src/libimcv/ietf/ietf_attr_port_filter.h
index d383b19..e6c5a3f 100644
--- a/src/libimcv/ietf/ietf_attr_port_filter.h
+++ b/src/libimcv/ietf/ietf_attr_port_filter.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011-2014 Andreas Steffen
+ * Copyright (C) 2011-2015 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -61,16 +61,18 @@ struct ietf_attr_port_filter_t {
 /**
  * Creates an ietf_attr_port_filter_t object
  *
+ * @param type				Vendor ID / Attribute Type
  */
-pa_tnc_attr_t* ietf_attr_port_filter_create(void);
+pa_tnc_attr_t* ietf_attr_port_filter_create(pen_type_t type);
 
 /**
  * Creates an ietf_attr_port_filter_t object from received data
  *
  * @param length			Total length of attribute value
  * @param value				Unparsed attribute value (might be a segment)
+ * @param type				Vendor ID / Attribute Type
  */
 pa_tnc_attr_t* ietf_attr_port_filter_create_from_data(size_t length,
-													  chunk_t value);
+										chunk_t value, pen_type_t type);
 
 #endif /** IETF_ATTR_PORT_FILTER_H_ @}*/
diff --git a/src/libimcv/imc/imc_msg.c b/src/libimcv/imc/imc_msg.c
index 83337cf..9e12e29 100644
--- a/src/libimcv/imc/imc_msg.c
+++ b/src/libimcv/imc/imc_msg.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012-2014 Andreas Steffen
+ * Copyright (C) 2012-2015 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -108,6 +108,7 @@ METHOD(imc_msg_t, send_, TNC_Result,
 	pa_tnc_attr_t *attr;
 	TNC_UInt32 msg_flags;
 	TNC_MessageType msg_type;
+	size_t max_msg_len, min_seg_attr_len, space_left;
 	bool attr_added, oversize;
 	chunk_t msg;
 	seg_contract_t *contract;
@@ -120,23 +121,37 @@ METHOD(imc_msg_t, send_, TNC_Result,
 	contract = contracts->get_contract(contracts, this->msg_type,
 									   FALSE, this->dst_id);
 
+	/* Retrieve maximum allowed PA-TNC message size if set */
+	max_msg_len = this->state->get_max_msg_len(this->state);
+
+	/* Minimum size needed for Segmentation Envelope Attribute */
+	min_seg_attr_len = PA_TNC_ATTR_HEADER_SIZE + TCG_SEG_ATTR_SEG_ENV_HEADER +
+					   PA_TNC_ATTR_HEADER_SIZE;
+
 	while (this->attr_list->get_count(this->attr_list))
 	{
-		pa_tnc_msg = pa_tnc_msg_create(this->state->get_max_msg_len(this->state));
+		pa_tnc_msg = pa_tnc_msg_create(max_msg_len);
 		attr_added = FALSE;
 
 		enumerator = this->attr_list->create_enumerator(this->attr_list);
 		while (enumerator->enumerate(enumerator, &attr))
 		{
+			space_left = pa_tnc_msg->get_space(pa_tnc_msg);
+
 			if (contract && contract->check_size(contract, attr, &oversize))
 			{
 				if (oversize)
 				{
-					/* TODO generate SWID error msg */
+					/* TODO handle oversized attributes */
+				}
+				else if (max_msg_len == 0 || space_left >= min_seg_attr_len)
+				{
+					attr = contract->first_segment(contract, attr, space_left);
 				}
 				else
 				{
-					attr = contract->first_segment(contract, attr);
+					/* segment attribute in next iteration */
+					break;
 				}
 			}
 			if (pa_tnc_msg->add_attribute(pa_tnc_msg, attr))
@@ -147,11 +162,12 @@ METHOD(imc_msg_t, send_, TNC_Result,
 			{
 				if (attr_added)
 				{
+					/* there might be space for attribute in next iteration */
 					break;
 				}
 				else
 				{
-					DBG1(DBG_IMC, "PA-TNC attribute too large to send, deleted");
+					DBG1(DBG_IMV, "PA-TNC attribute too large to send, deleted");
 					attr->destroy(attr);
 				}
 			}
@@ -341,9 +357,7 @@ METHOD(imc_msg_t, receive, TNC_Result,
 				my_max_seg_size = this->state->get_max_msg_len(this->state)
 									- PA_TNC_HEADER_SIZE
 									- PA_TNC_ATTR_HEADER_SIZE
-									- TCG_SEG_ATTR_SEG_ENV_HEADER
-									- PA_TNC_ATTR_HEADER_SIZE
-									- TCG_SEG_ATTR_MAX_SIZE_SIZE;
+									- TCG_SEG_ATTR_SEG_ENV_HEADER;
 
 				/* If segmentation is possible select lower segment size */
 				if (max_seg_size != SEG_CONTRACT_NO_FRAGMENTATION &&
diff --git a/src/libimcv/imc/imc_os_info.c b/src/libimcv/imc/imc_os_info.c
index 47697f1..0a094eb 100644
--- a/src/libimcv/imc/imc_os_info.c
+++ b/src/libimcv/imc/imc_os_info.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012-2014 Andreas Steffen
+ * Copyright (C) 2012-2015 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -90,6 +90,14 @@ METHOD(imc_os_info_t, get_version, chunk_t,
 	return this->version;
 }
 
+METHOD(imc_os_info_t, get_default_pwd_status, bool,
+	private_imc_os_info_t *this)
+{
+	/* As an option the default password status can be configured manually */
+	return lib->settings->get_bool(lib->settings,
+					"%s.imcv.os_info.default_password_enabled", FALSE, lib->ns);
+}
+
 #ifdef WIN32
 
 METHOD(imc_os_info_t, get_fwd_status, os_fwd_status_t,
@@ -618,6 +626,7 @@ imc_os_info_t *imc_os_info_create(void)
 			.get_numeric_version = _get_numeric_version,
 			.get_version = _get_version,
 			.get_fwd_status = _get_fwd_status,
+			.get_default_pwd_status = _get_default_pwd_status,
 			.get_uptime = _get_uptime,
 			.get_setting = _get_setting,
 			.create_package_enumerator = _create_package_enumerator,
diff --git a/src/libimcv/imc/imc_os_info.h b/src/libimcv/imc/imc_os_info.h
index 6bb0e96..ef7fb6d 100644
--- a/src/libimcv/imc/imc_os_info.h
+++ b/src/libimcv/imc/imc_os_info.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012-2014 Andreas Steffen
+ * Copyright (C) 2012-2015 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -72,6 +72,13 @@ struct imc_os_info_t {
 	os_fwd_status_t (*get_fwd_status)(imc_os_info_t *this);
 
 	/**
+	 * Get the default password status
+	 *
+	 * @return					TRUE if enabled, FALSE otherwise
+	 */
+	bool (*get_default_pwd_status)(imc_os_info_t *this);
+
+	/**
 	 * Get the OS uptime in seconds
 	 *
 	 * @return					OS uptime
diff --git a/src/libimcv/imcv.c b/src/libimcv/imcv.c
index bd4156c..ec6ea42 100644
--- a/src/libimcv/imcv.c
+++ b/src/libimcv/imcv.c
@@ -1,5 +1,6 @@
 /*
- * Copyright (C) 2011 Andreas Steffen, HSR Hochschule fuer Technik Rapperswil
+ * Copyright (C) 2011-2015 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
@@ -15,6 +16,7 @@
 #include "imcv.h"
 #include "ietf/ietf_attr.h"
 #include "ita/ita_attr.h"
+#include "pwg/pwg_attr.h"
 #include "tcg/tcg_attr.h"
 #include "pts/components/pts_component.h"
 #include "pts/components/pts_component_manager.h"
@@ -179,6 +181,8 @@ bool libimcv_init(bool is_imv)
 							ietf_attr_create_from_data, ietf_attr_names);
 		imcv_pa_tnc_attributes->add_vendor(imcv_pa_tnc_attributes, PEN_ITA,
 							ita_attr_create_from_data, ita_attr_names);
+		imcv_pa_tnc_attributes->add_vendor(imcv_pa_tnc_attributes, PEN_PWG,
+							pwg_attr_create_from_data, pwg_attr_names);
 		imcv_pa_tnc_attributes->add_vendor(imcv_pa_tnc_attributes, PEN_TCG,
 							tcg_attr_create_from_data, tcg_attr_names);
 
@@ -235,6 +239,7 @@ void libimcv_deinit(void)
 
 		imcv_pa_tnc_attributes->remove_vendor(imcv_pa_tnc_attributes, PEN_IETF);
 		imcv_pa_tnc_attributes->remove_vendor(imcv_pa_tnc_attributes, PEN_ITA);
+		imcv_pa_tnc_attributes->remove_vendor(imcv_pa_tnc_attributes, PEN_PWG);
 		imcv_pa_tnc_attributes->remove_vendor(imcv_pa_tnc_attributes, PEN_TCG);
 		DESTROY_IF(imcv_pa_tnc_attributes);
 		imcv_pa_tnc_attributes = NULL;
diff --git a/src/libimcv/imcv.h b/src/libimcv/imcv.h
index 31536ec..e260ff8 100644
--- a/src/libimcv/imcv.h
+++ b/src/libimcv/imcv.h
@@ -15,6 +15,9 @@
 /**
  * @defgroup libimcv libimcv
  *
+ * @defgroup generic_attr generic_attr
+ * @ingroup libimcv
+ *
  * @defgroup libimcv_imc imc
  * @ingroup libimcv
  *
diff --git a/src/libimcv/imv/imv_msg.c b/src/libimcv/imv/imv_msg.c
index fdf6332..039124c 100644
--- a/src/libimcv/imv/imv_msg.c
+++ b/src/libimcv/imv/imv_msg.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012-2014 Andreas Steffen
+ * Copyright (C) 2012-2015 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -125,6 +125,7 @@ METHOD(imv_msg_t, send_, TNC_Result,
 	pa_tnc_attr_t *attr;
 	TNC_UInt32 msg_flags;
 	TNC_MessageType msg_type;
+	size_t max_msg_len, min_seg_attr_len, space_left;
 	bool attr_added, oversize;
 	chunk_t msg;
 	seg_contract_t *contract;
@@ -137,23 +138,37 @@ METHOD(imv_msg_t, send_, TNC_Result,
 	contract = contracts->get_contract(contracts, this->msg_type,
 									   FALSE, this->dst_id);
 
+	/* Retrieve maximum allowed PA-TNC message size if set */
+	max_msg_len = this->state->get_max_msg_len(this->state);
+
+	/* Minimum size needed for Segmentation Envelope Attribute */
+	min_seg_attr_len = PA_TNC_ATTR_HEADER_SIZE + TCG_SEG_ATTR_SEG_ENV_HEADER +
+					   PA_TNC_ATTR_HEADER_SIZE;
+
 	while (this->attr_list->get_count(this->attr_list))
 	{
-		pa_tnc_msg = pa_tnc_msg_create(this->state->get_max_msg_len(this->state));
+		pa_tnc_msg = pa_tnc_msg_create(max_msg_len);
 		attr_added = FALSE;
 
 		enumerator = this->attr_list->create_enumerator(this->attr_list);
 		while (enumerator->enumerate(enumerator, &attr))
 		{
+			space_left = pa_tnc_msg->get_space(pa_tnc_msg);
+
 			if (contract && contract->check_size(contract, attr, &oversize))
 			{
 				if (oversize)
 				{
-					/* TODO generate SWID error msg */
+					/* TODO handle oversized attributes */
+				}
+				else if (max_msg_len == 0 || space_left >= min_seg_attr_len)
+				{
+					attr = contract->first_segment(contract, attr, space_left);
 				}
 				else
 				{
-					attr = contract->first_segment(contract, attr);
+					/* segment attribute in next iteration */
+					break;
 				}
 			}
 			if (pa_tnc_msg->add_attribute(pa_tnc_msg, attr))
@@ -164,6 +179,7 @@ METHOD(imv_msg_t, send_, TNC_Result,
 			{
 				if (attr_added)
 				{
+					/* there might be space for attribute in next iteration */
 					break;
 				}
 				else
@@ -377,9 +393,7 @@ METHOD(imv_msg_t, receive, TNC_Result,
 				my_max_seg_size = this->state->get_max_msg_len(this->state)
 									- PA_TNC_HEADER_SIZE
 									- PA_TNC_ATTR_HEADER_SIZE
-									- TCG_SEG_ATTR_SEG_ENV_HEADER
-									- PA_TNC_ATTR_HEADER_SIZE
-									- TCG_SEG_ATTR_MAX_SIZE_SIZE;
+									- TCG_SEG_ATTR_SEG_ENV_HEADER;
 
 				/* If segmentation is possible select lower segment size */
 				if (max_seg_size != SEG_CONTRACT_NO_FRAGMENTATION &&
diff --git a/src/libimcv/ita/ita_attr.c b/src/libimcv/ita/ita_attr.c
index 9d7706d..35c882c 100644
--- a/src/libimcv/ita/ita_attr.c
+++ b/src/libimcv/ita/ita_attr.c
@@ -19,7 +19,7 @@
 #include "ita/ita_attr_get_settings.h"
 #include "ita/ita_attr_settings.h"
 #include "ita/ita_attr_angel.h"
-#include "ita/ita_attr_device_id.h"
+#include "generic/generic_attr_string.h"
 
 ENUM(ita_attr_names, ITA_ATTR_COMMAND, ITA_ATTR_DEVICE_ID,
 	"Command",
@@ -53,7 +53,8 @@ pa_tnc_attr_t* ita_attr_create_from_data(u_int32_t type, size_t length,
 		case ITA_ATTR_STOP_ANGEL:
 			return ita_attr_angel_create_from_data(FALSE);
 		case ITA_ATTR_DEVICE_ID:
-			return ita_attr_device_id_create_from_data(length, value);
+			return generic_attr_string_create_from_data(length, value,
+									pen_type_create(PEN_ITA, type));
 		default:
 			return NULL;
 	}
diff --git a/src/libimcv/pa_tnc/pa_tnc_msg.c b/src/libimcv/pa_tnc/pa_tnc_msg.c
index ea4dee9..17c649d 100644
--- a/src/libimcv/pa_tnc/pa_tnc_msg.c
+++ b/src/libimcv/pa_tnc/pa_tnc_msg.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011-2014 Andreas Steffen
+ * Copyright (C) 2011-2015 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -92,6 +92,12 @@ METHOD(pa_tnc_msg_t, get_encoding, chunk_t,
 	return this->encoding;
 }
 
+METHOD(pa_tnc_msg_t, get_space, size_t,
+	private_pa_tnc_msg_t *this)
+{
+	return this->max_msg_len ? this->max_msg_len - this->msg_len : 0;
+}
+
 METHOD(pa_tnc_msg_t, add_attribute, bool,
 	private_pa_tnc_msg_t *this, pa_tnc_attr_t *attr)
 {
@@ -389,6 +395,7 @@ pa_tnc_msg_t *pa_tnc_msg_create(size_t max_msg_len)
 	INIT(this,
 		.public = {
 			.get_encoding = _get_encoding,
+			.get_space = _get_space,
 			.add_attribute = _add_attribute,
 			.build = _build,
 			.process = _process,
@@ -416,6 +423,7 @@ pa_tnc_msg_t *pa_tnc_msg_create_from_data(chunk_t data)
 	INIT(this,
 		.public = {
 			.get_encoding = _get_encoding,
+			.get_space = _get_space,
 			.add_attribute = _add_attribute,
 			.build = _build,
 			.process = _process,
diff --git a/src/libimcv/pa_tnc/pa_tnc_msg.h b/src/libimcv/pa_tnc/pa_tnc_msg.h
index 57ff1a0..3be3020 100644
--- a/src/libimcv/pa_tnc/pa_tnc_msg.h
+++ b/src/libimcv/pa_tnc/pa_tnc_msg.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011-2014 Andreas Steffen
+ * Copyright (C) 2011-2015 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -44,6 +44,13 @@ struct pa_tnc_msg_t {
 	chunk_t (*get_encoding)(pa_tnc_msg_t *this);
 
 	/**
+	 * Get the remaining space in octets left in the PA-TNC message
+	 *
+	 * @return					remaining space or 0 if max_msg_len is not set
+	 */
+	size_t (*get_space)(pa_tnc_msg_t *this);
+
+	/**
 	 * Add a PA-TNC attribute
 	 *
 	 * @param attr				PA-TNC attribute to be addedd
diff --git a/src/libimcv/plugins/imc_hcd/Makefile.am b/src/libimcv/plugins/imc_hcd/Makefile.am
new file mode 100644
index 0000000..db25a57
--- /dev/null
+++ b/src/libimcv/plugins/imc_hcd/Makefile.am
@@ -0,0 +1,16 @@
+AM_CPPFLAGS = \
+	-I$(top_srcdir)/src/libstrongswan \
+	-I$(top_srcdir)/src/libtncif \
+	-I$(top_srcdir)/src/libimcv
+
+AM_CFLAGS = \
+	$(PLUGIN_CFLAGS)
+
+imcv_LTLIBRARIES = imc-hcd.la
+
+imc_hcd_la_LIBADD = $(top_builddir)/src/libimcv/libimcv.la \
+	$(top_builddir)/src/libstrongswan/libstrongswan.la
+
+imc_hcd_la_SOURCES = imc_hcd.c imc_hcd_state.h imc_hcd_state.c
+
+imc_hcd_la_LDFLAGS = -module -avoid-version -no-undefined
diff --git a/src/libipsec/Makefile.in b/src/libimcv/plugins/imc_hcd/Makefile.in
similarity index 70%
copy from src/libipsec/Makefile.in
copy to src/libimcv/plugins/imc_hcd/Makefile.in
index a80d28a..da7523c 100644
--- a/src/libipsec/Makefile.in
+++ b/src/libimcv/plugins/imc_hcd/Makefile.in
@@ -78,7 +78,7 @@ PRE_UNINSTALL = :
 POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
-subdir = src/libipsec
+subdir = src/libimcv/plugins/imc_hcd
 DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
 	$(top_srcdir)/depcomp
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
@@ -125,19 +125,19 @@ am__uninstall_files_from_dir = { \
     || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
          $(am__cd) "$$dir" && rm -f $$files; }; \
   }
-am__installdirs = "$(DESTDIR)$(ipseclibdir)"
-LTLIBRARIES = $(ipseclib_LTLIBRARIES)
-libipsec_la_DEPENDENCIES =  \
+am__installdirs = "$(DESTDIR)$(imcvdir)"
+LTLIBRARIES = $(imcv_LTLIBRARIES)
+imc_hcd_la_DEPENDENCIES = $(top_builddir)/src/libimcv/libimcv.la \
 	$(top_builddir)/src/libstrongswan/libstrongswan.la
-am_libipsec_la_OBJECTS = ipsec.lo esp_context.lo esp_packet.lo \
-	ip_packet.lo ipsec_event_relay.lo ipsec_policy.lo \
-	ipsec_policy_mgr.lo ipsec_processor.lo ipsec_sa.lo \
-	ipsec_sa_mgr.lo
-libipsec_la_OBJECTS = $(am_libipsec_la_OBJECTS)
+am_imc_hcd_la_OBJECTS = imc_hcd.lo imc_hcd_state.lo
+imc_hcd_la_OBJECTS = $(am_imc_hcd_la_OBJECTS)
 AM_V_lt = $(am__v_lt_ at AM_V@)
 am__v_lt_ = $(am__v_lt_ at AM_DEFAULT_V@)
 am__v_lt_0 = --silent
 am__v_lt_1 = 
+imc_hcd_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(imc_hcd_la_LDFLAGS) $(LDFLAGS) -o $@
 AM_V_P = $(am__v_P_ at AM_V@)
 am__v_P_ = $(am__v_P_ at AM_DEFAULT_V@)
 am__v_P_0 = false
@@ -172,29 +172,13 @@ AM_V_CCLD = $(am__v_CCLD_ at AM_V@)
 am__v_CCLD_ = $(am__v_CCLD_ at AM_DEFAULT_V@)
 am__v_CCLD_0 = @echo "  CCLD    " $@;
 am__v_CCLD_1 = 
-SOURCES = $(libipsec_la_SOURCES)
-DIST_SOURCES = $(libipsec_la_SOURCES)
-RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
-	ctags-recursive dvi-recursive html-recursive info-recursive \
-	install-data-recursive install-dvi-recursive \
-	install-exec-recursive install-html-recursive \
-	install-info-recursive install-pdf-recursive \
-	install-ps-recursive install-recursive installcheck-recursive \
-	installdirs-recursive pdf-recursive ps-recursive \
-	tags-recursive uninstall-recursive
+SOURCES = $(imc_hcd_la_SOURCES)
+DIST_SOURCES = $(imc_hcd_la_SOURCES)
 am__can_run_installinfo = \
   case $$AM_UPDATE_INFO_DIR in \
     n|no|NO) false;; \
     *) (install-info --version) >/dev/null 2>&1;; \
   esac
-RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive	\
-  distclean-recursive maintainer-clean-recursive
-am__recursive_targets = \
-  $(RECURSIVE_TARGETS) \
-  $(RECURSIVE_CLEAN_TARGETS) \
-  $(am__extra_recursive_targets)
-AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
-	distdir
 am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
 # Read a list of newline-separated strings from the standard input,
 # and print each of them once, without duplicates.  Input order is
@@ -214,33 +198,7 @@ am__define_uniq_tagged_files = \
   done | $(am__uniquify_input)`
 ETAGS = etags
 CTAGS = ctags
-DIST_SUBDIRS = .
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
-am__relativize = \
-  dir0=`pwd`; \
-  sed_first='s,^\([^/]*\)/.*$$,\1,'; \
-  sed_rest='s,^[^/]*/*,,'; \
-  sed_last='s,^.*/\([^/]*\)$$,\1,'; \
-  sed_butlast='s,/*[^/]*$$,,'; \
-  while test -n "$$dir1"; do \
-    first=`echo "$$dir1" | sed -e "$$sed_first"`; \
-    if test "$$first" != "."; then \
-      if test "$$first" = ".."; then \
-        dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
-        dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
-      else \
-        first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
-        if test "$$first2" = "$$first"; then \
-          dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
-        else \
-          dir2="../$$dir2"; \
-        fi; \
-        dir0="$$dir0"/"$$first"; \
-      fi; \
-    fi; \
-    dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
-  done; \
-  reldir="$$dir2"
 ACLOCAL = @ACLOCAL@
 ALLOCA = @ALLOCA@
 AMTAR = @AMTAR@
@@ -466,36 +424,21 @@ top_srcdir = @top_srcdir@
 urandom_device = @urandom_device@
 xml_CFLAGS = @xml_CFLAGS@
 xml_LIBS = @xml_LIBS@
-ipseclib_LTLIBRARIES = libipsec.la
-libipsec_la_SOURCES = \
-ipsec.c ipsec.h \
-esp_context.c esp_context.h \
-esp_packet.c esp_packet.h \
-ip_packet.c ip_packet.h \
-ipsec_event_listener.h \
-ipsec_event_relay.c ipsec_event_relay.h \
-ipsec_policy.c ipsec_policy.h \
-ipsec_policy_mgr.c ipsec_policy_mgr.h \
-ipsec_processor.c ipsec_processor.h \
-ipsec_sa.c ipsec_sa.h \
-ipsec_sa_mgr.c ipsec_sa_mgr.h
-
-libipsec_la_LIBADD = \
-	$(top_builddir)/src/libstrongswan/libstrongswan.la
-
 AM_CPPFLAGS = \
-	-I$(top_srcdir)/src/libstrongswan
+	-I$(top_srcdir)/src/libstrongswan \
+	-I$(top_srcdir)/src/libtncif \
+	-I$(top_srcdir)/src/libimcv
 
-AM_LDFLAGS = \
-	-no-undefined
+AM_CFLAGS = \
+	$(PLUGIN_CFLAGS)
 
-EXTRA_DIST = Android.mk
- at MONOLITHIC_FALSE@SUBDIRS = .
+imcv_LTLIBRARIES = imc-hcd.la
+imc_hcd_la_LIBADD = $(top_builddir)/src/libimcv/libimcv.la \
+	$(top_builddir)/src/libstrongswan/libstrongswan.la
 
-# build optional plugins
-########################
- at MONOLITHIC_TRUE@SUBDIRS = 
-all: all-recursive
+imc_hcd_la_SOURCES = imc_hcd.c imc_hcd_state.h imc_hcd_state.c
+imc_hcd_la_LDFLAGS = -module -avoid-version -no-undefined
+all: all-am
 
 .SUFFIXES:
 .SUFFIXES: .c .lo .o .obj
@@ -508,9 +451,9 @@ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
 	      exit 1;; \
 	  esac; \
 	done; \
-	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/libipsec/Makefile'; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/libimcv/plugins/imc_hcd/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
-	  $(AUTOMAKE) --gnu src/libipsec/Makefile
+	  $(AUTOMAKE) --gnu src/libimcv/plugins/imc_hcd/Makefile
 .PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
@@ -530,33 +473,33 @@ $(ACLOCAL_M4):  $(am__aclocal_m4_deps)
 	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
 $(am__aclocal_m4_deps):
 
-install-ipseclibLTLIBRARIES: $(ipseclib_LTLIBRARIES)
+install-imcvLTLIBRARIES: $(imcv_LTLIBRARIES)
 	@$(NORMAL_INSTALL)
-	@list='$(ipseclib_LTLIBRARIES)'; test -n "$(ipseclibdir)" || list=; \
+	@list='$(imcv_LTLIBRARIES)'; test -n "$(imcvdir)" || list=; \
 	list2=; for p in $$list; do \
 	  if test -f $$p; then \
 	    list2="$$list2 $$p"; \
 	  else :; fi; \
 	done; \
 	test -z "$$list2" || { \
-	  echo " $(MKDIR_P) '$(DESTDIR)$(ipseclibdir)'"; \
-	  $(MKDIR_P) "$(DESTDIR)$(ipseclibdir)" || exit 1; \
-	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(ipseclibdir)'"; \
-	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(ipseclibdir)"; \
+	  echo " $(MKDIR_P) '$(DESTDIR)$(imcvdir)'"; \
+	  $(MKDIR_P) "$(DESTDIR)$(imcvdir)" || exit 1; \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(imcvdir)'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(imcvdir)"; \
 	}
 
-uninstall-ipseclibLTLIBRARIES:
+uninstall-imcvLTLIBRARIES:
 	@$(NORMAL_UNINSTALL)
-	@list='$(ipseclib_LTLIBRARIES)'; test -n "$(ipseclibdir)" || list=; \
+	@list='$(imcv_LTLIBRARIES)'; test -n "$(imcvdir)" || list=; \
 	for p in $$list; do \
 	  $(am__strip_dir) \
-	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(ipseclibdir)/$$f'"; \
-	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(ipseclibdir)/$$f"; \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(imcvdir)/$$f'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(imcvdir)/$$f"; \
 	done
 
-clean-ipseclibLTLIBRARIES:
-	-test -z "$(ipseclib_LTLIBRARIES)" || rm -f $(ipseclib_LTLIBRARIES)
-	@list='$(ipseclib_LTLIBRARIES)'; \
+clean-imcvLTLIBRARIES:
+	-test -z "$(imcv_LTLIBRARIES)" || rm -f $(imcv_LTLIBRARIES)
+	@list='$(imcv_LTLIBRARIES)'; \
 	locs=`for p in $$list; do echo $$p; done | \
 	      sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
 	      sort -u`; \
@@ -565,8 +508,8 @@ clean-ipseclibLTLIBRARIES:
 	  rm -f $${locs}; \
 	}
 
-libipsec.la: $(libipsec_la_OBJECTS) $(libipsec_la_DEPENDENCIES) $(EXTRA_libipsec_la_DEPENDENCIES) 
-	$(AM_V_CCLD)$(LINK) -rpath $(ipseclibdir) $(libipsec_la_OBJECTS) $(libipsec_la_LIBADD) $(LIBS)
+imc-hcd.la: $(imc_hcd_la_OBJECTS) $(imc_hcd_la_DEPENDENCIES) $(EXTRA_imc_hcd_la_DEPENDENCIES) 
+	$(AM_V_CCLD)$(imc_hcd_la_LINK) -rpath $(imcvdir) $(imc_hcd_la_OBJECTS) $(imc_hcd_la_LIBADD) $(LIBS)
 
 mostlyclean-compile:
 	-rm -f *.$(OBJEXT)
@@ -574,16 +517,8 @@ mostlyclean-compile:
 distclean-compile:
 	-rm -f *.tab.c
 
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/esp_context.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/esp_packet.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/ip_packet.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/ipsec.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/ipsec_event_relay.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/ipsec_policy.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/ipsec_policy_mgr.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/ipsec_processor.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/ipsec_sa.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/ipsec_sa_mgr.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/imc_hcd.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/imc_hcd_state.Plo at am__quote@
 
 .c.o:
 @am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
@@ -615,61 +550,14 @@ mostlyclean-libtool:
 clean-libtool:
 	-rm -rf .libs _libs
 
-# This directory's subdirectories are mostly independent; you can cd
-# into them and run 'make' without going through this Makefile.
-# To change the values of 'make' variables: instead of editing Makefiles,
-# (1) if the variable is set in 'config.status', edit 'config.status'
-#     (which will cause the Makefiles to be regenerated when you run 'make');
-# (2) otherwise, pass the desired values on the 'make' command line.
-$(am__recursive_targets):
-	@fail=; \
-	if $(am__make_keepgoing); then \
-	  failcom='fail=yes'; \
-	else \
-	  failcom='exit 1'; \
-	fi; \
-	dot_seen=no; \
-	target=`echo $@ | sed s/-recursive//`; \
-	case "$@" in \
-	  distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
-	  *) list='$(SUBDIRS)' ;; \
-	esac; \
-	for subdir in $$list; do \
-	  echo "Making $$target in $$subdir"; \
-	  if test "$$subdir" = "."; then \
-	    dot_seen=yes; \
-	    local_target="$$target-am"; \
-	  else \
-	    local_target="$$target"; \
-	  fi; \
-	  ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
-	  || eval $$failcom; \
-	done; \
-	if test "$$dot_seen" = "no"; then \
-	  $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
-	fi; test -z "$$fail"
-
 ID: $(am__tagged_files)
 	$(am__define_uniq_tagged_files); mkid -fID $$unique
-tags: tags-recursive
+tags: tags-am
 TAGS: tags
 
 tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
 	set x; \
 	here=`pwd`; \
-	if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
-	  include_option=--etags-include; \
-	  empty_fix=.; \
-	else \
-	  include_option=--include; \
-	  empty_fix=; \
-	fi; \
-	list='$(SUBDIRS)'; for subdir in $$list; do \
-	  if test "$$subdir" = .; then :; else \
-	    test ! -f $$subdir/TAGS || \
-	      set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
-	  fi; \
-	done; \
 	$(am__define_uniq_tagged_files); \
 	shift; \
 	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
@@ -682,7 +570,7 @@ tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
 	      $$unique; \
 	  fi; \
 	fi
-ctags: ctags-recursive
+ctags: ctags-am
 
 CTAGS: ctags
 ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
@@ -695,7 +583,7 @@ GTAGS:
 	here=`$(am__cd) $(top_builddir) && pwd` \
 	  && $(am__cd) $(top_srcdir) \
 	  && gtags -i $(GTAGS_ARGS) "$$here"
-cscopelist: cscopelist-recursive
+cscopelist: cscopelist-am
 
 cscopelist-am: $(am__tagged_files)
 	list='$(am__tagged_files)'; \
@@ -744,48 +632,22 @@ distdir: $(DISTFILES)
 	    || exit 1; \
 	  fi; \
 	done
-	@list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
-	  if test "$$subdir" = .; then :; else \
-	    $(am__make_dryrun) \
-	      || test -d "$(distdir)/$$subdir" \
-	      || $(MKDIR_P) "$(distdir)/$$subdir" \
-	      || exit 1; \
-	    dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
-	    $(am__relativize); \
-	    new_distdir=$$reldir; \
-	    dir1=$$subdir; dir2="$(top_distdir)"; \
-	    $(am__relativize); \
-	    new_top_distdir=$$reldir; \
-	    echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
-	    echo "     am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
-	    ($(am__cd) $$subdir && \
-	      $(MAKE) $(AM_MAKEFLAGS) \
-	        top_distdir="$$new_top_distdir" \
-	        distdir="$$new_distdir" \
-		am__remove_distdir=: \
-		am__skip_length_check=: \
-		am__skip_mode_fix=: \
-	        distdir) \
-	      || exit 1; \
-	  fi; \
-	done
 check-am: all-am
-check: check-recursive
+check: check-am
 all-am: Makefile $(LTLIBRARIES)
-installdirs: installdirs-recursive
-installdirs-am:
-	for dir in "$(DESTDIR)$(ipseclibdir)"; do \
+installdirs:
+	for dir in "$(DESTDIR)$(imcvdir)"; do \
 	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
 	done
-install: install-recursive
-install-exec: install-exec-recursive
-install-data: install-data-recursive
-uninstall: uninstall-recursive
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
 
 install-am: all-am
 	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
 
-installcheck: installcheck-recursive
+installcheck: installcheck-am
 install-strip:
 	if test -z '$(STRIP)'; then \
 	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
@@ -807,94 +669,93 @@ 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."
-clean: clean-recursive
+clean: clean-am
 
-clean-am: clean-generic clean-ipseclibLTLIBRARIES clean-libtool \
+clean-am: clean-generic clean-imcvLTLIBRARIES clean-libtool \
 	mostlyclean-am
 
-distclean: distclean-recursive
+distclean: distclean-am
 	-rm -rf ./$(DEPDIR)
 	-rm -f Makefile
 distclean-am: clean-am distclean-compile distclean-generic \
 	distclean-tags
 
-dvi: dvi-recursive
+dvi: dvi-am
 
 dvi-am:
 
-html: html-recursive
+html: html-am
 
 html-am:
 
-info: info-recursive
+info: info-am
 
 info-am:
 
-install-data-am: install-ipseclibLTLIBRARIES
+install-data-am: install-imcvLTLIBRARIES
 
-install-dvi: install-dvi-recursive
+install-dvi: install-dvi-am
 
 install-dvi-am:
 
 install-exec-am:
 
-install-html: install-html-recursive
+install-html: install-html-am
 
 install-html-am:
 
-install-info: install-info-recursive
+install-info: install-info-am
 
 install-info-am:
 
 install-man:
 
-install-pdf: install-pdf-recursive
+install-pdf: install-pdf-am
 
 install-pdf-am:
 
-install-ps: install-ps-recursive
+install-ps: install-ps-am
 
 install-ps-am:
 
 installcheck-am:
 
-maintainer-clean: maintainer-clean-recursive
+maintainer-clean: maintainer-clean-am
 	-rm -rf ./$(DEPDIR)
 	-rm -f Makefile
 maintainer-clean-am: distclean-am maintainer-clean-generic
 
-mostlyclean: mostlyclean-recursive
+mostlyclean: mostlyclean-am
 
 mostlyclean-am: mostlyclean-compile mostlyclean-generic \
 	mostlyclean-libtool
 
-pdf: pdf-recursive
+pdf: pdf-am
 
 pdf-am:
 
-ps: ps-recursive
+ps: ps-am
 
 ps-am:
 
-uninstall-am: uninstall-ipseclibLTLIBRARIES
-
-.MAKE: $(am__recursive_targets) install-am install-strip
-
-.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
-	check-am clean clean-generic clean-ipseclibLTLIBRARIES \
-	clean-libtool cscopelist-am ctags ctags-am distclean \
-	distclean-compile distclean-generic distclean-libtool \
-	distclean-tags 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-ipseclibLTLIBRARIES install-man install-pdf \
-	install-pdf-am install-ps install-ps-am install-strip \
-	installcheck installcheck-am installdirs installdirs-am \
-	maintainer-clean maintainer-clean-generic mostlyclean \
-	mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
-	pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \
-	uninstall-ipseclibLTLIBRARIES
+uninstall-am: uninstall-imcvLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+	clean-imcvLTLIBRARIES clean-libtool cscopelist-am ctags \
+	ctags-am distclean distclean-compile distclean-generic \
+	distclean-libtool distclean-tags 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-imcvLTLIBRARIES 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-compile mostlyclean-generic \
+	mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
+	uninstall-am uninstall-imcvLTLIBRARIES
 
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
diff --git a/src/libimcv/plugins/imc_hcd/imc_hcd.c b/src/libimcv/plugins/imc_hcd/imc_hcd.c
new file mode 100644
index 0000000..b631683
--- /dev/null
+++ b/src/libimcv/plugins/imc_hcd/imc_hcd.c
@@ -0,0 +1,791 @@
+/*
+ * Copyright (C) 2015 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
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include "imc_hcd_state.h"
+
+#include <imc/imc_agent.h>
+#include <imc/imc_msg.h>
+#include <imc/imc_os_info.h>
+#include <generic/generic_attr_bool.h>
+#include <generic/generic_attr_chunk.h>
+#include <generic/generic_attr_string.h>
+#include <ietf/ietf_attr.h>
+#include <ietf/ietf_attr_attr_request.h>
+#include "ietf/ietf_attr_fwd_enabled.h"
+#include <pwg/pwg_attr.h>
+#include <pwg/pwg_attr_vendor_smi_code.h>
+
+#include <tncif_pa_subtypes.h>
+
+#include <pen/pen.h>
+#include <utils/debug.h>
+
+/* IMC definitions */
+
+static const char imc_name[] = "HCD";
+
+static pen_type_t msg_types[] = {
+	{ PEN_PWG, PA_SUBTYPE_PWG_HCD_SYSTEM },
+	{ PEN_PWG, PA_SUBTYPE_PWG_HCD_CONSOLE },
+	{ PEN_PWG, PA_SUBTYPE_PWG_HCD_MARKER },
+	{ PEN_PWG, PA_SUBTYPE_PWG_HCD_FINISHER },
+	{ PEN_PWG, PA_SUBTYPE_PWG_HCD_INTERFACE },
+	{ PEN_PWG, PA_SUBTYPE_PWG_HCD_SCANNER }
+};
+
+static imc_agent_t *imc_hcd;
+static imc_os_info_t *os;
+
+typedef struct section_subtype_t section_subtype_t;
+
+struct section_subtype_t {
+	char *section;
+	pa_subtype_pwg_t subtype;
+};
+
+static section_subtype_t section_subtypes[] = {
+	{ "system",    PA_SUBTYPE_PWG_HCD_SYSTEM    },
+	{ "console",   PA_SUBTYPE_PWG_HCD_CONSOLE   },
+	{ "marker",    PA_SUBTYPE_PWG_HCD_MARKER    },
+	{ "finisher",  PA_SUBTYPE_PWG_HCD_FINISHER  },
+	{ "interface", PA_SUBTYPE_PWG_HCD_INTERFACE },
+	{ "scanner"  , PA_SUBTYPE_PWG_HCD_SCANNER   }
+};
+
+typedef struct quadruple_t quadruple_t;
+
+struct quadruple_t {
+	char *section;
+	pwg_attr_t name_attr;
+	pwg_attr_t patches_attr;
+	pwg_attr_t string_version_attr;
+	pwg_attr_t version_attr;
+};
+
+static quadruple_t quadruples[] = {
+	{ "firmware",
+	   PWG_HCD_FIRMWARE_NAME, PWG_HCD_FIRMWARE_PATCHES,
+	   PWG_HCD_FIRMWARE_STRING_VERSION, PWG_HCD_FIRMWARE_VERSION },
+	{ "resident_application",
+	   PWG_HCD_RESIDENT_APP_NAME, PWG_HCD_RESIDENT_APP_PATCHES,
+	   PWG_HCD_RESIDENT_APP_STRING_VERSION, PWG_HCD_RESIDENT_APP_VERSION },
+	{ "user_application",
+	   PWG_HCD_USER_APP_NAME, PWG_HCD_USER_APP_PATCHES,
+	   PWG_HCD_USER_APP_STRING_VERSION, PWG_HCD_USER_APP_VERSION }
+};
+
+/**
+ * see section 3.8.1 of TCG TNC IF-IMC Specification 1.3
+ */
+TNC_Result TNC_IMC_API TNC_IMC_Initialize(TNC_IMCID imc_id,
+										  TNC_Version min_version,
+										  TNC_Version max_version,
+										  TNC_Version *actual_version)
+{
+	if (imc_hcd)
+	{
+		DBG1(DBG_IMC, "IMC \"%s\" has already been initialized", imc_name);
+		return TNC_RESULT_ALREADY_INITIALIZED;
+	}
+	imc_hcd = imc_agent_create(imc_name, msg_types, countof(msg_types),
+							  imc_id, actual_version);
+	if (!imc_hcd)
+	{
+		return TNC_RESULT_FATAL;
+	}
+
+	os = imc_os_info_create();
+	if (!os)
+	{
+		imc_hcd->destroy(imc_hcd);
+		imc_hcd = NULL;
+
+		return TNC_RESULT_FATAL;
+	}
+
+	if (min_version > TNC_IFIMC_VERSION_1 || max_version < TNC_IFIMC_VERSION_1)
+	{
+		DBG1(DBG_IMC, "no common IF-IMC version");
+		return TNC_RESULT_NO_COMMON_VERSION;
+	}
+	return TNC_RESULT_SUCCESS;
+}
+
+/**
+ * see section 3.8.2 of TCG TNC IF-IMC Specification 1.3
+ */
+TNC_Result TNC_IMC_API TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id,
+				TNC_ConnectionID connection_id, TNC_ConnectionState new_state)
+{
+	imc_state_t *state;
+
+	if (!imc_hcd)
+	{
+		DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
+		return TNC_RESULT_NOT_INITIALIZED;
+	}
+	switch (new_state)
+	{
+		case TNC_CONNECTION_STATE_CREATE:
+			state = imc_hcd_state_create(connection_id);
+			return imc_hcd->create_state(imc_hcd, state);
+		case TNC_CONNECTION_STATE_HANDSHAKE:
+			if (imc_hcd->change_state(imc_hcd, connection_id, new_state,
+				&state) != TNC_RESULT_SUCCESS)
+			{
+				return TNC_RESULT_FATAL;
+			}
+			state->set_result(state, imc_id,
+							  TNC_IMV_EVALUATION_RESULT_DONT_KNOW);
+			return TNC_RESULT_SUCCESS;
+		case TNC_CONNECTION_STATE_DELETE:
+			return imc_hcd->delete_state(imc_hcd, connection_id);
+		default:
+			return imc_hcd->change_state(imc_hcd, connection_id,
+											 new_state, NULL);
+	}
+}
+
+/**
+ * Add AttributesNaturalLanguage attribute to send queue
+ */
+static void add_attrs_natural_lang(imc_msg_t *msg, char *section)
+{
+	pa_tnc_attr_t *attr;
+	char *string;
+
+	string = lib->settings->get_str(lib->settings,
+				"%s.plugins.imc-hcd.subtypes.%s.attributes_natural_language",
+				"en", lib->ns, section);
+	DBG2(DBG_IMC, "  %N: %s", pwg_attr_names, PWG_HCD_ATTRS_NATURAL_LANG,
+				string);
+	attr = generic_attr_string_create(chunk_from_str(string),
+				pen_type_create(PEN_PWG, PWG_HCD_ATTRS_NATURAL_LANG));
+	msg->add_attribute(msg, attr);
+}
+
+/**
+ * Add DefaultPasswordEnabled attribute to send queue
+ */
+static void add_default_pwd_enabled(imc_msg_t *msg)
+{
+	pa_tnc_attr_t *attr;
+	bool status;
+
+	status = os->get_default_pwd_status(os);
+	DBG2(DBG_IMC, "  %N: %s", pwg_attr_names, PWG_HCD_DEFAULT_PWD_ENABLED,
+				status ? "yes" : "no");
+	attr = generic_attr_bool_create(status,
+				pen_type_create(PEN_PWG, PWG_HCD_DEFAULT_PWD_ENABLED));
+	msg->add_attribute(msg, attr);
+}
+
+/**
+ * Add ForwardingEnabled attribute to send queue
+ */
+static void add_forwarding_enabled(imc_msg_t *msg)
+{
+	pa_tnc_attr_t *attr;
+	os_fwd_status_t fwd_status;
+
+	fwd_status = os->get_fwd_status(os);
+	DBG2(DBG_IMC, "  %N: %N", pwg_attr_names, PWG_HCD_FORWARDING_ENABLED,
+				os_fwd_status_names, fwd_status);
+	attr = ietf_attr_fwd_enabled_create(fwd_status,
+				pen_type_create(PEN_PWG, PWG_HCD_FORWARDING_ENABLED));
+	msg->add_attribute(msg, attr);
+}
+
+/**
+ * Add MachineTypeModel attribute to send queue
+ */
+static void add_machine_type_model(imc_msg_t *msg)
+{
+	pa_tnc_attr_t *attr;
+	char *string;
+
+	string = lib->settings->get_str(lib->settings,
+				"%s.plugins.imc-hcd.subtypes.system.machine_type_model",
+				"", lib->ns);
+	DBG2(DBG_IMC, "  %N: %s", pwg_attr_names, PWG_HCD_MACHINE_TYPE_MODEL,
+				string);
+	attr = generic_attr_string_create(chunk_from_str(string),
+				pen_type_create(PEN_PWG, PWG_HCD_MACHINE_TYPE_MODEL));
+	msg->add_attribute(msg, attr);
+}
+
+/**
+ * Add PSTNFaxEnabled attribute to send queue
+ */
+static void add_pstn_fax_enabled(imc_msg_t *msg)
+{
+	pa_tnc_attr_t *attr;
+	bool status;
+
+	status = lib->settings->get_bool(lib->settings,
+				"%s.plugins.imc-hcd.subtypes.system.pstn_fax_enabled",
+				FALSE, lib->ns);
+	DBG2(DBG_IMC, "  %N: %s", pwg_attr_names, PWG_HCD_PSTN_FAX_ENABLED,
+				status ? "yes" : "no");
+	attr = generic_attr_bool_create(status,
+				pen_type_create(PEN_PWG, PWG_HCD_PSTN_FAX_ENABLED));
+	msg->add_attribute(msg, attr);
+}
+
+/**
+ * Add TimeSource attribute to send queue
+ */
+static void add_time_source(imc_msg_t *msg)
+{
+	pa_tnc_attr_t *attr;
+	char *string;
+
+	string = lib->settings->get_str(lib->settings,
+				"%s.plugins.imc-hcd.subtypes.system.time_source",
+				"", lib->ns);
+	DBG2(DBG_IMC, "  %N: %s", pwg_attr_names, PWG_HCD_TIME_SOURCE,
+				string);
+	attr = generic_attr_string_create(chunk_from_str(string),
+				pen_type_create(PEN_PWG, PWG_HCD_TIME_SOURCE));
+	msg->add_attribute(msg, attr);
+}
+
+/**
+ * Add UserApplicationEnabled attribute to send queue
+ */
+static void add_user_app_enabled(imc_msg_t *msg)
+{
+	pa_tnc_attr_t *attr;
+	bool status;
+
+	status = lib->settings->get_bool(lib->settings,
+				"%s.plugins.imc-hcd.subtypes.system.user_application_enabled",
+				FALSE, lib->ns);
+	DBG2(DBG_IMC, "  %N: %s", pwg_attr_names, PWG_HCD_USER_APP_ENABLED,
+				status ? "yes" : "no");
+	attr = generic_attr_bool_create(status,
+				pen_type_create(PEN_PWG, PWG_HCD_USER_APP_ENABLED));
+	msg->add_attribute(msg, attr);
+}
+
+/**
+ * Add UserApplicationPersistenceEnabled attribute to send queue
+ */
+static void add_user_app_persist_enabled(imc_msg_t *msg)
+{
+	pa_tnc_attr_t *attr;
+	bool status;
+
+	status = lib->settings->get_bool(lib->settings,
+				"%s.plugins.imc-hcd.subtypes.system.user_application_persistence.enabled",
+				FALSE, lib->ns);
+	DBG2(DBG_IMC, "  %N: %s", pwg_attr_names, PWG_HCD_USER_APP_PERSIST_ENABLED,
+				status ? "yes" : "no");
+	attr = generic_attr_bool_create(status,
+				pen_type_create(PEN_PWG, PWG_HCD_USER_APP_PERSIST_ENABLED));
+	msg->add_attribute(msg, attr);
+}
+
+/**
+ * Add VendorName attribute to send queue
+ */
+static void add_vendor_name(imc_msg_t *msg)
+{
+	pa_tnc_attr_t *attr;
+	char *string;
+
+	string = lib->settings->get_str(lib->settings,
+				"%s.plugins.imc-hcd.subtypes.system.vendor_name",
+				"", lib->ns);
+	DBG2(DBG_IMC, "  %N: %s", pwg_attr_names, PWG_HCD_VENDOR_NAME,
+				string);
+	attr = generic_attr_string_create(chunk_from_str(string),
+				pen_type_create(PEN_PWG, PWG_HCD_VENDOR_NAME));
+	msg->add_attribute(msg, attr);
+}
+
+/**
+ * Add VendorSMICode attribute to send queue
+ */
+static void add_vendor_smi_code(imc_msg_t *msg)
+{
+	pa_tnc_attr_t *attr;
+	int smi_code;
+
+	smi_code = lib->settings->get_int(lib->settings,
+				"%s.plugins.imc-hcd.subtypes.system.vendor_smi_code",
+				0, lib->ns);
+	DBG2(DBG_IMC, "  %N: 0x%06x (%d)", pwg_attr_names, PWG_HCD_VENDOR_SMI_CODE,
+				smi_code, smi_code);
+	attr = pwg_attr_vendor_smi_code_create(smi_code);
+	msg->add_attribute(msg, attr);
+}
+
+/**
+ * Add CertificationState attribute to send queue
+ */
+static void add_certification_state(imc_msg_t *msg)
+{
+	pa_tnc_attr_t *attr;
+	char *hex_string;
+	chunk_t blob;
+
+	hex_string = lib->settings->get_str(lib->settings,
+					"%s.plugins.imc-hcd.subtypes.system.certification_state",
+					NULL, lib->ns);
+	if (hex_string)
+	{
+		blob = chunk_from_hex(chunk_from_str(hex_string), NULL);
+	
+		DBG2(DBG_IMC, "  %N: %B", pwg_attr_names, PWG_HCD_CERTIFICATION_STATE,
+					&blob);
+		attr = generic_attr_chunk_create(blob,
+					pen_type_create(PEN_PWG, PWG_HCD_CERTIFICATION_STATE));
+		msg->add_attribute(msg, attr);
+		chunk_free(&blob);
+	}
+}
+
+/**
+ * Add CertificationState attribute to send queue
+ */
+static void add_configuration_state(imc_msg_t *msg)
+{
+	pa_tnc_attr_t *attr;
+	char *hex_string;
+	chunk_t blob;
+
+	hex_string = lib->settings->get_str(lib->settings,
+					"%s.plugins.imc-hcd.subtypes.system.configuration_state",
+					NULL, lib->ns);
+	if (hex_string)
+	{
+		blob = chunk_from_hex(chunk_from_str(hex_string), NULL);
+	
+		DBG2(DBG_IMC, "  %N: %B", pwg_attr_names, PWG_HCD_CONFIGURATION_STATE,
+					&blob);
+		attr = generic_attr_chunk_create(blob,
+					pen_type_create(PEN_PWG, PWG_HCD_CONFIGURATION_STATE));
+		msg->add_attribute(msg, attr);
+		chunk_free(&blob);
+	}
+}
+
+/**
+ * Add Correlated Attributes to send queue
+ */
+static void add_quadruple(imc_msg_t *msg, char *section, quadruple_t *quad)
+{
+	pa_tnc_attr_t *attr;
+	const size_t version_len = 16;
+	char version[version_len];
+	char hex_version_default[] = "00000000000000000000000000000000";
+	char *app, *name, *patches, *string_version, *hex_version;
+	size_t len;
+	chunk_t num_version;
+	enumerator_t *enumerator;
+
+	enumerator = lib->settings->create_section_enumerator(lib->settings,
+					"%s.plugins.imc-hcd.subtypes.%s.%s",
+					lib->ns, section, quad->section);
+	while (enumerator->enumerate(enumerator, &app))
+	{
+		name = lib->settings->get_str(lib->settings,
+					"%s.plugins.imc-hcd.subtypes.%s.%s.%s.name",
+					"",	lib->ns, section, quad->section, app);
+		patches = lib->settings->get_str(lib->settings,
+					"%s.plugins.imc-hcd.subtypes.%s.%s.%s.patches",
+					"", lib->ns, section, quad->section, app);
+		string_version = lib->settings->get_str(lib->settings,
+					"%s.plugins.imc-hcd.subtypes.%s.%s.%s.string_version",
+					"",	lib->ns, section, quad->section, app);
+		hex_version = lib->settings->get_str(lib->settings,
+					"%s.plugins.imc-hcd.subtypes.%s.%s.%s.version", 
+					hex_version_default, lib->ns, section, quad->section, app);
+
+		/* convert hex string into binary chunk */
+		if (strlen(hex_version) > 2 * version_len)
+		{
+			hex_version = hex_version_default;
+		}
+		num_version = chunk_from_hex(chunk_from_str(hex_version), version);
+
+		DBG2(DBG_IMC, "--- %s ---", app);
+
+		DBG2(DBG_IMC, "  %N: %s", pwg_attr_names, quad->name_attr, name);
+		attr = generic_attr_string_create(chunk_from_str(name),
+						pen_type_create(PEN_PWG, quad->name_attr));
+		msg->add_attribute(msg, attr);
+
+		/* remove any trailing LF from patches string for logging */
+		len = strlen(patches);
+		if (len && (patches[len - 1] == '\n'))
+		{
+			len--;
+		}
+		DBG2(DBG_IMC, "  %N:%s%.*s", pwg_attr_names, quad->patches_attr,
+						len ? "\n" : " ", len, patches);
+		attr = generic_attr_string_create(chunk_from_str(patches),
+						pen_type_create(PEN_PWG, quad->patches_attr));
+		msg->add_attribute(msg, attr);
+
+		DBG2(DBG_IMC, "  %N: %s", pwg_attr_names, quad->string_version_attr,
+						string_version);
+		attr = generic_attr_string_create(chunk_from_str(string_version),
+						pen_type_create(PEN_PWG, quad->string_version_attr));
+		msg->add_attribute(msg, attr);
+
+		DBG2(DBG_IMC, "  %N: %#B", pwg_attr_names, quad->version_attr, &num_version);
+		attr = generic_attr_chunk_create(num_version,
+						pen_type_create(PEN_PWG, quad->version_attr));
+		msg->add_attribute(msg, attr);
+	}
+	enumerator->destroy(enumerator);
+}
+
+/**
+ * see section 3.8.3 of TCG TNC IF-IMC Specification 1.3
+ */
+TNC_Result TNC_IMC_API TNC_IMC_BeginHandshake(TNC_IMCID imc_id,
+											  TNC_ConnectionID connection_id)
+{
+	imc_state_t *state;
+	imc_msg_t *out_msg;
+	TNC_Result result = TNC_RESULT_SUCCESS;
+	pa_subtype_pwg_t subtype;
+	pen_type_t msg_type;
+	enumerator_t *enumerator;
+	char *section;
+	int i;
+
+	if (!imc_hcd)
+	{
+		DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
+		return TNC_RESULT_NOT_INITIALIZED;
+	}
+	if (!imc_hcd->get_state(imc_hcd, connection_id, &state))
+	{
+		return TNC_RESULT_FATAL;
+	}
+
+	/* Enumerate over all HCD subtype sections */
+	enumerator = lib->settings->create_section_enumerator(lib->settings,
+						"%s.plugins.imc-hcd.subtypes", lib->ns);
+	while (enumerator->enumerate(enumerator, &section) &&
+		   result == TNC_RESULT_SUCCESS)
+	{
+		subtype = PA_SUBTYPE_PWG_HCD_UNKNOWN;
+
+		for (i = 0; i < countof(section_subtypes); i++)
+		{
+			if (streq(section, section_subtypes[i].section))
+			{
+				subtype = section_subtypes[i].subtype;
+				break;
+			}
+		}
+		if (subtype == PA_SUBTYPE_PWG_HCD_UNKNOWN)
+		{
+			DBG1(DBG_IMC, "HCD subtype '%s' not supported", section);
+			continue;
+		}
+		DBG2(DBG_IMC, "retrieving attributes for PA subtype %N/%N",
+			 pen_names, PEN_PWG, pa_subtype_pwg_names, subtype);
+
+		msg_type = pen_type_create(PEN_PWG, subtype);
+		out_msg = imc_msg_create(imc_hcd, state, connection_id, imc_id,
+								 TNC_IMVID_ANY, msg_type);
+
+		/* mandatory attributes that are always sent without request */
+		add_attrs_natural_lang(out_msg, section);
+		if (subtype == PA_SUBTYPE_PWG_HCD_SYSTEM)
+		{
+			add_default_pwd_enabled(out_msg);
+			add_forwarding_enabled(out_msg);
+			add_machine_type_model(out_msg);
+			add_pstn_fax_enabled(out_msg);
+			add_time_source(out_msg);
+			add_vendor_name(out_msg);
+			add_vendor_smi_code(out_msg);
+			add_user_app_enabled(out_msg);
+			add_user_app_persist_enabled(out_msg);
+		}
+		if (lib->settings->get_bool(lib->settings,
+								"%s.plugins.imc-hcd.push_info", FALSE, lib->ns))
+		{
+			/* correlated attributes */
+			for (i = 0; i < countof(quadruples); i++)
+			{
+				add_quadruple(out_msg, section, &quadruples[i]);
+			}
+		}
+
+		/* send PA-TNC message with the excl flag not set */
+		result = out_msg->send(out_msg, FALSE);
+		out_msg->destroy(out_msg);
+	}
+	enumerator->destroy(enumerator);
+
+	return result;
+}
+
+static TNC_Result receive_message(imc_state_t *state, imc_msg_t *in_msg)
+{
+	imc_msg_t *out_msg;
+	enumerator_t *enumerator;
+	pa_tnc_attr_t *attr;
+	pen_type_t type, msg_type;
+	TNC_Result result;
+	char *section = NULL;
+	int i;
+	bool fatal_error = FALSE, pushed_info;
+
+	/* generate an outgoing PA-TNC message - we might need it */
+	out_msg = imc_msg_create_as_reply(in_msg);
+
+	/* parse received PA-TNC message and handle local and remote errors */
+	result = in_msg->receive(in_msg, out_msg, &fatal_error);
+	if (result != TNC_RESULT_SUCCESS)
+	{
+		out_msg->destroy(out_msg);
+		return result;
+	}
+	msg_type = in_msg->get_msg_type(in_msg);
+
+	for (i = 0; i < countof(section_subtypes); i++)
+	{
+		if (msg_type.type == section_subtypes[i].subtype)
+		{
+			section = section_subtypes[i].section;
+			break;
+		}
+	}
+	pushed_info = lib->settings->get_bool(lib->settings,
+						"%s.plugins.imc-hcd.push_info", FALSE, lib->ns);
+
+	/* analyze PA-TNC attributes */
+	enumerator = in_msg->create_attribute_enumerator(in_msg);
+	while (enumerator->enumerate(enumerator, &attr))
+	{
+		type = attr->get_type(attr);
+
+		if (type.vendor_id == PEN_IETF)
+		{
+			if (type.type == IETF_ATTR_ATTRIBUTE_REQUEST)
+			{
+				ietf_attr_attr_request_t *attr_cast;
+				pen_type_t *entry;
+				enumerator_t *e;
+
+				attr_cast = (ietf_attr_attr_request_t*)attr;
+
+				e = attr_cast->create_enumerator(attr_cast);
+				while (e->enumerate(e, &entry))
+				{
+					if (entry->vendor_id == PEN_PWG)
+					{
+						switch (entry->type)
+						{
+							case PWG_HCD_ATTRS_NATURAL_LANG:
+								add_attrs_natural_lang(out_msg, section);
+								break;
+							case PWG_HCD_DEFAULT_PWD_ENABLED:
+								add_default_pwd_enabled(out_msg);
+								break;
+							case PWG_HCD_FORWARDING_ENABLED:
+								add_forwarding_enabled(out_msg);
+								break;
+							case PWG_HCD_MACHINE_TYPE_MODEL:
+								add_machine_type_model(out_msg);
+								break;
+							case PWG_HCD_PSTN_FAX_ENABLED:
+								add_pstn_fax_enabled(out_msg);
+								break;
+							case PWG_HCD_TIME_SOURCE:
+								add_time_source(out_msg);
+								break;
+							case PWG_HCD_USER_APP_ENABLED:
+								add_user_app_enabled(out_msg);
+								break;
+							case PWG_HCD_USER_APP_PERSIST_ENABLED:
+								add_user_app_persist_enabled(out_msg);
+								break;
+							case PWG_HCD_VENDOR_NAME:
+								add_vendor_name(out_msg);
+								break;
+							case PWG_HCD_VENDOR_SMI_CODE:
+								add_vendor_smi_code(out_msg);
+								break;
+							case PWG_HCD_CERTIFICATION_STATE:
+								add_certification_state(out_msg);
+								break;
+							case PWG_HCD_CONFIGURATION_STATE:
+								add_configuration_state(out_msg);
+								break;
+							default:
+								if (pushed_info)
+								{
+									continue;
+								}
+						}
+
+						/* if not pushed, deliver on request */
+						switch (entry->type)
+						{
+							case PWG_HCD_FIRMWARE_NAME:
+								add_quadruple(out_msg, section, &quadruples[0]);
+								break;
+							case PWG_HCD_RESIDENT_APP_NAME:
+								add_quadruple(out_msg, section, &quadruples[1]);
+								break;
+							case PWG_HCD_USER_APP_NAME:
+								add_quadruple(out_msg, section, &quadruples[2]);
+								break;
+							default:
+								break;
+						}
+					}
+				}
+				e->destroy(e);
+			}
+		}
+	}
+	enumerator->destroy(enumerator);
+
+	if (fatal_error)
+	{
+		result = TNC_RESULT_FATAL;
+	}
+	else
+	{
+		/* send PA-TNC message with the EXCL flag set */
+		result = out_msg->send(out_msg, TRUE);
+	}
+	out_msg->destroy(out_msg);
+
+	return result;
+}
+
+/**
+ * see section 3.8.4 of TCG TNC IF-IMC Specification 1.3
+ */
+TNC_Result TNC_IMC_API TNC_IMC_ReceiveMessage(TNC_IMCID imc_id,
+											  TNC_ConnectionID connection_id,
+											  TNC_BufferReference msg,
+											  TNC_UInt32 msg_len,
+											  TNC_MessageType msg_type)
+{
+	imc_state_t *state;
+	imc_msg_t *in_msg;
+	TNC_Result result;
+
+	if (!imc_hcd)
+	{
+		DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
+		return TNC_RESULT_NOT_INITIALIZED;
+	}
+	if (!imc_hcd->get_state(imc_hcd, connection_id, &state))
+	{
+		return TNC_RESULT_FATAL;
+	}
+	in_msg = imc_msg_create_from_data(imc_hcd, state, connection_id, msg_type,
+									  chunk_create(msg, msg_len));
+	result = receive_message(state, in_msg);
+	in_msg->destroy(in_msg);
+
+	return result;
+}
+
+/**
+ * see section 3.8.6 of TCG TNC IF-IMV Specification 1.3
+ */
+TNC_Result TNC_IMC_API TNC_IMC_ReceiveMessageLong(TNC_IMCID imc_id,
+												  TNC_ConnectionID connection_id,
+												  TNC_UInt32 msg_flags,
+												  TNC_BufferReference msg,
+												  TNC_UInt32 msg_len,
+												  TNC_VendorID msg_vid,
+												  TNC_MessageSubtype msg_subtype,
+												  TNC_UInt32 src_imv_id,
+												  TNC_UInt32 dst_imc_id)
+{
+	imc_state_t *state;
+	imc_msg_t *in_msg;
+	TNC_Result result;
+
+	if (!imc_hcd)
+	{
+		DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
+		return TNC_RESULT_NOT_INITIALIZED;
+	}
+	if (!imc_hcd->get_state(imc_hcd, connection_id, &state))
+	{
+		return TNC_RESULT_FATAL;
+	}
+	in_msg = imc_msg_create_from_long_data(imc_hcd, state, connection_id,
+								src_imv_id, dst_imc_id,msg_vid, msg_subtype,
+								chunk_create(msg, msg_len));
+	result =receive_message(state, in_msg);
+	in_msg->destroy(in_msg);
+
+	return result;
+}
+
+/**
+ * see section 3.8.7 of TCG TNC IF-IMC Specification 1.3
+ */
+TNC_Result TNC_IMC_API TNC_IMC_BatchEnding(TNC_IMCID imc_id,
+										   TNC_ConnectionID connection_id)
+{
+	if (!imc_hcd)
+	{
+		DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
+		return TNC_RESULT_NOT_INITIALIZED;
+	}
+	return TNC_RESULT_SUCCESS;
+}
+
+/**
+ * see section 3.8.8 of TCG TNC IF-IMC Specification 1.3
+ */
+TNC_Result TNC_IMC_API TNC_IMC_Terminate(TNC_IMCID imc_id)
+{
+	if (!imc_hcd)
+	{
+		DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
+		return TNC_RESULT_NOT_INITIALIZED;
+	}
+	imc_hcd->destroy(imc_hcd);
+	imc_hcd = NULL;
+
+	os->destroy(os);
+	os = NULL;
+
+	return TNC_RESULT_SUCCESS;
+}
+
+/**
+ * see section 4.2.8.1 of TCG TNC IF-IMC Specification 1.3
+ */
+TNC_Result TNC_IMC_API TNC_IMC_ProvideBindFunction(TNC_IMCID imc_id,
+									TNC_TNCC_BindFunctionPointer bind_function)
+{
+	if (!imc_hcd)
+	{
+		DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
+		return TNC_RESULT_NOT_INITIALIZED;
+	}
+	return imc_hcd->bind_functions(imc_hcd, bind_function);
+}
diff --git a/src/libimcv/plugins/imc_hcd/imc_hcd_state.c b/src/libimcv/plugins/imc_hcd/imc_hcd_state.c
new file mode 100644
index 0000000..ce93d7e
--- /dev/null
+++ b/src/libimcv/plugins/imc_hcd/imc_hcd_state.c
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2015 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
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include "imc_hcd_state.h"
+
+#include <tncif_names.h>
+
+#include <utils/debug.h>
+
+typedef struct private_imc_hcd_state_t private_imc_hcd_state_t;
+
+/**
+ * Private data of an imc_hcd_state_t object.
+ */
+struct private_imc_hcd_state_t {
+
+	/**
+	 * Public members of imc_hcd_state_t
+	 */
+	imc_hcd_state_t public;
+
+	/**
+	 * TNCCS connection ID
+	 */
+	TNC_ConnectionID connection_id;
+
+	/**
+	 * TNCCS connection state
+	 */
+	TNC_ConnectionState state;
+
+	/**
+	 * Assessment/Evaluation Result
+	 */
+	TNC_IMV_Evaluation_Result result;
+
+	/**
+	 * Does the TNCCS connection support long message types?
+	 */
+	bool has_long;
+
+	/**
+	 * Does the TNCCS connection support exclusive delivery?
+	 */
+	bool has_excl;
+
+	/**
+	 * Maximum PA-TNC message size for this TNCCS connection
+	 */
+	u_int32_t max_msg_len;
+
+	/**
+	 * PA-TNC attribute segmentation contracts associated with TNCCS connection
+	 */
+	seg_contract_manager_t *contracts;
+};
+
+METHOD(imc_state_t, get_connection_id, TNC_ConnectionID,
+	private_imc_hcd_state_t *this)
+{
+	return this->connection_id;
+}
+
+METHOD(imc_state_t, has_long, bool,
+	private_imc_hcd_state_t *this)
+{
+	return this->has_long;
+}
+
+METHOD(imc_state_t, has_excl, bool,
+	private_imc_hcd_state_t *this)
+{
+	return this->has_excl;
+}
+
+METHOD(imc_state_t, set_flags, void,
+	private_imc_hcd_state_t *this, bool has_long, bool has_excl)
+{
+	this->has_long = has_long;
+	this->has_excl = has_excl;
+}
+
+METHOD(imc_state_t, set_max_msg_len, void,
+	private_imc_hcd_state_t *this, u_int32_t max_msg_len)
+{
+	this->max_msg_len = max_msg_len;
+}
+
+METHOD(imc_state_t, get_max_msg_len, u_int32_t,
+	private_imc_hcd_state_t *this)
+{
+	return this->max_msg_len;
+}
+
+METHOD(imc_state_t, get_contracts, seg_contract_manager_t*,
+	private_imc_hcd_state_t *this)
+{
+	return this->contracts;
+}
+
+METHOD(imc_state_t, change_state, void,
+	private_imc_hcd_state_t *this, TNC_ConnectionState new_state)
+{
+	this->state = new_state;
+}
+
+METHOD(imc_state_t, set_result, void,
+	private_imc_hcd_state_t *this, TNC_IMCID id,
+	TNC_IMV_Evaluation_Result result)
+{
+	this->result = result;
+}
+
+METHOD(imc_state_t, get_result, bool,
+	private_imc_hcd_state_t *this, TNC_IMCID id,
+	TNC_IMV_Evaluation_Result *result)
+{
+	if (result)
+	{
+		*result = this->result;
+	}
+	return this->result != TNC_IMV_EVALUATION_RESULT_DONT_KNOW;
+}
+
+METHOD(imc_state_t, destroy, void,
+	private_imc_hcd_state_t *this)
+{
+	this->contracts->destroy(this->contracts);
+	free(this);
+}
+
+/**
+ * Described in header.
+ */
+imc_state_t *imc_hcd_state_create(TNC_ConnectionID connection_id)
+{
+	private_imc_hcd_state_t *this;
+
+	INIT(this,
+		.public = {
+			.interface = {
+				.get_connection_id = _get_connection_id,
+				.has_long = _has_long,
+				.has_excl = _has_excl,
+				.set_flags = _set_flags,
+				.set_max_msg_len = _set_max_msg_len,
+				.get_max_msg_len = _get_max_msg_len,
+				.get_contracts = _get_contracts,
+				.change_state = _change_state,
+				.set_result = _set_result,
+				.get_result = _get_result,
+				.destroy = _destroy,
+			},
+		},
+		.state = TNC_CONNECTION_STATE_CREATE,
+		.result = TNC_IMV_EVALUATION_RESULT_DONT_KNOW,
+		.connection_id = connection_id,
+		.contracts = seg_contract_manager_create(),
+	);
+
+	return &this->public.interface;
+}
+
+
diff --git a/src/libimcv/plugins/imc_hcd/imc_hcd_state.h b/src/libimcv/plugins/imc_hcd/imc_hcd_state.h
new file mode 100644
index 0000000..dbd5ddb
--- /dev/null
+++ b/src/libimcv/plugins/imc_hcd/imc_hcd_state.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2015 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
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup imc_hcd imc_hcd
+ * @ingroup libimcv_plugins
+ *
+ * @defgroup imc_hcd_state_t imc_hcd_state
+ * @{ @ingroup imc_hcd
+ */
+
+#ifndef IMC_HCD_STATE_H_
+#define IMC_HCD_STATE_H_
+
+#include <imc/imc_state.h>
+#include <library.h>
+
+typedef struct imc_hcd_state_t imc_hcd_state_t;
+
+/**
+ * Internal state of an imc_hcd_t connection instance
+ */
+struct imc_hcd_state_t {
+
+	/**
+	 * imc_state_t interface
+	 */
+	imc_state_t interface;
+};
+
+/**
+ * Create an imc_hcd_state_t instance
+ *
+ * @param id		connection ID
+ */
+imc_state_t* imc_hcd_state_create(TNC_ConnectionID id);
+
+#endif /** IMC_HCD_STATE_H_ @}*/
diff --git a/src/libimcv/plugins/imc_os/imc_os.c b/src/libimcv/plugins/imc_os/imc_os.c
index 4fe8856..af1862a 100644
--- a/src/libimcv/plugins/imc_os/imc_os.c
+++ b/src/libimcv/plugins/imc_os/imc_os.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011-2014 Andreas Steffen
+ * Copyright (C) 2011-2015 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -18,10 +18,11 @@
 #include <imc/imc_agent.h>
 #include <imc/imc_msg.h>
 #include <imc/imc_os_info.h>
+#include <generic/generic_attr_bool.h>
+#include <generic/generic_attr_string.h>
 #include <ietf/ietf_attr.h>
 #include <ietf/ietf_attr_attr_request.h>
-#include <ietf/ietf_attr_default_pwd_enabled.h>
-#include <ietf/ietf_attr_fwd_enabled.h>
+#include "ietf/ietf_attr_fwd_enabled.h"
 #include <ietf/ietf_attr_installed_packages.h>
 #include <ietf/ietf_attr_numeric_version.h>
 #include <ietf/ietf_attr_op_status.h>
@@ -30,7 +31,6 @@
 #include <ita/ita_attr.h>
 #include <ita/ita_attr_get_settings.h>
 #include <ita/ita_attr_settings.h>
-#include <ita/ita_attr_device_id.h>
 
 #include <tncif_pa_subtypes.h>
 
@@ -212,9 +212,9 @@ static void add_fwd_enabled(imc_msg_t *msg)
 	os_fwd_status_t fwd_status;
 
 	fwd_status = os->get_fwd_status(os);
-	DBG1(DBG_IMC, "IPv4 forwarding is %N",
-				   os_fwd_status_names, fwd_status);
-	attr = ietf_attr_fwd_enabled_create(fwd_status);
+	DBG1(DBG_IMC, "IPv4 forwarding is %N", os_fwd_status_names, fwd_status);
+	attr = ietf_attr_fwd_enabled_create(fwd_status,
+				pen_type_create(PEN_IETF, IETF_ATTR_FORWARDING_ENABLED));
 	msg->add_attribute(msg, attr);
 }
 
@@ -224,9 +224,12 @@ static void add_fwd_enabled(imc_msg_t *msg)
 static void add_default_pwd_enabled(imc_msg_t *msg)
 {
 	pa_tnc_attr_t *attr;
+	bool status;
 
-	DBG1(DBG_IMC, "factory default password is disabled");
-	attr = ietf_attr_default_pwd_enabled_create(FALSE);
+	status = os->get_default_pwd_status(os);
+	DBG1(DBG_IMC, "factory default password is %sabled", status ? "en" : "dis");
+	attr = generic_attr_bool_create(status,
+			pen_type_create(PEN_IETF, IETF_ATTR_FACTORY_DEFAULT_PWD_ENABLED));
 	msg->add_attribute(msg, attr);
 }
 
@@ -330,7 +333,8 @@ static void add_device_id(imc_msg_t *msg)
 	}
 
 	DBG1(DBG_IMC, "device ID is %.*s", value.len, value.ptr);
-	attr = ita_attr_device_id_create(value);
+	attr = generic_attr_string_create(value, pen_type_create(PEN_ITA,
+									  ITA_ATTR_DEVICE_ID));
 	msg->add_attribute(msg, attr);
 	free(value.ptr);
 }
diff --git a/src/libimcv/plugins/imc_scanner/imc_scanner.c b/src/libimcv/plugins/imc_scanner/imc_scanner.c
index 0478841..c67636f 100644
--- a/src/libimcv/plugins/imc_scanner/imc_scanner.c
+++ b/src/libimcv/plugins/imc_scanner/imc_scanner.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011-2014 Andreas Steffen
+ * Copyright (C) 2011-2015 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -34,7 +34,7 @@
 static const char imc_name[] = "Scanner";
 
 static pen_type_t msg_types[] = {
-	{ PEN_IETF, PA_SUBTYPE_IETF_VPN }
+	{ PEN_IETF, PA_SUBTYPE_IETF_FIREWALL }
 };
 
 static imc_agent_t *imc_scanner;
@@ -241,7 +241,8 @@ static TNC_Result add_port_filter(imc_msg_t *msg)
 	pa_tnc_attr_t *attr;
 	ietf_attr_port_filter_t *attr_port_filter;
 
-	attr = ietf_attr_port_filter_create();
+	attr = ietf_attr_port_filter_create(pen_type_create(PEN_IETF,
+										IETF_ATTR_PORT_FILTER));
 	attr->set_noskip_flag(attr, TRUE);
 	attr_port_filter = (ietf_attr_port_filter_t*)attr;
 	if (!do_netstat(attr_port_filter))
diff --git a/src/libimcv/plugins/imc_swid/imc_swid.c b/src/libimcv/plugins/imc_swid/imc_swid.c
index 40f352a..0dcb9af 100644
--- a/src/libimcv/plugins/imc_swid/imc_swid.c
+++ b/src/libimcv/plugins/imc_swid/imc_swid.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013-2014 Andreas Steffen
+ * Copyright (C) 2013-2015 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -134,9 +134,7 @@ TNC_Result TNC_IMC_BeginHandshake(TNC_IMCID imc_id,
 	/* Determine maximum PA-TNC attribute segment size */
 	max_seg_size = state->get_max_msg_len(state) - PA_TNC_HEADER_SIZE
 												 - PA_TNC_ATTR_HEADER_SIZE
-												 - TCG_SEG_ATTR_SEG_ENV_HEADER
-												 - PA_TNC_ATTR_HEADER_SIZE
-												 - TCG_SEG_ATTR_MAX_SIZE_SIZE;
+												 - TCG_SEG_ATTR_SEG_ENV_HEADER;
 
 	/* Announce support of PA-TNC segmentation to IMV */
 	contract = seg_contract_create(msg_types[0], max_attr_size, max_seg_size,
diff --git a/src/libimcv/plugins/imv_attestation/imv_attestation_agent.c b/src/libimcv/plugins/imv_attestation/imv_attestation_agent.c
index 8e37368..28ebd00 100644
--- a/src/libimcv/plugins/imv_attestation/imv_attestation_agent.c
+++ b/src/libimcv/plugins/imv_attestation/imv_attestation_agent.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2011-2012 Sansar Choinyambuu
- * Copyright (C) 2011-2014 Andreas Steffen
+ * Copyright (C) 2011-2015 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -27,13 +27,13 @@
 #include <imv/imv_msg.h>
 #include <imv/imv_session.h>
 #include <imv/imv_os_info.h>
+#include <generic/generic_attr_string.h>
 #include <ietf/ietf_attr.h>
 #include <ietf/ietf_attr_attr_request.h>
 #include <ietf/ietf_attr_pa_tnc_error.h>
 #include <ietf/ietf_attr_product_info.h>
 #include <ietf/ietf_attr_string_version.h>
 #include <ita/ita_attr.h>
-#include <ita/ita_attr_device_id.h>
 #include <tcg/tcg_attr.h>
 #include <tcg/pts/tcg_pts_attr_meas_algo.h>
 #include <tcg/pts/tcg_pts_attr_proto_caps.h>
@@ -484,9 +484,7 @@ METHOD(imv_agent_if_t, batch_ending, TNC_Result,
 		max_seg_size = state->get_max_msg_len(state)
 								- PA_TNC_HEADER_SIZE
 								- PA_TNC_ATTR_HEADER_SIZE
-								- TCG_SEG_ATTR_SEG_ENV_HEADER
-								- PA_TNC_ATTR_HEADER_SIZE
-								- TCG_SEG_ATTR_MAX_SIZE_SIZE;
+								- TCG_SEG_ATTR_SEG_ENV_HEADER;
 
 		/* Announce support of PA-TNC segmentation to IMC */
 		contract = seg_contract_create(msg_types[0], max_attr_size,
diff --git a/src/libimcv/plugins/imv_hcd/Makefile.am b/src/libimcv/plugins/imv_hcd/Makefile.am
new file mode 100644
index 0000000..28926d4
--- /dev/null
+++ b/src/libimcv/plugins/imv_hcd/Makefile.am
@@ -0,0 +1,18 @@
+AM_CPPFLAGS = \
+	-I$(top_srcdir)/src/libstrongswan \
+	-I$(top_srcdir)/src/libtncif \
+	-I$(top_srcdir)/src/libimcv
+
+AM_CFLAGS = \
+	$(PLUGIN_CFLAGS)
+
+imcv_LTLIBRARIES = imv-hcd.la
+
+imv_hcd_la_LIBADD = $(top_builddir)/src/libimcv/libimcv.la \
+	$(top_builddir)/src/libstrongswan/libstrongswan.la
+
+imv_hcd_la_SOURCES = \
+	imv_hcd.c imv_hcd_state.h imv_hcd_state.c \
+	imv_hcd_agent.h imv_hcd_agent.c
+
+imv_hcd_la_LDFLAGS = -module -avoid-version -no-undefined
diff --git a/src/libipsec/Makefile.in b/src/libimcv/plugins/imv_hcd/Makefile.in
similarity index 70%
copy from src/libipsec/Makefile.in
copy to src/libimcv/plugins/imv_hcd/Makefile.in
index a80d28a..ea01764 100644
--- a/src/libipsec/Makefile.in
+++ b/src/libimcv/plugins/imv_hcd/Makefile.in
@@ -78,7 +78,7 @@ PRE_UNINSTALL = :
 POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
-subdir = src/libipsec
+subdir = src/libimcv/plugins/imv_hcd
 DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
 	$(top_srcdir)/depcomp
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
@@ -125,19 +125,19 @@ am__uninstall_files_from_dir = { \
     || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
          $(am__cd) "$$dir" && rm -f $$files; }; \
   }
-am__installdirs = "$(DESTDIR)$(ipseclibdir)"
-LTLIBRARIES = $(ipseclib_LTLIBRARIES)
-libipsec_la_DEPENDENCIES =  \
+am__installdirs = "$(DESTDIR)$(imcvdir)"
+LTLIBRARIES = $(imcv_LTLIBRARIES)
+imv_hcd_la_DEPENDENCIES = $(top_builddir)/src/libimcv/libimcv.la \
 	$(top_builddir)/src/libstrongswan/libstrongswan.la
-am_libipsec_la_OBJECTS = ipsec.lo esp_context.lo esp_packet.lo \
-	ip_packet.lo ipsec_event_relay.lo ipsec_policy.lo \
-	ipsec_policy_mgr.lo ipsec_processor.lo ipsec_sa.lo \
-	ipsec_sa_mgr.lo
-libipsec_la_OBJECTS = $(am_libipsec_la_OBJECTS)
+am_imv_hcd_la_OBJECTS = imv_hcd.lo imv_hcd_state.lo imv_hcd_agent.lo
+imv_hcd_la_OBJECTS = $(am_imv_hcd_la_OBJECTS)
 AM_V_lt = $(am__v_lt_ at AM_V@)
 am__v_lt_ = $(am__v_lt_ at AM_DEFAULT_V@)
 am__v_lt_0 = --silent
 am__v_lt_1 = 
+imv_hcd_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(imv_hcd_la_LDFLAGS) $(LDFLAGS) -o $@
 AM_V_P = $(am__v_P_ at AM_V@)
 am__v_P_ = $(am__v_P_ at AM_DEFAULT_V@)
 am__v_P_0 = false
@@ -172,29 +172,13 @@ AM_V_CCLD = $(am__v_CCLD_ at AM_V@)
 am__v_CCLD_ = $(am__v_CCLD_ at AM_DEFAULT_V@)
 am__v_CCLD_0 = @echo "  CCLD    " $@;
 am__v_CCLD_1 = 
-SOURCES = $(libipsec_la_SOURCES)
-DIST_SOURCES = $(libipsec_la_SOURCES)
-RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
-	ctags-recursive dvi-recursive html-recursive info-recursive \
-	install-data-recursive install-dvi-recursive \
-	install-exec-recursive install-html-recursive \
-	install-info-recursive install-pdf-recursive \
-	install-ps-recursive install-recursive installcheck-recursive \
-	installdirs-recursive pdf-recursive ps-recursive \
-	tags-recursive uninstall-recursive
+SOURCES = $(imv_hcd_la_SOURCES)
+DIST_SOURCES = $(imv_hcd_la_SOURCES)
 am__can_run_installinfo = \
   case $$AM_UPDATE_INFO_DIR in \
     n|no|NO) false;; \
     *) (install-info --version) >/dev/null 2>&1;; \
   esac
-RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive	\
-  distclean-recursive maintainer-clean-recursive
-am__recursive_targets = \
-  $(RECURSIVE_TARGETS) \
-  $(RECURSIVE_CLEAN_TARGETS) \
-  $(am__extra_recursive_targets)
-AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
-	distdir
 am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
 # Read a list of newline-separated strings from the standard input,
 # and print each of them once, without duplicates.  Input order is
@@ -214,33 +198,7 @@ am__define_uniq_tagged_files = \
   done | $(am__uniquify_input)`
 ETAGS = etags
 CTAGS = ctags
-DIST_SUBDIRS = .
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
-am__relativize = \
-  dir0=`pwd`; \
-  sed_first='s,^\([^/]*\)/.*$$,\1,'; \
-  sed_rest='s,^[^/]*/*,,'; \
-  sed_last='s,^.*/\([^/]*\)$$,\1,'; \
-  sed_butlast='s,/*[^/]*$$,,'; \
-  while test -n "$$dir1"; do \
-    first=`echo "$$dir1" | sed -e "$$sed_first"`; \
-    if test "$$first" != "."; then \
-      if test "$$first" = ".."; then \
-        dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
-        dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
-      else \
-        first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
-        if test "$$first2" = "$$first"; then \
-          dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
-        else \
-          dir2="../$$dir2"; \
-        fi; \
-        dir0="$$dir0"/"$$first"; \
-      fi; \
-    fi; \
-    dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
-  done; \
-  reldir="$$dir2"
 ACLOCAL = @ACLOCAL@
 ALLOCA = @ALLOCA@
 AMTAR = @AMTAR@
@@ -466,36 +424,24 @@ top_srcdir = @top_srcdir@
 urandom_device = @urandom_device@
 xml_CFLAGS = @xml_CFLAGS@
 xml_LIBS = @xml_LIBS@
-ipseclib_LTLIBRARIES = libipsec.la
-libipsec_la_SOURCES = \
-ipsec.c ipsec.h \
-esp_context.c esp_context.h \
-esp_packet.c esp_packet.h \
-ip_packet.c ip_packet.h \
-ipsec_event_listener.h \
-ipsec_event_relay.c ipsec_event_relay.h \
-ipsec_policy.c ipsec_policy.h \
-ipsec_policy_mgr.c ipsec_policy_mgr.h \
-ipsec_processor.c ipsec_processor.h \
-ipsec_sa.c ipsec_sa.h \
-ipsec_sa_mgr.c ipsec_sa_mgr.h
-
-libipsec_la_LIBADD = \
-	$(top_builddir)/src/libstrongswan/libstrongswan.la
-
 AM_CPPFLAGS = \
-	-I$(top_srcdir)/src/libstrongswan
+	-I$(top_srcdir)/src/libstrongswan \
+	-I$(top_srcdir)/src/libtncif \
+	-I$(top_srcdir)/src/libimcv
 
-AM_LDFLAGS = \
-	-no-undefined
+AM_CFLAGS = \
+	$(PLUGIN_CFLAGS)
 
-EXTRA_DIST = Android.mk
- at MONOLITHIC_FALSE@SUBDIRS = .
+imcv_LTLIBRARIES = imv-hcd.la
+imv_hcd_la_LIBADD = $(top_builddir)/src/libimcv/libimcv.la \
+	$(top_builddir)/src/libstrongswan/libstrongswan.la
 
-# build optional plugins
-########################
- at MONOLITHIC_TRUE@SUBDIRS = 
-all: all-recursive
+imv_hcd_la_SOURCES = \
+	imv_hcd.c imv_hcd_state.h imv_hcd_state.c \
+	imv_hcd_agent.h imv_hcd_agent.c
+
+imv_hcd_la_LDFLAGS = -module -avoid-version -no-undefined
+all: all-am
 
 .SUFFIXES:
 .SUFFIXES: .c .lo .o .obj
@@ -508,9 +454,9 @@ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
 	      exit 1;; \
 	  esac; \
 	done; \
-	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/libipsec/Makefile'; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/libimcv/plugins/imv_hcd/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
-	  $(AUTOMAKE) --gnu src/libipsec/Makefile
+	  $(AUTOMAKE) --gnu src/libimcv/plugins/imv_hcd/Makefile
 .PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
@@ -530,33 +476,33 @@ $(ACLOCAL_M4):  $(am__aclocal_m4_deps)
 	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
 $(am__aclocal_m4_deps):
 
-install-ipseclibLTLIBRARIES: $(ipseclib_LTLIBRARIES)
+install-imcvLTLIBRARIES: $(imcv_LTLIBRARIES)
 	@$(NORMAL_INSTALL)
-	@list='$(ipseclib_LTLIBRARIES)'; test -n "$(ipseclibdir)" || list=; \
+	@list='$(imcv_LTLIBRARIES)'; test -n "$(imcvdir)" || list=; \
 	list2=; for p in $$list; do \
 	  if test -f $$p; then \
 	    list2="$$list2 $$p"; \
 	  else :; fi; \
 	done; \
 	test -z "$$list2" || { \
-	  echo " $(MKDIR_P) '$(DESTDIR)$(ipseclibdir)'"; \
-	  $(MKDIR_P) "$(DESTDIR)$(ipseclibdir)" || exit 1; \
-	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(ipseclibdir)'"; \
-	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(ipseclibdir)"; \
+	  echo " $(MKDIR_P) '$(DESTDIR)$(imcvdir)'"; \
+	  $(MKDIR_P) "$(DESTDIR)$(imcvdir)" || exit 1; \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(imcvdir)'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(imcvdir)"; \
 	}
 
-uninstall-ipseclibLTLIBRARIES:
+uninstall-imcvLTLIBRARIES:
 	@$(NORMAL_UNINSTALL)
-	@list='$(ipseclib_LTLIBRARIES)'; test -n "$(ipseclibdir)" || list=; \
+	@list='$(imcv_LTLIBRARIES)'; test -n "$(imcvdir)" || list=; \
 	for p in $$list; do \
 	  $(am__strip_dir) \
-	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(ipseclibdir)/$$f'"; \
-	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(ipseclibdir)/$$f"; \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(imcvdir)/$$f'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(imcvdir)/$$f"; \
 	done
 
-clean-ipseclibLTLIBRARIES:
-	-test -z "$(ipseclib_LTLIBRARIES)" || rm -f $(ipseclib_LTLIBRARIES)
-	@list='$(ipseclib_LTLIBRARIES)'; \
+clean-imcvLTLIBRARIES:
+	-test -z "$(imcv_LTLIBRARIES)" || rm -f $(imcv_LTLIBRARIES)
+	@list='$(imcv_LTLIBRARIES)'; \
 	locs=`for p in $$list; do echo $$p; done | \
 	      sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
 	      sort -u`; \
@@ -565,8 +511,8 @@ clean-ipseclibLTLIBRARIES:
 	  rm -f $${locs}; \
 	}
 
-libipsec.la: $(libipsec_la_OBJECTS) $(libipsec_la_DEPENDENCIES) $(EXTRA_libipsec_la_DEPENDENCIES) 
-	$(AM_V_CCLD)$(LINK) -rpath $(ipseclibdir) $(libipsec_la_OBJECTS) $(libipsec_la_LIBADD) $(LIBS)
+imv-hcd.la: $(imv_hcd_la_OBJECTS) $(imv_hcd_la_DEPENDENCIES) $(EXTRA_imv_hcd_la_DEPENDENCIES) 
+	$(AM_V_CCLD)$(imv_hcd_la_LINK) -rpath $(imcvdir) $(imv_hcd_la_OBJECTS) $(imv_hcd_la_LIBADD) $(LIBS)
 
 mostlyclean-compile:
 	-rm -f *.$(OBJEXT)
@@ -574,16 +520,9 @@ mostlyclean-compile:
 distclean-compile:
 	-rm -f *.tab.c
 
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/esp_context.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/esp_packet.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/ip_packet.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/ipsec.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/ipsec_event_relay.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/ipsec_policy.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/ipsec_policy_mgr.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/ipsec_processor.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/ipsec_sa.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/ipsec_sa_mgr.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/imv_hcd.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/imv_hcd_agent.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/imv_hcd_state.Plo at am__quote@
 
 .c.o:
 @am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
@@ -615,61 +554,14 @@ mostlyclean-libtool:
 clean-libtool:
 	-rm -rf .libs _libs
 
-# This directory's subdirectories are mostly independent; you can cd
-# into them and run 'make' without going through this Makefile.
-# To change the values of 'make' variables: instead of editing Makefiles,
-# (1) if the variable is set in 'config.status', edit 'config.status'
-#     (which will cause the Makefiles to be regenerated when you run 'make');
-# (2) otherwise, pass the desired values on the 'make' command line.
-$(am__recursive_targets):
-	@fail=; \
-	if $(am__make_keepgoing); then \
-	  failcom='fail=yes'; \
-	else \
-	  failcom='exit 1'; \
-	fi; \
-	dot_seen=no; \
-	target=`echo $@ | sed s/-recursive//`; \
-	case "$@" in \
-	  distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
-	  *) list='$(SUBDIRS)' ;; \
-	esac; \
-	for subdir in $$list; do \
-	  echo "Making $$target in $$subdir"; \
-	  if test "$$subdir" = "."; then \
-	    dot_seen=yes; \
-	    local_target="$$target-am"; \
-	  else \
-	    local_target="$$target"; \
-	  fi; \
-	  ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
-	  || eval $$failcom; \
-	done; \
-	if test "$$dot_seen" = "no"; then \
-	  $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
-	fi; test -z "$$fail"
-
 ID: $(am__tagged_files)
 	$(am__define_uniq_tagged_files); mkid -fID $$unique
-tags: tags-recursive
+tags: tags-am
 TAGS: tags
 
 tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
 	set x; \
 	here=`pwd`; \
-	if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
-	  include_option=--etags-include; \
-	  empty_fix=.; \
-	else \
-	  include_option=--include; \
-	  empty_fix=; \
-	fi; \
-	list='$(SUBDIRS)'; for subdir in $$list; do \
-	  if test "$$subdir" = .; then :; else \
-	    test ! -f $$subdir/TAGS || \
-	      set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
-	  fi; \
-	done; \
 	$(am__define_uniq_tagged_files); \
 	shift; \
 	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
@@ -682,7 +574,7 @@ tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
 	      $$unique; \
 	  fi; \
 	fi
-ctags: ctags-recursive
+ctags: ctags-am
 
 CTAGS: ctags
 ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
@@ -695,7 +587,7 @@ GTAGS:
 	here=`$(am__cd) $(top_builddir) && pwd` \
 	  && $(am__cd) $(top_srcdir) \
 	  && gtags -i $(GTAGS_ARGS) "$$here"
-cscopelist: cscopelist-recursive
+cscopelist: cscopelist-am
 
 cscopelist-am: $(am__tagged_files)
 	list='$(am__tagged_files)'; \
@@ -744,48 +636,22 @@ distdir: $(DISTFILES)
 	    || exit 1; \
 	  fi; \
 	done
-	@list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
-	  if test "$$subdir" = .; then :; else \
-	    $(am__make_dryrun) \
-	      || test -d "$(distdir)/$$subdir" \
-	      || $(MKDIR_P) "$(distdir)/$$subdir" \
-	      || exit 1; \
-	    dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
-	    $(am__relativize); \
-	    new_distdir=$$reldir; \
-	    dir1=$$subdir; dir2="$(top_distdir)"; \
-	    $(am__relativize); \
-	    new_top_distdir=$$reldir; \
-	    echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
-	    echo "     am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
-	    ($(am__cd) $$subdir && \
-	      $(MAKE) $(AM_MAKEFLAGS) \
-	        top_distdir="$$new_top_distdir" \
-	        distdir="$$new_distdir" \
-		am__remove_distdir=: \
-		am__skip_length_check=: \
-		am__skip_mode_fix=: \
-	        distdir) \
-	      || exit 1; \
-	  fi; \
-	done
 check-am: all-am
-check: check-recursive
+check: check-am
 all-am: Makefile $(LTLIBRARIES)
-installdirs: installdirs-recursive
-installdirs-am:
-	for dir in "$(DESTDIR)$(ipseclibdir)"; do \
+installdirs:
+	for dir in "$(DESTDIR)$(imcvdir)"; do \
 	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
 	done
-install: install-recursive
-install-exec: install-exec-recursive
-install-data: install-data-recursive
-uninstall: uninstall-recursive
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
 
 install-am: all-am
 	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
 
-installcheck: installcheck-recursive
+installcheck: installcheck-am
 install-strip:
 	if test -z '$(STRIP)'; then \
 	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
@@ -807,94 +673,93 @@ 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."
-clean: clean-recursive
+clean: clean-am
 
-clean-am: clean-generic clean-ipseclibLTLIBRARIES clean-libtool \
+clean-am: clean-generic clean-imcvLTLIBRARIES clean-libtool \
 	mostlyclean-am
 
-distclean: distclean-recursive
+distclean: distclean-am
 	-rm -rf ./$(DEPDIR)
 	-rm -f Makefile
 distclean-am: clean-am distclean-compile distclean-generic \
 	distclean-tags
 
-dvi: dvi-recursive
+dvi: dvi-am
 
 dvi-am:
 
-html: html-recursive
+html: html-am
 
 html-am:
 
-info: info-recursive
+info: info-am
 
 info-am:
 
-install-data-am: install-ipseclibLTLIBRARIES
+install-data-am: install-imcvLTLIBRARIES
 
-install-dvi: install-dvi-recursive
+install-dvi: install-dvi-am
 
 install-dvi-am:
 
 install-exec-am:
 
-install-html: install-html-recursive
+install-html: install-html-am
 
 install-html-am:
 
-install-info: install-info-recursive
+install-info: install-info-am
 
 install-info-am:
 
 install-man:
 
-install-pdf: install-pdf-recursive
+install-pdf: install-pdf-am
 
 install-pdf-am:
 
-install-ps: install-ps-recursive
+install-ps: install-ps-am
 
 install-ps-am:
 
 installcheck-am:
 
-maintainer-clean: maintainer-clean-recursive
+maintainer-clean: maintainer-clean-am
 	-rm -rf ./$(DEPDIR)
 	-rm -f Makefile
 maintainer-clean-am: distclean-am maintainer-clean-generic
 
-mostlyclean: mostlyclean-recursive
+mostlyclean: mostlyclean-am
 
 mostlyclean-am: mostlyclean-compile mostlyclean-generic \
 	mostlyclean-libtool
 
-pdf: pdf-recursive
+pdf: pdf-am
 
 pdf-am:
 
-ps: ps-recursive
+ps: ps-am
 
 ps-am:
 
-uninstall-am: uninstall-ipseclibLTLIBRARIES
-
-.MAKE: $(am__recursive_targets) install-am install-strip
-
-.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
-	check-am clean clean-generic clean-ipseclibLTLIBRARIES \
-	clean-libtool cscopelist-am ctags ctags-am distclean \
-	distclean-compile distclean-generic distclean-libtool \
-	distclean-tags 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-ipseclibLTLIBRARIES install-man install-pdf \
-	install-pdf-am install-ps install-ps-am install-strip \
-	installcheck installcheck-am installdirs installdirs-am \
-	maintainer-clean maintainer-clean-generic mostlyclean \
-	mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
-	pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \
-	uninstall-ipseclibLTLIBRARIES
+uninstall-am: uninstall-imcvLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+	clean-imcvLTLIBRARIES clean-libtool cscopelist-am ctags \
+	ctags-am distclean distclean-compile distclean-generic \
+	distclean-libtool distclean-tags 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-imcvLTLIBRARIES 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-compile mostlyclean-generic \
+	mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
+	uninstall-am uninstall-imcvLTLIBRARIES
 
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
diff --git a/src/libcharon/tests/libcharon_tests.h b/src/libimcv/plugins/imv_hcd/imv_hcd.c
similarity index 65%
copy from src/libcharon/tests/libcharon_tests.h
copy to src/libimcv/plugins/imv_hcd/imv_hcd.c
index dc9681a..f320952 100644
--- a/src/libcharon/tests/libcharon_tests.h
+++ b/src/libimcv/plugins/imv_hcd/imv_hcd.c
@@ -1,6 +1,6 @@
 /*
- * Copyright (C) 2014 Martin Willi
- * Copyright (C) 2014 revosec AG
+ * Copyright (C) 2015 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
@@ -13,4 +13,12 @@
  * for more details.
  */
 
-TEST_SUITE(mem_pool_suite_create)
+#include "imv_hcd_agent.h"
+
+static const char imv_name[] = "HCD";
+static const imv_agent_create_t imv_agent_create = imv_hcd_agent_create;
+
+/* include generic TGC TNC IF-IMV API code below */
+
+#include <imv/imv_if.h>
+
diff --git a/src/libimcv/plugins/imv_hcd/imv_hcd_agent.c b/src/libimcv/plugins/imv_hcd/imv_hcd_agent.c
new file mode 100644
index 0000000..e15eeb1
--- /dev/null
+++ b/src/libimcv/plugins/imv_hcd/imv_hcd_agent.c
@@ -0,0 +1,680 @@
+/*
+ * Copyright (C) 2015 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
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+
+#include "imv_hcd_agent.h"
+#include "imv_hcd_state.h"
+
+#include <imcv.h>
+#include <imv/imv_agent.h>
+#include <imv/imv_msg.h>
+#include <generic/generic_attr_bool.h>
+#include <generic/generic_attr_chunk.h>
+#include <generic/generic_attr_string.h>
+#include <ietf/ietf_attr.h>
+#include <ietf/ietf_attr_attr_request.h>
+#include <ietf/ietf_attr_fwd_enabled.h>
+#include <pwg/pwg_attr.h>
+#include <pwg/pwg_attr_vendor_smi_code.h>
+#include "tcg/seg/tcg_seg_attr_max_size.h"
+#include "tcg/seg/tcg_seg_attr_seg_env.h"
+
+#include <tncif_names.h>
+#include <tncif_pa_subtypes.h>
+
+#include <pen/pen.h>
+#include <utils/debug.h>
+
+#define HCD_MAX_ATTR_SIZE	10000000
+
+typedef struct private_imv_hcd_agent_t private_imv_hcd_agent_t;
+
+/* Subscribed PA-TNC message subtypes */
+static pen_type_t msg_types[] = {
+	{ PEN_IETF, PA_SUBTYPE_IETF_OPERATING_SYSTEM },
+	{ PEN_PWG, PA_SUBTYPE_PWG_HCD_SYSTEM },
+	{ PEN_PWG, PA_SUBTYPE_PWG_HCD_CONSOLE },
+	{ PEN_PWG, PA_SUBTYPE_PWG_HCD_MARKER },
+	{ PEN_PWG, PA_SUBTYPE_PWG_HCD_FINISHER },
+	{ PEN_PWG, PA_SUBTYPE_PWG_HCD_INTERFACE },
+	{ PEN_PWG, PA_SUBTYPE_PWG_HCD_SCANNER }
+};
+
+static imv_hcd_attr_t attr_type_to_flag(pwg_attr_t attr_type)
+{
+	switch (attr_type)
+	{
+		case PWG_HCD_DEFAULT_PWD_ENABLED:
+			return IMV_HCD_ATTR_DEFAULT_PWD_ENABLED;
+		case PWG_HCD_FIREWALL_SETTING:
+			return IMV_HCD_ATTR_FIREWALL_SETTING;
+		case PWG_HCD_FORWARDING_ENABLED:
+			return IMV_HCD_ATTR_FORWARDING_ENABLED;
+		case PWG_HCD_MACHINE_TYPE_MODEL:
+			return IMV_HCD_ATTR_MACHINE_TYPE_MODEL;
+		case PWG_HCD_PSTN_FAX_ENABLED:
+			return IMV_HCD_ATTR_PSTN_FAX_ENABLED;
+		case PWG_HCD_TIME_SOURCE:
+			return IMV_HCD_ATTR_TIME_SOURCE;
+		case PWG_HCD_USER_APP_ENABLED:
+			return IMV_HCD_ATTR_USER_APP_ENABLED;
+		case PWG_HCD_USER_APP_PERSIST_ENABLED:
+			return IMV_HCD_ATTR_USER_APP_PERSIST_ENABLED;
+		case PWG_HCD_VENDOR_NAME:
+			return IMV_HCD_ATTR_VENDOR_NAME;
+		case PWG_HCD_VENDOR_SMI_CODE:
+			return IMV_HCD_ATTR_VENDOR_SMI_CODE;
+		case PWG_HCD_CERTIFICATION_STATE:
+			return IMV_HCD_ATTR_CERTIFICATION_STATE;
+		case PWG_HCD_CONFIGURATION_STATE:
+			return IMV_HCD_ATTR_CONFIGURATION_STATE;
+		case PWG_HCD_ATTRS_NATURAL_LANG:
+			return IMV_HCD_ATTR_NATURAL_LANG;
+		case PWG_HCD_FIRMWARE_NAME:
+			return IMV_HCD_ATTR_FIRMWARE_NAME;
+		case PWG_HCD_RESIDENT_APP_NAME:
+			return IMV_HCD_ATTR_RESIDENT_APP_NAME;
+		case PWG_HCD_USER_APP_NAME:
+			return IMV_HCD_ATTR_USER_APP_NAME;
+		default:
+			return IMV_HCD_ATTR_NONE;
+	}
+}
+
+/**
+ * Private data of an imv_hcd_agent_t object.
+ */
+struct private_imv_hcd_agent_t {
+
+	/**
+	 * Public members of imv_hcd_agent_t
+	 */
+	imv_agent_if_t public;
+
+	/**
+	 * IMV agent responsible for generic functions
+	 */
+	imv_agent_t *agent;
+
+};
+
+METHOD(imv_agent_if_t, bind_functions, TNC_Result,
+	private_imv_hcd_agent_t *this, TNC_TNCS_BindFunctionPointer bind_function)
+{
+	return this->agent->bind_functions(this->agent, bind_function);
+}
+
+METHOD(imv_agent_if_t, notify_connection_change, TNC_Result,
+	private_imv_hcd_agent_t *this, TNC_ConnectionID id,
+	TNC_ConnectionState new_state)
+{
+	TNC_IMV_Action_Recommendation rec;
+	imv_state_t *state;
+	imv_session_t *session;
+
+	switch (new_state)
+	{
+		case TNC_CONNECTION_STATE_CREATE:
+			state = imv_hcd_state_create(id);
+			return this->agent->create_state(this->agent, state);
+		case TNC_CONNECTION_STATE_DELETE:
+			return this->agent->delete_state(this->agent, id);
+		case TNC_CONNECTION_STATE_ACCESS_ALLOWED:
+		case TNC_CONNECTION_STATE_ACCESS_ISOLATED:
+		case TNC_CONNECTION_STATE_ACCESS_NONE:
+			if (this->agent->get_state(this->agent, id, &state) && imcv_db)
+			{
+				session = state->get_session(state);
+
+				if (session->get_policy_started(session))
+				{
+					switch (new_state)
+					{
+						case TNC_CONNECTION_STATE_ACCESS_ALLOWED:
+							rec = TNC_IMV_ACTION_RECOMMENDATION_ALLOW;
+							break;
+						case TNC_CONNECTION_STATE_ACCESS_ISOLATED:
+							rec = TNC_IMV_ACTION_RECOMMENDATION_ISOLATE;
+							break;
+						case TNC_CONNECTION_STATE_ACCESS_NONE:
+						default:
+							rec = TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS;
+					}
+					imcv_db->add_recommendation(imcv_db, session, rec);
+					if (!imcv_db->policy_script(imcv_db, session, FALSE))
+					{
+						DBG1(DBG_IMV, "error in policy script stop");
+					}
+				}
+			}
+			/* fall through to default state */
+		default:
+			return this->agent->change_state(this->agent, id, new_state, NULL);
+	}
+}
+
+/**
+ * Process a received message
+ */
+static TNC_Result receive_msg(private_imv_hcd_agent_t *this, imv_state_t *state,
+							  imv_msg_t *in_msg)
+{
+	imv_msg_t *out_msg;
+	imv_hcd_state_t *hcd_state;
+	pa_tnc_attr_t *attr;
+	enum_name_t *pa_subtype_names; 
+	pen_type_t type, msg_type;
+	TNC_Result result;
+	bool fatal_error = FALSE, assessment = FALSE;
+	enumerator_t *enumerator;
+
+	hcd_state = (imv_hcd_state_t*)state;
+
+	/* generate an outgoing PA-TNC message - we might need it */
+	out_msg = imv_msg_create_as_reply(in_msg);
+
+	/* parse received PA-TNC message and handle local and remote errors */
+	result = in_msg->receive(in_msg,out_msg, &fatal_error);
+	if (result != TNC_RESULT_SUCCESS)
+	{
+		out_msg->destroy(out_msg);
+		return result;
+	}
+	msg_type = in_msg->get_msg_type(in_msg);
+	pa_subtype_names = get_pa_subtype_names(msg_type.vendor_id);
+	DBG2(DBG_IMV, "received attributes for PA subtype %N/%N",
+		 pen_names, msg_type.vendor_id, pa_subtype_names, msg_type.type);
+
+	/* set current subtype */
+	if (msg_type.vendor_id == PEN_IETF)
+	{
+		hcd_state->set_subtype(hcd_state, PA_SUBTYPE_PWG_HCD_SYSTEM);
+	}
+	else
+	{
+		hcd_state->set_subtype(hcd_state, msg_type.type);
+	}
+
+	/* analyze PA-TNC attributes */
+	enumerator = in_msg->create_attribute_enumerator(in_msg);
+	while (enumerator->enumerate(enumerator, &attr))
+	{
+		type = attr->get_type(attr);
+
+		if (type.vendor_id == PEN_IETF)
+		{
+			switch (type.type)
+			{
+				case IETF_ATTR_FORWARDING_ENABLED:
+				{
+					ietf_attr_fwd_enabled_t *attr_cast;
+					os_fwd_status_t fwd_status;
+
+					attr_cast = (ietf_attr_fwd_enabled_t*)attr;
+					fwd_status = attr_cast->get_status(attr_cast);
+					DBG2(DBG_IMV, "  %N: %N", ietf_attr_names, type.type,
+								   os_fwd_status_names, fwd_status);
+					state->set_action_flags(state,
+											IMV_HCD_ATTR_FORWARDING_ENABLED);
+					break;
+				}
+				case IETF_ATTR_FACTORY_DEFAULT_PWD_ENABLED:
+				{
+					generic_attr_bool_t *attr_cast;
+					bool status;
+
+					attr_cast = (generic_attr_bool_t*)attr;
+					status = attr_cast->get_status(attr_cast);
+					DBG2(DBG_IMV, "  %N: %s", ietf_attr_names, type.type,
+								   status ? "yes" : "no");
+					state->set_action_flags(state,
+											IMV_HCD_ATTR_DEFAULT_PWD_ENABLED);
+					break;
+				}
+				default:
+					break;
+			}
+		}
+		else if (type.vendor_id == PEN_PWG)
+		{
+			state->set_action_flags(state, attr_type_to_flag(type.type));
+
+			switch (type.type)
+			{
+				case PWG_HCD_ATTRS_NATURAL_LANG:
+				case PWG_HCD_MACHINE_TYPE_MODEL:
+				case PWG_HCD_VENDOR_NAME:
+				case PWG_HCD_TIME_SOURCE:
+				case PWG_HCD_FIRMWARE_NAME:
+				case PWG_HCD_FIRMWARE_STRING_VERSION:
+				case PWG_HCD_RESIDENT_APP_NAME:
+				case PWG_HCD_RESIDENT_APP_STRING_VERSION:
+				case PWG_HCD_USER_APP_NAME:
+				case PWG_HCD_USER_APP_STRING_VERSION:
+				{
+					chunk_t value;
+
+					value = attr->get_value(attr);
+					DBG2(DBG_IMV, "  %N: %.*s", pwg_attr_names, type.type,
+								  value.len, value.ptr);
+					break;
+				}
+				case PWG_HCD_FIRMWARE_PATCHES:
+				case PWG_HCD_RESIDENT_APP_PATCHES:
+				case PWG_HCD_USER_APP_PATCHES:
+				{
+					chunk_t value;
+					size_t len;
+
+					value = attr->get_value(attr);
+					len = value.len;
+
+					/* remove any trailing LF from patches string */
+					if (len && (value.ptr[len - 1] == '\n'))
+					{
+						len--;
+					}
+					DBG2(DBG_IMV, "  %N:%s%.*s", pwg_attr_names, type.type,
+								  len ? "\n" : " ", len, value.ptr);
+					break;
+				}
+				case PWG_HCD_FIRMWARE_VERSION:
+				case PWG_HCD_RESIDENT_APP_VERSION:
+				case PWG_HCD_USER_APP_VERSION:
+				{
+					chunk_t value;
+
+					value = attr->get_value(attr);
+					DBG2(DBG_IMV, "  %N: %#B", pwg_attr_names, type.type, &value);
+					break;
+				}
+				case PWG_HCD_CERTIFICATION_STATE:
+				case PWG_HCD_CONFIGURATION_STATE:
+				{
+					chunk_t value;
+
+					value = attr->get_value(attr);
+					DBG2(DBG_IMV, "  %N: %B", pwg_attr_names, type.type, &value);
+					break;
+				}
+				case PWG_HCD_DEFAULT_PWD_ENABLED:
+				case PWG_HCD_PSTN_FAX_ENABLED:
+				case PWG_HCD_USER_APP_ENABLED:
+				case PWG_HCD_USER_APP_PERSIST_ENABLED:
+				{
+					generic_attr_bool_t *attr_cast;
+					bool status;
+
+					attr_cast = (generic_attr_bool_t*)attr;
+					status = attr_cast->get_status(attr_cast);
+					DBG2(DBG_IMV, "  %N: %s", pwg_attr_names, type.type,
+								  status ? "yes" : "no");
+
+					if (type.type == PWG_HCD_USER_APP_ENABLED && !status)
+					{
+						/* do not request user applications */
+						hcd_state->set_user_app_disabled(hcd_state);
+					}		
+					break;
+				}
+				case PWG_HCD_FORWARDING_ENABLED:
+				{
+					ietf_attr_fwd_enabled_t *attr_cast;
+					os_fwd_status_t fwd_status;
+
+					attr_cast = (ietf_attr_fwd_enabled_t*)attr;
+					fwd_status = attr_cast->get_status(attr_cast);
+					DBG2(DBG_IMV, "  %N: %N", pwg_attr_names, type.type,
+								  os_fwd_status_names, fwd_status);
+					break;
+				}
+
+				case PWG_HCD_VENDOR_SMI_CODE:
+				{
+					pwg_attr_vendor_smi_code_t *attr_cast;
+					uint32_t smi_code;
+
+					attr_cast = (pwg_attr_vendor_smi_code_t*)attr;
+					smi_code = attr_cast->get_vendor_smi_code(attr_cast);
+					DBG2(DBG_IMV, "  %N: 0x%06x (%u)", pwg_attr_names, type.type,
+								  smi_code, smi_code);
+					break;
+				}
+				default:
+					break;
+			}
+		}
+	}
+	enumerator->destroy(enumerator);
+
+	if (fatal_error)
+	{
+		state->set_recommendation(state,
+								TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION,
+								TNC_IMV_EVALUATION_RESULT_ERROR);
+		assessment = TRUE;
+	}
+
+	if (assessment)
+	{
+		hcd_state->set_handshake_state(hcd_state, IMV_HCD_STATE_END);
+		result = out_msg->send_assessment(out_msg);
+		if (result == TNC_RESULT_SUCCESS)
+		{
+			result = this->agent->provide_recommendation(this->agent, state);
+		}
+	}
+	else
+	{
+		/* send PA-TNC message with the EXCL flag set */
+		result = out_msg->send(out_msg, TRUE);
+	}
+	out_msg->destroy(out_msg);
+
+	return result;
+}
+
+METHOD(imv_agent_if_t, receive_message, TNC_Result,
+	private_imv_hcd_agent_t *this, TNC_ConnectionID id,
+	TNC_MessageType msg_type, chunk_t msg)
+{
+	imv_state_t *state;
+	imv_msg_t *in_msg;
+	TNC_Result result;
+
+	if (!this->agent->get_state(this->agent, id, &state))
+	{
+		return TNC_RESULT_FATAL;
+	}
+	in_msg = imv_msg_create_from_data(this->agent, state, id, msg_type, msg);
+	result = receive_msg(this, state, in_msg);
+	in_msg->destroy(in_msg);
+
+	return result;
+}
+
+METHOD(imv_agent_if_t, receive_message_long, TNC_Result,
+	private_imv_hcd_agent_t *this, TNC_ConnectionID id,
+	TNC_UInt32 src_imc_id, TNC_UInt32 dst_imv_id,
+	TNC_VendorID msg_vid, TNC_MessageSubtype msg_subtype, chunk_t msg)
+{
+	imv_state_t *state;
+	imv_msg_t *in_msg;
+	TNC_Result result;
+
+	if (!this->agent->get_state(this->agent, id, &state))
+	{
+		return TNC_RESULT_FATAL;
+	}
+	in_msg = imv_msg_create_from_long_data(this->agent, state, id,
+					src_imc_id, dst_imv_id, msg_vid, msg_subtype, msg);
+	result = receive_msg(this, state, in_msg);
+	in_msg->destroy(in_msg);
+
+	return result;
+
+}
+
+/**
+ * Build an IETF Attribute Request attribute for missing attributes
+ */
+static pa_tnc_attr_t* build_attr_request(uint32_t received)
+{
+	pa_tnc_attr_t *attr;
+	ietf_attr_attr_request_t *attr_cast;
+
+	attr = ietf_attr_attr_request_create(PEN_RESERVED, 0);
+	attr_cast = (ietf_attr_attr_request_t*)attr;
+
+	if (!(received & IMV_HCD_ATTR_NATURAL_LANG))
+	{
+		attr_cast->add(attr_cast, PEN_PWG, PWG_HCD_ATTRS_NATURAL_LANG);
+	}
+	if (!(received & IMV_HCD_ATTR_DEFAULT_PWD_ENABLED))
+	{
+		attr_cast->add(attr_cast, PEN_PWG, PWG_HCD_DEFAULT_PWD_ENABLED);
+	}
+	if (!(received & IMV_HCD_ATTR_FIREWALL_SETTING))
+	{
+		attr_cast->add(attr_cast, PEN_PWG, PWG_HCD_FIREWALL_SETTING);
+	}
+	if (!(received & IMV_HCD_ATTR_FIRMWARE_NAME))
+	{
+		attr_cast->add(attr_cast, PEN_PWG, PWG_HCD_FIRMWARE_NAME);
+	}
+	if (!(received & IMV_HCD_ATTR_FORWARDING_ENABLED))
+	{
+		attr_cast->add(attr_cast, PEN_PWG, PWG_HCD_FORWARDING_ENABLED);
+	}
+	if (!(received & IMV_HCD_ATTR_MACHINE_TYPE_MODEL))
+	{
+		attr_cast->add(attr_cast, PEN_PWG, PWG_HCD_MACHINE_TYPE_MODEL);
+	}
+	if (!(received & IMV_HCD_ATTR_PSTN_FAX_ENABLED))
+	{
+		attr_cast->add(attr_cast, PEN_PWG, PWG_HCD_PSTN_FAX_ENABLED);
+	}
+	if (!(received & IMV_HCD_ATTR_RESIDENT_APP_NAME))
+	{
+		attr_cast->add(attr_cast, PEN_PWG, PWG_HCD_RESIDENT_APP_NAME);
+	}
+	if (!(received & IMV_HCD_ATTR_TIME_SOURCE))
+	{
+		attr_cast->add(attr_cast, PEN_PWG, PWG_HCD_TIME_SOURCE);
+	}
+	if (!(received & IMV_HCD_ATTR_USER_APP_ENABLED))
+	{
+		attr_cast->add(attr_cast, PEN_PWG, PWG_HCD_USER_APP_ENABLED);
+	}
+	if (!(received & IMV_HCD_ATTR_USER_APP_PERSIST_ENABLED))
+	{
+		attr_cast->add(attr_cast, PEN_PWG, PWG_HCD_USER_APP_PERSIST_ENABLED);
+	}
+	if (!(received & IMV_HCD_ATTR_USER_APP_NAME))
+	{
+		attr_cast->add(attr_cast, PEN_PWG, PWG_HCD_USER_APP_NAME);
+	}
+	if (!(received & IMV_HCD_ATTR_VENDOR_NAME))
+	{
+		attr_cast->add(attr_cast, PEN_PWG, PWG_HCD_VENDOR_NAME);
+	}
+	if (!(received & IMV_HCD_ATTR_VENDOR_SMI_CODE))
+	{
+		attr_cast->add(attr_cast, PEN_PWG, PWG_HCD_VENDOR_SMI_CODE);
+	}
+	if (!(received & IMV_HCD_ATTR_CERTIFICATION_STATE))
+	{
+		attr_cast->add(attr_cast, PEN_PWG, PWG_HCD_CERTIFICATION_STATE);
+	}
+	if (!(received & IMV_HCD_ATTR_CONFIGURATION_STATE))
+	{
+		attr_cast->add(attr_cast, PEN_PWG, PWG_HCD_CONFIGURATION_STATE);
+	}
+	return attr;
+}
+
+METHOD(imv_agent_if_t, batch_ending, TNC_Result,
+	private_imv_hcd_agent_t *this, TNC_ConnectionID id)
+{
+	imv_msg_t *out_msg;
+	imv_state_t *state;
+	imv_hcd_state_t *hcd_state;
+	imv_hcd_handshake_state_t handshake_state;
+	pa_tnc_attr_t *attr;
+	TNC_IMVID imv_id;
+	TNC_Result result = TNC_RESULT_SUCCESS;
+
+	if (!this->agent->get_state(this->agent, id, &state))
+	{
+		return TNC_RESULT_FATAL;
+	}
+	hcd_state = (imv_hcd_state_t*)state;
+	handshake_state = hcd_state->get_handshake_state(hcd_state);
+	imv_id = this->agent->get_id(this->agent);
+
+	if (handshake_state == IMV_HCD_STATE_END)
+	{
+		return TNC_RESULT_SUCCESS;
+	}
+
+	if (handshake_state == IMV_HCD_STATE_INIT)
+	{
+		size_t max_attr_size = HCD_MAX_ATTR_SIZE;
+		size_t max_seg_size;
+		seg_contract_t *contract;
+		seg_contract_manager_t *contracts;
+		char buf[BUF_LEN];
+		uint32_t received;
+		int i;
+
+		/* Determine maximum PA-TNC attribute segment size */
+		max_seg_size = state->get_max_msg_len(state)
+								- PA_TNC_HEADER_SIZE 
+								- PA_TNC_ATTR_HEADER_SIZE
+								- TCG_SEG_ATTR_SEG_ENV_HEADER
+								- PA_TNC_ATTR_HEADER_SIZE
+								- TCG_SEG_ATTR_MAX_SIZE_SIZE;
+		contracts = state->get_contracts(state);
+
+		for (i = 1; i < countof(msg_types); i++)
+		{
+			out_msg = imv_msg_create(this->agent, state, id, imv_id,
+									 TNC_IMCID_ANY, msg_types[i]);
+
+			/* Announce support of PA-TNC segmentation to IMC */
+			contract = seg_contract_create(msg_types[i], max_attr_size,
+										   max_seg_size, TRUE, imv_id, FALSE);
+			contract->get_info_string(contract, buf, BUF_LEN, TRUE);
+			DBG2(DBG_IMV, "%s", buf);
+			contracts->add_contract(contracts, contract);
+			attr = tcg_seg_attr_max_size_create(max_attr_size, max_seg_size,
+												TRUE);
+			out_msg->add_attribute(out_msg, attr);
+
+			hcd_state->set_subtype(hcd_state, msg_types[i].type);	
+			received = state->get_action_flags(state);
+
+			if ((received & IMV_HCD_ATTR_MUST) != IMV_HCD_ATTR_MUST)
+			{
+				/* create attribute request for missing mandatory attributes */
+				out_msg->add_attribute(out_msg, build_attr_request(received));
+			}
+			result = out_msg->send(out_msg, FALSE);
+			out_msg->destroy(out_msg);
+
+			if (result != TNC_RESULT_SUCCESS)
+			{
+				break;
+			}
+		}
+		hcd_state->set_handshake_state(hcd_state, IMV_HCD_STATE_ATTR_REQ);
+	}
+
+	return result;
+}
+
+METHOD(imv_agent_if_t, solicit_recommendation, TNC_Result,
+	private_imv_hcd_agent_t *this, TNC_ConnectionID id)
+{
+	imv_state_t *state;
+	imv_hcd_state_t* hcd_state;
+	imv_hcd_handshake_state_t handshake_state;
+	enum_name_t *pa_subtype_names;
+	bool missing = FALSE;
+	uint32_t received;
+	int i;
+
+	if (!this->agent->get_state(this->agent, id, &state))
+	{
+		return TNC_RESULT_FATAL;
+	}
+	hcd_state = (imv_hcd_state_t*)state;
+	handshake_state = hcd_state->get_handshake_state(hcd_state);
+
+	if (handshake_state == IMV_HCD_STATE_ATTR_REQ)
+	{
+		pa_subtype_names = get_pa_subtype_names(PEN_PWG);
+
+		for (i = 1; i < countof(msg_types); i++)
+		{
+			hcd_state->set_subtype(hcd_state, msg_types[i].type);
+			received = state->get_action_flags(state);
+			if ((received & IMV_HCD_ATTR_MUST) != IMV_HCD_ATTR_MUST)
+			{
+				DBG1(DBG_IMV, "missing attributes for PA subtype %N/%N",
+					 pen_names, PEN_PWG, pa_subtype_names, msg_types[i].type);
+				missing = TRUE;
+			}
+		}
+
+		if (missing)
+		{
+			state->set_recommendation(state,
+							TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS ,
+							TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR);
+		}
+		else
+		{
+			state->set_recommendation(state,
+							TNC_IMV_ACTION_RECOMMENDATION_ALLOW ,
+							TNC_IMV_EVALUATION_RESULT_COMPLIANT);
+		}
+	}
+	hcd_state->set_handshake_state(hcd_state, IMV_HCD_STATE_END);
+
+	return this->agent->provide_recommendation(this->agent, state);
+}
+
+METHOD(imv_agent_if_t, destroy, void,
+	private_imv_hcd_agent_t *this)
+{
+	DESTROY_IF(this->agent);
+	free(this);
+}
+
+/**
+ * Described in header.
+ */
+imv_agent_if_t *imv_hcd_agent_create(const char *name, TNC_IMVID id,
+									TNC_Version *actual_version)
+{
+	private_imv_hcd_agent_t *this;
+	imv_agent_t *agent;
+
+	agent = imv_agent_create(name, msg_types, countof(msg_types), id,
+							 actual_version);
+	if (!agent)
+	{
+		return NULL;
+	}
+
+	INIT(this,
+		.public = {
+			.bind_functions = _bind_functions,
+			.notify_connection_change = _notify_connection_change,
+			.receive_message = _receive_message,
+			.receive_message_long = _receive_message_long,
+			.batch_ending = _batch_ending,
+			.solicit_recommendation = _solicit_recommendation,
+			.destroy = _destroy,
+		},
+		.agent = agent,
+	);
+
+	return &this->public;
+}
+
diff --git a/src/libstrongswan/credentials/certificates/ocsp_request.h b/src/libimcv/plugins/imv_hcd/imv_hcd_agent.h
similarity index 53%
copy from src/libstrongswan/credentials/certificates/ocsp_request.h
copy to src/libimcv/plugins/imv_hcd/imv_hcd_agent.h
index 0b18713..d4e2e3f 100644
--- a/src/libstrongswan/credentials/certificates/ocsp_request.h
+++ b/src/libimcv/plugins/imv_hcd/imv_hcd_agent.h
@@ -1,6 +1,6 @@
 /*
- * Copyright (C) 2008 Martin Willi
- * Hochschule fuer Technik Rapperswil
+ * Copyright (C) 2015 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
@@ -14,26 +14,23 @@
  */
 
 /**
- * @defgroup ocsp_request ocsp_request
- * @{ @ingroup certificates
+ * @defgroup imv_hcd_agent_t imv_hcd_agent
+ * @{ @ingroup imv_hcd
  */
 
-#ifndef OCSP_REQUEST_H_
-#define OCSP_REQUEST_H_
+#ifndef IMV_HCD_AGENT_H_
+#define IMV_HCD_AGENT_H_
 
-#include <credentials/certificates/certificate.h>
-
-typedef struct ocsp_request_t ocsp_request_t;
+#include <imv/imv_agent_if.h>
 
 /**
- * OCSP request message.
+ * Creates a HCD IMV agent
+ *
+ * @param name					Name of the IMV
+ * @param id					ID of the IMV
+ * @param actual_version		TNC IF-IMV version
  */
-struct ocsp_request_t {
-
-	/**
-	 * Implements certificiate_t interface
-	 */
-	certificate_t interface;
-};
+imv_agent_if_t* imv_hcd_agent_create(const char* name, TNC_IMVID id,
+									TNC_Version *actual_version);
 
-#endif /** OCSP_REQUEST_H_ @}*/
+#endif /** IMV_HCD_AGENT_H_ @}*/
diff --git a/src/libimcv/plugins/imv_hcd/imv_hcd_state.c b/src/libimcv/plugins/imv_hcd/imv_hcd_state.c
new file mode 100644
index 0000000..bfe6dd6
--- /dev/null
+++ b/src/libimcv/plugins/imv_hcd/imv_hcd_state.c
@@ -0,0 +1,350 @@
+/*
+ * Copyright (C) 2015 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
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include "imv_hcd_state.h"
+#include "imv/imv_lang_string.h"
+#include "imv/imv_reason_string.h"
+
+#include <tncif_policy.h>
+
+#include <utils/debug.h>
+
+typedef struct private_imv_hcd_state_t private_imv_hcd_state_t;
+typedef struct subtype_action_flags_t subtype_action_flags_t;
+
+struct subtype_action_flags_t {
+	pa_subtype_pwg_t subtype;
+	uint32_t action_flags;
+};
+
+/**
+ * Private data of an imv_hcd_state_t object.
+ */
+struct private_imv_hcd_state_t {
+
+	/**
+	 * Public members of imv_hcd_state_t
+	 */
+	imv_hcd_state_t public;
+
+	/**
+	 * TNCCS connection ID
+	 */
+	TNC_ConnectionID connection_id;
+
+	/**
+	 * TNCCS connection state
+	 */
+	TNC_ConnectionState state;
+
+	/**
+	 * Does the TNCCS connection support long message types?
+	 */
+	bool has_long;
+
+	/**
+	 * Does the TNCCS connection support exclusive delivery?
+	 */
+	bool has_excl;
+
+	/**
+	 * Maximum PA-TNC message size for this TNCCS connection
+	 */
+	uint32_t max_msg_len;
+
+	/**
+	 * Current flags set for completed actions
+	 */
+	uint32_t *action_flags;
+
+	/**
+	 * Action flags for all PA subtypes
+	 */
+	subtype_action_flags_t subtype_action_flags[6];
+
+	/**
+	 * IMV database session associated with TNCCS connection
+	 */
+	imv_session_t *session;
+
+	/**
+	 * PA-TNC attribute segmentation contracts associated with TNCCS connection
+	 */
+	seg_contract_manager_t *contracts;
+
+	/**
+	 * IMV action recommendation
+	 */
+	TNC_IMV_Action_Recommendation rec;
+
+	/**
+	 * IMV evaluation result
+	 */
+	TNC_IMV_Evaluation_Result eval;
+
+	/**
+	 * IMV OS handshake state
+	 */
+	imv_hcd_handshake_state_t handshake_state;
+
+	/**
+	 * TNC Reason String
+	 */
+	imv_reason_string_t *reason_string;
+
+};
+
+/**
+ * Supported languages
+ */
+static char* languages[] = { "en", "de", "fr", "pl" };
+
+/**
+ * Reason strings for "Port Filter"
+ */
+static imv_lang_string_t reasons[] = {
+	{ "en", "Mandatory HCD attributes are missing" },
+	{ "de", "Obligatorische HCD Attribute fehlen" },
+	{ "fr", "Il manque des attributes HCD obligatoires" },
+	{ "pl", "Brakuje atrybutów obowiązkowych" },
+	{ NULL, NULL }
+};
+
+METHOD(imv_state_t, get_connection_id, TNC_ConnectionID,
+	private_imv_hcd_state_t *this)
+{
+	return this->connection_id;
+}
+
+METHOD(imv_state_t, has_long, bool,
+	private_imv_hcd_state_t *this)
+{
+	return this->has_long;
+}
+
+METHOD(imv_state_t, has_excl, bool,
+	private_imv_hcd_state_t *this)
+{
+	return this->has_excl;
+}
+
+METHOD(imv_state_t, set_flags, void,
+	private_imv_hcd_state_t *this, bool has_long, bool has_excl)
+{
+	this->has_long = has_long;
+	this->has_excl = has_excl;
+}
+
+METHOD(imv_state_t, set_max_msg_len, void,
+	private_imv_hcd_state_t *this, uint32_t max_msg_len)
+{
+	this->max_msg_len = max_msg_len;
+}
+
+METHOD(imv_state_t, get_max_msg_len, uint32_t,
+	private_imv_hcd_state_t *this)
+{
+	return this->max_msg_len;
+}
+
+METHOD(imv_state_t, set_action_flags, void,
+	private_imv_hcd_state_t *this, uint32_t flags)
+{
+	*this->action_flags |= flags;
+}
+
+METHOD(imv_state_t, get_action_flags, uint32_t,
+	private_imv_hcd_state_t *this)
+{
+	return *this->action_flags;
+}
+
+METHOD(imv_state_t, set_session, void,
+	private_imv_hcd_state_t *this, imv_session_t *session)
+{
+	this->session = session;
+}
+
+METHOD(imv_state_t, get_session, imv_session_t*,
+	private_imv_hcd_state_t *this)
+{
+	return this->session;
+}
+
+METHOD(imv_state_t, get_contracts, seg_contract_manager_t*,
+	private_imv_hcd_state_t *this)
+{
+	return this->contracts;
+}
+
+METHOD(imv_state_t, get_recommendation, void,
+	private_imv_hcd_state_t *this, TNC_IMV_Action_Recommendation *rec,
+								  TNC_IMV_Evaluation_Result *eval)
+{
+	*rec = this->rec;
+	*eval = this->eval;
+}
+
+METHOD(imv_state_t, set_recommendation, void,
+	private_imv_hcd_state_t *this, TNC_IMV_Action_Recommendation rec,
+								  TNC_IMV_Evaluation_Result eval)
+{
+	this->rec = rec;
+	this->eval = eval;
+}
+
+METHOD(imv_state_t, update_recommendation, void,
+	private_imv_hcd_state_t *this, TNC_IMV_Action_Recommendation rec,
+								  TNC_IMV_Evaluation_Result eval)
+{
+	this->rec  = tncif_policy_update_recommendation(this->rec, rec);
+	this->eval = tncif_policy_update_evaluation(this->eval, eval);
+}
+
+METHOD(imv_state_t, change_state, void,
+	private_imv_hcd_state_t *this, TNC_ConnectionState new_state)
+{
+	this->state = new_state;
+}
+
+METHOD(imv_state_t, get_reason_string, bool,
+	private_imv_hcd_state_t *this, enumerator_t *language_enumerator,
+	chunk_t *reason_string, char **reason_language)
+{
+	if (this->rec == TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION)
+	{
+		return FALSE;
+	}
+	*reason_language = imv_lang_string_select_lang(language_enumerator,
+											  languages, countof(languages));
+
+	/* Instantiate a TNC Reason String object */
+	DESTROY_IF(this->reason_string);
+	this->reason_string = imv_reason_string_create(*reason_language, "\n");
+	this->reason_string->add_reason(this->reason_string, reasons);
+	*reason_string = this->reason_string->get_encoding(this->reason_string);
+
+	return TRUE;
+}
+
+METHOD(imv_state_t, get_remediation_instructions, bool,
+	private_imv_hcd_state_t *this, enumerator_t *language_enumerator,
+	chunk_t *string, char **lang_code, char **uri)
+{
+	return FALSE;
+}
+
+METHOD(imv_state_t, destroy, void,
+	private_imv_hcd_state_t *this)
+{
+	DESTROY_IF(this->session);
+	DESTROY_IF(this->reason_string);
+	this->contracts->destroy(this->contracts);
+	free(this);
+}
+
+METHOD(imv_hcd_state_t, set_handshake_state, void,
+	private_imv_hcd_state_t *this, imv_hcd_handshake_state_t new_state)
+{
+	this->handshake_state = new_state;
+}
+
+METHOD(imv_hcd_state_t, get_handshake_state, imv_hcd_handshake_state_t,
+	private_imv_hcd_state_t *this)
+{
+	return this->handshake_state;
+}
+
+METHOD(imv_hcd_state_t, set_subtype, void,
+	private_imv_hcd_state_t *this, pa_subtype_pwg_t subtype)
+{
+	int i;
+
+	for (i = 0; i < countof(this->subtype_action_flags); i++)
+	{
+		if (subtype == this->subtype_action_flags[i].subtype)
+		{
+			this->action_flags = &this->subtype_action_flags[i].action_flags;
+			break;
+		}
+	}
+}
+
+METHOD(imv_hcd_state_t, set_user_app_disabled, void,
+	private_imv_hcd_state_t *this)
+{
+	int i;
+
+	for (i = 0; i < countof(this->subtype_action_flags); i++)
+	{
+		this->subtype_action_flags[i].action_flags |= IMV_HCD_ATTR_USER_APP_NAME;
+	}
+}
+
+/**
+ * Described in header.
+ */
+imv_state_t *imv_hcd_state_create(TNC_ConnectionID connection_id)
+{
+	private_imv_hcd_state_t *this;
+
+	INIT(this,
+		.public = {
+			.interface = {
+				.get_connection_id = _get_connection_id,
+				.has_long = _has_long,
+				.has_excl = _has_excl,
+				.set_flags = _set_flags,
+				.set_max_msg_len = _set_max_msg_len,
+				.get_max_msg_len = _get_max_msg_len,
+				.set_action_flags = _set_action_flags,
+				.get_action_flags = _get_action_flags,
+				.set_session = _set_session,
+				.get_session = _get_session,
+				.get_contracts = _get_contracts,
+				.change_state = _change_state,
+				.get_recommendation = _get_recommendation,
+				.set_recommendation = _set_recommendation,
+				.update_recommendation = _update_recommendation,
+				.get_reason_string = _get_reason_string,
+				.get_remediation_instructions = _get_remediation_instructions,
+				.destroy = _destroy,
+			},
+			.set_handshake_state = _set_handshake_state,
+			.get_handshake_state = _get_handshake_state,
+			.set_subtype = _set_subtype,
+			.set_user_app_disabled = _set_user_app_disabled,
+		},
+		.state = TNC_CONNECTION_STATE_CREATE,
+		.rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION,
+		.eval = TNC_IMV_EVALUATION_RESULT_DONT_KNOW,
+		.connection_id = connection_id,
+		.contracts = seg_contract_manager_create(),
+		.subtype_action_flags = {
+			{ PA_SUBTYPE_PWG_HCD_SYSTEM,    IMV_HCD_ATTR_NONE        },
+			{ PA_SUBTYPE_PWG_HCD_CONSOLE,   IMV_HCD_ATTR_SYSTEM_ONLY },
+			{ PA_SUBTYPE_PWG_HCD_MARKER,    IMV_HCD_ATTR_SYSTEM_ONLY },
+			{ PA_SUBTYPE_PWG_HCD_FINISHER,  IMV_HCD_ATTR_SYSTEM_ONLY },
+			{ PA_SUBTYPE_PWG_HCD_INTERFACE, IMV_HCD_ATTR_SYSTEM_ONLY },
+			{ PA_SUBTYPE_PWG_HCD_SCANNER,   IMV_HCD_ATTR_SYSTEM_ONLY },
+		}
+	);
+
+	this->action_flags = &this->subtype_action_flags[0].action_flags;
+
+	return &this->public.interface;
+}
+
+
diff --git a/src/libimcv/plugins/imv_hcd/imv_hcd_state.h b/src/libimcv/plugins/imv_hcd/imv_hcd_state.h
new file mode 100644
index 0000000..dce9b30
--- /dev/null
+++ b/src/libimcv/plugins/imv_hcd/imv_hcd_state.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2015 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
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup imv_hcd imv_hcd
+ * @ingroup libimcv_plugins
+ *
+ * @defgroup imv_hcd_state_t imv_hcd_state
+ * @{ @ingroup imv_hcd
+ */
+
+#ifndef IMV_HCD_STATE_H_
+#define IMV_HCD_STATE_H_
+
+#include <imv/imv_state.h>
+#include <library.h>
+
+#include <tncif_pa_subtypes.h>
+
+typedef struct imv_hcd_state_t imv_hcd_state_t;
+typedef enum imv_hcd_attr_t imv_hcd_attr_t;
+typedef enum imv_hcd_handshake_state_t imv_hcd_handshake_state_t;
+typedef enum os_settings_t os_settings_t;
+
+/**
+ * Flag set when corresponding attribute has been received
+ */
+enum imv_hcd_attr_t {
+	IMV_HCD_ATTR_NONE =                          0,
+	IMV_HCD_ATTR_DEFAULT_PWD_ENABLED =       (1<<0),
+	IMV_HCD_ATTR_FIREWALL_SETTING =          (1<<1),
+	IMV_HCD_ATTR_FORWARDING_ENABLED =        (1<<2),
+	IMV_HCD_ATTR_MACHINE_TYPE_MODEL =        (1<<3),
+	IMV_HCD_ATTR_PSTN_FAX_ENABLED =          (1<<4),
+	IMV_HCD_ATTR_TIME_SOURCE =               (1<<5),
+	IMV_HCD_ATTR_USER_APP_ENABLED =          (1<<6),
+	IMV_HCD_ATTR_USER_APP_PERSIST_ENABLED =  (1<<7),
+	IMV_HCD_ATTR_VENDOR_NAME =               (1<<8),
+	IMV_HCD_ATTR_VENDOR_SMI_CODE =           (1<<9),
+	IMV_HCD_ATTR_CERTIFICATION_STATE =       (1<<10),
+	IMV_HCD_ATTR_CONFIGURATION_STATE =       (1<<11),
+
+	IMV_HCD_ATTR_SYSTEM_ONLY =               (1<<12)-1,
+
+	IMV_HCD_ATTR_NATURAL_LANG =              (1<<12),
+	IMV_HCD_ATTR_FIRMWARE_NAME =             (1<<13),
+	IMV_HCD_ATTR_RESIDENT_APP_NAME =         (1<<14),
+	IMV_HCD_ATTR_USER_APP_NAME =             (1<<15),
+
+	IMV_HCD_ATTR_MUST =                      (1<<16)-1
+};
+
+/**
+ * IMV OS Handshake States (state machine)
+ */
+enum imv_hcd_handshake_state_t {
+	IMV_HCD_STATE_INIT,
+	IMV_HCD_STATE_ATTR_REQ,
+	IMV_HCD_STATE_END
+};
+
+/**
+ * Internal state of an imv_hcd_t connection instance
+ */
+struct imv_hcd_state_t {
+
+	/**
+	 * imv_state_t interface
+	 */
+	imv_state_t interface;
+
+	/**
+	 * Set state of the handshake
+	 *
+	 * @param new_state			the handshake state of IMV
+	 */
+	void (*set_handshake_state)(imv_hcd_state_t *this,
+								imv_hcd_handshake_state_t new_state);
+
+	/**
+	 * Get state of the handshake
+	 *
+	 * @return					the handshake state of IMV
+	 */
+	imv_hcd_handshake_state_t (*get_handshake_state)(imv_hcd_state_t *this);
+
+	/**
+	 * Set the PWG HCD PA subtype currently being handled
+	 *
+	 * @param subtype			PWG HCD PA subtype
+	 */
+	void (*set_subtype)(imv_hcd_state_t *this, pa_subtype_pwg_t subtype);
+
+	/**
+	 * Set User Application Disabled
+	 */
+	void (*set_user_app_disabled)(imv_hcd_state_t *this);
+
+};
+
+/**
+ * Create an imv_hcd_state_t instance
+ *
+ * @param id			connection ID
+ */
+imv_state_t* imv_hcd_state_create(TNC_ConnectionID id);
+
+#endif /** IMV_HCD_STATE_H_ @}*/
diff --git a/src/libimcv/plugins/imv_os/imv_os_agent.c b/src/libimcv/plugins/imv_os/imv_os_agent.c
index f0b1936..4bf6c7e 100644
--- a/src/libimcv/plugins/imv_os/imv_os_agent.c
+++ b/src/libimcv/plugins/imv_os/imv_os_agent.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013-2014 Andreas Steffen
+ * Copyright (C) 2013-2015 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -23,10 +23,10 @@
 #include <imcv.h>
 #include <imv/imv_agent.h>
 #include <imv/imv_msg.h>
+#include <generic/generic_attr_bool.h>
+#include <generic/generic_attr_string.h>
 #include <ietf/ietf_attr.h>
 #include <ietf/ietf_attr_attr_request.h>
-#include <ietf/ietf_attr_default_pwd_enabled.h>
-#include <ietf/ietf_attr_fwd_enabled.h>
 #include <ietf/ietf_attr_installed_packages.h>
 #include <ietf/ietf_attr_numeric_version.h>
 #include <ietf/ietf_attr_op_status.h>
@@ -37,7 +37,6 @@
 #include <ita/ita_attr.h>
 #include <ita/ita_attr_get_settings.h>
 #include <ita/ita_attr_settings.h>
-#include <ita/ita_attr_device_id.h>
 #include "tcg/seg/tcg_seg_attr_max_size.h"
 #include "tcg/seg/tcg_seg_attr_seg_env.h"
 
@@ -270,12 +269,12 @@ static TNC_Result receive_msg(private_imv_os_agent_t *this, imv_state_t *state,
 				}
 				case IETF_ATTR_FORWARDING_ENABLED:
 				{
-					ietf_attr_fwd_enabled_t *attr_cast;
+					generic_attr_bool_t *attr_cast;
 					os_fwd_status_t fwd_status;
 
 					state->set_action_flags(state,
 											IMV_OS_ATTR_FORWARDING_ENABLED);
-					attr_cast = (ietf_attr_fwd_enabled_t*)attr;
+					attr_cast = (generic_attr_bool_t*)attr;
 					fwd_status = attr_cast->get_status(attr_cast);
 					DBG1(DBG_IMV, "IPv4 forwarding is %N",
 								   os_fwd_status_names, fwd_status);
@@ -288,12 +287,12 @@ static TNC_Result receive_msg(private_imv_os_agent_t *this, imv_state_t *state,
 				}
 				case IETF_ATTR_FACTORY_DEFAULT_PWD_ENABLED:
 				{
-					ietf_attr_default_pwd_enabled_t *attr_cast;
+					generic_attr_bool_t *attr_cast;
 					bool default_pwd_status;
 
 					state->set_action_flags(state,
 									IMV_OS_ATTR_FACTORY_DEFAULT_PWD_ENABLED);
-					attr_cast = (ietf_attr_default_pwd_enabled_t*)attr;
+					attr_cast = (generic_attr_bool_t*)attr;
 					default_pwd_status = attr_cast->get_status(attr_cast);
 					DBG1(DBG_IMV, "factory default password is %sabled",
 								   default_pwd_status ? "en":"dis");
@@ -542,9 +541,7 @@ METHOD(imv_agent_if_t, batch_ending, TNC_Result,
 		max_seg_size = state->get_max_msg_len(state)
 								- PA_TNC_HEADER_SIZE 
 								- PA_TNC_ATTR_HEADER_SIZE
-								- TCG_SEG_ATTR_SEG_ENV_HEADER
-								- PA_TNC_ATTR_HEADER_SIZE
-								- TCG_SEG_ATTR_MAX_SIZE_SIZE;
+								- TCG_SEG_ATTR_SEG_ENV_HEADER;
 
 		/* Announce support of PA-TNC segmentation to IMC */
 		contract = seg_contract_create(msg_types[0], max_attr_size,
diff --git a/src/libimcv/plugins/imv_os/pacman.c b/src/libimcv/plugins/imv_os/pacman.c
index 019e2ad..fbcab5e 100644
--- a/src/libimcv/plugins/imv_os/pacman.c
+++ b/src/libimcv/plugins/imv_os/pacman.c
@@ -104,8 +104,14 @@ static void cleanup(void)
 
 static void usage(void)
 {
- 	printf("Usage:\n"
-		   "ipsec pacman --product <name> --file <filename> [--update]\n");
+	printf("Parses package information files from Debian/Ubuntu repositories and\n");
+	printf("stores the extracted information in the database used by the OS IMV.\n\n");
+	printf("ipsec pacman --product <name> --file <filename> [--security]\n\n");
+	printf("  --help               print usage information\n");
+	printf("  --product <name>     name of the Debian/Ubuntu release, as stored in the DB\n");
+	printf("  --file <filename>    package information file to parse\n");
+	printf("  --security           set this when parsing a file with security updates\n");
+	printf("\n");
 }
 
 /**
@@ -396,6 +402,17 @@ static void process_packages(char *filename, char *product, bool security)
 				pacman_state = PACMAN_STATE_BEGIN_PACKAGE;
 		}
 	}
+	switch (pacman_state)
+	{
+		case PACMAN_STATE_END_PACKAGE:
+			free(version);
+			/* fall-through */
+		case PACMAN_STATE_VERSION:
+			free(package);
+			break;
+		default:
+			break;
+	}
 	fclose(file);
 	db->destroy(db);
 
diff --git a/src/libimcv/plugins/imv_scanner/imv_scanner_agent.c b/src/libimcv/plugins/imv_scanner/imv_scanner_agent.c
index cbabc80..acef11c 100644
--- a/src/libimcv/plugins/imv_scanner/imv_scanner_agent.c
+++ b/src/libimcv/plugins/imv_scanner/imv_scanner_agent.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013-2014 Andreas Steffen
+ * Copyright (C) 2013-2015 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -35,7 +35,7 @@ typedef struct private_imv_scanner_agent_t private_imv_scanner_agent_t;
 
 /* Subscribed PA-TNC message subtypes */
 static pen_type_t msg_types[] = {
-	{ PEN_IETF, PA_SUBTYPE_IETF_VPN }
+	{ PEN_IETF, PA_SUBTYPE_IETF_FIREWALL }
 };
 
 /**
diff --git a/src/libimcv/plugins/imv_swid/imv_swid_agent.c b/src/libimcv/plugins/imv_swid/imv_swid_agent.c
index 5bebf32..6d32783 100644
--- a/src/libimcv/plugins/imv_swid/imv_swid_agent.c
+++ b/src/libimcv/plugins/imv_swid/imv_swid_agent.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013-2014 Andreas Steffen
+ * Copyright (C) 2013-2015 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -446,9 +446,7 @@ METHOD(imv_agent_if_t, batch_ending, TNC_Result,
 				max_seg_size = state->get_max_msg_len(state)
 								- PA_TNC_HEADER_SIZE 
 								- PA_TNC_ATTR_HEADER_SIZE
-								- TCG_SEG_ATTR_SEG_ENV_HEADER
-								- PA_TNC_ATTR_HEADER_SIZE
-								- TCG_SEG_ATTR_MAX_SIZE_SIZE;
+								- TCG_SEG_ATTR_SEG_ENV_HEADER;
 
 				/* Announce support of PA-TNC segmentation to IMC */
 				contract = seg_contract_create(msg_types[0], max_attr_size,
diff --git a/src/libimcv/pwg/pwg_attr.c b/src/libimcv/pwg/pwg_attr.c
new file mode 100644
index 0000000..8a2eb28
--- /dev/null
+++ b/src/libimcv/pwg/pwg_attr.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2015 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
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include "pwg_attr.h"
+
+#include "generic/generic_attr_bool.h"
+#include "generic/generic_attr_chunk.h"
+#include "generic/generic_attr_string.h"
+#include "ietf/ietf_attr_fwd_enabled.h"
+#include "ietf/ietf_attr_port_filter.h"
+#include "pwg/pwg_attr_vendor_smi_code.h"
+
+ENUM_BEGIN(pwg_attr_names,	PWG_HCD_ATTRS_NATURAL_LANG,
+							PWG_HCD_VENDOR_SMI_CODE,
+	"HCD AttributesNaturalLanguage",
+	"HCD MachineTypeModel",
+	"HCD VendorName",
+	"HCD VendorSMICode");
+ENUM_NEXT(pwg_attr_names,	PWG_HCD_DEFAULT_PWD_ENABLED,
+							PWG_HCD_FORWARDING_ENABLED,
+							PWG_HCD_VENDOR_SMI_CODE,
+	"HCD DefaultPasswordEnabled",
+	"HCD FirewallSetting",
+	"HCD ForwardingEnabled");
+ENUM_NEXT(pwg_attr_names,	PWG_HCD_PSTN_FAX_ENABLED,
+							PWG_HCD_PSTN_FAX_ENABLED,
+							PWG_HCD_FORWARDING_ENABLED,
+	"HCD PSTNFaxEnabled");
+ENUM_NEXT(pwg_attr_names,	PWG_HCD_TIME_SOURCE,
+							PWG_HCD_TIME_SOURCE,
+							PWG_HCD_PSTN_FAX_ENABLED,
+	"HCD TimeSource");
+ENUM_NEXT(pwg_attr_names,	PWG_HCD_FIRMWARE_NAME,
+							PWG_HCD_FIRMWARE_VERSION,
+							PWG_HCD_TIME_SOURCE,
+	"HCD FirmwareName",
+	"HCD FirmwarePatches",
+	"HCD FirmwareStringVersion",
+	"HCD FirmwareVersion");
+ENUM_NEXT(pwg_attr_names,	PWG_HCD_RESIDENT_APP_NAME,
+							PWG_HCD_RESIDENT_APP_VERSION,
+							PWG_HCD_FIRMWARE_VERSION,
+	"HCD ResidentApplicationName",
+	"HCD ResidentApplicationPatches",
+	"HCD ResidentApplicationStringVersion",
+	"HCD ResidentApplicationVersion");
+ENUM_NEXT(pwg_attr_names,	PWG_HCD_USER_APP_NAME,
+							PWG_HCD_USER_APP_PERSIST_ENABLED,
+							PWG_HCD_RESIDENT_APP_VERSION,
+	"HCD UserApplicationName",
+	"HCD UserApplicationPatches",
+	"HCD UserApplicationStringVersion",
+	"HCD UserApplicationVersion",
+	"HCD UserApplicationEnabled",
+	"HCD UserApplicationPersistenceEnabled");
+ENUM_NEXT(pwg_attr_names,	PWG_HCD_CERTIFICATION_STATE,
+							PWG_HCD_CONFIGURATION_STATE,
+							PWG_HCD_USER_APP_PERSIST_ENABLED,
+	"HCD CertificationState",
+	"HCD ConfigurationState");
+ENUM_END(pwg_attr_names,	PWG_HCD_CONFIGURATION_STATE);
+
+/**
+ * See header
+ */
+pa_tnc_attr_t* pwg_attr_create_from_data(u_int32_t type, size_t length, chunk_t value)
+{
+	switch (type)
+	{
+		case PWG_HCD_DEFAULT_PWD_ENABLED:
+		case PWG_HCD_USER_APP_ENABLED:
+		case PWG_HCD_USER_APP_PERSIST_ENABLED:
+		case PWG_HCD_PSTN_FAX_ENABLED:
+			return generic_attr_bool_create_from_data(length, value,
+									pen_type_create(PEN_PWG, type));
+		case PWG_HCD_ATTRS_NATURAL_LANG:
+		case PWG_HCD_MACHINE_TYPE_MODEL:
+		case PWG_HCD_VENDOR_NAME:
+		case PWG_HCD_FIRMWARE_NAME:
+		case PWG_HCD_FIRMWARE_PATCHES:
+		case PWG_HCD_FIRMWARE_STRING_VERSION:
+		case PWG_HCD_TIME_SOURCE:
+		case PWG_HCD_USER_APP_NAME:
+		case PWG_HCD_USER_APP_PATCHES:
+		case PWG_HCD_USER_APP_STRING_VERSION:
+		case PWG_HCD_RESIDENT_APP_NAME:
+		case PWG_HCD_RESIDENT_APP_PATCHES:
+		case PWG_HCD_RESIDENT_APP_STRING_VERSION:
+			return generic_attr_string_create_from_data(length, value,
+									pen_type_create(PEN_PWG, type));
+		case PWG_HCD_FIRMWARE_VERSION:
+		case PWG_HCD_RESIDENT_APP_VERSION:
+		case PWG_HCD_USER_APP_VERSION:
+			return generic_attr_chunk_create_from_data(length, value, 16,
+									pen_type_create(PEN_PWG, type));
+		case PWG_HCD_CERTIFICATION_STATE:
+		case PWG_HCD_CONFIGURATION_STATE:
+			return generic_attr_chunk_create_from_data(length, value, 0,
+									pen_type_create(PEN_PWG, type));
+		case PWG_HCD_VENDOR_SMI_CODE:
+			return pwg_attr_vendor_smi_code_create_from_data(length, value);
+		case PWG_HCD_FORWARDING_ENABLED:
+			return ietf_attr_fwd_enabled_create_from_data(length, value,
+									pen_type_create(PEN_PWG, type));
+		case PWG_HCD_FIREWALL_SETTING:
+			return ietf_attr_port_filter_create_from_data(length, value,
+									pen_type_create(PEN_PWG, type));
+		default:
+			return NULL;
+	}
+}
diff --git a/src/libimcv/pwg/pwg_attr.h b/src/libimcv/pwg/pwg_attr.h
new file mode 100644
index 0000000..01db42c
--- /dev/null
+++ b/src/libimcv/pwg/pwg_attr.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2015 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
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup pwg_attr pwg_attr
+ * @{ @ingroup libimcv
+ */
+
+#ifndef PWG_ATTR_H_
+#define PWG_ATTR_H_
+
+#include <pa_tnc/pa_tnc_attr.h>
+#include <library.h>
+
+typedef enum pwg_attr_t pwg_attr_t;
+
+/**
+ * PWG HCD IF-M Attributes (Hardcopy Device Health Assessment TNC Binding)
+ */
+enum pwg_attr_t {
+	PWG_HCD_ATTRS_NATURAL_LANG =          0x00000001, /*   1 */
+	PWG_HCD_MACHINE_TYPE_MODEL =          0x00000002, /*   2 */
+	PWG_HCD_VENDOR_NAME =                 0x00000003, /*   3 */
+	PWG_HCD_VENDOR_SMI_CODE =             0x00000004, /*   4 */
+	PWG_HCD_DEFAULT_PWD_ENABLED =         0x00000014, /*  20 */
+	PWG_HCD_FIREWALL_SETTING =            0x00000015, /*  21 */
+	PWG_HCD_FORWARDING_ENABLED =          0x00000016, /*  22 */
+	PWG_HCD_PSTN_FAX_ENABLED =            0x00000028, /*  40 */
+	PWG_HCD_TIME_SOURCE =                 0x00000032, /*  50 ??? */
+	PWG_HCD_FIRMWARE_NAME =               0x0000003C, /*  60 */
+	PWG_HCD_FIRMWARE_PATCHES =            0x0000003D, /*  61 */
+	PWG_HCD_FIRMWARE_STRING_VERSION =     0x0000003E, /*  62 */
+	PWG_HCD_FIRMWARE_VERSION =            0x0000003F, /*  63 */
+	PWG_HCD_RESIDENT_APP_NAME =           0x00000050, /*  80 */
+	PWG_HCD_RESIDENT_APP_PATCHES =        0x00000051, /*  81 */
+	PWG_HCD_RESIDENT_APP_STRING_VERSION = 0x00000052, /*  82 */
+	PWG_HCD_RESIDENT_APP_VERSION =        0x00000053, /*  83 */
+	PWG_HCD_USER_APP_NAME =               0x00000064, /* 100 */
+	PWG_HCD_USER_APP_PATCHES =            0x00000065, /* 101 */
+	PWG_HCD_USER_APP_STRING_VERSION =     0x00000066, /* 102 */
+	PWG_HCD_USER_APP_VERSION =            0x00000067, /* 103 */
+	PWG_HCD_USER_APP_ENABLED =            0x00000068, /* 104 */
+	PWG_HCD_USER_APP_PERSIST_ENABLED =    0x00000069, /* 105 */
+	PWG_HCD_CERTIFICATION_STATE =         0x000000C8, /* 200 */
+	PWG_HCD_CONFIGURATION_STATE =         0x000000C9, /* 201 */
+};
+
+/**
+ * enum name for pwg_attr_t.
+ */
+extern enum_name_t *pwg_attr_names;
+
+/**
+ * Create a TCG PA-TNC attribute from data
+ *
+ * @param type				attribute type
+ * @param length			attribute length
+ * @param value				attribute value or segment
+ */
+pa_tnc_attr_t* pwg_attr_create_from_data(u_int32_t type, size_t length,
+										 chunk_t value);
+
+#endif /** PWG_ATTR_H_ @}*/
diff --git a/src/libimcv/ietf/ietf_attr_fwd_enabled.c b/src/libimcv/pwg/pwg_attr_vendor_smi_code.c
similarity index 62%
copy from src/libimcv/ietf/ietf_attr_fwd_enabled.c
copy to src/libimcv/pwg/pwg_attr_vendor_smi_code.c
index c00a5ef..7931259 100644
--- a/src/libimcv/ietf/ietf_attr_fwd_enabled.c
+++ b/src/libimcv/pwg/pwg_attr_vendor_smi_code.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012-2014 Andreas Steffen
+ * Copyright (C) 2015 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -13,36 +13,36 @@
  * for more details.
  */
 
-#include "ietf_attr_fwd_enabled.h"
+#include "pwg_attr_vendor_smi_code.h"
 
 #include <pa_tnc/pa_tnc_msg.h>
 #include <bio/bio_writer.h>
 #include <bio/bio_reader.h>
 #include <utils/debug.h>
 
-typedef struct private_ietf_attr_fwd_enabled_t private_ietf_attr_fwd_enabled_t;
+typedef struct private_pwg_attr_vendor_smi_code_t private_pwg_attr_vendor_smi_code_t;
 
 /**
- * PA-TNC Forwarding Enabled type  (see section 4.2.11 of RFC 5792)
+ * PWG HCD PA-TNC Vendor SMI Code
  *
  *                       1                   2                   3
  *   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *  |                        Forwarding Enabled                     |
+ *  |    Reserved   |                 Vendor SMI Code               |
  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  */
 
-#define FORWARDING_ENABLED_SIZE		4
+#define VENDOR_SMI_CODE_SIZE	4
 
 /**
- * Private data of an ietf_attr_fwd_enabled_t object.
+ * Private data of an pwg_attr_vendor_smi_code_t object.
  */
-struct private_ietf_attr_fwd_enabled_t {
+struct private_pwg_attr_vendor_smi_code_t {
 
 	/**
-	 * Public members of ietf_attr_fwd_enabled_t
+	 * Public members of pwg_attr_vendor_smi_code_t
 	 */
-	ietf_attr_fwd_enabled_t public;
+	pwg_attr_vendor_smi_code_t public;
 
 	/**
 	 * Vendor-specific attribute type
@@ -65,9 +65,9 @@ struct private_ietf_attr_fwd_enabled_t {
 	bool noskip_flag;
 
 	/**
-	 * Forwarding Enabled status
+	 * Vendor SMI code
 	 */
-	os_fwd_status_t fwd_status;
+	pen_t vendor_smi_code;
 
 	/**
 	 * Reference count
@@ -76,31 +76,31 @@ struct private_ietf_attr_fwd_enabled_t {
 };
 
 METHOD(pa_tnc_attr_t, get_type, pen_type_t,
-	private_ietf_attr_fwd_enabled_t *this)
+	private_pwg_attr_vendor_smi_code_t *this)
 {
 	return this->type;
 }
 
 METHOD(pa_tnc_attr_t, get_value, chunk_t,
-	private_ietf_attr_fwd_enabled_t *this)
+	private_pwg_attr_vendor_smi_code_t *this)
 {
 	return this->value;
 }
 
 METHOD(pa_tnc_attr_t, get_noskip_flag, bool,
-	private_ietf_attr_fwd_enabled_t *this)
+	private_pwg_attr_vendor_smi_code_t *this)
 {
 	return this->noskip_flag;
 }
 
 METHOD(pa_tnc_attr_t, set_noskip_flag,void,
-	private_ietf_attr_fwd_enabled_t *this, bool noskip)
+	private_pwg_attr_vendor_smi_code_t *this, bool noskip)
 {
 	this->noskip_flag = noskip;
 }
 
 METHOD(pa_tnc_attr_t, build, void,
-	private_ietf_attr_fwd_enabled_t *this)
+	private_pwg_attr_vendor_smi_code_t *this)
 {
 	bio_writer_t *writer;
 
@@ -108,8 +108,8 @@ METHOD(pa_tnc_attr_t, build, void,
 	{
 		return;
 	}
-	writer = bio_writer_create(FORWARDING_ENABLED_SIZE);
-	writer->write_uint32(writer, this->fwd_status);
+	writer = bio_writer_create(VENDOR_SMI_CODE_SIZE);
+	writer->write_uint32(writer, this->vendor_smi_code);
 
 	this->value = writer->extract_buf(writer);
 	this->length = this->value.len;
@@ -117,10 +117,11 @@ METHOD(pa_tnc_attr_t, build, void,
 }
 
 METHOD(pa_tnc_attr_t, process, status_t,
-	private_ietf_attr_fwd_enabled_t *this, u_int32_t *offset)
+	private_pwg_attr_vendor_smi_code_t *this, u_int32_t *offset)
 {
 	bio_reader_t *reader;
-	u_int32_t fwd_status;
+	uint32_t vendor_smi_code;
+	uint8_t reserved;
 
 	*offset = 0;
 
@@ -128,41 +129,35 @@ METHOD(pa_tnc_attr_t, process, status_t,
 	{
 		return NEED_MORE;
 	}
-	if (this->value.len != FORWARDING_ENABLED_SIZE)
+	if (this->value.len != VENDOR_SMI_CODE_SIZE)
 	{
-		DBG1(DBG_TNC, "incorrect size for IETF forwarding enabled attribute");
+		DBG1(DBG_TNC, "incorrect attribute length for PWG HCD Vendor SMI Code");
 		return FAILED;
 	}
 	reader = bio_reader_create(this->value);
-	reader->read_uint32(reader, &fwd_status);
+	reader->read_uint8 (reader, &reserved);
+	reader->read_uint24(reader, &vendor_smi_code);
 	reader->destroy(reader);
-
-	if (fwd_status > OS_FWD_UNKNOWN)
-	{
-		DBG1(DBG_TNC, "IETF forwarding enabled field has unknown value %u",
-					   fwd_status);
-		return FAILED;
-	}
-	this->fwd_status = fwd_status;
+	this->vendor_smi_code = vendor_smi_code;
 
 	return SUCCESS;
 }
 
 METHOD(pa_tnc_attr_t, add_segment, void,
-	private_ietf_attr_fwd_enabled_t *this, chunk_t segment)
+	private_pwg_attr_vendor_smi_code_t *this, chunk_t segment)
 {
 	this->value = chunk_cat("mc", this->value, segment);
 }
 
 METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*,
-	private_ietf_attr_fwd_enabled_t *this)
+	private_pwg_attr_vendor_smi_code_t *this)
 {
 	ref_get(&this->ref);
 	return &this->public.pa_tnc_attribute;
 }
 
 METHOD(pa_tnc_attr_t, destroy, void,
-	private_ietf_attr_fwd_enabled_t *this)
+	private_pwg_attr_vendor_smi_code_t *this)
 {
 	if (ref_put(&this->ref))
 	{
@@ -171,18 +166,18 @@ METHOD(pa_tnc_attr_t, destroy, void,
 	}
 }
 
-METHOD(ietf_attr_fwd_enabled_t, get_status, os_fwd_status_t,
-	private_ietf_attr_fwd_enabled_t *this)
+METHOD(pwg_attr_vendor_smi_code_t, get_vendor_smi_code, pen_t,
+	private_pwg_attr_vendor_smi_code_t *this)
 {
-	return this->fwd_status;
+	return this->vendor_smi_code;
 }
 
 /**
  * Described in header.
  */
-pa_tnc_attr_t *ietf_attr_fwd_enabled_create(os_fwd_status_t fwd_status)
+pa_tnc_attr_t *pwg_attr_vendor_smi_code_create(pen_t vendor_smi_code)
 {
-	private_ietf_attr_fwd_enabled_t *this;
+	private_pwg_attr_vendor_smi_code_t *this;
 
 	INIT(this,
 		.public = {
@@ -197,10 +192,10 @@ pa_tnc_attr_t *ietf_attr_fwd_enabled_create(os_fwd_status_t fwd_status)
 				.get_ref = _get_ref,
 				.destroy = _destroy,
 			},
-			.get_status = _get_status,
+			.get_vendor_smi_code = _get_vendor_smi_code,
 		},
-		.type = { PEN_IETF, IETF_ATTR_FORWARDING_ENABLED },
-		.fwd_status = fwd_status,
+		.type = { PEN_PWG, PWG_HCD_VENDOR_SMI_CODE },
+		.vendor_smi_code = vendor_smi_code,
 		.ref = 1,
 	);
 
@@ -210,10 +205,10 @@ pa_tnc_attr_t *ietf_attr_fwd_enabled_create(os_fwd_status_t fwd_status)
 /**
  * Described in header.
  */
-pa_tnc_attr_t *ietf_attr_fwd_enabled_create_from_data(size_t length,
-													  chunk_t data)
+pa_tnc_attr_t *pwg_attr_vendor_smi_code_create_from_data(size_t length,
+														 chunk_t data)
 {
-	private_ietf_attr_fwd_enabled_t *this;
+	private_pwg_attr_vendor_smi_code_t *this;
 
 	INIT(this,
 		.public = {
@@ -228,9 +223,9 @@ pa_tnc_attr_t *ietf_attr_fwd_enabled_create_from_data(size_t length,
 				.get_ref = _get_ref,
 				.destroy = _destroy,
 			},
-			.get_status = _get_status,
+			.get_vendor_smi_code = _get_vendor_smi_code,
 		},
-		.type = { PEN_IETF, IETF_ATTR_FORWARDING_ENABLED },
+		.type = { PEN_PWG, PWG_HCD_VENDOR_SMI_CODE },
 		.length = length,
 		.value = chunk_clone(data),
 		.ref = 1,
diff --git a/src/libimcv/ietf/ietf_attr_fwd_enabled.h b/src/libimcv/pwg/pwg_attr_vendor_smi_code.h
similarity index 50%
copy from src/libimcv/ietf/ietf_attr_fwd_enabled.h
copy to src/libimcv/pwg/pwg_attr_vendor_smi_code.h
index 3d55436..31255b4 100644
--- a/src/libimcv/ietf/ietf_attr_fwd_enabled.h
+++ b/src/libimcv/pwg/pwg_attr_vendor_smi_code.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012-2014 Andreas Steffen
+ * Copyright (C) 2015 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -14,24 +14,24 @@
  */
 
 /**
- * @defgroup ietf_attr_fwd_enabled ietf_attr_fwd_enabled
+ * @defgroup pwg_attr_vendor_smi_codet pwg_attr_vendor_smi_code
  * @{ @ingroup ietf_attr
  */
 
-#ifndef IETF_ATTR_FWD_ENABLED_H_
-#define IETF_ATTR_FWD_ENABLED_H_
+#ifndef PWG_ATTR_VENDOR_SMI_CODE_H_
+#define PWG_ATTR_VENDOR_SMI_CODE_H_
 
-typedef struct ietf_attr_fwd_enabled_t ietf_attr_fwd_enabled_t;
+typedef struct pwg_attr_vendor_smi_code_t pwg_attr_vendor_smi_code_t;
 
-#include "ietf_attr.h"
+#include "pwg_attr.h"
 #include "pa_tnc/pa_tnc_attr.h"
-#include "os_info/os_info.h"
+
 
 /**
- * Class implementing the IETF PA-TNC Forwarding Enabled attribute.
+ * Class implementing the PWG HCD PA-TNC Vendor SMI Code attribute.
  *
  */
-struct ietf_attr_fwd_enabled_t {
+struct pwg_attr_vendor_smi_code_t {
 
 	/**
 	 * Public PA-TNC attribute interface
@@ -39,28 +39,27 @@ struct ietf_attr_fwd_enabled_t {
 	pa_tnc_attr_t pa_tnc_attribute;
 
 	/**
-	 * Gets the Forwarding Enabled status
+	 * Gets the Vendor SMI Code
 	 *
-	 * @return				Forwarding Enabled status
+	 * @return				Vendor SMI Code
 	 */
-	os_fwd_status_t (*get_status)(ietf_attr_fwd_enabled_t *this);
+	pen_t (*get_vendor_smi_code)(pwg_attr_vendor_smi_code_t *this);
 
 };
 
 /**
- * Creates an ietf_attr_fwd_enabled_t object
+ * Creates an pwg_attr_vendor_smi_code_t object
  *
- * @param fwd_status		Forwarding Enabled status
  */
-pa_tnc_attr_t* ietf_attr_fwd_enabled_create(os_fwd_status_t fwd_status);
+pa_tnc_attr_t* pwg_attr_vendor_smi_code_create(pen_t vendor_smi_code);
 
 /**
- * Creates an ietf_attr_fwd_enabled_t object from received data
+ * Creates an pwg_attr_vendor_smi_code_t object from received data
  *
  * @param length			Total length of attribute value
  * @param value				Unparsed attribute value (might be a segment)
  */
-pa_tnc_attr_t* ietf_attr_fwd_enabled_create_from_data(size_t length,
-													  chunk_t value);
+pa_tnc_attr_t* pwg_attr_vendor_smi_code_create_from_data(size_t length,
+														 chunk_t value);
 
-#endif /** IETF_ATTR_FWD_ENABLED_H_ @}*/
+#endif /** PWG_ATTR_VENDOR_SMI_CODE_H_ @}*/
diff --git a/src/libimcv/seg/seg_contract.c b/src/libimcv/seg/seg_contract.c
index 7db702a..41aed58 100644
--- a/src/libimcv/seg/seg_contract.c
+++ b/src/libimcv/seg/seg_contract.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 Andreas Steffen
+ * Copyright (C) 2014-2015 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -148,7 +148,7 @@ METHOD(seg_contract_t, check_size, bool,
 }
 
 METHOD(seg_contract_t, first_segment, pa_tnc_attr_t*,
-	private_seg_contract_t *this, pa_tnc_attr_t *attr)
+	private_seg_contract_t *this, pa_tnc_attr_t *attr, size_t max_attr_len)
 {
 	seg_env_t *seg_env;
 
@@ -160,7 +160,7 @@ METHOD(seg_contract_t, first_segment, pa_tnc_attr_t*,
 	}
 	this->seg_envs->insert_last(this->seg_envs, seg_env);
 
-	return seg_env->first_segment(seg_env);
+	return seg_env->first_segment(seg_env, max_attr_len);
 }
 
 METHOD(seg_contract_t, next_segment, pa_tnc_attr_t*,
diff --git a/src/libimcv/seg/seg_contract.h b/src/libimcv/seg/seg_contract.h
index 23676a9..afbf309 100644
--- a/src/libimcv/seg/seg_contract.h
+++ b/src/libimcv/seg/seg_contract.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 Andreas Steffen
+ * Copyright (C) 2014-2015 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -78,9 +78,11 @@ struct seg_contract_t {
 	 * Generate first segment of a PA-TNC attribute according to the contract
 	 *
 	 * @param attr			PA-TNC attribute to be segmented
+	 * @param max_attr_len	Maximum size of first segment envelope attribute
 	 * @return				First segment envelope attribute
 	 */
-	pa_tnc_attr_t* (*first_segment)(seg_contract_t *this, pa_tnc_attr_t *attr);
+	pa_tnc_attr_t* (*first_segment)(seg_contract_t *this, pa_tnc_attr_t *attr,
+									size_t max_attr_len);
 
 	/**
 	 * Generate next segment of a PA-TNC attribute according to the contract
diff --git a/src/libimcv/seg/seg_env.c b/src/libimcv/seg/seg_env.c
index f384192..8d0f760 100644
--- a/src/libimcv/seg/seg_env.c
+++ b/src/libimcv/seg/seg_env.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 Andreas Steffen
+ * Copyright (C) 2014-2015 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -89,14 +89,21 @@ METHOD(seg_env_t, get_base_attr_info, chunk_t,
 }
 
 METHOD(seg_env_t, first_segment, pa_tnc_attr_t*,
-	private_seg_env_t *this)
+	private_seg_env_t *this, size_t max_attr_len)
 {
 	pa_tnc_attr_t *seg_env_attr;
 	bio_writer_t *writer;
 	pen_type_t type;
 	chunk_t segment_data, value;
+	size_t seg_size;
 	uint8_t flags, seg_env_flags;
 
+	/* compute size of first segment */
+	seg_size = max_attr_len ? min(this->max_seg_size,
+								  max_attr_len - PA_TNC_ATTR_HEADER_SIZE
+											   - TCG_SEG_ATTR_SEG_ENV_HEADER)
+							: this->max_seg_size;
+
 	/* get components of base attribute header and data */
 	flags = this->base_attr->get_noskip_flag(this->base_attr) ?
 				PA_TNC_ATTR_FLAG_NOSKIP : PA_TNC_ATTR_FLAG_NONE;
@@ -104,7 +111,7 @@ METHOD(seg_env_t, first_segment, pa_tnc_attr_t*,
 
 	/* attribute data going into the first segment */
 	segment_data = this->data;
-	segment_data.len = this->max_seg_size - PA_TNC_ATTR_HEADER_SIZE;
+	segment_data.len = seg_size - PA_TNC_ATTR_HEADER_SIZE;
 
 	/* build encoding of the base attribute header and first segment data */
 	writer = bio_writer_create(this->max_seg_size);
@@ -118,7 +125,7 @@ METHOD(seg_env_t, first_segment, pa_tnc_attr_t*,
 	this->data = chunk_skip(this->data, segment_data.len);
 
 	DBG2(DBG_TNC, "creating first segment for base attribute ID %d (%d bytes)",
-		 this->base_attr_id, this->max_seg_size);
+		 this->base_attr_id, seg_size);
 
 	seg_env_flags = SEG_ENV_FLAG_START | SEG_ENV_FLAG_MORE;
 	seg_env_attr = tcg_seg_attr_seg_env_create(value, seg_env_flags,
diff --git a/src/libimcv/seg/seg_env.h b/src/libimcv/seg/seg_env.h
index 611f9a9..5f21236 100644
--- a/src/libimcv/seg/seg_env.h
+++ b/src/libimcv/seg/seg_env.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 Andreas Steffen
+ * Copyright (C) 2014-2015 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -66,9 +66,10 @@ struct seg_env_t {
 	/**
 	 * Generate the first segment envelope of the base attribute
 	 *
+	 * @param max_attr_len	Maximum size of first attribute segment envelope
 	 * @return				First attribute segment envelope
 	 */
-	pa_tnc_attr_t* (*first_segment)(seg_env_t *this);
+	pa_tnc_attr_t* (*first_segment)(seg_env_t *this, size_t max_attr_len);
 
 	/**
 	 * Generate the next segment envelope of the base attribute
diff --git a/src/libimcv/suites/test_imcv_seg.c b/src/libimcv/suites/test_imcv_seg.c
index 8b51eda..5245be9 100644
--- a/src/libimcv/suites/test_imcv_seg.c
+++ b/src/libimcv/suites/test_imcv_seg.c
@@ -42,7 +42,7 @@ static struct {
 	{ 24, 1, 24 },
 	{ 25, 1, 23 },
 	{ 47, 1,  1 },
-	{ 48, 0,  0 },	
+	{ 48, 0,  0 },
 };
 
 static char command[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
@@ -87,7 +87,7 @@ START_TEST(test_imcv_seg_env)
 			if (n == 0)
 			{
 				/* create first segment */
-				attr = seg_env->first_segment(seg_env);
+				attr = seg_env->first_segment(seg_env, 0);
 			
 				seg_env_attr = (tcg_seg_attr_seg_env_t*)attr;
 				segment = seg_env_attr->get_segment(seg_env_attr, &flags);
@@ -168,8 +168,9 @@ START_TEST(test_imcv_seg_env_special)
 	pen_type_t type;
 	seg_env_t *seg_env;
 	chunk_t segment, value;
+	uint32_t max_attr_len = 60;
 	uint32_t max_seg_size = 47;
-	uint32_t last_seg_size = 1;
+	uint32_t last_seg_size = 4;
 	uint32_t offset = 12;
 
 	base_attr = ita_attr_command_create(command);
@@ -179,7 +180,7 @@ START_TEST(test_imcv_seg_env_special)
 	base_attr->set_noskip_flag(base_attr, TRUE);
 
 	seg_env = seg_env_create(id, base_attr, max_seg_size);
-	attr = seg_env->first_segment(seg_env);
+	attr = seg_env->first_segment(seg_env, max_attr_len);
 	attr->destroy(attr);
 
 	/* don't return last segment indicator */
@@ -306,7 +307,7 @@ START_TEST(test_imcv_seg_contract)
 	contract_r = seg_contract_create(msg_type, max_attr_size, max_seg_size,
 									 FALSE, issuer_id, TRUE);
 	attr = contract_r->first_segment(contract_r,
-									 base_attr_r->get_ref(base_attr_r));
+									 base_attr_r->get_ref(base_attr_r), 0);
 
 	if (seg_env_tests[_i].next_segs == 0)
 	{
@@ -422,8 +423,8 @@ START_TEST(test_imcv_seg_contract_special)
 	ck_assert(!oversize);
 
 	/* get first segment of each base attribute */
-	attr1_f = contract_r->first_segment(contract_r, base_attr1_r->get_ref(base_attr1_r));
-	attr2_f = contract_r->first_segment(contract_r, base_attr2_r->get_ref(base_attr2_r));
+	attr1_f = contract_r->first_segment(contract_r, base_attr1_r->get_ref(base_attr1_r), 0);
+	attr2_f = contract_r->first_segment(contract_r, base_attr2_r->get_ref(base_attr2_r), 0);
 	ck_assert(attr1_f);
 	ck_assert(attr2_f);
 	seg_env_attr1 = (tcg_seg_attr_seg_env_t*)attr1_f;
diff --git a/src/libipsec/Makefile.am b/src/libipsec/Makefile.am
index 41f5ae9..90b4561 100644
--- a/src/libipsec/Makefile.am
+++ b/src/libipsec/Makefile.am
@@ -24,11 +24,4 @@ AM_LDFLAGS = \
 
 EXTRA_DIST = Android.mk
 
-# build optional plugins
-########################
-
-if MONOLITHIC
-SUBDIRS =
-else
-SUBDIRS = .
-endif
+SUBDIRS = . tests
diff --git a/src/libipsec/Makefile.in b/src/libipsec/Makefile.in
index a80d28a..aa79344 100644
--- a/src/libipsec/Makefile.in
+++ b/src/libipsec/Makefile.in
@@ -214,7 +214,7 @@ am__define_uniq_tagged_files = \
   done | $(am__uniquify_input)`
 ETAGS = etags
 CTAGS = ctags
-DIST_SUBDIRS = .
+DIST_SUBDIRS = $(SUBDIRS)
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 am__relativize = \
   dir0=`pwd`; \
@@ -490,11 +490,7 @@ AM_LDFLAGS = \
 	-no-undefined
 
 EXTRA_DIST = Android.mk
- at MONOLITHIC_FALSE@SUBDIRS = .
-
-# build optional plugins
-########################
- at MONOLITHIC_TRUE@SUBDIRS = 
+SUBDIRS = . tests
 all: all-recursive
 
 .SUFFIXES:
diff --git a/src/libipsec/esp_context.c b/src/libipsec/esp_context.c
index a2307e0..b742d15 100644
--- a/src/libipsec/esp_context.c
+++ b/src/libipsec/esp_context.c
@@ -215,6 +215,7 @@ static bool create_aead(private_esp_context_t *this, int alg,
 		case ENCR_AES_GCM_ICV8:
 		case ENCR_AES_GCM_ICV12:
 		case ENCR_AES_GCM_ICV16:
+		case ENCR_CHACHA20_POLY1305:
 			/* the key includes a 4 byte salt */
 			this->aead = lib->crypto->create_aead(lib->crypto, alg,
 												  key.len - 4, 4);
diff --git a/src/libipsec/tests/Makefile.am b/src/libipsec/tests/Makefile.am
new file mode 100644
index 0000000..6138833
--- /dev/null
+++ b/src/libipsec/tests/Makefile.am
@@ -0,0 +1,21 @@
+TESTS = ipsec_tests
+
+check_PROGRAMS = $(TESTS)
+
+ipsec_tests_SOURCES = \
+	suites/test_chapoly.c \
+	ipsec_tests.h ipsec_tests.c
+
+ipsec_tests_CFLAGS = \
+	-I$(top_srcdir)/src/libipsec \
+	-I$(top_srcdir)/src/libstrongswan \
+	-I$(top_srcdir)/src/libstrongswan/tests \
+	-DPLUGINDIR=\""$(abs_top_builddir)/src/libstrongswan/plugins\"" \
+	-DPLUGINS=\""${s_plugins}\"" \
+	@COVERAGE_CFLAGS@
+
+ipsec_tests_LDFLAGS = @COVERAGE_LDFLAGS@
+ipsec_tests_LDADD = \
+	$(top_builddir)/src/libipsec/libipsec.la \
+	$(top_builddir)/src/libstrongswan/libstrongswan.la \
+	$(top_builddir)/src/libstrongswan/tests/libtest.la
diff --git a/src/libcharon/tests/Makefile.in b/src/libipsec/tests/Makefile.in
similarity index 82%
copy from src/libcharon/tests/Makefile.in
copy to src/libipsec/tests/Makefile.in
index 7f4f4b2..9a9bb31 100644
--- a/src/libcharon/tests/Makefile.in
+++ b/src/libipsec/tests/Makefile.in
@@ -77,9 +77,9 @@ PRE_UNINSTALL = :
 POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
-TESTS = libcharon_tests$(EXEEXT)
+TESTS = ipsec_tests$(EXEEXT)
 check_PROGRAMS = $(am__EXEEXT_1)
-subdir = src/libcharon/tests
+subdir = src/libipsec/tests
 DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
 	$(top_srcdir)/depcomp
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
@@ -99,25 +99,21 @@ mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
 CONFIG_CLEAN_VPATH_FILES =
-am__EXEEXT_1 = libcharon_tests$(EXEEXT)
+am__EXEEXT_1 = ipsec_tests$(EXEEXT)
 am__dirstamp = $(am__leading_dot)dirstamp
-am_libcharon_tests_OBJECTS =  \
-	suites/libcharon_tests-test_mem_pool.$(OBJEXT) \
-	libcharon_tests-libcharon_tests.$(OBJEXT)
-libcharon_tests_OBJECTS = $(am_libcharon_tests_OBJECTS)
-libcharon_tests_DEPENDENCIES =  \
-	$(top_builddir)/src/libcharon/libcharon.la \
-	$(top_builddir)/src/libhydra/libhydra.la \
+am_ipsec_tests_OBJECTS = suites/ipsec_tests-test_chapoly.$(OBJEXT) \
+	ipsec_tests-ipsec_tests.$(OBJEXT)
+ipsec_tests_OBJECTS = $(am_ipsec_tests_OBJECTS)
+ipsec_tests_DEPENDENCIES = $(top_builddir)/src/libipsec/libipsec.la \
 	$(top_builddir)/src/libstrongswan/libstrongswan.la \
 	$(top_builddir)/src/libstrongswan/tests/libtest.la
 AM_V_lt = $(am__v_lt_ at AM_V@)
 am__v_lt_ = $(am__v_lt_ at AM_DEFAULT_V@)
 am__v_lt_0 = --silent
 am__v_lt_1 = 
-libcharon_tests_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
-	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
-	$(libcharon_tests_CFLAGS) $(CFLAGS) $(libcharon_tests_LDFLAGS) \
-	$(LDFLAGS) -o $@
+ipsec_tests_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(ipsec_tests_CFLAGS) \
+	$(CFLAGS) $(ipsec_tests_LDFLAGS) $(LDFLAGS) -o $@
 AM_V_P = $(am__v_P_ at AM_V@)
 am__v_P_ = $(am__v_P_ at AM_DEFAULT_V@)
 am__v_P_0 = false
@@ -152,8 +148,8 @@ AM_V_CCLD = $(am__v_CCLD_ at AM_V@)
 am__v_CCLD_ = $(am__v_CCLD_ at AM_DEFAULT_V@)
 am__v_CCLD_0 = @echo "  CCLD    " $@;
 am__v_CCLD_1 = 
-SOURCES = $(libcharon_tests_SOURCES)
-DIST_SOURCES = $(libcharon_tests_SOURCES)
+SOURCES = $(ipsec_tests_SOURCES)
+DIST_SOURCES = $(ipsec_tests_SOURCES)
 am__can_run_installinfo = \
   case $$AM_UPDATE_INFO_DIR in \
     n|no|NO) false;; \
@@ -426,23 +422,23 @@ top_srcdir = @top_srcdir@
 urandom_device = @urandom_device@
 xml_CFLAGS = @xml_CFLAGS@
 xml_LIBS = @xml_LIBS@
-libcharon_tests_SOURCES = \
-  suites/test_mem_pool.c \
-  libcharon_tests.h libcharon_tests.c
-
-libcharon_tests_CFLAGS = \
-  -I$(top_srcdir)/src/libcharon \
-  -I$(top_srcdir)/src/libhydra \
-  -I$(top_srcdir)/src/libstrongswan \
-  -I$(top_srcdir)/src/libstrongswan/tests \
-  @COVERAGE_CFLAGS@
-
-libcharon_tests_LDFLAGS = @COVERAGE_LDFLAGS@
-libcharon_tests_LDADD = \
-  $(top_builddir)/src/libcharon/libcharon.la \
-  $(top_builddir)/src/libhydra/libhydra.la \
-  $(top_builddir)/src/libstrongswan/libstrongswan.la \
-  $(top_builddir)/src/libstrongswan/tests/libtest.la
+ipsec_tests_SOURCES = \
+	suites/test_chapoly.c \
+	ipsec_tests.h ipsec_tests.c
+
+ipsec_tests_CFLAGS = \
+	-I$(top_srcdir)/src/libipsec \
+	-I$(top_srcdir)/src/libstrongswan \
+	-I$(top_srcdir)/src/libstrongswan/tests \
+	-DPLUGINDIR=\""$(abs_top_builddir)/src/libstrongswan/plugins\"" \
+	-DPLUGINS=\""${s_plugins}\"" \
+	@COVERAGE_CFLAGS@
+
+ipsec_tests_LDFLAGS = @COVERAGE_LDFLAGS@
+ipsec_tests_LDADD = \
+	$(top_builddir)/src/libipsec/libipsec.la \
+	$(top_builddir)/src/libstrongswan/libstrongswan.la \
+	$(top_builddir)/src/libstrongswan/tests/libtest.la
 
 all: all-am
 
@@ -457,9 +453,9 @@ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
 	      exit 1;; \
 	  esac; \
 	done; \
-	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/libcharon/tests/Makefile'; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/libipsec/tests/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
-	  $(AUTOMAKE) --gnu src/libcharon/tests/Makefile
+	  $(AUTOMAKE) --gnu src/libipsec/tests/Makefile
 .PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
@@ -493,12 +489,12 @@ suites/$(am__dirstamp):
 suites/$(DEPDIR)/$(am__dirstamp):
 	@$(MKDIR_P) suites/$(DEPDIR)
 	@: > suites/$(DEPDIR)/$(am__dirstamp)
-suites/libcharon_tests-test_mem_pool.$(OBJEXT):  \
-	suites/$(am__dirstamp) suites/$(DEPDIR)/$(am__dirstamp)
+suites/ipsec_tests-test_chapoly.$(OBJEXT): suites/$(am__dirstamp) \
+	suites/$(DEPDIR)/$(am__dirstamp)
 
-libcharon_tests$(EXEEXT): $(libcharon_tests_OBJECTS) $(libcharon_tests_DEPENDENCIES) $(EXTRA_libcharon_tests_DEPENDENCIES) 
-	@rm -f libcharon_tests$(EXEEXT)
-	$(AM_V_CCLD)$(libcharon_tests_LINK) $(libcharon_tests_OBJECTS) $(libcharon_tests_LDADD) $(LIBS)
+ipsec_tests$(EXEEXT): $(ipsec_tests_OBJECTS) $(ipsec_tests_DEPENDENCIES) $(EXTRA_ipsec_tests_DEPENDENCIES) 
+	@rm -f ipsec_tests$(EXEEXT)
+	$(AM_V_CCLD)$(ipsec_tests_LINK) $(ipsec_tests_OBJECTS) $(ipsec_tests_LDADD) $(LIBS)
 
 mostlyclean-compile:
 	-rm -f *.$(OBJEXT)
@@ -507,8 +503,8 @@ mostlyclean-compile:
 distclean-compile:
 	-rm -f *.tab.c
 
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcharon_tests-libcharon_tests.Po at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at suites/$(DEPDIR)/libcharon_tests-test_mem_pool.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/ipsec_tests-ipsec_tests.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at suites/$(DEPDIR)/ipsec_tests-test_chapoly.Po at am__quote@
 
 .c.o:
 @am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
@@ -534,33 +530,33 @@ distclean-compile:
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LTCOMPILE) -c -o $@ $<
 
-suites/libcharon_tests-test_mem_pool.o: suites/test_mem_pool.c
- at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcharon_tests_CFLAGS) $(CFLAGS) -MT suites/libcharon_tests-test_mem_pool.o -MD -MP -MF suites/$(DEPDIR)/libcharon_tests-test_mem_pool.Tpo -c -o suites/libcharon_tests-test_mem_pool.o `test -f 'suites/test_mem_pool.c' || echo '$(srcdir)/'`suites/test_mem_pool.c
- at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) suites/$(DEPDIR)/libcharon_tests-test_mem_pool.Tpo suites/$(DEPDIR)/libcharon_tests-test_mem_pool.Po
- at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='suites/test_mem_pool.c' object='suites/libcharon_tests-test_mem_pool.o' libtool=no @AMDEPBACKSLASH@
+suites/ipsec_tests-test_chapoly.o: suites/test_chapoly.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ipsec_tests_CFLAGS) $(CFLAGS) -MT suites/ipsec_tests-test_chapoly.o -MD -MP -MF suites/$(DEPDIR)/ipsec_tests-test_chapoly.Tpo -c -o suites/ipsec_tests-test_chapoly.o `test -f 'suites/test_chapoly.c' || echo '$(srcdir)/'`suites/test_chapoly.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) suites/$(DEPDIR)/ipsec_tests-test_chapoly.Tpo suites/$(DEPDIR)/ipsec_tests-test_chapoly.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='suites/test_chapoly.c' object='suites/ipsec_tests-test_chapoly.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
- at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcharon_tests_CFLAGS) $(CFLAGS) -c -o suites/libcharon_tests-test_mem_pool.o `test -f 'suites/test_mem_pool.c' || echo '$(srcdir)/'`suites/test_mem_pool.c
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ipsec_tests_CFLAGS) $(CFLAGS) -c -o suites/ipsec_tests-test_chapoly.o `test -f 'suites/test_chapoly.c' || echo '$(srcdir)/'`suites/test_chapoly.c
 
-suites/libcharon_tests-test_mem_pool.obj: suites/test_mem_pool.c
- at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcharon_tests_CFLAGS) $(CFLAGS) -MT suites/libcharon_tests-test_mem_pool.obj -MD -MP -MF suites/$(DEPDIR)/libcharon_tests-test_mem_pool.Tpo -c -o suites/libcharon_tests-test_mem_pool.obj `if test -f 'suites/test_mem_pool.c'; then $(CYGPATH_W) 'suites/test_mem_pool.c'; else $(CYGPATH_W) '$(srcdir)/suites/test_mem_pool.c'; fi`
- at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) suites/$(DEPDIR)/libcharon_tests-test_mem_pool.Tpo suites/$(DEPDIR)/libcharon_tests-test_mem_pool.Po
- at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='suites/test_mem_pool.c' object='suites/libcharon_tests-test_mem_pool.obj' libtool=no @AMDEPBACKSLASH@
+suites/ipsec_tests-test_chapoly.obj: suites/test_chapoly.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ipsec_tests_CFLAGS) $(CFLAGS) -MT suites/ipsec_tests-test_chapoly.obj -MD -MP -MF suites/$(DEPDIR)/ipsec_tests-test_chapoly.Tpo -c -o suites/ipsec_tests-test_chapoly.obj `if test -f 'suites/test_chapoly.c'; then $(CYGPATH_W) 'suites/test_chapoly.c'; else $(CYGPATH_W) '$(srcdir)/suites/test_chapoly.c'; fi`
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) suites/$(DEPDIR)/ipsec_tests-test_chapoly.Tpo suites/$(DEPDIR)/ipsec_tests-test_chapoly.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='suites/test_chapoly.c' object='suites/ipsec_tests-test_chapoly.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
- at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcharon_tests_CFLAGS) $(CFLAGS) -c -o suites/libcharon_tests-test_mem_pool.obj `if test -f 'suites/test_mem_pool.c'; then $(CYGPATH_W) 'suites/test_mem_pool.c'; else $(CYGPATH_W) '$(srcdir)/suites/test_mem_pool.c'; fi`
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ipsec_tests_CFLAGS) $(CFLAGS) -c -o suites/ipsec_tests-test_chapoly.obj `if test -f 'suites/test_chapoly.c'; then $(CYGPATH_W) 'suites/test_chapoly.c'; else $(CYGPATH_W) '$(srcdir)/suites/test_chapoly.c'; fi`
 
-libcharon_tests-libcharon_tests.o: libcharon_tests.c
- at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcharon_tests_CFLAGS) $(CFLAGS) -MT libcharon_tests-libcharon_tests.o -MD -MP -MF $(DEPDIR)/libcharon_tests-libcharon_tests.Tpo -c -o libcharon_tests-libcharon_tests.o `test -f 'libcharon_tests.c' || echo '$(srcdir)/'`libcharon_tests.c
- at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcharon_tests-libcharon_tests.Tpo $(DEPDIR)/libcharon_tests-libcharon_tests.Po
- at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='libcharon_tests.c' object='libcharon_tests-libcharon_tests.o' libtool=no @AMDEPBACKSLASH@
+ipsec_tests-ipsec_tests.o: ipsec_tests.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ipsec_tests_CFLAGS) $(CFLAGS) -MT ipsec_tests-ipsec_tests.o -MD -MP -MF $(DEPDIR)/ipsec_tests-ipsec_tests.Tpo -c -o ipsec_tests-ipsec_tests.o `test -f 'ipsec_tests.c' || echo '$(srcdir)/'`ipsec_tests.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/ipsec_tests-ipsec_tests.Tpo $(DEPDIR)/ipsec_tests-ipsec_tests.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='ipsec_tests.c' object='ipsec_tests-ipsec_tests.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
- at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcharon_tests_CFLAGS) $(CFLAGS) -c -o libcharon_tests-libcharon_tests.o `test -f 'libcharon_tests.c' || echo '$(srcdir)/'`libcharon_tests.c
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ipsec_tests_CFLAGS) $(CFLAGS) -c -o ipsec_tests-ipsec_tests.o `test -f 'ipsec_tests.c' || echo '$(srcdir)/'`ipsec_tests.c
 
-libcharon_tests-libcharon_tests.obj: libcharon_tests.c
- at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcharon_tests_CFLAGS) $(CFLAGS) -MT libcharon_tests-libcharon_tests.obj -MD -MP -MF $(DEPDIR)/libcharon_tests-libcharon_tests.Tpo -c -o libcharon_tests-libcharon_tests.obj `if test -f 'libcharon_tests.c'; then $(CYGPATH_W) 'libcharon_tests.c'; else $(CYGPATH_W) '$(srcdir)/libcharon_tests.c'; fi`
- at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcharon_tests-libcharon_tests.Tpo $(DEPDIR)/libcharon_tests-libcharon_tests.Po
- at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='libcharon_tests.c' object='libcharon_tests-libcharon_tests.obj' libtool=no @AMDEPBACKSLASH@
+ipsec_tests-ipsec_tests.obj: ipsec_tests.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ipsec_tests_CFLAGS) $(CFLAGS) -MT ipsec_tests-ipsec_tests.obj -MD -MP -MF $(DEPDIR)/ipsec_tests-ipsec_tests.Tpo -c -o ipsec_tests-ipsec_tests.obj `if test -f 'ipsec_tests.c'; then $(CYGPATH_W) 'ipsec_tests.c'; else $(CYGPATH_W) '$(srcdir)/ipsec_tests.c'; fi`
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/ipsec_tests-ipsec_tests.Tpo $(DEPDIR)/ipsec_tests-ipsec_tests.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='ipsec_tests.c' object='ipsec_tests-ipsec_tests.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
- at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcharon_tests_CFLAGS) $(CFLAGS) -c -o libcharon_tests-libcharon_tests.obj `if test -f 'libcharon_tests.c'; then $(CYGPATH_W) 'libcharon_tests.c'; else $(CYGPATH_W) '$(srcdir)/libcharon_tests.c'; fi`
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ipsec_tests_CFLAGS) $(CFLAGS) -c -o ipsec_tests-ipsec_tests.obj `if test -f 'ipsec_tests.c'; then $(CYGPATH_W) 'ipsec_tests.c'; else $(CYGPATH_W) '$(srcdir)/ipsec_tests.c'; fi`
 
 mostlyclean-libtool:
 	-rm -f *.lo
diff --git a/src/libtls/tests/tls_tests.c b/src/libipsec/tests/ipsec_tests.c
similarity index 81%
copy from src/libtls/tests/tls_tests.c
copy to src/libipsec/tests/ipsec_tests.c
index 2c2c5ba..d5e9053 100644
--- a/src/libtls/tests/tls_tests.c
+++ b/src/libipsec/tests/ipsec_tests.c
@@ -1,6 +1,6 @@
 /*
- * Copyright (C) 2014 Martin Willi
- * Copyright (C) 2014 revosec AG
+ * Copyright (C) 2015 Martin Willi
+ * Copyright (C) 2015 revosec AG
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
@@ -18,16 +18,16 @@
 /* declare test suite constructors */
 #define TEST_SUITE(x) test_suite_t* x();
 #define TEST_SUITE_DEPEND(x, ...) TEST_SUITE(x)
-#include "tls_tests.h"
+#include "ipsec_tests.h"
 #undef TEST_SUITE
 #undef TEST_SUITE_DEPEND
 
 static test_configuration_t tests[] = {
 #define TEST_SUITE(x) \
 	{ .suite = x, },
-#define TEST_SUITE_DEPEND(x, type, args) \
-	{ .suite = x, .feature = PLUGIN_DEPENDS(type, args) },
-#include "tls_tests.h"
+#define TEST_SUITE_DEPEND(x, type, ...) \
+	{ .suite = x, .feature = PLUGIN_DEPENDS(type, __VA_ARGS__) },
+#include "ipsec_tests.h"
 	{ .suite = NULL, }
 };
 
@@ -53,5 +53,5 @@ static bool test_runner_init(bool init)
 
 int main(int argc, char *argv[])
 {
-	return test_runner_run("libtls", tests, test_runner_init);
+	return test_runner_run("libipsec", tests, test_runner_init);
 }
diff --git a/src/libcharon/tests/libcharon_tests.h b/src/libipsec/tests/ipsec_tests.h
similarity index 79%
copy from src/libcharon/tests/libcharon_tests.h
copy to src/libipsec/tests/ipsec_tests.h
index dc9681a..1b591f9 100644
--- a/src/libcharon/tests/libcharon_tests.h
+++ b/src/libipsec/tests/ipsec_tests.h
@@ -1,6 +1,6 @@
 /*
- * Copyright (C) 2014 Martin Willi
- * Copyright (C) 2014 revosec AG
+ * Copyright (C) 2015 Martin Willi
+ * Copyright (C) 2015 revosec AG
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
@@ -13,4 +13,4 @@
  * for more details.
  */
 
-TEST_SUITE(mem_pool_suite_create)
+TEST_SUITE_DEPEND(chapoly_suite_create, AEAD, ENCR_CHACHA20_POLY1305, 32)
diff --git a/src/libipsec/tests/suites/test_chapoly.c b/src/libipsec/tests/suites/test_chapoly.c
new file mode 100644
index 0000000..31dc2ac
--- /dev/null
+++ b/src/libipsec/tests/suites/test_chapoly.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2015 Martin Willi
+ * Copyright (C) 2015 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include <test_suite.h>
+
+#include <ip_packet.h>
+#include <esp_packet.h>
+
+static iv_gen_t *ivgen;
+
+METHOD(aead_t, get_iv_gen, iv_gen_t*,
+	aead_t *this)
+{
+	return ivgen;
+}
+
+METHOD(iv_gen_t, get_iv, bool,
+	iv_gen_t *this, u_int64_t seq, size_t size, u_int8_t *buffer)
+{
+	if (size != 8)
+	{
+		return FALSE;
+	}
+	memcpy(buffer, "\x10\x11\x12\x13\x14\x15\x16\x17", 8);
+	return TRUE;
+}
+
+METHOD(iv_gen_t, allocate_iv, bool,
+	iv_gen_t *this, u_int64_t seq, size_t size, chunk_t *chunk)
+{
+	if (size != 8)
+	{
+		return FALSE;
+	}
+	*chunk = chunk_alloc(size);
+	return get_iv(this, seq, chunk->len, chunk->ptr);
+}
+
+/**
+ * Appendix A draft-ietf-ipsecme-chacha20-poly1305-06
+ */
+START_TEST(test_chapoly)
+{
+	host_t *src, *dst;
+	ip_packet_t *icmp;
+	esp_packet_t *esp;
+	esp_context_t *ctx;
+	chunk_t data, exp;
+	u_int32_t seq = 0;
+
+	icmp = ip_packet_create(chunk_clone(chunk_from_chars(
+								0x45,0x00,0x00,0x54,0xa6,0xf2,0x00,0x00,
+								0x40,0x01,0xe7,0x78,0xc6,0x33,0x64,0x05,
+								0xc0,0x00,0x02,0x05,0x08,0x00,0x5b,0x7a,
+								0x3a,0x08,0x00,0x00,0x55,0x3b,0xec,0x10,
+								0x00,0x07,0x36,0x27,0x08,0x09,0x0a,0x0b,
+								0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,
+								0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,
+								0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,
+								0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,
+								0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,
+								0x34,0x35,0x36,0x37)));
+	ck_assert(icmp);
+
+	src = host_create_from_string("203.0.113.153", 0);
+	dst = host_create_from_string("203.0.113.5", 0);
+	esp = esp_packet_create_from_payload(src, dst, icmp);
+
+	ctx = esp_context_create(ENCR_CHACHA20_POLY1305, chunk_from_chars(
+								0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,
+								0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+								0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,
+								0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
+								0xa0,0xa1,0xa2,0xa3),
+							 AUTH_UNDEFINED, chunk_empty, FALSE);
+	while (seq != 4)
+	{
+		ck_assert(ctx->next_seqno(ctx, &seq));
+	}
+	INIT(ivgen,
+		.get_iv = _get_iv,
+		.allocate_iv = _allocate_iv,
+		.destroy = (void*)free,
+	);
+	ctx->get_aead(ctx)->get_iv_gen = _get_iv_gen;
+	ck_assert(esp->encrypt(esp, ctx, htonl(0x01020304)) == SUCCESS);
+
+	data = esp->packet.get_data(&esp->packet);
+	exp = chunk_from_chars(0x01,0x02,0x03,0x04,0x00,0x00,0x00,0x05,
+						   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
+						   0x24,0x03,0x94,0x28,0xb9,0x7f,0x41,0x7e,
+						   0x3c,0x13,0x75,0x3a,0x4f,0x05,0x08,0x7b,
+						   0x67,0xc3,0x52,0xe6,0xa7,0xfa,0xb1,0xb9,
+						   0x82,0xd4,0x66,0xef,0x40,0x7a,0xe5,0xc6,
+						   0x14,0xee,0x80,0x99,0xd5,0x28,0x44,0xeb,
+						   0x61,0xaa,0x95,0xdf,0xab,0x4c,0x02,0xf7,
+						   0x2a,0xa7,0x1e,0x7c,0x4c,0x4f,0x64,0xc9,
+						   0xbe,0xfe,0x2f,0xac,0xc6,0x38,0xe8,0xf3,
+						   0xcb,0xec,0x16,0x3f,0xac,0x46,0x9b,0x50,
+						   0x27,0x73,0xf6,0xfb,0x94,0xe6,0x64,0xda,
+						   0x91,0x65,0xb8,0x28,0x29,0xf6,0x41,0xe0,
+						   0x76,0xAA,0xA8,0x26,0x6B,0x7F,0xB0,0xF7,
+						   0xB1,0x1B,0x36,0x99,0x07,0xE1,0xAD,0x43);
+	ck_assert_msg(chunk_equals(data, exp), "got %B\nexp %B", &data, &exp);
+
+	esp->destroy(esp);
+	ctx->destroy(ctx);
+	ivgen->destroy(ivgen);
+}
+END_TEST
+
+Suite *chapoly_suite_create()
+{
+	Suite *s;
+	TCase *tc;
+
+	s = suite_create("chapoly");
+
+	tc = tcase_create("ChaCha20Poly1305 ESP encryption");
+	tcase_add_test(tc, test_chapoly);
+	suite_add_tcase(s, tc);
+
+	return s;
+}
diff --git a/src/libpttls/pt_tls_client.c b/src/libpttls/pt_tls_client.c
index 315129d..bd5b96f 100644
--- a/src/libpttls/pt_tls_client.c
+++ b/src/libpttls/pt_tls_client.c
@@ -450,6 +450,7 @@ METHOD(pt_tls_client_t, run_assessment, status_t,
 	{
 		return FAILED;
 	}
+	tnccs->set_auth_type(tnccs, TNC_AUTH_X509_CERT);
 
 	DBG1(DBG_TNC, "entering PT-TLS data transport phase");
 	if (!assess(this, (tls_t*)tnccs))
diff --git a/src/libradius/radius_message.c b/src/libradius/radius_message.c
index e6abfe2..01c8298 100644
--- a/src/libradius/radius_message.c
+++ b/src/libradius/radius_message.c
@@ -97,7 +97,7 @@ ENUM_NEXT(radius_message_code_names, RMC_DISCONNECT_REQUEST, RMC_COA_NAK, RMC_AC
 	"CoA-NAK");
 ENUM_END(radius_message_code_names, RMC_COA_NAK);
 
-ENUM(radius_attribute_type_names, RAT_USER_NAME, RAT_MIP6_HOME_LINK_PREFIX,
+ENUM_BEGIN(radius_attribute_type_names, RAT_USER_NAME, RAT_MIP6_HOME_LINK_PREFIX,
 	"User-Name",
 	"User-Password",
 	"CHAP-Password",
@@ -223,6 +223,13 @@ ENUM(radius_attribute_type_names, RAT_USER_NAME, RAT_MIP6_HOME_LINK_PREFIX,
 	"Delegated-IPv6-Prefix",
 	"MIP6-Feature-Vector",
 	"MIP6-Home-Link-Prefix");
+ENUM_NEXT(radius_attribute_type_names, RAT_FRAMED_IPV6_ADDRESS, RAT_STATEFUL_IPV6_ADDRESS_POOL, RAT_MIP6_HOME_LINK_PREFIX,
+	"Framed-IPv6-Address",
+	"DNS-Server-IPv6-Address",
+	"Route-IPv6-Information",
+	"Delegated-IPv6-Prefix-Pool",
+	"Stateful-IPv6-Address-Pool");
+ENUM_END(radius_attribute_type_names, RAT_STATEFUL_IPV6_ADDRESS_POOL);
 
 /**
  * Attribute enumerator implementation
diff --git a/src/libradius/radius_message.h b/src/libradius/radius_message.h
index 4ce03a4..e6cb40b 100644
--- a/src/libradius/radius_message.h
+++ b/src/libradius/radius_message.h
@@ -186,6 +186,11 @@ enum radius_attribute_type_t {
 	RAT_DELEGATED_IPV6_PREFIX = 123,
 	RAT_MIP6_FEATURE_VECTOR = 124,
 	RAT_MIP6_HOME_LINK_PREFIX = 125,
+	RAT_FRAMED_IPV6_ADDRESS = 168,
+	RAT_FRAMED_IPV6_DNS_SERVER = 169,
+	RAT_ROUTE_IPV6_INFORMATION = 170,
+	RAT_DELEGATED_IPV6_PREFIX_POOL = 171,
+	RAT_STATEFUL_IPV6_ADDRESS_POOL = 172,
 };
 
 /**
diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am
index b3636cf..adf3687 100644
--- a/src/libstrongswan/Makefile.am
+++ b/src/libstrongswan/Makefile.am
@@ -100,7 +100,7 @@ resolver/rr.h resolver/resolver_manager.h \
 plugins/plugin_loader.h plugins/plugin.h plugins/plugin_feature.h \
 processing/jobs/job.h processing/jobs/callback_job.h processing/processor.h \
 processing/scheduler.h processing/watcher.h selectors/traffic_selector.h \
-settings/settings.h threading/thread_value.h \
+settings/settings.h settings/settings_parser.h threading/thread_value.h \
 threading/thread.h threading/windows/thread.h \
 threading/mutex.h threading/condvar.h threading/spinlock.h threading/semaphore.h \
 threading/rwlock.h threading/rwlock_condvar.h threading/lock_profiler.h \
@@ -540,6 +540,13 @@ if MONOLITHIC
 endif
 endif
 
+if USE_CHAPOLY
+  SUBDIRS += plugins/chapoly
+if MONOLITHIC
+  libstrongswan_la_LIBADD += plugins/chapoly/libstrongswan-chapoly.la
+endif
+endif
+
 if USE_CTR
   SUBDIRS += plugins/ctr
 if MONOLITHIC
diff --git a/src/libstrongswan/Makefile.in b/src/libstrongswan/Makefile.in
index 5b20f6e..9598c8b 100644
--- a/src/libstrongswan/Makefile.in
+++ b/src/libstrongswan/Makefile.in
@@ -203,19 +203,21 @@ host_triplet = @host@
 @MONOLITHIC_TRUE@@USE_KEYCHAIN_TRUE at am__append_105 = plugins/keychain/libstrongswan-keychain.la
 @USE_PKCS11_TRUE at am__append_106 = plugins/pkcs11
 @MONOLITHIC_TRUE@@USE_PKCS11_TRUE at am__append_107 = plugins/pkcs11/libstrongswan-pkcs11.la
- at USE_CTR_TRUE@am__append_108 = plugins/ctr
- at MONOLITHIC_TRUE@@USE_CTR_TRUE at am__append_109 = plugins/ctr/libstrongswan-ctr.la
- at USE_CCM_TRUE@am__append_110 = plugins/ccm
- at MONOLITHIC_TRUE@@USE_CCM_TRUE at am__append_111 = plugins/ccm/libstrongswan-ccm.la
- at USE_GCM_TRUE@am__append_112 = plugins/gcm
- at MONOLITHIC_TRUE@@USE_GCM_TRUE at am__append_113 = plugins/gcm/libstrongswan-gcm.la
- at USE_NTRU_TRUE@am__append_114 = plugins/ntru
- at MONOLITHIC_TRUE@@USE_NTRU_TRUE at am__append_115 = plugins/ntru/libstrongswan-ntru.la
- at USE_BLISS_TRUE@am__append_116 = plugins/bliss
- at MONOLITHIC_TRUE@@USE_BLISS_TRUE at am__append_117 = plugins/bliss/libstrongswan-bliss.la
- at USE_TEST_VECTORS_TRUE@am__append_118 = plugins/test_vectors
- at MONOLITHIC_TRUE@@USE_TEST_VECTORS_TRUE at am__append_119 = plugins/test_vectors/libstrongswan-test-vectors.la
- at USE_BLISS_TRUE@am__append_120 = plugins/bliss/tests
+ at USE_CHAPOLY_TRUE@am__append_108 = plugins/chapoly
+ at MONOLITHIC_TRUE@@USE_CHAPOLY_TRUE at am__append_109 = plugins/chapoly/libstrongswan-chapoly.la
+ at USE_CTR_TRUE@am__append_110 = plugins/ctr
+ at MONOLITHIC_TRUE@@USE_CTR_TRUE at am__append_111 = plugins/ctr/libstrongswan-ctr.la
+ at USE_CCM_TRUE@am__append_112 = plugins/ccm
+ at MONOLITHIC_TRUE@@USE_CCM_TRUE at am__append_113 = plugins/ccm/libstrongswan-ccm.la
+ at USE_GCM_TRUE@am__append_114 = plugins/gcm
+ at MONOLITHIC_TRUE@@USE_GCM_TRUE at am__append_115 = plugins/gcm/libstrongswan-gcm.la
+ at USE_NTRU_TRUE@am__append_116 = plugins/ntru
+ at MONOLITHIC_TRUE@@USE_NTRU_TRUE at am__append_117 = plugins/ntru/libstrongswan-ntru.la
+ at USE_BLISS_TRUE@am__append_118 = plugins/bliss
+ at MONOLITHIC_TRUE@@USE_BLISS_TRUE at am__append_119 = plugins/bliss/libstrongswan-bliss.la
+ at USE_TEST_VECTORS_TRUE@am__append_120 = plugins/test_vectors
+ at MONOLITHIC_TRUE@@USE_TEST_VECTORS_TRUE at am__append_121 = plugins/test_vectors/libstrongswan-test-vectors.la
+ at USE_BLISS_TRUE@am__append_122 = plugins/bliss/tests
 subdir = src/libstrongswan
 DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
 	settings/settings_parser.h settings/settings_parser.c \
@@ -295,7 +297,7 @@ libstrongswan_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
 	$(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_119) $(am__append_121)
 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 \
@@ -558,15 +560,16 @@ am__nobase_strongswan_include_HEADERS_DIST = library.h asn1/asn1.h \
 	processing/jobs/job.h processing/jobs/callback_job.h \
 	processing/processor.h processing/scheduler.h \
 	processing/watcher.h selectors/traffic_selector.h \
-	settings/settings.h threading/thread_value.h \
-	threading/thread.h threading/windows/thread.h \
-	threading/mutex.h threading/condvar.h threading/spinlock.h \
-	threading/semaphore.h threading/rwlock.h \
-	threading/rwlock_condvar.h threading/lock_profiler.h \
-	utils/utils.h utils/chunk.h utils/debug.h utils/enum.h \
-	utils/identification.h utils/lexparser.h utils/optionsfrom.h \
-	utils/capabilities.h utils/backtrace.h utils/cpu_feature.h \
-	utils/leak_detective.h utils/printf_hook/printf_hook.h \
+	settings/settings.h settings/settings_parser.h \
+	threading/thread_value.h threading/thread.h \
+	threading/windows/thread.h threading/mutex.h \
+	threading/condvar.h threading/spinlock.h threading/semaphore.h \
+	threading/rwlock.h threading/rwlock_condvar.h \
+	threading/lock_profiler.h utils/utils.h utils/chunk.h \
+	utils/debug.h utils/enum.h utils/identification.h \
+	utils/lexparser.h utils/optionsfrom.h utils/capabilities.h \
+	utils/backtrace.h utils/cpu_feature.h utils/leak_detective.h \
+	utils/printf_hook/printf_hook.h \
 	utils/printf_hook/printf_hook_vstr.h \
 	utils/printf_hook/printf_hook_builtin.h utils/parser_helper.h \
 	utils/test.h utils/integrity_checker.h utils/process.h \
@@ -615,9 +618,9 @@ DIST_SUBDIRS = . plugins/af_alg plugins/aes plugins/des \
 	plugins/files plugins/winhttp plugins/unbound plugins/soup \
 	plugins/ldap plugins/mysql plugins/sqlite plugins/padlock \
 	plugins/openssl plugins/gcrypt plugins/fips_prf plugins/agent \
-	plugins/keychain plugins/pkcs11 plugins/ctr plugins/ccm \
-	plugins/gcm plugins/ntru plugins/bliss plugins/test_vectors \
-	tests plugins/bliss/tests
+	plugins/keychain plugins/pkcs11 plugins/chapoly plugins/ctr \
+	plugins/ccm plugins/gcm plugins/ntru plugins/bliss \
+	plugins/test_vectors tests plugins/bliss/tests
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 am__relativize = \
   dir0=`pwd`; \
@@ -970,7 +973,7 @@ settings/settings_types.h
 @USE_DEV_HEADERS_TRUE at plugins/plugin_loader.h plugins/plugin.h plugins/plugin_feature.h \
 @USE_DEV_HEADERS_TRUE at processing/jobs/job.h processing/jobs/callback_job.h processing/processor.h \
 @USE_DEV_HEADERS_TRUE at processing/scheduler.h processing/watcher.h selectors/traffic_selector.h \
- at USE_DEV_HEADERS_TRUE@settings/settings.h threading/thread_value.h \
+ at USE_DEV_HEADERS_TRUE@settings/settings.h settings/settings_parser.h threading/thread_value.h \
 @USE_DEV_HEADERS_TRUE at threading/thread.h threading/windows/thread.h \
 @USE_DEV_HEADERS_TRUE at threading/mutex.h threading/condvar.h threading/spinlock.h threading/semaphore.h \
 @USE_DEV_HEADERS_TRUE at threading/rwlock.h threading/rwlock_condvar.h threading/lock_profiler.h \
@@ -1004,7 +1007,7 @@ libstrongswan_la_LIBADD = $(DLLIB) $(BTLIB) $(SOCKLIB) $(RTLIB) \
 	$(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_119) $(am__append_121)
 AM_CPPFLAGS = -I$(top_srcdir)/src/libstrongswan \
 	-DIPSEC_DIR=\"${ipsecdir}\" -DIPSEC_LIB_DIR=\"${ipseclibdir}\" \
 	-DPLUGINDIR=\"${plugindir}\" \
@@ -1056,7 +1059,8 @@ $(srcdir)/crypto/proposal/proposal_keywords_static.c
 @MONOLITHIC_FALSE@	$(am__append_106) $(am__append_108) \
 @MONOLITHIC_FALSE@	$(am__append_110) $(am__append_112) \
 @MONOLITHIC_FALSE@	$(am__append_114) $(am__append_116) \
- at MONOLITHIC_FALSE@	$(am__append_118) tests $(am__append_120)
+ at MONOLITHIC_FALSE@	$(am__append_118) $(am__append_120) tests \
+ at MONOLITHIC_FALSE@	$(am__append_122)
 
 # build plugins with their own Makefile
 #######################################
@@ -1085,7 +1089,8 @@ $(srcdir)/crypto/proposal/proposal_keywords_static.c
 @MONOLITHIC_TRUE@	$(am__append_106) $(am__append_108) \
 @MONOLITHIC_TRUE@	$(am__append_110) $(am__append_112) \
 @MONOLITHIC_TRUE@	$(am__append_114) $(am__append_116) \
- at MONOLITHIC_TRUE@	$(am__append_118) . tests $(am__append_120)
+ at MONOLITHIC_TRUE@	$(am__append_118) $(am__append_120) . tests \
+ at MONOLITHIC_TRUE@	$(am__append_122)
 all: $(BUILT_SOURCES)
 	$(MAKE) $(AM_MAKEFLAGS) all-recursive
 
diff --git a/src/libstrongswan/asn1/asn1.c b/src/libstrongswan/asn1/asn1.c
index 37b89c6..628bb99 100644
--- a/src/libstrongswan/asn1/asn1.c
+++ b/src/libstrongswan/asn1/asn1.c
@@ -340,7 +340,7 @@ static const int days[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 33
 static const int tm_leap_1970 = 477;
 
 /**
- * Converts ASN.1 UTCTIME or GENERALIZEDTIME into calender time
+ * Converts ASN.1 UTCTIME or GENERALIZEDTIME into calendar time
  */
 time_t asn1_to_time(const chunk_t *utctime, asn1_t type)
 {
diff --git a/src/libstrongswan/credentials/auth_cfg.c b/src/libstrongswan/credentials/auth_cfg.c
index 0ca45a1..1e93f02 100644
--- a/src/libstrongswan/credentials/auth_cfg.c
+++ b/src/libstrongswan/credentials/auth_cfg.c
@@ -514,9 +514,10 @@ METHOD(auth_cfg_t, complies, bool,
 	private_auth_cfg_t *this, auth_cfg_t *constraints, bool log_error)
 {
 	enumerator_t *e1, *e2;
-	bool success = TRUE, group_match = FALSE, cert_match = FALSE;
+	bool success = TRUE, group_match = FALSE;
+	bool ca_match = FALSE, cert_match = FALSE;
 	identification_t *require_group = NULL;
-	certificate_t *require_cert = NULL;
+	certificate_t *require_ca = NULL, *require_cert = NULL;
 	signature_scheme_t scheme = SIGN_UNKNOWN;
 	u_int strength = 0;
 	auth_rule_t t1, t2;
@@ -531,26 +532,21 @@ METHOD(auth_cfg_t, complies, bool,
 			case AUTH_RULE_CA_CERT:
 			case AUTH_RULE_IM_CERT:
 			{
-				certificate_t *c1, *c2;
+				certificate_t *cert;
 
-				c1 = (certificate_t*)value;
+				/* for CA certs, a match of a single cert is sufficient */
+				require_ca = (certificate_t*)value;
 
-				success = FALSE;
 				e2 = create_enumerator(this);
-				while (e2->enumerate(e2, &t2, &c2))
+				while (e2->enumerate(e2, &t2, &cert))
 				{
 					if ((t2 == AUTH_RULE_CA_CERT || t2 == AUTH_RULE_IM_CERT) &&
-						c1->equals(c1, c2))
+						cert->equals(cert, require_ca))
 					{
-						success = TRUE;
+						ca_match = TRUE;
 					}
 				}
 				e2->destroy(e2);
-				if (!success && log_error)
-				{
-					DBG1(DBG_CFG, "constraint check failed: peer not "
-						 "authenticated by CA '%Y'.", c1->get_subject(c1));
-				}
 				break;
 			}
 			case AUTH_RULE_SUBJECT_CERT:
@@ -665,7 +661,9 @@ METHOD(auth_cfg_t, complies, bool,
 			}
 			case AUTH_RULE_EAP_TYPE:
 			{
-				if ((uintptr_t)value != (uintptr_t)get(this, t1))
+				if ((uintptr_t)value != (uintptr_t)get(this, t1) &&
+					(uintptr_t)value != EAP_DYNAMIC &&
+					(uintptr_t)value != EAP_RADIUS)
 				{
 					success = FALSE;
 					if (log_error)
@@ -853,13 +851,22 @@ METHOD(auth_cfg_t, complies, bool,
 		}
 		return FALSE;
 	}
-
+	if (require_ca && !ca_match)
+	{
+		if (log_error)
+		{
+			DBG1(DBG_CFG, "constraint check failed: peer not "
+				 "authenticated by CA '%Y'",
+				 require_ca->get_subject(require_ca));
+		}
+		return FALSE;
+	}
 	if (require_cert && !cert_match)
 	{
 		if (log_error)
 		{
 			DBG1(DBG_CFG, "constraint check failed: peer not "
-				 "authenticated with peer cert '%Y'.",
+				 "authenticated with peer cert '%Y'",
 				 require_cert->get_subject(require_cert));
 		}
 		return FALSE;
diff --git a/src/libstrongswan/credentials/certificates/ocsp_request.h b/src/libstrongswan/credentials/certificates/ocsp_request.h
index 0b18713..730d95d 100644
--- a/src/libstrongswan/credentials/certificates/ocsp_request.h
+++ b/src/libstrongswan/credentials/certificates/ocsp_request.h
@@ -31,7 +31,7 @@ typedef struct ocsp_request_t ocsp_request_t;
 struct ocsp_request_t {
 
 	/**
-	 * Implements certificiate_t interface
+	 * Implements certificate_t interface
 	 */
 	certificate_t interface;
 };
diff --git a/src/libstrongswan/credentials/certificates/ocsp_response.h b/src/libstrongswan/credentials/certificates/ocsp_response.h
index 1575774..9c5637b 100644
--- a/src/libstrongswan/credentials/certificates/ocsp_response.h
+++ b/src/libstrongswan/credentials/certificates/ocsp_response.h
@@ -50,7 +50,7 @@ extern enum_name_t *ocsp_status_names;
 struct ocsp_response_t {
 
 	/**
-	 * Implements certificiate_t interface
+	 * Implements certificate_t interface
 	 */
 	certificate_t certificate;
 
diff --git a/src/libstrongswan/credentials/sets/mem_cred.c b/src/libstrongswan/credentials/sets/mem_cred.c
index 7ad011b..4884c4b 100644
--- a/src/libstrongswan/credentials/sets/mem_cred.c
+++ b/src/libstrongswan/credentials/sets/mem_cred.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010-2013 Tobias Brunner
+ * Copyright (C) 2010-2015 Tobias Brunner
  * Hochschule fuer Technik Rapperwsil
  * Copyright (C) 2010 Martin Willi
  * Copyright (C) 2010 revosec AG
@@ -197,7 +197,7 @@ METHOD(mem_cred_t, get_cert_ref, certificate_t*,
 {
 	certificate_t *cached;
 
-	this->lock->write_lock(this->lock);
+	this->lock->read_lock(this->lock);
 	if (this->untrusted->find_first(this->untrusted,
 									(linked_list_match_t)certificate_equals,
 									(void**)&cached, cert) == SUCCESS)
@@ -643,6 +643,49 @@ METHOD(credential_set_t, create_cdp_enumerator, enumerator_t*,
 
 }
 
+static void reset_certs(private_mem_cred_t *this)
+{
+	this->trusted->destroy_offset(this->trusted,
+								  offsetof(certificate_t, destroy));
+	this->untrusted->destroy_offset(this->untrusted,
+									offsetof(certificate_t, destroy));
+	this->trusted = linked_list_create();
+	this->untrusted = linked_list_create();
+}
+
+static void copy_certs(linked_list_t *dst, linked_list_t *src, bool clone)
+{
+	enumerator_t *enumerator;
+	certificate_t *cert;
+
+	enumerator = src->create_enumerator(src);
+	while (enumerator->enumerate(enumerator, &cert))
+	{
+		if (clone)
+		{
+			cert = cert->get_ref(cert);
+		}
+		else
+		{
+			src->remove_at(src, enumerator);
+		}
+		dst->insert_last(dst, cert);
+	}
+	enumerator->destroy(enumerator);
+}
+
+METHOD(mem_cred_t, replace_certs, void,
+	private_mem_cred_t *this, mem_cred_t *other_set, bool clone)
+{
+	private_mem_cred_t *other = (private_mem_cred_t*)other_set;
+
+	this->lock->write_lock(this->lock);
+	reset_certs(this);
+	copy_certs(this->untrusted, other->untrusted, clone);
+	copy_certs(this->trusted, other->trusted, clone);
+	this->lock->unlock(this->lock);
+}
+
 static void reset_secrets(private_mem_cred_t *this)
 {
 	this->keys->destroy_offset(this->keys, offsetof(private_key_t, destroy));
@@ -710,17 +753,11 @@ METHOD(mem_cred_t, clear_, void,
 	private_mem_cred_t *this)
 {
 	this->lock->write_lock(this->lock);
-	this->trusted->destroy_offset(this->trusted,
-								  offsetof(certificate_t, destroy));
-	this->untrusted->destroy_offset(this->untrusted,
-									offsetof(certificate_t, destroy));
 	this->cdps->destroy_function(this->cdps, (void*)cdp_destroy);
-	this->trusted = linked_list_create();
-	this->untrusted = linked_list_create();
 	this->cdps = linked_list_create();
+	reset_certs(this);
+	reset_secrets(this);
 	this->lock->unlock(this->lock);
-
-	clear_secrets(this);
 }
 
 METHOD(mem_cred_t, destroy, void,
@@ -760,6 +797,7 @@ mem_cred_t *mem_cred_create()
 			.add_shared = _add_shared,
 			.add_shared_list = _add_shared_list,
 			.add_cdp = _add_cdp,
+			.replace_certs = _replace_certs,
 			.replace_secrets = _replace_secrets,
 			.clear = _clear_,
 			.clear_secrets = _clear_secrets,
diff --git a/src/libstrongswan/credentials/sets/mem_cred.h b/src/libstrongswan/credentials/sets/mem_cred.h
index 3ce815a..51f0b8c 100644
--- a/src/libstrongswan/credentials/sets/mem_cred.h
+++ b/src/libstrongswan/credentials/sets/mem_cred.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010-2013 Tobias Brunner
+ * Copyright (C) 2010-2015 Tobias Brunner
  * Hochschule fuer Technik Rapperswil
  * Copyright (C) 2010 Martin Willi
  * Copyright (C) 2010 revosec AG
@@ -102,6 +102,7 @@ struct mem_cred_t {
 	 */
 	void (*add_shared_list)(mem_cred_t *this, shared_key_t *shared,
 							linked_list_t *owners);
+
 	/**
 	 * Add a certificate distribution point to the set.
 	 *
@@ -113,6 +114,15 @@ struct mem_cred_t {
 					identification_t *id, char *uri);
 
 	/**
+	 * Replace all certificates in this credential set with those of another.
+	 *
+	 * @param other			credential set to get certificates from
+	 * @param clone			TRUE to clone certs, FALSE to adopt them (they
+	 *						get removed from the other set)
+	 */
+	void (*replace_certs)(mem_cred_t *this, mem_cred_t *other, bool clone);
+
+	/**
 	 * Replace all secrets (private and shared keys) in this credential set
 	 * with those of another.
 	 *
diff --git a/src/libstrongswan/crypto/crypters/crypter.c b/src/libstrongswan/crypto/crypters/crypter.c
index 1e73baa..3e33765 100644
--- a/src/libstrongswan/crypto/crypters/crypter.c
+++ b/src/libstrongswan/crypto/crypters/crypter.c
@@ -40,13 +40,14 @@ ENUM_NEXT(encryption_algorithm_names, ENCR_AES_GCM_ICV8, ENCR_NULL_AUTH_AES_GMAC
 	"AES_GCM_12",
 	"AES_GCM_16",
 	"NULL_AES_GMAC");
-ENUM_NEXT(encryption_algorithm_names, ENCR_CAMELLIA_CBC, ENCR_CAMELLIA_CCM_ICV16, ENCR_NULL_AUTH_AES_GMAC,
+ENUM_NEXT(encryption_algorithm_names, ENCR_CAMELLIA_CBC, ENCR_CHACHA20_POLY1305, ENCR_NULL_AUTH_AES_GMAC,
 	"CAMELLIA_CBC",
 	"CAMELLIA_CTR",
 	"CAMELLIA_CCM_8",
 	"CAMELLIA_CCM_12",
-	"CAMELLIA_CCM_16");
-ENUM_NEXT(encryption_algorithm_names, ENCR_UNDEFINED, ENCR_RC2_CBC, ENCR_CAMELLIA_CCM_ICV16,
+	"CAMELLIA_CCM_16",
+	"CHACHA20_POLY1305");
+ENUM_NEXT(encryption_algorithm_names, ENCR_UNDEFINED, ENCR_RC2_CBC, ENCR_CHACHA20_POLY1305,
 	"UNDEFINED",
 	"DES_ECB",
 	"SERPENT_CBC",
@@ -184,6 +185,7 @@ bool encryption_algorithm_is_aead(encryption_algorithm_t alg)
 		case ENCR_CAMELLIA_CCM_ICV8:
 		case ENCR_CAMELLIA_CCM_ICV12:
 		case ENCR_CAMELLIA_CCM_ICV16:
+		case ENCR_CHACHA20_POLY1305:
 			return TRUE;
 		default:
 			return FALSE;
diff --git a/src/libstrongswan/crypto/crypters/crypter.h b/src/libstrongswan/crypto/crypters/crypter.h
index 849aea5..19ba55d 100644
--- a/src/libstrongswan/crypto/crypters/crypter.h
+++ b/src/libstrongswan/crypto/crypters/crypter.h
@@ -57,6 +57,7 @@ enum encryption_algorithm_t {
 	ENCR_CAMELLIA_CCM_ICV8 =  25,
 	ENCR_CAMELLIA_CCM_ICV12 = 26,
 	ENCR_CAMELLIA_CCM_ICV16 = 27,
+	ENCR_CHACHA20_POLY1305 =  28,
 	ENCR_UNDEFINED =        1024,
 	ENCR_DES_ECB =          1025,
 	ENCR_SERPENT_CBC =      1026,
diff --git a/src/libstrongswan/crypto/iv/iv_gen.c b/src/libstrongswan/crypto/iv/iv_gen.c
index e188432..7d6570a 100644
--- a/src/libstrongswan/crypto/iv/iv_gen.c
+++ b/src/libstrongswan/crypto/iv/iv_gen.c
@@ -48,6 +48,7 @@ iv_gen_t* iv_gen_create_for_alg(encryption_algorithm_t alg)
 		case ENCR_CAMELLIA_CCM_ICV8:
 		case ENCR_CAMELLIA_CCM_ICV12:
 		case ENCR_CAMELLIA_CCM_ICV16:
+		case ENCR_CHACHA20_POLY1305:
 		case ENCR_NULL_AUTH_AES_GMAC:
 			return iv_gen_seq_create();
 		case ENCR_NULL:
diff --git a/src/libstrongswan/crypto/proposal/proposal_keywords_static.c b/src/libstrongswan/crypto/proposal/proposal_keywords_static.c
index 1da1421..51b9d78 100644
--- a/src/libstrongswan/crypto/proposal/proposal_keywords_static.c
+++ b/src/libstrongswan/crypto/proposal/proposal_keywords_static.c
@@ -59,12 +59,12 @@ struct proposal_token {
 	u_int16_t         keysize;
 };
 
-#define TOTAL_KEYWORDS 138
+#define TOTAL_KEYWORDS 139
 #define MIN_WORD_LENGTH 3
 #define MAX_WORD_LENGTH 17
-#define MIN_HASH_VALUE 20
-#define MAX_HASH_VALUE 295
-/* maximum key range = 276, duplicates = 0 */
+#define MIN_HASH_VALUE 18
+#define MAX_HASH_VALUE 276
+/* maximum key range = 259, duplicates = 0 */
 
 #ifdef __GNUC__
 __inline
@@ -80,32 +80,32 @@ hash (str, len)
 {
   static const unsigned short asso_values[] =
     {
-      296, 296, 296, 296, 296, 296, 296, 296, 296, 296,
-      296, 296, 296, 296, 296, 296, 296, 296, 296, 296,
-      296, 296, 296, 296, 296, 296, 296, 296, 296, 296,
-      296, 296, 296, 296, 296, 296, 296, 296, 296, 296,
-      296, 296, 296, 296, 296, 296, 296, 296,  47,   6,
-       15,   8,  64,  24,  12,  14,   7,   5, 296, 296,
-      296, 296, 296, 296, 296, 296, 296, 296, 296, 296,
-      296, 296, 296, 296, 296, 296, 296, 296, 296, 296,
-      296, 296, 296, 296, 296, 296, 296, 296, 296, 296,
-      296, 296, 296, 296, 296, 120, 296,   9,   5,  22,
-       48, 114,  28,  76,   6,   5, 296, 296,   5,  20,
-        7,  14,  82,   7,  81,  98,  10,  86, 296, 296,
-        5, 296, 296, 296, 296, 296, 296, 296, 296, 296,
-      296, 296, 296, 296, 296, 296, 296, 296, 296, 296,
-      296, 296, 296, 296, 296, 296, 296, 296, 296, 296,
-      296, 296, 296, 296, 296, 296, 296, 296, 296, 296,
-      296, 296, 296, 296, 296, 296, 296, 296, 296, 296,
-      296, 296, 296, 296, 296, 296, 296, 296, 296, 296,
-      296, 296, 296, 296, 296, 296, 296, 296, 296, 296,
-      296, 296, 296, 296, 296, 296, 296, 296, 296, 296,
-      296, 296, 296, 296, 296, 296, 296, 296, 296, 296,
-      296, 296, 296, 296, 296, 296, 296, 296, 296, 296,
-      296, 296, 296, 296, 296, 296, 296, 296, 296, 296,
-      296, 296, 296, 296, 296, 296, 296, 296, 296, 296,
-      296, 296, 296, 296, 296, 296, 296, 296, 296, 296,
-      296, 296, 296, 296, 296, 296, 296
+      277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
+      277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
+      277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
+      277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
+      277, 277, 277, 277, 277, 277, 277, 277,  66,   6,
+       18,  39,  81,  30,   9,  27,   3,   0, 277, 277,
+      277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
+      277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
+      277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
+      277, 277, 277, 277, 277, 105, 277,  33,   0,   6,
+       57,  60,  15,  96,   3,   0, 277, 277,   0,   0,
+        0,  18, 126,  30, 111,  24,  36, 159, 277, 277,
+        9, 277, 277, 277, 277, 277, 277, 277, 277, 277,
+      277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
+      277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
+      277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
+      277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
+      277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
+      277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
+      277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
+      277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
+      277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
+      277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
+      277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
+      277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
+      277, 277, 277, 277, 277, 277, 277
     };
   register int hval = len;
 
@@ -144,178 +144,177 @@ hash (str, len)
 
 static const struct proposal_token wordlist[] =
   {
-    {"sha1",             INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA1_96,         0},
-    {"sha",              INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA1_96,         0},
+    {"esn",              EXTENDED_SEQUENCE_NUMBERS, EXT_SEQ_NUMBERS,      0},
     {"null",             ENCRYPTION_ALGORITHM, ENCR_NULL,                 0},
     {"noesn",            EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS,   0},
-    {"md5",              INTEGRITY_ALGORITHM,  AUTH_HMAC_MD5_96,          0},
-    {"esn",              EXTENDED_SEQUENCE_NUMBERS, EXT_SEQ_NUMBERS,      0},
+    {"aesxcbc",          INTEGRITY_ALGORITHM,  AUTH_AES_XCBC_96,          0},
+    {"aes",              ENCRYPTION_ALGORITHM, ENCR_AES_CBC,            128},
     {"aes128",           ENCRYPTION_ALGORITHM, ENCR_AES_CBC,            128},
-    {"prfsha1",          PSEUDO_RANDOM_FUNCTION, PRF_HMAC_SHA1,           0},
-    {"aes192",           ENCRYPTION_ALGORITHM, ENCR_AES_CBC,            192},
+    {"md5",              INTEGRITY_ALGORITHM,  AUTH_HMAC_MD5_96,          0},
     {"modp8192",         DIFFIE_HELLMAN_GROUP, MODP_8192_BIT,             0},
     {"md5_128",          INTEGRITY_ALGORITHM,  AUTH_HMAC_MD5_128,         0},
-    {"sha512",           INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA2_512_256,    0},
-    {"modp768",          DIFFIE_HELLMAN_GROUP, MODP_768_BIT,              0},
-    {"ntru128",          DIFFIE_HELLMAN_GROUP, NTRU_128_BIT,              0},
-    {"prfsha256",        PSEUDO_RANDOM_FUNCTION, PRF_HMAC_SHA2_256,       0},
-    {"aes256",           ENCRYPTION_ALGORITHM, ENCR_AES_CBC,            256},
-    {"ecp521",           DIFFIE_HELLMAN_GROUP, ECP_521_BIT,               0},
-    {"ntru192",          DIFFIE_HELLMAN_GROUP, NTRU_192_BIT,              0},
-    {"ntru112",          DIFFIE_HELLMAN_GROUP, NTRU_112_BIT,              0},
-    {"sha256",           INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA2_256_128,    0},
-    {"modp1536",         DIFFIE_HELLMAN_GROUP, MODP_1536_BIT,             0},
-    {"ecp192",           DIFFIE_HELLMAN_GROUP, ECP_192_BIT,               0},
-    {"prfsha512",        PSEUDO_RANDOM_FUNCTION, PRF_HMAC_SHA2_512,       0},
     {"aes192ccm8",       ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8,       192},
-    {"aes192ccm128",     ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16,      192},
+    {"aes192",           ENCRYPTION_ALGORITHM, ENCR_AES_CBC,            192},
     {"aes128ccm8",       ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8,       128},
-    {"aes128ccm128",     ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16,      128},
     {"aes192ccm96",      ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV12,      192},
-    {"aes192ccm16",      ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16,      192},
+    {"aes192ccm128",     ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16,      192},
+    {"sha1",             INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA1_96,         0},
     {"aes128ccm96",      ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV12,      128},
+    {"aes128ccm128",     ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16,      128},
+    {"modp768",          DIFFIE_HELLMAN_GROUP, MODP_768_BIT,              0},
+    {"aes192ccm16",      ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16,      192},
+    {"ecp521",           DIFFIE_HELLMAN_GROUP, ECP_521_BIT,               0},
+    {"aescmac",          INTEGRITY_ALGORITHM,  AUTH_AES_CMAC_96,          0},
     {"aes128ccm16",      ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16,      128},
+    {"aes256",           ENCRYPTION_ALGORITHM, ENCR_AES_CBC,            256},
+    {"ntru128",          DIFFIE_HELLMAN_GROUP, NTRU_128_BIT,              0},
+    {"blowfish",         ENCRYPTION_ALGORITHM, ENCR_BLOWFISH,           128},
+    {"ecp192",           DIFFIE_HELLMAN_GROUP, ECP_192_BIT,               0},
     {"aes192ccm12",      ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV12,      192},
-    {"camellia",         ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CBC,       128},
-    {"aes128ccm12",      ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV12,      128},
-    {"ecp256",           DIFFIE_HELLMAN_GROUP, ECP_256_BIT,               0},
-    {"aesxcbc",          INTEGRITY_ALGORITHM,  AUTH_AES_XCBC_96,          0},
-    {"ntru256",          DIFFIE_HELLMAN_GROUP, NTRU_256_BIT,              0},
-    {"aescmac",          INTEGRITY_ALGORITHM,  AUTH_AES_CMAC_96,          0},
     {"aes256ccm8",       ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8,       256},
-    {"aes256ccm128",     ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16,      256},
-    {"cast128",          ENCRYPTION_ALGORITHM, ENCR_CAST,               128},
+    {"aes128ccm12",      ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV12,      128},
     {"aes256ccm96",      ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV12,      256},
+    {"aes256ccm128",     ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16,      256},
+    {"ntru192",          DIFFIE_HELLMAN_GROUP, NTRU_192_BIT,              0},
+    {"ecp256",           DIFFIE_HELLMAN_GROUP, ECP_256_BIT,               0},
     {"aes256ccm16",      ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16,      256},
-    {"camellia192",      ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CBC,       192},
-    {"aes256ccm12",      ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV12,      256},
-    {"camellia128",      ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CBC,       128},
+    {"sha",              INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA1_96,         0},
+    {"ntru112",          DIFFIE_HELLMAN_GROUP, NTRU_112_BIT,              0},
+    {"blowfish192",      ENCRYPTION_ALGORITHM, ENCR_BLOWFISH,           192},
+    {"blowfish128",      ENCRYPTION_ALGORITHM, ENCR_BLOWFISH,           128},
     {"camellia192ccm8",  ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV8,  192},
-    {"camellia192ccm128",ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV16, 192},
-    {"modp3072",         DIFFIE_HELLMAN_GROUP, MODP_3072_BIT,             0},
+    {"aes256ccm12",      ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV12,      256},
+    {"camelliaxcbc",     INTEGRITY_ALGORITHM,  AUTH_CAMELLIA_XCBC_96,     0},
     {"camellia192ccm96", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV12, 192},
+    {"camellia192ccm128",ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV16, 192},
+    {"sha512",           INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA2_512_256,    0},
+    {"prfsha1",          PSEUDO_RANDOM_FUNCTION, PRF_HMAC_SHA1,           0},
+    {"camellia192",      ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CBC,       192},
+    {"des",              ENCRYPTION_ALGORITHM, ENCR_DES,                  0},
     {"camellia192ccm16", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV16, 192},
-    {"prfsha384",        PSEUDO_RANDOM_FUNCTION, PRF_HMAC_SHA2_384,       0},
-    {"camellia192ccm12", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV12, 192},
-    {"aes",              ENCRYPTION_ALGORITHM, ENCR_AES_CBC,            128},
+    {"camellia128",      ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CBC,       128},
+    {"sha256",           INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA2_256_128,    0},
+    {"ntru256",          DIFFIE_HELLMAN_GROUP, NTRU_256_BIT,              0},
+    {"modp1536",         DIFFIE_HELLMAN_GROUP, MODP_1536_BIT,             0},
+    {"cast128",          ENCRYPTION_ALGORITHM, ENCR_CAST,               128},
+    {"blowfish256",      ENCRYPTION_ALGORITHM, ENCR_BLOWFISH,           256},
     {"camellia128ccm8",  ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV8,  128},
-    {"camellia128ccm128",ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV16, 128},
-    {"prfmd5",           PSEUDO_RANDOM_FUNCTION, PRF_HMAC_MD5,            0},
-    {"camellia256",      ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CBC,       256},
+    {"camellia192ccm12", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV12, 192},
+    {"camellia",         ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CBC,       128},
     {"camellia128ccm96", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV12, 128},
+    {"camellia128ccm128",ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV16, 128},
+    {"prfsha256",        PSEUDO_RANDOM_FUNCTION, PRF_HMAC_SHA2_256,       0},
     {"camellia128ccm16", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV16, 128},
-    {"camellia128ccm12", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV12, 128},
+    {"camellia256",      ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CBC,       256},
     {"camellia256ccm8",  ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV8,  256},
-    {"camellia256ccm128",ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV16, 256},
-    {"modpnull",         DIFFIE_HELLMAN_GROUP, MODP_NULL,                 0},
-    {"camelliaxcbc",     INTEGRITY_ALGORITHM,  AUTH_CAMELLIA_XCBC_96,     0},
+    {"3des",             ENCRYPTION_ALGORITHM, ENCR_3DES,                 0},
     {"camellia256ccm96", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV12, 256},
+    {"camellia256ccm128",ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV16, 256},
+    {"camellia128ccm12", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV12, 128},
     {"camellia256ccm16", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV16, 256},
+    {"prfsha512",        PSEUDO_RANDOM_FUNCTION, PRF_HMAC_SHA2_512,       0},
+    {"aes192ccm64",      ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8,       192},
     {"camellia256ccm12", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV12, 256},
+    {"aes128ccm64",      ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8,       128},
     {"aes192gcm8",       ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV8,       192},
-    {"aes192gcm128",     ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16,      192},
     {"aes128gcm8",       ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV8,       128},
-    {"aes128gcm128",     ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16,      128},
     {"aes192gcm96",      ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12,      192},
-    {"aes192gcm16",      ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16,      192},
+    {"aes192gcm128",     ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16,      192},
+    {"aes192gmac",       ENCRYPTION_ALGORITHM, ENCR_NULL_AUTH_AES_GMAC, 192},
     {"aes128gcm96",      ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12,      128},
+    {"aes128gcm128",     ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16,      128},
+    {"aes128gmac",       ENCRYPTION_ALGORITHM, ENCR_NULL_AUTH_AES_GMAC, 128},
+    {"aes192gcm16",      ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16,      192},
+    {"prfaescmac",       PSEUDO_RANDOM_FUNCTION, PRF_AES128_CMAC,         0},
     {"aes128gcm16",      ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16,      128},
-    {"aes192gcm12",      ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12,      192},
-    {"aes192ccm64",      ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8,       192},
-    {"aes128gcm12",      ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12,      128},
-    {"aes128ccm64",      ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8,       128},
     {"aes192ctr",        ENCRYPTION_ALGORITHM, ENCR_AES_CTR,            192},
+    {"prfaesxcbc",       PSEUDO_RANDOM_FUNCTION, PRF_AES128_XCBC,         0},
+    {"aes256ccm64",      ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8,       256},
     {"aes128ctr",        ENCRYPTION_ALGORITHM, ENCR_AES_CTR,            128},
-    {"modp1024s160",     DIFFIE_HELLMAN_GROUP, MODP_1024_160,             0},
+    {"serpent128",       ENCRYPTION_ALGORITHM, ENCR_SERPENT_CBC,        128},
+    {"aes192gcm12",      ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12,      192},
+    {"prfcamelliaxcbc",  PSEUDO_RANDOM_FUNCTION, PRF_CAMELLIA128_XCBC,    0},
     {"aes256gcm8",       ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV8,       256},
-    {"aes256gcm128",     ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16,      256},
-    {"modp4096",         DIFFIE_HELLMAN_GROUP, MODP_4096_BIT,             0},
-    {"ecp512bp",         DIFFIE_HELLMAN_GROUP, ECP_512_BP,                0},
+    {"aes128gcm12",      ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12,      128},
+    {"prfmd5",           PSEUDO_RANDOM_FUNCTION, PRF_HMAC_MD5,            0},
     {"aes256gcm96",      ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12,      256},
+    {"aes256gcm128",     ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16,      256},
+    {"aes256gmac",       ENCRYPTION_ALGORITHM, ENCR_NULL_AUTH_AES_GMAC, 256},
+    {"modp3072",         DIFFIE_HELLMAN_GROUP, MODP_3072_BIT,             0},
+    {"serpent256",       ENCRYPTION_ALGORITHM, ENCR_SERPENT_CBC,        256},
     {"aes256gcm16",      ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16,      256},
-    {"modp1024",         DIFFIE_HELLMAN_GROUP, MODP_1024_BIT,             0},
-    {"modp2048",         DIFFIE_HELLMAN_GROUP, MODP_2048_BIT,             0},
-    {"aes256gcm12",      ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12,      256},
-    {"aes256ccm64",      ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8,       256},
-    {"sha384",           INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA2_384_192,    0},
+    {"camellia192ccm64", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV8,  192},
+    {"modp4096",         DIFFIE_HELLMAN_GROUP, MODP_4096_BIT,             0},
     {"aes256ctr",        ENCRYPTION_ALGORITHM, ENCR_AES_CTR,            256},
-    {"aes192gmac",       ENCRYPTION_ALGORITHM, ENCR_NULL_AUTH_AES_GMAC, 192},
-    {"aes128gmac",       ENCRYPTION_ALGORITHM, ENCR_NULL_AUTH_AES_GMAC, 128},
+    {"modpnull",         DIFFIE_HELLMAN_GROUP, MODP_NULL,                 0},
+    {"aes256gcm12",      ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12,      256},
+    {"ecp512bp",         DIFFIE_HELLMAN_GROUP, ECP_512_BP,                0},
+    {"modp1024s160",     DIFFIE_HELLMAN_GROUP, MODP_1024_160,             0},
     {"serpent",          ENCRYPTION_ALGORITHM, ENCR_SERPENT_CBC,        128},
-    {"ecp256bp",         DIFFIE_HELLMAN_GROUP, ECP_256_BP,                0},
-    {"camellia192ccm64", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV8,  192},
-    {"modp6144",         DIFFIE_HELLMAN_GROUP, MODP_6144_BIT,             0},
+    {"modp2048",         DIFFIE_HELLMAN_GROUP, MODP_2048_BIT,             0},
+    {"serpent192",       ENCRYPTION_ALGORITHM, ENCR_SERPENT_CBC,        192},
+    {"modp1024",         DIFFIE_HELLMAN_GROUP, MODP_1024_BIT,             0},
+    {"camellia128ccm64", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV8,  128},
     {"camellia192ctr",   ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CTR,       192},
-    {"serpent128",       ENCRYPTION_ALGORITHM, ENCR_SERPENT_CBC,        128},
-    {"3des",             ENCRYPTION_ALGORITHM, ENCR_3DES,                 0},
-    {"blowfish",         ENCRYPTION_ALGORITHM, ENCR_BLOWFISH,           128},
+    {"modp6144",         DIFFIE_HELLMAN_GROUP, MODP_6144_BIT,             0},
     {"ecp384",           DIFFIE_HELLMAN_GROUP, ECP_384_BIT,               0},
-    {"camellia128ccm64", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV8,  128},
-    {"aes256gmac",       ENCRYPTION_ALGORITHM, ENCR_NULL_AUTH_AES_GMAC, 256},
-    {"modp2048s256",     DIFFIE_HELLMAN_GROUP, MODP_2048_256,             0},
+    {"ecp256bp",         DIFFIE_HELLMAN_GROUP, ECP_256_BP,                0},
+    {"camellia256ccm64", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV8,  256},
+    {"prfsha384",        PSEUDO_RANDOM_FUNCTION, PRF_HMAC_SHA2_384,       0},
+    {"twofish",          ENCRYPTION_ALGORITHM, ENCR_TWOFISH_CBC,        128},
+    {"sha256_96",        INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA2_256_96,     0},
     {"camellia128ctr",   ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CTR,       128},
-    {"serpent256",       ENCRYPTION_ALGORITHM, ENCR_SERPENT_CBC,        256},
     {"ecp224",           DIFFIE_HELLMAN_GROUP, ECP_224_BIT,               0},
-    {"camellia256ccm64", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV8,  256},
-    {"serpent192",       ENCRYPTION_ALGORITHM, ENCR_SERPENT_CBC,        192},
-    {"camellia256ctr",   ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CTR,       256},
+    {"twofish128",       ENCRYPTION_ALGORITHM, ENCR_TWOFISH_CBC,        128},
     {"sha2_512",         INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA2_512_256,    0},
-    {"blowfish192",      ENCRYPTION_ALGORITHM, ENCR_BLOWFISH,           192},
-    {"blowfish128",      ENCRYPTION_ALGORITHM, ENCR_BLOWFISH,           128},
-    {"sha256_96",        INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA2_256_96,     0},
-    {"aes192gcm64",      ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV8,       192},
+    {"modp2048s256",     DIFFIE_HELLMAN_GROUP, MODP_2048_256,             0},
     {"sha2_256",         INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA2_256_128,    0},
-    {"aes128gcm64",      ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV8,       128},
-    {"ecp384bp",         DIFFIE_HELLMAN_GROUP, ECP_384_BP,                0},
+    {"sha384",           INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA2_384_192,    0},
     {"sha2_256_96",      INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA2_256_96,     0},
-    {"blowfish256",      ENCRYPTION_ALGORITHM, ENCR_BLOWFISH,           256},
-    {"ecp224bp",         DIFFIE_HELLMAN_GROUP, ECP_224_BP,                0},
+    {"camellia256ctr",   ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CTR,       256},
+    {"twofish256",       ENCRYPTION_ALGORITHM, ENCR_TWOFISH_CBC,        256},
+    {"aes192gcm64",      ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV8,       192},
+    {"aes128gcm64",      ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV8,       128},
     {"sha1_160",         INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA1_160,        0},
+    {"twofish192",       ENCRYPTION_ALGORITHM, ENCR_TWOFISH_CBC,        192},
+    {"ecp384bp",         DIFFIE_HELLMAN_GROUP, ECP_384_BP,                0},
     {"aes256gcm64",      ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV8,       256},
-    {"twofish",          ENCRYPTION_ALGORITHM, ENCR_TWOFISH_CBC,        128},
-    {"prfcamelliaxcbc",  PSEUDO_RANDOM_FUNCTION, PRF_CAMELLIA128_XCBC,    0},
-    {"des",              ENCRYPTION_ALGORITHM, ENCR_DES,                  0},
+    {"chacha20poly1305", ENCRYPTION_ALGORITHM, ENCR_CHACHA20_POLY1305,  256},
+    {"ecp224bp",         DIFFIE_HELLMAN_GROUP, ECP_224_BP,                0},
     {"sha2_384",         INTEGRITY_ALGORITHM,  AUTH_HMAC_SHA2_384_192,    0},
-    {"twofish128",       ENCRYPTION_ALGORITHM, ENCR_TWOFISH_CBC,        128},
-    {"modp2048s224",     DIFFIE_HELLMAN_GROUP, MODP_2048_224,             0},
-    {"twofish256",       ENCRYPTION_ALGORITHM, ENCR_TWOFISH_CBC,        256},
-    {"twofish192",       ENCRYPTION_ALGORITHM, ENCR_TWOFISH_CBC,        192},
-    {"prfaesxcbc",       PSEUDO_RANDOM_FUNCTION, PRF_AES128_XCBC,         0},
-    {"prfaescmac",       PSEUDO_RANDOM_FUNCTION, PRF_AES128_CMAC,         0}
+    {"modp2048s224",     DIFFIE_HELLMAN_GROUP, MODP_2048_224,             0}
   };
 
 static const short lookup[] =
   {
      -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+     -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,
+     -1,  -1,   1,   2,  -1,   3,  -1,   4,  -1,  -1,
+      5,  -1,  -1,   6,  -1,   7,  -1,   8,  -1,  -1,
+      9,  -1,  10,  11,  12,  13,  14,  15,  16,  17,
+     18,  19,  20,  21,  22,  23,  24,  25,  -1,  26,
+     -1,  27,  28,  -1,  -1,  29,  30,  31,  -1,  32,
+     -1,  33,  34,  35,  36,  -1,  -1,  37,  38,  -1,
+     39,  40,  41,  42,  43,  44,  45,  46,  47,  48,
+     49,  50,  51,  -1,  52,  53,  54,  55,  56,  -1,
+     57,  58,  59,  -1,  -1,  -1,  60,  61,  62,  63,
+     -1,  -1,  64,  65,  -1,  66,  -1,  -1,  67,  -1,
+     -1,  -1,  -1,  68,  -1,  69,  -1,  70,  71,  -1,
+     72,  -1,  -1,  73,  74,  75,  76,  77,  78,  79,
+     80,  -1,  81,  82,  83,  84,  85,  86,  87,  88,
+     89,  90,  91,  92,  -1,  93,  94,  95,  96,  -1,
+     97,  98,  -1,  99, 100, 101,  -1, 102,  -1,  -1,
+    103,  -1,  -1, 104, 105, 106, 107,  -1, 108, 109,
+     -1, 110, 111,  -1,  -1, 112, 113,  -1, 114,  -1,
+     -1,  -1,  -1, 115,  -1, 116, 117,  -1, 118,  -1,
+    119, 120, 121, 122, 123,  -1, 124, 125,  -1, 126,
+     -1,  -1, 127,  -1, 128, 129,  -1,  -1, 130,  -1,
      -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
-      0,  -1,   1,   2,  -1,  -1,  -1,  -1,  -1,  -1,
-     -1,  -1,  -1,   3,   4,  -1,  -1,  -1,   5,  -1,
-      6,   7,  -1,  -1,  -1,  -1,   8,  -1,   9,  10,
-     -1,  -1,  11,  -1,  12,  -1,  13,  -1,  14,  15,
-     -1,  16,  17,  18,  19,  20,  -1,  -1,  -1,  21,
-     22,  23,  24,  25,  26,  27,  28,  29,  30,  31,
-     32,  33,  34,  35,  36,  37,  -1,  38,  39,  -1,
-     40,  41,  42,  -1,  43,  44,  45,  46,  47,  48,
-     -1,  49,  50,  51,  -1,  52,  53,  54,  55,  56,
-     57,  58,  59,  -1,  -1,  60,  61,  62,  63,  64,
-     65,  66,  -1,  -1,  67,  68,  69,  70,  71,  72,
-     73,  74,  75,  76,  77,  78,  79,  80,  -1,  81,
-     82,  83,  84,  85,  86,  87,  88,  89,  90,  91,
-     92,  93,  -1,  94,  -1,  95,  -1,  96,  97,  98,
-     99, 100,  -1, 101,  -1, 102, 103, 104,  -1, 105,
-    106, 107, 108, 109,  -1, 110,  -1, 111,  -1, 112,
-     -1, 113, 114, 115, 116,  -1, 117, 118, 119, 120,
-    121,  -1,  -1,  -1, 122,  -1,  -1, 123,  -1,  -1,
-    124,  -1, 125, 126, 127,  -1,  -1,  -1, 128,  -1,
-     -1,  -1,  -1,  -1, 129, 130,  -1, 131,  -1, 132,
-     -1,  -1,  -1,  -1, 133,  -1,  -1,  -1,  -1, 134,
-     -1,  -1,  -1,  -1,  -1, 135,  -1,  -1,  -1,  -1,
-     -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
-     -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+    131,  -1, 132, 133,  -1,  -1, 134,  -1,  -1,  -1,
+     -1, 135,  -1,  -1,  -1,  -1,  -1,  -1, 136,  -1,
      -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
-     -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1, 136,  -1,
      -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
-     -1,  -1,  -1,  -1,  -1, 137
+     -1,  -1, 137,  -1,  -1,  -1, 138
   };
 
 #ifdef __GNUC__
diff --git a/src/libstrongswan/crypto/proposal/proposal_keywords_static.txt b/src/libstrongswan/crypto/proposal/proposal_keywords_static.txt
index 70e7915..da92409 100644
--- a/src/libstrongswan/crypto/proposal/proposal_keywords_static.txt
+++ b/src/libstrongswan/crypto/proposal/proposal_keywords_static.txt
@@ -78,6 +78,7 @@ aes256gcm128,     ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16,      256
 aes128gmac,       ENCRYPTION_ALGORITHM, ENCR_NULL_AUTH_AES_GMAC, 128
 aes192gmac,       ENCRYPTION_ALGORITHM, ENCR_NULL_AUTH_AES_GMAC, 192
 aes256gmac,       ENCRYPTION_ALGORITHM, ENCR_NULL_AUTH_AES_GMAC, 256
+chacha20poly1305, ENCRYPTION_ALGORITHM, ENCR_CHACHA20_POLY1305,  256
 blowfish,         ENCRYPTION_ALGORITHM, ENCR_BLOWFISH,           128
 blowfish128,      ENCRYPTION_ALGORITHM, ENCR_BLOWFISH,           128
 blowfish192,      ENCRYPTION_ALGORITHM, ENCR_BLOWFISH,           192
diff --git a/src/libstrongswan/networking/host.c b/src/libstrongswan/networking/host.c
index 07da3ef..2e464b0 100644
--- a/src/libstrongswan/networking/host.c
+++ b/src/libstrongswan/networking/host.c
@@ -354,6 +354,10 @@ host_t *host_create_from_string_and_family(char *string, int family,
 		struct sockaddr_in6 v6;
 	} addr;
 
+	if (!string)
+	{
+		return NULL;
+	}
 	if (streq(string, "%any"))
 	{
 		return host_create_any_port(family ? family : AF_INET, port);
diff --git a/src/libstrongswan/pen/pen.c b/src/libstrongswan/pen/pen.c
index 474a7a8..9fe4754 100644
--- a/src/libstrongswan/pen/pen.c
+++ b/src/libstrongswan/pen/pen.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 Andreas Steffen
+ * Copyright (C) 2011-2015 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -23,7 +23,9 @@ ENUM_NEXT(pen_names, PEN_MICROSOFT, PEN_MICROSOFT, PEN_IBM,
 	"Microsoft");
 ENUM_NEXT(pen_names, PEN_REDHAT, PEN_REDHAT, PEN_MICROSOFT,
 	"Redhat");
-ENUM_NEXT(pen_names, PEN_ALTIGA, PEN_ALTIGA, PEN_REDHAT,
+ENUM_NEXT(pen_names, PEN_PWG, PEN_PWG, PEN_REDHAT,
+	"PWG");
+ENUM_NEXT(pen_names, PEN_ALTIGA, PEN_ALTIGA, PEN_PWG,
 	"Altiga");
 ENUM_NEXT(pen_names, PEN_OSC, PEN_OSC, PEN_ALTIGA,
 	"OSC");
diff --git a/src/libstrongswan/pen/pen.h b/src/libstrongswan/pen/pen.h
index 1760a05..2c55923 100644
--- a/src/libstrongswan/pen/pen.h
+++ b/src/libstrongswan/pen/pen.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011-2012 Andreas Steffen
+ * Copyright (C) 2011-2015 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -39,6 +39,7 @@ enum pen_t {
 	PEN_IBM =			0x000002,	/*        2 */
 	PEN_MICROSOFT =		0x000137,	/*      311 */
 	PEN_REDHAT =		0x000908,	/*     2312 */
+	PEN_PWG =			0x000A8B,	/*     2699 */
 	PEN_ALTIGA =		0x000c04,	/*     3076 */
 	PEN_OSC =			0x002358,	/*     9048 */
 	PEN_DEBIAN =		0x002572,	/*     9586 */
diff --git a/src/libstrongswan/plugins/bliss/bliss_private_key.c b/src/libstrongswan/plugins/bliss/bliss_private_key.c
index e1064d2..1386eeb 100644
--- a/src/libstrongswan/plugins/bliss/bliss_private_key.c
+++ b/src/libstrongswan/plugins/bliss/bliss_private_key.c
@@ -168,7 +168,7 @@ static bool sign_bliss(private_bliss_private_key_t *this, hash_algorithm_t alg,
 	bliss_sampler_t *sampler = NULL;
 	rng_t *rng;
 	hasher_t *hasher;
-	hash_algorithm_t mgf1_alg;
+	hash_algorithm_t mgf1_alg, oracle_alg;
 	size_t mgf1_seed_len;
 	uint8_t mgf1_seed_buf[HASH_SIZE_SHA512], data_hash_buf[HASH_SIZE_SHA512];
 	chunk_t mgf1_seed, data_hash;
@@ -185,7 +185,7 @@ static bool sign_bliss(private_bliss_private_key_t *this, hash_algorithm_t alg,
 	/* Initialize signature */
 	*signature = chunk_empty;
 
-	/* Create data hash */
+	/* Create data hash using configurable hash algorithm */
 	hasher = lib->crypto->create_hasher(lib->crypto, alg);
 	if (!hasher)
 	{
@@ -200,13 +200,6 @@ static bool sign_bliss(private_bliss_private_key_t *this, hash_algorithm_t alg,
 	}
 	hasher->destroy(hasher);
 
-	/* Create SHA512 hasher for c_indices oracle */
-	hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA512);
-	if (!hasher)
-	{
-		return FALSE;
-	}
-
 	/* Set MGF1 hash algorithm and seed length based on security strength */
 	if (this->set->strength > 160)
 	{
@@ -223,10 +216,12 @@ static bool sign_bliss(private_bliss_private_key_t *this, hash_algorithm_t alg,
 	rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG);
 	if (!rng)
 	{
-		hasher->destroy(hasher);
 		return FALSE;
 	}
 
+	/* MGF1 hash algorithm to be used for random oracle */
+	oracle_alg = HASH_SHA512;
+
 	/* Initialize a couple of needed variables */
 	n  = this->set->n;
 	q  = this->set->q;
@@ -360,7 +355,7 @@ static bool sign_bliss(private_bliss_private_key_t *this, hash_algorithm_t alg,
 			DBG3(DBG_LIB, "%3d  %6d   %4d", i, u[i], ud[i]);
 		}
 
-		if (!bliss_utils_generate_c(hasher, data_hash, ud, n, this->set->kappa,
+		if (!bliss_utils_generate_c(oracle_alg, data_hash, ud, this->set,
 									c_indices))
 		{
 			goto end;
@@ -495,7 +490,6 @@ static bool sign_bliss(private_bliss_private_key_t *this, hash_algorithm_t alg,
 end:
 	/* cleanup */
 	DESTROY_IF(sampler);
-	hasher->destroy(hasher);
 	sig->destroy(sig);
 	fft->destroy(fft);
 	rng->destroy(rng);
diff --git a/src/libstrongswan/plugins/bliss/bliss_public_key.c b/src/libstrongswan/plugins/bliss/bliss_public_key.c
index 0175b0f..2b305f6 100644
--- a/src/libstrongswan/plugins/bliss/bliss_public_key.c
+++ b/src/libstrongswan/plugins/bliss/bliss_public_key.c
@@ -70,11 +70,12 @@ static bool verify_bliss(private_bliss_public_key_t *this, hash_algorithm_t alg,
 	uint8_t data_hash_buf[HASH_SIZE_SHA512];
 	chunk_t data_hash;
 	hasher_t *hasher;
+	hash_algorithm_t oracle_alg;
 	bliss_fft_t *fft;
 	bliss_signature_t *sig;
 	bool success = FALSE;
 
-	/* Create data hash */
+	/* Create data hash using configurable hash algorithm */
 	hasher = lib->crypto->create_hasher(lib->crypto, alg);
 	if (!hasher )
 	{
@@ -89,28 +90,22 @@ static bool verify_bliss(private_bliss_public_key_t *this, hash_algorithm_t alg,
 	}
 	hasher->destroy(hasher);
 
-	/* Create SHA512 hasher for c_indices oracle */
-	hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA512);
-	if (!hasher)
-	{
-		return FALSE;
-	}
-
 	sig = bliss_signature_create_from_data(this->set, signature);
 	if (!sig)
 	{
-		hasher->destroy(hasher);
 		return FALSE;
 	}
 	sig->get_parameters(sig, &z1, &z2d, &c_indices);
 
 	if (!bliss_utils_check_norms(this->set, z1, z2d))
 	{
-		hasher->destroy(hasher);
 		sig->destroy(sig);
 		return FALSE;
 	}
 
+	/* MGF1 hash algorithm to be used for random oracle */
+	oracle_alg = HASH_SHA512;
+
 	/* Initialize a couple of needed variables */
 	n  = this->set->n;
 	q  = this->set->q;
@@ -165,8 +160,7 @@ static bool verify_bliss(private_bliss_public_key_t *this, hash_algorithm_t alg,
 		DBG3(DBG_LIB, "%3d  %6d   %4d  %4d", i, u[i], ud[i], z2d[i]);
 	}
 
-	if (!bliss_utils_generate_c(hasher, data_hash, ud, n, this->set->kappa,
-								indices))
+	if (!bliss_utils_generate_c(oracle_alg, data_hash, ud, this->set, indices))
 	{
 		goto end;
 	}
@@ -183,7 +177,6 @@ static bool verify_bliss(private_bliss_public_key_t *this, hash_algorithm_t alg,
 
 end:
 	/* cleanup */
-	hasher->destroy(hasher);
 	sig->destroy(sig);
 	fft->destroy(fft);
 	free(az);
diff --git a/src/libstrongswan/plugins/bliss/bliss_utils.c b/src/libstrongswan/plugins/bliss/bliss_utils.c
index 5a06998..5e313ff 100644
--- a/src/libstrongswan/plugins/bliss/bliss_utils.c
+++ b/src/libstrongswan/plugins/bliss/bliss_utils.c
@@ -17,6 +17,7 @@
 
 #include <asn1/asn1.h>
 #include <crypto/hashers/hasher.h>
+#include <crypto/mgf1/mgf1_bitspender.h>
 #include <utils/debug.h>
 
 /**
@@ -54,55 +55,63 @@ void bliss_utils_round_and_drop(bliss_param_set_t *set, int32_t *x, int16_t *xd)
 /**
  * See header.
  */
-bool bliss_utils_generate_c(hasher_t *hasher, chunk_t data_hash, uint16_t *ud,
-							int n, uint16_t kappa, uint16_t *c_indices)
+bool bliss_utils_generate_c(hash_algorithm_t alg, chunk_t data_hash,
+							uint16_t *ud, bliss_param_set_t *set,
+							uint16_t *c_indices)
 {
-	int i, j;
-	uint64_t extra_bits;
-	uint16_t index, rounds = 0;
-	uint8_t hash[HASH_SIZE_SHA512], un16_buf[2];
-	chunk_t un16 = { un16_buf, 2 };
-	bool index_taken[n];
-
-	while (TRUE)
+	int i, index_trials = 0, index_found = 0;
+	bool index_taken[set->n];
+	uint32_t index;
+	uint8_t *seed_pos;
+	chunk_t seed;
+	mgf1_bitspender_t *bitspender;
+
+	seed = chunk_alloca(data_hash.len + set->n * sizeof(uint16_t));
+
+	/* the data hash makes up the first part of the oracle seed */
+	memcpy(seed.ptr, data_hash.ptr, data_hash.len);
+	seed_pos = seed.ptr + data_hash.len;
+
+	/* followed by the n elements of the ud vector in network order */
+	for (i = 0; i < set->n; i++)
 	{
-		if (!hasher->get_hash(hasher, data_hash, NULL))
-		{
-			return FALSE;
-		}
+		htoun16(seed_pos, ud[i]);
+		seed_pos += sizeof(uint16_t);
+	}
 
-		for (i = 0; i < n; i++)
-		{
-			htoun16(un16_buf, ud[i]);
-			if (!hasher->get_hash(hasher, un16, NULL))
-			{
-				return FALSE;
-			}
-			index_taken[i] = FALSE;
-		}
+	bitspender = mgf1_bitspender_create(alg, seed, FALSE);
+	if (!bitspender)
+	{
+	    return NULL;
+	}
 
-		htoun16(un16_buf, rounds++);
-		if (!hasher->get_hash(hasher, un16, hash))
-		{
-			return FALSE;
-		}
+	for (i = 0; i < set->n; i++)
+	{
+		index_taken[i] = FALSE;
+	}
 
-		extra_bits = untoh64(hash + sizeof(hash) - sizeof(uint64_t));
+	DBG3(DBG_LIB, " i  c_index[i]");
+	while (bitspender->get_bits(bitspender, set->n_bits, &index))
+	{
+		index_trials++;
 
-		for (i = 0, j = 0; j < sizeof(hash); j++)
+		if (!index_taken[index])
 		{
-			index = 2 * (uint16_t)hash[i] + (extra_bits & 1);
-			if (!index_taken[index])
-			{
-				c_indices[i++] = index;
-				index_taken[index] = TRUE;
-			}
-			if (i == kappa)
+			DBG3(DBG_LIB, "%2u %8u", index_found, index);
+			c_indices[index_found++] = index;
+			index_taken[index] = TRUE;
+
+			if (index_found == set->kappa)
 			{
+				DBG3(DBG_LIB, "%2d  index trials", index_trials);
+				bitspender->destroy(bitspender);
 				return TRUE;
 			}
 		}
 	}
+
+	bitspender->destroy(bitspender);
+	return FALSE;
 }
 
 /**
diff --git a/src/libstrongswan/plugins/bliss/bliss_utils.h b/src/libstrongswan/plugins/bliss/bliss_utils.h
index 063fd91..156968d 100644
--- a/src/libstrongswan/plugins/bliss/bliss_utils.h
+++ b/src/libstrongswan/plugins/bliss/bliss_utils.h
@@ -47,15 +47,15 @@ void bliss_utils_round_and_drop(bliss_param_set_t *set,	int32_t *x, int16_t *xd)
 /**
  * Generate the binary challenge vector c as an array of kappa indices
  *
- * @param hasher	hasher used as an oracle
+ * @param alg		hash algorithm to be used for the internal oracle
  * @param data_hash	hash of the data to be signed
  * @param ud		input vector ud of size n
- * @param n			size of input vector ud
- * @param kappa		parameter kappa
+ * @param set		BLISS parameter set to be used (n, n_bits, kappa)
  * @param c_indices	indexes of non-zero challenge coefficients
  */
-bool bliss_utils_generate_c(hasher_t *hasher, chunk_t data_hash, uint16_t *ud,
-							int n, uint16_t kappa, uint16_t *c_indices);
+bool bliss_utils_generate_c(hash_algorithm_t alg, chunk_t data_hash,
+							uint16_t *ud, bliss_param_set_t *set,
+							uint16_t *c_indices);
 
 /**
  * Check the infinity and l2 norms of the vectors z1 and z2d << d
diff --git a/src/libstrongswan/plugins/chapoly/Makefile.am b/src/libstrongswan/plugins/chapoly/Makefile.am
new file mode 100644
index 0000000..1753de0
--- /dev/null
+++ b/src/libstrongswan/plugins/chapoly/Makefile.am
@@ -0,0 +1,29 @@
+AM_CPPFLAGS = \
+	-I$(top_srcdir)/src/libstrongswan
+
+AM_CFLAGS = \
+	$(PLUGIN_CFLAGS)
+
+noinst_LTLIBRARIES =
+if MONOLITHIC
+noinst_LTLIBRARIES += libstrongswan-chapoly.la
+else
+plugin_LTLIBRARIES = libstrongswan-chapoly.la
+endif
+
+libstrongswan_chapoly_la_SOURCES = \
+	chapoly_plugin.h chapoly_plugin.c \
+	chapoly_drv.h chapoly_drv.c \
+	chapoly_drv_portable.h chapoly_drv_portable.c \
+	chapoly_aead.h chapoly_aead.c
+
+noinst_LTLIBRARIES += libchapoly-drv-ssse3.la
+libchapoly_drv_ssse3_la_SOURCES = chapoly_drv_ssse3.h chapoly_drv_ssse3.c
+if USE_X86X64
+  libchapoly_drv_ssse3_la_CFLAGS = $(PLUGIN_CFLAGS) -mssse3
+endif
+
+libstrongswan_chapoly_la_LIBADD = \
+	libchapoly-drv-ssse3.la
+
+libstrongswan_chapoly_la_LDFLAGS = -module -avoid-version
diff --git a/src/libstrongswan/plugins/test_vectors/Makefile.in b/src/libstrongswan/plugins/chapoly/Makefile.in
similarity index 71%
copy from src/libstrongswan/plugins/test_vectors/Makefile.in
copy to src/libstrongswan/plugins/chapoly/Makefile.in
index e98119b..98e1f4d 100644
--- a/src/libstrongswan/plugins/test_vectors/Makefile.in
+++ b/src/libstrongswan/plugins/chapoly/Makefile.in
@@ -78,7 +78,8 @@ PRE_UNINSTALL = :
 POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
-subdir = src/libstrongswan/plugins/test_vectors
+ at MONOLITHIC_TRUE@am__append_1 = libstrongswan-chapoly.la
+subdir = src/libstrongswan/plugins/chapoly
 DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
 	$(top_srcdir)/depcomp
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
@@ -127,37 +128,31 @@ am__uninstall_files_from_dir = { \
   }
 am__installdirs = "$(DESTDIR)$(plugindir)"
 LTLIBRARIES = $(noinst_LTLIBRARIES) $(plugin_LTLIBRARIES)
-libstrongswan_test_vectors_la_LIBADD =
-am__dirstamp = $(am__leading_dot)dirstamp
-am_libstrongswan_test_vectors_la_OBJECTS = test_vectors_plugin.lo \
-	test_vectors/3des_cbc.lo test_vectors/aes_cbc.lo \
-	test_vectors/aes_ctr.lo test_vectors/aes_xcbc.lo \
-	test_vectors/aes_cmac.lo test_vectors/aes_ccm.lo \
-	test_vectors/aes_gcm.lo test_vectors/blowfish.lo \
-	test_vectors/camellia_cbc.lo test_vectors/camellia_ctr.lo \
-	test_vectors/camellia_xcbc.lo test_vectors/cast.lo \
-	test_vectors/des.lo test_vectors/idea.lo test_vectors/null.lo \
-	test_vectors/rc2.lo test_vectors/rc5.lo \
-	test_vectors/serpent_cbc.lo test_vectors/twofish_cbc.lo \
-	test_vectors/md2.lo test_vectors/md4.lo test_vectors/md5.lo \
-	test_vectors/md5_hmac.lo test_vectors/sha1.lo \
-	test_vectors/sha1_hmac.lo test_vectors/sha2.lo \
-	test_vectors/sha2_hmac.lo test_vectors/fips_prf.lo \
-	test_vectors/modp.lo test_vectors/modpsub.lo \
-	test_vectors/ecp.lo test_vectors/ecpbp.lo test_vectors/rng.lo
-libstrongswan_test_vectors_la_OBJECTS =  \
-	$(am_libstrongswan_test_vectors_la_OBJECTS)
+libchapoly_drv_ssse3_la_LIBADD =
+am_libchapoly_drv_ssse3_la_OBJECTS =  \
+	libchapoly_drv_ssse3_la-chapoly_drv_ssse3.lo
+libchapoly_drv_ssse3_la_OBJECTS =  \
+	$(am_libchapoly_drv_ssse3_la_OBJECTS)
 AM_V_lt = $(am__v_lt_ at AM_V@)
 am__v_lt_ = $(am__v_lt_ at AM_DEFAULT_V@)
 am__v_lt_0 = --silent
 am__v_lt_1 = 
-libstrongswan_test_vectors_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+libchapoly_drv_ssse3_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
 	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
-	$(AM_CFLAGS) $(CFLAGS) \
-	$(libstrongswan_test_vectors_la_LDFLAGS) $(LDFLAGS) -o $@
- at MONOLITHIC_FALSE@am_libstrongswan_test_vectors_la_rpath = -rpath \
+	$(libchapoly_drv_ssse3_la_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+	$(LDFLAGS) -o $@
+libstrongswan_chapoly_la_DEPENDENCIES = libchapoly-drv-ssse3.la
+am_libstrongswan_chapoly_la_OBJECTS = chapoly_plugin.lo chapoly_drv.lo \
+	chapoly_drv_portable.lo chapoly_aead.lo
+libstrongswan_chapoly_la_OBJECTS =  \
+	$(am_libstrongswan_chapoly_la_OBJECTS)
+libstrongswan_chapoly_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+	$(AM_CFLAGS) $(CFLAGS) $(libstrongswan_chapoly_la_LDFLAGS) \
+	$(LDFLAGS) -o $@
+ at MONOLITHIC_FALSE@am_libstrongswan_chapoly_la_rpath = -rpath \
 @MONOLITHIC_FALSE@	$(plugindir)
- at MONOLITHIC_TRUE@am_libstrongswan_test_vectors_la_rpath =
+ at MONOLITHIC_TRUE@am_libstrongswan_chapoly_la_rpath =
 AM_V_P = $(am__v_P_ at AM_V@)
 am__v_P_ = $(am__v_P_ at AM_DEFAULT_V@)
 am__v_P_0 = false
@@ -192,8 +187,10 @@ AM_V_CCLD = $(am__v_CCLD_ at AM_V@)
 am__v_CCLD_ = $(am__v_CCLD_ at AM_DEFAULT_V@)
 am__v_CCLD_0 = @echo "  CCLD    " $@;
 am__v_CCLD_1 = 
-SOURCES = $(libstrongswan_test_vectors_la_SOURCES)
-DIST_SOURCES = $(libstrongswan_test_vectors_la_SOURCES)
+SOURCES = $(libchapoly_drv_ssse3_la_SOURCES) \
+	$(libstrongswan_chapoly_la_SOURCES)
+DIST_SOURCES = $(libchapoly_drv_ssse3_la_SOURCES) \
+	$(libstrongswan_chapoly_la_SOURCES)
 am__can_run_installinfo = \
   case $$AM_UPDATE_INFO_DIR in \
     n|no|NO) false;; \
@@ -450,45 +447,20 @@ AM_CPPFLAGS = \
 AM_CFLAGS = \
 	$(PLUGIN_CFLAGS)
 
- at MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-test-vectors.la
- at MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-test-vectors.la
-libstrongswan_test_vectors_la_SOURCES = \
-	test_vectors_plugin.h test_vectors_plugin.c test_vectors.h \
-	test_vectors/3des_cbc.c \
-	test_vectors/aes_cbc.c \
-	test_vectors/aes_ctr.c \
-	test_vectors/aes_xcbc.c \
-	test_vectors/aes_cmac.c \
-	test_vectors/aes_ccm.c \
-	test_vectors/aes_gcm.c \
-	test_vectors/blowfish.c \
-	test_vectors/camellia_cbc.c \
-	test_vectors/camellia_ctr.c \
-	test_vectors/camellia_xcbc.c \
-	test_vectors/cast.c \
-	test_vectors/des.c \
-	test_vectors/idea.c \
-	test_vectors/null.c \
-	test_vectors/rc2.c \
-	test_vectors/rc5.c \
-	test_vectors/serpent_cbc.c \
-	test_vectors/twofish_cbc.c \
-	test_vectors/md2.c \
-	test_vectors/md4.c \
-	test_vectors/md5.c \
-	test_vectors/md5_hmac.c \
-	test_vectors/sha1.c \
-	test_vectors/sha1_hmac.c \
-	test_vectors/sha2.c \
-	test_vectors/sha2_hmac.c \
-	test_vectors/fips_prf.c \
-	test_vectors/modp.c \
-	test_vectors/modpsub.c \
-	test_vectors/ecp.c \
-	test_vectors/ecpbp.c \
-	test_vectors/rng.c
-
-libstrongswan_test_vectors_la_LDFLAGS = -module -avoid-version
+noinst_LTLIBRARIES = $(am__append_1) libchapoly-drv-ssse3.la
+ at MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-chapoly.la
+libstrongswan_chapoly_la_SOURCES = \
+	chapoly_plugin.h chapoly_plugin.c \
+	chapoly_drv.h chapoly_drv.c \
+	chapoly_drv_portable.h chapoly_drv_portable.c \
+	chapoly_aead.h chapoly_aead.c
+
+libchapoly_drv_ssse3_la_SOURCES = chapoly_drv_ssse3.h chapoly_drv_ssse3.c
+ at USE_X86X64_TRUE@libchapoly_drv_ssse3_la_CFLAGS = $(PLUGIN_CFLAGS) -mssse3
+libstrongswan_chapoly_la_LIBADD = \
+	libchapoly-drv-ssse3.la
+
+libstrongswan_chapoly_la_LDFLAGS = -module -avoid-version
 all: all-am
 
 .SUFFIXES:
@@ -502,9 +474,9 @@ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
 	      exit 1;; \
 	  esac; \
 	done; \
-	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/libstrongswan/plugins/test_vectors/Makefile'; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/libstrongswan/plugins/chapoly/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
-	  $(AUTOMAKE) --gnu src/libstrongswan/plugins/test_vectors/Makefile
+	  $(AUTOMAKE) --gnu src/libstrongswan/plugins/chapoly/Makefile
 .PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
@@ -569,124 +541,24 @@ clean-pluginLTLIBRARIES:
 	  echo rm -f $${locs}; \
 	  rm -f $${locs}; \
 	}
-test_vectors/$(am__dirstamp):
-	@$(MKDIR_P) test_vectors
-	@: > test_vectors/$(am__dirstamp)
-test_vectors/$(DEPDIR)/$(am__dirstamp):
-	@$(MKDIR_P) test_vectors/$(DEPDIR)
-	@: > test_vectors/$(DEPDIR)/$(am__dirstamp)
-test_vectors/3des_cbc.lo: test_vectors/$(am__dirstamp) \
-	test_vectors/$(DEPDIR)/$(am__dirstamp)
-test_vectors/aes_cbc.lo: test_vectors/$(am__dirstamp) \
-	test_vectors/$(DEPDIR)/$(am__dirstamp)
-test_vectors/aes_ctr.lo: test_vectors/$(am__dirstamp) \
-	test_vectors/$(DEPDIR)/$(am__dirstamp)
-test_vectors/aes_xcbc.lo: test_vectors/$(am__dirstamp) \
-	test_vectors/$(DEPDIR)/$(am__dirstamp)
-test_vectors/aes_cmac.lo: test_vectors/$(am__dirstamp) \
-	test_vectors/$(DEPDIR)/$(am__dirstamp)
-test_vectors/aes_ccm.lo: test_vectors/$(am__dirstamp) \
-	test_vectors/$(DEPDIR)/$(am__dirstamp)
-test_vectors/aes_gcm.lo: test_vectors/$(am__dirstamp) \
-	test_vectors/$(DEPDIR)/$(am__dirstamp)
-test_vectors/blowfish.lo: test_vectors/$(am__dirstamp) \
-	test_vectors/$(DEPDIR)/$(am__dirstamp)
-test_vectors/camellia_cbc.lo: test_vectors/$(am__dirstamp) \
-	test_vectors/$(DEPDIR)/$(am__dirstamp)
-test_vectors/camellia_ctr.lo: test_vectors/$(am__dirstamp) \
-	test_vectors/$(DEPDIR)/$(am__dirstamp)
-test_vectors/camellia_xcbc.lo: test_vectors/$(am__dirstamp) \
-	test_vectors/$(DEPDIR)/$(am__dirstamp)
-test_vectors/cast.lo: test_vectors/$(am__dirstamp) \
-	test_vectors/$(DEPDIR)/$(am__dirstamp)
-test_vectors/des.lo: test_vectors/$(am__dirstamp) \
-	test_vectors/$(DEPDIR)/$(am__dirstamp)
-test_vectors/idea.lo: test_vectors/$(am__dirstamp) \
-	test_vectors/$(DEPDIR)/$(am__dirstamp)
-test_vectors/null.lo: test_vectors/$(am__dirstamp) \
-	test_vectors/$(DEPDIR)/$(am__dirstamp)
-test_vectors/rc2.lo: test_vectors/$(am__dirstamp) \
-	test_vectors/$(DEPDIR)/$(am__dirstamp)
-test_vectors/rc5.lo: test_vectors/$(am__dirstamp) \
-	test_vectors/$(DEPDIR)/$(am__dirstamp)
-test_vectors/serpent_cbc.lo: test_vectors/$(am__dirstamp) \
-	test_vectors/$(DEPDIR)/$(am__dirstamp)
-test_vectors/twofish_cbc.lo: test_vectors/$(am__dirstamp) \
-	test_vectors/$(DEPDIR)/$(am__dirstamp)
-test_vectors/md2.lo: test_vectors/$(am__dirstamp) \
-	test_vectors/$(DEPDIR)/$(am__dirstamp)
-test_vectors/md4.lo: test_vectors/$(am__dirstamp) \
-	test_vectors/$(DEPDIR)/$(am__dirstamp)
-test_vectors/md5.lo: test_vectors/$(am__dirstamp) \
-	test_vectors/$(DEPDIR)/$(am__dirstamp)
-test_vectors/md5_hmac.lo: test_vectors/$(am__dirstamp) \
-	test_vectors/$(DEPDIR)/$(am__dirstamp)
-test_vectors/sha1.lo: test_vectors/$(am__dirstamp) \
-	test_vectors/$(DEPDIR)/$(am__dirstamp)
-test_vectors/sha1_hmac.lo: test_vectors/$(am__dirstamp) \
-	test_vectors/$(DEPDIR)/$(am__dirstamp)
-test_vectors/sha2.lo: test_vectors/$(am__dirstamp) \
-	test_vectors/$(DEPDIR)/$(am__dirstamp)
-test_vectors/sha2_hmac.lo: test_vectors/$(am__dirstamp) \
-	test_vectors/$(DEPDIR)/$(am__dirstamp)
-test_vectors/fips_prf.lo: test_vectors/$(am__dirstamp) \
-	test_vectors/$(DEPDIR)/$(am__dirstamp)
-test_vectors/modp.lo: test_vectors/$(am__dirstamp) \
-	test_vectors/$(DEPDIR)/$(am__dirstamp)
-test_vectors/modpsub.lo: test_vectors/$(am__dirstamp) \
-	test_vectors/$(DEPDIR)/$(am__dirstamp)
-test_vectors/ecp.lo: test_vectors/$(am__dirstamp) \
-	test_vectors/$(DEPDIR)/$(am__dirstamp)
-test_vectors/ecpbp.lo: test_vectors/$(am__dirstamp) \
-	test_vectors/$(DEPDIR)/$(am__dirstamp)
-test_vectors/rng.lo: test_vectors/$(am__dirstamp) \
-	test_vectors/$(DEPDIR)/$(am__dirstamp)
-
-libstrongswan-test-vectors.la: $(libstrongswan_test_vectors_la_OBJECTS) $(libstrongswan_test_vectors_la_DEPENDENCIES) $(EXTRA_libstrongswan_test_vectors_la_DEPENDENCIES) 
-	$(AM_V_CCLD)$(libstrongswan_test_vectors_la_LINK) $(am_libstrongswan_test_vectors_la_rpath) $(libstrongswan_test_vectors_la_OBJECTS) $(libstrongswan_test_vectors_la_LIBADD) $(LIBS)
+
+libchapoly-drv-ssse3.la: $(libchapoly_drv_ssse3_la_OBJECTS) $(libchapoly_drv_ssse3_la_DEPENDENCIES) $(EXTRA_libchapoly_drv_ssse3_la_DEPENDENCIES) 
+	$(AM_V_CCLD)$(libchapoly_drv_ssse3_la_LINK)  $(libchapoly_drv_ssse3_la_OBJECTS) $(libchapoly_drv_ssse3_la_LIBADD) $(LIBS)
+
+libstrongswan-chapoly.la: $(libstrongswan_chapoly_la_OBJECTS) $(libstrongswan_chapoly_la_DEPENDENCIES) $(EXTRA_libstrongswan_chapoly_la_DEPENDENCIES) 
+	$(AM_V_CCLD)$(libstrongswan_chapoly_la_LINK) $(am_libstrongswan_chapoly_la_rpath) $(libstrongswan_chapoly_la_OBJECTS) $(libstrongswan_chapoly_la_LIBADD) $(LIBS)
 
 mostlyclean-compile:
 	-rm -f *.$(OBJEXT)
-	-rm -f test_vectors/*.$(OBJEXT)
-	-rm -f test_vectors/*.lo
 
 distclean-compile:
 	-rm -f *.tab.c
 
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test_vectors_plugin.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at test_vectors/$(DEPDIR)/3des_cbc.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at test_vectors/$(DEPDIR)/aes_cbc.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at test_vectors/$(DEPDIR)/aes_ccm.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at test_vectors/$(DEPDIR)/aes_cmac.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at test_vectors/$(DEPDIR)/aes_ctr.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at test_vectors/$(DEPDIR)/aes_gcm.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at test_vectors/$(DEPDIR)/aes_xcbc.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at test_vectors/$(DEPDIR)/blowfish.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at test_vectors/$(DEPDIR)/camellia_cbc.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at test_vectors/$(DEPDIR)/camellia_ctr.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at test_vectors/$(DEPDIR)/camellia_xcbc.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at test_vectors/$(DEPDIR)/cast.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at test_vectors/$(DEPDIR)/des.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at test_vectors/$(DEPDIR)/ecp.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at test_vectors/$(DEPDIR)/ecpbp.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at test_vectors/$(DEPDIR)/fips_prf.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at test_vectors/$(DEPDIR)/idea.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at test_vectors/$(DEPDIR)/md2.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at test_vectors/$(DEPDIR)/md4.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at test_vectors/$(DEPDIR)/md5.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at test_vectors/$(DEPDIR)/md5_hmac.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at test_vectors/$(DEPDIR)/modp.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at test_vectors/$(DEPDIR)/modpsub.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at test_vectors/$(DEPDIR)/null.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at test_vectors/$(DEPDIR)/rc2.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at test_vectors/$(DEPDIR)/rc5.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at test_vectors/$(DEPDIR)/rng.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at test_vectors/$(DEPDIR)/serpent_cbc.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at test_vectors/$(DEPDIR)/sha1.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at test_vectors/$(DEPDIR)/sha1_hmac.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at test_vectors/$(DEPDIR)/sha2.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at test_vectors/$(DEPDIR)/sha2_hmac.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at test_vectors/$(DEPDIR)/twofish_cbc.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/chapoly_aead.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/chapoly_drv.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/chapoly_drv_portable.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/chapoly_plugin.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libchapoly_drv_ssse3_la-chapoly_drv_ssse3.Plo at am__quote@
 
 .c.o:
 @am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
@@ -712,12 +584,18 @@ distclean-compile:
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LTCOMPILE) -c -o $@ $<
 
+libchapoly_drv_ssse3_la-chapoly_drv_ssse3.lo: chapoly_drv_ssse3.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libchapoly_drv_ssse3_la_CFLAGS) $(CFLAGS) -MT libchapoly_drv_ssse3_la-chapoly_drv_ssse3.lo -MD -MP -MF $(DEPDIR)/libchapoly_drv_ssse3_la-chapoly_drv_ssse3.Tpo -c -o libchapoly_drv_ssse3_la-chapoly_drv_ssse3.lo `test -f 'chapoly_drv_ssse3.c' || echo '$(srcdir)/'`chapoly_drv_ssse3.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libchapoly_drv_ssse3_la-chapoly_drv_ssse3.Tpo $(DEPDIR)/libchapoly_drv_ssse3_la-chapoly_drv_ssse3.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='chapoly_drv_ssse3.c' object='libchapoly_drv_ssse3_la-chapoly_drv_ssse3.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libchapoly_drv_ssse3_la_CFLAGS) $(CFLAGS) -c -o libchapoly_drv_ssse3_la-chapoly_drv_ssse3.lo `test -f 'chapoly_drv_ssse3.c' || echo '$(srcdir)/'`chapoly_drv_ssse3.c
+
 mostlyclean-libtool:
 	-rm -f *.lo
 
 clean-libtool:
 	-rm -rf .libs _libs
-	-rm -rf test_vectors/.libs test_vectors/_libs
 
 ID: $(am__tagged_files)
 	$(am__define_uniq_tagged_files); mkid -fID $$unique
@@ -834,8 +712,6 @@ clean-generic:
 distclean-generic:
 	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
 	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
-	-rm -f test_vectors/$(DEPDIR)/$(am__dirstamp)
-	-rm -f test_vectors/$(am__dirstamp)
 
 maintainer-clean-generic:
 	@echo "This command is intended for maintainers to use"
@@ -846,7 +722,7 @@ clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
 	clean-pluginLTLIBRARIES mostlyclean-am
 
 distclean: distclean-am
-	-rm -rf ./$(DEPDIR) test_vectors/$(DEPDIR)
+	-rm -rf ./$(DEPDIR)
 	-rm -f Makefile
 distclean-am: clean-am distclean-compile distclean-generic \
 	distclean-tags
@@ -892,7 +768,7 @@ install-ps-am:
 installcheck-am:
 
 maintainer-clean: maintainer-clean-am
-	-rm -rf ./$(DEPDIR) test_vectors/$(DEPDIR)
+	-rm -rf ./$(DEPDIR)
 	-rm -f Makefile
 maintainer-clean-am: distclean-am maintainer-clean-generic
 
diff --git a/src/libstrongswan/plugins/chapoly/chapoly_aead.c b/src/libstrongswan/plugins/chapoly/chapoly_aead.c
new file mode 100644
index 0000000..50ad84b
--- /dev/null
+++ b/src/libstrongswan/plugins/chapoly/chapoly_aead.c
@@ -0,0 +1,333 @@
+/*
+ * Copyright (C) 2015 Martin Willi
+ * Copyright (C) 2015 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include "chapoly_aead.h"
+#include "chapoly_drv.h"
+
+#include <crypto/iv/iv_gen_seq.h>
+
+/* maximum plain message size */
+#define P_MAX 247877906880
+
+typedef struct private_chapoly_aead_t private_chapoly_aead_t;
+
+/**
+ * Private data of an chapoly_aead_t object.
+ */
+struct private_chapoly_aead_t {
+
+	/**
+	 * Public chapoly_aead_t interface.
+	 */
+	chapoly_aead_t public;
+
+	/**
+	 * IV generator.
+	 */
+	iv_gen_t *iv_gen;
+
+	/**
+	 * Driver backend
+	 */
+	chapoly_drv_t *drv;
+};
+
+/**
+ * Include a partial block to ICV by padding it with zero bytes
+ */
+static bool poly_update_padded(private_chapoly_aead_t *this,
+							   u_char *in, size_t len)
+{
+	u_char b[POLY_BLOCK_SIZE];
+
+	memset(b, 0, sizeof(b));
+	memcpy(b, in, len);
+
+	return this->drv->poly(this->drv, b, 1);
+}
+
+/**
+ * Include associated data with padding to ICV
+ */
+static bool poly_head(private_chapoly_aead_t *this, u_char *assoc, size_t len)
+{
+	u_int blocks, rem;
+
+	blocks = len / POLY_BLOCK_SIZE;
+	rem = len % POLY_BLOCK_SIZE;
+	if (!this->drv->poly(this->drv, assoc, blocks))
+	{
+		return FALSE;
+	}
+	if (rem)
+	{
+		return poly_update_padded(this, assoc + blocks * POLY_BLOCK_SIZE, rem);
+	}
+	return TRUE;
+}
+
+/**
+ * Include length fields to ICV
+ */
+static bool poly_tail(private_chapoly_aead_t *this, size_t alen, size_t clen)
+{
+	struct {
+		u_int64_t alen;
+		u_int64_t clen;
+	} b;
+
+	b.alen = htole64(alen);
+	b.clen = htole64(clen);
+
+	return this->drv->poly(this->drv, (u_char*)&b, 1);
+}
+
+/**
+ * Perform ChaCha20 encryption inline and generate an ICV tag
+ */
+static bool do_encrypt(private_chapoly_aead_t *this, size_t len, u_char *data,
+					   u_char *iv, size_t alen, u_char *assoc, u_char *icv)
+{
+	u_int blocks, rem, prem;
+
+	if (!this->drv->init(this->drv, iv) ||
+		!poly_head(this, assoc, alen))
+	{
+		return FALSE;
+	}
+	blocks = len / CHACHA_BLOCK_SIZE;
+	if (!this->drv->encrypt(this->drv, data, blocks))
+	{
+		return FALSE;
+	}
+	rem = len % CHACHA_BLOCK_SIZE;
+	if (rem)
+	{
+		u_char stream[CHACHA_BLOCK_SIZE];
+
+		data += blocks * CHACHA_BLOCK_SIZE;
+		if (!this->drv->chacha(this->drv, stream))
+		{
+			return FALSE;
+		}
+		memxor(data, stream, rem);
+
+		blocks = rem / POLY_BLOCK_SIZE;
+		if (!this->drv->poly(this->drv, data, blocks))
+		{
+			return FALSE;
+		}
+		prem = rem % POLY_BLOCK_SIZE;
+		if (prem)
+		{
+			poly_update_padded(this, data + blocks * POLY_BLOCK_SIZE, prem);
+		}
+	}
+	return poly_tail(this, alen, len) &&
+		   this->drv->finish(this->drv, icv);
+}
+
+/**
+ * Perform ChaCha20 decryption inline and generate an ICV tag
+ */
+static bool do_decrypt(private_chapoly_aead_t *this, size_t len, u_char *data,
+					   u_char *iv, size_t alen, u_char *assoc, u_char *icv)
+{
+	u_int blocks, rem, prem;
+
+	if (!this->drv->init(this->drv, iv) ||
+		!poly_head(this, assoc, alen))
+	{
+		return FALSE;
+	}
+	blocks = len / CHACHA_BLOCK_SIZE;
+	if (!this->drv->decrypt(this->drv, data, blocks))
+	{
+		return FALSE;
+	}
+	rem = len % CHACHA_BLOCK_SIZE;
+	if (rem)
+	{
+		u_char stream[CHACHA_BLOCK_SIZE];
+
+		data += blocks * CHACHA_BLOCK_SIZE;
+
+		blocks = rem / POLY_BLOCK_SIZE;
+		if (!this->drv->poly(this->drv, data, blocks))
+		{
+			return FALSE;
+		}
+		prem = rem % POLY_BLOCK_SIZE;
+		if (prem)
+		{
+			poly_update_padded(this, data + blocks * POLY_BLOCK_SIZE, prem);
+		}
+		if (!this->drv->chacha(this->drv, stream))
+		{
+			return FALSE;
+		}
+		memxor(data, stream, rem);
+	}
+	return poly_tail(this, alen, len) &&
+		   this->drv->finish(this->drv, icv);
+}
+
+METHOD(aead_t, encrypt, bool,
+	private_chapoly_aead_t *this, chunk_t plain, chunk_t assoc, chunk_t iv,
+	chunk_t *encr)
+{
+	u_char *out;
+
+	if (sizeof(plain.len) > sizeof(u_int32_t) && plain.len > P_MAX)
+	{
+		return FALSE;
+	}
+	if (iv.len != CHACHA_IV_SIZE)
+	{
+		return FALSE;
+	}
+	out = plain.ptr;
+	if (encr)
+	{
+		*encr = chunk_alloc(plain.len + POLY_ICV_SIZE);
+		out = encr->ptr;
+		memcpy(out, plain.ptr, plain.len);
+	}
+	do_encrypt(this, plain.len, out, iv.ptr, assoc.len, assoc.ptr,
+			   out + plain.len);
+	return TRUE;
+}
+
+METHOD(aead_t, decrypt, bool,
+	private_chapoly_aead_t *this, chunk_t encr, chunk_t assoc, chunk_t iv,
+	chunk_t *plain)
+{
+	u_char *out, icv[POLY_ICV_SIZE];
+	if (iv.len != CHACHA_IV_SIZE || encr.len < POLY_ICV_SIZE)
+	{
+		return FALSE;
+	}
+	encr.len -= POLY_ICV_SIZE;
+	if (sizeof(encr.len) > sizeof(u_int32_t) && encr.len > P_MAX)
+	{
+		return FALSE;
+	}
+	out = encr.ptr;
+	if (plain)
+	{
+		*plain = chunk_alloc(encr.len);
+		out = plain->ptr;
+		memcpy(out, encr.ptr, encr.len);
+	}
+	do_decrypt(this, encr.len, out, iv.ptr, assoc.len, assoc.ptr, icv);
+	return memeq_const(icv, encr.ptr + encr.len, POLY_ICV_SIZE);
+}
+
+METHOD(aead_t, get_block_size, size_t,
+	private_chapoly_aead_t *this)
+{
+	return 1;
+}
+
+METHOD(aead_t, get_icv_size, size_t,
+	private_chapoly_aead_t *this)
+{
+	return POLY_ICV_SIZE;
+}
+
+METHOD(aead_t, get_iv_size, size_t,
+	private_chapoly_aead_t *this)
+{
+	return CHACHA_IV_SIZE;
+}
+
+METHOD(aead_t, get_iv_gen, iv_gen_t*,
+	private_chapoly_aead_t *this)
+{
+	return this->iv_gen;
+}
+
+METHOD(aead_t, get_key_size, size_t,
+	private_chapoly_aead_t *this)
+{
+	return CHACHA_KEY_SIZE + CHACHA_SALT_SIZE;
+}
+
+METHOD(aead_t, set_key, bool,
+	private_chapoly_aead_t *this, chunk_t key)
+{
+	if (key.len != CHACHA_KEY_SIZE + CHACHA_SALT_SIZE)
+	{
+		return FALSE;
+	}
+	return this->drv->set_key(this->drv, "expand 32-byte k",
+							  key.ptr, key.ptr + CHACHA_KEY_SIZE);
+}
+
+METHOD(aead_t, destroy, void,
+	private_chapoly_aead_t *this)
+{
+	this->drv->destroy(this->drv);
+	this->iv_gen->destroy(this->iv_gen);
+	free(this);
+}
+
+/**
+ * See header
+ */
+chapoly_aead_t *chapoly_aead_create(encryption_algorithm_t algo,
+									size_t key_size, size_t salt_size)
+{
+	private_chapoly_aead_t *this;
+	chapoly_drv_t *drv;
+
+	if (algo != ENCR_CHACHA20_POLY1305)
+	{
+		return NULL;
+	}
+	if (key_size && key_size != CHACHA_KEY_SIZE)
+	{
+		return NULL;
+	}
+	if (salt_size && salt_size != CHACHA_SALT_SIZE)
+	{
+		return NULL;
+	}
+	drv = chapoly_drv_probe();
+	if (!drv)
+	{
+		return NULL;
+	}
+
+	INIT(this,
+		.public = {
+			.aead = {
+				.encrypt = _encrypt,
+				.decrypt = _decrypt,
+				.get_block_size = _get_block_size,
+				.get_icv_size = _get_icv_size,
+				.get_iv_size = _get_iv_size,
+				.get_iv_gen = _get_iv_gen,
+				.get_key_size = _get_key_size,
+				.set_key = _set_key,
+				.destroy = _destroy,
+			},
+		},
+		.iv_gen = iv_gen_seq_create(),
+		.drv = drv,
+	);
+
+	return &this->public;
+}
diff --git a/src/libstrongswan/plugins/chapoly/chapoly_aead.h b/src/libstrongswan/plugins/chapoly/chapoly_aead.h
new file mode 100644
index 0000000..e090541
--- /dev/null
+++ b/src/libstrongswan/plugins/chapoly/chapoly_aead.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2015 Martin Willi
+ * Copyright (C) 2015 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup chapoly_aead chapoly_aead
+ * @{ @ingroup chapoly
+ */
+
+#ifndef CHAPOLY_AEAD_H_
+#define CHAPOLY_AEAD_H_
+
+#include <crypto/aead.h>
+
+typedef struct chapoly_aead_t chapoly_aead_t;
+
+/**
+ * ChaCha20/Poly1305 AEAD implementation.
+ *
+ * TODO-Chapoly: draft-ietf-ipsecme-chacha20-poly1305-05
+ */
+struct chapoly_aead_t {
+
+	/**
+	 * Implements aead_t interface.
+	 */
+	aead_t aead;
+};
+
+/**
+ * Create a chapoly_aead instance.
+ *
+ * @param algo			algorithm to implement, ENCR_CHACHA20_POLY1305
+ * @param key_size		key size in bytes, 32
+ * @param salt_size		size of implicit salt length, 0
+ * @return				AEAD, NULL if not supported
+ */
+chapoly_aead_t *chapoly_aead_create(encryption_algorithm_t algo,
+									size_t key_size, size_t salt_size);
+
+#endif /** CHAPOLY_AEAD_H_ @}*/
diff --git a/src/libstrongswan/credentials/certificates/ocsp_request.h b/src/libstrongswan/plugins/chapoly/chapoly_drv.c
similarity index 52%
copy from src/libstrongswan/credentials/certificates/ocsp_request.h
copy to src/libstrongswan/plugins/chapoly/chapoly_drv.c
index 0b18713..ca5e2be 100644
--- a/src/libstrongswan/credentials/certificates/ocsp_request.h
+++ b/src/libstrongswan/plugins/chapoly/chapoly_drv.c
@@ -1,6 +1,6 @@
 /*
- * Copyright (C) 2008 Martin Willi
- * Hochschule fuer Technik Rapperswil
+ * Copyright (C) 2015 Martin Willi
+ * Copyright (C) 2015 revosec AG
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
@@ -13,27 +13,31 @@
  * for more details.
  */
 
-/**
- * @defgroup ocsp_request ocsp_request
- * @{ @ingroup certificates
- */
-
-#ifndef OCSP_REQUEST_H_
-#define OCSP_REQUEST_H_
+#include "chapoly_drv.h"
+#include "chapoly_drv_portable.h"
+#include "chapoly_drv_ssse3.h"
 
-#include <credentials/certificates/certificate.h>
-
-typedef struct ocsp_request_t ocsp_request_t;
+typedef chapoly_drv_t*(*chapoly_drv_create)();
 
 /**
- * OCSP request message.
+ * See header.
  */
-struct ocsp_request_t {
-
-	/**
-	 * Implements certificiate_t interface
-	 */
-	certificate_t interface;
-};
+chapoly_drv_t *chapoly_drv_probe()
+{
+	chapoly_drv_create drivers[] = {
+		chapoly_drv_ssse3_create,
+		chapoly_drv_portable_create,
+	};
+	chapoly_drv_t *driver;
+	int i;
 
-#endif /** OCSP_REQUEST_H_ @}*/
+	for (i = 0; i < countof(drivers); i++)
+	{
+		driver = drivers[i]();
+		if (driver)
+		{
+			return driver;
+		}
+	}
+	return NULL;
+}
diff --git a/src/libstrongswan/plugins/chapoly/chapoly_drv.h b/src/libstrongswan/plugins/chapoly/chapoly_drv.h
new file mode 100644
index 0000000..bffc434
--- /dev/null
+++ b/src/libstrongswan/plugins/chapoly/chapoly_drv.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2015 Martin Willi
+ * Copyright (C) 2015 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup chapoly_drv chapoly_drv
+ * @{ @ingroup chapoly
+ */
+
+#ifndef CHAPOLY_DRV_H_
+#define CHAPOLY_DRV_H_
+
+#include <library.h>
+
+#define CHACHA_BLOCK_SIZE 64
+#define CHACHA_IV_SIZE 8
+#define CHACHA_SALT_SIZE 4
+#define CHACHA_KEY_SIZE 32
+#define POLY_BLOCK_SIZE 16
+#define POLY_ICV_SIZE 16
+
+typedef struct chapoly_drv_t chapoly_drv_t;
+
+/**
+ * ChaCha20/Poly1305 backend implementation.
+ */
+struct chapoly_drv_t {
+
+	/**
+	 * Set the ChaCha20 encryption key.
+	 *
+	 * @param constant		16 byte key constant to use
+	 * @param key			32 byte encryption key
+	 * @param salt			4 byte nonce salt
+	 * @return				TRUE if key set
+	 */
+	bool (*set_key)(chapoly_drv_t *this, u_char *constant, u_char *key,
+					u_char *salt);
+
+	/**
+	 * Start an AEAD en/decryption session, reset state.
+	 *
+	 * @param iv			8 byte initialization vector for nonce
+	 * @return				TRUE if initialized
+	 */
+	bool (*init)(chapoly_drv_t *this, u_char *iv);
+
+	/**
+	 * Poly1305 update multiple blocks.
+	 *
+	 * @param data			data to update Poly1305 for
+	 * @param blocks		number of 16-byte blocks to process
+	 * @return				TRUE if updated
+	 */
+	bool (*poly)(chapoly_drv_t *this, u_char *data, u_int blocks);
+
+	/**
+	 * Create a single ChaCha20 keystream block.
+	 *
+	 * @param stream		64-byte block to write key stream data to
+	 * @return				TRUE if keystream returned
+	 */
+	bool (*chacha)(chapoly_drv_t *this, u_char *stream);
+
+	/**
+	 * Encrypt multiple blocks of data inline, update Poly1305.
+	 *
+	 * @param data			data to process
+	 * @param blocks		number of 64-byte blocks to process
+	 * @return				TRUE if encrypted
+	 */
+	bool (*encrypt)(chapoly_drv_t *this, u_char *data, u_int blocks);
+
+	/**
+	 * Decrypt multiple blocks of data inline, update Poly1305.
+	 *
+	 * @param data			data to process
+	 * @param blocks		number of 64-byte blocks to process
+	 * @return				TRUE if decrypted
+	 */
+	bool (*decrypt)(chapoly_drv_t *this, u_char *data, u_int blocks);
+
+	/**
+	 * End a AEAD encryption session, return MAC.
+	 *
+	 * @param mac			16-byte block to write MAC to
+	 * @return				TRUE if MAC returned
+	 */
+	bool (*finish)(chapoly_drv_t *this, u_char *mac);
+
+	/**
+	 * Destroy a chapoly_drv_t.
+	 */
+	void (*destroy)(chapoly_drv_t *this);
+};
+
+/**
+ * Create a chapoly_drv instance.
+ */
+chapoly_drv_t *chapoly_drv_probe();
+
+#endif /** CHAPOLY_DRV_H_ @}*/
diff --git a/src/libstrongswan/plugins/chapoly/chapoly_drv_portable.c b/src/libstrongswan/plugins/chapoly/chapoly_drv_portable.c
new file mode 100644
index 0000000..54e934e
--- /dev/null
+++ b/src/libstrongswan/plugins/chapoly/chapoly_drv_portable.c
@@ -0,0 +1,454 @@
+/*
+ * Copyright (C) 2015 Martin Willi
+ * Copyright (C) 2015 revosec AG
+ *
+ * Based on public domain code by Andrew Moon and Daniel J. Bernstein.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include "chapoly_drv_portable.h"
+
+#define CHACHA_DOUBLEROUNDS 10
+/* index of some state fields */
+#define CHACHA_BLOCKCOUNT 12
+#define CHACHA_NONCE1 13
+#define CHACHA_NONCE2 14
+#define CHACHA_NONCE3 15
+
+typedef struct private_chapoly_drv_portable_t private_chapoly_drv_portable_t;
+
+/**
+ * Private data of an chapoly_drv_portable_t object.
+ */
+struct private_chapoly_drv_portable_t {
+
+	/**
+	 * Public chapoly_drv_portable_t interface.
+	 */
+	chapoly_drv_t public;
+
+	/**
+	 * ChaCha20 state matrix
+	 */
+	u_int32_t m[16];
+
+	/**
+	 * Poly1305 update key
+	 */
+	u_int32_t r[5];
+
+	/**
+	 * Poly1305 state
+	 */
+	u_int32_t h[5];
+
+	/**
+	 * Poly1305 finalize key
+	 */
+	u_int32_t s[4];
+};
+
+/**
+ * Convert unaligned little endian to host byte order
+ */
+static inline u_int32_t uletoh32(void *p)
+{
+	u_int32_t ret;
+
+	memcpy(&ret, p, sizeof(ret));
+	ret = le32toh(ret);
+	return ret;
+}
+
+/**
+ * Convert host byte order to unaligned little endian
+ */
+static inline void htoule32(void *p, u_int32_t v)
+{
+	v = htole32(v);
+	memcpy(p, &v, sizeof(v));
+}
+
+/**
+ * XOR a 32-bit integer into an unaligned destination
+ */
+static inline void xor32u(void *p, u_int32_t x)
+{
+	u_int32_t y;
+
+	memcpy(&y, p, sizeof(y));
+	y ^= x;
+	memcpy(p, &y, sizeof(y));
+}
+
+/**
+ * Multiply two 64-bit words
+ */
+static inline u_int64_t mlt(u_int64_t a, u_int64_t b)
+{
+	return a * b;
+}
+
+/**
+ * Shift a 64-bit unsigned integer v right by n bits, clamp to 32 bit
+*/
+static inline u_int32_t sr(u_int64_t v, u_char n)
+{
+	return v >> n;
+}
+
+/**
+ * Circular left shift by n bits
+ */
+static inline u_int32_t rotl32(u_int32_t v, u_char n)
+{
+	return (v << n) | (v >> (sizeof(v) * 8 - n));
+}
+
+/**
+ * AND two values, using a native integer size >= sizeof(u_int32_t)
+ */
+static inline u_long and(u_long v, u_long mask)
+{
+	return v & mask;
+}
+
+/**
+ * XOR a Chacha20 keystream block into data, increment counter
+ */
+static void chacha_block_xor(private_chapoly_drv_portable_t *this, void *data)
+{
+	u_int32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, xa, xb, xc, xd, xe, xf;
+	u_int32_t *out = data;
+	u_int i;
+
+	x0 = this->m[ 0];
+	x1 = this->m[ 1];
+	x2 = this->m[ 2];
+	x3 = this->m[ 3];
+	x4 = this->m[ 4];
+	x5 = this->m[ 5];
+	x6 = this->m[ 6];
+	x7 = this->m[ 7];
+	x8 = this->m[ 8];
+	x9 = this->m[ 9];
+	xa = this->m[10];
+	xb = this->m[11];
+	xc = this->m[12];
+	xd = this->m[13];
+	xe = this->m[14];
+	xf = this->m[15];
+
+	for (i = 0; i < CHACHA_DOUBLEROUNDS; i++)
+	{
+		x0 += x4; xc = rotl32(xc ^ x0, 16);
+		x1 += x5; xd = rotl32(xd ^ x1, 16);
+		x2 += x6; xe = rotl32(xe ^ x2, 16);
+		x3 += x7; xf = rotl32(xf ^ x3, 16);
+
+		x8 += xc; x4 = rotl32(x4 ^ x8, 12);
+		x9 += xd; x5 = rotl32(x5 ^ x9, 12);
+		xa += xe; x6 = rotl32(x6 ^ xa, 12);
+		xb += xf; x7 = rotl32(x7 ^ xb, 12);
+
+		x0 += x4; xc = rotl32(xc ^ x0, 8);
+		x1 += x5; xd = rotl32(xd ^ x1, 8);
+		x2 += x6; xe = rotl32(xe ^ x2, 8);
+		x3 += x7; xf = rotl32(xf ^ x3, 8);
+
+		x8 += xc; x4 = rotl32(x4 ^ x8, 7);
+		x9 += xd; x5 = rotl32(x5 ^ x9, 7);
+		xa += xe; x6 = rotl32(x6 ^ xa, 7);
+		xb += xf; x7 = rotl32(x7 ^ xb, 7);
+
+		x0 += x5; xf = rotl32(xf ^ x0, 16);
+		x1 += x6; xc = rotl32(xc ^ x1, 16);
+		x2 += x7; xd = rotl32(xd ^ x2, 16);
+		x3 += x4; xe = rotl32(xe ^ x3, 16);
+
+		xa += xf; x5 = rotl32(x5 ^ xa, 12);
+		xb += xc; x6 = rotl32(x6 ^ xb, 12);
+		x8 += xd; x7 = rotl32(x7 ^ x8, 12);
+		x9 += xe; x4 = rotl32(x4 ^ x9, 12);
+
+		x0 += x5; xf = rotl32(xf ^ x0, 8);
+		x1 += x6; xc = rotl32(xc ^ x1, 8);
+		x2 += x7; xd = rotl32(xd ^ x2, 8);
+		x3 += x4; xe = rotl32(xe ^ x3, 8);
+
+		xa += xf; x5 = rotl32(x5 ^ xa, 7);
+		xb += xc; x6 = rotl32(x6 ^ xb, 7);
+		x8 += xd; x7 = rotl32(x7 ^ x8, 7);
+		x9 += xe; x4 = rotl32(x4 ^ x9, 7);
+	}
+
+	xor32u(out +  0, le32toh(x0 + this->m[ 0]));
+	xor32u(out +  1, le32toh(x1 + this->m[ 1]));
+	xor32u(out +  2, le32toh(x2 + this->m[ 2]));
+	xor32u(out +  3, le32toh(x3 + this->m[ 3]));
+	xor32u(out +  4, le32toh(x4 + this->m[ 4]));
+	xor32u(out +  5, le32toh(x5 + this->m[ 5]));
+	xor32u(out +  6, le32toh(x6 + this->m[ 6]));
+	xor32u(out +  7, le32toh(x7 + this->m[ 7]));
+	xor32u(out +  8, le32toh(x8 + this->m[ 8]));
+	xor32u(out +  9, le32toh(x9 + this->m[ 9]));
+	xor32u(out + 10, le32toh(xa + this->m[10]));
+	xor32u(out + 11, le32toh(xb + this->m[11]));
+	xor32u(out + 12, le32toh(xc + this->m[12]));
+	xor32u(out + 13, le32toh(xd + this->m[13]));
+	xor32u(out + 14, le32toh(xe + this->m[14]));
+	xor32u(out + 15, le32toh(xf + this->m[15]));
+
+	this->m[CHACHA_BLOCKCOUNT]++;
+}
+
+METHOD(chapoly_drv_t, set_key, bool,
+	private_chapoly_drv_portable_t *this, u_char *constant, u_char *key,
+	u_char *salt)
+{
+	this->m[ 0] = uletoh32(constant +  0);
+	this->m[ 1] = uletoh32(constant +  4);
+	this->m[ 2] = uletoh32(constant +  8);
+	this->m[ 3] = uletoh32(constant + 12);
+
+	this->m[ 4] = uletoh32(key +  0);
+	this->m[ 5] = uletoh32(key +  4);
+	this->m[ 6] = uletoh32(key +  8);
+	this->m[ 7] = uletoh32(key + 12);
+	this->m[ 8] = uletoh32(key + 16);
+	this->m[ 9] = uletoh32(key + 20);
+	this->m[10] = uletoh32(key + 24);
+	this->m[11] = uletoh32(key + 28);
+
+	this->m[CHACHA_NONCE1] = uletoh32(salt);
+
+	return TRUE;
+}
+
+METHOD(chapoly_drv_t, init, bool,
+	private_chapoly_drv_portable_t *this, u_char *iv)
+{
+	u_char key[CHACHA_BLOCK_SIZE];
+
+	this->m[CHACHA_BLOCKCOUNT] = 0;
+	this->m[CHACHA_NONCE2] = uletoh32(iv + 0);
+	this->m[CHACHA_NONCE3] = uletoh32(iv + 4);
+
+	memset(key, 0, CHACHA_BLOCK_SIZE);
+	chacha_block_xor(this, key);
+
+	/* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
+	this->r[0] = (uletoh32(key +  0) >> 0) & 0x3ffffff;
+	this->r[1] = (uletoh32(key +  3) >> 2) & 0x3ffff03;
+	this->r[2] = (uletoh32(key +  6) >> 4) & 0x3ffc0ff;
+	this->r[3] = (uletoh32(key +  9) >> 6) & 0x3f03fff;
+	this->r[4] = (uletoh32(key + 12) >> 8) & 0x00fffff;
+
+	/* h = 0 */
+	memwipe(this->h, sizeof(this->h));
+
+	this->s[0] = uletoh32(key + 16);
+	this->s[1] = uletoh32(key + 20);
+	this->s[2] = uletoh32(key + 24);
+	this->s[3] = uletoh32(key + 28);
+
+	return TRUE;
+}
+
+METHOD(chapoly_drv_t, poly, bool,
+	private_chapoly_drv_portable_t *this, u_char *data, u_int blocks)
+{
+	u_int32_t r0, r1, r2, r3, r4;
+	u_int32_t s1, s2, s3, s4;
+	u_int32_t h0, h1, h2, h3, h4;
+	u_int64_t d0, d1, d2, d3, d4;
+	u_int i;
+
+	r0 = this->r[0];
+	r1 = this->r[1];
+	r2 = this->r[2];
+	r3 = this->r[3];
+	r4 = this->r[4];
+
+	s1 = r1 * 5;
+	s2 = r2 * 5;
+	s3 = r3 * 5;
+	s4 = r4 * 5;
+
+	h0 = this->h[0];
+	h1 = this->h[1];
+	h2 = this->h[2];
+	h3 = this->h[3];
+	h4 = this->h[4];
+
+	for (i = 0; i < blocks; i++)
+	{
+		/* h += m[i] */
+		h0 += (uletoh32(data +  0) >> 0) & 0x3ffffff;
+		h1 += (uletoh32(data +  3) >> 2) & 0x3ffffff;
+		h2 += (uletoh32(data +  6) >> 4) & 0x3ffffff;
+		h3 += (uletoh32(data +  9) >> 6) & 0x3ffffff;
+		h4 += (uletoh32(data + 12) >> 8) | (1 << 24);
+
+		/* h *= r */
+		d0 = mlt(h0, r0) + mlt(h1, s4) + mlt(h2, s3) + mlt(h3, s2) + mlt(h4, s1);
+		d1 = mlt(h0, r1) + mlt(h1, r0) + mlt(h2, s4) + mlt(h3, s3) + mlt(h4, s2);
+		d2 = mlt(h0, r2) + mlt(h1, r1) + mlt(h2, r0) + mlt(h3, s4) + mlt(h4, s3);
+		d3 = mlt(h0, r3) + mlt(h1, r2) + mlt(h2, r1) + mlt(h3, r0) + mlt(h4, s4);
+		d4 = mlt(h0, r4) + mlt(h1, r3) + mlt(h2, r2) + mlt(h3, r1) + mlt(h4, r0);
+
+		/* (partial) h %= p */
+		d1 += sr(d0, 26);     h0 = and(d0, 0x3ffffff);
+		d2 += sr(d1, 26);     h1 = and(d1, 0x3ffffff);
+		d3 += sr(d2, 26);     h2 = and(d2, 0x3ffffff);
+		d4 += sr(d3, 26);     h3 = and(d3, 0x3ffffff);
+		h0 += sr(d4, 26) * 5; h4 = and(d4, 0x3ffffff);
+		h1 += h0 >> 26;       h0 = h0 & 0x3ffffff;
+
+		data += POLY_BLOCK_SIZE;
+	}
+
+	this->h[0] = h0;
+	this->h[1] = h1;
+	this->h[2] = h2;
+	this->h[3] = h3;
+	this->h[4] = h4;
+
+	return TRUE;
+}
+
+METHOD(chapoly_drv_t, chacha, bool,
+	private_chapoly_drv_portable_t *this, u_char *stream)
+{
+	memset(stream, 0, CHACHA_BLOCK_SIZE);
+	chacha_block_xor(this, stream);
+
+	return TRUE;
+}
+
+METHOD(chapoly_drv_t, encrypt, bool,
+	private_chapoly_drv_portable_t *this, u_char *data, u_int blocks)
+{
+	u_int i;
+
+	for (i = 0; i < blocks; i++)
+	{
+		chacha_block_xor(this, data);
+		poly(this, data, 4);
+		data += CHACHA_BLOCK_SIZE;
+	}
+	return TRUE;
+}
+
+METHOD(chapoly_drv_t, decrypt, bool,
+	private_chapoly_drv_portable_t *this, u_char *data, u_int blocks)
+{
+	u_int i;
+
+	for (i = 0; i < blocks; i++)
+	{
+		poly(this, data, 4);
+		chacha_block_xor(this, data);
+		data += CHACHA_BLOCK_SIZE;
+	}
+	return TRUE;
+}
+
+METHOD(chapoly_drv_t, finish, bool,
+	private_chapoly_drv_portable_t *this, u_char *mac)
+{
+	u_int32_t h0, h1, h2, h3, h4;
+	u_int32_t g0, g1, g2, g3, g4;
+	u_int32_t mask;
+	u_int64_t f = 0;
+
+	/* fully carry h */
+	h0 = this->h[0];
+	h1 = this->h[1];
+	h2 = this->h[2];
+	h3 = this->h[3];
+	h4 = this->h[4];
+
+	h2 += (h1 >> 26);     h1 = h1 & 0x3ffffff;
+	h3 += (h2 >> 26);     h2 = h2 & 0x3ffffff;
+	h4 += (h3 >> 26);     h3 = h3 & 0x3ffffff;
+	h0 += (h4 >> 26) * 5; h4 = h4 & 0x3ffffff;
+	h1 += (h0 >> 26);     h0 = h0 & 0x3ffffff;
+
+	/* compute h + -p */
+	g0 = h0 + 5;
+	g1 = h1 + (g0 >> 26);             g0 &= 0x3ffffff;
+	g2 = h2 + (g1 >> 26);             g1 &= 0x3ffffff;
+	g3 = h3 + (g2 >> 26);             g2 &= 0x3ffffff;
+	g4 = h4 + (g3 >> 26) - (1 << 26); g3 &= 0x3ffffff;
+
+	/* select h if h < p, or h + -p if h >= p */
+	mask = (g4 >> ((sizeof(u_int32_t) * 8) - 1)) - 1;
+	g0 &= mask;
+	g1 &= mask;
+	g2 &= mask;
+	g3 &= mask;
+	g4 &= mask;
+	mask = ~mask;
+	h0 = (h0 & mask) | g0;
+	h1 = (h1 & mask) | g1;
+	h2 = (h2 & mask) | g2;
+	h3 = (h3 & mask) | g3;
+	h4 = (h4 & mask) | g4;
+
+	/* h = h % (2^128) */
+	h0 = (h0 >>  0) | (h1 << 26);
+	h1 = (h1 >>  6) | (h2 << 20);
+	h2 = (h2 >> 12) | (h3 << 14);
+	h3 = (h3 >> 18) | (h4 <<  8);
+
+	/* mac = (h + s) % (2^128) */
+	f = (f >> 32) + h0 + this->s[0]; htoule32(mac +  0, f);
+	f = (f >> 32) + h1 + this->s[1]; htoule32(mac +  4, f);
+	f = (f >> 32) + h2 + this->s[2]; htoule32(mac +  8, f);
+	f = (f >> 32) + h3 + this->s[3]; htoule32(mac + 12, f);
+
+	return TRUE;
+}
+
+METHOD(chapoly_drv_t, destroy, void,
+	private_chapoly_drv_portable_t *this)
+{
+	memwipe(this->m, sizeof(this->m));
+	memwipe(this->h, sizeof(this->h));
+	memwipe(this->r, sizeof(this->r));
+	memwipe(this->s, sizeof(this->s));
+	free(this);
+}
+
+/**
+ * See header
+ */
+chapoly_drv_t *chapoly_drv_portable_create()
+{
+	private_chapoly_drv_portable_t *this;
+
+	INIT(this,
+		.public = {
+			.set_key = _set_key,
+			.init = _init,
+			.poly = _poly,
+			.chacha = _chacha,
+			.encrypt = _encrypt,
+			.decrypt = _decrypt,
+			.finish = _finish,
+			.destroy = _destroy,
+		},
+	);
+
+	return &this->public;
+}
diff --git a/src/libcharon/tests/libcharon_tests.h b/src/libstrongswan/plugins/chapoly/chapoly_drv_portable.h
similarity index 59%
copy from src/libcharon/tests/libcharon_tests.h
copy to src/libstrongswan/plugins/chapoly/chapoly_drv_portable.h
index dc9681a..a320b2d 100644
--- a/src/libcharon/tests/libcharon_tests.h
+++ b/src/libstrongswan/plugins/chapoly/chapoly_drv_portable.h
@@ -1,6 +1,6 @@
 /*
- * Copyright (C) 2014 Martin Willi
- * Copyright (C) 2014 revosec AG
+ * Copyright (C) 2015 Martin Willi
+ * Copyright (C) 2015 revosec AG
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
@@ -13,4 +13,19 @@
  * for more details.
  */
 
-TEST_SUITE(mem_pool_suite_create)
+/**
+ * @defgroup chapoly_drv_portable chapoly_drv_portable
+ * @{ @ingroup chapoly
+ */
+
+#include "chapoly_drv.h"
+
+#ifndef CHAPOLY_DRV_PORTABLE_H_
+#define CHAPOLY_DRV_PORTABLE_H_
+
+/**
+ * Create a chapoly_drv_portable instance.
+ */
+chapoly_drv_t *chapoly_drv_portable_create();
+
+#endif /** CHAPOLY_drv_PORTABLE_H_ @}*/
diff --git a/src/libstrongswan/plugins/chapoly/chapoly_drv_ssse3.c b/src/libstrongswan/plugins/chapoly/chapoly_drv_ssse3.c
new file mode 100644
index 0000000..df88e7d
--- /dev/null
+++ b/src/libstrongswan/plugins/chapoly/chapoly_drv_ssse3.c
@@ -0,0 +1,867 @@
+/*
+ * Copyright (C) 2015 Martin Willi
+ * Copyright (C) 2015 revosec AG
+ *
+ * Based on public domain code by Andrew Moon and Daniel J. Bernstein.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include "chapoly_drv_ssse3.h"
+
+#ifdef __SSSE3__
+
+#include <utils/cpu_feature.h>
+
+#include <tmmintrin.h>
+
+#define CHACHA_DOUBLEROUNDS 10
+
+typedef struct private_chapoly_drv_ssse3_t private_chapoly_drv_ssse3_t;
+
+/**
+ * Private data of an chapoly_drv_ssse3_t object.
+ */
+struct private_chapoly_drv_ssse3_t {
+
+	/**
+	 * Public chapoly_drv_ssse3_t interface.
+	 */
+	chapoly_drv_t public;
+
+	/**
+	 * ChaCha20 state matrix, as 128-bit vectors
+	 */
+	__m128i m[4];
+
+	/**
+	 * Poly1305 update key
+	 */
+	u_int32_t r[5];
+
+	/**
+	 * Poly1305 update key r^2
+	 */
+	u_int32_t u[5];
+
+	/**
+	 * Poly1305 state
+	 */
+	u_int32_t h[5];
+
+	/**
+	 * Poly1305 finalize key
+	 */
+	u_int32_t s[4];
+};
+
+/**
+ * Read a 32-bit integer from an unaligned address
+ */
+static inline u_int32_t ru32(void *p)
+{
+	u_int32_t ret;
+
+	memcpy(&ret, p, sizeof(ret));
+	return ret;
+}
+
+/**
+ * Write a 32-bit word to an unaligned address
+ */
+static inline void wu32(void *p, u_int32_t v)
+{
+	memcpy(p, &v, sizeof(v));
+}
+
+/**
+ * Shift a 64-bit unsigned integer v right by n bits, clamp to 32 bit
+*/
+static inline u_int32_t sr(u_int64_t v, u_char n)
+{
+	return v >> n;
+}
+
+/**
+ * AND two values, using a native integer size >= sizeof(u_int32_t)
+ */
+static inline u_long and(u_long v, u_long mask)
+{
+	return v & mask;
+}
+
+/**
+ * r = shuffle(a ^ b, s)
+ */
+static inline __m128i sfflxor32(__m128i a, __m128i b, __m128i s)
+{
+	return _mm_shuffle_epi8(_mm_xor_si128(a, b), s);
+}
+
+/**
+ * r = rotl32(a ^ b, r)
+ */
+static inline __m128i rotlxor32(__m128i a, __m128i b, u_char r)
+{
+	a = _mm_xor_si128(a, b);
+	return _mm_or_si128(_mm_slli_epi32(a, r), _mm_srli_epi32(a, 32 - r));
+}
+
+/**
+ * XOR a Chacha20 keystream block into data, increment counter
+ */
+static void chacha_block_xor(private_chapoly_drv_ssse3_t *this, void *data)
+{
+	__m128i x0, x1, x2, x3, r8, r16, *out = data;
+	u_int i;
+
+	r8  = _mm_set_epi8(14, 13, 12, 15, 10, 9, 8, 11, 6, 5, 4, 7, 2, 1, 0, 3);
+	r16 = _mm_set_epi8(13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2);
+
+	x0 = this->m[0];
+	x1 = this->m[1];
+	x2 = this->m[2];
+	x3 = this->m[3];
+
+	for (i = 0 ; i < CHACHA_DOUBLEROUNDS; i++)
+	{
+		x0 = _mm_add_epi32(x0, x1);
+		x3 = sfflxor32(x3, x0, r16);
+
+		x2 = _mm_add_epi32(x2, x3);
+		x1 = rotlxor32(x1, x2, 12);
+
+		x0 = _mm_add_epi32(x0, x1);
+		x3 = sfflxor32(x3, x0, r8);
+
+		x2 = _mm_add_epi32(x2, x3);
+		x1 = rotlxor32(x1, x2, 7);
+
+		x1 = _mm_shuffle_epi32(x1, _MM_SHUFFLE(0, 3, 2, 1));
+		x2 = _mm_shuffle_epi32(x2, _MM_SHUFFLE(1, 0, 3, 2));
+		x3 = _mm_shuffle_epi32(x3, _MM_SHUFFLE(2, 1, 0, 3));
+
+		x0 = _mm_add_epi32(x0, x1);
+		x3 = sfflxor32(x3, x0, r16);
+
+		x2 = _mm_add_epi32(x2, x3);
+		x1 = rotlxor32(x1, x2, 12);
+
+		x0 = _mm_add_epi32(x0, x1);
+		x3 = sfflxor32(x3, x0, r8);
+
+		x2 = _mm_add_epi32(x2, x3);
+		x1 = rotlxor32(x1, x2, 7);
+
+		x1 = _mm_shuffle_epi32(x1, _MM_SHUFFLE(2, 1, 0, 3));
+		x2 = _mm_shuffle_epi32(x2, _MM_SHUFFLE(1, 0, 3, 2));
+		x3 = _mm_shuffle_epi32(x3, _MM_SHUFFLE(0, 3, 2, 1));
+	}
+
+	x0 = _mm_add_epi32(x0, this->m[0]);
+	x1 = _mm_add_epi32(x1, this->m[1]);
+	x2 = _mm_add_epi32(x2, this->m[2]);
+	x3 = _mm_add_epi32(x3, this->m[3]);
+	x0 = _mm_xor_si128(x0, _mm_loadu_si128(out + 0));
+	x1 = _mm_xor_si128(x1, _mm_loadu_si128(out + 1));
+	x2 = _mm_xor_si128(x2, _mm_loadu_si128(out + 2));
+	x3 = _mm_xor_si128(x3, _mm_loadu_si128(out + 3));
+	_mm_storeu_si128(out + 0, x0);
+	_mm_storeu_si128(out + 1, x1);
+	_mm_storeu_si128(out + 2, x2);
+	_mm_storeu_si128(out + 3, x3);
+
+	this->m[3] = _mm_add_epi32(this->m[3], _mm_set_epi32(0, 0, 0, 1));
+}
+
+/**
+ * XOR four Chacha20 keystream blocks into data, increment counter
+ */
+static void chacha_4block_xor(private_chapoly_drv_ssse3_t *this, void *data)
+{
+	__m128i x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, xa, xb, xc, xd, xe, xf;
+	__m128i r8, r16, ctrinc, t, *out = data;
+	u_int32_t *m = (u_int32_t*)this->m;
+	u_int i;
+
+	r8  = _mm_set_epi8(14, 13, 12, 15, 10, 9, 8, 11, 6, 5, 4, 7, 2, 1, 0, 3);
+	r16 = _mm_set_epi8(13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2);
+	ctrinc = _mm_set_epi32(3, 2, 1, 0);
+
+	x0 = _mm_set1_epi32(m[ 0]);
+	x1 = _mm_set1_epi32(m[ 1]);
+	x2 = _mm_set1_epi32(m[ 2]);
+	x3 = _mm_set1_epi32(m[ 3]);
+	x4 = _mm_set1_epi32(m[ 4]);
+	x5 = _mm_set1_epi32(m[ 5]);
+	x6 = _mm_set1_epi32(m[ 6]);
+	x7 = _mm_set1_epi32(m[ 7]);
+	x8 = _mm_set1_epi32(m[ 8]);
+	x9 = _mm_set1_epi32(m[ 9]);
+	xa = _mm_set1_epi32(m[10]);
+	xb = _mm_set1_epi32(m[11]);
+	xc = _mm_set1_epi32(m[12]);
+	xd = _mm_set1_epi32(m[13]);
+	xe = _mm_set1_epi32(m[14]);
+	xf = _mm_set1_epi32(m[15]);
+
+	xc = _mm_add_epi32(xc, ctrinc);
+
+	for (i = 0 ; i < CHACHA_DOUBLEROUNDS; i++)
+	{
+		x0 = _mm_add_epi32(x0, x4); xc = sfflxor32(xc, x0, r16);
+		x1 = _mm_add_epi32(x1, x5); xd = sfflxor32(xd, x1, r16);
+		x2 = _mm_add_epi32(x2, x6); xe = sfflxor32(xe, x2, r16);
+		x3 = _mm_add_epi32(x3, x7); xf = sfflxor32(xf, x3, r16);
+
+		x8 = _mm_add_epi32(x8, xc); x4 = rotlxor32(x4, x8, 12);
+		x9 = _mm_add_epi32(x9, xd); x5 = rotlxor32(x5, x9, 12);
+		xa = _mm_add_epi32(xa, xe); x6 = rotlxor32(x6, xa, 12);
+		xb = _mm_add_epi32(xb, xf); x7 = rotlxor32(x7, xb, 12);
+
+		x0 = _mm_add_epi32(x0, x4); xc = sfflxor32(xc, x0, r8);
+		x1 = _mm_add_epi32(x1, x5); xd = sfflxor32(xd, x1, r8);
+		x2 = _mm_add_epi32(x2, x6); xe = sfflxor32(xe, x2, r8);
+		x3 = _mm_add_epi32(x3, x7); xf = sfflxor32(xf, x3, r8);
+
+		x8 = _mm_add_epi32(x8, xc); x4 = rotlxor32(x4, x8, 7);
+		x9 = _mm_add_epi32(x9, xd); x5 = rotlxor32(x5, x9, 7);
+		xa = _mm_add_epi32(xa, xe); x6 = rotlxor32(x6, xa, 7);
+		xb = _mm_add_epi32(xb, xf); x7 = rotlxor32(x7, xb, 7);
+
+		x0 = _mm_add_epi32(x0, x5); xf = sfflxor32(xf, x0, r16);
+		x1 = _mm_add_epi32(x1, x6); xc = sfflxor32(xc, x1, r16);
+		x2 = _mm_add_epi32(x2, x7); xd = sfflxor32(xd, x2, r16);
+		x3 = _mm_add_epi32(x3, x4); xe = sfflxor32(xe, x3, r16);
+
+		xa = _mm_add_epi32(xa, xf); x5 = rotlxor32(x5, xa, 12);
+		xb = _mm_add_epi32(xb, xc); x6 = rotlxor32(x6, xb, 12);
+		x8 = _mm_add_epi32(x8, xd); x7 = rotlxor32(x7, x8, 12);
+		x9 = _mm_add_epi32(x9, xe); x4 = rotlxor32(x4, x9, 12);
+
+		x0 = _mm_add_epi32(x0, x5); xf = sfflxor32(xf, x0, r8);
+		x1 = _mm_add_epi32(x1, x6); xc = sfflxor32(xc, x1, r8);
+		x2 = _mm_add_epi32(x2, x7); xd = sfflxor32(xd, x2, r8);
+		x3 = _mm_add_epi32(x3, x4); xe = sfflxor32(xe, x3, r8);
+
+		xa = _mm_add_epi32(xa, xf); x5 = rotlxor32(x5, xa, 7);
+		xb = _mm_add_epi32(xb, xc); x6 = rotlxor32(x6, xb, 7);
+		x8 = _mm_add_epi32(x8, xd); x7 = rotlxor32(x7, x8, 7);
+		x9 = _mm_add_epi32(x9, xe); x4 = rotlxor32(x4, x9, 7);
+	}
+
+	x0 = _mm_add_epi32(x0, _mm_set1_epi32(m[ 0]));
+	x1 = _mm_add_epi32(x1, _mm_set1_epi32(m[ 1]));
+	x2 = _mm_add_epi32(x2, _mm_set1_epi32(m[ 2]));
+	x3 = _mm_add_epi32(x3, _mm_set1_epi32(m[ 3]));
+	x4 = _mm_add_epi32(x4, _mm_set1_epi32(m[ 4]));
+	x5 = _mm_add_epi32(x5, _mm_set1_epi32(m[ 5]));
+	x6 = _mm_add_epi32(x6, _mm_set1_epi32(m[ 6]));
+	x7 = _mm_add_epi32(x7, _mm_set1_epi32(m[ 7]));
+	x8 = _mm_add_epi32(x8, _mm_set1_epi32(m[ 8]));
+	x9 = _mm_add_epi32(x9, _mm_set1_epi32(m[ 9]));
+	xa = _mm_add_epi32(xa, _mm_set1_epi32(m[10]));
+	xb = _mm_add_epi32(xb, _mm_set1_epi32(m[11]));
+	xc = _mm_add_epi32(xc, _mm_set1_epi32(m[12]));
+	xd = _mm_add_epi32(xd, _mm_set1_epi32(m[13]));
+	xe = _mm_add_epi32(xe, _mm_set1_epi32(m[14]));
+	xf = _mm_add_epi32(xf, _mm_set1_epi32(m[15]));
+
+	xc = _mm_add_epi32(xc, ctrinc);
+
+	/* transpose state matrix by interleaving 32-, then 64-bit words */
+	t = x0;	x0 = _mm_unpacklo_epi32(t, x1);
+			x1 = _mm_unpackhi_epi32(t, x1);
+	t = x2;	x2 = _mm_unpacklo_epi32(t, x3);
+			x3 = _mm_unpackhi_epi32(t, x3);
+	t = x4;	x4 = _mm_unpacklo_epi32(t, x5);
+			x5 = _mm_unpackhi_epi32(t, x5);
+	t = x6;	x6 = _mm_unpacklo_epi32(t, x7);
+			x7 = _mm_unpackhi_epi32(t, x7);
+	t = x8;	x8 = _mm_unpacklo_epi32(t, x9);
+			x9 = _mm_unpackhi_epi32(t, x9);
+	t = xa;	xa = _mm_unpacklo_epi32(t, xb);
+			xb = _mm_unpackhi_epi32(t, xb);
+	t = xc;	xc = _mm_unpacklo_epi32(t, xd);
+			xd = _mm_unpackhi_epi32(t, xd);
+	t = xe;	xe = _mm_unpacklo_epi32(t, xf);
+			xf = _mm_unpackhi_epi32(t, xf);
+
+	t = x0;	x0 = _mm_unpacklo_epi64(t, x2);
+			x2 = _mm_unpackhi_epi64(t, x2);
+	t = x1;	x1 = _mm_unpacklo_epi64(t, x3);
+			x3 = _mm_unpackhi_epi64(t, x3);
+	t = x4;	x4 = _mm_unpacklo_epi64(t, x6);
+			x6 = _mm_unpackhi_epi64(t, x6);
+	t = x5;	x5 = _mm_unpacklo_epi64(t, x7);
+			x7 = _mm_unpackhi_epi64(t, x7);
+	t = x8;	x8 = _mm_unpacklo_epi64(t, xa);
+			xa = _mm_unpackhi_epi64(t, xa);
+	t = x9;	x9 = _mm_unpacklo_epi64(t, xb);
+			xb = _mm_unpackhi_epi64(t, xb);
+	t = xc;	xc = _mm_unpacklo_epi64(t, xe);
+			xe = _mm_unpackhi_epi64(t, xe);
+	t = xd;	xd = _mm_unpacklo_epi64(t, xf);
+			xf = _mm_unpackhi_epi64(t, xf);
+
+	x0 = _mm_xor_si128(_mm_loadu_si128(out +  0), x0);
+	x1 = _mm_xor_si128(_mm_loadu_si128(out +  8), x1);
+	x2 = _mm_xor_si128(_mm_loadu_si128(out +  4), x2);
+	x3 = _mm_xor_si128(_mm_loadu_si128(out + 12), x3);
+	x4 = _mm_xor_si128(_mm_loadu_si128(out +  1), x4);
+	x5 = _mm_xor_si128(_mm_loadu_si128(out +  9), x5);
+	x6 = _mm_xor_si128(_mm_loadu_si128(out +  5), x6);
+	x7 = _mm_xor_si128(_mm_loadu_si128(out + 13), x7);
+	x8 = _mm_xor_si128(_mm_loadu_si128(out +  2), x8);
+	x9 = _mm_xor_si128(_mm_loadu_si128(out + 10), x9);
+	xa = _mm_xor_si128(_mm_loadu_si128(out +  6), xa);
+	xb = _mm_xor_si128(_mm_loadu_si128(out + 14), xb);
+	xc = _mm_xor_si128(_mm_loadu_si128(out +  3), xc);
+	xd = _mm_xor_si128(_mm_loadu_si128(out + 11), xd);
+	xe = _mm_xor_si128(_mm_loadu_si128(out +  7), xe);
+	xf = _mm_xor_si128(_mm_loadu_si128(out + 15), xf);
+
+	_mm_storeu_si128(out +  0, x0);
+	_mm_storeu_si128(out +  8, x1);
+	_mm_storeu_si128(out +  4, x2);
+	_mm_storeu_si128(out + 12, x3);
+	_mm_storeu_si128(out +  1, x4);
+	_mm_storeu_si128(out +  9, x5);
+	_mm_storeu_si128(out +  5, x6);
+	_mm_storeu_si128(out + 13, x7);
+	_mm_storeu_si128(out +  2, x8);
+	_mm_storeu_si128(out + 10, x9);
+	_mm_storeu_si128(out +  6, xa);
+	_mm_storeu_si128(out + 14, xb);
+	_mm_storeu_si128(out +  3, xc);
+	_mm_storeu_si128(out + 11, xd);
+	_mm_storeu_si128(out +  7, xe);
+	_mm_storeu_si128(out + 15, xf);
+
+	this->m[3] = _mm_add_epi32(this->m[3], _mm_set_epi32(0, 0, 0, 4));
+}
+
+METHOD(chapoly_drv_t, set_key, bool,
+	private_chapoly_drv_ssse3_t *this, u_char *constant, u_char *key,
+	u_char *salt)
+{
+	this->m[0] = _mm_loadu_si128((__m128i*)constant);
+	this->m[1] = _mm_loadu_si128((__m128i*)key + 0);
+	this->m[2] = _mm_loadu_si128((__m128i*)key + 1);
+	this->m[3] = _mm_set_epi32(0, 0, ru32(salt), 0);
+
+	return TRUE;
+}
+
+/**
+ * r[127:64] = h[95:64] * a, r[63:0] = h[31:0] * b
+ */
+static inline __m128i mul2(__m128i h, u_int32_t a, u_int32_t b)
+{
+	return _mm_mul_epu32(h, _mm_set_epi32(0, a, 0, b));
+}
+
+/**
+ * c = a[127:64] + a[63:0] + b[127:64] + b[63:0]
+ * z = x[127:64] + x[63:0] + y[127:64] + y[63:0]
+ */
+static inline void sum2(__m128i a, __m128i b, __m128i x, __m128i y,
+						u_int64_t *c, u_int64_t *z)
+{
+	__m128i r, s;
+
+	a = _mm_add_epi64(a, b);
+	x = _mm_add_epi64(x, y);
+	r = _mm_unpacklo_epi64(x, a);
+	s = _mm_unpackhi_epi64(x, a);
+	r = _mm_add_epi64(r, s);
+
+	_mm_storel_epi64((__m128i*)z, r);
+	_mm_storel_epi64((__m128i*)c, _mm_srli_si128(r, 8));
+}
+
+/**
+ * r = a[127:64] + b[127:64] + c[127:64] + d[127:64] + e[127:64]
+ *   + a[63:0]   + b[63:0]   + c[63:0]   + d[63:0]   + e[63:0]
+ */
+static inline u_int64_t sum5(__m128i a, __m128i b, __m128i c,
+							 __m128i d, __m128i e)
+{
+	u_int64_t r;
+
+	a = _mm_add_epi64(a, b);
+	c = _mm_add_epi64(c, d);
+	a = _mm_add_epi64(a, e);
+	a = _mm_add_epi64(a, c);
+
+	a = _mm_add_epi64(a, _mm_srli_si128(a, 8));
+	_mm_storel_epi64((__m128i*)&r, a);
+
+	return r;
+}
+
+/**
+ * Make second Poly1305 key u = r^2
+ */
+static void make_u(private_chapoly_drv_ssse3_t *this)
+{
+	__m128i r01, r23, r44, x0, x1, y0, y1, z0;
+	u_int32_t r0, r1, r2, r3, r4;
+	u_int32_t u0, u1, u2, u3, u4;
+	u_int32_t s1, s2, s3, s4;
+	u_int64_t d0, d1, d2, d3, d4;
+
+	r0 = this->r[0];
+	r1 = this->r[1];
+	r2 = this->r[2];
+	r3 = this->r[3];
+	r4 = this->r[4];
+
+	s1 = r1 * 5;
+	s2 = r2 * 5;
+	s3 = r3 * 5;
+	s4 = r4 * 5;
+
+	r01 = _mm_set_epi32(0, r0, 0, r1);
+	r23 = _mm_set_epi32(0, r2, 0, r3);
+	r44 = _mm_set_epi32(0, r4, 0, r4);
+
+	/* u = r^2 */
+	x0 = mul2(r01, r0, s4);
+	x1 = mul2(r01, r1, r0);
+	y0 = mul2(r23, s3, s2);
+	y1 = mul2(r23, s4, s3);
+	z0 = mul2(r44, s1, s2);
+	y0 = _mm_add_epi64(y0, _mm_srli_si128(z0, 8));
+	y1 = _mm_add_epi64(y1, _mm_slli_si128(z0, 8));
+	sum2(x0, y0, x1, y1, &d0, &d1);
+
+	x0 = mul2(r01, r2, r1);
+	x1 = mul2(r01, r3, r2);
+	y0 = mul2(r23, r0, s4);
+	y1 = mul2(r23, r1, r0);
+	z0 = mul2(r44, s3, s4);
+	y0 = _mm_add_epi64(y0, _mm_srli_si128(z0, 8));
+	y1 = _mm_add_epi64(y1, _mm_slli_si128(z0, 8));
+	sum2(x0, y0, x1, y1, &d2, &d3);
+
+	x0 = mul2(r01, r4, r3);
+	y0 = mul2(r23, r2, r1);
+	z0 = mul2(r44, r0, 0);
+	y0 = _mm_add_epi64(y0, z0);
+	x0 = _mm_add_epi64(x0, y0);
+	x0 = _mm_add_epi64(x0, _mm_srli_si128(x0, 8));
+	_mm_storel_epi64((__m128i*)&d4, x0);
+
+	/* (partial) r %= p */
+	d1 += sr(d0, 26);     u0 = and(d0, 0x3ffffff);
+	d2 += sr(d1, 26);     u1 = and(d1, 0x3ffffff);
+	d3 += sr(d2, 26);     u2 = and(d2, 0x3ffffff);
+	d4 += sr(d3, 26);     u3 = and(d3, 0x3ffffff);
+	u0 += sr(d4, 26) * 5; u4 = and(d4, 0x3ffffff);
+	u1 += u0 >> 26;       u0 &= 0x3ffffff;
+
+	this->u[0] = u0;
+	this->u[1] = u1;
+	this->u[2] = u2;
+	this->u[3] = u3;
+	this->u[4] = u4;
+}
+
+METHOD(chapoly_drv_t, init, bool,
+	private_chapoly_drv_ssse3_t *this, u_char *iv)
+{
+	u_char key[CHACHA_BLOCK_SIZE];
+
+	this->m[3] = _mm_or_si128(
+					_mm_set_epi32(ru32(iv + 4), ru32(iv + 0), 0, 0),
+					_mm_and_si128(this->m[3], _mm_set_epi32(0, 0, ~0, 0)));
+
+	memset(key, 0, CHACHA_BLOCK_SIZE);
+	chacha_block_xor(this, key);
+
+	/* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
+	this->r[0] = (ru32(key +  0) >> 0) & 0x3ffffff;
+	this->r[1] = (ru32(key +  3) >> 2) & 0x3ffff03;
+	this->r[2] = (ru32(key +  6) >> 4) & 0x3ffc0ff;
+	this->r[3] = (ru32(key +  9) >> 6) & 0x3f03fff;
+	this->r[4] = (ru32(key + 12) >> 8) & 0x00fffff;
+
+	make_u(this);
+
+	/* h = 0 */
+	memwipe(this->h, sizeof(this->h));
+
+	this->s[0] = ru32(key + 16);
+	this->s[1] = ru32(key + 20);
+	this->s[2] = ru32(key + 24);
+	this->s[3] = ru32(key + 28);
+
+	return TRUE;
+}
+
+/**
+ * Update Poly1305 for a multiple of two blocks
+ */
+static void poly2(private_chapoly_drv_ssse3_t *this, u_char *data, u_int dblks)
+{
+	u_int32_t r0, r1, r2, r3, r4, u0, u1, u2, u3, u4;
+	u_int32_t s1, s2, s3, s4, v1, v2, v3, v4;
+	__m128i hc0, hc1, hc2, hc3, hc4;
+	u_int32_t h0, h1, h2, h3, h4;
+	u_int32_t c0, c1, c2, c3, c4;
+	u_int64_t d0, d1, d2, d3, d4;
+	u_int i;
+
+	r0 = this->r[0];
+	r1 = this->r[1];
+	r2 = this->r[2];
+	r3 = this->r[3];
+	r4 = this->r[4];
+
+	s1 = r1 * 5;
+	s2 = r2 * 5;
+	s3 = r3 * 5;
+	s4 = r4 * 5;
+
+	u0 = this->u[0];
+	u1 = this->u[1];
+	u2 = this->u[2];
+	u3 = this->u[3];
+	u4 = this->u[4];
+
+	v1 = u1 * 5;
+	v2 = u2 * 5;
+	v3 = u3 * 5;
+	v4 = u4 * 5;
+
+	h0 = this->h[0];
+	h1 = this->h[1];
+	h2 = this->h[2];
+	h3 = this->h[3];
+	h4 = this->h[4];
+
+	/* h = (h + c1) * r^2 + c2 * r */
+	for (i = 0; i < dblks; i++)
+	{
+		/* h += m[i] */
+		h0 += (ru32(data +  0) >> 0) & 0x3ffffff;
+		h1 += (ru32(data +  3) >> 2) & 0x3ffffff;
+		h2 += (ru32(data +  6) >> 4) & 0x3ffffff;
+		h3 += (ru32(data +  9) >> 6) & 0x3ffffff;
+		h4 += (ru32(data + 12) >> 8) | (1 << 24);
+		data += POLY_BLOCK_SIZE;
+
+		/* c = m[i + 1] */
+		c0 = (ru32(data +  0) >> 0) & 0x3ffffff;
+		c1 = (ru32(data +  3) >> 2) & 0x3ffffff;
+		c2 = (ru32(data +  6) >> 4) & 0x3ffffff;
+		c3 = (ru32(data +  9) >> 6) & 0x3ffffff;
+		c4 = (ru32(data + 12) >> 8) | (1 << 24);
+		data += POLY_BLOCK_SIZE;
+
+		hc0 = _mm_set_epi32(0, h0, 0, c0);
+		hc1 = _mm_set_epi32(0, h1, 0, c1);
+		hc2 = _mm_set_epi32(0, h2, 0, c2);
+		hc3 = _mm_set_epi32(0, h3, 0, c3);
+		hc4 = _mm_set_epi32(0, h4, 0, c4);
+
+		/* h = h * r^2 + c * r */
+		d0 = sum5(mul2(hc0, u0, r0),
+				  mul2(hc1, v4, s4),
+				  mul2(hc2, v3, s3),
+				  mul2(hc3, v2, s2),
+				  mul2(hc4, v1, s1));
+		d1 = sum5(mul2(hc0, u1, r1),
+				  mul2(hc1, u0, r0),
+				  mul2(hc2, v4, s4),
+				  mul2(hc3, v3, s3),
+				  mul2(hc4, v2, s2));
+		d2 = sum5(mul2(hc0, u2, r2),
+				  mul2(hc1, u1, r1),
+				  mul2(hc2, u0, r0),
+				  mul2(hc3, v4, s4),
+				  mul2(hc4, v3, s3));
+		d3 = sum5(mul2(hc0, u3, r3),
+				  mul2(hc1, u2, r2),
+				  mul2(hc2, u1, r1),
+				  mul2(hc3, u0, r0),
+				  mul2(hc4, v4, s4));
+		d4 = sum5(mul2(hc0, u4, r4),
+				  mul2(hc1, u3, r3),
+				  mul2(hc2, u2, r2),
+				  mul2(hc3, u1, r1),
+				  mul2(hc4, u0, r0));
+
+		/* (partial) h %= p */
+		d1 += sr(d0, 26);     h0 = and(d0, 0x3ffffff);
+		d2 += sr(d1, 26);     h1 = and(d1, 0x3ffffff);
+		d3 += sr(d2, 26);     h2 = and(d2, 0x3ffffff);
+		d4 += sr(d3, 26);     h3 = and(d3, 0x3ffffff);
+		h0 += sr(d4, 26) * 5; h4 = and(d4, 0x3ffffff);
+		h1 += h0 >> 26;       h0 = h0 & 0x3ffffff;
+	}
+
+	this->h[0] = h0;
+	this->h[1] = h1;
+	this->h[2] = h2;
+	this->h[3] = h3;
+	this->h[4] = h4;
+}
+
+/**
+ * Update Poly1305 for a single block
+ */
+static void poly1(private_chapoly_drv_ssse3_t *this, u_char *data)
+{
+	u_int32_t r0, r1, r2, r3, r4;
+	u_int32_t s1, s2, s3, s4;
+	u_int32_t h0, h1, h2, h3, h4;
+	u_int64_t d0, d1, d2, d3, d4;
+	__m128i h01, h23, h44;
+	__m128i x0, x1, y0, y1, z0;
+	u_int32_t t0, t1;
+
+	r0 = this->r[0];
+	r1 = this->r[1];
+	r2 = this->r[2];
+	r3 = this->r[3];
+	r4 = this->r[4];
+
+	s1 = r1 * 5;
+	s2 = r2 * 5;
+	s3 = r3 * 5;
+	s4 = r4 * 5;
+
+	h0 = this->h[0];
+	h1 = this->h[1];
+	h2 = this->h[2];
+	h3 = this->h[3];
+	h4 = this->h[4];
+
+	h01 = _mm_set_epi32(0, h0, 0, h1);
+	h23 = _mm_set_epi32(0, h2, 0, h3);
+	h44 = _mm_set_epi32(0, h4, 0, h4);
+
+	/* h += m[i] */
+	t0  = (ru32(data +  0) >> 0) & 0x3ffffff;
+	t1  = (ru32(data +  3) >> 2) & 0x3ffffff;
+	h01 = _mm_add_epi32(h01, _mm_set_epi32(0, t0, 0, t1));
+	t0  = (ru32(data +  6) >> 4) & 0x3ffffff;
+	t1  = (ru32(data +  9) >> 6) & 0x3ffffff;
+	h23 = _mm_add_epi32(h23, _mm_set_epi32(0, t0, 0, t1));
+	t0  = (ru32(data + 12) >> 8) | (1 << 24);
+	h44 = _mm_add_epi32(h44, _mm_set_epi32(0, t0, 0, t0));
+
+	/* h *= r */
+	x0 = mul2(h01, r0, s4);
+	x1 = mul2(h01, r1, r0);
+	y0 = mul2(h23, s3, s2);
+	y1 = mul2(h23, s4, s3);
+	z0 = mul2(h44, s1, s2);
+	y0 = _mm_add_epi64(y0, _mm_srli_si128(z0, 8));
+	y1 = _mm_add_epi64(y1, _mm_slli_si128(z0, 8));
+	sum2(x0, y0, x1, y1, &d0, &d1);
+
+	x0 = mul2(h01, r2, r1);
+	x1 = mul2(h01, r3, r2);
+	y0 = mul2(h23, r0, s4);
+	y1 = mul2(h23, r1, r0);
+	z0 = mul2(h44, s3, s4);
+	y0 = _mm_add_epi64(y0, _mm_srli_si128(z0, 8));
+	y1 = _mm_add_epi64(y1, _mm_slli_si128(z0, 8));
+	sum2(x0, y0, x1, y1, &d2, &d3);
+
+	x0 = mul2(h01, r4, r3);
+	y0 = mul2(h23, r2, r1);
+	z0 = mul2(h44, r0, 0);
+	y0 = _mm_add_epi64(y0, z0);
+	x0 = _mm_add_epi64(x0, y0);
+	x0 = _mm_add_epi64(x0, _mm_srli_si128(x0, 8));
+	_mm_storel_epi64((__m128i*)&d4, x0);
+
+	/* (partial) h %= p */
+	d1 += sr(d0, 26);     h0 = and(d0, 0x3ffffff);
+	d2 += sr(d1, 26);     h1 = and(d1, 0x3ffffff);
+	d3 += sr(d2, 26);     h2 = and(d2, 0x3ffffff);
+	d4 += sr(d3, 26);     h3 = and(d3, 0x3ffffff);
+	h0 += sr(d4, 26) * 5; h4 = and(d4, 0x3ffffff);
+	h1 += h0 >> 26;       h0 = h0 & 0x3ffffff;
+
+	this->h[0] = h0;
+	this->h[1] = h1;
+	this->h[2] = h2;
+	this->h[3] = h3;
+	this->h[4] = h4;
+}
+
+METHOD(chapoly_drv_t, poly, bool,
+	private_chapoly_drv_ssse3_t *this, u_char *data, u_int blocks)
+{
+	poly2(this, data, blocks / 2);
+	if (blocks-- % 2)
+	{
+		poly1(this, data + POLY_BLOCK_SIZE * blocks);
+	}
+	return TRUE;
+}
+
+METHOD(chapoly_drv_t, chacha, bool,
+	private_chapoly_drv_ssse3_t *this, u_char *stream)
+{
+	memset(stream, 0, CHACHA_BLOCK_SIZE);
+	chacha_block_xor(this, stream);
+
+	return TRUE;
+}
+
+METHOD(chapoly_drv_t, encrypt, bool,
+	private_chapoly_drv_ssse3_t *this, u_char *data, u_int blocks)
+{
+	while (blocks >= 4)
+	{
+		chacha_4block_xor(this, data);
+		poly2(this, data, 8);
+		data += CHACHA_BLOCK_SIZE * 4;
+		blocks -= 4;
+	}
+	while (blocks--)
+	{
+		chacha_block_xor(this, data);
+		poly2(this, data, 2);
+		data += CHACHA_BLOCK_SIZE;
+	}
+	return TRUE;
+}
+
+METHOD(chapoly_drv_t, decrypt, bool,
+	private_chapoly_drv_ssse3_t *this, u_char *data, u_int blocks)
+{
+	while (blocks >= 4)
+	{
+		poly2(this, data, 8);
+		chacha_4block_xor(this, data);
+		data += CHACHA_BLOCK_SIZE * 4;
+		blocks -= 4;
+	}
+	while (blocks--)
+	{
+		poly2(this, data, 2);
+		chacha_block_xor(this, data);
+		data += CHACHA_BLOCK_SIZE;
+	}
+	return TRUE;
+}
+
+METHOD(chapoly_drv_t, finish, bool,
+	private_chapoly_drv_ssse3_t *this, u_char *mac)
+{
+	u_int32_t h0, h1, h2, h3, h4;
+	u_int32_t g0, g1, g2, g3, g4;
+	u_int32_t mask;
+	u_int64_t f = 0;
+
+	/* fully carry h */
+	h0 = this->h[0];
+	h1 = this->h[1];
+	h2 = this->h[2];
+	h3 = this->h[3];
+	h4 = this->h[4];
+
+	h2 += (h1 >> 26);     h1 = h1 & 0x3ffffff;
+	h3 += (h2 >> 26);     h2 = h2 & 0x3ffffff;
+	h4 += (h3 >> 26);     h3 = h3 & 0x3ffffff;
+	h0 += (h4 >> 26) * 5; h4 = h4 & 0x3ffffff;
+	h1 += (h0 >> 26);     h0 = h0 & 0x3ffffff;
+
+	/* compute h + -p */
+	g0 = h0 + 5;
+	g1 = h1 + (g0 >> 26);             g0 &= 0x3ffffff;
+	g2 = h2 + (g1 >> 26);             g1 &= 0x3ffffff;
+	g3 = h3 + (g2 >> 26);             g2 &= 0x3ffffff;
+	g4 = h4 + (g3 >> 26) - (1 << 26); g3 &= 0x3ffffff;
+
+	/* select h if h < p, or h + -p if h >= p */
+	mask = (g4 >> ((sizeof(u_int32_t) * 8) - 1)) - 1;
+	g0 &= mask;
+	g1 &= mask;
+	g2 &= mask;
+	g3 &= mask;
+	g4 &= mask;
+	mask = ~mask;
+	h0 = (h0 & mask) | g0;
+	h1 = (h1 & mask) | g1;
+	h2 = (h2 & mask) | g2;
+	h3 = (h3 & mask) | g3;
+	h4 = (h4 & mask) | g4;
+
+	/* h = h % (2^128) */
+	h0 = (h0 >>  0) | (h1 << 26);
+	h1 = (h1 >>  6) | (h2 << 20);
+	h2 = (h2 >> 12) | (h3 << 14);
+	h3 = (h3 >> 18) | (h4 <<  8);
+
+	/* mac = (h + s) % (2^128) */
+	f = (f >> 32) + h0 + this->s[0]; wu32(mac +  0, f);
+	f = (f >> 32) + h1 + this->s[1]; wu32(mac +  4, f);
+	f = (f >> 32) + h2 + this->s[2]; wu32(mac +  8, f);
+	f = (f >> 32) + h3 + this->s[3]; wu32(mac + 12, f);
+
+	return TRUE;
+}
+
+METHOD(chapoly_drv_t, destroy, void,
+	private_chapoly_drv_ssse3_t *this)
+{
+	memwipe(this->m, sizeof(this->m));
+	memwipe(this->h, sizeof(this->h));
+	memwipe(this->r, sizeof(this->r));
+	memwipe(this->u, sizeof(this->u));
+	memwipe(this->s, sizeof(this->s));
+	free_align(this);
+}
+
+/**
+ * See header
+ */
+chapoly_drv_t *chapoly_drv_ssse3_create()
+{
+	private_chapoly_drv_ssse3_t *this;
+
+	if (!cpu_feature_available(CPU_FEATURE_SSSE3))
+	{
+		return FALSE;
+	}
+
+	INIT_ALIGN(this, sizeof(__m128i),
+		.public = {
+			.set_key = _set_key,
+			.init = _init,
+			.poly = _poly,
+			.chacha = _chacha,
+			.encrypt = _encrypt,
+			.decrypt = _decrypt,
+			.finish = _finish,
+			.destroy = _destroy,
+		},
+	);
+
+	return &this->public;
+}
+
+#else /* !__SSSE3__ */
+
+chapoly_drv_t *chapoly_drv_ssse3_create()
+{
+	return NULL;
+}
+
+#endif /* !__SSSE3__ */
diff --git a/src/libcharon/tests/libcharon_tests.h b/src/libstrongswan/plugins/chapoly/chapoly_drv_ssse3.h
similarity index 60%
copy from src/libcharon/tests/libcharon_tests.h
copy to src/libstrongswan/plugins/chapoly/chapoly_drv_ssse3.h
index dc9681a..7e0e808 100644
--- a/src/libcharon/tests/libcharon_tests.h
+++ b/src/libstrongswan/plugins/chapoly/chapoly_drv_ssse3.h
@@ -1,6 +1,6 @@
 /*
- * Copyright (C) 2014 Martin Willi
- * Copyright (C) 2014 revosec AG
+ * Copyright (C) 2015 Martin Willi
+ * Copyright (C) 2015 revosec AG
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
@@ -13,4 +13,19 @@
  * for more details.
  */
 
-TEST_SUITE(mem_pool_suite_create)
+/**
+ * @defgroup chapoly_drv_ssse3 chapoly_drv_ssse3
+ * @{ @ingroup chapoly
+ */
+
+#include "chapoly_drv.h"
+
+#ifndef CHAPOLY_DRV_SSSE3_H_
+#define CHAPOLY_DRV_SSSE3_H_
+
+/**
+ * Create a chapoly_drv_ssse3 instance.
+ */
+chapoly_drv_t *chapoly_drv_ssse3_create();
+
+#endif /** CHAPOLY_DRV_SSSE3_H_ @}*/
diff --git a/src/libstrongswan/plugins/chapoly/chapoly_plugin.c b/src/libstrongswan/plugins/chapoly/chapoly_plugin.c
new file mode 100644
index 0000000..02e7121
--- /dev/null
+++ b/src/libstrongswan/plugins/chapoly/chapoly_plugin.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2015 Martin Willi
+ * Copyright (C) 2015 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include "chapoly_plugin.h"
+#include "chapoly_aead.h"
+
+#include <library.h>
+
+typedef struct private_chapoly_plugin_t private_chapoly_plugin_t;
+
+/**
+ * Private data of chapoly_plugin
+ */
+struct private_chapoly_plugin_t {
+
+	/**
+	 * Public functions
+	 */
+	chapoly_plugin_t public;
+};
+
+METHOD(plugin_t, get_name, char*,
+	private_chapoly_plugin_t *this)
+{
+	return "chapoly";
+}
+
+METHOD(plugin_t, get_features, int,
+	private_chapoly_plugin_t *this, plugin_feature_t *features[])
+{
+	static plugin_feature_t f[] = {
+		PLUGIN_REGISTER(AEAD, chapoly_aead_create),
+			PLUGIN_PROVIDE(AEAD, ENCR_CHACHA20_POLY1305, 32),
+	};
+	*features = f;
+	return countof(f);
+}
+
+METHOD(plugin_t, destroy, void,
+	private_chapoly_plugin_t *this)
+{
+	free(this);
+}
+
+/*
+ * see header file
+ */
+plugin_t *chapoly_plugin_create()
+{
+	private_chapoly_plugin_t *this;
+
+	INIT(this,
+		.public = {
+			.plugin = {
+				.get_name = _get_name,
+				.get_features = _get_features,
+				.destroy = _destroy,
+			},
+		},
+	);
+
+	return &this->public.plugin;
+}
diff --git a/src/libstrongswan/credentials/certificates/ocsp_request.h b/src/libstrongswan/plugins/chapoly/chapoly_plugin.h
similarity index 55%
copy from src/libstrongswan/credentials/certificates/ocsp_request.h
copy to src/libstrongswan/plugins/chapoly/chapoly_plugin.h
index 0b18713..f2b62e7 100644
--- a/src/libstrongswan/credentials/certificates/ocsp_request.h
+++ b/src/libstrongswan/plugins/chapoly/chapoly_plugin.h
@@ -1,6 +1,6 @@
 /*
- * Copyright (C) 2008 Martin Willi
- * Hochschule fuer Technik Rapperswil
+ * Copyright (C) 2015 Martin Willi
+ * Copyright (C) 2015 revosec AG
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
@@ -14,26 +14,29 @@
  */
 
 /**
- * @defgroup ocsp_request ocsp_request
- * @{ @ingroup certificates
+ * @defgroup chapoly chapoly
+ * @ingroup plugins
+ *
+ * @defgroup chapoly_plugin chapoly_plugin
+ * @{ @ingroup chapoly
  */
 
-#ifndef OCSP_REQUEST_H_
-#define OCSP_REQUEST_H_
+#ifndef CHAPOLY_PLUGIN_H_
+#define CHAPOLY_PLUGIN_H_
 
-#include <credentials/certificates/certificate.h>
+#include <plugins/plugin.h>
 
-typedef struct ocsp_request_t ocsp_request_t;
+typedef struct chapoly_plugin_t chapoly_plugin_t;
 
 /**
- * OCSP request message.
+ * Plugin providing a ChaCha20/Poly1305 AEAD.
  */
-struct ocsp_request_t {
+struct chapoly_plugin_t {
 
 	/**
-	 * Implements certificiate_t interface
+	 * Implements plugin interface.
 	 */
-	certificate_t interface;
+	plugin_t plugin;
 };
 
-#endif /** OCSP_REQUEST_H_ @}*/
+#endif /** CHAPOLY_PLUGIN_H_ @}*/
diff --git a/src/libstrongswan/plugins/des/des_crypter.c b/src/libstrongswan/plugins/des/des_crypter.c
index c81318b..6010f9d 100644
--- a/src/libstrongswan/plugins/des/des_crypter.c
+++ b/src/libstrongswan/plugins/des/des_crypter.c
@@ -112,7 +112,7 @@ struct private_des_crypter_t {
 #endif
 
 /* This helps C compiler generate the correct code for multiple functional
- * units.  It reduces register dependancies at the expense of 2 more
+ * units.  It reduces register dependencies at the expense of 2 more
  * registers */
 #ifndef DES_RISC1
 #define DES_RISC1
diff --git a/src/libstrongswan/plugins/padlock/padlock_sha1_hasher.h b/src/libstrongswan/plugins/padlock/padlock_sha1_hasher.h
index 2d2b2b4..bb45d7b 100644
--- a/src/libstrongswan/plugins/padlock/padlock_sha1_hasher.h
+++ b/src/libstrongswan/plugins/padlock/padlock_sha1_hasher.h
@@ -15,7 +15,7 @@
  */
 
 /**
- * @defgroup sha1_hasher sha1_hasher
+ * @defgroup padlock_sha1_hasher padlock_sha1_hasher
  * @{ @ingroup padlock_p
  */
 
diff --git a/src/libstrongswan/plugins/pkcs11/pkcs11_public_key.c b/src/libstrongswan/plugins/pkcs11/pkcs11_public_key.c
index 6d52116..3847776 100644
--- a/src/libstrongswan/plugins/pkcs11/pkcs11_public_key.c
+++ b/src/libstrongswan/plugins/pkcs11/pkcs11_public_key.c
@@ -439,12 +439,17 @@ static bool encode_rsa(private_pkcs11_public_key_t *this,
 		attr[0].ulValueLen > 0 && attr[1].ulValueLen > 0)
 	{
 		chunk_t n, e;
-		n = chunk_create(attr[0].pValue, attr[0].ulValueLen);
+		/* some tokens/libraries add unnecessary 0x00 prefixes */
+		n = chunk_skip_zero(chunk_create(attr[0].pValue, attr[0].ulValueLen));
 		if (n.ptr[0] & 0x80)
-		{	/* add leading 0x00, encoders expect it already like this */
+		{	/* add leading 0x00, encoders might expect it in two's complement */
 			n = chunk_cata("cc", chunk_from_chars(0x00), n);
 		}
-		e = chunk_create(attr[1].pValue, attr[1].ulValueLen);
+		e = chunk_skip_zero(chunk_create(attr[1].pValue, attr[1].ulValueLen));
+		if (e.ptr[0] & 0x80)
+		{
+			e = chunk_cata("cc", chunk_from_chars(0x00), e);
+		}
 		success = lib->encoding->encode(lib->encoding, type, cache, encoding,
 			CRED_PART_RSA_MODULUS, n, CRED_PART_RSA_PUB_EXP, e, CRED_PART_END);
 	}
diff --git a/src/libstrongswan/plugins/plugin_feature.c b/src/libstrongswan/plugins/plugin_feature.c
index 2d0ce8a..0ea5eea 100644
--- a/src/libstrongswan/plugins/plugin_feature.c
+++ b/src/libstrongswan/plugins/plugin_feature.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012-2013 Tobias Brunner
+ * Copyright (C) 2012-2015 Tobias Brunner
  * Hochschule fuer Technik Rapperswil
  *
  * Copyright (C) 2011 Martin Willi
@@ -59,7 +59,7 @@ ENUM(plugin_feature_names, FEATURE_NONE, FEATURE_CUSTOM,
  */
 u_int32_t plugin_feature_hash(plugin_feature_t *feature)
 {
-	chunk_t data;
+	chunk_t data = chunk_empty;
 
 	switch (feature->type)
 	{
@@ -185,7 +185,8 @@ bool plugin_feature_matches(plugin_feature_t *a, plugin_feature_t *b)
 				return a->arg.container == b->arg.container;
 			case FEATURE_EAP_SERVER:
 			case FEATURE_EAP_PEER:
-				return a->arg.eap == b->arg.eap;
+				return a->arg.eap.vendor == b->arg.eap.vendor &&
+					   a->arg.eap.type == b->arg.eap.type;
 			case FEATURE_DATABASE:
 				return a->arg.database == DB_ANY ||
 					   a->arg.database == b->arg.database;
@@ -368,8 +369,15 @@ char* plugin_feature_get_string(plugin_feature_t *feature)
 			break;
 		case FEATURE_EAP_SERVER:
 		case FEATURE_EAP_PEER:
-			if (asprintf(&str, "%N:%N", plugin_feature_names, feature->type,
-					eap_type_short_names, feature->arg.eap) > 0)
+			if (feature->arg.eap.vendor &&
+				asprintf(&str, "%N:%d-%d", plugin_feature_names, feature->type,
+					feature->arg.eap.type, feature->arg.eap.vendor) > 0)
+			{
+				return str;
+			}
+			else if (!feature->arg.eap.vendor &&
+				asprintf(&str, "%N:%N", plugin_feature_names, feature->type,
+					eap_type_short_names, feature->arg.eap.type) > 0)
 			{
 				return str;
 			}
diff --git a/src/libstrongswan/plugins/plugin_feature.h b/src/libstrongswan/plugins/plugin_feature.h
index ea23f76..03f1ba8 100644
--- a/src/libstrongswan/plugins/plugin_feature.h
+++ b/src/libstrongswan/plugins/plugin_feature.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012-2013 Tobias Brunner
+ * Copyright (C) 2012-2015 Tobias Brunner
  * Hochschule fuer Technik Rapperswil
  *
  * Copyright (C) 2011 Martin Willi
@@ -196,7 +196,7 @@ struct plugin_feature_t {
 		/** FEATURE_CONTAINER_DECODE/ENCODE */
 		container_type_t container;
 		/** FEATURE_EAP_SERVER/CLIENT */
-		eap_type_t eap;
+		eap_vendor_type_t eap;
 		/** FEATURE_DATABASE */
 		db_driver_t database;
 		/** FEATURE_FETCHER */
@@ -292,8 +292,10 @@ struct plugin_feature_t {
 #define _PLUGIN_FEATURE_CERT_ENCODE(kind, type)				__PLUGIN_FEATURE(kind, CERT_ENCODE, .cert = type)
 #define _PLUGIN_FEATURE_CONTAINER_DECODE(kind, type)		__PLUGIN_FEATURE(kind, CONTAINER_DECODE, .container = type)
 #define _PLUGIN_FEATURE_CONTAINER_ENCODE(kind, type)		__PLUGIN_FEATURE(kind, CONTAINER_ENCODE, .container = type)
-#define _PLUGIN_FEATURE_EAP_SERVER(kind, type)				__PLUGIN_FEATURE(kind, EAP_SERVER, .eap = type)
-#define _PLUGIN_FEATURE_EAP_PEER(kind, type)				__PLUGIN_FEATURE(kind, EAP_PEER, .eap = type)
+#define _PLUGIN_FEATURE_EAP_SERVER(kind, type)				_PLUGIN_FEATURE_EAP_SERVER_VENDOR(kind, type, 0)
+#define _PLUGIN_FEATURE_EAP_PEER(kind, type)				_PLUGIN_FEATURE_EAP_PEER_VENDOR(kind, type, 0)
+#define _PLUGIN_FEATURE_EAP_SERVER_VENDOR(kind, type, vendor)__PLUGIN_FEATURE(kind, EAP_SERVER, .eap = { type, vendor })
+#define _PLUGIN_FEATURE_EAP_PEER_VENDOR(kind, type, vendor)	__PLUGIN_FEATURE(kind, EAP_PEER, .eap = { type, vendor })
 #define _PLUGIN_FEATURE_DATABASE(kind, type)				__PLUGIN_FEATURE(kind, DATABASE, .database = type)
 #define _PLUGIN_FEATURE_FETCHER(kind, type)					__PLUGIN_FEATURE(kind, FETCHER, .fetcher = type)
 #define _PLUGIN_FEATURE_RESOLVER(kind, ...)					__PLUGIN_FEATURE(kind, RESOLVER, .custom = NULL)
diff --git a/src/libstrongswan/plugins/test_vectors/Makefile.am b/src/libstrongswan/plugins/test_vectors/Makefile.am
index bde27b8..72ba4ce 100644
--- a/src/libstrongswan/plugins/test_vectors/Makefile.am
+++ b/src/libstrongswan/plugins/test_vectors/Makefile.am
@@ -19,6 +19,7 @@ libstrongswan_test_vectors_la_SOURCES = \
 	test_vectors/aes_cmac.c \
 	test_vectors/aes_ccm.c \
 	test_vectors/aes_gcm.c \
+	test_vectors/chacha20poly1305.c \
 	test_vectors/blowfish.c \
 	test_vectors/camellia_cbc.c \
 	test_vectors/camellia_ctr.c \
diff --git a/src/libstrongswan/plugins/test_vectors/Makefile.in b/src/libstrongswan/plugins/test_vectors/Makefile.in
index e98119b..fa7c3cb 100644
--- a/src/libstrongswan/plugins/test_vectors/Makefile.in
+++ b/src/libstrongswan/plugins/test_vectors/Makefile.in
@@ -133,11 +133,11 @@ am_libstrongswan_test_vectors_la_OBJECTS = test_vectors_plugin.lo \
 	test_vectors/3des_cbc.lo test_vectors/aes_cbc.lo \
 	test_vectors/aes_ctr.lo test_vectors/aes_xcbc.lo \
 	test_vectors/aes_cmac.lo test_vectors/aes_ccm.lo \
-	test_vectors/aes_gcm.lo test_vectors/blowfish.lo \
-	test_vectors/camellia_cbc.lo test_vectors/camellia_ctr.lo \
-	test_vectors/camellia_xcbc.lo test_vectors/cast.lo \
-	test_vectors/des.lo test_vectors/idea.lo test_vectors/null.lo \
-	test_vectors/rc2.lo test_vectors/rc5.lo \
+	test_vectors/aes_gcm.lo test_vectors/chacha20poly1305.lo \
+	test_vectors/blowfish.lo test_vectors/camellia_cbc.lo \
+	test_vectors/camellia_ctr.lo test_vectors/camellia_xcbc.lo \
+	test_vectors/cast.lo test_vectors/des.lo test_vectors/idea.lo \
+	test_vectors/null.lo test_vectors/rc2.lo test_vectors/rc5.lo \
 	test_vectors/serpent_cbc.lo test_vectors/twofish_cbc.lo \
 	test_vectors/md2.lo test_vectors/md4.lo test_vectors/md5.lo \
 	test_vectors/md5_hmac.lo test_vectors/sha1.lo \
@@ -461,6 +461,7 @@ libstrongswan_test_vectors_la_SOURCES = \
 	test_vectors/aes_cmac.c \
 	test_vectors/aes_ccm.c \
 	test_vectors/aes_gcm.c \
+	test_vectors/chacha20poly1305.c \
 	test_vectors/blowfish.c \
 	test_vectors/camellia_cbc.c \
 	test_vectors/camellia_ctr.c \
@@ -589,6 +590,8 @@ test_vectors/aes_ccm.lo: test_vectors/$(am__dirstamp) \
 	test_vectors/$(DEPDIR)/$(am__dirstamp)
 test_vectors/aes_gcm.lo: test_vectors/$(am__dirstamp) \
 	test_vectors/$(DEPDIR)/$(am__dirstamp)
+test_vectors/chacha20poly1305.lo: test_vectors/$(am__dirstamp) \
+	test_vectors/$(DEPDIR)/$(am__dirstamp)
 test_vectors/blowfish.lo: test_vectors/$(am__dirstamp) \
 	test_vectors/$(DEPDIR)/$(am__dirstamp)
 test_vectors/camellia_cbc.lo: test_vectors/$(am__dirstamp) \
@@ -666,6 +669,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at test_vectors/$(DEPDIR)/camellia_ctr.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at test_vectors/$(DEPDIR)/camellia_xcbc.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at test_vectors/$(DEPDIR)/cast.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at test_vectors/$(DEPDIR)/chacha20poly1305.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at test_vectors/$(DEPDIR)/des.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at test_vectors/$(DEPDIR)/ecp.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at test_vectors/$(DEPDIR)/ecpbp.Plo at am__quote@
diff --git a/src/libstrongswan/plugins/test_vectors/test_vectors.h b/src/libstrongswan/plugins/test_vectors/test_vectors.h
index f7450aa..57c218c 100644
--- a/src/libstrongswan/plugins/test_vectors/test_vectors.h
+++ b/src/libstrongswan/plugins/test_vectors/test_vectors.h
@@ -113,6 +113,10 @@ TEST_VECTOR_AEAD(aes_gcm21)
 TEST_VECTOR_AEAD(aes_gcm22)
 TEST_VECTOR_AEAD(aes_gcm23)
 
+TEST_VECTOR_AEAD(chacha20poly1305_1)
+TEST_VECTOR_AEAD(chacha20poly1305_2)
+TEST_VECTOR_AEAD(chacha20poly1305_3)
+
 TEST_VECTOR_SIGNER(aes_xcbc_s1)
 TEST_VECTOR_SIGNER(aes_xcbc_s2)
 TEST_VECTOR_SIGNER(aes_xcbc_s3)
diff --git a/src/libstrongswan/plugins/test_vectors/test_vectors/chacha20poly1305.c b/src/libstrongswan/plugins/test_vectors/test_vectors/chacha20poly1305.c
new file mode 100644
index 0000000..21726cb
--- /dev/null
+++ b/src/libstrongswan/plugins/test_vectors/test_vectors/chacha20poly1305.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2015 Martin Willi
+ * Copyright (C) 2015 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the Licenseor (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 usefulbut
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include <crypto/crypto_tester.h>
+
+/**
+ * From draft-irtf-cfrg-chacha20-poly1305
+ */
+aead_test_vector_t chacha20poly1305_1 = {
+	.alg = ENCR_CHACHA20_POLY1305, .key_size = 32, .salt_size = 4,
+	.len = 265, .alen = 12,
+	.key	= "\x1c\x92\x40\xa5\xeb\x55\xd3\x8a\xf3\x33\x88\x86\x04\xf6\xb5\xf0"
+			  "\x47\x39\x17\xc1\x40\x2b\x80\x09\x9d\xca\x5c\xbc\x20\x70\x75\xc0"
+			  "\x00\x00\x00\x00",
+	.iv		= "\x01\x02\x03\x04\x05\x06\x07\x08",
+	.adata	= "\xf3\x33\x88\x86\x00\x00\x00\x00\x00\x00\x4e\x91",
+	.plain	= "\x49\x6e\x74\x65\x72\x6e\x65\x74\x2d\x44\x72\x61\x66\x74\x73\x20"
+			  "\x61\x72\x65\x20\x64\x72\x61\x66\x74\x20\x64\x6f\x63\x75\x6d\x65"
+			  "\x6e\x74\x73\x20\x76\x61\x6c\x69\x64\x20\x66\x6f\x72\x20\x61\x20"
+			  "\x6d\x61\x78\x69\x6d\x75\x6d\x20\x6f\x66\x20\x73\x69\x78\x20\x6d"
+			  "\x6f\x6e\x74\x68\x73\x20\x61\x6e\x64\x20\x6d\x61\x79\x20\x62\x65"
+			  "\x20\x75\x70\x64\x61\x74\x65\x64\x2c\x20\x72\x65\x70\x6c\x61\x63"
+			  "\x65\x64\x2c\x20\x6f\x72\x20\x6f\x62\x73\x6f\x6c\x65\x74\x65\x64"
+			  "\x20\x62\x79\x20\x6f\x74\x68\x65\x72\x20\x64\x6f\x63\x75\x6d\x65"
+			  "\x6e\x74\x73\x20\x61\x74\x20\x61\x6e\x79\x20\x74\x69\x6d\x65\x2e"
+			  "\x20\x49\x74\x20\x69\x73\x20\x69\x6e\x61\x70\x70\x72\x6f\x70\x72"
+			  "\x69\x61\x74\x65\x20\x74\x6f\x20\x75\x73\x65\x20\x49\x6e\x74\x65"
+			  "\x72\x6e\x65\x74\x2d\x44\x72\x61\x66\x74\x73\x20\x61\x73\x20\x72"
+			  "\x65\x66\x65\x72\x65\x6e\x63\x65\x20\x6d\x61\x74\x65\x72\x69\x61"
+			  "\x6c\x20\x6f\x72\x20\x74\x6f\x20\x63\x69\x74\x65\x20\x74\x68\x65"
+			  "\x6d\x20\x6f\x74\x68\x65\x72\x20\x74\x68\x61\x6e\x20\x61\x73\x20"
+			  "\x2f\xe2\x80\x9c\x77\x6f\x72\x6b\x20\x69\x6e\x20\x70\x72\x6f\x67"
+			  "\x72\x65\x73\x73\x2e\x2f\xe2\x80\x9d",
+	.cipher	= "\x64\xa0\x86\x15\x75\x86\x1a\xf4\x60\xf0\x62\xc7\x9b\xe6\x43\xbd"
+			  "\x5e\x80\x5c\xfd\x34\x5c\xf3\x89\xf1\x08\x67\x0a\xc7\x6c\x8c\xb2"
+			  "\x4c\x6c\xfc\x18\x75\x5d\x43\xee\xa0\x9e\xe9\x4e\x38\x2d\x26\xb0"
+			  "\xbd\xb7\xb7\x3c\x32\x1b\x01\x00\xd4\xf0\x3b\x7f\x35\x58\x94\xcf"
+			  "\x33\x2f\x83\x0e\x71\x0b\x97\xce\x98\xc8\xa8\x4a\xbd\x0b\x94\x81"
+			  "\x14\xad\x17\x6e\x00\x8d\x33\xbd\x60\xf9\x82\xb1\xff\x37\xc8\x55"
+			  "\x97\x97\xa0\x6e\xf4\xf0\xef\x61\xc1\x86\x32\x4e\x2b\x35\x06\x38"
+			  "\x36\x06\x90\x7b\x6a\x7c\x02\xb0\xf9\xf6\x15\x7b\x53\xc8\x67\xe4"
+			  "\xb9\x16\x6c\x76\x7b\x80\x4d\x46\xa5\x9b\x52\x16\xcd\xe7\xa4\xe9"
+			  "\x90\x40\xc5\xa4\x04\x33\x22\x5e\xe2\x82\xa1\xb0\xa0\x6c\x52\x3e"
+			  "\xaf\x45\x34\xd7\xf8\x3f\xa1\x15\x5b\x00\x47\x71\x8c\xbc\x54\x6a"
+			  "\x0d\x07\x2b\x04\xb3\x56\x4e\xea\x1b\x42\x22\x73\xf5\x48\x27\x1a"
+			  "\x0b\xb2\x31\x60\x53\xfa\x76\x99\x19\x55\xeb\xd6\x31\x59\x43\x4e"
+			  "\xce\xbb\x4e\x46\x6d\xae\x5a\x10\x73\xa6\x72\x76\x27\x09\x7a\x10"
+			  "\x49\xe6\x17\xd9\x1d\x36\x10\x94\xfa\x68\xf0\xff\x77\x98\x71\x30"
+			  "\x30\x5b\xea\xba\x2e\xda\x04\xdf\x99\x7b\x71\x4d\x6c\x6f\x2c\x29"
+			  "\xa6\xad\x5c\xb4\x02\x2b\x02\x70\x9b\xee\xad\x9d\x67\x89\x0c\xbb"
+			  "\x22\x39\x23\x36\xfe\xa1\x85\x1f\x38",
+};
+
+/**
+ * ESP example from draft-ietf-ipsecme-chacha20-poly1305-06
+ */
+aead_test_vector_t chacha20poly1305_2 = {
+	.alg = ENCR_CHACHA20_POLY1305, .key_size = 32, .salt_size = 4,
+	.len = 88, .alen = 8,
+	.key	= "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+			  "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+			  "\xa0\xa1\xa2\xa3",
+	.iv		= "\x10\x11\x12\x13\x14\x15\x16\x17",
+	.adata	= "\x01\x02\x03\x04\x00\x00\x00\x05",
+	.plain	= "\x45\x00\x00\x54\xa6\xf2\x00\x00\x40\x01\xe7\x78\xc6\x33\x64\x05"
+			  "\xc0\x00\x02\x05\x08\x00\x5b\x7a\x3a\x08\x00\x00\x55\x3b\xec\x10"
+			  "\x00\x07\x36\x27\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13"
+			  "\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23"
+			  "\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33"
+			  "\x34\x35\x36\x37\x01\x02\x02\x04",
+	.cipher	= "\x24\x03\x94\x28\xb9\x7f\x41\x7e\x3c\x13\x75\x3a\x4f\x05\x08\x7b"
+			  "\x67\xc3\x52\xe6\xa7\xfa\xb1\xb9\x82\xd4\x66\xef\x40\x7a\xe5\xc6"
+			  "\x14\xee\x80\x99\xd5\x28\x44\xeb\x61\xaa\x95\xdf\xab\x4c\x02\xf7"
+			  "\x2a\xa7\x1e\x7c\x4c\x4f\x64\xc9\xbe\xfe\x2f\xac\xc6\x38\xe8\xf3"
+			  "\xcb\xec\x16\x3f\xac\x46\x9b\x50\x27\x73\xf6\xfb\x94\xe6\x64\xda"
+			  "\x91\x65\xb8\x28\x29\xf6\x41\xe0\x76\xaa\xa8\x26\x6b\x7f\xb0\xf7"
+			  "\xb1\x1b\x36\x99\x07\xe1\xad\x43",
+};
+
+/**
+ * IKEv2 example from draft-ietf-ipsecme-chacha20-poly1305-06
+ */
+aead_test_vector_t chacha20poly1305_3 = {
+	.alg = ENCR_CHACHA20_POLY1305, .key_size = 32, .salt_size = 4,
+	.len = 13, .alen = 32,
+	.key	= "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+			  "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+			  "\xa0\xa1\xa2\xa3",
+	.iv		= "\x10\x11\x12\x13\x14\x15\x16\x17",
+	.adata	= "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+			  "\x2e\x20\x25\x00\x00\x00\x00\x09\x00\x00\x00\x45\x29\x00\x00\x29",
+	.plain	= "\x00\x00\x00\x0c\x00\x00\x40\x01\x00\x00\x00\x0a\x00",
+	.cipher	= "\x61\x03\x94\x70\x1f\x8d\x01\x7f\x7c\x12\x92\x48\x89\x6b\x71\xbf"
+			  "\xe2\x52\x36\xef\xd7\xcd\xc6\x70\x66\x90\x63\x15\xb2",
+};
diff --git a/src/libstrongswan/selectors/traffic_selector.c b/src/libstrongswan/selectors/traffic_selector.c
index 3b7f8c5..6686324 100644
--- a/src/libstrongswan/selectors/traffic_selector.c
+++ b/src/libstrongswan/selectors/traffic_selector.c
@@ -849,8 +849,7 @@ traffic_selector_t *traffic_selector_create_from_rfc3779_format(ts_type_t type,
 		memcpy(this->to, to.ptr+1, to.len-1);
 		this->to[to.len-2] |= mask;
 	}
-	this->netbits = chunk_equals(from, to) ? (from.len-1)*8 - from.ptr[0]
-										   : NON_SUBNET_ADDRESS_RANGE;
+	calc_netbits(this);
 	return (&this->public);
 }
 
diff --git a/src/libstrongswan/settings/settings.c b/src/libstrongswan/settings/settings.c
index acf9160..305ebe6 100644
--- a/src/libstrongswan/settings/settings.c
+++ b/src/libstrongswan/settings/settings.c
@@ -37,9 +37,10 @@
 typedef struct private_settings_t private_settings_t;
 
 /**
- * Parse function provided by the generated parser.
+ * Parse functions provided by the generated parser.
  */
 bool settings_parser_parse_file(section_t *root, char *name);
+bool settings_parser_parse_string(section_t *root, char *settings);
 
 /**
  * Private data of settings
@@ -843,16 +844,17 @@ METHOD(settings_t, add_fallback, void,
 }
 
 /**
- * Load settings from files matching the given file pattern.
+ * Load settings from files matching the given file pattern or from a string.
  * All sections and values are added relative to "parent".
  * All files (even included ones) have to be loaded successfully.
  * If merge is FALSE the contents of parent are replaced with the parsed
  * contents, otherwise they are merged together.
  */
-static bool load_files_internal(private_settings_t *this, section_t *parent,
-								char *pattern, bool merge)
+static bool load_internal(private_settings_t *this, section_t *parent,
+						  char *pattern, bool merge, bool string)
 {
 	section_t *section;
+	bool loaded;
 
 	if (pattern == NULL || !pattern[0])
 	{	/* TODO: Clear parent if merge is FALSE? */
@@ -860,7 +862,9 @@ static bool load_files_internal(private_settings_t *this, section_t *parent,
 	}
 
 	section = settings_section_create(NULL);
-	if (!settings_parser_parse_file(section, pattern))
+	loaded = string ? settings_parser_parse_string(section, pattern) :
+					  settings_parser_parse_file(section, pattern);
+	if (!loaded)
 	{
 		settings_section_destroy(section, NULL);
 		return FALSE;
@@ -877,7 +881,7 @@ static bool load_files_internal(private_settings_t *this, section_t *parent,
 METHOD(settings_t, load_files, bool,
 	private_settings_t *this, char *pattern, bool merge)
 {
-	return load_files_internal(this, this->top, pattern, merge);
+	return load_internal(this, this->top, pattern, merge, FALSE);
 }
 
 METHOD(settings_t, load_files_section, bool,
@@ -894,7 +898,30 @@ METHOD(settings_t, load_files_section, bool,
 	{
 		return FALSE;
 	}
-	return load_files_internal(this, section, pattern, merge);
+	return load_internal(this, section, pattern, merge, FALSE);
+}
+
+METHOD(settings_t, load_string, bool,
+	private_settings_t *this, char *settings, bool merge)
+{
+	return load_internal(this, this->top, settings, merge, TRUE);
+}
+
+METHOD(settings_t, load_string_section, bool,
+	private_settings_t *this, char *settings, bool merge, char *key, ...)
+{
+	section_t *section;
+	va_list args;
+
+	va_start(args, key);
+	section = ensure_section(this, this->top, key, args);
+	va_end(args);
+
+	if (!section)
+	{
+		return FALSE;
+	}
+	return load_internal(this, section, settings, merge, TRUE);
 }
 
 METHOD(settings_t, destroy, void,
@@ -906,10 +933,7 @@ METHOD(settings_t, destroy, void,
 	free(this);
 }
 
-/*
- * see header file
- */
-settings_t *settings_create(char *file)
+static private_settings_t *settings_create_base()
 {
 	private_settings_t *this;
 
@@ -931,14 +955,37 @@ settings_t *settings_create(char *file)
 			.add_fallback = _add_fallback,
 			.load_files = _load_files,
 			.load_files_section = _load_files_section,
+			.load_string = _load_string,
+			.load_string_section = _load_string_section,
 			.destroy = _destroy,
 		},
 		.top = settings_section_create(NULL),
 		.contents = array_create(0, 0),
 		.lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
 	);
+	return this;
+}
+
+/*
+ * see header file
+ */
+settings_t *settings_create(char *file)
+{
+	private_settings_t *this = settings_create_base();
 
 	load_files(this, file, FALSE);
 
 	return &this->public;
 }
+
+/*
+ * see header file
+ */
+settings_t *settings_create_string(char *settings)
+{
+	private_settings_t *this = settings_create_base();
+
+	load_string(this, settings, FALSE);
+
+	return &this->public;
+}
diff --git a/src/libstrongswan/settings/settings.h b/src/libstrongswan/settings/settings.h
index 3b87c8f..4ef80d0 100644
--- a/src/libstrongswan/settings/settings.h
+++ b/src/libstrongswan/settings/settings.h
@@ -335,6 +335,50 @@ struct settings_t {
 							   char *section, ...);
 
 	/**
+	 * Load settings from the given string.
+	 *
+	 * If merge is TRUE, existing sections are extended, existing values
+	 * replaced, by those found in the string. If it is FALSE, existing
+	 * sections are purged before reading the new config.
+	 *
+	 * @note If the string contains _include_ statements they should be
+	 * absolute paths.
+	 *
+	 * @note If any failures occur, no settings are added at all. So, it's all
+	 * or nothing.
+	 *
+	 * @param settings	string to parse
+	 * @param merge		TRUE to merge config with existing values
+	 * @return			TRUE, if settings were loaded successfully
+	 */
+	bool (*load_string)(settings_t *this, char *settings, bool merge);
+
+	/**
+	 * Load settings from the given string.
+	 *
+	 * If merge is TRUE, existing sections are extended, existing values
+	 * replaced, by those found in the string. If it is FALSE, existing
+	 * sections are purged before reading the new config.
+	 *
+	 * All settings are loaded relative to the given section. The section is
+	 * created, if it does not yet exist.
+	 *
+	 * @note If the string contains _include_ statements they should be
+	 * absolute paths.
+	 *
+	 * @note If any failures occur, no settings are added at all. So, it's all
+	 * or nothing.
+	 *
+	 * @param settings	string to parse
+	 * @param merge		TRUE to merge config with existing values
+	 * @param section	section name of parent section, printf style
+	 * @param ...		argument list for section
+	 * @return			TRUE, if settings were loaded successfully
+	 */
+	bool (*load_string_section)(settings_t *this, char *settings, bool merge,
+								char *section, ...);
+
+	/**
 	 * Destroy a settings instance.
 	 */
 	void (*destroy)(settings_t *this);
@@ -350,4 +394,14 @@ struct settings_t {
  */
 settings_t *settings_create(char *file);
 
+/**
+ * Load settings from a string.
+ *
+ * @note If parsing the file fails the object is still created.
+ *
+ * @param settings		string to read settings from
+ * @return				settings object, or NULL
+ */
+settings_t *settings_create_string(char *settings);
+
 #endif /** SETTINGS_H_ @}*/
diff --git a/src/libstrongswan/settings/settings_lexer.c b/src/libstrongswan/settings/settings_lexer.c
index 0d71a1d..6e64e15 100644
--- a/src/libstrongswan/settings/settings_lexer.c
+++ b/src/libstrongswan/settings/settings_lexer.c
@@ -456,8 +456,8 @@ static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner );
 	yyg->yy_c_buf_p = yy_cp;
 
 /* %% [4.0] data tables for the DFA and the user's section 1 definitions go here */
-#define YY_NUM_RULES 26
-#define YY_END_OF_BUFFER 27
+#define YY_NUM_RULES 23
+#define YY_END_OF_BUFFER 24
 /* This struct is not used in this scanner,
    but its presence is necessary. */
 struct yy_trans_info
@@ -465,14 +465,13 @@ struct yy_trans_info
 	flex_int32_t yy_verify;
 	flex_int32_t yy_nxt;
 	};
-static yyconst flex_int16_t yy_accept[52] =
+static yyconst flex_int16_t yy_accept[49] =
     {   0,
-        0,    0,    0,    0,    0,    0,   27,    9,    2,    3,
+        0,    0,    0,    0,    0,    0,   24,    9,    2,    3,
         8,    1,    6,    9,    4,    5,   14,   10,   11,   12,
-       25,   16,   15,   17,    9,    2,    1,    1,    3,    9,
-       14,   13,   25,   24,   23,   24,   21,   22,   18,   19,
-       20,    1,    9,    9,    9,    9,    9,    0,    7,    7,
-        0
+       22,   15,   16,    9,    2,    1,    1,    3,    9,   14,
+       13,   22,   21,   20,   21,   17,   18,   19,    1,    9,
+        9,    9,    9,    9,    0,    7,    7,    0
     } ;
 
 static yyconst flex_int32_t yy_ec[256] =
@@ -486,11 +485,11 @@ static yyconst flex_int32_t yy_ec[256] =
         8,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    9,    1,    1,    1,    1,    1,   10,   11,   12,
+        1,    9,    1,    1,    1,    1,    1,    1,   10,   11,
 
-       13,   14,    1,    1,   15,    1,    1,   16,    1,   17,
-        1,    1,    1,   18,    1,   19,   20,    1,    1,    1,
-        1,    1,   21,    1,   22,    1,    1,    1,    1,    1,
+       12,    1,    1,    1,   13,    1,    1,   14,    1,   15,
+        1,    1,    1,   16,    1,   17,   18,    1,    1,    1,
+        1,    1,   19,    1,   20,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
@@ -507,92 +506,91 @@ static yyconst flex_int32_t yy_ec[256] =
         1,    1,    1,    1,    1
     } ;
 
-static yyconst flex_int32_t yy_meta[23] =
+static yyconst flex_int32_t yy_meta[21] =
     {   0,
         1,    2,    3,    1,    4,    5,    4,    6,    7,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        8,    4
+        1,    1,    1,    1,    1,    1,    1,    1,    8,    9
     } ;
 
-static yyconst flex_int16_t yy_base[62] =
+static yyconst flex_int16_t yy_base[60] =
     {   0,
-        0,    0,   21,   42,   26,   28,   63,    0,   31,  155,
-      155,   59,  155,   44,  155,  155,    0,  155,  155,    0,
-        0,  155,  155,   62,    0,   48,    0,   57,  155,   47,
-        0,  155,    0,  155,  155,   49,  155,  155,  155,  155,
-      155,    0,   30,   21,   28,   12,   37,   52,  155,   54,
-      155,   81,   89,   97,  104,  112,  117,  122,  130,  138,
-      146
+        0,    0,   19,   38,   21,   23,   55,    0,   47,  161,
+      161,   50,  161,   37,  161,  161,    0,  161,  161,    0,
+        0,  161,   56,    0,   44,    0,   47,  161,   39,    0,
+      161,    0,  161,  161,   45,  161,  161,  161,    0,   32,
+       24,   26,   11,   29,   31,  161,   33,  161,   73,   82,
+       91,   97,  101,  110,  115,  124,  133,  142,  151
     } ;
 
-static yyconst flex_int16_t yy_def[62] =
+static yyconst flex_int16_t yy_def[60] =
     {   0,
-       51,    1,   52,   52,   53,   53,   51,   54,   51,   51,
-       51,   55,   51,   54,   51,   51,   56,   51,   51,   57,
-       58,   51,   51,   59,   54,   51,   60,   55,   51,   54,
-       56,   51,   58,   51,   51,   51,   51,   51,   51,   51,
-       51,   60,   54,   54,   54,   54,   54,   61,   51,   61,
-        0,   51,   51,   51,   51,   51,   51,   51,   51,   51,
-       51
+       48,    1,   49,   49,   50,   50,   48,   51,   52,   48,
+       48,   53,   48,   51,   48,   48,   54,   48,   48,   55,
+       56,   48,   57,   51,   52,   58,   53,   48,   51,   54,
+       48,   56,   48,   48,   48,   48,   48,   48,   58,   51,
+       51,   51,   51,   51,   59,   48,   59,    0,   48,   48,
+       48,   48,   48,   48,   48,   48,   48,   48,   48
     } ;
 
-static yyconst flex_int16_t yy_nxt[178] =
+static yyconst flex_int16_t yy_nxt[182] =
     {   0,
         8,    9,   10,    8,    9,   11,   12,   13,    8,    8,
-        8,    8,    8,    8,   14,    8,    8,    8,    8,    8,
-       15,   16,   18,   18,   47,   18,   19,   18,   22,   20,
-       22,   23,   26,   23,   24,   26,   24,   27,   48,   46,
-       45,   48,   18,   18,   18,   44,   18,   19,   18,   26,
-       20,   35,   26,   50,   27,   50,   50,   43,   50,   29,
-       30,   29,   51,   18,   35,   36,   51,   51,   51,   51,
-       51,   37,   51,   51,   51,   38,   51,   51,   39,   40,
-       41,   17,   17,   17,   17,   17,   17,   17,   17,   21,
-       21,   21,   21,   21,   21,   21,   21,   25,   51,   51,
-
-       51,   51,   51,   25,   28,   28,   28,   28,   28,   28,
-       28,   28,   31,   51,   51,   51,   51,   31,   51,   31,
-       32,   32,   33,   33,   51,   33,   51,   33,   51,   33,
-       34,   34,   34,   34,   34,   34,   34,   34,   42,   42,
-       51,   42,   42,   42,   42,   42,   49,   49,   49,   49,
-       49,   51,   49,   49,    7,   51,   51,   51,   51,   51,
-       51,   51,   51,   51,   51,   51,   51,   51,   51,   51,
-       51,   51,   51,   51,   51,   51,   51
+        8,    8,   14,    8,    8,    8,    8,    8,   15,   16,
+       18,   18,   44,   18,   19,   18,   22,   20,   22,   23,
+       45,   23,   47,   45,   47,   47,   43,   47,   18,   18,
+       18,   42,   18,   19,   18,   41,   20,   34,   40,   28,
+       26,   29,   28,   26,   48,   48,   48,   18,   34,   35,
+       48,   48,   48,   48,   48,   48,   48,   48,   48,   48,
+       36,   37,   38,   17,   17,   17,   17,   17,   17,   17,
+       17,   17,   21,   21,   21,   21,   21,   21,   21,   21,
+       21,   24,   48,   48,   48,   48,   48,   24,   25,   48,
+
+       25,   27,   27,   27,   27,   27,   27,   27,   27,   27,
+       30,   48,   48,   48,   48,   30,   48,   30,   31,   31,
+       48,   48,   48,   31,   32,   32,   32,   32,   48,   32,
+       48,   32,   32,   33,   33,   33,   33,   33,   33,   33,
+       33,   33,   39,   39,   48,   39,   39,   39,   39,   39,
+       39,   46,   46,   46,   46,   46,   48,   46,   46,   46,
+        7,   48,   48,   48,   48,   48,   48,   48,   48,   48,
+       48,   48,   48,   48,   48,   48,   48,   48,   48,   48,
+       48
     } ;
 
-static yyconst flex_int16_t yy_chk[178] =
+static yyconst flex_int16_t yy_chk[182] =
     {   0,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    3,    3,   46,    3,    3,    3,    5,    3,
-        6,    5,    9,    6,    5,    9,    6,    9,   47,   45,
-       44,   47,    3,    4,    4,   43,    4,    4,    4,   26,
-        4,   36,   26,   48,   26,   50,   48,   30,   50,   28,
-       14,   12,    7,    4,   24,   24,    0,    0,    0,    0,
-        0,   24,    0,    0,    0,   24,    0,    0,   24,   24,
-       24,   52,   52,   52,   52,   52,   52,   52,   52,   53,
-       53,   53,   53,   53,   53,   53,   53,   54,    0,    0,
-
-        0,    0,    0,   54,   55,   55,   55,   55,   55,   55,
-       55,   55,   56,    0,    0,    0,    0,   56,    0,   56,
-       57,   57,   58,   58,    0,   58,    0,   58,    0,   58,
-       59,   59,   59,   59,   59,   59,   59,   59,   60,   60,
-        0,   60,   60,   60,   60,   60,   61,   61,   61,   61,
-       61,    0,   61,   61,   51,   51,   51,   51,   51,   51,
-       51,   51,   51,   51,   51,   51,   51,   51,   51,   51,
-       51,   51,   51,   51,   51,   51,   51
+        3,    3,   43,    3,    3,    3,    5,    3,    6,    5,
+       44,    6,   45,   44,   47,   45,   42,   47,    3,    4,
+        4,   41,    4,    4,    4,   40,    4,   35,   29,   27,
+       25,   14,   12,    9,    7,    0,    0,    4,   23,   23,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+       23,   23,   23,   49,   49,   49,   49,   49,   49,   49,
+       49,   49,   50,   50,   50,   50,   50,   50,   50,   50,
+       50,   51,    0,    0,    0,    0,    0,   51,   52,    0,
+
+       52,   53,   53,   53,   53,   53,   53,   53,   53,   53,
+       54,    0,    0,    0,    0,   54,    0,   54,   55,   55,
+        0,    0,    0,   55,   56,   56,   56,   56,    0,   56,
+        0,   56,   56,   57,   57,   57,   57,   57,   57,   57,
+       57,   57,   58,   58,    0,   58,   58,   58,   58,   58,
+       58,   59,   59,   59,   59,   59,    0,   59,   59,   59,
+       48,   48,   48,   48,   48,   48,   48,   48,   48,   48,
+       48,   48,   48,   48,   48,   48,   48,   48,   48,   48,
+       48
     } ;
 
 /* Table of booleans, true if rule could match eol. */
-static yyconst flex_int32_t yy_rule_can_match_eol[27] =
+static yyconst flex_int32_t yy_rule_can_match_eol[24] =
     {   0,
-0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 
-    0, 0, 0, 1, 0, 0, 0,     };
+0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    1, 0, 1, 0,     };
 
-static yyconst flex_int16_t yy_rule_linenum[26] =
+static yyconst flex_int16_t yy_rule_linenum[23] =
     {   0,
        59,   60,   61,   63,   64,   65,   67,   72,   77,   85,
-      105,  108,  111,  114,  120,  122,  123,  146,  147,  148,
-      149,  150,  151,  152,  153
+      105,  108,  111,  114,  120,  122,  141,  142,  143,  144,
+      145,  146
     } ;
 
 /* The intent behind this definition is that it'll catch
@@ -640,7 +638,7 @@ static void include_files(parser_helper_t *ctx);
 
 /* state used to scan quoted strings */
 
-#line 644 "settings/settings_lexer.c"
+#line 642 "settings/settings_lexer.c"
 
 #define INITIAL 0
 #define inc 1
@@ -952,7 +950,7 @@ YY_DECL
 #line 57 "settings/settings_lexer.l"
 
 
-#line 956 "settings/settings_lexer.c"
+#line 954 "settings/settings_lexer.c"
 
     yylval = yylval_param;
 
@@ -1017,13 +1015,13 @@ yy_match:
 			while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
 				{
 				yy_current_state = (int) yy_def[yy_current_state];
-				if ( yy_current_state >= 52 )
+				if ( yy_current_state >= 49 )
 					yy_c = yy_meta[(unsigned int) yy_c];
 				}
 			yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
 			++yy_cp;
 			}
-		while ( yy_base[yy_current_state] != 155 );
+		while ( yy_base[yy_current_state] != 161 );
 
 yy_find_action:
 /* %% [10.0] code to find the action number goes here */
@@ -1058,13 +1056,13 @@ do_action:	/* This label is used only to access EOF actions. */
 			{
 			if ( yy_act == 0 )
 				fprintf( stderr, "--scanner backing up\n" );
-			else if ( yy_act < 26 )
+			else if ( yy_act < 23 )
 				fprintf( stderr, "--accepting rule at line %ld (\"%s\")\n",
 				         (long)yy_rule_linenum[yy_act], yytext );
-			else if ( yy_act == 26 )
+			else if ( yy_act == 23 )
 				fprintf( stderr, "--accepting default rule (\"%s\")\n",
 				         yytext );
-			else if ( yy_act == 27 )
+			else if ( yy_act == 24 )
 				fprintf( stderr, "--(end of buffer or a NUL)\n" );
 			else
 				fprintf( stderr, "--EOF (start condition %d)\n", YY_START );
@@ -1197,21 +1195,13 @@ case 15:
 case YY_STATE_EOF(str):
 #line 121 "settings/settings_lexer.l"
 case 16:
-/* rule 16 can match eol */
-#line 123 "settings/settings_lexer.l"
-case 17:
-/* rule 17 can match eol */
 YY_RULE_SETUP
-#line 123 "settings/settings_lexer.l"
+#line 122 "settings/settings_lexer.l"
 {
 		if (!streq(yytext, "\""))
 		{
-			if (streq(yytext, "\n"))
-			{	/* put the newline back to fix the line numbers */
-				unput('\n');
-				yy_set_bol(0);
-			}
 			PARSER_DBG1(yyextra, "unterminated string detected");
+			return STRING_ERROR;
 		}
 		if (yy_top_state(yyscanner) == inc)
 		{	/* string include */
@@ -1227,52 +1217,43 @@ YY_RULE_SETUP
 		}
 	}
 	YY_BREAK
-case 18:
+case 17:
 YY_RULE_SETUP
-#line 146 "settings/settings_lexer.l"
+#line 141 "settings/settings_lexer.l"
 yyextra->string_add(yyextra, "\n");
 	YY_BREAK
-case 19:
+case 18:
 YY_RULE_SETUP
-#line 147 "settings/settings_lexer.l"
+#line 142 "settings/settings_lexer.l"
 yyextra->string_add(yyextra, "\r");
 	YY_BREAK
-case 20:
+case 19:
 YY_RULE_SETUP
-#line 148 "settings/settings_lexer.l"
+#line 143 "settings/settings_lexer.l"
 yyextra->string_add(yyextra, "\t");
 	YY_BREAK
-case 21:
-YY_RULE_SETUP
-#line 149 "settings/settings_lexer.l"
-yyextra->string_add(yyextra, "\b");
-	YY_BREAK
-case 22:
-YY_RULE_SETUP
-#line 150 "settings/settings_lexer.l"
-yyextra->string_add(yyextra, "\f");
-	YY_BREAK
-case 23:
-/* rule 23 can match eol */
+case 20:
+/* rule 20 can match eol */
 YY_RULE_SETUP
-#line 151 "settings/settings_lexer.l"
+#line 144 "settings/settings_lexer.l"
 /* merge lines that end with EOL characters */
 	YY_BREAK
-case 24:
+case 21:
 YY_RULE_SETUP
-#line 152 "settings/settings_lexer.l"
+#line 145 "settings/settings_lexer.l"
 yyextra->string_add(yyextra, yytext+1);
 	YY_BREAK
-case 25:
+case 22:
+/* rule 22 can match eol */
 YY_RULE_SETUP
-#line 153 "settings/settings_lexer.l"
+#line 146 "settings/settings_lexer.l"
 {
 		yyextra->string_add(yyextra, yytext);
 	}
 	YY_BREAK
 
 case YY_STATE_EOF(INITIAL):
-#line 158 "settings/settings_lexer.l"
+#line 151 "settings/settings_lexer.l"
 {
 	settings_parser_pop_buffer_state(yyscanner);
 	if (!settings_parser_open_next_file(yyextra) && !YY_CURRENT_BUFFER)
@@ -1281,12 +1262,12 @@ case YY_STATE_EOF(INITIAL):
 	}
 }
 	YY_BREAK
-case 26:
+case 23:
 YY_RULE_SETUP
-#line 166 "settings/settings_lexer.l"
+#line 159 "settings/settings_lexer.l"
 YY_FATAL_ERROR( "flex scanner jammed" );
 	YY_BREAK
-#line 1290 "settings/settings_lexer.c"
+#line 1271 "settings/settings_lexer.c"
 
 	case YY_END_OF_BUFFER:
 		{
@@ -1599,7 +1580,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
 		while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
 			{
 			yy_current_state = (int) yy_def[yy_current_state];
-			if ( yy_current_state >= 52 )
+			if ( yy_current_state >= 49 )
 				yy_c = yy_meta[(unsigned int) yy_c];
 			}
 		yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
@@ -1633,11 +1614,11 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
 	while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
 		{
 		yy_current_state = (int) yy_def[yy_current_state];
-		if ( yy_current_state >= 52 )
+		if ( yy_current_state >= 49 )
 			yy_c = yy_meta[(unsigned int) yy_c];
 		}
 	yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
-	yy_is_jam = (yy_current_state == 51);
+	yy_is_jam = (yy_current_state == 48);
 
 	return yy_is_jam ? 0 : yy_current_state;
 }
@@ -2654,7 +2635,7 @@ void settings_parser_free (void * ptr , yyscan_t yyscanner)
 
 /* %ok-for-header */
 
-#line 166 "settings/settings_lexer.l"
+#line 159 "settings/settings_lexer.l"
 
 
 
@@ -2692,3 +2673,11 @@ static void include_files(parser_helper_t *ctx)
 	settings_parser_open_next_file(ctx);
 }
 
+/**
+ * Load the given string to be parsed next
+ */
+void settings_parser_load_string(parser_helper_t *ctx, const char *content)
+{
+	settings_parser__scan_string(content, ctx->scanner);
+}
+
diff --git a/src/libstrongswan/settings/settings_lexer.l b/src/libstrongswan/settings/settings_lexer.l
index 176387f..ce9d4ee 100644
--- a/src/libstrongswan/settings/settings_lexer.l
+++ b/src/libstrongswan/settings/settings_lexer.l
@@ -119,16 +119,11 @@ static void include_files(parser_helper_t *ctx);
 <str>{
 	"\""				|
 	<<EOF>>				|
-	\n					|
 	\\					{
 		if (!streq(yytext, "\""))
 		{
-			if (streq(yytext, "\n"))
-			{	/* put the newline back to fix the line numbers */
-				unput('\n');
-				yy_set_bol(0);
-			}
 			PARSER_DBG1(yyextra, "unterminated string detected");
+			return STRING_ERROR;
 		}
 		if (yy_top_state(yyscanner) == inc)
 		{	/* string include */
@@ -146,11 +141,9 @@ static void include_files(parser_helper_t *ctx);
 	\\n     yyextra->string_add(yyextra, "\n");
 	\\r     yyextra->string_add(yyextra, "\r");
 	\\t     yyextra->string_add(yyextra, "\t");
-	\\b     yyextra->string_add(yyextra, "\b");
-	\\f     yyextra->string_add(yyextra, "\f");
 	\\\r?\n /* merge lines that end with EOL characters */
 	\\.     yyextra->string_add(yyextra, yytext+1);
-	[^\\\n"]+			{
+	[^\\"]+			{
 		yyextra->string_add(yyextra, yytext);
 	}
 }
@@ -198,3 +191,11 @@ static void include_files(parser_helper_t *ctx)
 
 	settings_parser_open_next_file(ctx);
 }
+
+/**
+ * Load the given string to be parsed next
+ */
+void settings_parser_load_string(parser_helper_t *ctx, const char *content)
+{
+	settings_parser__scan_string(content, ctx->scanner);
+}
diff --git a/src/libstrongswan/settings/settings_parser.c b/src/libstrongswan/settings/settings_parser.c
index be805ef..6cd3b17 100644
--- a/src/libstrongswan/settings/settings_parser.c
+++ b/src/libstrongswan/settings/settings_parser.c
@@ -110,6 +110,7 @@ int settings_parser_get_leng(void *scanner);
 int settings_parser_get_lineno(void *scanner);
 /* Custom functions in lexer */
 bool settings_parser_open_next_file(parser_helper_t *ctx);
+bool settings_parser_load_string(parser_helper_t *ctx, const char *content);
 
 /**
  * Forward declarations
@@ -130,7 +131,7 @@ static int yylex(YYSTYPE *lvalp, parser_helper_t *ctx)
 }
 
 
-#line 134 "settings/settings_parser.c" /* yacc.c:339  */
+#line 135 "settings/settings_parser.c" /* yacc.c:339  */
 
 # ifndef YY_NULLPTR
 #  if defined __cplusplus && 201103L <= __cplusplus
@@ -167,26 +168,28 @@ extern int settings_parser_debug;
   {
     NAME = 258,
     STRING = 259,
-    NEWLINE = 260
+    NEWLINE = 260,
+    STRING_ERROR = 261
   };
 #endif
 /* Tokens.  */
 #define NAME 258
 #define STRING 259
 #define NEWLINE 260
+#define STRING_ERROR 261
 
 /* Value type.  */
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
 typedef union YYSTYPE YYSTYPE;
 union YYSTYPE
 {
-#line 76 "settings/settings_parser.y" /* yacc.c:355  */
+#line 77 "settings/settings_parser.y" /* yacc.c:355  */
 
 	char *s;
 	struct section_t *sec;
 	struct kv_t *kv;
 
-#line 190 "settings/settings_parser.c" /* yacc.c:355  */
+#line 193 "settings/settings_parser.c" /* yacc.c:355  */
 };
 # define YYSTYPE_IS_TRIVIAL 1
 # define YYSTYPE_IS_DECLARED 1
@@ -200,7 +203,7 @@ int settings_parser_parse (parser_helper_t *ctx);
 
 /* Copy the second part of user declarations.  */
 
-#line 204 "settings/settings_parser.c" /* yacc.c:358  */
+#line 207 "settings/settings_parser.c" /* yacc.c:358  */
 
 #ifdef short
 # undef short
@@ -445,7 +448,7 @@ union yyalloc
 #define YYLAST   13
 
 /* YYNTOKENS -- Number of terminals.  */
-#define YYNTOKENS  9
+#define YYNTOKENS  10
 /* YYNNTS -- Number of nonterminals.  */
 #define YYNNTS  8
 /* YYNRULES -- Number of rules.  */
@@ -456,7 +459,7 @@ union yyalloc
 /* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned
    by yylex, with out-of-bounds checking.  */
 #define YYUNDEFTOK  2
-#define YYMAXUTOK   260
+#define YYMAXUTOK   261
 
 #define YYTRANSLATE(YYX)                                                \
   ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
@@ -471,13 +474,13 @@ static const yytype_uint8 yytranslate[] =
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     8,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     9,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     7,     2,     6,     2,     2,     2,     2,
+       2,     2,     2,     8,     2,     7,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
@@ -491,15 +494,15 @@ static const yytype_uint8 yytranslate[] =
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
-       5
+       5,     6
 };
 
 #if YYDEBUG
   /* YYRLINE[YYN] -- Source line where rule number YYN was defined.  */
 static const yytype_uint8 yyrline[] =
 {
-       0,   104,   104,   106,   107,   111,   115,   122,   130,   135,
-     142,   147,   154,   155,   169,   170
+       0,   105,   105,   107,   108,   112,   116,   123,   131,   136,
+     143,   148,   155,   156,   170,   171
 };
 #endif
 
@@ -508,9 +511,9 @@ static const yytype_uint8 yyrline[] =
    First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
 static const char *const yytname[] =
 {
-  "$end", "error", "$undefined", "NAME", "STRING", "NEWLINE", "'}'",
-  "'{'", "'='", "$accept", "statements", "statement", "section",
-  "section_start", "setting", "value", "valuepart", YY_NULLPTR
+  "$end", "error", "$undefined", "NAME", "STRING", "NEWLINE",
+  "STRING_ERROR", "'}'", "'{'", "'='", "$accept", "statements",
+  "statement", "section", "section_start", "setting", "value", "valuepart", YY_NULLPTR
 };
 #endif
 
@@ -519,14 +522,14 @@ static const char *const yytname[] =
    (internal) symbol number NUM (which must be that of a token).  */
 static const yytype_uint16 yytoknum[] =
 {
-       0,   256,   257,   258,   259,   260,   125,   123,    61
+       0,   256,   257,   258,   259,   260,   261,   125,   123,    61
 };
 # endif
 
-#define YYPACT_NINF -5
+#define YYPACT_NINF -11
 
 #define yypact_value_is_default(Yystate) \
-  (!!((Yystate) == (-5)))
+  (!!((Yystate) == (-11)))
 
 #define YYTABLE_NINF -1
 
@@ -537,8 +540,8 @@ static const yytype_uint16 yytoknum[] =
      STATE-NUM.  */
 static const yytype_int8 yypact[] =
 {
-      -5,     0,    -5,    -1,    -5,    -5,    -5,    -5,    -5,     2,
-      -5,    -2,     5,    -5,    -5,    -5,    -2,    -5,    -5,    -5
+     -11,     0,   -11,    -1,   -11,   -11,   -11,   -11,   -11,     2,
+     -11,    -2,     6,   -11,   -11,   -11,    -2,   -11,   -11,   -11
 };
 
   /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
@@ -553,7 +556,7 @@ static const yytype_uint8 yydefact[] =
   /* YYPGOTO[NTERM-NUM].  */
 static const yytype_int8 yypgoto[] =
 {
-      -5,     6,    -5,    -5,    -5,    -5,    -5,    -4
+     -11,     5,   -11,   -11,   -11,   -11,   -11,   -10
 };
 
   /* YYDEFGOTO[NTERM-NUM].  */
@@ -567,29 +570,29 @@ static const yytype_int8 yydefgoto[] =
      number is the opposite.  If YYTABLE_NINF, syntax error.  */
 static const yytype_uint8 yytable[] =
 {
-       2,    14,    15,     3,     9,     4,    10,    11,     3,    13,
-       4,    18,    19,    12
+       2,    14,    15,     3,     9,     4,    19,    10,    11,     3,
+      13,     4,    12,    18
 };
 
 static const yytype_uint8 yycheck[] =
 {
-       0,     3,     4,     3,     5,     5,     7,     8,     3,     7,
-       5,     6,    16,     7
+       0,     3,     4,     3,     5,     5,    16,     8,     9,     3,
+       8,     5,     7,     7
 };
 
   /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
      symbol of state STATE-NUM.  */
 static const yytype_uint8 yystos[] =
 {
-       0,    10,     0,     3,     5,    11,    12,    13,    14,     5,
-       7,     8,    10,     7,     3,     4,    15,    16,     6,    16
+       0,    11,     0,     3,     5,    12,    13,    14,    15,     5,
+       8,     9,    11,     8,     3,     4,    16,    17,     7,    17
 };
 
   /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
 static const yytype_uint8 yyr1[] =
 {
-       0,     9,    10,    10,    10,    11,    11,    12,    13,    13,
-      14,    14,    15,    15,    16,    16
+       0,    10,    11,    11,    11,    12,    12,    13,    14,    14,
+      15,    15,    16,    16,    17,    17
 };
 
   /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN.  */
@@ -1022,45 +1025,45 @@ yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, parser_helper_t *c
   switch (yytype)
     {
           case 3: /* NAME  */
-#line 90 "settings/settings_parser.y" /* yacc.c:1257  */
+#line 91 "settings/settings_parser.y" /* yacc.c:1257  */
       { free(((*yyvaluep).s)); }
-#line 1028 "settings/settings_parser.c" /* yacc.c:1257  */
+#line 1031 "settings/settings_parser.c" /* yacc.c:1257  */
         break;
 
     case 4: /* STRING  */
-#line 90 "settings/settings_parser.y" /* yacc.c:1257  */
+#line 91 "settings/settings_parser.y" /* yacc.c:1257  */
       { free(((*yyvaluep).s)); }
-#line 1034 "settings/settings_parser.c" /* yacc.c:1257  */
+#line 1037 "settings/settings_parser.c" /* yacc.c:1257  */
         break;
 
-    case 12: /* section  */
-#line 92 "settings/settings_parser.y" /* yacc.c:1257  */
+    case 13: /* section  */
+#line 93 "settings/settings_parser.y" /* yacc.c:1257  */
       { pop_section(ctx); settings_section_destroy(((*yyvaluep).sec), NULL); }
-#line 1040 "settings/settings_parser.c" /* yacc.c:1257  */
+#line 1043 "settings/settings_parser.c" /* yacc.c:1257  */
         break;
 
-    case 13: /* section_start  */
-#line 92 "settings/settings_parser.y" /* yacc.c:1257  */
+    case 14: /* section_start  */
+#line 93 "settings/settings_parser.y" /* yacc.c:1257  */
       { pop_section(ctx); settings_section_destroy(((*yyvaluep).sec), NULL); }
-#line 1046 "settings/settings_parser.c" /* yacc.c:1257  */
+#line 1049 "settings/settings_parser.c" /* yacc.c:1257  */
         break;
 
-    case 14: /* setting  */
-#line 93 "settings/settings_parser.y" /* yacc.c:1257  */
+    case 15: /* setting  */
+#line 94 "settings/settings_parser.y" /* yacc.c:1257  */
       { settings_kv_destroy(((*yyvaluep).kv), NULL); }
-#line 1052 "settings/settings_parser.c" /* yacc.c:1257  */
+#line 1055 "settings/settings_parser.c" /* yacc.c:1257  */
         break;
 
-    case 15: /* value  */
-#line 90 "settings/settings_parser.y" /* yacc.c:1257  */
+    case 16: /* value  */
+#line 91 "settings/settings_parser.y" /* yacc.c:1257  */
       { free(((*yyvaluep).s)); }
-#line 1058 "settings/settings_parser.c" /* yacc.c:1257  */
+#line 1061 "settings/settings_parser.c" /* yacc.c:1257  */
         break;
 
-    case 16: /* valuepart  */
-#line 90 "settings/settings_parser.y" /* yacc.c:1257  */
+    case 17: /* valuepart  */
+#line 91 "settings/settings_parser.y" /* yacc.c:1257  */
       { free(((*yyvaluep).s)); }
-#line 1064 "settings/settings_parser.c" /* yacc.c:1257  */
+#line 1067 "settings/settings_parser.c" /* yacc.c:1257  */
         break;
 
 
@@ -1326,64 +1329,64 @@ yyreduce:
   switch (yyn)
     {
         case 5:
-#line 112 "settings/settings_parser.y" /* yacc.c:1646  */
+#line 113 "settings/settings_parser.y" /* yacc.c:1646  */
     {
 		add_section(ctx, (yyvsp[0].sec));
 	}
-#line 1334 "settings/settings_parser.c" /* yacc.c:1646  */
+#line 1337 "settings/settings_parser.c" /* yacc.c:1646  */
     break;
 
   case 6:
-#line 116 "settings/settings_parser.y" /* yacc.c:1646  */
+#line 117 "settings/settings_parser.y" /* yacc.c:1646  */
     {
 		add_setting(ctx, (yyvsp[0].kv));
 	}
-#line 1342 "settings/settings_parser.c" /* yacc.c:1646  */
+#line 1345 "settings/settings_parser.c" /* yacc.c:1646  */
     break;
 
   case 7:
-#line 123 "settings/settings_parser.y" /* yacc.c:1646  */
+#line 124 "settings/settings_parser.y" /* yacc.c:1646  */
     {
 		pop_section(ctx);
 		(yyval.sec) = (yyvsp[-2].sec);
 	}
-#line 1351 "settings/settings_parser.c" /* yacc.c:1646  */
+#line 1354 "settings/settings_parser.c" /* yacc.c:1646  */
     break;
 
   case 8:
-#line 131 "settings/settings_parser.y" /* yacc.c:1646  */
+#line 132 "settings/settings_parser.y" /* yacc.c:1646  */
     {
 		(yyval.sec) = push_section(ctx, (yyvsp[-1].s));
 	}
-#line 1359 "settings/settings_parser.c" /* yacc.c:1646  */
+#line 1362 "settings/settings_parser.c" /* yacc.c:1646  */
     break;
 
   case 9:
-#line 136 "settings/settings_parser.y" /* yacc.c:1646  */
+#line 137 "settings/settings_parser.y" /* yacc.c:1646  */
     {
 		(yyval.sec) = push_section(ctx, (yyvsp[-2].s));
 	}
-#line 1367 "settings/settings_parser.c" /* yacc.c:1646  */
+#line 1370 "settings/settings_parser.c" /* yacc.c:1646  */
     break;
 
   case 10:
-#line 143 "settings/settings_parser.y" /* yacc.c:1646  */
+#line 144 "settings/settings_parser.y" /* yacc.c:1646  */
     {
 		(yyval.kv) = settings_kv_create((yyvsp[-2].s), (yyvsp[0].s));
 	}
-#line 1375 "settings/settings_parser.c" /* yacc.c:1646  */
+#line 1378 "settings/settings_parser.c" /* yacc.c:1646  */
     break;
 
   case 11:
-#line 148 "settings/settings_parser.y" /* yacc.c:1646  */
+#line 149 "settings/settings_parser.y" /* yacc.c:1646  */
     {
 		(yyval.kv) = settings_kv_create((yyvsp[-1].s), NULL);
 	}
-#line 1383 "settings/settings_parser.c" /* yacc.c:1646  */
+#line 1386 "settings/settings_parser.c" /* yacc.c:1646  */
     break;
 
   case 13:
-#line 156 "settings/settings_parser.y" /* yacc.c:1646  */
+#line 157 "settings/settings_parser.y" /* yacc.c:1646  */
     {	/* just put a single space between them, use strings for more */
 		if (asprintf(&(yyval.s), "%s %s", (yyvsp[-1].s), (yyvsp[0].s)) < 0)
 		{
@@ -1394,11 +1397,11 @@ yyreduce:
 		free((yyvsp[-1].s));
 		free((yyvsp[0].s));
 	}
-#line 1398 "settings/settings_parser.c" /* yacc.c:1646  */
+#line 1401 "settings/settings_parser.c" /* yacc.c:1646  */
     break;
 
 
-#line 1402 "settings/settings_parser.c" /* yacc.c:1646  */
+#line 1405 "settings/settings_parser.c" /* yacc.c:1646  */
       default: break;
     }
   /* User semantic actions sometimes alter yychar, and that requires
@@ -1626,7 +1629,7 @@ yyreturn:
 #endif
   return yyresult;
 }
-#line 173 "settings/settings_parser.y" /* yacc.c:1906  */
+#line 174 "settings/settings_parser.y" /* yacc.c:1906  */
 
 
 /**
@@ -1743,3 +1746,39 @@ bool settings_parser_parse_file(section_t *root, char *name)
 	helper->destroy(helper);
 	return success;
 }
+
+/**
+ * Parse the given string and add all sections and key/value pairs to the
+ * given section.
+ */
+bool settings_parser_parse_string(section_t *root, char *settings)
+{
+	parser_helper_t *helper;
+	array_t *sections = NULL;
+	bool success = FALSE;
+
+	array_insert_create(&sections, ARRAY_TAIL, root);
+	helper = parser_helper_create(sections);
+	helper->get_lineno = settings_parser_get_lineno;
+	if (settings_parser_lex_init_extra(helper, &helper->scanner) != 0)
+	{
+		helper->destroy(helper);
+		array_destroy(sections);
+		return FALSE;
+	}
+	settings_parser_load_string(helper, settings);
+	if (getenv("DEBUG_SETTINGS_PARSER"))
+	{
+		yydebug = 1;
+		settings_parser_set_debug(1, helper->scanner);
+	}
+	success = yyparse(helper) == 0;
+	if (!success)
+	{
+		DBG1(DBG_CFG, "failed to parse settings '%s'", settings);
+	}
+	array_destroy(sections);
+	settings_parser_lex_destroy(helper->scanner);
+	helper->destroy(helper);
+	return success;
+}
diff --git a/src/libstrongswan/settings/settings_parser.h b/src/libstrongswan/settings/settings_parser.h
index 9d56465..d887777 100644
--- a/src/libstrongswan/settings/settings_parser.h
+++ b/src/libstrongswan/settings/settings_parser.h
@@ -47,26 +47,28 @@ extern int settings_parser_debug;
   {
     NAME = 258,
     STRING = 259,
-    NEWLINE = 260
+    NEWLINE = 260,
+    STRING_ERROR = 261
   };
 #endif
 /* Tokens.  */
 #define NAME 258
 #define STRING 259
 #define NEWLINE 260
+#define STRING_ERROR 261
 
 /* Value type.  */
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
 typedef union YYSTYPE YYSTYPE;
 union YYSTYPE
 {
-#line 76 "settings/settings_parser.y" /* yacc.c:1909  */
+#line 77 "settings/settings_parser.y" /* yacc.c:1909  */
 
 	char *s;
 	struct section_t *sec;
 	struct kv_t *kv;
 
-#line 70 "settings/settings_parser.h" /* yacc.c:1909  */
+#line 72 "settings/settings_parser.h" /* yacc.c:1909  */
 };
 # define YYSTYPE_IS_TRIVIAL 1
 # define YYSTYPE_IS_DECLARED 1
diff --git a/src/libstrongswan/settings/settings_parser.y b/src/libstrongswan/settings/settings_parser.y
index d95a24b..96ab36f 100644
--- a/src/libstrongswan/settings/settings_parser.y
+++ b/src/libstrongswan/settings/settings_parser.y
@@ -39,6 +39,7 @@ int settings_parser_get_leng(void *scanner);
 int settings_parser_get_lineno(void *scanner);
 /* Custom functions in lexer */
 bool settings_parser_open_next_file(parser_helper_t *ctx);
+bool settings_parser_load_string(parser_helper_t *ctx, const char *content);
 
 /**
  * Forward declarations
@@ -79,7 +80,7 @@ static int yylex(YYSTYPE *lvalp, parser_helper_t *ctx)
 	struct kv_t *kv;
 }
 %token <s> NAME STRING
-%token NEWLINE
+%token NEWLINE STRING_ERROR
 
 /* ...and other symbols */
 %type <s> value valuepart
@@ -286,3 +287,39 @@ bool settings_parser_parse_file(section_t *root, char *name)
 	helper->destroy(helper);
 	return success;
 }
+
+/**
+ * Parse the given string and add all sections and key/value pairs to the
+ * given section.
+ */
+bool settings_parser_parse_string(section_t *root, char *settings)
+{
+	parser_helper_t *helper;
+	array_t *sections = NULL;
+	bool success = FALSE;
+
+	array_insert_create(&sections, ARRAY_TAIL, root);
+	helper = parser_helper_create(sections);
+	helper->get_lineno = settings_parser_get_lineno;
+	if (settings_parser_lex_init_extra(helper, &helper->scanner) != 0)
+	{
+		helper->destroy(helper);
+		array_destroy(sections);
+		return FALSE;
+	}
+	settings_parser_load_string(helper, settings);
+	if (getenv("DEBUG_SETTINGS_PARSER"))
+	{
+		yydebug = 1;
+		settings_parser_set_debug(1, helper->scanner);
+	}
+	success = yyparse(helper) == 0;
+	if (!success)
+	{
+		DBG1(DBG_CFG, "failed to parse settings '%s'", settings);
+	}
+	array_destroy(sections);
+	settings_parser_lex_destroy(helper->scanner);
+	helper->destroy(helper);
+	return success;
+}
diff --git a/src/libstrongswan/tests/suites/test_chunk.c b/src/libstrongswan/tests/suites/test_chunk.c
index 312a187..6272ca7 100644
--- a/src/libstrongswan/tests/suites/test_chunk.c
+++ b/src/libstrongswan/tests/suites/test_chunk.c
@@ -1020,7 +1020,7 @@ START_TEST(test_printf_hook)
 	int len;
 
 	/* %B should be the same as %b, which is what we check, comparing the
-	 * acutal result could be tricky as %b prints the chunk's memory address */
+	 * actual result could be tricky as %b prints the chunk's memory address */
 	len = snprintf(buf, sizeof(buf), "%B", &printf_hook_data[_i].in);
 	ck_assert(len >= 0 && len < sizeof(buf));
 	len = snprintf(mem, sizeof(mem), "%b", printf_hook_data[_i].in.ptr,
diff --git a/src/libstrongswan/tests/suites/test_host.c b/src/libstrongswan/tests/suites/test_host.c
index 7161b2c..5cb8013 100644
--- a/src/libstrongswan/tests/suites/test_host.c
+++ b/src/libstrongswan/tests/suites/test_host.c
@@ -104,6 +104,9 @@ START_TEST(test_create_from_string_v4)
 {
 	host_t *host;
 
+	host = host_create_from_string(NULL, 500);
+	ck_assert(!host);
+
 	host = host_create_from_string("%any", 500);
 	verify_any(host, AF_INET, 500);
 	host->destroy(host);
@@ -196,6 +199,7 @@ static void test_create_from_string_and_family_addr(char *string, chunk_t addr,
 
 START_TEST(test_create_from_string_and_family_v4)
 {
+	test_create_from_string_and_family_any(NULL, AF_INET, AF_UNSPEC);
 	test_create_from_string_and_family_any("%any", AF_INET, AF_INET);
 	test_create_from_string_and_family_any("%any4", AF_INET, AF_INET);
 	test_create_from_string_and_family_any("0.0.0.0", AF_INET, AF_INET);
@@ -210,6 +214,7 @@ END_TEST
 
 START_TEST(test_create_from_string_and_family_v6)
 {
+	test_create_from_string_and_family_any(NULL, AF_INET6, AF_UNSPEC);
 	test_create_from_string_and_family_any("%any", AF_INET6, AF_INET6);
 	test_create_from_string_and_family_any("%any6", AF_INET6, AF_INET6);
 	test_create_from_string_and_family_any("::", AF_INET6, AF_INET6);
@@ -224,6 +229,7 @@ END_TEST
 
 START_TEST(test_create_from_string_and_family_other)
 {
+	test_create_from_string_and_family_any(NULL, AF_UNSPEC, AF_UNSPEC);
 	test_create_from_string_and_family_any("%any", AF_UNSPEC, AF_INET);
 	test_create_from_string_and_family_any("%any4", AF_UNSPEC, AF_INET);
 	test_create_from_string_and_family_any("0.0.0.0", AF_UNSPEC, AF_INET);
diff --git a/src/libstrongswan/tests/suites/test_identification.c b/src/libstrongswan/tests/suites/test_identification.c
index de00e4a..ff14ba8 100644
--- a/src/libstrongswan/tests/suites/test_identification.c
+++ b/src/libstrongswan/tests/suites/test_identification.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Tobias Brunner
+ * Copyright (C) 2013-2015 Tobias Brunner
  * Copyright (C) 2009 Martin Willi
  * Hochschule fuer Technik Rapperswil
  *
@@ -727,6 +727,88 @@ START_TEST(test_matches_empty_reverse)
 END_TEST
 
 /*******************************************************************************
+ * identification hashing
+ */
+
+static bool id_hash_equals(char *str, char *b_str)
+{
+	identification_t *a, *b;
+	bool success = FALSE;
+
+	a = identification_create_from_string(str);
+	b = identification_create_from_string(b_str ?: str);
+	success = a->hash(a, 0) == b->hash(b, 0);
+	a->destroy(a);
+	b->destroy(b);
+	return success;
+}
+
+START_TEST(test_hash)
+{
+	ck_assert(id_hash_equals("moon at strongswan.org", NULL));
+	ck_assert(id_hash_equals("vpn.strongswan.org", NULL));
+	ck_assert(id_hash_equals("192.168.1.1", NULL));
+	ck_assert(id_hash_equals("C=CH", NULL));
+
+	ck_assert(!id_hash_equals("moon at strongswan.org", "sun at strongswan.org"));
+	ck_assert(!id_hash_equals("vpn.strongswan.org", "*.strongswan.org"));
+	ck_assert(!id_hash_equals("192.168.1.1", "192.168.1.2"));
+	ck_assert(!id_hash_equals("C=CH", "C=DE"));
+	ck_assert(!id_hash_equals("fqdn:strongswan.org", "keyid:strongswan.org"));
+}
+END_TEST
+
+START_TEST(test_hash_any)
+{
+	ck_assert(id_hash_equals("%any", NULL));
+	ck_assert(id_hash_equals("%any", "0.0.0.0"));
+	ck_assert(id_hash_equals("%any", "*"));
+	ck_assert(id_hash_equals("%any", ""));
+
+	ck_assert(!id_hash_equals("%any", "any"));
+}
+END_TEST
+
+START_TEST(test_hash_dn)
+{
+	identification_t *a, *b;
+
+	/* same DN (C=CH, O=strongSwan), different RDN type (PRINTABLESTRING vs.
+	 * UTF8STRING) */
+	a = identification_create_from_data(chunk_from_chars(
+			0x30, 0x22, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
+			0x55, 0x04, 0x06, 0x13, 0x02, 0x43, 0x48, 0x31,
+			0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0a,
+			0x13, 0x0a, 0x73, 0x74, 0x72, 0x6f, 0x6e, 0x67,
+			0x53, 0x77, 0x61, 0x6e));
+	b = identification_create_from_data(chunk_from_chars(
+			0x30, 0x22, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
+			0x55, 0x04, 0x06, 0x0c, 0x02, 0x43, 0x48, 0x31,
+			0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0a,
+			0x0c, 0x0a, 0x73, 0x74, 0x72, 0x6f, 0x6e, 0x67,
+			0x53, 0x77, 0x61, 0x6e));
+	ck_assert_int_eq(a->hash(a, 0), b->hash(b, 0));
+	ck_assert(a->equals(a, b));
+	a->destroy(a);
+	b->destroy(b);
+}
+END_TEST
+
+START_TEST(test_hash_inc)
+{
+	identification_t *a;
+
+	a = identification_create_from_string("vpn.strongswan.org");
+	ck_assert(a->hash(a, 0) != a->hash(a, 1));
+	a->destroy(a);
+
+	a = identification_create_from_string("C=CH, O=strongSwan");
+	ck_assert(a->hash(a, 0) != a->hash(a, 1));
+	a->destroy(a);
+}
+END_TEST
+
+/*******************************************************************************
  * identification part enumeration
  */
 
@@ -851,6 +933,13 @@ Suite *identification_suite_create()
 	tcase_add_loop_test(tc, test_matches_empty_reverse, ID_ANY, ID_KEY_ID + 1);
 	suite_add_tcase(s, tc);
 
+	tc = tcase_create("hash");
+	tcase_add_test(tc, test_hash);
+	tcase_add_test(tc, test_hash_any);
+	tcase_add_test(tc, test_hash_dn);
+	tcase_add_test(tc, test_hash_inc);
+	suite_add_tcase(s, tc);
+
 	tc = tcase_create("part enumeration");
 	tcase_add_test(tc, test_parts);
 	suite_add_tcase(s, tc);
diff --git a/src/libstrongswan/tests/suites/test_settings.c b/src/libstrongswan/tests/suites/test_settings.c
index 9601a34..bead9d7 100644
--- a/src/libstrongswan/tests/suites/test_settings.c
+++ b/src/libstrongswan/tests/suites/test_settings.c
@@ -58,6 +58,10 @@ START_SETUP(setup_base_config)
 		"	}\n"
 		"	key2 = with space\n"
 		"	key3 = \"string with\\nnewline\"\n"
+		"	key4 = \"multi line\n"
+		"string\"\n"
+		"	key5 = \"escaped \\\n"
+		"newline\"\n"
 		"}\n"
 		"out = side\n"
 		"other {\n"
@@ -88,6 +92,8 @@ START_TEST(test_get_str)
 	verify_string("", "main.empty");
 	verify_string("with space", "main.key2");
 	verify_string("string with\nnewline", "main.key3");
+	verify_string("multi line\nstring", "main.key4");
+	verify_string("escaped newline", "main.key5");
 	verify_string("value", "main.sub1.key");
 	verify_string("value2", "main.sub1.key2");
 	verify_string("bar", "main.sub1.subsub.foo");
@@ -97,7 +103,7 @@ START_TEST(test_get_str)
 	verify_string("other val", "other.key1");
 
 	verify_null("main.none");
-	verify_null("main.key4");
+	verify_null("main.key6");
 	verify_null("other.sub");
 }
 END_TEST
@@ -131,7 +137,7 @@ START_TEST(test_get_str_printf)
 	 * probably document it at least */
 	verify_null("main.%s%u.key%d", "sub", 1, 2);
 
-	verify_null("%s.%s%d", "main", "key", 4);
+	verify_null("%s.%s%d", "main", "key", 6);
 }
 END_TEST
 
@@ -529,9 +535,7 @@ END_TEST
 # define include2 "/tmp/strongswan-settings-test-include2"
 #endif
 
-START_SETUP(setup_include_config)
-{
-	chunk_t inc1 = chunk_from_str(
+static char *include_content1 =
 		"main {\n"
 		"	key1 = n1\n"
 		"	key2 = n2\n"
@@ -544,14 +548,17 @@ START_SETUP(setup_include_config)
 		"		sub3 = val3\n"
 		"	}\n"
 		"	include " include2 "\n"
-		"}");
-	chunk_t inc2 = chunk_from_str(
+		"}";
+static char *include_content2 =
 		"key2 = v2\n"
 		"sub1 {\n"
 		"	key = val\n"
-		"}");
-	ck_assert(chunk_write(inc1, include1, 0022, TRUE));
-	ck_assert(chunk_write(inc2, include2, 0022, TRUE));
+		"}";
+
+START_SETUP(setup_include_config)
+{
+	ck_assert(chunk_write(chunk_from_str(include_content1), include1, 0022, TRUE));
+	ck_assert(chunk_write(chunk_from_str(include_content2), include2, 0022, TRUE));
 }
 END_SETUP
 
@@ -600,6 +607,27 @@ START_TEST(test_include)
 }
 END_TEST
 
+START_TEST(test_include_string)
+{
+	chunk_t contents = chunk_from_str(
+		"main {\n"
+		"	key1 = val1\n"
+		"	key2 = val2\n"
+		"	none = x\n"
+		"	sub1 {\n"
+		"		include this/does/not/exist.conf\n"
+		"		include = value\n"
+		"		key2 = value2\n"
+		"		include \"" include2 "\"\n"
+		"	}\n"
+		"}\n"
+		"include \"" include1 "\"");
+
+	create_settings(contents);
+	verify_include();
+}
+END_TEST
+
 START_TEST(test_load_files)
 {
 	chunk_t contents = chunk_from_str(
@@ -784,6 +812,104 @@ START_TEST(test_order_section)
 }
 END_TEST
 
+
+START_TEST(test_load_string)
+{
+	char *content =
+		"main {\n"
+		"	key1 = val1\n"
+		"	key2 = val2\n"
+		"	key3 = val3\n"
+		"	none = x\n"
+		"	sub1 {\n"
+		"		include = value\n"
+		"		key2 = v2\n"
+		"		sub1 {\n"
+		"			key = val\n"
+		"		}\n"
+		"	}\n"
+		"}";
+	char *val1, *val2, *val3;
+
+	settings = settings_create_string(content);
+
+	val1 = settings->get_str(settings, "main.key1", NULL);
+	val2 = settings->get_str(settings, "main.sub1.key2", NULL);
+	/* loading the same content twice should not change anything, with... */
+	ck_assert(settings->load_string(settings, content, TRUE));
+	ck_assert(val1 == settings->get_str(settings, "main.key1", NULL));
+	ck_assert(val2 == settings->get_str(settings, "main.sub1.key2", NULL));
+	/* ...or without merging */
+	ck_assert(settings->load_string(settings, content, FALSE));
+	ck_assert(val1 == settings->get_str(settings, "main.key1", NULL));
+	ck_assert(val2 == settings->get_str(settings, "main.sub1.key2", NULL));
+
+	val1 = settings->get_str(settings, "main.key2", NULL);
+	val2 = settings->get_str(settings, "main.key3", NULL);
+	val3 = settings->get_str(settings, "main.none", NULL);
+	/* only pointers for modified settings should change, but still be valid */
+	ck_assert(settings->load_string(settings, include_content1, FALSE));
+	ck_assert(val1 != settings->get_str(settings, "main.key2", NULL));
+	ck_assert_str_eq(val1, "val2");
+	ck_assert(val2 == settings->get_str(settings, "main.key3", NULL));
+	ck_assert(val3 != settings->get_str(settings, "main.none", NULL));
+	ck_assert_str_eq(val3, "x");
+
+	settings->destroy(settings);
+	settings = settings_create_string(content);
+	ck_assert(settings);
+
+	ck_assert(settings->load_string(settings, include_content1, TRUE));
+	verify_include();
+
+	ck_assert(settings->load_string(settings, include_content2, FALSE));
+	verify_null("main.key1");
+	verify_string("v2", "key2");
+	verify_string("val", "sub1.key");
+	verify_null("main.sub1.key3");
+}
+END_TEST
+
+
+START_TEST(test_load_string_section)
+{
+	char *content =
+		"main {\n"
+		"	key1 = val1\n"
+		"	key2 = val2\n"
+		"	none = x\n"
+		"	sub1 {\n"
+		"		include = value\n"
+		"		key2 = value2\n"
+		"	}\n"
+		"}";
+
+	settings = settings_create_string(content);
+
+	ck_assert(settings->load_string_section(settings, include_content1, TRUE, ""));
+	ck_assert(settings->load_string_section(settings, include_content2, TRUE, "main.sub1"));
+	verify_include();
+
+	/* invalid strings are a failure */
+	ck_assert(!settings->load_string_section(settings, "conf {", TRUE, ""));
+	/* NULL or empty strings are OK though */
+	ck_assert(settings->load_string_section(settings, "", TRUE, ""));
+	ck_assert(settings->load_string_section(settings, NULL, TRUE, ""));
+	verify_include();
+
+	ck_assert(settings->load_string_section(settings, include_content2, FALSE, "main"));
+	verify_null("main.key1");
+	verify_string("v2", "main.key2");
+	verify_string("val", "main.sub1.key");
+	verify_null("main.sub1.key3");
+	verify_null("main.sub2.sub3");
+
+	ck_assert(settings->load_string_section(settings, include_content2, TRUE, "main.sub2"));
+	verify_string("v2", "main.sub2.key2");
+	verify_string("val", "main.sub2.sub1.key");
+}
+END_TEST
+
 START_SETUP(setup_fallback_config)
 {
 	create_settings(chunk_from_str(
@@ -904,11 +1030,10 @@ END_TEST
 START_SETUP(setup_string_config)
 {
 	create_settings(chunk_from_str(
-		"string = \"  with    accurate\twhitespace\"\n"
+		"string = \"  with    accurate\twhite\\tspace\"\n"
 		"special = \"all { special } characters # can be used.\"\n"
-		"unterminated = \"is fine\n"
-		"but = produces a warning\n"
-		"newlines = \"can either be encoded\\nor \\\n"
+		"newlines = \"can be encoded explicitly\\nor implicitly\n"
+		"or \\\n"
 		"escaped\"\n"
 		"quotes = \"\\\"and\\\" slashes \\\\ can \\\\ be\" # escaped too\n"
 		"multiple = \"strings\" are \"combined\"\n"
@@ -918,11 +1043,9 @@ END_SETUP
 
 START_TEST(test_strings)
 {
-	verify_string("  with    accurate\twhitespace", "string");
+	verify_string("  with    accurate\twhite\tspace", "string");
 	verify_string("all { special } characters # can be used.", "special");
-	verify_string("is fine", "unterminated");
-	verify_string("produces a warning", "but");
-	verify_string("can either be encoded\nor escaped", "newlines");
+	verify_string("can be encoded explicitly\nor implicitly\nor escaped", "newlines");
 	verify_string("\"and\" slashes \\ can \\ be", "quotes");
 	verify_string("strings are combined", "multiple");
 }
@@ -990,6 +1113,12 @@ START_TEST(test_invalid)
 	ck_assert(!settings->load_files(settings, path, FALSE));
 
 	contents = chunk_from_str(
+		"unterminated {\n"
+		"	strings = \"are invalid\n");
+	ck_assert(chunk_write(contents, path, 0022, TRUE));
+	ck_assert(!settings->load_files(settings, path, FALSE));
+
+	contents = chunk_from_str(
 		"spaces in name {}");
 	ck_assert(chunk_write(contents, path, 0022, TRUE));
 	ck_assert(!settings->load_files(settings, path, FALSE));
@@ -1054,12 +1183,19 @@ Suite *settings_suite_create()
 	tc = tcase_create("include/load_files[_section]");
 	tcase_add_checked_fixture(tc, setup_include_config, teardown_include_config);
 	tcase_add_test(tc, test_include);
+	tcase_add_test(tc, test_include_string);
 	tcase_add_test(tc, test_load_files);
 	tcase_add_test(tc, test_load_files_section);
 	tcase_add_test(tc, test_order_kv);
 	tcase_add_test(tc, test_order_section);
 	suite_add_tcase(s, tc);
 
+	tc = tcase_create("load_string[_section]");
+	tcase_add_checked_fixture(tc, setup_include_config, teardown_config);
+	tcase_add_test(tc, test_load_string);
+	tcase_add_test(tc, test_load_string_section);
+	suite_add_tcase(s, tc);
+
 	tc = tcase_create("fallback");
 	tcase_add_checked_fixture(tc, setup_fallback_config, teardown_config);
 	tcase_add_test(tc, test_add_fallback);
diff --git a/src/libstrongswan/tests/suites/test_traffic_selector.c b/src/libstrongswan/tests/suites/test_traffic_selector.c
index 4312c6c..bec32d2 100644
--- a/src/libstrongswan/tests/suites/test_traffic_selector.c
+++ b/src/libstrongswan/tests/suites/test_traffic_selector.c
@@ -1,4 +1,7 @@
 /*
+ * Copyright (C) 2015 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
  * Copyright (C) 2015 Martin Willi
  * Copyright (C) 2015 revosec AG
  *
@@ -22,10 +25,9 @@ static void verify(const char *str, const char *alt, traffic_selector_t *ts)
 {
 	char buf[512];
 
-	ck_assert(ts != NULL);
 	snprintf(buf, sizeof(buf), "%R", ts);
-	ts->destroy(ts);
-	if (!streq(buf, str) && !streq(buf, alt))
+	DESTROY_IF(ts);
+	if (!streq(buf, str) && (!alt || !streq(buf, alt)))
 	{
 		fail("%s != %s or %s", buf, str, alt);
 	}
@@ -43,6 +45,16 @@ START_TEST(test_create_from_string)
 	verify("fec1::/64", NULL,
 		traffic_selector_create_from_string(0, TS_IPV6_ADDR_RANGE,
 							"fec1::", 0, "fec1::ffff:ffff:ffff:ffff", 65535));
+	verify("fec1::1..fec1::ffff:ffff:ffff:ffff", NULL,
+		traffic_selector_create_from_string(0, TS_IPV6_ADDR_RANGE,
+							"fec1::1", 0, "fec1::ffff:ffff:ffff:ffff", 65535));
+
+	ck_assert(!traffic_selector_create_from_string(IPPROTO_TCP, 0,
+							"10.1.0.0", 80, "10.1.255.255", 80));
+	ck_assert(!traffic_selector_create_from_string(IPPROTO_TCP, TS_IPV4_ADDR_RANGE,
+							"a.b.c.d", 80, "10.1.255.255", 80));
+	ck_assert(!traffic_selector_create_from_string(IPPROTO_TCP, TS_IPV4_ADDR_RANGE,
+							"10.1.0.0", 80, "a.b.c.d", 80));
 }
 END_TEST
 
@@ -53,6 +65,10 @@ START_TEST(test_create_from_cidr)
 	verify("10.1.0.1/32[udp/1234-1235]", "10.1.0.1/32[17/1234-1235]",
 		traffic_selector_create_from_cidr("10.1.0.1/32", IPPROTO_UDP,
 										  1234, 1235));
+	verify("10.1.0.0/16[OPAQUE]", NULL,
+		traffic_selector_create_from_cidr("10.1.0.0/16", 0, 65535, 0));
+
+	ck_assert(!traffic_selector_create_from_cidr("a.b.c.d/16", 0, 0, 65535));
 }
 END_TEST
 
@@ -62,6 +78,16 @@ START_TEST(test_create_from_bytes)
 		traffic_selector_create_from_bytes(0, TS_IPV4_ADDR_RANGE,
 			chunk_from_chars(0x0a,0x01,0x00,0x00), 0,
 			chunk_from_chars(0x0a,0x01,0xff,0xff), 65535));
+
+	ck_assert(!traffic_selector_create_from_bytes(0, TS_IPV4_ADDR_RANGE,
+			chunk_empty, 0,
+			chunk_empty, 65535));
+	ck_assert(!traffic_selector_create_from_bytes(0, TS_IPV6_ADDR_RANGE,
+			chunk_from_chars(0x0a,0x01,0x00,0x00), 0,
+			chunk_from_chars(0x0a,0x01,0xff,0xff), 65535));
+	ck_assert(!traffic_selector_create_from_bytes(0, 0,
+			chunk_from_chars(0x0a,0x01,0x00,0x00), 0,
+			chunk_from_chars(0x0a,0x01,0xff,0xff), 65535));
 }
 END_TEST
 
@@ -73,6 +99,175 @@ START_TEST(test_create_from_subnet)
 }
 END_TEST
 
+struct {
+	char *net;
+	ts_type_t type;
+	chunk_t enc;
+} rfc3779_prefix_tests[] = {
+	/* some examples from RFC 3779, for addressPrefix elements we pass the same
+	 * value twice to the constructor */
+	{ "10.0.0.0/8",		TS_IPV4_ADDR_RANGE,	chunk_from_chars(0x00,0x0a),				},
+	{ "10.0.32.0/20",	TS_IPV4_ADDR_RANGE,	chunk_from_chars(0x04,0x0a,0x00,0x20),		},
+	{ "10.0.64.0/24",	TS_IPV4_ADDR_RANGE,	chunk_from_chars(0x00,0x0a,0x00,0x40),		},
+	{ "10.1.0.0/16",	TS_IPV4_ADDR_RANGE,	chunk_from_chars(0x00,0x0a,0x01),			},
+	{ "10.5.0.1/32",	TS_IPV4_ADDR_RANGE,	chunk_from_chars(0x00,0x0a,0x05,0x00,0x01),	},
+	{ "10.5.0.0/23",	TS_IPV4_ADDR_RANGE,	chunk_from_chars(0x01,0x0a,0x05,0x00),		},
+	{ "10.64.0.0/12",	TS_IPV4_ADDR_RANGE,	chunk_from_chars(0x04,0x0a,0x40),			},
+	{ "10.64.0.0/20",	TS_IPV4_ADDR_RANGE,	chunk_from_chars(0x04,0x0a,0x40,0x00),		},
+	{ "128.0.0.0/4",	TS_IPV4_ADDR_RANGE,	chunk_from_chars(0x04,0x80),				},
+	{ "172.16.0.0/12",	TS_IPV4_ADDR_RANGE,	chunk_from_chars(0x04,0xac,0x10),			},
+	{ "0.0.0.0/0",		TS_IPV4_ADDR_RANGE,	chunk_from_chars(0x00),						},
+	/* FIXME: not a correct encoding, so we might want to fail here */
+	{ "0.0.0.0/0",		TS_IPV4_ADDR_RANGE,	{NULL, 0},									},
+	{ "2001:0:2::/48",	TS_IPV6_ADDR_RANGE,	chunk_from_chars(0x00,0x20,0x01,0x00,0x00,0x00,0x02),},
+	{ "2001:0:200::/39",TS_IPV6_ADDR_RANGE,	chunk_from_chars(0x01,0x20,0x01,0x00,0x00,0x02),},
+	{ "::/0",			TS_IPV6_ADDR_RANGE,	chunk_from_chars(0x00),						},
+	/* FIXME: not a correct encoding, so we might want to fail here */
+	{ "::/0",			TS_IPV6_ADDR_RANGE,	{NULL, 0},									},
+};
+
+START_TEST(test_create_from_rfc3779_format_prefix)
+{
+	verify(rfc3779_prefix_tests[_i].net, NULL,
+		traffic_selector_create_from_rfc3779_format(rfc3779_prefix_tests[_i].type,
+					rfc3779_prefix_tests[_i].enc, rfc3779_prefix_tests[_i].enc));
+}
+END_TEST
+
+START_TEST(test_create_from_rfc3779_format_range)
+{
+	/* addressRange elements encode a from and to address, which may still
+	 * represent prefixes */
+	verify("10.5.0.0/23", NULL,
+		traffic_selector_create_from_rfc3779_format(TS_IPV4_ADDR_RANGE,
+					chunk_from_chars(0x00,0x0a,0x05),
+					chunk_from_chars(0x01,0x0a,0x05,0x00)));
+	verify("2001:0:200::/39", NULL,
+		traffic_selector_create_from_rfc3779_format(TS_IPV6_ADDR_RANGE,
+					chunk_from_chars(0x01,0x20,0x01,0x00,0x00,0x02),
+					chunk_from_chars(0x02,0x20,0x01,0x00,0x00,0x00)));
+	verify("10.2.48.0..10.2.64.255", NULL,
+		traffic_selector_create_from_rfc3779_format(TS_IPV4_ADDR_RANGE,
+					chunk_from_chars(0x04,0x0a,0x02,0x30),
+					chunk_from_chars(0x00,0x0a,0x02,0x40)));
+	verify("129.64.0.0..143.255.255.255", NULL,
+		traffic_selector_create_from_rfc3779_format(TS_IPV4_ADDR_RANGE,
+					chunk_from_chars(0x06,0x81,0x40),
+					chunk_from_chars(0x04,0x80)));
+}
+END_TEST
+
+
+static void verify_address(char *addr_from, char *addr_to, traffic_selector_t *ts)
+{
+	host_t *from, *to;
+
+	from = host_create_from_string(addr_from, 0);
+	to = host_create_from_string(addr_to, 0);
+
+	ck_assert_chunk_eq(from->get_address(from), ts->get_from_address(ts));
+	ck_assert_chunk_eq(to->get_address(to), ts->get_to_address(ts));
+	from->destroy(from);
+	to->destroy(to);
+	ts->destroy(ts);
+}
+
+START_TEST(test_get_address_range)
+{
+	verify_address("10.1.0.1", "10.1.0.10",
+				   traffic_selector_create_from_string(0, TS_IPV4_ADDR_RANGE,
+											"10.1.0.1", 0, "10.1.0.10", 65535));
+	/* currently not reordered */
+	verify_address("10.1.0.10", "10.1.0.1",
+				   traffic_selector_create_from_string(0, TS_IPV4_ADDR_RANGE,
+											"10.1.0.10", 0, "10.1.0.1", 65535));
+}
+END_TEST
+
+START_TEST(test_get_address_cidr)
+{
+	verify_address("10.1.0.0", "10.1.255.255",
+				   traffic_selector_create_from_cidr("10.1.0.0/16", 0, 0, 65535));
+	verify_address("fec1::", "fec1::ffff:ffff:ffff:ffff",
+				   traffic_selector_create_from_cidr("fec1::/64", 0, 0, 65535));
+}
+END_TEST
+
+struct {
+	ts_type_t type;
+	char *from;
+	char *to;
+	char *net;
+	u_int8_t mask;
+	bool exact;
+} to_subnet_tests[] = {
+	{ TS_IPV4_ADDR_RANGE,	"10.0.0.1",	"10.0.0.1",			"10.0.0.1",	32,	TRUE	},
+	{ TS_IPV4_ADDR_RANGE,	"10.0.0.0",	"10.255.255.255",	"10.0.0.0",	8,	TRUE	},
+	{ TS_IPV4_ADDR_RANGE,	"10.0.0.1",	"10.0.0.255",		"10.0.0.0",	24,	FALSE	},
+	{ TS_IPV4_ADDR_RANGE,	"10.0.0.0",	"10.0.0.15",		"10.0.0.0",	28,	TRUE	},
+	{ TS_IPV4_ADDR_RANGE,	"10.0.0.1",	"10.0.0.15",		"10.0.0.0",	28,	FALSE	},
+	{ TS_IPV4_ADDR_RANGE,	"10.0.0.1",	"10.0.0.16",		"10.0.0.0",	27,	FALSE	},
+	{ TS_IPV6_ADDR_RANGE,	"fec1::1",	"fec1::1",						"fec1::1",	128,	TRUE	},
+	{ TS_IPV6_ADDR_RANGE,	"fec1::0",	"fec1::ffff:ffff:ffff:ffff",	"fec1::",	64,		TRUE	},
+	{ TS_IPV6_ADDR_RANGE,	"fec1::1",	"fec1::ffff:ffff:ffff:ffff",	"fec1::",	64,		FALSE	},
+	{ TS_IPV6_ADDR_RANGE,	"fec1::1",	"fec1::7fff",					"fec1::",	113,	FALSE	},
+	{ TS_IPV6_ADDR_RANGE,	"fec1::1",	"fec1::efff",					"fec1::",	112,	FALSE	},
+};
+
+START_TEST(test_to_subnet)
+{
+	traffic_selector_t *ts;
+	host_t *net, *exp_net;
+	u_int8_t mask;
+
+	ts = traffic_selector_create_from_string(0, to_subnet_tests[_i].type,
+					to_subnet_tests[_i].from, 0, to_subnet_tests[_i].to, 0);
+	ck_assert(ts->to_subnet(ts, &net, &mask) == to_subnet_tests[_i].exact);
+	exp_net = host_create_from_string(to_subnet_tests[_i].net, 0);
+	ck_assert(exp_net->ip_equals(exp_net, net));
+	ck_assert_int_eq(to_subnet_tests[_i].mask, mask);
+	exp_net->destroy(exp_net);
+	net->destroy(net);
+	ts->destroy(ts);
+}
+END_TEST
+
+struct {
+	char *cidr;
+	u_int16_t from_port;
+	u_int16_t to_port;
+	u_int16_t port;
+} to_subnet_port_tests[] = {
+	{ "10.0.0.0/8",		0,		0,		0	},
+	{ "10.0.0.1/32",	80,		80,		80	},
+	{ "10.0.0.1/32",	123,	465,	0	},
+	{ "0.0.0.0/0",		0,		65535,	0	},
+	{ "fec1::/64",		0,		0,		0	},
+	{ "fec1::1/128",	80,		80,		80	},
+	{ "fec1::1/128",	123,	465,	0	},
+	{ "::/0",			0,		65535,	0	},
+};
+
+START_TEST(test_to_subnet_port)
+{
+	traffic_selector_t *ts;
+	host_t *net, *exp_net;
+	u_int8_t mask;
+	int exp_mask;
+
+	ts = traffic_selector_create_from_cidr(to_subnet_port_tests[_i].cidr, 0,
+										   to_subnet_port_tests[_i].from_port,
+										   to_subnet_port_tests[_i].to_port);
+	ck_assert(ts->to_subnet(ts, &net, &mask));
+	exp_net = host_create_from_subnet(to_subnet_port_tests[_i].cidr, &exp_mask);
+	ck_assert(exp_net->ip_equals(exp_net, net));
+	ck_assert_int_eq(exp_mask, mask);
+	ck_assert_int_eq(to_subnet_port_tests[_i].port, net->get_port(net));
+	exp_net->destroy(exp_net);
+	net->destroy(net);
+	ts->destroy(ts);
+}
+END_TEST
 
 START_TEST(test_subset)
 {
@@ -81,6 +276,14 @@ START_TEST(test_subset)
 	a = traffic_selector_create_from_cidr("10.1.0.0/16", 0, 0, 65535);
 	b = traffic_selector_create_from_cidr("10.1.5.0/24", 0, 0, 65535);
 	verify("10.1.5.0/24", NULL, a->get_subset(a, b));
+	verify("10.1.5.0/24", NULL, b->get_subset(b, a));
+	a->destroy(a);
+	b->destroy(b);
+
+	a = traffic_selector_create_from_cidr("fec1::/64", 0, 0, 65535);
+	b = traffic_selector_create_from_cidr("fec1::1/128", 0, 0, 65535);
+	verify("fec1::1/128", NULL, a->get_subset(a, b));
+	verify("fec1::1/128", NULL, b->get_subset(b, a));
 	a->destroy(a);
 	b->destroy(b);
 }
@@ -117,7 +320,7 @@ START_TEST(test_subset_nonet)
 
 	a = traffic_selector_create_from_cidr("10.1.0.0/16", 0, 0, 65535);
 	b = traffic_selector_create_from_cidr("10.2.0.0/16", 0, 0, 65535);
-	ck_assert(a->get_subset(a, b) == NULL);
+	ck_assert(!a->get_subset(a, b));
 	a->destroy(a);
 	b->destroy(b);
 }
@@ -129,7 +332,7 @@ START_TEST(test_subset_noport)
 
 	a = traffic_selector_create_from_cidr("10.1.0.0/16", 0, 0, 9999);
 	b = traffic_selector_create_from_cidr("10.1.0.0/16", 0, 10000, 65535);
-	ck_assert(a->get_subset(a, b) == NULL);
+	ck_assert(!a->get_subset(a, b));
 	a->destroy(a);
 	b->destroy(b);
 }
@@ -141,7 +344,7 @@ START_TEST(test_subset_noproto)
 
 	a = traffic_selector_create_from_cidr("10.1.0.0/16", IPPROTO_TCP, 0, 65535);
 	b = traffic_selector_create_from_cidr("10.1.0.0/16", IPPROTO_UDP, 0, 65535);
-	ck_assert(a->get_subset(a, b) == NULL);
+	ck_assert(!a->get_subset(a, b));
 	a->destroy(a);
 	b->destroy(b);
 }
@@ -153,7 +356,43 @@ START_TEST(test_subset_nofamily)
 
 	a = traffic_selector_create_from_cidr("0.0.0.0/0", 0, 0, 65535);
 	b = traffic_selector_create_from_cidr("::/0", 0, 0, 65535);
-	ck_assert(a->get_subset(a, b) == NULL);
+	ck_assert(!a->get_subset(a, b));
+	a->destroy(a);
+	b->destroy(b);
+}
+END_TEST
+
+START_TEST(test_subset_dynamic)
+{
+	traffic_selector_t *a, *b;
+
+	a = traffic_selector_create_dynamic(0, 0, 65535);
+	b = traffic_selector_create_from_cidr("10.1.0.0/16", 0, 0, 65535);
+	ck_assert(!a->get_subset(a, b));
+	ck_assert(!b->get_subset(b, a));
+	a->destroy(a);
+	b->destroy(b);
+}
+END_TEST
+
+START_TEST(test_subset_opaque)
+{
+	traffic_selector_t *a, *b;
+
+	a = traffic_selector_create_from_cidr("10.0.0.0/8", 0, 65535, 0);
+	b = traffic_selector_create_from_cidr("10.2.7.16/30", IPPROTO_TCP, 80, 80);
+	ck_assert(!a->get_subset(a, b));
+	ck_assert(!b->get_subset(b, a));
+	b->destroy(b);
+
+	b = traffic_selector_create_from_cidr("10.2.7.16/30", IPPROTO_TCP, 65535, 0);
+	verify("10.2.7.16/30[tcp/OPAQUE]", "10.2.7.16/30[6/OPAQUE]", a->get_subset(a, b));
+	verify("10.2.7.16/30[tcp/OPAQUE]", "10.2.7.16/30[6/OPAQUE]", b->get_subset(b, a));
+	b->destroy(b);
+
+	b = traffic_selector_create_from_cidr("10.2.7.16/30", IPPROTO_TCP, 0, 65535);
+	verify("10.2.7.16/30[tcp/OPAQUE]", "10.2.7.16/30[6/OPAQUE]", a->get_subset(a, b));
+	verify("10.2.7.16/30[tcp/OPAQUE]", "10.2.7.16/30[6/OPAQUE]", b->get_subset(b, a));
 	a->destroy(a);
 	b->destroy(b);
 }
@@ -189,6 +428,130 @@ START_TEST(test_includes)
 END_TEST
 
 struct {
+	bool contained;
+	struct {
+		char *net;
+		u_int8_t proto;
+		u_int16_t from_port;
+		u_int16_t to_port;
+	} a, b;
+} is_contained_in_tests[] = {
+	{  TRUE,  { "10.0.0.0/16", 0, 0, 65535 },	{ "10.0.0.0/16", 0, 0, 65535 },	},
+	{  TRUE,  { "10.0.1.0/24", 0, 0, 65535 },	{ "10.0.0.0/16", 0, 0, 65535 },	},
+	{  TRUE,  { "10.0.1.0/24", 17, 123, 456 },	{ "10.0.0.0/16", 0, 0, 65535 },	},
+	{  TRUE,  { "10.0.1.0/24", 17, 123, 456 },	{ "10.0.0.0/16", 17, 123, 456 },},
+	{  FALSE, { "10.0.0.0/8", 0, 0, 65535 },	{ "10.0.0.0/16", 0, 0, 65535 },	},
+	{  FALSE, { "10.0.1.0/24", 17, 0, 65535 },	{ "10.0.0.0/16", 17, 123, 456 },},
+	{  FALSE, { "fec2::/64", 0, 0, 65535 },		{ "10.0.0.0/16", 17, 123, 456 },},
+};
+
+START_TEST(test_is_contained_in)
+{
+	traffic_selector_t *a, *b;
+
+	a = traffic_selector_create_from_cidr(
+			is_contained_in_tests[_i].a.net, is_contained_in_tests[_i].a.proto,
+			is_contained_in_tests[_i].a.from_port, is_contained_in_tests[_i].a.to_port);
+	b = traffic_selector_create_from_cidr(
+			is_contained_in_tests[_i].b.net, is_contained_in_tests[_i].b.proto,
+			is_contained_in_tests[_i].b.from_port, is_contained_in_tests[_i].b.to_port);
+	ck_assert(a->is_contained_in(a, b) == is_contained_in_tests[_i].contained);
+	a->destroy(a);
+	b->destroy(b);
+}
+END_TEST
+
+struct {
+	char *net;
+	char *host;
+	bool is_host;
+	bool when_null;
+} is_host_tests[] = {
+	{ "0.0.0.0/0",		"192.168.1.2",	FALSE, FALSE },
+	{ "::/0",			"fec2::1",		FALSE, FALSE },
+	{ "192.168.1.2/32",	"192.168.1.2",	TRUE,  TRUE },
+	{ "192.168.1.2/32",	"192.168.1.1",	FALSE, TRUE },
+	{ "192.168.1.2/32",	"fec2::1",		FALSE, TRUE },
+	{ "fec2::1/128",	"fec2::1",		TRUE,  TRUE },
+	{ "fec2::1/128",	"fec2::2",		FALSE, TRUE },
+	{ "fec2::1/128",	"192.168.1.2",	FALSE, TRUE },
+};
+
+START_TEST(test_is_host)
+{
+	traffic_selector_t *ts;
+	host_t *h;
+
+	ts = traffic_selector_create_from_cidr(is_host_tests[_i].net, 0, 0, 65535);
+	h = host_create_from_string(is_host_tests[_i].host, 0);
+	ck_assert(ts->is_host(ts, h) == is_host_tests[_i].is_host);
+	ck_assert(ts->is_host(ts, NULL) == is_host_tests[_i].when_null);
+	ts->destroy(ts);
+	h->destroy(h);
+}
+END_TEST
+
+START_TEST(test_is_host_dynamic)
+{
+	traffic_selector_t *ts;
+	host_t *h;
+
+	ts = traffic_selector_create_dynamic(0, 0, 65535);
+	h = host_create_from_string(is_host_tests[_i].host, 0);
+	ck_assert(!ts->is_host(ts, h));
+	ck_assert(ts->is_host(ts, NULL));
+	ts->destroy(ts);
+	h->destroy(h);
+}
+END_TEST
+
+
+struct {
+	char *orig;
+	char *host;
+	char *after;
+} set_address_tests[] = {
+	{ "0.0.0.0/0",		"192.168.1.2",	"0.0.0.0/0" },
+	{ "::/0",			"fec2::1",		"::/0" },
+	{ "192.168.1.2/32",	"192.168.1.1",	"192.168.1.1/32" },
+	{ "192.168.1.2/32",	"fec2::1",		"fec2::1/128" },
+	{ "192.168.1.2/32",	"%any",			"0.0.0.0/0" },
+	{ "192.168.1.2/32",	"%any6",		"::/0" },
+	{ "fec2::1/128",	"192.168.1.1",	"192.168.1.1/32" },
+	{ "fec2::1/128",	"fec2::2",		"fec2::2/128" },
+	{ "fec2::1/128",	"%any",			"0.0.0.0/0" },
+	{ "fec2::1/128",	"%any6",		"::/0" },
+	{ NULL,				"192.168.1.1",	"192.168.1.1/32" },
+	{ NULL,				"fec2::1",		"fec2::1/128" },
+	{ NULL,				"%any",			"0.0.0.0/0" },
+	{ NULL,				"%any6",		"::/0" },
+};
+
+START_TEST(test_set_address)
+{
+	traffic_selector_t *ts;
+	host_t *h;
+
+	if (set_address_tests[_i].orig)
+	{
+		ts = traffic_selector_create_from_cidr(set_address_tests[_i].orig, 0, 0, 65535);
+		ck_assert(!ts->is_dynamic(ts));
+	}
+	else
+	{
+		ts = traffic_selector_create_dynamic(0, 0, 65535);
+		ck_assert(ts->is_dynamic(ts));
+	}
+	h = host_create_from_string(set_address_tests[_i].host, 0);
+	ts->set_address(ts, h);
+	ck_assert(!ts->is_dynamic(ts));
+	verify(set_address_tests[_i].after, NULL, ts);
+	h->destroy(h);
+}
+END_TEST
+
+
+struct {
 	int res;
 	struct {
 		char *net;
@@ -206,6 +569,10 @@ struct {
 	{  1, { "2.0.0.0/8", 0, 0, 65535 },		{ "1.0.0.0/8", 0, 0, 65535 },	},
 	{ -1, { "1.0.0.0/8", 0, 0, 65535 },		{ "1.0.0.0/16", 0, 0, 65535 },	},
 	{  1, { "1.0.0.0/16", 0, 0, 65535 },	{ "1.0.0.0/8", 0, 0, 65535 },	},
+	{ -1, { "fec1::/64", 0, 0, 65535 },		{ "fec2::/64", 0, 0, 65535 },	},
+	{  1, { "fec2::/64", 0, 0, 65535 },		{ "fec1::/64", 0, 0, 65535 },	},
+	{ -1, { "fec1::/48", 0, 0, 65535 },		{ "fec1::/64", 0, 0, 65535 },	},
+	{  1, { "fec1::/64", 0, 0, 65535 },		{ "fec1::/48", 0, 0, 65535 },	},
 
 	{ -1, { "10.0.0.0/8", 0, 0, 65535 },	{ "fec2::/64", 0, 0, 65535 },	},
 	{  1, { "fec2::/64", 0, 0, 65535 },		{ "10.0.0.0/8", 0, 0, 65535 },	},
@@ -235,12 +602,15 @@ START_TEST(test_cmp)
 	{
 		case 0:
 			ck_assert(traffic_selector_cmp(a, b, NULL) == 0);
+			ck_assert(a->equals(a, b));
 			break;
 		case 1:
 			ck_assert(traffic_selector_cmp(a, b, NULL) > 0);
+			ck_assert(!a->equals(a, b));
 			break;
 		case -1:
 			ck_assert(traffic_selector_cmp(a, b, NULL) < 0);
+			ck_assert(!a->equals(a, b));
 			break;
 	}
 	a->destroy(a);
@@ -248,6 +618,172 @@ START_TEST(test_cmp)
 }
 END_TEST
 
+static void verify_clone(traffic_selector_t *ts)
+{
+	traffic_selector_t *clone;
+
+	clone = ts->clone(ts);
+	if (!ts->equals(ts, clone))
+	{
+		fail("%R != %R", ts, clone);
+	}
+	/* equals() already compares most of these but not all */
+	ck_assert(ts->get_type(ts) == clone->get_type(clone));
+	ck_assert(ts->get_protocol(ts) == clone->get_protocol(clone));
+	ck_assert(ts->get_from_port(ts) == clone->get_from_port(clone));
+	ck_assert(ts->get_to_port(ts) == clone->get_to_port(clone));
+	ck_assert_chunk_eq(ts->get_from_address(ts), clone->get_from_address(clone));
+	ck_assert_chunk_eq(ts->get_to_address(ts), clone->get_to_address(clone));
+	ck_assert(ts->is_host(ts, NULL) == clone->is_host(clone, NULL));
+	ck_assert(ts->is_dynamic(ts) == clone->is_dynamic(clone));
+	clone->destroy(clone);
+	ts->destroy(ts);
+}
+
+START_TEST(test_clone)
+{
+	traffic_selector_t *ts;
+	host_t *h;
+
+	ts = traffic_selector_create_dynamic(0, 0, 0);
+	verify_clone(ts);
+	ts = traffic_selector_create_dynamic(IPPROTO_UDP, 123, 456);
+	verify_clone(ts);
+	ts = traffic_selector_create_dynamic(IPPROTO_UDP, 0, 65535);
+	verify_clone(ts);
+
+	h = host_create_from_string("192.168.1.1", 0);
+	ts = traffic_selector_create_dynamic(0, 0, 0);
+	ts->set_address(ts, h);
+	verify_clone(ts);
+	ts = traffic_selector_create_dynamic(IPPROTO_UDP, 123, 456);
+	ts->set_address(ts, h);
+	verify_clone(ts);
+	h->destroy(h);
+
+	ts = traffic_selector_create_from_string(0, TS_IPV4_ADDR_RANGE, "10.0.0.1", 0, "10.0.0.16", 65535);
+	verify_clone(ts);
+	ts = traffic_selector_create_from_string(IPPROTO_TCP, TS_IPV6_ADDR_RANGE, "fec1::1", 80, "fec1::1:0000", 80);
+	verify_clone(ts);
+	ts = traffic_selector_create_from_cidr("10.0.0.0/8", 0, 0, 65535);
+	verify_clone(ts);
+	ts = traffic_selector_create_from_cidr("fec1::/64", 0, 0, 65535);
+	verify_clone(ts);
+}
+END_TEST
+
+START_TEST(test_hash)
+{
+	traffic_selector_t *a, *b;
+	host_t *h;
+
+	a = traffic_selector_create_dynamic(0, 0, 0);
+	b = traffic_selector_create_from_cidr("0.0.0.0/0", 0, 0, 0);
+	ck_assert(a->hash(a, 0) != a->hash(a, 1));
+	ck_assert_int_eq(a->hash(a, 0), b->hash(b, 0));
+	ck_assert_int_eq(a->hash(a, 1), b->hash(b, 1));
+
+	h = host_create_from_string("192.168.1.1", 0);
+	a->set_address(a, h);
+	ck_assert(a->hash(a, 0) != b->hash(b, 0));
+	h->destroy(h);
+
+	a->destroy(a);
+	a = traffic_selector_create_from_string(0, TS_IPV4_ADDR_RANGE, "192.168.0.0", 0, "192.168.0.255", 65535);
+	ck_assert(a->hash(a, 0) != b->hash(b, 0));
+	b->destroy(b);
+	b = traffic_selector_create_from_cidr("192.168.0.0/24", 0, 0, 65535);
+	ck_assert_int_eq(a->hash(a, 0), b->hash(b, 0));
+	b->destroy(b);
+	b = traffic_selector_create_from_cidr("192.168.0.0/24", IPPROTO_TCP, 0, 65535);
+	ck_assert(a->hash(a, 0) != b->hash(b, 0));
+	b->destroy(b);
+	b = traffic_selector_create_from_cidr("192.168.0.0/24", 0, 123, 456);
+	ck_assert(a->hash(a, 0) != b->hash(b, 0));
+	b->destroy(b);
+	a->destroy(a);
+}
+END_TEST
+
+struct {
+	u_int8_t proto;
+	u_int16_t from_port;
+	u_int16_t to_port;
+	u_int8_t from_type;
+	u_int8_t from_code;
+	u_int8_t to_type;
+	u_int8_t to_code;
+	char *str;
+	char *str_alt;
+} icmp_tests[] = {
+	{ IPPROTO_ICMP, 0, 0, 0, 0, 0, 0, "dynamic[icmp/0]", "dynamic[1/0]" },
+	{ IPPROTO_ICMP, 3, 3, 3, 0, 3, 0, "dynamic[icmp/3]", "dynamic[1/3]" },
+	{ IPPROTO_ICMP, 0x0307, 0x0307, 3, 7, 3, 7, "dynamic[icmp/3(7)]", "dynamic[1/3(7)]" },
+	{ IPPROTO_ICMP, 0x0300, 0x040f, 3, 0, 4, 15, "dynamic[icmp/3-4(15)]", "dynamic[1/3-4(15)]" },
+	{ IPPROTO_ICMP, 0x0301, 0x040f, 3, 1, 4, 15, "dynamic[icmp/3(1)-4(15)]", "dynamic[1/3(1)-4(15)]" },
+	{ IPPROTO_ICMPV6, 0, 0, 0, 0, 0, 0, "dynamic[ipv6-icmp/0]", "dynamic[58/0]" },
+	{ IPPROTO_ICMPV6, 1, 1, 1, 0, 1, 0, "dynamic[ipv6-icmp/1]", "dynamic[58/1]" },
+	{ IPPROTO_ICMPV6, 0x0104, 0x0104, 1, 4, 1, 4, "dynamic[ipv6-icmp/1(4)]", "dynamic[58/1(4)]" },
+	{ IPPROTO_ICMPV6, 0x0100, 0x040f, 1, 0, 4, 15, "dynamic[ipv6-icmp/1-4(15)]", "dynamic[58/1-4(15)]" },
+	{ IPPROTO_ICMPV6, 0x0101, 0x040f, 1, 1, 4, 15, "dynamic[ipv6-icmp/1(1)-4(15)]", "dynamic[58/1(1)-4(15)]" },
+};
+
+START_TEST(test_icmp)
+{
+	traffic_selector_t *ts;
+	u_int16_t from, to;
+
+	ts = traffic_selector_create_dynamic(icmp_tests[_i].proto,
+							icmp_tests[_i].from_port, icmp_tests[_i].to_port);
+	from = ts->get_from_port(ts);
+	to = ts->get_to_port(ts);
+	ck_assert_int_eq(icmp_tests[_i].from_type, traffic_selector_icmp_type(from));
+	ck_assert_int_eq(icmp_tests[_i].from_code, traffic_selector_icmp_code(from));
+	ck_assert_int_eq(icmp_tests[_i].to_type, traffic_selector_icmp_type(to));
+	ck_assert_int_eq(icmp_tests[_i].to_code, traffic_selector_icmp_code(to));
+	verify(icmp_tests[_i].str, icmp_tests[_i].str_alt, ts);
+}
+END_TEST
+
+static void verify_list(const char *str, const char *alt, linked_list_t *list)
+{
+	char buf[512];
+
+	snprintf(buf, sizeof(buf), "%#R", list);
+	list->destroy_offset(list, offsetof(traffic_selector_t, destroy));
+	if (!streq(buf, str) && !streq(buf, alt))
+	{
+		fail("%s != %s or %s", buf, str, alt);
+	}
+}
+
+START_TEST(test_printf_hook_null)
+{
+	verify("(null)", NULL, NULL);
+}
+END_TEST
+
+START_TEST(test_printf_hook_hash)
+{
+	linked_list_t *list;
+
+	list = linked_list_create_with_items(
+				traffic_selector_create_from_cidr("10.1.0.0/16", 0, 0, 65535),
+				NULL);
+	verify_list("10.1.0.0/16 ", NULL, list);
+	list = linked_list_create_with_items(
+				traffic_selector_create_from_cidr("10.1.0.0/16", 0, 0, 65535),
+				traffic_selector_create_from_cidr("10.1.0.1/32", IPPROTO_UDP, 1234, 1235),
+				NULL);
+	verify_list("10.1.0.0/16 10.1.0.1/32[udp/1234-1235] ", "10.1.0.0/16 10.1.0.1/32[17/1234-1235] ", list);
+	list = linked_list_create_with_items(
+				traffic_selector_create_from_cidr("10.1.0.0/16", 0, 0, 65535),
+				traffic_selector_create_from_string(IPPROTO_UDP, TS_IPV4_ADDR_RANGE, "10.1.0.1", 1234, "10.1.0.99", 1235),
+				NULL);
+	verify_list("10.1.0.0/16 10.1.0.1..10.1.0.99[udp/1234-1235] ", "10.1.0.0/16 10.1.0.1..10.1.0.99[17/1234-1235] ", list);
+}
+END_TEST
+
 Suite *traffic_selector_suite_create()
 {
 	Suite *s;
@@ -260,6 +796,18 @@ Suite *traffic_selector_suite_create()
 	tcase_add_test(tc, test_create_from_cidr);
 	tcase_add_test(tc, test_create_from_bytes);
 	tcase_add_test(tc, test_create_from_subnet);
+	tcase_add_loop_test(tc, test_create_from_rfc3779_format_prefix, 0, countof(rfc3779_prefix_tests));
+	tcase_add_test(tc, test_create_from_rfc3779_format_range);
+	suite_add_tcase(s, tc);
+
+	tc = tcase_create("addresses");
+	tcase_add_test(tc, test_get_address_range);
+	tcase_add_test(tc, test_get_address_cidr);
+	suite_add_tcase(s, tc);
+
+	tc = tcase_create("to_subnet");
+	tcase_add_loop_test(tc, test_to_subnet, 0, countof(to_subnet_tests));
+	tcase_add_loop_test(tc, test_to_subnet_port, 0, countof(to_subnet_port_tests));
 	suite_add_tcase(s, tc);
 
 	tc = tcase_create("subset");
@@ -270,15 +818,47 @@ Suite *traffic_selector_suite_create()
 	tcase_add_test(tc, test_subset_noport);
 	tcase_add_test(tc, test_subset_noproto);
 	tcase_add_test(tc, test_subset_nofamily);
+	tcase_add_test(tc, test_subset_dynamic);
+	tcase_add_test(tc, test_subset_opaque);
 	suite_add_tcase(s, tc);
 
 	tc = tcase_create("includes");
 	tcase_add_loop_test(tc, test_includes, 0, countof(include_tests));
 	suite_add_tcase(s, tc);
 
+	tc = tcase_create("is_contained_in");
+	tcase_add_loop_test(tc, test_is_contained_in, 0, countof(is_contained_in_tests));
+	suite_add_tcase(s, tc);
+
+	tc = tcase_create("is_host");
+	tcase_add_loop_test(tc, test_is_host, 0, countof(is_host_tests));
+	tcase_add_loop_test(tc, test_is_host_dynamic, 0, countof(is_host_tests));
+	suite_add_tcase(s, tc);
+
+	tc = tcase_create("set_address");
+	tcase_add_loop_test(tc, test_set_address, 0, countof(is_host_tests));
+	suite_add_tcase(s, tc);
+
 	tc = tcase_create("cmp");
 	tcase_add_loop_test(tc, test_cmp, 0, countof(cmp_tests));
 	suite_add_tcase(s, tc);
 
+	tc = tcase_create("clone");
+	tcase_add_test(tc, test_clone);
+	suite_add_tcase(s, tc);
+
+	tc = tcase_create("hash");
+	tcase_add_test(tc, test_hash);
+	suite_add_tcase(s, tc);
+
+	tc = tcase_create("icmp");
+	tcase_add_loop_test(tc, test_icmp, 0, countof(icmp_tests));
+	suite_add_tcase(s, tc);
+
+	tc = tcase_create("printf hook");
+	tcase_add_test(tc, test_printf_hook_null);
+	tcase_add_test(tc, test_printf_hook_hash);
+	suite_add_tcase(s, tc);
+
 	return s;
 }
diff --git a/src/libstrongswan/tests/test_runner.c b/src/libstrongswan/tests/test_runner.c
index 0bae9c8..66d0e61 100644
--- a/src/libstrongswan/tests/test_runner.c
+++ b/src/libstrongswan/tests/test_runner.c
@@ -265,7 +265,7 @@ static bool pre_test(test_runner_init_t init, char *cfg)
  */
 typedef struct {
 	char *name;
-	char msg[512 - sizeof(char*) - 2 * sizeof(int)];
+	char msg[4096 - sizeof(char*) - 2 * sizeof(int)];
 	const char *file;
 	int line;
 	int i;
diff --git a/src/libstrongswan/tests/test_suite.c b/src/libstrongswan/tests/test_suite.c
index 00ac318..0af34c8 100644
--- a/src/libstrongswan/tests/test_suite.c
+++ b/src/libstrongswan/tests/test_suite.c
@@ -27,7 +27,7 @@
 /**
  * Failure message buf
  */
-static char failure_buf[512];
+static char failure_buf[4096];
 
 /**
  * Source file failure occurred
diff --git a/src/libstrongswan/tests/tests.c b/src/libstrongswan/tests/tests.c
index aed600f..0fdfac5 100644
--- a/src/libstrongswan/tests/tests.c
+++ b/src/libstrongswan/tests/tests.c
@@ -25,8 +25,8 @@
 static test_configuration_t tests[] = {
 #define TEST_SUITE(x) \
 	{ .suite = x, },
-#define TEST_SUITE_DEPEND(x, type, args) \
-	{ .suite = x, .feature = PLUGIN_DEPENDS(type, args) },
+#define TEST_SUITE_DEPEND(x, type, ...) \
+	{ .suite = x, .feature = PLUGIN_DEPENDS(type, __VA_ARGS__) },
 #include "tests.h"
 	{ .suite = NULL, }
 };
diff --git a/src/libstrongswan/utils/capabilities.c b/src/libstrongswan/utils/capabilities.c
index 923b7d4..ce5f550 100644
--- a/src/libstrongswan/utils/capabilities.c
+++ b/src/libstrongswan/utils/capabilities.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012-2013 Tobias Brunner
+ * Copyright (C) 2012-2015 Tobias Brunner
  * Hochschule fuer Technik Rapperswil
  * Copyright (C) 2012 Martin Willi
  * Copyright (C) 2012 revosec AG
@@ -288,13 +288,25 @@ METHOD(capabilities_t, resolve_uid, bool,
 
 #ifdef HAVE_GETPWNAM_R
 	struct passwd passwd;
-	char buf[1024];
+	size_t buflen = 1024;
+	char *buf = NULL;
 
-	err = getpwnam_r(username, &passwd, buf, sizeof(buf), &pwp);
-	if (pwp)
+	while (TRUE)
 	{
-		this->uid = pwp->pw_uid;
+		buf = realloc(buf, buflen);
+		err = getpwnam_r(username, &passwd, buf, buflen, &pwp);
+		if (err == ERANGE)
+		{
+			buflen *= 2;
+			continue;
+		}
+		if (pwp)
+		{
+			this->uid = pwp->pw_uid;
+		}
+		break;
 	}
+	free(buf);
 #else /* HAVE GETPWNAM_R */
 	this->mutex->lock(this->mutex);
 	pwp = getpwnam(username);
@@ -324,13 +336,25 @@ METHOD(capabilities_t, resolve_gid, bool,
 
 #ifdef HAVE_GETGRNAM_R
 	struct group group;
-	char buf[1024];
+	size_t buflen = 1024;
+	char *buf = NULL;
 
-	err = getgrnam_r(groupname, &group, buf, sizeof(buf), &grp);
-	if (grp)
+	while (TRUE)
 	{
-		this->gid = grp->gr_gid;
+		buf = realloc(buf, buflen);
+		err = getgrnam_r(groupname, &group, buf, buflen, &grp);
+		if (err == ERANGE)
+		{
+			buflen *= 2;
+			continue;
+		}
+		if (grp)
+		{
+			this->gid = grp->gr_gid;
+		}
+		break;
 	}
+	free(buf);
 #else /* HAVE_GETGRNAM_R */
 	this->mutex->lock(this->mutex);
 	grp = getgrnam(groupname);
@@ -362,12 +386,24 @@ static bool init_supplementary_groups(private_capabilities_t *this)
 
 #ifdef HAVE_GETPWUID_R
 	struct passwd pwd;
-	char buf[1024];
+	size_t buflen = 1024;
+	char *buf = NULL;
 
-	if (getpwuid_r(this->uid, &pwd, buf, sizeof(buf), &pwp) == 0 && pwp)
+	while (TRUE)
 	{
-		res = initgroups(pwp->pw_name, this->gid);
+		buf = realloc(buf, buflen);
+		if (getpwuid_r(this->uid, &pwd, buf, buflen, &pwp) == ERANGE)
+		{
+			buflen *= 2;
+			continue;
+		}
+		if (pwp)
+		{
+			res = initgroups(pwp->pw_name, this->gid);
+		}
+		break;
 	}
+	free(buf);
 #else /* HAVE_GETPWUID_R */
 	this->mutex->lock(this->mutex);
 	pwp = getpwuid(this->uid);
diff --git a/src/libstrongswan/utils/identification.c b/src/libstrongswan/utils/identification.c
index b69adf3..da23d14 100644
--- a/src/libstrongswan/utils/identification.c
+++ b/src/libstrongswan/utils/identification.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009-2012 Tobias Brunner
+ * Copyright (C) 2009-2015 Tobias Brunner
  * Copyright (C) 2005-2009 Martin Willi
  * Copyright (C) 2005 Jan Hutter
  * Hochschule fuer Technik Rapperswil
@@ -47,10 +47,9 @@ ENUM_BEGIN(id_type_names, ID_ANY, ID_KEY_ID,
 	"ID_DER_ASN1_DN",
 	"ID_DER_ASN1_GN",
 	"ID_KEY_ID");
-ENUM_NEXT(id_type_names, ID_DER_ASN1_GN_URI, ID_USER_ID, ID_KEY_ID,
-	"ID_DER_ASN1_GN_URI",
-	"ID_USER_ID");
-ENUM_END(id_type_names, ID_USER_ID);
+ENUM_NEXT(id_type_names, ID_DER_ASN1_GN_URI, ID_DER_ASN1_GN_URI, ID_KEY_ID,
+	"ID_DER_ASN1_GN_URI");
+ENUM_END(id_type_names, ID_DER_ASN1_GN_URI);
 
 /**
  * coding of X.501 distinguished name
@@ -478,7 +477,7 @@ static status_t atodn(char *src, chunk_t *dn)
 					name.len -= whitespace;
 					rdn_type = (x501rdns[i].type == ASN1_PRINTABLESTRING
 								&& !asn1_is_printablestring(name))
-								? ASN1_T61STRING : x501rdns[i].type;
+								? ASN1_UTF8STRING : x501rdns[i].type;
 
 					if (rdn_count < RDN_MAX)
 					{
@@ -579,6 +578,19 @@ METHOD(identification_t, contains_wildcards_memchr, bool,
 	return memchr(this->encoded.ptr, '*', this->encoded.len) != NULL;
 }
 
+METHOD(identification_t, hash_binary, u_int,
+	private_identification_t *this, u_int inc)
+{
+	u_int hash;
+
+	hash = chunk_hash_inc(chunk_from_thing(this->type), inc);
+	if (this->type != ID_ANY)
+	{
+		hash = chunk_hash_inc(this->encoded, hash);
+	}
+	return hash;
+}
+
 METHOD(identification_t, equals_binary, bool,
 	private_identification_t *this, identification_t *other)
 {
@@ -687,6 +699,24 @@ METHOD(identification_t, equals_dn, bool,
 	return compare_dn(this->encoded, other->get_encoding(other), NULL);
 }
 
+METHOD(identification_t, hash_dn, u_int,
+	private_identification_t *this, u_int inc)
+{
+	enumerator_t *rdns;
+	chunk_t oid, data;
+	u_char type;
+	u_int hash;
+
+	hash = chunk_hash_inc(chunk_from_thing(this->type), inc);
+	rdns = create_rdn_enumerator(this->encoded);
+	while (rdns->enumerate(rdns, &oid, &type, &data))
+	{
+		hash = chunk_hash_inc(data, chunk_hash_inc(oid, hash));
+	}
+	rdns->destroy(rdns);
+	return hash;
+}
+
 METHOD(identification_t, equals_strcasecmp,  bool,
 	private_identification_t *this, identification_t *other)
 {
@@ -828,7 +858,6 @@ int identification_printf_hook(printf_hook_data_t *data,
 		case ID_FQDN:
 		case ID_RFC822_ADDR:
 		case ID_DER_ASN1_GN_URI:
-		case ID_USER_ID:
 			chunk_printable(this->encoded, &proper, '?');
 			snprintf(buf, sizeof(buf), "%.*s", (int)proper.len, proper.ptr);
 			chunk_free(&proper);
@@ -903,23 +932,26 @@ static private_identification_t *identification_create(id_type_t type)
 	switch (type)
 	{
 		case ID_ANY:
+			this->public.hash = _hash_binary;
 			this->public.matches = _matches_any;
 			this->public.equals = _equals_binary;
 			this->public.contains_wildcards = return_true;
 			break;
 		case ID_FQDN:
 		case ID_RFC822_ADDR:
-		case ID_USER_ID:
+			this->public.hash = _hash_binary;
 			this->public.matches = _matches_string;
 			this->public.equals = _equals_strcasecmp;
 			this->public.contains_wildcards = _contains_wildcards_memchr;
 			break;
 		case ID_DER_ASN1_DN:
+			this->public.hash = _hash_dn;
 			this->public.equals = _equals_dn;
 			this->public.matches = _matches_dn;
 			this->public.contains_wildcards = _contains_wildcards_dn;
 			break;
 		default:
+			this->public.hash = _hash_binary;
 			this->public.equals = _equals_binary;
 			this->public.matches = _matches_binary;
 			this->public.contains_wildcards = return_false;
diff --git a/src/libstrongswan/utils/identification.h b/src/libstrongswan/utils/identification.h
index e6a9fe1..5f27ba1 100644
--- a/src/libstrongswan/utils/identification.h
+++ b/src/libstrongswan/utils/identification.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 Tobias Brunner
+ * Copyright (C) 2009-2015 Tobias Brunner
  * Copyright (C) 2005-2009 Martin Willi
  * Copyright (C) 2005 Jan Hutter
  * Hochschule fuer Technik Rapperswil
@@ -129,11 +129,6 @@ enum id_type_t {
 	 * Private ID type which represents a GeneralName of type URI
 	 */
 	ID_DER_ASN1_GN_URI = 201,
-
-	/**
-	 * Private ID type which represents a user ID
-	 */
-	ID_USER_ID = 202
 };
 
 /**
@@ -219,6 +214,14 @@ struct identification_t {
 	id_type_t (*get_type) (identification_t *this);
 
 	/**
+	 * Create a hash value for this identification_t object.
+	 *
+	 * @param inc		optional value for incremental hashing
+	 * @return			hash value
+	 */
+	u_int (*hash) (identification_t *this, u_int inc);
+
+	/**
 	 * Check if two identification_t objects are equal.
 	 *
 	 * @param other		other identification_t object
diff --git a/src/libstrongswan/utils/printf_hook/printf_hook_builtin.c b/src/libstrongswan/utils/printf_hook/printf_hook_builtin.c
index 466c673..af54940 100644
--- a/src/libstrongswan/utils/printf_hook/printf_hook_builtin.c
+++ b/src/libstrongswan/utils/printf_hook/printf_hook_builtin.c
@@ -843,7 +843,8 @@ int builtin_vsnprintf(char *buffer, size_t n, const char *format, va_list ap)
 								/* String */
 								sarg = va_arg(ap, const char *);
 								sarg = sarg ? sarg : "(null)";
-								slen = strlen(sarg);
+								slen = prec != -1 ? strnlen(sarg, prec)
+												  : strlen(sarg);
 								goto is_string;
 							}
 							case 'm':
diff --git a/src/libstrongswan/utils/printf_hook/printf_hook_builtin.h b/src/libstrongswan/utils/printf_hook/printf_hook_builtin.h
index 409b5bf..efbacff 100644
--- a/src/libstrongswan/utils/printf_hook/printf_hook_builtin.h
+++ b/src/libstrongswan/utils/printf_hook/printf_hook_builtin.h
@@ -15,7 +15,7 @@
 
 /**
  * @defgroup printf_hook_builtin printf_hook_builtin
- * @{ @ingroup utils
+ * @{ @ingroup printf_hook
  */
 
 #ifndef PRINTF_HOOK_BUILTIN_H_
diff --git a/src/libstrongswan/utils/printf_hook/printf_hook_vstr.h b/src/libstrongswan/utils/printf_hook/printf_hook_vstr.h
index 2f9ee59..7c24b05 100644
--- a/src/libstrongswan/utils/printf_hook/printf_hook_vstr.h
+++ b/src/libstrongswan/utils/printf_hook/printf_hook_vstr.h
@@ -16,7 +16,7 @@
 
 /**
  * @defgroup printf_hook_vstr printf_hook_vstr
- * @{ @ingroup utils
+ * @{ @ingroup printf_hook
  */
 
 #ifndef PRINTF_HOOK_VSTR_H_
diff --git a/src/libstrongswan/utils/utils.c b/src/libstrongswan/utils/utils.c
index 9b516ac..b4a4db8 100644
--- a/src/libstrongswan/utils/utils.c
+++ b/src/libstrongswan/utils/utils.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008-2014 Tobias Brunner
+ * Copyright (C) 2008-2015 Tobias Brunner
  * Copyright (C) 2005-2008 Martin Willi
  * Hochschule fuer Technik Rapperswil
  *
@@ -16,15 +16,38 @@
 
 #include "utils.h"
 
+#include <sys/types.h>
 #include <unistd.h>
 #include <limits.h>
+#include <ctype.h>
 #ifndef WIN32
 # include <signal.h>
 #endif
 
+#ifndef HAVE_CLOSEFROM
+#if defined(__linux__) && defined(HAVE_SYS_SYSCALL_H)
+# include <sys/stat.h>
+# include <fcntl.h>
+# include <sys/syscall.h>
+/* This is from the kernel sources.  We limit the length of directory names to
+ * 256 as we only use it to enumerate FDs. */
+struct linux_dirent64 {
+	u_int64_t d_ino;
+	int64_t d_off;
+	unsigned short	d_reclen;
+	unsigned char d_type;
+	char d_name[256];
+};
+#else /* !defined(__linux__) || !defined(HAVE_SYS_SYSCALL_H) */
+# include <dirent.h>
+#endif /* defined(__linux__) && defined(HAVE_SYS_SYSCALL_H) */
+#endif
+
 #include <library.h>
 #include <collections/enumerator.h>
 
+#define FD_DIR "/proc/self/fd"
+
 #ifdef WIN32
 
 #include <threading/mutex.h>
@@ -110,43 +133,89 @@ void wait_sigint()
 /**
  * Described in header.
  */
-void closefrom(int lowfd)
+void closefrom(int low_fd)
 {
-	char fd_dir[PATH_MAX];
-	int maxfd, fd, len;
+	int max_fd, dir_fd, fd;
 
 	/* try to close only open file descriptors on Linux... */
-	len = snprintf(fd_dir, sizeof(fd_dir), "/proc/%u/fd", getpid());
-	if (len > 0 && len < sizeof(fd_dir) && access(fd_dir, F_OK) == 0)
+#if defined(__linux__) && defined(HAVE_SYS_SYSCALL_H)
+	/* By directly using a syscall we avoid any calls that might be unsafe after
+	 * fork() (e.g. malloc()). */
+	char buffer[sizeof(struct linux_dirent64)];
+	struct linux_dirent64 *entry;
+	int offset, len;
+
+	dir_fd = open("/proc/self/fd", O_RDONLY);
+	if (dir_fd != -1)
 	{
-		enumerator_t *enumerator = enumerator_create_directory(fd_dir);
-		if (enumerator)
+		while ((len = syscall(SYS_getdents64, dir_fd, buffer,
+							  sizeof(buffer))) > 0)
 		{
-			char *rel;
-			while (enumerator->enumerate(enumerator, &rel, NULL, NULL))
+			for (offset = 0; offset < len; offset += entry->d_reclen)
 			{
-				fd = atoi(rel);
-				if (fd >= lowfd)
+				entry = (struct linux_dirent64*)(buffer + offset);
+				if (!isdigit(entry->d_name[0]))
+				{
+					continue;
+				}
+				fd = atoi(entry->d_name);
+				if (fd != dir_fd && fd >= low_fd)
 				{
 					close(fd);
 				}
 			}
-			enumerator->destroy(enumerator);
-			return;
 		}
+		close(dir_fd);
+		return;
+	}
+#else /* !defined(__linux__) || !defined(HAVE_SYS_SYSCALL_H) */
+	/* This is potentially unsafe when called after fork() in multi-threaded
+	 * applications.  In particular opendir() will require an allocation.
+	 * Depends on how the malloc() implementation handles such situations. */
+	DIR *dir;
+	struct dirent *entry;
+
+#ifndef HAVE_DIRFD
+	/* if we don't have dirfd() lets close the lowest FD and hope it gets reused
+	 * by opendir() */
+	close(low_fd);
+	dir_fd = low_fd++;
+#endif
+
+	dir = opendir(FD_DIR);
+	if (dir)
+	{
+#ifdef HAVE_DIRFD
+		dir_fd = dirfd(dir);
+#endif
+		while ((entry = readdir(dir)))
+		{
+			if (!isdigit(entry->d_name[0]))
+			{
+				continue;
+			}
+			fd = atoi(entry->d_name);
+			if (fd != dir_fd && fd >= low_fd)
+			{
+				close(fd);
+			}
+		}
+		closedir(dir);
+		return;
 	}
+#endif /* defined(__linux__) && defined(HAVE_SYS_SYSCALL_H) */
 
 	/* ...fall back to closing all fds otherwise */
 #ifdef WIN32
-	maxfd = _getmaxstdio();
+	max_fd = _getmaxstdio();
 #else
-	maxfd = (int)sysconf(_SC_OPEN_MAX);
+	max_fd = (int)sysconf(_SC_OPEN_MAX);
 #endif
-	if (maxfd < 0)
+	if (max_fd < 0)
 	{
-		maxfd = 256;
+		max_fd = 256;
 	}
-	for (fd = lowfd; fd < maxfd; fd++)
+	for (fd = low_fd; fd < max_fd; fd++)
 	{
 		close(fd);
 	}
diff --git a/src/libstrongswan/utils/utils/string.c b/src/libstrongswan/utils/utils/string.c
index 14087e7..56910ed 100644
--- a/src/libstrongswan/utils/utils/string.c
+++ b/src/libstrongswan/utils/utils/string.c
@@ -44,7 +44,7 @@ char* translate(char *str, const char *from, const char *to)
 char* strreplace(const char *str, const char *search, const char *replace)
 {
 	size_t len, slen, rlen, count = 0;
-	char *res, *pos, *found, *dst;
+	char *res, *pos, *found = NULL, *dst;
 
 	if (!str || !*str || !search || !*search || !replace)
 	{
diff --git a/src/libtls/tests/tls_tests.c b/src/libtls/tests/tls_tests.c
index 2c2c5ba..3f22f9c 100644
--- a/src/libtls/tests/tls_tests.c
+++ b/src/libtls/tests/tls_tests.c
@@ -25,8 +25,8 @@
 static test_configuration_t tests[] = {
 #define TEST_SUITE(x) \
 	{ .suite = x, },
-#define TEST_SUITE_DEPEND(x, type, args) \
-	{ .suite = x, .feature = PLUGIN_DEPENDS(type, args) },
+#define TEST_SUITE_DEPEND(x, type, ...) \
+	{ .suite = x, .feature = PLUGIN_DEPENDS(type, __VA_ARGS__) },
 #include "tls_tests.h"
 	{ .suite = NULL, }
 };
diff --git a/src/libtnccs/plugins/tnc_tnccs/tnc_tnccs_manager.c b/src/libtnccs/plugins/tnc_tnccs/tnc_tnccs_manager.c
index 30e5052..67c33ee 100644
--- a/src/libtnccs/plugins/tnc_tnccs/tnc_tnccs_manager.c
+++ b/src/libtnccs/plugins/tnc_tnccs/tnc_tnccs_manager.c
@@ -729,7 +729,9 @@ METHOD(tnccs_manager_t, get_attribute, TNC_Result,
 			list = linked_list_create();
 			tnccs = entry->tnccs;
 
-			peer_id = tnccs->tls.get_peer_id(&tnccs->tls);
+			peer_id = tnccs->tls.is_server(&tnccs->tls) ?
+					tnccs->tls.get_peer_id(&tnccs->tls) :
+					tnccs->tls.get_server_id(&tnccs->tls);
 			if (peer_id)
 			{
 				switch (peer_id->get_type(peer_id))
@@ -771,7 +773,9 @@ METHOD(tnccs_manager_t, get_attribute, TNC_Result,
 				}
 			}
 
-			peer_ip = tnccs->get_peer_ip(tnccs);
+			peer_ip = tnccs->tls.is_server(&tnccs->tls) ?
+					tnccs->get_peer_ip(tnccs) :
+					tnccs->get_server_ip(tnccs);
 			if (peer_ip)
 			{
 				switch (peer_ip->get_family(peer_ip))
diff --git a/src/libtncif/tncif_pa_subtypes.c b/src/libtncif/tncif_pa_subtypes.c
index bf1e999..d83c325 100644
--- a/src/libtncif/tncif_pa_subtypes.c
+++ b/src/libtncif/tncif_pa_subtypes.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010-2011 Andreas Steffen
+ * Copyright (C) 2010-2015 Andreas Steffen
  *
  * HSR Hochschule fuer Technik Rapperswil
  *
@@ -16,6 +16,7 @@
 
 #include "tncif_pa_subtypes.h"
 
+/* IETF PA Subtype names */
 ENUM_BEGIN(pa_subtype_ietf_names, PA_SUBTYPE_IETF_TESTING, PA_SUBTYPE_IETF_NEA_CLIENT,
 	"Testing",
 	"Operating System",
@@ -33,6 +34,7 @@ ENUM_NEXT(pa_subtype_ietf_names, PA_SUBTYPE_IETF_ANY, PA_SUBTYPE_IETF_ANY,
 );
 ENUM_END(pa_subtype_ietf_names, PA_SUBTYPE_IETF_ANY);
 
+/* TCG PA Subtype names */
 ENUM_BEGIN(pa_subtype_tcg_names, PA_SUBTYPE_TCG_PTS, PA_SUBTYPE_TCG_SWID,
 	"PTS",
 	"SCAP",
@@ -44,6 +46,56 @@ ENUM_NEXT(pa_subtype_tcg_names, PA_SUBTYPE_TCG_ANY, PA_SUBTYPE_TCG_ANY,
 );
 ENUM_END(pa_subtype_tcg_names, PA_SUBTYPE_TCG_ANY);
 
+/* PWG PA Subtype names */
+ENUM_BEGIN(pa_subtype_pwg_names, PA_SUBTYPE_PWG_HCD_TESTING,
+								 PA_SUBTYPE_PWG_HCD_UNKNOWN,
+	"HCD Testing",
+	"HCD Other",
+	"HCD Unknown"
+);
+ENUM_NEXT(pa_subtype_pwg_names, PA_SUBTYPE_PWG_HCD_CONSOLE,
+								PA_SUBTYPE_PWG_HCD_COVER,
+								PA_SUBTYPE_PWG_HCD_UNKNOWN,
+	"HCD Console",
+	"HCD System",
+	"HCD Cover"
+);
+ENUM_NEXT(pa_subtype_pwg_names, PA_SUBTYPE_PWG_HCD_INPUT_TRAY,
+								PA_SUBTYPE_PWG_HCD_MARKER,
+								PA_SUBTYPE_PWG_HCD_COVER,
+	"HCD Input Tray",
+	"HCD Output Tray",
+	"HCD Marker"
+);
+ENUM_NEXT(pa_subtype_pwg_names, PA_SUBTYPE_PWG_HCD_MEDIA_PATH,
+								PA_SUBTYPE_PWG_HCD_INTERPRETER,
+								PA_SUBTYPE_PWG_HCD_MARKER,
+	"HCD Media Path",
+	"HCD Channel",
+	"HCD Interpreter"
+);
+ENUM_NEXT(pa_subtype_pwg_names, PA_SUBTYPE_PWG_HCD_FINISHER,
+								PA_SUBTYPE_PWG_HCD_FINISHER,
+								PA_SUBTYPE_PWG_HCD_INTERPRETER,
+	"HCD Finisher"
+);
+ENUM_NEXT(pa_subtype_pwg_names, PA_SUBTYPE_PWG_HCD_INTERFACE,
+								PA_SUBTYPE_PWG_HCD_INTERFACE,
+								PA_SUBTYPE_PWG_HCD_FINISHER,
+	"HCD Interface"
+);
+ENUM_NEXT(pa_subtype_pwg_names, PA_SUBTYPE_PWG_HCD_SCANNER,
+								PA_SUBTYPE_PWG_HCD_SCANNER,
+								PA_SUBTYPE_PWG_HCD_INTERFACE,
+	"HCD Scanner"
+);
+ENUM_NEXT(pa_subtype_pwg_names, PA_SUBTYPE_PWG_ANY, PA_SUBTYPE_PWG_ANY,
+								PA_SUBTYPE_PWG_HCD_SCANNER,
+	"ANY"
+);
+ENUM_END(pa_subtype_pwg_names, PA_SUBTYPE_PWG_ANY);
+
+/* FHH PA Subtype names */
 ENUM_BEGIN(pa_subtype_fhh_names, PA_SUBTYPE_FHH_HOSTSCANNER, PA_SUBTYPE_FHH_DUMMY,
 	"HostScanner",
 	"Dummy"
@@ -63,6 +115,7 @@ ENUM_NEXT(pa_subtype_fhh_names, PA_SUBTYPE_FHH_ANY, PA_SUBTYPE_FHH_ANY,
 );
 ENUM_END(pa_subtype_fhh_names, PA_SUBTYPE_FHH_ANY);
 
+/* ITA-HSR PA Subtype names */
 ENUM_BEGIN(pa_subtype_ita_names, PA_SUBTYPE_ITA_TEST, PA_SUBTYPE_ITA_ECHO,
 	"Test",
 	"Echo"
@@ -84,6 +137,8 @@ enum_name_t* get_pa_subtype_names(pen_t pen)
 			return pa_subtype_ietf_names;
 		case PEN_TCG:
 			return pa_subtype_tcg_names;
+		case PEN_PWG:
+			return pa_subtype_pwg_names;
 		case PEN_FHH:
 			return pa_subtype_fhh_names;
 		case PEN_ITA:
diff --git a/src/libtncif/tncif_pa_subtypes.h b/src/libtncif/tncif_pa_subtypes.h
index 0855d1d..d6dcad0 100644
--- a/src/libtncif/tncif_pa_subtypes.h
+++ b/src/libtncif/tncif_pa_subtypes.h
@@ -1,5 +1,6 @@
 /*
- * Copyright (C) 2011 Andreas Steffen, HSR Hochschule fuer Technik Rapperswil
+ * Copyright (C) 2011-2015 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
@@ -22,6 +23,7 @@
 
 typedef enum pa_subtype_ietf_t pa_subtype_ietf_t;
 typedef enum pa_subtype_tcg_t pa_subtype_tcg_t;
+typedef enum pa_subtype_pwg_t pa_subtype_pwg_t;
 typedef enum pa_subtype_fhh_t pa_subtype_fhh_t;
 typedef enum pa_subtype_ita_t pa_subtype_ita_t;
 
@@ -65,6 +67,33 @@ extern enum_name_t *pa_subtype_ietf_names;
 extern enum_name_t *pa_subtype_tcg_names;
 
 /**
+ * PA-TNC PWG Subtypes
+ */
+ enum pa_subtype_pwg_t {
+	PA_SUBTYPE_PWG_HCD_TESTING =		0x00,
+	PA_SUBTYPE_PWG_HCD_OTHER =			0x01,
+	PA_SUBTYPE_PWG_HCD_UNKNOWN =		0x02,
+	PA_SUBTYPE_PWG_HCD_CONSOLE =		0x04,
+	PA_SUBTYPE_PWG_HCD_SYSTEM =			0x05,
+	PA_SUBTYPE_PWG_HCD_COVER =			0x06,
+	PA_SUBTYPE_PWG_HCD_INPUT_TRAY =		0x08,
+	PA_SUBTYPE_PWG_HCD_OUTPUT_TRAY =	0x09,
+	PA_SUBTYPE_PWG_HCD_MARKER =			0x0a,
+	PA_SUBTYPE_PWG_HCD_MEDIA_PATH =		0x0d,
+	PA_SUBTYPE_PWG_HCD_CHANNEL =		0x0e,
+	PA_SUBTYPE_PWG_HCD_INTERPRETER =	0x0f,
+	PA_SUBTYPE_PWG_HCD_FINISHER =		0x1e,
+	PA_SUBTYPE_PWG_HCD_INTERFACE =		0x28,
+	PA_SUBTYPE_PWG_HCD_SCANNER =		0x32,
+	PA_SUBTYPE_PWG_ANY =				0xff
+};
+
+/**
+ * enum name for pa_subtype_pwg_t.
+ */
+extern enum_name_t *pa_subtype_pwg_names;
+
+/**
  * PA-TNC FHH Subtypes
  */
  enum pa_subtype_fhh_t {
diff --git a/src/pki/Makefile.am b/src/pki/Makefile.am
index ab407e0..a3da0ab 100644
--- a/src/pki/Makefile.am
+++ b/src/pki/Makefile.am
@@ -3,17 +3,18 @@ SUBDIRS = man
 bin_PROGRAMS = pki
 
 pki_SOURCES = pki.c pki.h command.c command.h \
+	commands/acert.c \
+	commands/dn.c \
 	commands/gen.c \
 	commands/issue.c \
 	commands/keyid.c \
+	commands/pkcs12.c \
+	commands/pkcs7.c \
+	commands/print.c \
 	commands/pub.c \
 	commands/req.c \
 	commands/self.c \
-	commands/print.c \
 	commands/signcrl.c \
-	commands/acert.c \
-	commands/pkcs7.c \
-	commands/pkcs12.c \
 	commands/verify.c
 
 pki_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la
diff --git a/src/pki/Makefile.in b/src/pki/Makefile.in
index 4205469..b4829f7 100644
--- a/src/pki/Makefile.in
+++ b/src/pki/Makefile.in
@@ -103,12 +103,13 @@ am__installdirs = "$(DESTDIR)$(bindir)"
 PROGRAMS = $(bin_PROGRAMS)
 am__dirstamp = $(am__leading_dot)dirstamp
 am_pki_OBJECTS = pki.$(OBJEXT) command.$(OBJEXT) \
+	commands/acert.$(OBJEXT) commands/dn.$(OBJEXT) \
 	commands/gen.$(OBJEXT) commands/issue.$(OBJEXT) \
-	commands/keyid.$(OBJEXT) commands/pub.$(OBJEXT) \
-	commands/req.$(OBJEXT) commands/self.$(OBJEXT) \
-	commands/print.$(OBJEXT) commands/signcrl.$(OBJEXT) \
-	commands/acert.$(OBJEXT) commands/pkcs7.$(OBJEXT) \
-	commands/pkcs12.$(OBJEXT) commands/verify.$(OBJEXT)
+	commands/keyid.$(OBJEXT) commands/pkcs12.$(OBJEXT) \
+	commands/pkcs7.$(OBJEXT) commands/print.$(OBJEXT) \
+	commands/pub.$(OBJEXT) commands/req.$(OBJEXT) \
+	commands/self.$(OBJEXT) commands/signcrl.$(OBJEXT) \
+	commands/verify.$(OBJEXT)
 pki_OBJECTS = $(am_pki_OBJECTS)
 pki_DEPENDENCIES = $(top_builddir)/src/libstrongswan/libstrongswan.la
 AM_V_lt = $(am__v_lt_ at AM_V@)
@@ -445,17 +446,18 @@ xml_CFLAGS = @xml_CFLAGS@
 xml_LIBS = @xml_LIBS@
 SUBDIRS = man
 pki_SOURCES = pki.c pki.h command.c command.h \
+	commands/acert.c \
+	commands/dn.c \
 	commands/gen.c \
 	commands/issue.c \
 	commands/keyid.c \
+	commands/pkcs12.c \
+	commands/pkcs7.c \
+	commands/print.c \
 	commands/pub.c \
 	commands/req.c \
 	commands/self.c \
-	commands/print.c \
 	commands/signcrl.c \
-	commands/acert.c \
-	commands/pkcs7.c \
-	commands/pkcs12.c \
 	commands/verify.c
 
 pki_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la
@@ -552,27 +554,29 @@ commands/$(am__dirstamp):
 commands/$(DEPDIR)/$(am__dirstamp):
 	@$(MKDIR_P) commands/$(DEPDIR)
 	@: > commands/$(DEPDIR)/$(am__dirstamp)
+commands/acert.$(OBJEXT): commands/$(am__dirstamp) \
+	commands/$(DEPDIR)/$(am__dirstamp)
+commands/dn.$(OBJEXT): commands/$(am__dirstamp) \
+	commands/$(DEPDIR)/$(am__dirstamp)
 commands/gen.$(OBJEXT): commands/$(am__dirstamp) \
 	commands/$(DEPDIR)/$(am__dirstamp)
 commands/issue.$(OBJEXT): commands/$(am__dirstamp) \
 	commands/$(DEPDIR)/$(am__dirstamp)
 commands/keyid.$(OBJEXT): commands/$(am__dirstamp) \
 	commands/$(DEPDIR)/$(am__dirstamp)
-commands/pub.$(OBJEXT): commands/$(am__dirstamp) \
-	commands/$(DEPDIR)/$(am__dirstamp)
-commands/req.$(OBJEXT): commands/$(am__dirstamp) \
+commands/pkcs12.$(OBJEXT): commands/$(am__dirstamp) \
 	commands/$(DEPDIR)/$(am__dirstamp)
-commands/self.$(OBJEXT): commands/$(am__dirstamp) \
+commands/pkcs7.$(OBJEXT): commands/$(am__dirstamp) \
 	commands/$(DEPDIR)/$(am__dirstamp)
 commands/print.$(OBJEXT): commands/$(am__dirstamp) \
 	commands/$(DEPDIR)/$(am__dirstamp)
-commands/signcrl.$(OBJEXT): commands/$(am__dirstamp) \
+commands/pub.$(OBJEXT): commands/$(am__dirstamp) \
 	commands/$(DEPDIR)/$(am__dirstamp)
-commands/acert.$(OBJEXT): commands/$(am__dirstamp) \
+commands/req.$(OBJEXT): commands/$(am__dirstamp) \
 	commands/$(DEPDIR)/$(am__dirstamp)
-commands/pkcs7.$(OBJEXT): commands/$(am__dirstamp) \
+commands/self.$(OBJEXT): commands/$(am__dirstamp) \
 	commands/$(DEPDIR)/$(am__dirstamp)
-commands/pkcs12.$(OBJEXT): commands/$(am__dirstamp) \
+commands/signcrl.$(OBJEXT): commands/$(am__dirstamp) \
 	commands/$(DEPDIR)/$(am__dirstamp)
 commands/verify.$(OBJEXT): commands/$(am__dirstamp) \
 	commands/$(DEPDIR)/$(am__dirstamp)
@@ -591,6 +595,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/command.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/pki.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at commands/$(DEPDIR)/acert.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at commands/$(DEPDIR)/dn.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at commands/$(DEPDIR)/gen.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at commands/$(DEPDIR)/issue.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at commands/$(DEPDIR)/keyid.Po at am__quote@
diff --git a/src/pki/command.h b/src/pki/command.h
index d49adda..e55c579 100644
--- a/src/pki/command.h
+++ b/src/pki/command.h
@@ -24,7 +24,7 @@
 /**
  * Maximum number of commands (+1).
  */
-#define MAX_COMMANDS 13
+#define MAX_COMMANDS 14
 
 /**
  * Maximum number of options in a command (+3)
diff --git a/src/pki/commands/dn.c b/src/pki/commands/dn.c
new file mode 100644
index 0000000..75585fc
--- /dev/null
+++ b/src/pki/commands/dn.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2015 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include "pki.h"
+
+#include <credentials/certificates/certificate.h>
+
+#include <errno.h>
+
+/**
+ * Extract subject DN
+ */
+static int dn()
+{
+	identification_t *id;
+	certificate_t *cert;
+	chunk_t chunk;
+	enum {
+		FORMAT_CONFIG,
+		FORMAT_HEX,
+		FORMAT_BASE64,
+		FORMAT_BINARY,
+	} format = FORMAT_CONFIG;
+	char *arg, *file = NULL, *fmt;
+
+	while (TRUE)
+	{
+		switch (command_getopt(&arg))
+		{
+			case 'h':
+				return command_usage(NULL);
+			case 'f':
+				if (streq(arg, "hex"))
+				{
+					format = FORMAT_HEX;
+				}
+				else if (streq(arg, "base64"))
+				{
+					format = FORMAT_BASE64;
+				}
+				else if (streq(arg, "bin"))
+				{
+					format = FORMAT_BINARY;
+				}
+				else if (!streq(arg, "config"))
+				{
+					return command_usage( "invalid output format");
+				}
+				continue;
+			case 'i':
+				file = arg;
+				continue;
+			case EOF:
+				break;
+			default:
+				return command_usage("invalid --print option");
+		}
+		break;
+	}
+	if (file)
+	{
+		cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
+								  BUILD_FROM_FILE, file, BUILD_END);
+	}
+	else
+	{
+		chunk_t chunk;
+
+		set_file_mode(stdin, CERT_ASN1_DER);
+		if (!chunk_from_fd(0, &chunk))
+		{
+			fprintf(stderr, "reading input failed: %s\n", strerror(errno));
+			return 1;
+		}
+		cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
+								  BUILD_BLOB, chunk, BUILD_END);
+		free(chunk.ptr);
+	}
+	if (!cert)
+	{
+		fprintf(stderr, "parsing input failed\n");
+		return 1;
+	}
+	id = cert->get_subject(cert);
+	if (!id)
+	{
+		fprintf(stderr, "failed to get certificate's subject DN\n");
+		cert->destroy(cert);
+		return 1;
+	}
+	fmt = "%.*s\n";
+	switch (format)
+	{
+		case FORMAT_CONFIG:
+			fmt = "\"asn1dn:#%.*s\"\n";
+			/* fall-through */
+		case FORMAT_HEX:
+			chunk = chunk_to_hex(id->get_encoding(id), NULL, FALSE);
+			printf(fmt, (int)chunk.len, chunk.ptr);
+			chunk_free(&chunk);
+			break;
+		case FORMAT_BASE64:
+			chunk = chunk_to_base64(id->get_encoding(id), NULL);
+			printf(fmt, (int)chunk.len, chunk.ptr);
+			chunk_free(&chunk);
+			break;
+		case FORMAT_BINARY:
+			chunk = id->get_encoding(id);
+			if (fwrite(chunk.ptr, chunk.len, 1, stdout) != 1)
+			{
+				fprintf(stderr, "writing subject DN failed\n");
+			}
+			break;
+	}
+	cert->destroy(cert);
+	return 0;
+}
+
+/**
+ * Register the command.
+ */
+static void __attribute__ ((constructor))reg()
+{
+	command_register((command_t)
+		{ dn, 'd', "dn",
+		"extract the subject DN of an X.509 certificate",
+		{"[--in file] [--format config|hex|base64|bin]"},
+		{
+			{"help",		'h', 0, "show usage information"},
+			{"in",			'i', 1, "input file, default: stdin"},
+			{"format",		'f', 1, "output format, default: config"},
+		}
+	});
+}
diff --git a/src/pki/commands/issue.c b/src/pki/commands/issue.c
index 6a2d09d..2dc9fcc 100644
--- a/src/pki/commands/issue.c
+++ b/src/pki/commands/issue.c
@@ -64,6 +64,8 @@ static int issue()
 	certificate_t *cert_req = NULL, *cert = NULL, *ca =NULL;
 	private_key_t *private = NULL;
 	public_key_t *public = NULL;
+	credential_type_t type = CRED_PUBLIC_KEY;
+	key_type_t subtype = KEY_ANY;
 	bool pkcs10 = FALSE;
 	char *file = NULL, *dn = NULL, *hex = NULL, *cacert = NULL, *cakey = NULL;
 	char *error = NULL, *keyid = NULL;
@@ -100,6 +102,21 @@ static int issue()
 				{
 					pkcs10 = TRUE;
 				}
+				else if (streq(arg, "rsa"))
+				{
+					type = CRED_PRIVATE_KEY;
+					subtype = KEY_RSA;
+				}
+				else if (streq(arg, "ecdsa"))
+				{
+					type = CRED_PRIVATE_KEY;
+					subtype = KEY_ECDSA;
+				}
+				else if (streq(arg, "bliss"))
+				{
+					type = CRED_PRIVATE_KEY;
+					subtype = KEY_BLISS;
+				}
 				else if (!streq(arg, "pub"))
 				{
 					error = "invalid input type";
@@ -447,10 +464,10 @@ static int issue()
 	}
 	else
 	{
-		DBG2(DBG_LIB, "Reading public key:");
+		DBG2(DBG_LIB, "Reading key:");
 		if (file)
 		{
-			public = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ANY,
+			public = lib->creds->create(lib->creds, type, subtype,
 										BUILD_FROM_FILE, file, BUILD_END);
 		}
 		else
@@ -460,13 +477,19 @@ static int issue()
 			if (!chunk_from_fd(0, &chunk))
 			{
 				fprintf(stderr, "%s: ", strerror(errno));
-				error = "reading public key failed";
+				error = "reading key failed";
 				goto end;
 			}
-			public = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ANY,
+			public = lib->creds->create(lib->creds, type, subtype,
 										 BUILD_BLOB, chunk, BUILD_END);
 			free(chunk.ptr);
 		}
+		if (public && type == CRED_PRIVATE_KEY)
+		{
+			private_key_t *priv = (private_key_t*)public;
+			public = priv->get_public_key(priv);
+			priv->destroy(priv);
+		}
 	}
 	if (!public)
 	{
@@ -557,7 +580,7 @@ static void __attribute__ ((constructor))reg()
 	command_register((command_t) {
 		issue, 'i', "issue",
 		"issue a certificate using a CA certificate and key",
-		{"[--in file] [--type pub|pkcs10] --cakey file|--cakeyid hex",
+		{"[--in file] [--type pub|pkcs10|rsa|ecdsa|bliss] --cakey file|--cakeyid hex",
 		 " --cacert file [--dn subject-dn] [--san subjectAltName]+",
 		 "[--lifetime days] [--serial hex] [--ca] [--pathlen len]",
 		 "[--flag serverAuth|clientAuth|crlSign|ocspSigning|msSmartcardLogon]+",
@@ -568,7 +591,7 @@ static void __attribute__ ((constructor))reg()
 		 "[--digest md5|sha1|sha224|sha256|sha384|sha512] [--outform der|pem]"},
 		{
 			{"help",			'h', 0, "show usage information"},
-			{"in",				'i', 1, "public key/request file to issue, default: stdin"},
+			{"in",				'i', 1, "key/request file to issue, default: stdin"},
 			{"type",			't', 1, "type of input, default: pub"},
 			{"cacert",			'c', 1, "CA certificate file"},
 			{"cakey",			'k', 1, "CA private key file"},
diff --git a/src/pki/man/Makefile.am b/src/pki/man/Makefile.am
index 4c901ae..fc94400 100644
--- a/src/pki/man/Makefile.am
+++ b/src/pki/man/Makefile.am
@@ -1,15 +1,16 @@
 man1_MANS = \
 	pki.1 \
+	pki---acert.1 \
+	pki---dn.1 \
 	pki---gen.1 \
-	pki---self.1 \
 	pki---issue.1 \
-	pki---signcrl.1 \
-	pki---acert.1 \
-	pki---req.1 \
-	pki---pkcs7.1 \
 	pki---keyid.1 \
+	pki---pkcs7.1 \
 	pki---print.1 \
 	pki---pub.1 \
+	pki---req.1 \
+	pki---self.1 \
+	pki---signcrl.1 \
 	pki---verify.1
 
 CLEANFILES = $(man1_MANS)
diff --git a/src/pki/man/Makefile.in b/src/pki/man/Makefile.in
index 45355ba..62942d1 100644
--- a/src/pki/man/Makefile.in
+++ b/src/pki/man/Makefile.in
@@ -79,13 +79,13 @@ build_triplet = @build@
 host_triplet = @host@
 subdir = src/pki/man
 DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(srcdir)/pki.1.in $(srcdir)/pki---gen.1.in \
+	$(srcdir)/pki.1.in $(srcdir)/pki---acert.1.in \
+	$(srcdir)/pki---dn.1.in $(srcdir)/pki---gen.1.in \
 	$(srcdir)/pki---issue.1.in $(srcdir)/pki---keyid.1.in \
-	$(srcdir)/pki---pkcs7.1.in $(srcdir)/pki---pkcs12.1.in \
+	$(srcdir)/pki---pkcs12.1.in $(srcdir)/pki---pkcs7.1.in \
 	$(srcdir)/pki---print.1.in $(srcdir)/pki---pub.1.in \
 	$(srcdir)/pki---req.1.in $(srcdir)/pki---self.1.in \
-	$(srcdir)/pki---signcrl.1.in $(srcdir)/pki---acert.1.in \
-	$(srcdir)/pki---verify.1.in
+	$(srcdir)/pki---signcrl.1.in $(srcdir)/pki---verify.1.in
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \
 	$(top_srcdir)/m4/config/ltoptions.m4 \
@@ -101,10 +101,10 @@ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
-CONFIG_CLEAN_FILES = pki.1 pki---gen.1 pki---issue.1 pki---keyid.1 \
-	pki---pkcs7.1 pki---pkcs12.1 pki---print.1 pki---pub.1 \
-	pki---req.1 pki---self.1 pki---signcrl.1 pki---acert.1 \
-	pki---verify.1
+CONFIG_CLEAN_FILES = pki.1 pki---acert.1 pki---dn.1 pki---gen.1 \
+	pki---issue.1 pki---keyid.1 pki---pkcs12.1 pki---pkcs7.1 \
+	pki---print.1 pki---pub.1 pki---req.1 pki---self.1 \
+	pki---signcrl.1 pki---verify.1
 CONFIG_CLEAN_VPATH_FILES =
 AM_V_P = $(am__v_P_ at AM_V@)
 am__v_P_ = $(am__v_P_ at AM_DEFAULT_V@)
@@ -385,16 +385,17 @@ xml_CFLAGS = @xml_CFLAGS@
 xml_LIBS = @xml_LIBS@
 man1_MANS = \
 	pki.1 \
+	pki---acert.1 \
+	pki---dn.1 \
 	pki---gen.1 \
-	pki---self.1 \
 	pki---issue.1 \
-	pki---signcrl.1 \
-	pki---acert.1 \
-	pki---req.1 \
-	pki---pkcs7.1 \
 	pki---keyid.1 \
+	pki---pkcs7.1 \
 	pki---print.1 \
 	pki---pub.1 \
+	pki---req.1 \
+	pki---self.1 \
+	pki---signcrl.1 \
 	pki---verify.1
 
 CLEANFILES = $(man1_MANS)
@@ -433,16 +434,20 @@ $(ACLOCAL_M4):  $(am__aclocal_m4_deps)
 $(am__aclocal_m4_deps):
 pki.1: $(top_builddir)/config.status $(srcdir)/pki.1.in
 	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+pki---acert.1: $(top_builddir)/config.status $(srcdir)/pki---acert.1.in
+	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+pki---dn.1: $(top_builddir)/config.status $(srcdir)/pki---dn.1.in
+	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
 pki---gen.1: $(top_builddir)/config.status $(srcdir)/pki---gen.1.in
 	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
 pki---issue.1: $(top_builddir)/config.status $(srcdir)/pki---issue.1.in
 	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
 pki---keyid.1: $(top_builddir)/config.status $(srcdir)/pki---keyid.1.in
 	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
-pki---pkcs7.1: $(top_builddir)/config.status $(srcdir)/pki---pkcs7.1.in
-	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
 pki---pkcs12.1: $(top_builddir)/config.status $(srcdir)/pki---pkcs12.1.in
 	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+pki---pkcs7.1: $(top_builddir)/config.status $(srcdir)/pki---pkcs7.1.in
+	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
 pki---print.1: $(top_builddir)/config.status $(srcdir)/pki---print.1.in
 	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
 pki---pub.1: $(top_builddir)/config.status $(srcdir)/pki---pub.1.in
@@ -453,8 +458,6 @@ pki---self.1: $(top_builddir)/config.status $(srcdir)/pki---self.1.in
 	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
 pki---signcrl.1: $(top_builddir)/config.status $(srcdir)/pki---signcrl.1.in
 	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
-pki---acert.1: $(top_builddir)/config.status $(srcdir)/pki---acert.1.in
-	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
 pki---verify.1: $(top_builddir)/config.status $(srcdir)/pki---verify.1.in
 	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
 
diff --git a/src/pki/man/pki---dn.1.in b/src/pki/man/pki---dn.1.in
new file mode 100644
index 0000000..ce1210f
--- /dev/null
+++ b/src/pki/man/pki---dn.1.in
@@ -0,0 +1,56 @@
+.TH "PKI \-\-DN" 1 "2015-08-06" "@PACKAGE_VERSION@" "strongSwan"
+.
+.SH "NAME"
+.
+pki \-\-dn \- Extract the subject DN of an X.509 certificate
+.
+.SH "SYNOPSIS"
+.
+.SY pki\ \-\-dn
+.OP \-\-in file
+.OP \-\-format format
+.OP \-\-debug level
+.YS
+.
+.SY pki\ \-\-dn
+.BI \-\-options\~ file
+.YS
+.
+.SY "pki \-\-dn"
+.B \-h
+|
+.B \-\-help
+.YS
+.
+.SH "DESCRIPTION"
+.
+This sub-command of
+.BR pki (1)
+extracts the ASN.1-encoded subject DistinguishedName (DN) of an X.509
+certificate and exports it in different formats.  This may be useful when
+strongSwan's identity parser is unable to produce the correct binary encoding
+from a string.
+.
+.SH "OPTIONS"
+.
+.TP
+.B "\-h, \-\-help"
+Print usage information with a summary of the available options.
+.TP
+.BI "\-v, \-\-debug " level
+Set debug level, default: 1.
+.TP
+.BI "\-+, \-\-options " file
+Read command line options from \fIfile\fR.
+.TP
+.BI "\-i, \-\-in " file
+Input file. If not given the input is read from \fISTDIN\fR.
+.TP
+.BI "\-t, \-\-format " format
+Output format. One of \fIconfig\fR (strongSwan configuration compatible),
+\fIhex\fR (hexadecimal encoding, no prefix), \fIbase64\fR (Base64 encoding,
+no prefix), \fIbin\fR (raw binary data), defaults to \fIconfig\fR.
+.
+.SH "SEE ALSO"
+.
+.BR pki (1)
diff --git a/src/pki/man/pki---issue.1.in b/src/pki/man/pki---issue.1.in
index 3a89059..20238b7 100644
--- a/src/pki/man/pki---issue.1.in
+++ b/src/pki/man/pki---issue.1.in
@@ -67,8 +67,9 @@ Public key or PKCS#10 certificate request file to issue. If not given the
 key/request is read from \fISTDIN\fR.
 .TP
 .BI "\-t, \-\-type " type
-Type of the input. Either \fIpub\fR for a public key, or \fIpkcs10\fR for a
-PKCS#10 certificate request, defaults to \fIpub\fR.
+Type of the input. One of \fIpub\fR (public key), \fIrsa\fR (RSA private key),
+\fIecdsa\fR (ECDSA private key), or \fIpkcs10\fR (PKCS#10 certificate request),
+defaults to \fIpub\fR.
 .TP
 .BI "\-k, \-\-cakey " file
 CA private key file. Either this or
diff --git a/src/pki/man/pki.1.in b/src/pki/man/pki.1.in
index f347031..f1a2ae2 100644
--- a/src/pki/man/pki.1.in
+++ b/src/pki/man/pki.1.in
@@ -1,4 +1,4 @@
-.TH PKI 1 "2013-07-31" "@PACKAGE_VERSION@" "strongSwan"
+.TH PKI 1 "2015-08-06" "@PACKAGE_VERSION@" "strongSwan"
 .
 .SH "NAME"
 .
@@ -64,6 +64,9 @@ Calculate key identifiers of a key or certificate.
 .B "\-a, \-\-print"
 Print a credential (key, certificate etc.) in human readable form.
 .TP
+.B "\-d, \-\-dn"
+Extract the subject DN of an X.509 certificate.
+.TP
 .B "\-p, \-\-pub"
 Extract a public key from a private key or certificate.
 .TP
@@ -156,5 +159,6 @@ certificates with the \-\-crl option.
 .BR pki\ \-\-pkcs7 (1),
 .BR pki\ \-\-keyid (1),
 .BR pki\ \-\-print (1),
+.BR pki\ \-\-dn (1),
 .BR pki\ \-\-pub (1),
 .BR pki\ \-\-verify (1)
diff --git a/src/starter/netkey.c b/src/starter/netkey.c
index 2b500ba..3eb6973 100644
--- a/src/starter/netkey.c
+++ b/src/starter/netkey.c
@@ -55,16 +55,3 @@ bool starter_netkey_init(void)
 	DBG2(DBG_APP, "found netkey IPsec stack");
 	return TRUE;
 }
-
-void starter_netkey_cleanup(void)
-{
-	if (!lib->plugins->load(lib->plugins,
-			lib->settings->get_str(lib->settings, "starter.load", PLUGINS)))
-	{
-		DBG1(DBG_APP, "unable to load kernel plugins");
-		return;
-	}
-	hydra->kernel_interface->flush_sas(hydra->kernel_interface);
-	hydra->kernel_interface->flush_policies(hydra->kernel_interface);
-	lib->plugins->unload(lib->plugins);
-}
diff --git a/src/starter/netkey.h b/src/starter/netkey.h
index c129241..bc71af2 100644
--- a/src/starter/netkey.h
+++ b/src/starter/netkey.h
@@ -16,7 +16,6 @@
 #define _STARTER_NETKEY_H_
 
 extern bool starter_netkey_init (void);
-extern void starter_netkey_cleanup (void);
 
 #endif /* _STARTER_NETKEY_H_ */
 
diff --git a/src/starter/parser/conf_parser.h b/src/starter/parser/conf_parser.h
index 2093820..49131a0 100644
--- a/src/starter/parser/conf_parser.h
+++ b/src/starter/parser/conf_parser.h
@@ -119,4 +119,4 @@ struct conf_parser_t {
  */
 conf_parser_t *conf_parser_create(const char *file);
 
-#endif /** CONF_PARSER_H_ @}*/
\ No newline at end of file
+#endif /** CONF_PARSER_H_ @}*/
diff --git a/src/starter/parser/lexer.c b/src/starter/parser/lexer.c
index cebf5a0..a093771 100644
--- a/src/starter/parser/lexer.c
+++ b/src/starter/parser/lexer.c
@@ -456,8 +456,8 @@ static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner );
 	yyg->yy_c_buf_p = yy_cp;
 
 /* %% [4.0] data tables for the DFA and the user's section 1 definitions go here */
-#define YY_NUM_RULES 29
-#define YY_END_OF_BUFFER 30
+#define YY_NUM_RULES 26
+#define YY_END_OF_BUFFER 27
 /* This struct is not used in this scanner,
    but its presence is necessary. */
 struct yy_trans_info
@@ -465,17 +465,16 @@ struct yy_trans_info
 	flex_int32_t yy_verify;
 	flex_int32_t yy_nxt;
 	};
-static yyconst flex_int16_t yy_accept[83] =
+static yyconst flex_int16_t yy_accept[80] =
     {   0,
-        0,    0,    0,    0,    0,    0,   30,   12,    3,    5,
+        0,    0,    0,    0,    0,    0,   27,   12,    3,    5,
        11,    4,    6,   12,   12,    2,   12,   12,   17,   13,
-       14,   15,   28,   19,   18,   20,   12,    3,    4,    4,
-        0,   12,    2,    0,    9,   12,   12,   17,   16,   28,
-       27,   26,   27,   24,   25,   21,   22,   23,   12,    0,
-       12,   12,   12,    0,   12,    8,   12,   12,    0,   12,
-       12,   12,    0,   12,   12,   12,    0,    0,   12,    0,
-        0,    0,   12,    0,    1,   10,   10,    0,    0,    0,
-        7,    0
+       14,   15,   25,   18,   19,   12,    3,    4,    4,    0,
+       12,    2,    0,    9,   12,   12,   17,   16,   25,   24,
+       23,   24,   20,   21,   22,   12,    0,   12,   12,   12,
+        0,   12,    8,   12,   12,    0,   12,   12,   12,    0,
+       12,   12,   12,    0,    0,   12,    0,    0,    0,   12,
+        0,    1,   10,   10,    0,    0,    0,    7,    0
     } ;
 
 static yyconst flex_int32_t yy_ec[256] =
@@ -489,11 +488,11 @@ static yyconst flex_int32_t yy_ec[256] =
         8,    1,    1,    9,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,   10,    1,    1,    1,    1,   11,   12,   13,   14,
+        1,   10,    1,    1,    1,    1,   11,    1,   12,   13,
 
-       15,   16,   17,    1,   18,    1,    1,   19,    1,   20,
-       21,   22,    1,   23,   24,   25,   26,   27,    1,    1,
-        1,    1,    1,    1,   28,    1,    1,    1,    1,    1,
+       14,   15,   16,    1,   17,    1,    1,   18,    1,   19,
+       20,   21,    1,   22,   23,   24,   25,   26,    1,    1,
+        1,    1,    1,    1,   27,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
@@ -510,110 +509,106 @@ static yyconst flex_int32_t yy_ec[256] =
         1,    1,    1,    1,    1
     } ;
 
-static yyconst flex_int32_t yy_meta[29] =
+static yyconst flex_int32_t yy_meta[28] =
     {   0,
         1,    2,    3,    1,    2,    4,    2,    5,    1,    6,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1
+        1,    1,    1,    1,    1,    1,    1
     } ;
 
-static yyconst flex_int16_t yy_base[94] =
+static yyconst flex_int16_t yy_base[91] =
     {   0,
-        0,   17,   43,   52,    7,   26,  102,    0,    9,  189,
-      189,    0,  189,   93,   79,   36,   10,   83,    0,  189,
-      189,   59,    0,  189,  189,   85,    0,   32,    0,    0,
-        0,   83,   65,   80,    0,   74,   70,    0,  189,    0,
-      189,  189,   88,  189,  189,  189,  189,  189,   71,   63,
-       31,   61,   58,   59,   64,    0,   63,   66,   61,   61,
-       56,   60,   53,   64,   41,   10,   40,   32,  109,   66,
-       49,   27,  116,   37,  189,  189,   71,    8,    2,    5,
-      189,  189,  124,  130,  136,  142,  148,  154,  159,  164,
-      170,  176,  182
-
+        0,   16,   41,   50,    4,    5,  101,    0,   24,  184,
+      184,    0,  184,   92,   79,   32,   16,   83,    0,  184,
+      184,   56,    0,  184,   81,    0,   33,    0,    0,    0,
+       84,   62,   81,    0,   75,   71,    0,  184,    0,  184,
+      184,   89,  184,  184,  184,   73,   68,    1,   66,   62,
+       63,   65,    0,   64,   67,   62,   62,   57,   62,   55,
+       67,   47,   63,   40,   31,  104,   68,   47,   35,  111,
+       42,  184,  184,   69,   17,    7,    9,  184,  184,  119,
+      125,  131,  137,  143,  149,  154,  159,  165,  171,  177
     } ;
 
-static yyconst flex_int16_t yy_def[94] =
+static yyconst flex_int16_t yy_def[91] =
     {   0,
-       83,   83,   84,   84,   85,   85,   82,   86,   82,   82,
-       82,   87,   82,   86,   86,   82,   86,   86,   88,   82,
-       82,   82,   89,   82,   82,   90,   86,   82,   87,   87,
-       86,   86,   82,   82,   86,   86,   86,   88,   82,   89,
-       82,   82,   82,   82,   82,   82,   82,   82,   86,   82,
-       86,   86,   86,   82,   86,   86,   86,   86,   82,   86,
-       86,   86,   82,   86,   86,   86,   82,   82,   91,   92,
-       93,   82,   91,   93,   82,   82,   92,   82,   82,   82,
-       82,    0,   82,   82,   82,   82,   82,   82,   82,   82,
-       82,   82,   82
-
+       80,   80,   81,   81,   82,   82,   79,   83,   79,   79,
+       79,   84,   79,   83,   83,   79,   83,   83,   85,   79,
+       79,   79,   86,   79,   87,   83,   79,   84,   84,   83,
+       83,   79,   79,   83,   83,   83,   85,   79,   86,   79,
+       79,   79,   79,   79,   79,   83,   79,   83,   83,   83,
+       79,   83,   83,   83,   83,   79,   83,   83,   83,   79,
+       83,   83,   83,   79,   79,   88,   89,   90,   79,   88,
+       90,   79,   79,   89,   79,   79,   79,   79,    0,   79,
+       79,   79,   79,   79,   79,   79,   79,   79,   79,   79
     } ;
 
-static yyconst flex_int16_t yy_nxt[218] =
+static yyconst flex_int16_t yy_nxt[212] =
     {   0,
-       82,    9,   10,   82,    9,   11,   12,   13,   14,   24,
-       28,   70,   25,   28,   70,   29,   26,   15,   16,   10,
-       35,   16,   11,   12,   13,   14,   81,   80,   24,   17,
-       36,   25,   79,   28,   15,   26,   28,   33,   29,   75,
-       33,   78,   29,   18,   20,   20,   55,   20,   21,   20,
-       56,   75,   22,   20,   20,   72,   20,   21,   20,   71,
-       69,   22,   34,   39,   39,   39,   33,   77,   68,   33,
-       77,   29,   77,   67,   66,   77,   65,   64,   63,   62,
-       61,   60,   59,   58,   57,   54,   39,   42,   43,   53,
-       42,   34,   52,   51,   50,   49,   44,   37,   32,   31,
-
-       45,   82,   82,   82,   46,   82,   82,   47,   82,   48,
-       74,   75,   82,   74,   74,   74,   74,   74,   75,   82,
-       74,   74,   74,   74,    8,    8,    8,    8,    8,    8,
-       19,   19,   19,   19,   19,   19,   23,   23,   23,   23,
-       23,   23,   27,   82,   82,   82,   82,   27,   30,   30,
-       82,   30,   30,   30,   38,   82,   82,   82,   38,   40,
-       40,   82,   82,   40,   41,   41,   41,   41,   41,   41,
-       73,   73,   73,   73,   73,   73,   76,   76,   76,   76,
-       82,   76,   74,   74,   74,   74,   74,   74,    7,   82,
-       82,   82,   82,   82,   82,   82,   82,   82,   82,   82,
-
-       82,   82,   82,   82,   82,   82,   82,   82,   82,   82,
-       82,   82,   82,   82,   82,   82,   82
+       79,    9,   10,   79,    9,   11,   12,   13,   14,   24,
+       24,   79,   79,   25,   25,   52,   15,   16,   10,   53,
+       16,   11,   12,   13,   14,   27,   34,   17,   27,   78,
+       28,   77,   15,   32,   27,   35,   32,   27,   28,   28,
+       76,   18,   20,   20,   72,   20,   21,   20,   75,   72,
+       22,   20,   20,   69,   20,   21,   20,   33,   68,   22,
+       38,   38,   38,   32,   67,   66,   32,   67,   28,   74,
+       74,   65,   74,   74,   64,   63,   62,   61,   60,   59,
+       58,   57,   38,   41,   42,   56,   55,   33,   54,   51,
+       50,   41,   49,   48,   47,   46,   36,   31,   30,   43,
+
+       79,   79,   44,   79,   45,   71,   72,   79,   71,   71,
+       71,   71,   71,   72,   79,   71,   71,   71,   71,    8,
+        8,    8,    8,    8,    8,   19,   19,   19,   19,   19,
+       19,   23,   23,   23,   23,   23,   23,   26,   79,   79,
+       79,   79,   26,   29,   29,   79,   29,   29,   29,   37,
+       79,   79,   79,   37,   39,   39,   39,   79,   39,   40,
+       40,   40,   40,   40,   40,   70,   70,   70,   70,   70,
+       70,   73,   73,   73,   73,   79,   73,   71,   71,   71,
+       71,   71,   71,    7,   79,   79,   79,   79,   79,   79,
+       79,   79,   79,   79,   79,   79,   79,   79,   79,   79,
+
+       79,   79,   79,   79,   79,   79,   79,   79,   79,   79,
+       79
     } ;
 
-static yyconst flex_int16_t yy_chk[218] =
+static yyconst flex_int16_t yy_chk[212] =
     {   0,
         0,    1,    1,    0,    1,    1,    1,    1,    1,    5,
-        9,   66,    5,    9,   66,    9,    5,    1,    2,    2,
-       17,    2,    2,    2,    2,    2,   80,   79,    6,    2,
-       17,    6,   78,   28,    2,    6,   28,   16,   28,   74,
-       16,   72,   16,    2,    3,    3,   51,    3,    3,    3,
-       51,   71,    3,    4,    4,   68,    4,    4,    4,   67,
-       65,    4,   16,   22,   22,   22,   33,   70,   64,   33,
-       70,   33,   77,   63,   62,   77,   61,   60,   59,   58,
-       57,   55,   54,   53,   52,   50,   22,   26,   26,   49,
-       43,   33,   37,   36,   34,   32,   26,   18,   15,   14,
-
-       26,    7,    0,    0,   26,    0,    0,   26,    0,   26,
-       69,   69,    0,   69,   69,   69,   69,   73,   73,    0,
-       73,   73,   73,   73,   83,   83,   83,   83,   83,   83,
-       84,   84,   84,   84,   84,   84,   85,   85,   85,   85,
-       85,   85,   86,    0,    0,    0,    0,   86,   87,   87,
-        0,   87,   87,   87,   88,    0,    0,    0,   88,   89,
-       89,    0,    0,   89,   90,   90,   90,   90,   90,   90,
-       91,   91,   91,   91,   91,   91,   92,   92,   92,   92,
-        0,   92,   93,   93,   93,   93,   93,   93,   82,   82,
-       82,   82,   82,   82,   82,   82,   82,   82,   82,   82,
-
-       82,   82,   82,   82,   82,   82,   82,   82,   82,   82,
-       82,   82,   82,   82,   82,   82,   82
+        6,    0,    0,    5,    6,   48,    1,    2,    2,   48,
+        2,    2,    2,    2,    2,    9,   17,    2,    9,   77,
+        9,   76,    2,   16,   27,   17,   16,   27,   16,   27,
+       75,    2,    3,    3,   71,    3,    3,    3,   69,   68,
+        3,    4,    4,   65,    4,    4,    4,   16,   64,    4,
+       22,   22,   22,   32,   63,   62,   32,   63,   32,   67,
+       74,   61,   67,   74,   60,   59,   58,   57,   56,   55,
+       54,   52,   22,   25,   25,   51,   50,   32,   49,   47,
+       46,   42,   36,   35,   33,   31,   18,   15,   14,   25,
+
+        7,    0,   25,    0,   25,   66,   66,    0,   66,   66,
+       66,   66,   70,   70,    0,   70,   70,   70,   70,   80,
+       80,   80,   80,   80,   80,   81,   81,   81,   81,   81,
+       81,   82,   82,   82,   82,   82,   82,   83,    0,    0,
+        0,    0,   83,   84,   84,    0,   84,   84,   84,   85,
+        0,    0,    0,   85,   86,   86,   86,    0,   86,   87,
+       87,   87,   87,   87,   87,   88,   88,   88,   88,   88,
+       88,   89,   89,   89,   89,    0,   89,   90,   90,   90,
+       90,   90,   90,   79,   79,   79,   79,   79,   79,   79,
+       79,   79,   79,   79,   79,   79,   79,   79,   79,   79,
+
+       79,   79,   79,   79,   79,   79,   79,   79,   79,   79,
+       79
     } ;
 
 /* Table of booleans, true if rule could match eol. */
-static yyconst flex_int32_t yy_rule_can_match_eol[30] =
+static yyconst flex_int32_t yy_rule_can_match_eol[27] =
     {   0,
-0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 
-    1, 0, 0, 0, 0, 0, 1, 0, 0, 0,     };
+0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 1, 0, 1, 0,     };
 
-static yyconst flex_int16_t yy_rule_linenum[29] =
+static yyconst flex_int16_t yy_rule_linenum[26] =
     {   0,
        60,   61,   62,   63,   65,   67,   68,   69,   70,   72,
-       77,   82,   90,  109,  112,  115,  118,  124,  126,  127,
-      150,  151,  152,  153,  154,  155,  156,  157
+       77,   82,   90,  109,  112,  115,  118,  124,  126,  145,
+      146,  147,  148,  149,  150
     } ;
 
 /* The intent behind this definition is that it'll catch
@@ -662,7 +657,7 @@ static void include_files(parser_helper_t *ctx);
 
 /* state used to scan quoted strings */
 
-#line 666 "parser/lexer.c"
+#line 661 "parser/lexer.c"
 
 #define INITIAL 0
 #define inc 1
@@ -977,7 +972,7 @@ YY_DECL
 #line 58 "parser/lexer.l"
 
 
-#line 981 "parser/lexer.c"
+#line 976 "parser/lexer.c"
 
     yylval = yylval_param;
 
@@ -1043,13 +1038,13 @@ yy_match:
 			while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
 				{
 				yy_current_state = (int) yy_def[yy_current_state];
-				if ( yy_current_state >= 83 )
+				if ( yy_current_state >= 80 )
 					yy_c = yy_meta[(unsigned int) yy_c];
 				}
 			yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
 			++yy_cp;
 			}
-		while ( yy_base[yy_current_state] != 189 );
+		while ( yy_base[yy_current_state] != 184 );
 
 yy_find_action:
 /* %% [10.0] code to find the action number goes here */
@@ -1084,13 +1079,13 @@ do_action:	/* This label is used only to access EOF actions. */
 			{
 			if ( yy_act == 0 )
 				fprintf( stderr, "--scanner backing up\n" );
-			else if ( yy_act < 29 )
+			else if ( yy_act < 26 )
 				fprintf( stderr, "--accepting rule at line %ld (\"%s\")\n",
 				         (long)yy_rule_linenum[yy_act], yytext );
-			else if ( yy_act == 29 )
+			else if ( yy_act == 26 )
 				fprintf( stderr, "--accepting default rule (\"%s\")\n",
 				         yytext );
-			else if ( yy_act == 30 )
+			else if ( yy_act == 27 )
 				fprintf( stderr, "--(end of buffer or a NUL)\n" );
 			else
 				fprintf( stderr, "--EOF (start condition %d)\n", YY_START );
@@ -1246,21 +1241,13 @@ case 18:
 case YY_STATE_EOF(str):
 #line 125 "parser/lexer.l"
 case 19:
-/* rule 19 can match eol */
-#line 127 "parser/lexer.l"
-case 20:
-/* rule 20 can match eol */
 YY_RULE_SETUP
-#line 127 "parser/lexer.l"
+#line 126 "parser/lexer.l"
 {
 		if (!streq(yytext, "\""))
 		{
-			if (streq(yytext, "\n"))
-			{	/* put the newline back to fix the line numbers */
-				unput('\n');
-				yy_set_bol(0);
-			}
 			PARSER_DBG1(yyextra, "unterminated string detected");
+			return STRING_ERROR;
 		}
 		if (yy_top_state(yyscanner) == inc)
 		{	/* string include */
@@ -1276,52 +1263,43 @@ YY_RULE_SETUP
 		}
 	}
 	YY_BREAK
-case 21:
+case 20:
 YY_RULE_SETUP
-#line 150 "parser/lexer.l"
+#line 145 "parser/lexer.l"
 yyextra->string_add(yyextra, "\n");
 	YY_BREAK
-case 22:
+case 21:
 YY_RULE_SETUP
-#line 151 "parser/lexer.l"
+#line 146 "parser/lexer.l"
 yyextra->string_add(yyextra, "\r");
 	YY_BREAK
-case 23:
+case 22:
 YY_RULE_SETUP
-#line 152 "parser/lexer.l"
+#line 147 "parser/lexer.l"
 yyextra->string_add(yyextra, "\t");
 	YY_BREAK
-case 24:
-YY_RULE_SETUP
-#line 153 "parser/lexer.l"
-yyextra->string_add(yyextra, "\b");
-	YY_BREAK
-case 25:
-YY_RULE_SETUP
-#line 154 "parser/lexer.l"
-yyextra->string_add(yyextra, "\f");
-	YY_BREAK
-case 26:
-/* rule 26 can match eol */
+case 23:
+/* rule 23 can match eol */
 YY_RULE_SETUP
-#line 155 "parser/lexer.l"
+#line 148 "parser/lexer.l"
 /* merge lines that end with EOL characters */
 	YY_BREAK
-case 27:
+case 24:
 YY_RULE_SETUP
-#line 156 "parser/lexer.l"
+#line 149 "parser/lexer.l"
 yyextra->string_add(yyextra, yytext+1);
 	YY_BREAK
-case 28:
+case 25:
+/* rule 25 can match eol */
 YY_RULE_SETUP
-#line 157 "parser/lexer.l"
+#line 150 "parser/lexer.l"
 {
 		yyextra->string_add(yyextra, yytext);
 	}
 	YY_BREAK
 
 case YY_STATE_EOF(INITIAL):
-#line 162 "parser/lexer.l"
+#line 155 "parser/lexer.l"
 {
 	conf_parser_pop_buffer_state(yyscanner);
 	if (!conf_parser_open_next_file(yyextra) && !YY_CURRENT_BUFFER)
@@ -1330,12 +1308,12 @@ case YY_STATE_EOF(INITIAL):
 	}
 }
 	YY_BREAK
-case 29:
+case 26:
 YY_RULE_SETUP
-#line 170 "parser/lexer.l"
+#line 163 "parser/lexer.l"
 YY_FATAL_ERROR( "flex scanner jammed" );
 	YY_BREAK
-#line 1339 "parser/lexer.c"
+#line 1317 "parser/lexer.c"
 
 	case YY_END_OF_BUFFER:
 		{
@@ -1649,7 +1627,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
 		while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
 			{
 			yy_current_state = (int) yy_def[yy_current_state];
-			if ( yy_current_state >= 83 )
+			if ( yy_current_state >= 80 )
 				yy_c = yy_meta[(unsigned int) yy_c];
 			}
 		yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
@@ -1683,11 +1661,11 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
 	while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
 		{
 		yy_current_state = (int) yy_def[yy_current_state];
-		if ( yy_current_state >= 83 )
+		if ( yy_current_state >= 80 )
 			yy_c = yy_meta[(unsigned int) yy_c];
 		}
 	yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
-	yy_is_jam = (yy_current_state == 82);
+	yy_is_jam = (yy_current_state == 79);
 
 	return yy_is_jam ? 0 : yy_current_state;
 }
@@ -2705,7 +2683,7 @@ void conf_parser_free (void * ptr , yyscan_t yyscanner)
 
 /* %ok-for-header */
 
-#line 170 "parser/lexer.l"
+#line 163 "parser/lexer.l"
 
 
 
diff --git a/src/starter/parser/lexer.l b/src/starter/parser/lexer.l
index d967e74..f70658e 100644
--- a/src/starter/parser/lexer.l
+++ b/src/starter/parser/lexer.l
@@ -123,16 +123,11 @@ static void include_files(parser_helper_t *ctx);
 <str>{
 	"\""				|
 	<<EOF>>				|
-	\n					|
 	\\					{
 		if (!streq(yytext, "\""))
 		{
-			if (streq(yytext, "\n"))
-			{	/* put the newline back to fix the line numbers */
-				unput('\n');
-				yy_set_bol(0);
-			}
 			PARSER_DBG1(yyextra, "unterminated string detected");
+			return STRING_ERROR;
 		}
 		if (yy_top_state(yyscanner) == inc)
 		{	/* string include */
@@ -150,11 +145,9 @@ static void include_files(parser_helper_t *ctx);
 	\\n     yyextra->string_add(yyextra, "\n");
 	\\r     yyextra->string_add(yyextra, "\r");
 	\\t     yyextra->string_add(yyextra, "\t");
-	\\b     yyextra->string_add(yyextra, "\b");
-	\\f     yyextra->string_add(yyextra, "\f");
 	\\\r?\n /* merge lines that end with EOL characters */
 	\\.     yyextra->string_add(yyextra, yytext+1);
-	[^\\\n"]+			{
+	[^\\"]+			{
 		yyextra->string_add(yyextra, yytext);
 	}
 }
diff --git a/src/starter/parser/parser.c b/src/starter/parser/parser.c
index 8cf3fe1..41ab515 100644
--- a/src/starter/parser/parser.c
+++ b/src/starter/parser/parser.c
@@ -166,7 +166,8 @@ extern int conf_parser_debug;
     NEWLINE = 261,
     CONFIG_SETUP = 262,
     CONN = 263,
-    CA = 264
+    CA = 264,
+    STRING_ERROR = 265
   };
 #endif
 /* Tokens.  */
@@ -177,6 +178,7 @@ extern int conf_parser_debug;
 #define CONFIG_SETUP 262
 #define CONN 263
 #define CA 264
+#define STRING_ERROR 265
 
 /* Value type.  */
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
@@ -188,7 +190,7 @@ union YYSTYPE
 	char *s;
 	conf_parser_section_t t;
 
-#line 192 "parser/parser.c" /* yacc.c:355  */
+#line 194 "parser/parser.c" /* yacc.c:355  */
 };
 # define YYSTYPE_IS_TRIVIAL 1
 # define YYSTYPE_IS_DECLARED 1
@@ -202,7 +204,7 @@ int conf_parser_parse (parser_helper_t *ctx);
 
 /* Copy the second part of user declarations.  */
 
-#line 206 "parser/parser.c" /* yacc.c:358  */
+#line 208 "parser/parser.c" /* yacc.c:358  */
 
 #ifdef short
 # undef short
@@ -447,7 +449,7 @@ union yyalloc
 #define YYLAST   11
 
 /* YYNTOKENS -- Number of terminals.  */
-#define YYNTOKENS  10
+#define YYNTOKENS  11
 /* YYNNTS -- Number of nonterminals.  */
 #define YYNNTS  8
 /* YYNRULES -- Number of rules.  */
@@ -458,7 +460,7 @@ union yyalloc
 /* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned
    by yylex, with out-of-bounds checking.  */
 #define YYUNDEFTOK  2
-#define YYMAXUTOK   264
+#define YYMAXUTOK   265
 
 #define YYTRANSLATE(YYX)                                                \
   ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
@@ -493,7 +495,7 @@ static const yytype_uint8 yytranslate[] =
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
-       5,     6,     7,     8,     9
+       5,     6,     7,     8,     9,    10
 };
 
 #if YYDEBUG
@@ -511,8 +513,9 @@ static const yytype_uint8 yyrline[] =
 static const char *const yytname[] =
 {
   "$end", "error", "$undefined", "STRING", "EQ", "SPACES", "NEWLINE",
-  "CONFIG_SETUP", "CONN", "CA", "$accept", "statements", "statement",
-  "section", "section_type", "section_name", "setting", "value", YY_NULLPTR
+  "CONFIG_SETUP", "CONN", "CA", "STRING_ERROR", "$accept", "statements",
+  "statement", "section", "section_type", "section_name", "setting",
+  "value", YY_NULLPTR
 };
 #endif
 
@@ -521,7 +524,8 @@ static const char *const yytname[] =
    (internal) symbol number NUM (which must be that of a token).  */
 static const yytype_uint16 yytoknum[] =
 {
-       0,   256,   257,   258,   259,   260,   261,   262,   263,   264
+       0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
+     265
 };
 # endif
 
@@ -583,15 +587,15 @@ static const yytype_int8 yycheck[] =
      symbol of state STATE-NUM.  */
 static const yytype_uint8 yystos[] =
 {
-       0,    11,     0,     5,     6,     7,     8,     9,    12,    13,
-      14,     3,    16,     3,    15,     4,     3,    17,     3
+       0,    12,     0,     5,     6,     7,     8,     9,    13,    14,
+      15,     3,    17,     3,    16,     4,     3,    18,     3
 };
 
   /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
 static const yytype_uint8 yyr1[] =
 {
-       0,    10,    11,    11,    11,    12,    12,    13,    14,    14,
-      14,    15,    15,    16,    16,    16,    16,    17,    17
+       0,    11,    12,    12,    12,    13,    13,    14,    15,    15,
+      15,    16,    16,    17,    17,    17,    17,    18,    18
 };
 
   /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN.  */
@@ -1026,19 +1030,19 @@ yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, parser_helper_t *c
           case 3: /* STRING  */
 #line 86 "parser/parser.y" /* yacc.c:1257  */
       { free(((*yyvaluep).s)); }
-#line 1030 "parser/parser.c" /* yacc.c:1257  */
+#line 1034 "parser/parser.c" /* yacc.c:1257  */
         break;
 
-    case 15: /* section_name  */
+    case 16: /* section_name  */
 #line 86 "parser/parser.y" /* yacc.c:1257  */
       { free(((*yyvaluep).s)); }
-#line 1036 "parser/parser.c" /* yacc.c:1257  */
+#line 1040 "parser/parser.c" /* yacc.c:1257  */
         break;
 
-    case 17: /* value  */
+    case 18: /* value  */
 #line 86 "parser/parser.y" /* yacc.c:1257  */
       { free(((*yyvaluep).s)); }
-#line 1042 "parser/parser.c" /* yacc.c:1257  */
+#line 1046 "parser/parser.c" /* yacc.c:1257  */
         break;
 
 
@@ -1315,7 +1319,7 @@ yyreduce:
 		conf_parser_t *parser = (conf_parser_t*)ctx->context;
 		parser->add_section(parser, (yyvsp[-1].t), (yyvsp[0].s));
 	}
-#line 1319 "parser/parser.c" /* yacc.c:1646  */
+#line 1323 "parser/parser.c" /* yacc.c:1646  */
     break;
 
   case 8:
@@ -1323,7 +1327,7 @@ yyreduce:
     {
 		(yyval.t) = CONF_PARSER_CONFIG_SETUP;
 	}
-#line 1327 "parser/parser.c" /* yacc.c:1646  */
+#line 1331 "parser/parser.c" /* yacc.c:1646  */
     break;
 
   case 9:
@@ -1331,7 +1335,7 @@ yyreduce:
     {
 		(yyval.t) = CONF_PARSER_CONN;
 	}
-#line 1335 "parser/parser.c" /* yacc.c:1646  */
+#line 1339 "parser/parser.c" /* yacc.c:1646  */
     break;
 
   case 10:
@@ -1339,7 +1343,7 @@ yyreduce:
     {
 		(yyval.t) = CONF_PARSER_CA;
 	}
-#line 1343 "parser/parser.c" /* yacc.c:1646  */
+#line 1347 "parser/parser.c" /* yacc.c:1646  */
     break;
 
   case 11:
@@ -1347,7 +1351,7 @@ yyreduce:
     {
 		(yyval.s) = NULL;
 	}
-#line 1351 "parser/parser.c" /* yacc.c:1646  */
+#line 1355 "parser/parser.c" /* yacc.c:1646  */
     break;
 
   case 12:
@@ -1355,7 +1359,7 @@ yyreduce:
     {
 		(yyval.s) = (yyvsp[0].s);
 	}
-#line 1359 "parser/parser.c" /* yacc.c:1646  */
+#line 1363 "parser/parser.c" /* yacc.c:1646  */
     break;
 
   case 14:
@@ -1371,7 +1375,7 @@ yyreduce:
 		conf_parser_t *parser = (conf_parser_t*)ctx->context;
 		parser->add_setting(parser, (yyvsp[-2].s), (yyvsp[0].s));
 	}
-#line 1375 "parser/parser.c" /* yacc.c:1646  */
+#line 1379 "parser/parser.c" /* yacc.c:1646  */
     break;
 
   case 15:
@@ -1386,7 +1390,7 @@ yyreduce:
 		conf_parser_t *parser = (conf_parser_t*)ctx->context;
 		parser->add_setting(parser, (yyvsp[-1].s), NULL);
 	}
-#line 1390 "parser/parser.c" /* yacc.c:1646  */
+#line 1394 "parser/parser.c" /* yacc.c:1646  */
     break;
 
   case 16:
@@ -1396,7 +1400,7 @@ yyreduce:
 		free((yyvsp[0].s));
 		YYERROR;
 	}
-#line 1400 "parser/parser.c" /* yacc.c:1646  */
+#line 1404 "parser/parser.c" /* yacc.c:1646  */
     break;
 
   case 18:
@@ -1411,11 +1415,11 @@ yyreduce:
 		free((yyvsp[-1].s));
 		free((yyvsp[0].s));
 	}
-#line 1415 "parser/parser.c" /* yacc.c:1646  */
+#line 1419 "parser/parser.c" /* yacc.c:1646  */
     break;
 
 
-#line 1419 "parser/parser.c" /* yacc.c:1646  */
+#line 1423 "parser/parser.c" /* yacc.c:1646  */
       default: break;
     }
   /* User semantic actions sometimes alter yychar, and that requires
diff --git a/src/starter/parser/parser.h b/src/starter/parser/parser.h
index c10547b..ed6ed2b 100644
--- a/src/starter/parser/parser.h
+++ b/src/starter/parser/parser.h
@@ -51,7 +51,8 @@ extern int conf_parser_debug;
     NEWLINE = 261,
     CONFIG_SETUP = 262,
     CONN = 263,
-    CA = 264
+    CA = 264,
+    STRING_ERROR = 265
   };
 #endif
 /* Tokens.  */
@@ -62,6 +63,7 @@ extern int conf_parser_debug;
 #define CONFIG_SETUP 262
 #define CONN 263
 #define CA 264
+#define STRING_ERROR 265
 
 /* Value type.  */
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
@@ -73,7 +75,7 @@ union YYSTYPE
 	char *s;
 	conf_parser_section_t t;
 
-#line 77 "parser/parser.h" /* yacc.c:1909  */
+#line 79 "parser/parser.h" /* yacc.c:1909  */
 };
 # define YYSTYPE_IS_TRIVIAL 1
 # define YYSTYPE_IS_DECLARED 1
diff --git a/src/starter/parser/parser.y b/src/starter/parser/parser.y
index 54dedc1..0b2b3b0 100644
--- a/src/starter/parser/parser.y
+++ b/src/starter/parser/parser.y
@@ -73,7 +73,7 @@ static int yylex(YYSTYPE *lvalp, parser_helper_t *ctx)
 	conf_parser_section_t t;
 }
 %token <s> STRING
-%token EQ SPACES NEWLINE CONFIG_SETUP CONN CA
+%token EQ SPACES NEWLINE CONFIG_SETUP CONN CA STRING_ERROR
 
 /* ...and other symbols */
 %type <t> section_type
diff --git a/src/starter/starter.c b/src/starter/starter.c
index a192989..ab1ebdd 100644
--- a/src/starter/starter.c
+++ b/src/starter/starter.c
@@ -703,7 +703,6 @@ int main (int argc, char **argv)
 			{
 				starter_stop_charon();
 			}
-			starter_netkey_cleanup();
 			confread_free(cfg);
 			unlink(starter_pid_file);
 			cleanup();
diff --git a/src/starter/starterstroke.c b/src/starter/starterstroke.c
index 79a92cd..b92c00c 100644
--- a/src/starter/starterstroke.c
+++ b/src/starter/starterstroke.c
@@ -16,6 +16,7 @@
 
 #include <unistd.h>
 #include <stdlib.h>
+#include <stdint.h>
 #include <string.h>
 
 #include <credentials/auth_cfg.h>
diff --git a/src/starter/tests/suites/test_parser.c b/src/starter/tests/suites/test_parser.c
index 26a41ba..4ae7b22 100644
--- a/src/starter/tests/suites/test_parser.c
+++ b/src/starter/tests/suites/test_parser.c
@@ -328,6 +328,9 @@ static struct {
 	{ TRUE, "conn foo\n\tkey=val     ue", "foo", "val ue" },
 	{ TRUE, "conn foo\n\tkey=\"val   ue\"", "foo", "val   ue" },
 	{ TRUE, "conn foo\n\tkey=\"val\\nue\"", "foo", "val\nue" },
+	{ TRUE, "conn foo\n\tkey=\"val\nue\"", "foo", "val\nue" },
+	{ TRUE, "conn foo\n\tkey=\"val\\\nue\"", "foo", "value" },
+	{ FALSE, "conn foo\n\tkey=\"unterminated", "foo", NULL },
 };
 
 START_TEST(test_strings)
diff --git a/src/stroke/stroke.c b/src/stroke/stroke.c
index 07911d2..2dfb66d 100644
--- a/src/stroke/stroke.c
+++ b/src/stroke/stroke.c
@@ -17,6 +17,7 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <stdio.h>
+#include <stdint.h>
 #include <string.h>
 #include <getopt.h>
 
diff --git a/src/swanctl/Makefile.am b/src/swanctl/Makefile.am
index f4f9fdf..703e574 100644
--- a/src/swanctl/Makefile.am
+++ b/src/swanctl/Makefile.am
@@ -7,10 +7,12 @@ swanctl_SOURCES = \
 	commands/install.c \
 	commands/list_sas.c \
 	commands/list_pols.c \
+	commands/list_authorities.c \
 	commands/list_conns.c \
 	commands/list_certs.c \
 	commands/list_pools.c \
 	commands/load_all.c \
+	commands/load_authorities.h  commands/load_authorities.c \
 	commands/load_conns.c commands/load_conns.h \
 	commands/load_creds.c commands/load_creds.h \
 	commands/load_pools.c commands/load_pools.h \
@@ -46,7 +48,7 @@ CLEANFILES = $(man_MANS)
 
 swanctl.conf.5.main: swanctl.opt
 	$(AM_V_GEN) \
-	$(PYTHON) $(top_srcdir)/conf/format-options.py -n -f man swanctl.opt > $(srcdir)/$@
+	cd $(srcdir) && $(PYTHON) $(abs_top_srcdir)/conf/format-options.py -n -f man swanctl.opt > $@
 
 swanctl.conf.5: swanctl.conf.5.head swanctl.conf.5.main swanctl.conf.5.tail
 	$(AM_V_GEN) \
diff --git a/src/swanctl/Makefile.in b/src/swanctl/Makefile.in
index f981bb1..a4d853c 100644
--- a/src/swanctl/Makefile.in
+++ b/src/swanctl/Makefile.in
@@ -107,8 +107,10 @@ am__dirstamp = $(am__leading_dot)dirstamp
 am_swanctl_OBJECTS = command.$(OBJEXT) commands/initiate.$(OBJEXT) \
 	commands/terminate.$(OBJEXT) commands/install.$(OBJEXT) \
 	commands/list_sas.$(OBJEXT) commands/list_pols.$(OBJEXT) \
+	commands/list_authorities.$(OBJEXT) \
 	commands/list_conns.$(OBJEXT) commands/list_certs.$(OBJEXT) \
 	commands/list_pools.$(OBJEXT) commands/load_all.$(OBJEXT) \
+	commands/load_authorities.$(OBJEXT) \
 	commands/load_conns.$(OBJEXT) commands/load_creds.$(OBJEXT) \
 	commands/load_pools.$(OBJEXT) commands/log.$(OBJEXT) \
 	commands/version.$(OBJEXT) commands/stats.$(OBJEXT) \
@@ -445,10 +447,12 @@ swanctl_SOURCES = \
 	commands/install.c \
 	commands/list_sas.c \
 	commands/list_pols.c \
+	commands/list_authorities.c \
 	commands/list_conns.c \
 	commands/list_certs.c \
 	commands/list_pools.c \
 	commands/load_all.c \
+	commands/load_authorities.h  commands/load_authorities.c \
 	commands/load_conns.c commands/load_conns.h \
 	commands/load_creds.c commands/load_creds.h \
 	commands/load_pools.c commands/load_pools.h \
@@ -581,6 +585,8 @@ commands/list_sas.$(OBJEXT): commands/$(am__dirstamp) \
 	commands/$(DEPDIR)/$(am__dirstamp)
 commands/list_pols.$(OBJEXT): commands/$(am__dirstamp) \
 	commands/$(DEPDIR)/$(am__dirstamp)
+commands/list_authorities.$(OBJEXT): commands/$(am__dirstamp) \
+	commands/$(DEPDIR)/$(am__dirstamp)
 commands/list_conns.$(OBJEXT): commands/$(am__dirstamp) \
 	commands/$(DEPDIR)/$(am__dirstamp)
 commands/list_certs.$(OBJEXT): commands/$(am__dirstamp) \
@@ -589,6 +595,8 @@ commands/list_pools.$(OBJEXT): commands/$(am__dirstamp) \
 	commands/$(DEPDIR)/$(am__dirstamp)
 commands/load_all.$(OBJEXT): commands/$(am__dirstamp) \
 	commands/$(DEPDIR)/$(am__dirstamp)
+commands/load_authorities.$(OBJEXT): commands/$(am__dirstamp) \
+	commands/$(DEPDIR)/$(am__dirstamp)
 commands/load_conns.$(OBJEXT): commands/$(am__dirstamp) \
 	commands/$(DEPDIR)/$(am__dirstamp)
 commands/load_creds.$(OBJEXT): commands/$(am__dirstamp) \
@@ -619,12 +627,14 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/swanctl.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at commands/$(DEPDIR)/initiate.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at commands/$(DEPDIR)/install.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at commands/$(DEPDIR)/list_authorities.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at commands/$(DEPDIR)/list_certs.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at commands/$(DEPDIR)/list_conns.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at commands/$(DEPDIR)/list_pols.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at commands/$(DEPDIR)/list_pools.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at commands/$(DEPDIR)/list_sas.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at commands/$(DEPDIR)/load_all.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at commands/$(DEPDIR)/load_authorities.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at commands/$(DEPDIR)/load_conns.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at commands/$(DEPDIR)/load_creds.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at commands/$(DEPDIR)/load_pools.Po at am__quote@
@@ -977,7 +987,7 @@ swanctl.o :		$(top_builddir)/config.status
 
 swanctl.conf.5.main: swanctl.opt
 	$(AM_V_GEN) \
-	$(PYTHON) $(top_srcdir)/conf/format-options.py -n -f man swanctl.opt > $(srcdir)/$@
+	cd $(srcdir) && $(PYTHON) $(abs_top_srcdir)/conf/format-options.py -n -f man swanctl.opt > $@
 
 swanctl.conf.5: swanctl.conf.5.head swanctl.conf.5.main swanctl.conf.5.tail
 	$(AM_V_GEN) \
diff --git a/src/swanctl/command.c b/src/swanctl/command.c
index 03cd8b9..26c4134 100644
--- a/src/swanctl/command.c
+++ b/src/swanctl/command.c
@@ -211,7 +211,7 @@ int command_usage(char *error, ...)
 	{
 		for (i = 0; i < MAX_COMMANDS && cmds[i].cmd; i++)
 		{
-			fprintf(out, "  swanctl --%-15s (-%c)  %s\n",
+			fprintf(out, "  swanctl --%-16s (-%c)  %s\n",
 					cmds[i].cmd, cmds[i].op, cmds[i].description);
 		}
 	}
diff --git a/src/swanctl/command.h b/src/swanctl/command.h
index ffc3190..0760d13 100644
--- a/src/swanctl/command.h
+++ b/src/swanctl/command.h
@@ -27,7 +27,7 @@
 /**
  * Maximum number of commands (+1).
  */
-#define MAX_COMMANDS 19
+#define MAX_COMMANDS 21
 
 /**
  * Maximum number of options in a command (+3)
diff --git a/src/swanctl/commands/list_authorities.c b/src/swanctl/commands/list_authorities.c
new file mode 100644
index 0000000..8bff6f9
--- /dev/null
+++ b/src/swanctl/commands/list_authorities.c
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2015 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
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <errno.h>
+
+#include "command.h"
+
+#define LABELED_CRL_URI		(1 << 0)
+#define LABELED_OCSP_URI	(1 << 1)
+
+CALLBACK(authority_kv, int,
+	void *null, vici_res_t *res, char *name, void *value, int len)
+{
+	chunk_t chunk;
+
+	chunk = chunk_create(value, len);
+	if (chunk_printable(chunk, NULL, ' '))
+	{
+		printf("  %s: %.*s\n", name, len, value);
+	}
+
+	return 0;
+}
+
+
+CALLBACK(authority_list, int,
+	int *labeled, vici_res_t *res, char *name, void *value, int len)
+{
+	chunk_t chunk;
+
+	chunk = chunk_create(value, len);
+	if (chunk_printable(chunk, NULL, ' '))
+	{
+		if (streq(name, "crl_uris"))
+		{
+			printf("  %s %.*s\n",
+				  (*labeled & LABELED_CRL_URI)  ? "          " : "crl_uris: ", 
+				  len, value);
+			*labeled |= LABELED_CRL_URI;
+		}
+		if (streq(name, "ocsp_uris"))
+		{
+			printf("  %s %.*s\n",
+				  (*labeled & LABELED_OCSP_URI) ? "          " : "ocsp_uris:",
+				  len, value);
+			*labeled %= LABELED_OCSP_URI;
+		}
+	}
+	return 0;
+}
+
+CALLBACK(authorities, int,
+	void *null, vici_res_t *res, char *name)
+{
+	int labeled = 0;
+
+	printf("%s:\n", name);
+
+	return vici_parse_cb(res, NULL, authority_kv, authority_list, &labeled);
+}
+
+CALLBACK(list_cb, void,
+	command_format_options_t *format, char *name, vici_res_t *res)
+{
+	if (*format & COMMAND_FORMAT_RAW)
+	{
+		vici_dump(res, "list-authorities event", *format & COMMAND_FORMAT_PRETTY,
+				  stdout);
+	}
+	else
+	{
+		if (vici_parse_cb(res, authorities, NULL, NULL, NULL) != 0)
+		{
+			fprintf(stderr, "parsing authority event failed: %s\n",
+					strerror(errno));
+		}
+	}
+}
+
+static int list_authorities(vici_conn_t *conn)
+{
+	vici_req_t *req;
+	vici_res_t *res;
+	command_format_options_t format = COMMAND_FORMAT_NONE;
+	char *arg, *ca_name = NULL;;
+	int ret = 0;
+
+	while (TRUE)
+	{
+		switch (command_getopt(&arg))
+		{
+			case 'h':
+				return command_usage(NULL);
+			case 'n':
+				ca_name = arg;
+				continue;
+			case 'P':
+				format |= COMMAND_FORMAT_PRETTY;
+				/* fall through to raw */
+			case 'r':
+				format |= COMMAND_FORMAT_RAW;
+				continue;
+			case EOF:
+				break;
+			default:
+				return command_usage("invalid --list-authorities option");
+		}
+		break;
+	}
+	if (vici_register(conn, "list-authority", list_cb, &format) != 0)
+	{
+		ret = errno;
+		fprintf(stderr, "registering for authorities failed: %s\n",
+				strerror(errno));
+		return ret;
+	}
+
+	req = vici_begin("list-authorities");
+	if (ca_name)
+	{
+		vici_add_key_valuef(req, "name", "%s", ca_name);
+	}
+	res = vici_submit(req, conn);
+	if (!res)
+	{
+		ret = errno;
+		fprintf(stderr, "list-authorities request failed: %s\n", strerror(errno));
+		return ret;
+	}
+	if (format & COMMAND_FORMAT_RAW)
+	{
+		vici_dump(res, "list-authorities reply", format & COMMAND_FORMAT_PRETTY,
+				  stdout);
+	}
+	vici_free_res(res);
+	return 0;
+}
+
+/**
+ * Register the command.
+ */
+static void __attribute__ ((constructor))reg()
+{
+	command_register((command_t) {
+		list_authorities, 'B', "list-authorities",
+		"list loaded authority configurations",
+		{"[--raw|--pretty]"},
+		{
+			{"help",		'h', 0, "show usage information"},
+			{"name",		'n', 1, "filter by authority name"},
+			{"raw",			'r', 0, "dump raw response message"},
+			{"pretty",		'P', 0, "dump raw response message in pretty print"},
+		}
+	});
+}
diff --git a/src/swanctl/commands/list_certs.c b/src/swanctl/commands/list_certs.c
index ecb6528..167f8d8 100644
--- a/src/swanctl/commands/list_certs.c
+++ b/src/swanctl/commands/list_certs.c
@@ -2,6 +2,9 @@
  * Copyright (C) 2014 Martin Willi
  * Copyright (C) 2014 revosec AG
  *
+ * Copyright (C) 2015 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
@@ -388,7 +391,7 @@ static void print_crl(crl_t *crl)
 		chunk = chunk_skip_zero(chunk);
 		localtime_r(&ts, &tm);
 		strftime(buf, sizeof(buf), "%F %T", &tm);
-		printf("    %#B %N %s\n", &chunk, crl_reason_names, reason, buf);
+		printf("    %#B: %s, %N\n", &chunk, buf, crl_reason_names, reason);
 		count++;
 	}
 	enumerator->destroy(enumerator);
diff --git a/src/swanctl/commands/load_all.c b/src/swanctl/commands/load_all.c
index f47fee5..0010ce1 100644
--- a/src/swanctl/commands/load_all.c
+++ b/src/swanctl/commands/load_all.c
@@ -22,6 +22,7 @@
 #include "command.h"
 #include "swanctl.h"
 #include "load_creds.h"
+#include "load_authorities.h"
 #include "load_pools.h"
 #include "load_conns.h"
 
@@ -72,6 +73,10 @@ static int load_all(vici_conn_t *conn)
 	}
 	if (ret == 0)
 	{
+		ret = load_authorities_cfg(conn, format, cfg);
+	}
+	if (ret == 0)
+	{
 		ret = load_pools_cfg(conn, format, cfg);
 	}
 	if (ret == 0)
@@ -90,7 +95,8 @@ static int load_all(vici_conn_t *conn)
 static void __attribute__ ((constructor))reg()
 {
 	command_register((command_t) {
-		load_all, 'q', "load-all", "load credentials, pools and connections",
+		load_all, 'q', "load-all",
+		"load credentials, authorities, pools and connections",
 		{"[--raw|--pretty] [--clear] [--noprompt]"},
 		{
 			{"help",		'h', 0, "show usage information"},
diff --git a/src/swanctl/commands/load_authorities.c b/src/swanctl/commands/load_authorities.c
new file mode 100644
index 0000000..88dde6a
--- /dev/null
+++ b/src/swanctl/commands/load_authorities.c
@@ -0,0 +1,365 @@
+/*
+ * Copyright (C) 2015 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
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <errno.h>
+#include <limits.h>
+
+#include "command.h"
+#include "swanctl.h"
+#include "load_authorities.h"
+
+/**
+ * Add a vici list from a comma separated string value
+ */
+static void add_list_key(vici_req_t *req, char *key, char *value)
+{
+	enumerator_t *enumerator;
+	char *token;
+
+	vici_begin_list(req, key);
+	enumerator = enumerator_create_token(value, ",", " ");
+	while (enumerator->enumerate(enumerator, &token))
+	{
+		vici_add_list_itemf(req, "%s", token);
+	}
+	enumerator->destroy(enumerator);
+	vici_end_list(req);
+}
+
+/**
+ * Add a vici certificate blob value given by its file patch
+ */
+static bool add_file_key_value(vici_req_t *req, char *key, char *value)
+{
+	chunk_t *map;
+	char *path, buf[PATH_MAX];
+
+	if (path_absolute(value))
+	{
+		path = value;
+	}
+	else
+	{
+		path = buf;
+		snprintf(path, PATH_MAX, "%s%s%s",
+				 SWANCTL_X509CADIR, DIRECTORY_SEPARATOR, value);
+	}
+	map = chunk_map(path, FALSE);
+
+	if (map)
+	{
+		vici_add_key_value(req, key, map->ptr, map->len);
+		chunk_unmap(map);
+		return TRUE;
+	}
+	else
+	{
+		fprintf(stderr, "loading ca certificate '%s' failed: %s\n",
+				path, strerror(errno));
+		return FALSE;
+	}
+}
+
+/**
+ * Translate sletting key/values from a section into vici key-values/lists
+ */
+static bool add_key_values(vici_req_t *req, settings_t *cfg, char *section)
+{
+	enumerator_t *enumerator;
+	char *key, *value;
+	bool ret = TRUE;
+
+	enumerator = cfg->create_key_value_enumerator(cfg, section);
+	while (enumerator->enumerate(enumerator, &key, &value))
+	{
+		/* pool subnet is encoded as key/value, all other attributes as list */
+		if (streq(key, "cacert"))
+		{
+			ret = add_file_key_value(req, key, value);
+		}
+		else if (streq(key, "cert_uri_base"))
+		{
+			vici_add_key_valuef(req, key, "%s", value);
+		}
+		else
+		{
+			add_list_key(req, key, value);
+		}
+		if (!ret)
+		{
+			break;
+		}
+	}
+	enumerator->destroy(enumerator);
+
+	return ret;
+}
+
+/**
+ * Load an authority configuration
+ */
+static bool load_authority(vici_conn_t *conn, settings_t *cfg,
+						   char *section, command_format_options_t format)
+{
+	vici_req_t *req;
+	vici_res_t *res;
+	bool ret = TRUE;
+	char buf[128];
+
+	snprintf(buf, sizeof(buf), "%s.%s", "authorities", section);
+
+	req = vici_begin("load-authority");
+
+	vici_begin_section(req, section);
+	if (!add_key_values(req, cfg, buf))
+	{
+		vici_free_req(req);
+		return FALSE;
+	}
+	vici_end_section(req);
+
+	res = vici_submit(req, conn);
+	if (!res)
+	{
+		fprintf(stderr, "load-authority request failed: %s\n", strerror(errno));
+		return FALSE;
+	}
+	if (format & COMMAND_FORMAT_RAW)
+	{
+		vici_dump(res, "load-authority reply", format & COMMAND_FORMAT_PRETTY,
+				  stdout);
+	}
+	else if (!streq(vici_find_str(res, "no", "success"), "yes"))
+	{
+		fprintf(stderr, "loading authority '%s' failed: %s\n",
+				section, vici_find_str(res, "", "errmsg"));
+		ret = FALSE;
+	}
+	else
+	{
+		printf("loaded authority '%s'\n", section);
+	}
+	vici_free_res(res);
+	return ret;
+}
+
+CALLBACK(list_authority, int,
+	linked_list_t *list, vici_res_t *res, char *name, void *value, int len)
+{
+	if (streq(name, "authorities"))
+	{
+		char *str;
+
+		if (asprintf(&str, "%.*s", len, value) != -1)
+		{
+			list->insert_last(list, str);
+		}
+	}
+	return 0;
+}
+
+/**
+ * Create a list of currently loaded authorities
+ */
+static linked_list_t* list_authorities(vici_conn_t *conn,
+									   command_format_options_t format)
+{
+	linked_list_t *list;
+	vici_res_t *res;
+
+	list = linked_list_create();
+
+	res = vici_submit(vici_begin("get-authorities"), conn);
+	if (res)
+	{
+		if (format & COMMAND_FORMAT_RAW)
+		{
+			vici_dump(res, "get-authorities reply", format & COMMAND_FORMAT_PRETTY,
+					  stdout);
+		}
+		vici_parse_cb(res, NULL, NULL, list_authority, list);
+		vici_free_res(res);
+	}
+	return list;
+}
+
+/**
+ * Remove and free a string from a list
+ */
+static void remove_from_list(linked_list_t *list, char *str)
+{
+	enumerator_t *enumerator;
+	char *current;
+
+	enumerator = list->create_enumerator(list);
+	while (enumerator->enumerate(enumerator, &current))
+	{
+		if (streq(current, str))
+		{
+			list->remove_at(list, enumerator);
+			free(current);
+		}
+	}
+	enumerator->destroy(enumerator);
+}
+
+/**
+ * Unload a authority by name
+ */
+static bool unload_authority(vici_conn_t *conn, char *name,
+							 command_format_options_t format)
+{
+	vici_req_t *req;
+	vici_res_t *res;
+	bool ret = TRUE;
+
+	req = vici_begin("unload-authority");
+	vici_add_key_valuef(req, "name", "%s", name);
+	res = vici_submit(req, conn);
+	if (!res)
+	{
+		fprintf(stderr, "unload-authority request failed: %s\n", strerror(errno));
+		return FALSE;
+	}
+	if (format & COMMAND_FORMAT_RAW)
+	{
+		vici_dump(res, "unload-authority reply", format & COMMAND_FORMAT_PRETTY,
+				  stdout);
+	}
+	else if (!streq(vici_find_str(res, "no", "success"), "yes"))
+	{
+		fprintf(stderr, "unloading authority '%s' failed: %s\n",
+				name, vici_find_str(res, "", "errmsg"));
+		ret = FALSE;
+	}
+	vici_free_res(res);
+	return ret;
+}
+
+/**
+ * See header.
+ */
+int load_authorities_cfg(vici_conn_t *conn, command_format_options_t format,
+						 settings_t *cfg)
+{
+	u_int found = 0, loaded = 0, unloaded = 0;
+	char *section;
+	enumerator_t *enumerator;
+	linked_list_t *authorities;
+
+	authorities = list_authorities(conn, format);
+
+	enumerator = cfg->create_section_enumerator(cfg, "authorities");
+	while (enumerator->enumerate(enumerator, &section))
+	{
+		remove_from_list(authorities, section);
+		found++;
+		if (load_authority(conn, cfg, section, format))
+		{
+			loaded++;
+		}
+	}
+	enumerator->destroy(enumerator);
+
+	/* unload all authorities in daemon, but not in file */
+	while (authorities->remove_first(authorities, (void**)&section) == SUCCESS)
+	{
+		if (unload_authority(conn, section, format))
+		{
+			unloaded++;
+		}
+		free(section);
+	}
+	authorities->destroy(authorities);
+
+	if (format & COMMAND_FORMAT_RAW)
+	{
+		return 0;
+	}
+	if (found == 0)
+	{
+		printf("no authorities found, %u unloaded\n", unloaded);
+		return 0;
+	}
+	if (loaded == found)
+	{
+		printf("successfully loaded %u authorities, %u unloaded\n",
+			   loaded, unloaded);
+		return 0;
+	}
+	fprintf(stderr, "loaded %u of %u authorities, %u failed to load, "
+			"%u unloaded\n", loaded, found, found - loaded, unloaded);
+	return EINVAL;
+}
+
+static int load_authorities(vici_conn_t *conn)
+{
+	command_format_options_t format = COMMAND_FORMAT_NONE;
+	settings_t *cfg;
+	char *arg;
+	int ret;
+
+	while (TRUE)
+	{
+		switch (command_getopt(&arg))
+		{
+			case 'h':
+				return command_usage(NULL);
+			case 'P':
+				format |= COMMAND_FORMAT_PRETTY;
+				/* fall through to raw */
+			case 'r':
+				format |= COMMAND_FORMAT_RAW;
+				continue;
+			case EOF:
+				break;
+			default:
+				return command_usage("invalid --load-authorities option");
+		}
+		break;
+	}
+
+	cfg = settings_create(SWANCTL_CONF);
+	if (!cfg)
+	{
+		fprintf(stderr, "parsing '%s' failed\n", SWANCTL_CONF);
+		return EINVAL;
+	}
+
+	ret = load_authorities_cfg(conn, format, cfg);
+
+	cfg->destroy(cfg);
+
+	return ret;
+}
+
+/**
+ * Register the command.
+ */
+static void __attribute__ ((constructor))reg()
+{
+	command_register((command_t) {
+		load_authorities, 'b',
+		"load-authorities", "(re-)load authority configuration",
+		{"[--raw|--pretty]"},
+		{
+			{"help",		'h', 0, "show usage information"},
+			{"raw",			'r', 0, "dump raw response message"},
+			{"pretty",		'P', 0, "dump raw response message in pretty print"},
+		}
+	});
+}
diff --git a/src/libcharon/tests/libcharon_tests.h b/src/swanctl/commands/load_authorities.h
similarity index 57%
copy from src/libcharon/tests/libcharon_tests.h
copy to src/swanctl/commands/load_authorities.h
index dc9681a..d4be214 100644
--- a/src/libcharon/tests/libcharon_tests.h
+++ b/src/swanctl/commands/load_authorities.h
@@ -1,6 +1,6 @@
 /*
- * Copyright (C) 2014 Martin Willi
- * Copyright (C) 2014 revosec AG
+ * Copyright (C) 2015 Andreas Stefffen
+ * 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
@@ -13,4 +13,14 @@
  * for more details.
  */
 
-TEST_SUITE(mem_pool_suite_create)
+#include "command.h"
+
+/**
+ * Load all certification authority definitions from configuration file
+ *
+ * @param conn		vici connection to load to
+ * @param format	output format
+ * @param cfg		configuration to load from
+ */
+int load_authorities_cfg(vici_conn_t *conn, command_format_options_t format,
+						 settings_t *cfg);
diff --git a/src/swanctl/swanctl.8.in b/src/swanctl/swanctl.8.in
index 543c10a..cd033f9 100644
--- a/src/swanctl/swanctl.8.in
+++ b/src/swanctl/swanctl.8.in
@@ -53,9 +53,15 @@ list currently active IKE_SAs
 .B "\-P, \-\-list\-pols"
 list currently installed policies
 .TP
+.B "\-b, \-\-load\-authorities"
+(re\-)load certification authorities information
+.TP
 .B "\-L, \-\-list\-conns"
 list loaded configurations
 .TP
+.B "\-B, \-\-list\-authorities"
+list loaded certification authorities information
+.TP
 .B "\-x, \-\-list\-certs"
 list stored certificates
 .TP
@@ -63,7 +69,7 @@ list stored certificates
 list loaded pool configurations
 .TP
 .B "\-q, \-\-load\-all"
-(re\-)load credentials, pools and connections
+(re\-)load credentials, pools, authorities and connections
 .TP
 .B "\-c, \-\-load\-conns"
 (re\-)load connection configuration
diff --git a/src/swanctl/swanctl.conf b/src/swanctl/swanctl.conf
index faafecc..c480ce1 100644
--- a/src/swanctl/swanctl.conf
+++ b/src/swanctl/swanctl.conf
@@ -180,6 +180,9 @@
                 # drop).
                 # mode = tunnel
 
+                # Whether to install IPsec policies or not.
+                # policies = yes
+
                 # Action to perform on DPD timeout (clear, trap or restart).
                 # dpd_action = clear
 
@@ -316,3 +319,25 @@
 
 # }
 
+# Section defining attributes of certification authorities.
+# authorities {
+
+    # Section defining a certification authority with a unique name.
+    # <name> {
+
+        # CA certificate belonging to the certification authority.
+        # cacert =
+
+        # Comma-separated list of CRL distribution points
+        # crl_uris =
+
+        # Comma-separated list of OCSP URIs
+        # ocsp_uris =
+
+        # Defines the base URI for the Hash and URL feature supported by IKEv2.
+        # cert_uri_base =
+
+    # }
+
+# }
+
diff --git a/src/swanctl/swanctl.conf.5.main b/src/swanctl/swanctl.conf.5.main
index a770b28..6e3842d 100644
--- a/src/swanctl/swanctl.conf.5.main
+++ b/src/swanctl/swanctl.conf.5.main
@@ -726,6 +726,11 @@ are used to install shunt policies, which explicitly bypass
 the defined traffic from IPsec processing, or drop it, respectively.
 
 .TP
+.BR connections.<conn>.children.<child>.policies " [yes]"
+Whether to install IPsec policies or not. Disabling this can be useful in some
+scenarios e.g. MIPv6, where policies are not managed by the IKE daemon.
+
+.TP
 .BR connections.<conn>.children.<child>.dpd_action " [clear]"
 Action to perform for this CHILD_SA on DPD timeout. The default
 .RI "" "clear" ""
@@ -1022,3 +1027,35 @@ corresponding attribute types. Alternatively,
 can be a numerical
 identifier, for which string attribute values are accepted as well.
 
+.TP
+.B authorities
+.br
+Section defining attributes of certification authorities.
+
+.TP
+.B authorities.<name>
+.br
+Section defining a certification authority with a unique name.
+
+.TP
+.BR authorities.<name>.cacert " []"
+The certificates may use a relative path from the
+.RB "" "swanctl" ""
+.RI "" "x509ca" ""
+directory, or an absolute path.
+
+.TP
+.BR authorities.<name>.crl_uris " []"
+Comma\-separated list of CRL distribution points (ldap, http, or file URI)
+
+.TP
+.BR authorities.<name>.ocsp_uris " []"
+Comma\-separated list of OCSP URIs
+
+.TP
+.BR authorities.<name>.cert_uri_base " []"
+Defines the base URI for the Hash and URL feature supported by IKEv2. Instead of
+exchanging complete certificates, IKEv2 allows one to send an URI that resolves
+to the DER encoded certificate. The certificate URIs are built by appending the
+SHA1 hash of the DER encoded certificates to this base URI.
+
diff --git a/src/swanctl/swanctl.opt b/src/swanctl/swanctl.opt
index b6ef175..ef38d5d 100644
--- a/src/swanctl/swanctl.opt
+++ b/src/swanctl/swanctl.opt
@@ -589,6 +589,12 @@ connections.<conn>.children.<child>.mode = tunnel
 	_pass_ and _drop_ are used to install shunt policies, which explicitly
 	bypass the defined traffic from IPsec processing, or drop it, respectively.
 
+connections.<conn>.children.<child>.policies = yes
+	Whether to install IPsec policies or not.
+
+	Whether to install IPsec policies or not. Disabling this can be useful in
+	some scenarios e.g. MIPv6, where policies are not managed by the IKE daemon.
+
 connections.<conn>.children.<child>.dpd_action = clear
 	Action to perform on DPD timeout (_clear_, _trap_ or _restart_).
 
@@ -810,3 +816,35 @@ pools.<name>.<attr> =
 	subnets for the corresponding attribute types. Alternatively, **<attr>** can
 	be a numerical identifier, for which string attribute values are accepted
 	as well.
+
+authorities { # }
+	Section defining attributes of certification authorities.
+
+authorities.<name> { # }
+	Section defining a certification authority with a unique name.
+
+authorities.<name>.cacert =
+	CA certificate belonging to the certification authority.
+
+	The certificates may use a relative path from the **swanctl** _x509ca_
+	directory, or an absolute path.
+
+authorities.<name>.crl_uris =
+	Comma-separated list of CRL distribution points
+
+	Comma-separated list of CRL distribution points (ldap, http, or file URI)
+
+authorities.<name>.ocsp_uris =
+	Comma-separated list of OCSP URIs
+
+	Comma-separated list of OCSP URIs
+
+authorities.<name>.cert_uri_base =
+	Defines the base URI for the Hash and URL feature supported by IKEv2.
+
+	Defines the base URI for the Hash and URL feature supported by IKEv2.
+	Instead of exchanging complete certificates, IKEv2 allows one to send an
+	URI that resolves to the DER encoded certificate. The certificate URIs are
+	built by appending the SHA1 hash of the DER encoded certificates to this
+	base URI.
+
diff --git a/testing/config/kernel/config-4.1 b/testing/config/kernel/config-4.1
new file mode 100644
index 0000000..9cd28ca
--- /dev/null
+++ b/testing/config/kernel/config-4.1
@@ -0,0 +1,2201 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Linux/x86 4.1.0 Kernel Configuration
+#
+CONFIG_64BIT=y
+CONFIG_X86_64=y
+CONFIG_X86=y
+CONFIG_INSTRUCTION_DECODER=y
+CONFIG_PERF_EVENTS_INTEL_UNCORE=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_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_MMU=y
+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_HWEIGHT_CFLAGS="-fcall-saved-rdi -fcall-saved-rsi -fcall-saved-rdx -fcall-saved-rcx -fcall-saved-r8 -fcall-saved-r9 -fcall-saved-r10 -fcall-saved-r11"
+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
+
+#
+# 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 is not set
+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_GENERIC_IRQ_LEGACY_ALLOC_HWIRQ=y
+CONFIG_IRQ_DOMAIN=y
+CONFIG_GENERIC_MSI_IRQ=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_SRCU=y
+# CONFIG_TASKS_RCU is not set
+# CONFIG_RCU_STALL_COMMON is not set
+# CONFIG_TREE_RCU_TRACE is not set
+CONFIG_RCU_KTHREAD_PRIO=0
+# CONFIG_RCU_EXPEDITE_BOOT is not set
+CONFIG_BUILD_BIN2C=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y
+CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y
+CONFIG_ARCH_SUPPORTS_INT128=y
+# CONFIG_CGROUPS is not set
+# 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_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_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_PRINTK=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_PCI_QUIRKS=y
+# CONFIG_EMBEDDED is not set
+CONFIG_HAVE_PERF_EVENTS=y
+
+#
+# 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_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_ARCH_TRACEHOOK=y
+CONFIG_HAVE_DMA_ATTRS=y
+CONFIG_HAVE_DMA_CONTIGUOUS=y
+CONFIG_GENERIC_SMP_IDLE_THREAD=y
+CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=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_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_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_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
+
+#
+# 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_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_CMDLINE_PARSER is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_EFI_PARTITION=y
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+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_QUEUE_RWLOCK=y
+CONFIG_FREEZER=y
+
+#
+# Processor type and features
+#
+CONFIG_ZONE_DMA=y
+# CONFIG_SMP is not set
+CONFIG_X86_FEATURE_NAMES=y
+CONFIG_X86_MPPARSE=y
+CONFIG_X86_EXTENDED_PLATFORM=y
+# CONFIG_X86_GOLDFISH 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
+CONFIG_X86_16BIT=y
+CONFIG_X86_ESPFIX64=y
+CONFIG_X86_VSYSCALL_EMULATION=y
+# CONFIG_I8K is not set
+# CONFIG_MICROCODE is not set
+# 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_HOTREMOVE=y
+CONFIG_PAGEFLAGS_EXTENDED=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_ZONE_DMA_FLAG=1
+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_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_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_CRASH_DUMP is not set
+CONFIG_PHYSICAL_START=0x1000000
+CONFIG_RELOCATABLE=y
+# CONFIG_RANDOMIZE_BASE is not set
+CONFIG_PHYSICAL_ALIGN=0x1000000
+# CONFIG_CMDLINE_BOOL is not set
+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_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_SLEEP=y
+# CONFIG_ACPI_PROCFS_POWER is not set
+# 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_PROCESSOR=y
+# CONFIG_ACPI_PROCESSOR_AGGREGATOR is not set
+CONFIG_ACPI_THERMAL=y
+# CONFIG_ACPI_CUSTOM_DSDT is not set
+# 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_HAVE_ACPI_APEI=y
+CONFIG_HAVE_ACPI_APEI_NMI=y
+# CONFIG_ACPI_APEI is not set
+# CONFIG_PMIC_OPREGION 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
+
+#
+# Memory power savings
+#
+# CONFIG_I7300_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_MSI=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
+
+#
+# PCI host controller drivers
+#
+CONFIG_ISA_DMA_API=y
+CONFIG_AMD_NB=y
+# CONFIG_PCCARD is not set
+# CONFIG_HOTPLUG_PCI is not set
+# CONFIG_RAPIDIO is not set
+# CONFIG_X86_SYSFB is not set
+
+#
+# Executable file formats / Emulations
+#
+CONFIG_BINFMT_ELF=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_DEV_DMA_OPS=y
+CONFIG_PMC_ATOM=y
+CONFIG_NET=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_GENEVE is not set
+CONFIG_INET_AH=y
+CONFIG_INET_ESP=y
+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_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_INET_UDP_DIAG 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_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+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_GRE=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+# CONFIG_IPV6_MROUTE 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_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_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_QUEUE_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_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_SOCKET is not set
+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_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_CONNTRACK_PROC_COMPAT=y
+# 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_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_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_MMAP 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_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_FIB_RULES=y
+CONFIG_WIRELESS=y
+# CONFIG_CFG80211 is not set
+# CONFIG_LIB80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+# 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_HAVE_BPF_JIT=y
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
+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_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_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_NVME is not set
+# CONFIG_BLK_DEV_SKD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_PMEM is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_VIRTIO_BLK=y
+# CONFIG_BLK_DEV_HD is not set
+# CONFIG_BLK_DEV_RBD is not set
+# CONFIG_BLK_DEV_RSXX 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_VMWARE_VMCI is not set
+
+#
+# Intel MIC Bus Driver
+#
+# CONFIG_INTEL_MIC_BUS is not set
+
+#
+# Intel MIC Host Driver
+#
+
+#
+# Intel MIC Card Driver
+#
+# CONFIG_GENWQE is not set
+# CONFIG_ECHO is not set
+# CONFIG_CXL_BASE 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_IPVLAN is not set
+# CONFIG_VXLAN is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+CONFIG_TUN=y
+# CONFIG_VETH is not set
+CONFIG_VIRTIO_NET=y
+# CONFIG_NLMON is not set
+# CONFIG_ARCNET is not set
+
+#
+# CAIF transport drivers
+#
+# CONFIG_VHOST_NET is not set
+
+#
+# Distributed Switch Architecture drivers
+#
+# CONFIG_NET_DSA_MV88E6XXX is not set
+# CONFIG_NET_DSA_MV88E6XXX_NEED_PPU is not set
+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_ALTEON=y
+# CONFIG_ACENIC is not set
+# CONFIG_ALTERA_TSE is not set
+CONFIG_NET_VENDOR_AMD=y
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_PCNET32 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_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_NET_VENDOR_BROCADE=y
+# CONFIG_BNA 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_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_IP1000 is not set
+# 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_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_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_NET_VENDOR_QUALCOMM=y
+CONFIG_NET_VENDOR_REALTEK=y
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_R8169 is not set
+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_SFC 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_PRISM54 is not set
+# CONFIG_HOSTAP is not set
+# CONFIG_WL_TI is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+# CONFIG_WAN is not set
+# CONFIG_VMXNET3 is not set
+# CONFIG_ISDN 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_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_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
+
+#
+# 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_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_DEVPTS_MULTIPLE_INSTANCES is not set
+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_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_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_ARCH_WANT_OPTIONAL_GPIOLIB=y
+# CONFIG_GPIOLIB is not set
+# CONFIG_W1 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_BQ27x00 is not set
+# CONFIG_CHARGER_MAX8903 is not set
+# CONFIG_POWER_RESET is not set
+# CONFIG_POWER_AVS 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_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_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_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_EMULATION is not set
+# CONFIG_INTEL_POWERCLAMP is not set
+# CONFIG_INTEL_SOC_DTS_THERMAL is not set
+# CONFIG_INT340X_THERMAL is not set
+
+#
+# Texas Instruments thermal drivers
+#
+# 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_LPC_ICH is not set
+# CONFIG_LPC_SCH 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
+
+#
+# Direct Rendering Manager
+#
+# CONFIG_DRM 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_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_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_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_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_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_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 is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES 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_ASUS_LAPTOP 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_THINKPAD_ACPI is not set
+# CONFIG_SENSORS_HDAPS is not set
+# CONFIG_INTEL_MENLOW 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_IPS 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_CHROME_PLATFORMS 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_STE_MODEM_RPROC is not set
+
+#
+# Rpmsg drivers
+#
+
+#
+# SOC (System On Chip) specific Drivers
+#
+# CONFIG_SOC_TI 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_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_BCM_KONA_USB2_PHY is not set
+# CONFIG_POWERCAP is not set
+# CONFIG_MCB is not set
+# CONFIG_THUNDERBOLT is not set
+
+#
+# Android
+#
+# CONFIG_ANDROID 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_GOOGLE_FIRMWARE is not set
+
+#
+# File systems
+#
+CONFIG_DCACHE_WORD_ACCESS=y
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+# CONFIG_EXT3_FS_XATTR is not set
+# CONFIG_EXT4_FS is not set
+CONFIG_JBD=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_FILE_LOCKING=y
+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_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_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# 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_LOGFS 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_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_ARCH_WANT_FRAME_POINTERS=y
+CONFIG_FRAME_POINTER=y
+# 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_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_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_SHADOW_OFFSET=0xdffffc0000000000
+# 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_PANIC_ON_OOPS is not set
+CONFIG_PANIC_ON_OOPS_VALUE=0
+CONFIG_PANIC_TIMEOUT=0
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_SCHED_STACK_END_CHECK is not set
+# CONFIG_DEBUG_TIMEKEEPING is not set
+# CONFIG_TIMER_STATS 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_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_TORTURE_TEST is not set
+# CONFIG_RCU_TRACE 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_ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS=y
+# CONFIG_DEBUG_STRICT_USER_COPY_CHECKS is not set
+CONFIG_USER_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_FP_TEST=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_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_EVENT is not set
+# CONFIG_PROBE_EVENTS is not set
+# CONFIG_MMIOTRACE is not set
+# CONFIG_TRACEPOINT_BENCHMARK is not set
+
+#
+# Runtime Testing
+#
+# CONFIG_TEST_LIST_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_RHASHTABLE 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_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+# 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 is not set
+CONFIG_DEBUG_RODATA=y
+CONFIG_DEBUG_RODATA_TEST=y
+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_NMI_SELFTEST is not set
+# CONFIG_X86_DEBUG_STATIC_CPU_HAS 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_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_PCOMP=y
+CONFIG_CRYPTO_PCOMP2=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_WORKQUEUE=y
+CONFIG_CRYPTO_CRYPTD=y
+# CONFIG_CRYPTO_MCRYPTD is not set
+CONFIG_CRYPTO_AUTHENC=y
+CONFIG_CRYPTO_ABLK_HELPER=y
+CONFIG_CRYPTO_GLUE_HELPER_X86=y
+
+#
+# Authenticated Encryption with Associated Data
+#
+CONFIG_CRYPTO_CCM=y
+CONFIG_CRYPTO_GCM=y
+CONFIG_CRYPTO_SEQIV=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
+
+#
+# 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_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=y
+CONFIG_CRYPTO_SHA512=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_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_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_ZLIB=y
+CONFIG_CRYPTO_LZO=y
+CONFIG_CRYPTO_LZ4=y
+CONFIG_CRYPTO_LZ4HC=y
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+# CONFIG_CRYPTO_DRBG_MENU is not set
+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_HW is not set
+CONFIG_HAVE_KVM=y
+CONFIG_VIRTUALIZATION=y
+# CONFIG_KVM is not set
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_HAVE_ARCH_BITREVERSE is not set
+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_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_DQL=y
+CONFIG_NLATTR=y
+CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
+CONFIG_AVERAGE=y
+# CONFIG_CORDIC is not set
+# CONFIG_DDR is not set
+CONFIG_ARCH_HAS_SG_CHAIN=y
diff --git a/testing/config/kernel/config-4.2 b/testing/config/kernel/config-4.2
new file mode 100644
index 0000000..72d5b93
--- /dev/null
+++ b/testing/config/kernel/config-4.2
@@ -0,0 +1,2266 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Linux/x86 4.2.0 Kernel Configuration
+#
+CONFIG_64BIT=y
+CONFIG_X86_64=y
+CONFIG_X86=y
+CONFIG_INSTRUCTION_DECODER=y
+CONFIG_PERF_EVENTS_INTEL_UNCORE=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_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_MMU=y
+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_HWEIGHT_CFLAGS="-fcall-saved-rdi -fcall-saved-rsi -fcall-saved-rdx -fcall-saved-rcx -fcall-saved-r8 -fcall-saved-r9 -fcall-saved-r10 -fcall-saved-r11"
+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
+
+#
+# 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 is not set
+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_CLOCKSO