aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am12
-rw-r--r--src/charon/Android.mk2
-rw-r--r--src/charon/charon.c3
-rw-r--r--src/checksum/Makefile.am19
-rw-r--r--src/checksum/checksum_builder.c3
-rw-r--r--src/ipsec/Android.mk2
-rw-r--r--src/ipsec/Makefile.am2
-rw-r--r--src/libcharon/Android.mk4
-rwxr-xr-xsrc/libcharon/Makefile.am21
-rw-r--r--src/libcharon/daemon.c35
-rwxr-xr-xsrc/libcharon/encoding/payloads/notify_payload.c14
-rwxr-xr-xsrc/libcharon/encoding/payloads/notify_payload.h4
-rw-r--r--src/libcharon/plugins/eap_peap/eap_peap.c3
-rw-r--r--src/libcharon/plugins/eap_radius/Makefile.am10
-rw-r--r--src/libcharon/plugins/eap_radius/eap_radius.c61
-rw-r--r--src/libcharon/plugins/eap_radius/eap_radius_accounting.c339
-rw-r--r--src/libcharon/plugins/eap_radius/eap_radius_accounting.h49
-rw-r--r--src/libcharon/plugins/eap_radius/eap_radius_dae.c543
-rw-r--r--src/libcharon/plugins/eap_radius/eap_radius_dae.h44
-rw-r--r--src/libcharon/plugins/eap_radius/eap_radius_forward.c458
-rw-r--r--src/libcharon/plugins/eap_radius/eap_radius_forward.h65
-rw-r--r--src/libcharon/plugins/eap_radius/eap_radius_plugin.c157
-rw-r--r--src/libcharon/plugins/eap_radius/eap_radius_plugin.h9
-rw-r--r--src/libcharon/plugins/eap_tls/eap_tls.c6
-rw-r--r--src/libcharon/plugins/eap_ttls/Makefile.am3
-rw-r--r--src/libcharon/plugins/eap_ttls/eap_ttls.c3
-rw-r--r--src/libcharon/plugins/eap_ttls/eap_ttls_peer.c4
-rw-r--r--src/libcharon/plugins/farp/farp_listener.c147
-rw-r--r--src/libcharon/plugins/farp/farp_listener.h9
-rw-r--r--src/libcharon/plugins/farp/farp_spoofer.c16
-rw-r--r--src/libcharon/plugins/ha/ha_dispatcher.c12
-rw-r--r--src/libcharon/plugins/ha/ha_ike.c4
-rw-r--r--src/libcharon/plugins/ha/ha_kernel.c43
-rw-r--r--src/libcharon/plugins/ha/ha_message.c4
-rw-r--r--src/libcharon/plugins/ha/ha_message.h4
-rw-r--r--src/libcharon/plugins/ha/ha_segments.h4
-rw-r--r--src/libcharon/plugins/radattr/Makefile.am17
-rw-r--r--src/libcharon/plugins/radattr/radattr_listener.c221
-rw-r--r--src/libcharon/plugins/radattr/radattr_listener.h49
-rw-r--r--src/libcharon/plugins/radattr/radattr_plugin.c75
-rw-r--r--src/libcharon/plugins/radattr/radattr_plugin.h42
-rw-r--r--src/libcharon/plugins/stroke/stroke_control.c15
-rw-r--r--src/libcharon/plugins/stroke/stroke_cred.c38
-rw-r--r--src/libcharon/plugins/stroke/stroke_list.c11
-rw-r--r--src/libcharon/plugins/stroke/stroke_socket.c131
-rw-r--r--src/libcharon/plugins/tnc_imc/tnc_imc.c210
-rw-r--r--src/libcharon/plugins/tnc_imc/tnc_imc_bind_function.c126
-rw-r--r--src/libcharon/plugins/tnc_imc/tnc_imc_manager.c95
-rw-r--r--src/libcharon/plugins/tnc_imv/tnc_imv.c207
-rw-r--r--src/libcharon/plugins/tnc_imv/tnc_imv_bind_function.c84
-rw-r--r--src/libcharon/plugins/tnc_imv/tnc_imv_manager.c97
-rw-r--r--src/libcharon/plugins/tnc_pdp/Makefile.am24
-rw-r--r--src/libcharon/plugins/tnc_pdp/tnc_pdp.c648
-rw-r--r--src/libcharon/plugins/tnc_pdp/tnc_pdp.h46
-rw-r--r--src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.c220
-rw-r--r--src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.h77
-rw-r--r--src/libcharon/plugins/tnc_pdp/tnc_pdp_plugin.c91
-rw-r--r--src/libcharon/plugins/tnc_pdp/tnc_pdp_plugin.h42
-rw-r--r--src/libcharon/plugins/tnc_tnccs/tnc_tnccs_manager.c263
-rw-r--r--src/libcharon/plugins/tnccs_11/tnccs_11.c49
-rw-r--r--src/libcharon/plugins/tnccs_20/messages/pb_pa_msg.c11
-rw-r--r--src/libcharon/plugins/tnccs_20/messages/pb_pa_msg.h9
-rw-r--r--src/libcharon/plugins/tnccs_20/tnccs_20.c64
-rw-r--r--src/libcharon/sa/ike_sa.c136
-rw-r--r--src/libcharon/sa/ike_sa.h20
-rw-r--r--src/libcharon/sa/ikev2/task_manager_v2.c16
-rw-r--r--src/libcharon/sa/ikev2/tasks/ike_cert_pre.c2
-rw-r--r--src/libcharon/sa/ikev2/tasks/ike_mobike.c27
-rw-r--r--src/libcharon/sa/keymat.c2
-rw-r--r--src/libcharon/sa/trap_manager.c83
-rw-r--r--src/libfast/dispatcher.c2
-rw-r--r--src/libfast/smtp.h2
-rw-r--r--src/libfreeswan/Android.mk2
-rw-r--r--src/libfreeswan/Makefile.am1
-rw-r--r--src/libfreeswan/pfkey_v2_parse.c5
-rw-r--r--src/libhydra/Android.mk2
-rw-r--r--src/libhydra/kernel/kernel_interface.c2
-rw-r--r--src/libhydra/plugins/attr_sql/sql_attribute.c2
-rw-r--r--src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c30
-rw-r--r--src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c12
-rw-r--r--src/libhydra/plugins/resolve/resolve_plugin.c2
-rw-r--r--src/libimcv/Makefile.am8
-rw-r--r--src/libimcv/ietf/ietf_attr_port_filter.c25
-rw-r--r--src/libimcv/ietf/ietf_attr_product_info.c24
-rw-r--r--src/libimcv/imc/imc_agent.c364
-rw-r--r--src/libimcv/imc/imc_agent.h40
-rw-r--r--src/libimcv/imc/imc_state.h26
-rw-r--r--src/libimcv/imv/imv_agent.c320
-rw-r--r--src/libimcv/imv/imv_agent.h41
-rw-r--r--src/libimcv/imv/imv_state.h23
-rw-r--r--src/libimcv/pa_tnc/pa_tnc_msg.c58
-rw-r--r--src/libimcv/pa_tnc/pa_tnc_msg.h7
-rw-r--r--src/libimcv/plugins/imc_attestation/imc_attestation.c507
-rw-r--r--src/libimcv/plugins/imc_scanner/imc_scanner.c122
-rw-r--r--src/libimcv/plugins/imc_scanner/imc_scanner_state.c33
-rw-r--r--src/libimcv/plugins/imc_test/imc_test.c194
-rw-r--r--src/libimcv/plugins/imc_test/imc_test_state.c34
-rw-r--r--src/libimcv/plugins/imc_test/imc_test_state.h2
-rw-r--r--src/libimcv/plugins/imv_attestation/Makefile.am17
-rw-r--r--src/libimcv/plugins/imv_attestation/imv_attestation.c695
-rw-r--r--src/libimcv/plugins/imv_attestation/tables.sql36
-rw-r--r--src/libimcv/plugins/imv_scanner/imv_scanner.c109
-rw-r--r--src/libimcv/plugins/imv_scanner/imv_scanner_state.c32
-rw-r--r--src/libimcv/plugins/imv_test/imv_test.c164
-rw-r--r--src/libimcv/plugins/imv_test/imv_test_state.c109
-rw-r--r--src/libimcv/plugins/imv_test/imv_test_state.h11
-rw-r--r--src/libpts/Makefile.am33
-rw-r--r--src/libpts/libpts.c36
-rw-r--r--src/libpts/libpts.h7
-rw-r--r--src/libpts/plugins/imc_attestation/Makefile.am (renamed from src/libimcv/plugins/imc_attestation/Makefile.am)3
-rw-r--r--src/libpts/plugins/imc_attestation/imc_attestation.c358
-rw-r--r--src/libpts/plugins/imc_attestation/imc_attestation_process.c466
-rw-r--r--src/libpts/plugins/imc_attestation/imc_attestation_process.h49
-rw-r--r--src/libpts/plugins/imc_attestation/imc_attestation_state.c (renamed from src/libimcv/plugins/imc_attestation/imc_attestation_state.c)55
-rw-r--r--src/libpts/plugins/imc_attestation/imc_attestation_state.h (renamed from src/libimcv/plugins/imc_attestation/imc_attestation_state.h)16
-rw-r--r--src/libpts/plugins/imv_attestation/.gitignore1
-rw-r--r--src/libpts/plugins/imv_attestation/Makefile.am33
-rw-r--r--src/libpts/plugins/imv_attestation/attest.c373
-rw-r--r--src/libpts/plugins/imv_attestation/attest_db.c1200
-rw-r--r--src/libpts/plugins/imv_attestation/attest_db.h190
-rw-r--r--src/libpts/plugins/imv_attestation/attest_usage.c80
-rw-r--r--src/libpts/plugins/imv_attestation/attest_usage.h25
-rw-r--r--src/libpts/plugins/imv_attestation/data.sql (renamed from src/libimcv/plugins/imv_attestation/data.sql)565
-rw-r--r--src/libpts/plugins/imv_attestation/imv_attestation.c520
-rw-r--r--src/libpts/plugins/imv_attestation/imv_attestation_build.c300
-rw-r--r--src/libpts/plugins/imv_attestation/imv_attestation_build.h50
-rw-r--r--src/libpts/plugins/imv_attestation/imv_attestation_process.c399
-rw-r--r--src/libpts/plugins/imv_attestation/imv_attestation_process.h57
-rw-r--r--src/libpts/plugins/imv_attestation/imv_attestation_state.c (renamed from src/libimcv/plugins/imv_attestation/imv_attestation_state.c)173
-rw-r--r--src/libpts/plugins/imv_attestation/imv_attestation_state.h (renamed from src/libimcv/plugins/imv_attestation/imv_attestation_state.h)58
-rw-r--r--src/libpts/plugins/imv_attestation/tables.sql82
-rw-r--r--src/libpts/pts/components/ita/ita_comp_func_name.c45
-rw-r--r--src/libpts/pts/components/ita/ita_comp_func_name.h85
-rw-r--r--src/libpts/pts/components/ita/ita_comp_ima.c439
-rw-r--r--src/libpts/pts/components/ita/ita_comp_ima.h36
-rw-r--r--src/libpts/pts/components/ita/ita_comp_tboot.c330
-rw-r--r--src/libpts/pts/components/ita/ita_comp_tboot.h36
-rw-r--r--src/libpts/pts/components/ita/ita_comp_tgrub.c184
-rw-r--r--src/libpts/pts/components/ita/ita_comp_tgrub.h36
-rw-r--r--src/libpts/pts/components/pts_comp_evidence.c251
-rw-r--r--src/libpts/pts/components/pts_comp_evidence.h170
-rw-r--r--src/libpts/pts/components/pts_comp_func_name.c152
-rw-r--r--src/libpts/pts/components/pts_comp_func_name.h96
-rw-r--r--src/libpts/pts/components/pts_component.h94
-rw-r--r--src/libpts/pts/components/pts_component_manager.c317
-rw-r--r--src/libpts/pts/components/pts_component_manager.h125
-rw-r--r--src/libpts/pts/components/tcg/tcg_comp_func_name.c48
-rw-r--r--src/libpts/pts/components/tcg/tcg_comp_func_name.h98
-rw-r--r--src/libpts/pts/pts.c1079
-rw-r--r--src/libpts/pts/pts.h251
-rw-r--r--src/libpts/pts/pts_database.c208
-rw-r--r--src/libpts/pts/pts_database.h105
-rw-r--r--src/libpts/pts/pts_dh_group.c175
-rw-r--r--src/libpts/pts/pts_dh_group.h104
-rw-r--r--src/libpts/pts/pts_error.c42
-rw-r--r--src/libpts/pts/pts_error.h51
-rw-r--r--src/libpts/pts/pts_file_meta.c45
-rw-r--r--src/libpts/pts/pts_file_meta.h26
-rw-r--r--src/libpts/pts/pts_file_type.c33
-rw-r--r--src/libpts/pts/pts_file_type.h30
-rw-r--r--src/libpts/pts/pts_funct_comp_name.h81
-rw-r--r--src/libpts/pts/pts_meas_algo.c81
-rw-r--r--src/libpts/pts/pts_meas_algo.h49
-rw-r--r--src/libpts/pts/pts_req_func_comp_evid.h42
-rw-r--r--src/libpts/pts/pts_simple_evid_final.h47
-rw-r--r--src/libpts/tcg/tcg_attr.c32
-rw-r--r--src/libpts/tcg/tcg_attr.h2
-rw-r--r--src/libpts/tcg/tcg_pts_attr_aik.c26
-rw-r--r--src/libpts/tcg/tcg_pts_attr_dh_nonce_finish.c276
-rw-r--r--src/libpts/tcg/tcg_pts_attr_dh_nonce_finish.h89
-rw-r--r--src/libpts/tcg/tcg_pts_attr_dh_nonce_params_req.c247
-rw-r--r--src/libpts/tcg/tcg_pts_attr_dh_nonce_params_req.h72
-rw-r--r--src/libpts/tcg/tcg_pts_attr_dh_nonce_params_resp.c295
-rw-r--r--src/libpts/tcg/tcg_pts_attr_dh_nonce_params_resp.h93
-rw-r--r--src/libpts/tcg/tcg_pts_attr_file_meas.c41
-rw-r--r--src/libpts/tcg/tcg_pts_attr_gen_attest_evid.c26
-rw-r--r--src/libpts/tcg/tcg_pts_attr_get_aik.c23
-rw-r--r--src/libpts/tcg/tcg_pts_attr_get_tpm_version_info.c26
-rw-r--r--src/libpts/tcg/tcg_pts_attr_get_tpm_version_info.h3
-rw-r--r--src/libpts/tcg/tcg_pts_attr_meas_algo.c22
-rw-r--r--src/libpts/tcg/tcg_pts_attr_proto_caps.c22
-rw-r--r--src/libpts/tcg/tcg_pts_attr_req_file_meas.c24
-rw-r--r--src/libpts/tcg/tcg_pts_attr_req_file_meta.c30
-rw-r--r--src/libpts/tcg/tcg_pts_attr_req_func_comp_evid.c378
-rw-r--r--src/libpts/tcg/tcg_pts_attr_req_func_comp_evid.h80
-rw-r--r--src/libpts/tcg/tcg_pts_attr_req_funct_comp_evid.c425
-rw-r--r--src/libpts/tcg/tcg_pts_attr_req_funct_comp_evid.h147
-rw-r--r--src/libpts/tcg/tcg_pts_attr_simple_comp_evid.c772
-rw-r--r--src/libpts/tcg/tcg_pts_attr_simple_comp_evid.h263
-rw-r--r--src/libpts/tcg/tcg_pts_attr_simple_evid_final.c332
-rw-r--r--src/libpts/tcg/tcg_pts_attr_simple_evid_final.h119
-rw-r--r--src/libpts/tcg/tcg_pts_attr_tpm_version_info.c27
-rw-r--r--src/libpts/tcg/tcg_pts_attr_unix_file_meta.c216
-rw-r--r--src/libradius/Makefile.am11
-rw-r--r--src/libradius/radius_client.c (renamed from src/libcharon/plugins/eap_radius/radius_client.c)65
-rw-r--r--src/libradius/radius_client.h (renamed from src/libcharon/plugins/eap_radius/radius_client.h)6
-rw-r--r--src/libradius/radius_config.c (renamed from src/libcharon/plugins/eap_radius/radius_server.c)50
-rw-r--r--src/libradius/radius_config.h (renamed from src/libcharon/plugins/eap_radius/radius_server.h)45
-rw-r--r--src/libradius/radius_message.c (renamed from src/libcharon/plugins/eap_radius/radius_message.c)108
-rw-r--r--src/libradius/radius_message.h (renamed from src/libcharon/plugins/eap_radius/radius_message.h)43
-rw-r--r--src/libradius/radius_mppe.h40
-rw-r--r--src/libradius/radius_socket.c (renamed from src/libcharon/plugins/eap_radius/radius_socket.c)126
-rw-r--r--src/libradius/radius_socket.h (renamed from src/libcharon/plugins/eap_radius/radius_socket.h)9
-rw-r--r--src/libsimaka/simaka_manager.h4
-rw-r--r--src/libsimaka/simaka_message.c2
-rw-r--r--src/libstrongswan/Android.mk2
-rw-r--r--src/libstrongswan/Makefile.am7
-rw-r--r--src/libstrongswan/asn1/asn1.c69
-rw-r--r--src/libstrongswan/asn1/asn1.h10
-rw-r--r--src/libstrongswan/asn1/asn1_parser.c18
-rw-r--r--src/libstrongswan/asn1/oid.txt5
-rw-r--r--src/libstrongswan/credentials/auth_cfg.h21
-rw-r--r--src/libstrongswan/credentials/builder.c1
-rw-r--r--src/libstrongswan/credentials/builder.h8
-rw-r--r--src/libstrongswan/credentials/cert_validator.h2
-rw-r--r--src/libstrongswan/credentials/certificates/x509.h4
-rw-r--r--src/libstrongswan/credentials/cred_encoding.c6
-rw-r--r--src/libstrongswan/credentials/cred_encoding.h2
-rw-r--r--src/libstrongswan/credentials/credential_factory.h2
-rw-r--r--src/libstrongswan/credentials/credential_manager.c4
-rw-r--r--src/libstrongswan/credentials/credential_manager.h26
-rw-r--r--src/libstrongswan/credentials/credential_set.h4
-rw-r--r--src/libstrongswan/crypto/crypto_tester.c10
-rw-r--r--src/libstrongswan/crypto/diffie_hellman.c24
-rw-r--r--src/libstrongswan/crypto/diffie_hellman.h5
-rw-r--r--src/libstrongswan/crypto/pkcs7.c2
-rw-r--r--src/libstrongswan/crypto/proposal/proposal_keywords.txt2
-rw-r--r--src/libstrongswan/debug.c2
-rw-r--r--src/libstrongswan/debug.h2
-rw-r--r--src/libstrongswan/fetcher/fetcher_manager.h2
-rw-r--r--src/libstrongswan/library.c3
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_ec_private_key.c39
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c3
-rw-r--r--src/libstrongswan/plugins/pem/pem_builder.c16
-rw-r--r--src/libstrongswan/plugins/pgp/pgp_cert.c20
-rw-r--r--src/libstrongswan/plugins/pgp/pgp_utils.c18
-rw-r--r--src/libstrongswan/plugins/pkcs1/pkcs1_builder.c6
-rw-r--r--src/libstrongswan/plugins/pkcs11/pkcs11_public_key.c4
-rw-r--r--src/libstrongswan/plugins/pkcs8/Makefile.am16
-rw-r--r--src/libstrongswan/plugins/pkcs8/pkcs8_builder.c632
-rw-r--r--src/libstrongswan/plugins/pkcs8/pkcs8_builder.h36
-rw-r--r--src/libstrongswan/plugins/pkcs8/pkcs8_plugin.c78
-rw-r--r--src/libstrongswan/plugins/pkcs8/pkcs8_plugin.h42
-rw-r--r--src/libstrongswan/plugins/plugin_loader.c54
-rw-r--r--src/libstrongswan/plugins/plugin_loader.h10
-rw-r--r--src/libstrongswan/plugins/x509/x509_ac.c30
-rw-r--r--src/libstrongswan/plugins/x509/x509_cert.c50
-rw-r--r--src/libstrongswan/plugins/x509/x509_crl.c12
-rw-r--r--src/libstrongswan/plugins/x509/x509_ocsp_response.c8
-rw-r--r--src/libstrongswan/plugins/x509/x509_pkcs10.c16
-rw-r--r--src/libstrongswan/processing/processor.c6
-rw-r--r--src/libstrongswan/threading/thread.c36
-rw-r--r--src/libstrongswan/utils.c22
-rw-r--r--src/libstrongswan/utils.h26
-rw-r--r--src/libstrongswan/utils/leak_detective.c1
-rw-r--r--src/libtls/Makefile.am1
-rw-r--r--src/libtls/tls.c4
-rw-r--r--src/libtls/tls.h4
-rw-r--r--src/libtls/tls_cache.c237
-rw-r--r--src/libtls/tls_cache.h78
-rw-r--r--src/libtls/tls_compression.h4
-rw-r--r--src/libtls/tls_crypto.c154
-rw-r--r--src/libtls/tls_crypto.h50
-rw-r--r--src/libtls/tls_fragmentation.c14
-rw-r--r--src/libtls/tls_fragmentation.h4
-rw-r--r--src/libtls/tls_handshake.h13
-rw-r--r--src/libtls/tls_peer.c109
-rw-r--r--src/libtls/tls_protection.h4
-rw-r--r--src/libtls/tls_server.c153
-rw-r--r--src/libtls/tls_socket.c111
-rw-r--r--src/libtls/tls_socket.h22
-rw-r--r--src/libtnccs/Android.mk2
-rw-r--r--src/libtnccs/Makefile.am2
-rw-r--r--src/libtnccs/tnc/imc/imc.h124
-rw-r--r--src/libtnccs/tnc/imc/imc_manager.h56
-rw-r--r--src/libtnccs/tnc/imv/imv.h124
-rw-r--r--src/libtnccs/tnc/imv/imv_manager.h55
-rw-r--r--src/libtnccs/tnc/tnccs/tnccs.h19
-rw-r--r--src/libtnccs/tnc/tnccs/tnccs_manager.h41
-rw-r--r--src/libtncif/Android.mk2
-rw-r--r--src/libtncif/Makefile.am2
-rw-r--r--src/libtncif/tncif.h65
-rw-r--r--src/libtncif/tncif_names.h10
-rw-r--r--src/libtncif/tncif_pa_subtypes.c27
-rw-r--r--src/libtncif/tncif_pa_subtypes.h43
-rw-r--r--src/libtncif/tncifimc.h155
-rw-r--r--src/libtncif/tncifimv.h235
-rw-r--r--src/pki/command.c7
-rw-r--r--src/pki/commands/issue.c2
-rw-r--r--src/pki/commands/self.c2
-rw-r--r--src/pki/commands/signcrl.c2
-rw-r--r--src/pluto/Android.mk2
-rw-r--r--src/pluto/Makefile.am2
-rw-r--r--src/pluto/ca.c3
-rw-r--r--src/pluto/defs.c8
-rw-r--r--src/pluto/keys.c17
-rw-r--r--src/pluto/log.c15
-rw-r--r--src/pluto/plutomain.c27
-rw-r--r--src/scepclient/scepclient.c26
-rw-r--r--src/starter/Android.mk7
-rw-r--r--src/starter/Makefile.am2
-rw-r--r--src/starter/confread.c2
-rw-r--r--src/starter/confread.h4
-rw-r--r--src/starter/invokepluto.c4
-rw-r--r--src/starter/y.output351
-rw-r--r--src/stroke/Android.mk2
-rw-r--r--src/stroke/Makefile.am2
-rw-r--r--src/stroke/stroke.c2
-rw-r--r--src/whack/Android.mk2
-rw-r--r--src/whack/Makefile.am1
310 files changed, 21743 insertions, 5263 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 5e85a5f88..1440de20f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -16,6 +16,10 @@ if USE_TLS
SUBDIRS += libtls
endif
+if USE_RADIUS
+ SUBDIRS += libradius
+endif
+
if USE_LIBTNCIF
SUBDIRS += libtncif
endif
@@ -24,14 +28,14 @@ if USE_LIBTNCCS
SUBDIRS += libtnccs
endif
-if USE_PTS
- SUBDIRS += libpts
-endif
-
if USE_IMCV
SUBDIRS += libimcv
endif
+if USE_PTS
+ SUBDIRS += libpts
+endif
+
if USE_LIBCHARON
SUBDIRS += libcharon
endif
diff --git a/src/charon/Android.mk b/src/charon/Android.mk
index 491d7f946..eb7eca9dd 100644
--- a/src/charon/Android.mk
+++ b/src/charon/Android.mk
@@ -17,6 +17,8 @@ LOCAL_CFLAGS := $(strongswan_CFLAGS)
LOCAL_MODULE := charon
+LOCAL_MODULE_TAGS := optional
+
LOCAL_ARM_MODE := arm
LOCAL_PRELINK_MODULE := false
diff --git a/src/charon/charon.c b/src/charon/charon.c
index 141403b89..7a269d7f0 100644
--- a/src/charon/charon.c
+++ b/src/charon/charon.c
@@ -426,7 +426,7 @@ static void usage(const char *msg)
" [--version]\n"
" [--use-syslog]\n"
" [--debug-<type> <level>]\n"
- " <type>: log context type (dmn|mgr|ike|chd|job|cfg|knl|net|enc|tnc|imc|imv|pts|tls|lib)\n"
+ " <type>: log context type (dmn|mgr|ike|chd|job|cfg|knl|net|asn|enc|tnc|imc|imv|pts|tls|lib)\n"
" <level>: log verbosity (-1 = silent, 0 = audit, 1 = control,\n"
" 2 = controlmore, 3 = raw, 4 = private)\n"
"\n"
@@ -497,6 +497,7 @@ int main(int argc, char *argv[])
{ "debug-cfg", required_argument, &group, DBG_CFG },
{ "debug-knl", required_argument, &group, DBG_KNL },
{ "debug-net", required_argument, &group, DBG_NET },
+ { "debug-asn", required_argument, &group, DBG_ASN },
{ "debug-enc", required_argument, &group, DBG_ENC },
{ "debug-tnc", required_argument, &group, DBG_TNC },
{ "debug-imc", required_argument, &group, DBG_IMC },
diff --git a/src/checksum/Makefile.am b/src/checksum/Makefile.am
index 036a63715..58292a45a 100644
--- a/src/checksum/Makefile.am
+++ b/src/checksum/Makefile.am
@@ -45,6 +45,11 @@ if USE_TLS
libs += $(DESTDIR)$(ipseclibdir)/libtls.so
endif
+if USE_RADIUS
+ deps += $(top_builddir)/src/libradius/libradius.la
+ libs += $(DESTDIR)$(ipseclibdir)/libradius.so
+endif
+
if USE_LIBTNCCS
deps += $(top_builddir)/src/libtnccs/libtnccs.la
libs += $(DESTDIR)$(ipseclibdir)/libtnccs.so
@@ -55,6 +60,16 @@ if USE_SIMAKA
libs += $(DESTDIR)$(ipseclibdir)/libsimaka.so
endif
+if USE_IMCV
+ deps += $(top_builddir)/src/libimcv/libimcv.la
+ libs += $(DESTDIR)$(ipseclibdir)/libimcv.so
+endif
+
+if USE_PTS
+ deps += $(top_builddir)/src/libpts/libpts.la
+ libs += $(DESTDIR)$(ipseclibdir)/libpts.so
+endif
+
if USE_CHARON
deps += $(top_builddir)/src/libcharon/libcharon.la
libs += $(DESTDIR)$(ipseclibdir)/libcharon.so
@@ -79,6 +94,10 @@ if USE_ATTR_SQL
exes += $(top_builddir)/src/libhydra/plugins/attr_sql/.libs/pool
endif
+if USE_IMV_ATTESTATION
+ exes += $(top_builddir)/src/libpts/plugins/imv_attestation/.libs/attest
+endif
+
checksum.c : checksum_builder $(deps) $(exes)
./checksum_builder $(libs) $(exes) > checksum.c
diff --git a/src/checksum/checksum_builder.c b/src/checksum/checksum_builder.c
index 8311d9a39..670ec76bd 100644
--- a/src/checksum/checksum_builder.c
+++ b/src/checksum/checksum_builder.c
@@ -151,7 +151,8 @@ int main(int argc, char* argv[])
printf("\n");
printf("integrity_checksum_t checksums[] = {\n");
fprintf(stderr, "integrity test data:\n");
- fprintf(stderr, "module name, file size / checksum segment size / checksum\n");
+ fprintf(stderr, "module name, file size / checksum "
+ "segment size / checksum\n");
for (i = 1; i < argc; i++)
{
build_binary_checksum(argv[i]);
diff --git a/src/ipsec/Android.mk b/src/ipsec/Android.mk
index b6a7c714d..d134f7fd2 100644
--- a/src/ipsec/Android.mk
+++ b/src/ipsec/Android.mk
@@ -5,6 +5,8 @@ include $(CLEAR_VARS)
LOCAL_MODULE := ipsec
+LOCAL_MODULE_TAGS := optional
+
LOCAL_MODULE_CLASS := EXECUTABLES
GEN := $(local-intermediates-dir)/ipsec
diff --git a/src/ipsec/Makefile.am b/src/ipsec/Makefile.am
index 8420e1ace..bbf009721 100644
--- a/src/ipsec/Makefile.am
+++ b/src/ipsec/Makefile.am
@@ -1,7 +1,7 @@
sbin_SCRIPTS = ipsec
CLEANFILES = ipsec ipsec.8
dist_man8_MANS = ipsec.8
-EXTRA_DIST = ipsec.in ipsec.8.in
+EXTRA_DIST = ipsec.in ipsec.8.in Android.mk
ipsec.8 : ipsec.8.in
sed \
diff --git a/src/libcharon/Android.mk b/src/libcharon/Android.mk
index 3ba8307c8..f98d36a61 100644
--- a/src/libcharon/Android.mk
+++ b/src/libcharon/Android.mk
@@ -132,6 +132,8 @@ LOCAL_C_INCLUDES += $(LOCAL_PATH)/../libsimaka/
LOCAL_SRC_FILES += $(addprefix ../libsimaka/, \
simaka_message.h simaka_message.c \
simaka_crypto.h simaka_crypto.c \
+ simaka_manager.h simaka_manager.c \
+ simaka_card.h simaka_provider.h simaka_hooks.h \
)
endif
@@ -163,6 +165,8 @@ LOCAL_CFLAGS := $(strongswan_CFLAGS) \
LOCAL_MODULE := libcharon
+LOCAL_MODULE_TAGS := optional
+
LOCAL_ARM_MODE := arm
LOCAL_PRELINK_MODULE := false
diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am
index d5e139412..a322b0cce 100755
--- a/src/libcharon/Makefile.am
+++ b/src/libcharon/Makefile.am
@@ -360,6 +360,13 @@ if MONOLITHIC
endif
endif
+if USE_RADIUS
+if MONOLITHIC
+ # otherwise this library is linked to eap_radius
+ libcharon_la_LIBADD += $(top_builddir)/src/libradius/libradius.la
+endif
+endif
+
if USE_TNC_IFMAP
SUBDIRS += plugins/tnc_ifmap
if MONOLITHIC
@@ -367,6 +374,13 @@ if MONOLITHIC
endif
endif
+if USE_TNC_PDP
+ SUBDIRS += plugins/tnc_pdp
+if MONOLITHIC
+ libcharon_la_LIBADD += plugins/tnc_pdp/libstrongswan-tnc-pdp.la
+endif
+endif
+
if USE_TNC_IMC
SUBDIRS += plugins/tnc_imc
if MONOLITHIC
@@ -500,6 +514,13 @@ if MONOLITHIC
endif
endif
+if USE_RADATTR
+ SUBDIRS += plugins/radattr
+if MONOLITHIC
+ libcharon_la_LIBADD += plugins/radattr/libstrongswan-radattr.la
+endif
+endif
+
if USE_UCI
SUBDIRS += plugins/uci
if MONOLITHIC
diff --git a/src/libcharon/daemon.c b/src/libcharon/daemon.c
index 343063be5..575627206 100644
--- a/src/libcharon/daemon.c
+++ b/src/libcharon/daemon.c
@@ -111,6 +111,12 @@ static void destroy(private_daemon_t *this)
}
DESTROY_IF(this->public.receiver);
DESTROY_IF(this->public.sender);
+#ifdef ME
+ DESTROY_IF(this->public.connect_manager);
+ DESTROY_IF(this->public.mediation_manager);
+#endif /* ME */
+ /* make sure the cache is clear before unloading plugins */
+ lib->credmgr->flush_cache(lib->credmgr, CERT_ANY);
/* unload plugins to release threads */
lib->plugins->unload(lib->plugins);
#ifdef CAPABILITIES_LIBCAP
@@ -123,10 +129,6 @@ static void destroy(private_daemon_t *this)
DESTROY_IF(this->public.controller);
DESTROY_IF(this->public.eap);
DESTROY_IF(this->public.xauth);
-#ifdef ME
- DESTROY_IF(this->public.connect_manager);
- DESTROY_IF(this->public.mediation_manager);
-#endif /* ME */
DESTROY_IF(this->public.backends);
DESTROY_IF(this->public.socket);
@@ -200,27 +202,6 @@ METHOD(daemon_t, start, void,
DEFAULT_THREADS));
}
-/**
- * Log loaded plugins
- */
-static void print_plugins()
-{
- char buf[512];
- int len = 0;
- enumerator_t *enumerator;
- plugin_t *plugin;
-
- buf[0] = '\0';
- enumerator = lib->plugins->create_plugin_enumerator(lib->plugins);
- while (len < sizeof(buf) && enumerator->enumerate(enumerator, &plugin, NULL))
- {
- len += snprintf(&buf[len], sizeof(buf)-len, "%s ",
- plugin->get_name(plugin));
- }
- enumerator->destroy(enumerator);
- DBG1(DBG_DMN, "loaded plugins: %s", buf);
-}
-
METHOD(daemon_t, initialize, bool,
private_daemon_t *this)
{
@@ -241,8 +222,8 @@ METHOD(daemon_t, initialize, bool,
{
return FALSE;
}
-
- print_plugins();
+ DBG1(DBG_DMN, "loaded plugins: %s",
+ lib->plugins->loaded_plugins(lib->plugins));
this->public.ike_sa_manager = ike_sa_manager_create();
if (this->public.ike_sa_manager == NULL)
diff --git a/src/libcharon/encoding/payloads/notify_payload.c b/src/libcharon/encoding/payloads/notify_payload.c
index ade2d945f..411534491 100755
--- a/src/libcharon/encoding/payloads/notify_payload.c
+++ b/src/libcharon/encoding/payloads/notify_payload.c
@@ -115,15 +115,16 @@ ENUM_NEXT(notify_type_names, UNITY_LOAD_BALANCE, UNITY_LOAD_BALANCE, DPD_R_U_THE
"UNITY_LOAD_BALANCE");
ENUM_NEXT(notify_type_names, USE_BEET_MODE, USE_BEET_MODE, UNITY_LOAD_BALANCE,
"USE_BEET_MODE");
-ENUM_NEXT(notify_type_names, ME_MEDIATION, ME_RESPONSE, USE_BEET_MODE,
+ENUM_NEXT(notify_type_names, ME_MEDIATION, RADIUS_ATTRIBUTE, USE_BEET_MODE,
"ME_MEDIATION",
"ME_ENDPOINT",
"ME_CALLBACK",
"ME_CONNECTID",
"ME_CONNECTKEY",
"ME_CONNECTAUTH",
- "ME_RESPONSE");
-ENUM_END(notify_type_names, ME_RESPONSE);
+ "ME_RESPONSE",
+ "RADIUS_ATTRIBUTE",);
+ENUM_END(notify_type_names, RADIUS_ATTRIBUTE);
ENUM_BEGIN(notify_type_short_names, UNSUPPORTED_CRITICAL_PAYLOAD, UNSUPPORTED_CRITICAL_PAYLOAD,
@@ -216,15 +217,16 @@ ENUM_NEXT(notify_type_short_names, UNITY_LOAD_BALANCE, UNITY_LOAD_BALANCE, DPD_R
"UNITY_LB");
ENUM_NEXT(notify_type_short_names, USE_BEET_MODE, USE_BEET_MODE, UNITY_LOAD_BALANCE,
"BEET_MODE");
-ENUM_NEXT(notify_type_short_names, ME_MEDIATION, ME_RESPONSE, USE_BEET_MODE,
+ENUM_NEXT(notify_type_short_names, ME_MEDIATION, RADIUS_ATTRIBUTE, USE_BEET_MODE,
"ME_MED",
"ME_EP",
"ME_CB",
"ME_CID",
"ME_CKEY",
"ME_CAUTH",
- "ME_R");
-ENUM_END(notify_type_short_names, ME_RESPONSE);
+ "ME_R",
+ "RADIUS");
+ENUM_END(notify_type_short_names, RADIUS_ATTRIBUTE);
typedef struct private_notify_payload_t private_notify_payload_t;
diff --git a/src/libcharon/encoding/payloads/notify_payload.h b/src/libcharon/encoding/payloads/notify_payload.h
index 58d85ffae..07fbcb49b 100755
--- a/src/libcharon/encoding/payloads/notify_payload.h
+++ b/src/libcharon/encoding/payloads/notify_payload.h
@@ -154,7 +154,9 @@ enum notify_type_t {
ME_CONNECTID = 40965,
ME_CONNECTKEY = 40966,
ME_CONNECTAUTH = 40967,
- ME_RESPONSE = 40968
+ ME_RESPONSE = 40968,
+ /* RADIUS attribute received/to send to a AAA backend */
+ RADIUS_ATTRIBUTE = 40969,
};
/**
diff --git a/src/libcharon/plugins/eap_peap/eap_peap.c b/src/libcharon/plugins/eap_peap/eap_peap.c
index 5bae0fa9b..bd426bba7 100644
--- a/src/libcharon/plugins/eap_peap/eap_peap.c
+++ b/src/libcharon/plugins/eap_peap/eap_peap.c
@@ -166,7 +166,8 @@ static eap_peap_t *eap_peap_create(private_eap_peap_t * this,
"charon.plugins.eap-peap.max_message_count", MAX_MESSAGE_COUNT);
include_length = lib->settings->get_bool(lib->settings,
"charon.plugins.eap-peap.include_length", FALSE);
- tls = tls_create(is_server, server, peer, TLS_PURPOSE_EAP_PEAP, application);
+ tls = tls_create(is_server, server, peer, TLS_PURPOSE_EAP_PEAP,
+ application, NULL);
this->tls_eap = tls_eap_create(EAP_PEAP, tls, frag_size, max_msg_count,
include_length);
if (!this->tls_eap)
diff --git a/src/libcharon/plugins/eap_radius/Makefile.am b/src/libcharon/plugins/eap_radius/Makefile.am
index afc50bced..181497ab5 100644
--- a/src/libcharon/plugins/eap_radius/Makefile.am
+++ b/src/libcharon/plugins/eap_radius/Makefile.am
@@ -1,21 +1,21 @@
INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \
- -I$(top_srcdir)/src/libcharon
+ -I$(top_srcdir)/src/libcharon -I$(top_srcdir)/src/libradius
AM_CFLAGS = -rdynamic
if MONOLITHIC
noinst_LTLIBRARIES = libstrongswan-eap-radius.la
else
+libstrongswan_eap_radius_la_LIBADD = $(top_builddir)/src/libradius/libradius.la
plugin_LTLIBRARIES = libstrongswan-eap-radius.la
endif
libstrongswan_eap_radius_la_SOURCES = \
eap_radius_plugin.h eap_radius_plugin.c \
eap_radius.h eap_radius.c \
- radius_server.h radius_server.c \
- radius_socket.h radius_socket.c \
- radius_client.h radius_client.c \
- radius_message.h radius_message.c
+ eap_radius_accounting.h eap_radius_accounting.c \
+ eap_radius_dae.h eap_radius_dae.c \
+ eap_radius_forward.h eap_radius_forward.c
libstrongswan_eap_radius_la_LDFLAGS = -module -avoid-version
diff --git a/src/libcharon/plugins/eap_radius/eap_radius.c b/src/libcharon/plugins/eap_radius/eap_radius.c
index dfe0e2e09..c0a3703b6 100644
--- a/src/libcharon/plugins/eap_radius/eap_radius.c
+++ b/src/libcharon/plugins/eap_radius/eap_radius.c
@@ -14,14 +14,14 @@
*/
#include "eap_radius.h"
+#include "eap_radius_plugin.h"
+#include "eap_radius_forward.h"
-#include "radius_message.h"
-#include "radius_client.h"
+#include <radius_message.h>
+#include <radius_client.h>
#include <daemon.h>
-#define TUNNEL_TYPE_ESP 9
-
typedef struct private_eap_radius_t private_eap_radius_t;
/**
@@ -162,7 +162,7 @@ METHOD(eap_method_t, initiate, status_t,
status_t status = FAILED;
chunk_t username;
- request = radius_message_create_request();
+ request = radius_message_create(RMC_ACCESS_REQUEST);
username = chunk_create(this->id_prefix, strlen(this->id_prefix));
username = chunk_cata("cc", username, this->peer->get_encoding(this->peer));
request->add(request, RAT_USER_NAME, username);
@@ -175,16 +175,22 @@ METHOD(eap_method_t, initiate, status_t,
{
add_eap_identity(this, request);
}
+ eap_radius_forward_from_ike(request);
response = this->client->request(this->client, request);
if (response)
{
+ eap_radius_forward_to_ike(response);
if (radius2ike(this, response, out))
{
status = NEED_MORE;
}
response->destroy(response);
}
+ else
+ {
+ charon->bus->alert(charon->bus, ALERT_RADIUS_NOT_RESPONDING);
+ }
request->destroy(request);
return status;
}
@@ -253,7 +259,7 @@ static void process_filter_id(private_eap_radius_t *this, radius_message_t *msg)
tunnel_type = untoh32(data.ptr);
DBG1(DBG_IKE, "received RADIUS attribute Tunnel-Type: "
"tag = %u, value = %u", tunnel_tag, tunnel_type);
- is_esp_tunnel = (tunnel_type == TUNNEL_TYPE_ESP);
+ is_esp_tunnel = (tunnel_type == RADIUS_TUNNEL_TYPE_ESP);
break;
case RAT_FILTER_ID:
filter_id = data;
@@ -282,6 +288,31 @@ static void process_filter_id(private_eap_radius_t *this, radius_message_t *msg)
}
}
+/**
+ * Handle Session-Timeout attribte
+ */
+static void process_timeout(private_eap_radius_t *this, radius_message_t *msg)
+{
+ enumerator_t *enumerator;
+ ike_sa_t *ike_sa;
+ chunk_t data;
+ int type;
+
+ enumerator = msg->create_enumerator(msg);
+ while (enumerator->enumerate(enumerator, &type, &data))
+ {
+ if (type == RAT_SESSION_TIMEOUT && data.len == 4)
+ {
+ ike_sa = charon->bus->get_sa(charon->bus);
+ if (ike_sa)
+ {
+ ike_sa->set_auth_lifetime(ike_sa, untoh32(data.ptr));
+ }
+ }
+ }
+ enumerator->destroy(enumerator);
+}
+
METHOD(eap_method_t, process, status_t,
private_eap_radius_t *this, eap_payload_t *in, eap_payload_t **out)
{
@@ -289,22 +320,25 @@ METHOD(eap_method_t, process, status_t,
status_t status = FAILED;
chunk_t data;
- request = radius_message_create_request();
+ request = radius_message_create(RMC_ACCESS_REQUEST);
request->add(request, RAT_USER_NAME, this->peer->get_encoding(this->peer));
data = in->get_data(in);
DBG3(DBG_IKE, "%N payload %B", eap_type_names, this->type, &data);
-
- /* fragment data suitable for RADIUS (not more than 253 bytes) */
- while (data.len > 253)
+
+ /* fragment data suitable for RADIUS */
+ while (data.len > MAX_RADIUS_ATTRIBUTE_SIZE)
{
- request->add(request, RAT_EAP_MESSAGE, chunk_create(data.ptr, 253));
- data = chunk_skip(data, 253);
+ request->add(request, RAT_EAP_MESSAGE,
+ chunk_create(data.ptr,MAX_RADIUS_ATTRIBUTE_SIZE));
+ data = chunk_skip(data, MAX_RADIUS_ATTRIBUTE_SIZE);
}
request->add(request, RAT_EAP_MESSAGE, data);
+ eap_radius_forward_from_ike(request);
response = this->client->request(this->client, request);
if (response)
{
+ eap_radius_forward_to_ike(response);
switch (response->get_code(response))
{
case RMC_ACCESS_CHALLENGE:
@@ -324,6 +358,7 @@ METHOD(eap_method_t, process, status_t,
{
process_filter_id(this, response);
}
+ process_timeout(this, response);
DBG1(DBG_IKE, "RADIUS authentication of '%Y' successful",
this->peer);
status = SUCCESS;
@@ -427,7 +462,7 @@ eap_radius_t *eap_radius_create(identification_t *server, identification_t *peer
"charon.plugins.eap-radius.filter_id", FALSE),
);
- this->client = radius_client_create();
+ this->client = eap_radius_create_client();
if (!this->client)
{
free(this);
diff --git a/src/libcharon/plugins/eap_radius/eap_radius_accounting.c b/src/libcharon/plugins/eap_radius/eap_radius_accounting.c
new file mode 100644
index 000000000..243c76304
--- /dev/null
+++ b/src/libcharon/plugins/eap_radius/eap_radius_accounting.c
@@ -0,0 +1,339 @@
+/*
+ * Copyright (C) 2012 Martin Willi
+ * Copyright (C) 2012 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 "eap_radius_accounting.h"
+#include "eap_radius_plugin.h"
+
+#include <time.h>
+
+#include <radius_message.h>
+#include <radius_client.h>
+#include <daemon.h>
+#include <utils/hashtable.h>
+#include <threading/mutex.h>
+
+typedef struct private_eap_radius_accounting_t private_eap_radius_accounting_t;
+
+/**
+ * Private data of an eap_radius_accounting_t object.
+ */
+struct private_eap_radius_accounting_t {
+
+ /**
+ * Public eap_radius_accounting_t interface.
+ */
+ eap_radius_accounting_t public;
+
+ /**
+ * Hashtable with sessions, IKE_SA unique id => entry_t
+ */
+ hashtable_t *sessions;
+
+ /**
+ * Mutex to lock sessions
+ */
+ mutex_t *mutex;
+
+ /**
+ * Session ID prefix
+ */
+ u_int32_t prefix;
+};
+
+/**
+ * Hashtable entry with usage stats
+ */
+typedef struct {
+ /** RADIUS accounting session ID */
+ char sid[16];
+ /** number of octets sent */
+ u_int64_t sent;
+ /** number of octets received */
+ u_int64_t received;
+ /** session creation time */
+ time_t created;
+} entry_t;
+
+/**
+ * Accounting message status types
+ */
+typedef enum {
+ ACCT_STATUS_START = 1,
+ ACCT_STATUS_STOP = 2,
+ ACCT_STATUS_INTERIM_UPDATE = 3,
+ ACCT_STATUS_ACCOUNTING_ON = 7,
+ ACCT_STATUS_ACCOUNTING_OFF = 8,
+} radius_acct_status_t;
+
+/**
+ * Hashtable hash function
+ */
+static u_int hash(uintptr_t key)
+{
+ return key;
+}
+
+/**
+ * Hashtable equals function
+ */
+static bool equals(uintptr_t a, uintptr_t b)
+{
+ return a == b;
+}
+
+/**
+ * Update usage counter when a CHILD_SA rekeys/goes down
+ */
+static void update_usage(private_eap_radius_accounting_t *this,
+ ike_sa_t *ike_sa, child_sa_t *child_sa)
+{
+ u_int64_t sent, received;
+ entry_t *entry;
+
+ child_sa->get_usestats(child_sa, FALSE, NULL, &sent);
+ child_sa->get_usestats(child_sa, TRUE, NULL, &received);
+
+ this->mutex->lock(this->mutex);
+ entry = this->sessions->get(this->sessions,
+ (void*)(uintptr_t)ike_sa->get_unique_id(ike_sa));
+ if (entry)
+ {
+ entry->sent += sent;
+ entry->received += received;
+ }
+ this->mutex->unlock(this->mutex);
+}
+
+/**
+ * Send a RADIUS message, wait for response
+ */
+static bool send_message(private_eap_radius_accounting_t *this,
+ radius_message_t *request)
+{
+ radius_message_t *response;
+ radius_client_t *client;
+ bool ack = FALSE;
+
+ client = eap_radius_create_client();
+ if (client)
+ {
+ response = client->request(client, request);
+ if (response)
+ {
+ ack = response->get_code(response) == RMC_ACCOUNTING_RESPONSE;
+ response->destroy(response);
+ }
+ else
+ {
+ charon->bus->alert(charon->bus, ALERT_RADIUS_NOT_RESPONDING);
+ }
+ client->destroy(client);
+ }
+ return ack;
+}
+
+/**
+ * Add common IKE_SA parameters to RADIUS account message
+ */
+static void add_ike_sa_parameters(radius_message_t *message, ike_sa_t *ike_sa)
+{
+ host_t *vip;
+ char buf[64];
+ chunk_t data;
+
+ snprintf(buf, sizeof(buf), "%Y", ike_sa->get_other_eap_id(ike_sa));
+ message->add(message, RAT_USER_NAME, chunk_create(buf, strlen(buf)));
+ snprintf(buf, sizeof(buf), "%#H", ike_sa->get_other_host(ike_sa));
+ message->add(message, RAT_CALLING_STATION_ID, chunk_create(buf, strlen(buf)));
+ vip = ike_sa->get_virtual_ip(ike_sa, FALSE);
+ if (vip && vip->get_family(vip) == AF_INET)
+ {
+ message->add(message, RAT_FRAMED_IP_ADDRESS, vip->get_address(vip));
+ }
+ if (vip && vip->get_family(vip) == 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);
+ }
+}
+
+/**
+ * Send an accounting start message
+ */
+static void send_start(private_eap_radius_accounting_t *this, ike_sa_t *ike_sa)
+{
+ radius_message_t *message;
+ entry_t *entry;
+ u_int32_t id, value;
+
+ id = ike_sa->get_unique_id(ike_sa);
+ INIT(entry,
+ .created = time_monotonic(NULL),
+ );
+ snprintf(entry->sid, sizeof(entry->sid), "%u-%u", this->prefix, id);
+
+ message = radius_message_create(RMC_ACCOUNTING_REQUEST);
+ value = htonl(ACCT_STATUS_START);
+ message->add(message, RAT_ACCT_STATUS_TYPE, chunk_from_thing(value));
+ message->add(message, RAT_ACCT_SESSION_ID,
+ chunk_create(entry->sid, strlen(entry->sid)));
+ add_ike_sa_parameters(message, ike_sa);
+ if (send_message(this, message))
+ {
+ this->mutex->lock(this->mutex);
+ entry = this->sessions->put(this->sessions, (void*)(uintptr_t)id, entry);
+ this->mutex->unlock(this->mutex);
+ free(entry);
+ }
+ message->destroy(message);
+}
+
+/**
+ * Send an account stop message
+ */
+static void send_stop(private_eap_radius_accounting_t *this, ike_sa_t *ike_sa)
+{
+ radius_message_t *message;
+ entry_t *entry;
+ u_int32_t id, value;
+
+ id = ike_sa->get_unique_id(ike_sa);
+ this->mutex->lock(this->mutex);
+ entry = this->sessions->remove(this->sessions, (void*)(uintptr_t)id);
+ this->mutex->unlock(this->mutex);
+ if (entry)
+ {
+ message = radius_message_create(RMC_ACCOUNTING_REQUEST);
+ value = htonl(ACCT_STATUS_STOP);
+ message->add(message, RAT_ACCT_STATUS_TYPE, chunk_from_thing(value));
+ message->add(message, RAT_ACCT_SESSION_ID,
+ chunk_create(entry->sid, strlen(entry->sid)));
+ add_ike_sa_parameters(message, ike_sa);
+ value = htonl(entry->sent);
+ message->add(message, RAT_ACCT_OUTPUT_OCTETS, chunk_from_thing(value));
+ value = htonl(entry->sent >> 32);
+ if (value)
+ {
+ message->add(message, RAT_ACCT_OUTPUT_GIGAWORDS,
+ chunk_from_thing(value));
+ }
+ value = htonl(entry->received);
+ message->add(message, RAT_ACCT_INPUT_OCTETS, chunk_from_thing(value));
+ value = htonl(entry->received >> 32);
+ if (value)
+ {
+ message->add(message, RAT_ACCT_INPUT_GIGAWORDS,
+ chunk_from_thing(value));
+ }
+ value = htonl(time_monotonic(NULL) - entry->created);
+ message->add(message, RAT_ACCT_SESSION_TIME, chunk_from_thing(value));
+
+ send_message(this, message);
+ message->destroy(message);
+ free(entry);
+ }
+}
+
+METHOD(listener_t, ike_updown, bool,
+ private_eap_radius_accounting_t *this, ike_sa_t *ike_sa, bool up)
+{
+ if (!up)
+ {
+ enumerator_t *enumerator;
+ child_sa_t *child_sa;
+
+ /* update usage for all children just before sending stop */
+ enumerator = ike_sa->create_child_sa_enumerator(ike_sa);
+ while (enumerator->enumerate(enumerator, &child_sa))
+ {
+ update_usage(this, ike_sa, child_sa);
+ }
+ enumerator->destroy(enumerator);
+
+ send_stop(this, ike_sa);
+ }
+ return TRUE;
+}
+
+METHOD(listener_t, message_hook, bool,
+ private_eap_radius_accounting_t *this, ike_sa_t *ike_sa,
+ message_t *message, bool incoming, bool plain)
+{
+ /* start accounting here, virtual IP now is set */
+ if (plain && ike_sa->get_state(ike_sa) == IKE_ESTABLISHED &&
+ message->get_exchange_type(message) == IKE_AUTH &&
+ !incoming && !message->get_request(message))
+ {
+ send_start(this, ike_sa);
+ }
+ return TRUE;
+}
+
+METHOD(listener_t, child_rekey, bool,
+ private_eap_radius_accounting_t *this, ike_sa_t *ike_sa,
+ child_sa_t *old, child_sa_t *new)
+{
+ update_usage(this, ike_sa, old);
+
+ return TRUE;
+}
+
+METHOD(listener_t, child_updown, bool,
+ private_eap_radius_accounting_t *this, ike_sa_t *ike_sa,
+ child_sa_t *child_sa, bool up)
+{
+ if (!up && ike_sa->get_state(ike_sa) == IKE_ESTABLISHED)
+ {
+ update_usage(this, ike_sa, child_sa);
+ }
+ return TRUE;
+}
+
+METHOD(eap_radius_accounting_t, destroy, void,
+ private_eap_radius_accounting_t *this)
+{
+ this->mutex->destroy(this->mutex);
+ this->sessions->destroy(this->sessions);
+ free(this);
+}
+
+/**
+ * See header
+ */
+eap_radius_accounting_t *eap_radius_accounting_create()
+{
+ private_eap_radius_accounting_t *this;
+
+ INIT(this,
+ .public = {
+ .listener = {
+ .ike_updown = _ike_updown,
+ .message = _message_hook,
+ .child_updown = _child_updown,
+ .child_rekey = _child_rekey,
+ },
+ .destroy = _destroy,
+ },
+ /* use system time as Session ID prefix */
+ .prefix = (u_int32_t)time(NULL),
+ .sessions = hashtable_create((hashtable_hash_t)hash,
+ (hashtable_equals_t)equals, 32),
+ .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
+ );
+
+ return &this->public;
+}
diff --git a/src/libcharon/plugins/eap_radius/eap_radius_accounting.h b/src/libcharon/plugins/eap_radius/eap_radius_accounting.h
new file mode 100644
index 000000000..811a5bb90
--- /dev/null
+++ b/src/libcharon/plugins/eap_radius/eap_radius_accounting.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2012 Martin Willi
+ * Copyright (C) 2012 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 eap_radius_accounting eap_radius_accounting
+ * @{ @ingroup eap_radius
+ */
+
+#ifndef EAP_RADIUS_ACCOUNTING_H_
+#define EAP_RADIUS_ACCOUNTING_H_
+
+#include <bus/listeners/listener.h>
+
+typedef struct eap_radius_accounting_t eap_radius_accounting_t;
+
+/**
+ * RADIUS accounting for IKE/IPsec.
+ */
+struct eap_radius_accounting_t {
+
+ /**
+ * Implements listener_t.
+ */
+ listener_t listener;
+
+ /**
+ * Destroy a eap_radius_accounting_t.
+ */
+ void (*destroy)(eap_radius_accounting_t *this);
+};
+
+/**
+ * Create a eap_radius_accounting instance.
+ */
+eap_radius_accounting_t *eap_radius_accounting_create();
+
+#endif /** EAP_RADIUS_ACCOUNTING_H_ @}*/
diff --git a/src/libcharon/plugins/eap_radius/eap_radius_dae.c b/src/libcharon/plugins/eap_radius/eap_radius_dae.c
new file mode 100644
index 000000000..5823142cc
--- /dev/null
+++ b/src/libcharon/plugins/eap_radius/eap_radius_dae.c
@@ -0,0 +1,543 @@
+/*
+ * Copyright (C) 2012 Martin Willi
+ * Copyright (C) 2012 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 "eap_radius_dae.h"
+
+#include <radius_message.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <daemon.h>
+#include <threading/thread.h>
+#include <processing/jobs/callback_job.h>
+#include <processing/jobs/delete_ike_sa_job.h>
+
+#define RADIUS_DAE_PORT 3799
+
+typedef struct private_eap_radius_dae_t private_eap_radius_dae_t;
+
+/**
+ * Private data of an eap_radius_dae_t object.
+ */
+struct private_eap_radius_dae_t {
+
+ /**
+ * Public eap_radius_dae_t interface.
+ */
+ eap_radius_dae_t public;
+
+ /**
+ * RADIUS session state
+ */
+ eap_radius_accounting_t *accounting;
+
+ /**
+ * Socket to listen on authorization extension port
+ */
+ int fd;
+
+ /**
+ * Listen job
+ */
+ callback_job_t *job;
+
+ /**
+ * RADIUS shared secret for DAE exchanges
+ */
+ chunk_t secret;
+
+ /**
+ * MD5 hasher
+ */
+ hasher_t *hasher;
+
+ /**
+ * HMAC MD5 signer, with secret set
+ */
+ signer_t *signer;
+
+ /**
+ * List of responses for retransmission, as entry_t
+ */
+ linked_list_t *responses;
+};
+
+/**
+ * Entry to store responses for retransmit
+ */
+typedef struct {
+ /** stored response */
+ radius_message_t *response;
+ /** client that sent the request */
+ host_t *client;
+} entry_t;
+
+/**
+ * Clean up an entry
+ */
+static void entry_destroy(entry_t *entry)
+{
+ entry->response->destroy(entry->response);
+ entry->client->destroy(entry->client);
+ free(entry);
+}
+
+/**
+ * Save/Replace response for retransmission
+ */
+static void save_retransmit(private_eap_radius_dae_t *this,
+ radius_message_t *response, host_t *client)
+{
+ enumerator_t *enumerator;
+ entry_t *entry;
+ bool found = FALSE;
+
+ enumerator = this->responses->create_enumerator(this->responses);
+ while (enumerator->enumerate(enumerator, &entry))
+ {
+ if (client->equals(client, entry->client))
+ {
+ entry->response->destroy(entry->response);
+ entry->response = response;
+ found = TRUE;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ if (!found)
+ {
+ INIT(entry,
+ .response = response,
+ .client = client->clone(client),
+ );
+ this->responses->insert_first(this->responses, entry);
+ }
+}
+
+/**
+ * Send a RADIUS message to client
+ */
+static void send_message(private_eap_radius_dae_t *this,
+ radius_message_t *message, host_t *client)
+{
+ chunk_t data;
+
+ data = message->get_encoding(message);
+ if (sendto(this->fd, data.ptr, data.len, 0, client->get_sockaddr(client),
+ *client->get_sockaddr_len(client)) != data.len)
+ {
+ DBG1(DBG_CFG, "sending RADIUS DAE response failed: %s", strerror(errno));
+ }
+}
+
+/**
+ * Check if we request is a retransmit, retransmit stored response
+ */
+static bool send_retransmit(private_eap_radius_dae_t *this,
+ radius_message_t *request, host_t *client)
+{
+ enumerator_t *enumerator;
+ entry_t *entry;
+ bool found = FALSE;
+
+ enumerator = this->responses->create_enumerator(this->responses);
+ while (enumerator->enumerate(enumerator, &entry))
+ {
+ if (client->equals(client, entry->client) &&
+ request->get_identifier(request) ==
+ entry->response->get_identifier(entry->response))
+ {
+ DBG1(DBG_CFG, "received retransmit of RADIUS %N, retransmitting %N "
+ "to %H", radius_message_code_names, request->get_code(request),
+ radius_message_code_names,
+ entry->response->get_code(entry->response), client);
+ send_message(this, entry->response, client);
+ found = TRUE;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ return found;
+}
+
+/**
+ * Send an ACK/NAK response for a request
+ */
+static void send_response(private_eap_radius_dae_t *this,
+ radius_message_t *request, radius_message_code_t code,
+ host_t *client)
+{
+ radius_message_t *response;
+
+ response = radius_message_create(code);
+ response->set_identifier(response, request->get_identifier(request));
+ response->sign(response, request->get_authenticator(request),
+ this->secret, this->hasher, this->signer, NULL, FALSE);
+
+ send_message(this, response, client);
+ save_retransmit(this, response, client);
+}
+
+/**
+ * Add all IKE_SAs matching to user to a list
+ */
+static void add_matching_ike_sas(linked_list_t *list, identification_t *user)
+{
+ enumerator_t *enumerator;
+ ike_sa_t *ike_sa;
+ ike_sa_id_t *id;
+
+ enumerator = charon->ike_sa_manager->create_enumerator(
+ charon->ike_sa_manager, FALSE);
+ while (enumerator->enumerate(enumerator, &ike_sa))
+ {
+ if (user->matches(user, ike_sa->get_other_eap_id(ike_sa)))
+ {
+ id = ike_sa->get_id(ike_sa);
+ list->insert_last(list, id->clone(id));
+ }
+ }
+ enumerator->destroy(enumerator);
+}
+
+/**
+ * Get list of IKE_SAs matching a Disconnect/CoA request
+ */
+static linked_list_t *get_matching_ike_sas(private_eap_radius_dae_t *this,
+ radius_message_t *request, host_t *client)
+{
+ enumerator_t *enumerator;
+ identification_t *user;
+ linked_list_t *ids;
+ chunk_t data;
+ int type;
+
+ ids = linked_list_create();
+
+ enumerator = request->create_enumerator(request);
+ while (enumerator->enumerate(enumerator, &type, &data))
+ {
+ if (type == RAT_USER_NAME && data.len)
+ {
+ user = identification_create_from_data(data);
+ DBG1(DBG_CFG, "received RADIUS DAE %N for %Y from %H",
+ radius_message_code_names, request->get_code(request),
+ user, client);
+ add_matching_ike_sas(ids, user);
+ user->destroy(user);
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ return ids;
+}
+
+/**
+ * Process a DAE disconnect request, send response
+ */
+static void process_disconnect(private_eap_radius_dae_t *this,
+ radius_message_t *request, host_t *client)
+{
+ enumerator_t *enumerator;
+ linked_list_t *ids;
+ ike_sa_id_t *id;
+
+ ids = get_matching_ike_sas(this, request, client);
+
+ if (ids->get_count(ids))
+ {
+ DBG1(DBG_CFG, "closing %d IKE_SA%s matching %N, sending %N",
+ ids->get_count(ids), ids->get_count(ids) > 1 ? "s" : "",
+ radius_message_code_names, RMC_DISCONNECT_REQUEST,
+ radius_message_code_names, RMC_DISCONNECT_ACK);
+
+ enumerator = ids->create_enumerator(ids);
+ while (enumerator->enumerate(enumerator, &id))
+ {
+ lib->processor->queue_job(lib->processor, (job_t*)
+ delete_ike_sa_job_create(id, TRUE));
+ }
+ enumerator->destroy(enumerator);
+
+ send_response(this, request, RMC_DISCONNECT_ACK, client);
+ }
+ else
+ {
+ DBG1(DBG_CFG, "no IKE_SA matches %N, sending %N",
+ radius_message_code_names, RMC_DISCONNECT_REQUEST,
+ radius_message_code_names, RMC_DISCONNECT_NAK);
+ send_response(this, request, RMC_DISCONNECT_NAK, client);
+ }
+ ids->destroy_offset(ids, offsetof(ike_sa_id_t, destroy));
+}
+
+/**
+ * Apply a new lifetime to an IKE_SA
+ */
+static void apply_lifetime(private_eap_radius_dae_t *this, ike_sa_id_t *id,
+ u_int32_t lifetime)
+{
+ ike_sa_t *ike_sa;
+
+ ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, id);
+ if (ike_sa)
+ {
+ if (ike_sa->set_auth_lifetime(ike_sa, lifetime) == DESTROY_ME)
+ {
+ charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
+ ike_sa);
+ }
+ else
+ {
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+ }
+ }
+}
+
+/**
+ * Process a DAE CoA request, send response
+ */
+static void process_coa(private_eap_radius_dae_t *this,
+ radius_message_t *request, host_t *client)
+{
+ enumerator_t *enumerator;
+ linked_list_t *ids;
+ ike_sa_id_t *id;
+ chunk_t data;
+ int type;
+ u_int32_t lifetime = 0;
+ bool lifetime_seen = FALSE;
+
+ ids = get_matching_ike_sas(this, request, client);
+
+ if (ids->get_count(ids))
+ {
+ enumerator = request->create_enumerator(request);
+ while (enumerator->enumerate(enumerator, &type, &data))
+ {
+ if (type == RAT_SESSION_TIMEOUT && data.len == 4)
+ {
+ lifetime = untoh32(data.ptr);
+ lifetime_seen = TRUE;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ if (lifetime_seen)
+ {
+ DBG1(DBG_CFG, "applying %us lifetime to %d IKE_SA%s matching %N, "
+ "sending %N", lifetime, ids->get_count(ids),
+ ids->get_count(ids) > 1 ? "s" : "",
+ radius_message_code_names, RMC_COA_REQUEST,
+ radius_message_code_names, RMC_COA_ACK);
+
+ enumerator = ids->create_enumerator(ids);
+ while (enumerator->enumerate(enumerator, &id))
+ {
+ apply_lifetime(this, id, lifetime);
+ }
+ enumerator->destroy(enumerator);
+ send_response(this, request, RMC_COA_ACK, client);
+ }
+ else
+ {
+ DBG1(DBG_CFG, "no Session-Timeout attribute found in %N, sending %N",
+ radius_message_code_names, RMC_COA_REQUEST,
+ radius_message_code_names, RMC_COA_NAK);
+ send_response(this, request, RMC_COA_NAK, client);
+ }
+ }
+ else
+ {
+ DBG1(DBG_CFG, "no IKE_SA matches %N, sending %N",
+ radius_message_code_names, RMC_COA_REQUEST,
+ radius_message_code_names, RMC_COA_NAK);
+ send_response(this, request, RMC_COA_NAK, client);
+ }
+ ids->destroy_offset(ids, offsetof(ike_sa_id_t, destroy));
+}
+
+/**
+ * Receive RADIUS DAE requests
+ */
+static job_requeue_t receive(private_eap_radius_dae_t *this)
+{
+ struct sockaddr_storage addr;
+ socklen_t addr_len = sizeof(addr);
+ radius_message_t *request;
+ char buf[2048];
+ ssize_t len;
+ bool oldstate;
+ host_t *client;
+
+ oldstate = thread_cancelability(TRUE);
+ len = recvfrom(this->fd, buf, sizeof(buf), 0,
+ (struct sockaddr*)&addr, &addr_len);
+ thread_cancelability(oldstate);
+
+ if (len > 0)
+ {
+ request = radius_message_parse(chunk_create(buf, len));
+ if (request)
+ {
+ client = host_create_from_sockaddr((struct sockaddr*)&addr);
+ if (client)
+ {
+ if (!send_retransmit(this, request, client))
+ {
+ if (request->verify(request, NULL, this->secret,
+ this->hasher, this->signer))
+ {
+ switch (request->get_code(request))
+ {
+ case RMC_DISCONNECT_REQUEST:
+ process_disconnect(this, request, client);
+ break;
+ case RMC_COA_REQUEST:
+ process_coa(this, request, client);
+ break;
+ default:
+ DBG1(DBG_CFG, "ignoring unsupported RADIUS DAE "
+ "%N message from %H",
+ radius_message_code_names,
+ request->get_code(request), client);
+ break;
+ }
+ }
+ }
+ client->destroy(client);
+ }
+ request->destroy(request);
+ }
+ else
+ {
+ DBG1(DBG_NET, "ignoring invalid RADIUS DAE request");
+ }
+ }
+ else
+ {
+ DBG1(DBG_NET, "receving RADIUS DAE request failed: %s", strerror(errno));
+ }
+ return JOB_REQUEUE_DIRECT;
+}
+
+/**
+ * Open DAE socket
+ */
+static bool open_socket(private_eap_radius_dae_t *this)
+{
+ host_t *host;
+
+ this->fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (this->fd == -1)
+ {
+ DBG1(DBG_CFG, "unable to open RADIUS DAE socket: %s", strerror(errno));
+ return FALSE;
+ }
+
+ host = host_create_from_string(
+ lib->settings->get_str(lib->settings,
+ "charon.plugins.eap-radius.dae.listen", "0.0.0.0"),
+ lib->settings->get_int(lib->settings,
+ "charon.plugins.eap-radius.dae.port", RADIUS_DAE_PORT));
+ if (!host)
+ {
+ DBG1(DBG_CFG, "invalid RADIUS DAE listen address");
+ return FALSE;
+ }
+
+ if (bind(this->fd, host->get_sockaddr(host),
+ *host->get_sockaddr_len(host)) == -1)
+ {
+ DBG1(DBG_CFG, "unable to bind RADIUS DAE socket: %s", strerror(errno));
+ host->destroy(host);
+ return FALSE;
+ }
+ host->destroy(host);
+ return TRUE;
+}
+
+METHOD(eap_radius_dae_t, destroy, void,
+ private_eap_radius_dae_t *this)
+{
+ if (this->job)
+ {
+ this->job->cancel(this->job);
+ }
+ if (this->fd != -1)
+ {
+ close(this->fd);
+ }
+ DESTROY_IF(this->signer);
+ DESTROY_IF(this->hasher);
+ this->responses->destroy_function(this->responses, (void*)entry_destroy);
+ free(this);
+}
+
+/**
+ * See header
+ */
+eap_radius_dae_t *eap_radius_dae_create(eap_radius_accounting_t *accounting)
+{
+ private_eap_radius_dae_t *this;
+
+ INIT(this,
+ .public = {
+ .destroy = _destroy,
+ },
+ .accounting = accounting,
+ .fd = -1,
+ .secret = {
+ .ptr = lib->settings->get_str(lib->settings,
+ "charon.plugins.eap-radius.dae.secret", NULL),
+ },
+ .hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5),
+ .signer = lib->crypto->create_signer(lib->crypto, AUTH_HMAC_MD5_128),
+ .responses = linked_list_create(),
+ );
+
+ if (!this->hasher || !this->signer)
+ {
+ destroy(this);
+ return NULL;
+ }
+ if (!this->secret.ptr)
+ {
+ DBG1(DBG_CFG, "missing RADIUS DAE secret, disabled");
+ destroy(this);
+ return NULL;
+ }
+ this->secret.len = strlen(this->secret.ptr);
+ this->signer->set_key(this->signer, this->secret);
+
+ if (!open_socket(this))
+ {
+ destroy(this);
+ return NULL;
+ }
+
+ this->job = callback_job_create_with_prio((callback_job_cb_t)receive,
+ this, NULL, NULL, JOB_PRIO_CRITICAL);
+ lib->processor->queue_job(lib->processor, (job_t*)this->job);
+
+ return &this->public;
+}
diff --git a/src/libcharon/plugins/eap_radius/eap_radius_dae.h b/src/libcharon/plugins/eap_radius/eap_radius_dae.h
new file mode 100644
index 000000000..759eadb49
--- /dev/null
+++ b/src/libcharon/plugins/eap_radius/eap_radius_dae.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2012 Martin Willi
+ * Copyright (C) 2012 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 eap_radius_dae eap_radius_dae
+ * @{ @ingroup eap_radius
+ */
+
+#ifndef EAP_RADIUS_DAE_H_
+#define EAP_RADIUS_DAE_H_
+
+#include "eap_radius_accounting.h"
+
+typedef struct eap_radius_dae_t eap_radius_dae_t;
+
+/**
+ * Dynamic Authorization Extensions (RFC 5176) for EAP-RADIUS.
+ */
+struct eap_radius_dae_t {
+
+ /**
+ * Destroy a eap_radius_dae_t.
+ */
+ void (*destroy)(eap_radius_dae_t *this);
+};
+
+/**
+ * Create a eap_radius_dae instance.
+ */
+eap_radius_dae_t *eap_radius_dae_create(eap_radius_accounting_t *accounting);
+
+#endif /** EAP_RADIUS_DAE_H_ @}*/
diff --git a/src/libcharon/plugins/eap_radius/eap_radius_forward.c b/src/libcharon/plugins/eap_radius/eap_radius_forward.c
new file mode 100644
index 000000000..16701bb57
--- /dev/null
+++ b/src/libcharon/plugins/eap_radius/eap_radius_forward.c
@@ -0,0 +1,458 @@
+/*
+ * Copyright (C) 2012 Martin Willi
+ * Copyright (C) 2012 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 "eap_radius_forward.h"
+
+#include <daemon.h>
+#include <utils/linked_list.h>
+#include <utils/hashtable.h>
+#include <threading/mutex.h>
+
+typedef struct private_eap_radius_forward_t private_eap_radius_forward_t;
+
+/**
+ * Private data of an eap_radius_forward_t object.
+ */
+struct private_eap_radius_forward_t {
+
+ /**
+ * Public eap_radius_forward_t interface.
+ */
+ eap_radius_forward_t public;
+
+ /**
+ * List of attribute types to copy from IKE, as attr_t
+ */
+ linked_list_t *from_attr;
+
+ /**
+ * List of attribute types to copy to IKE, as attr_t
+ */
+ linked_list_t *to_attr;
+
+ /**
+ * Queued to forward from IKE, unique_id => linked_list_t of chunk_t
+ */
+ hashtable_t *from;
+
+ /**
+ * Queued to forward to IKE, unique_id => linked_list_t of chunk_t
+ */
+ hashtable_t *to;
+
+ /**
+ * Mutex to lock concurrent access to hashtables
+ */
+ mutex_t *mutex;
+};
+
+/**
+ * RADIUS attribute selector
+ */
+typedef struct {
+ /** vendor ID, 0 for standard attributes */
+ u_int32_t vendor;
+ /** attribute type */
+ u_int8_t type;
+} attr_t;
+
+/**
+ * Single instance of this
+ */
+static private_eap_radius_forward_t *singleton = NULL;
+
+/**
+ * Hashtable hash function
+ */
+static u_int hash(uintptr_t key)
+{
+ return key;
+}
+
+/**
+ * Hashtable equals function
+ */
+static bool equals(uintptr_t a, uintptr_t b)
+{
+ return a == b;
+}
+
+/**
+ * Free a queue entry
+ */
+static void free_attribute(chunk_t *chunk)
+{
+ free(chunk->ptr);
+ free(chunk);
+}
+
+/**
+ * Lookup/create an attribute queue from a table
+ */
+static linked_list_t *lookup_queue(private_eap_radius_forward_t *this,
+ hashtable_t *table)
+{
+ linked_list_t *queue = NULL;
+ ike_sa_t *ike_sa;
+ uintptr_t id;
+
+ ike_sa = charon->bus->get_sa(charon->bus);
+ if (ike_sa && ike_sa->supports_extension(ike_sa, EXT_STRONGSWAN))
+ {
+ id = ike_sa->get_unique_id(ike_sa);
+ this->mutex->lock(this->mutex);
+ queue = table->get(table, (void*)id);
+ if (!queue)
+ {
+ queue = linked_list_create();
+ table->put(table, (void*)id, queue);
+ }
+ this->mutex->unlock(this->mutex);
+ }
+ return queue;
+}
+
+/**
+ * Remove attribute queue from table
+ */
+static void remove_queue(private_eap_radius_forward_t *this,
+ hashtable_t *table, ike_sa_t *ike_sa)
+{
+ linked_list_t *queue;
+
+ this->mutex->lock(this->mutex);
+ queue = table->remove(table, (void*)(uintptr_t)ike_sa->get_unique_id(ike_sa));
+ this->mutex->unlock(this->mutex);
+ if (queue)
+ {
+ queue->destroy_function(queue, (void*)free_attribute);
+ }
+}
+
+/**
+ * Check if RADIUS attribute is contained in selector
+ */
+static bool is_attribute_selected(linked_list_t *selector,
+ radius_attribute_type_t type, chunk_t data)
+{
+ enumerator_t *enumerator;
+ u_int32_t vendor = 0;
+ attr_t *sel;
+ bool found = FALSE;
+
+ if (type == RAT_VENDOR_SPECIFIC)
+ {
+ if (data.len < 4)
+ {
+ return FALSE;
+ }
+ vendor = untoh32(data.ptr);
+ }
+ enumerator = selector->create_enumerator(selector);
+ while (!found && enumerator->enumerate(enumerator, &sel))
+ {
+ if (sel->vendor == vendor)
+ {
+ if (vendor)
+ {
+ if (sel->type == 0)
+ { /* any of that vendor is fine */
+ found = TRUE;
+ }
+ else if (data.len > 4 && data.ptr[4] == sel->type)
+ { /* vendor specific type field, as defined in RFC 2865 */
+ found = TRUE;
+ }
+ }
+ else
+ {
+ if (sel->type == type)
+ {
+ found = TRUE;
+ }
+ }
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ return found;
+}
+
+/**
+ * Copy RADIUS attributes from queue to a RADIUS message
+ */
+static void queue2radius(linked_list_t *queue, radius_message_t *message)
+{
+ chunk_t *data;
+
+ while (queue->remove_last(queue, (void**)&data) == SUCCESS)
+ {
+ if (data->len >= 2)
+ {
+ message->add(message, data->ptr[0], chunk_skip(*data, 2));
+ }
+ free_attribute(data);
+ }
+}
+
+/**
+ * Copy RADIUS attributes from a RADIUS message to the queue
+ */
+static void radius2queue(radius_message_t *message, linked_list_t *queue,
+ linked_list_t *selector)
+{
+ enumerator_t *enumerator;
+ int type;
+ chunk_t data, hdr, *ptr;
+
+ enumerator = message->create_enumerator(message);
+ while (enumerator->enumerate(enumerator, &type, &data))
+ {
+ if (is_attribute_selected(selector, type, data))
+ {
+ hdr = chunk_alloc(2);
+ hdr.ptr[0] = type;
+ hdr.ptr[1] = data.len + 2;
+
+ INIT(ptr);
+ *ptr = chunk_cat("mc", hdr, data);
+ queue->insert_last(queue, ptr);
+ }
+ }
+ enumerator->destroy(enumerator);
+}
+
+/**
+ * Copy RADIUS attribute nofifies from IKE message to queue
+ */
+static void ike2queue(message_t *message, linked_list_t *queue,
+ linked_list_t *selector)
+{
+ enumerator_t *enumerator;
+ payload_t *payload;
+ notify_payload_t *notify;
+ chunk_t data, *ptr;
+
+ enumerator = message->create_payload_enumerator(message);
+ while (enumerator->enumerate(enumerator, &payload))
+ {
+ if (payload->get_type(payload) == NOTIFY)
+ {
+ notify = (notify_payload_t*)payload;
+ if (notify->get_notify_type(notify) == RADIUS_ATTRIBUTE)
+ {
+ data = notify->get_notification_data(notify);
+ if (data.len >= 2 && is_attribute_selected(selector,
+ data.ptr[0], chunk_skip(data, 2)))
+ {
+ INIT(ptr);
+ *ptr = chunk_clone(data);
+ queue->insert_last(queue, ptr);
+ }
+ }
+ }
+ }
+ enumerator->destroy(enumerator);
+}
+
+/**
+ * Copy RADUIS attributes from queue to IKE message notifies
+ */
+static void queue2ike(linked_list_t *queue, message_t *message)
+{
+ chunk_t *data;
+
+ while (queue->remove_last(queue, (void**)&data) == SUCCESS)
+ {
+ message->add_notify(message, FALSE, RADIUS_ATTRIBUTE, *data);
+ free_attribute(data);
+ }
+}
+
+/**
+ * See header.
+ */
+void eap_radius_forward_from_ike(radius_message_t *request)
+{
+ private_eap_radius_forward_t *this = singleton;
+ linked_list_t *queue;
+
+ if (this)
+ {
+ queue = lookup_queue(this, this->from);
+ if (queue)
+ {
+ queue2radius(queue, request);
+ }
+ }
+}
+
+/**
+ * See header.
+ */
+void eap_radius_forward_to_ike(radius_message_t *response)
+{
+ private_eap_radius_forward_t *this = singleton;
+ linked_list_t *queue;
+
+ if (this)
+ {
+ queue = lookup_queue(this, this->to);
+ if (queue)
+ {
+ radius2queue(response, queue, this->to_attr);
+ }
+ }
+}
+
+METHOD(listener_t, message, bool,
+ private_eap_radius_forward_t *this,
+ ike_sa_t *ike_sa, message_t *message, bool incoming, bool plain)
+{
+ linked_list_t *queue;
+
+ if (plain && message->get_exchange_type(message) == IKE_AUTH)
+ {
+ if (incoming)
+ {
+ queue = lookup_queue(this, this->from);
+ if (queue)
+ {
+ ike2queue(message, queue, this->from_attr);
+ }
+ }
+ else
+ {
+ queue = lookup_queue(this, this->to);
+ if (queue)
+ {
+ queue2ike(queue, message);
+ }
+ }
+ }
+ return TRUE;
+}
+
+METHOD(listener_t, ike_updown, bool,
+ private_eap_radius_forward_t *this, ike_sa_t *ike_sa, bool up)
+{
+ /* up or down, we don't need the state anymore */
+ remove_queue(this, this->from, ike_sa);
+ remove_queue(this, this->to, ike_sa);
+ return TRUE;
+}
+
+/**
+ * Parse a selector string to a list of attr_t selectors
+ */
+static linked_list_t* parse_selector(char *selector)
+{
+ enumerator_t *enumerator;
+ linked_list_t *list;
+ char *token, *pos;
+
+ list = linked_list_create();
+ enumerator = enumerator_create_token(selector, ",", " ");
+ while (enumerator->enumerate(enumerator, &token))
+ {
+ int type, vendor = 0;
+ attr_t *attr;
+
+ pos = strchr(token, ':');
+ if (pos)
+ {
+ *(pos++) = 0;
+ vendor = atoi(token);
+ token = pos;
+ }
+ type = enum_from_name(radius_attribute_type_names, token);
+ if (type == -1)
+ {
+ type = atoi(token);
+ }
+ if (vendor == 0 && type == 0)
+ {
+ DBG1(DBG_CFG, "ignoring unknown RADIUS attribute type '%s'", token);
+ }
+ else
+ {
+ INIT(attr,
+ .type = type,
+ .vendor = vendor,
+ );
+ list->insert_last(list, attr);
+ if (!vendor)
+ {
+ DBG1(DBG_IKE, "forwarding RADIUS attribute %N",
+ radius_attribute_type_names, type);
+ }
+ else
+ {
+ DBG1(DBG_IKE, "forwarding RADIUS VSA %d-%d", vendor, type);
+ }
+ }
+ }
+ enumerator->destroy(enumerator);
+ return list;
+}
+
+METHOD(eap_radius_forward_t, destroy, void,
+ private_eap_radius_forward_t *this)
+{
+ this->from_attr->destroy_function(this->from_attr, free);
+ this->to_attr->destroy_function(this->to_attr, free);
+ this->from->destroy(this->from);
+ this->to->destroy(this->to);
+ this->mutex->destroy(this->mutex);
+ free(this);
+ singleton = NULL;
+}
+
+/**
+ * See header
+ */
+eap_radius_forward_t *eap_radius_forward_create()
+{
+ private_eap_radius_forward_t *this;
+
+ INIT(this,
+ .public = {
+ .listener = {
+ .message = _message,
+ .ike_updown = _ike_updown,
+ },
+ .destroy = _destroy,
+ },
+ .from_attr = parse_selector(lib->settings->get_str(lib->settings,
+ "charon.plugins.eap-radius.forward.ike_to_radius", "")),
+ .to_attr = parse_selector(lib->settings->get_str(lib->settings,
+ "charon.plugins.eap-radius.forward.radius_to_ike", "")),
+ .from = hashtable_create((hashtable_hash_t)hash,
+ (hashtable_equals_t)equals, 8),
+ .to = hashtable_create((hashtable_hash_t)hash,
+ (hashtable_equals_t)equals, 8),
+ .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
+ );
+
+ if (this->from_attr->get_count(this->from_attr) == 0 &&
+ this->to_attr->get_count(this->to_attr) == 0)
+ {
+ destroy(this);
+ return NULL;
+ }
+
+ singleton = this;
+ return &this->public;
+}
diff --git a/src/libcharon/plugins/eap_radius/eap_radius_forward.h b/src/libcharon/plugins/eap_radius/eap_radius_forward.h
new file mode 100644
index 000000000..2c1dbf7a8
--- /dev/null
+++ b/src/libcharon/plugins/eap_radius/eap_radius_forward.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2012 Martin Willi
+ * Copyright (C) 2012 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 eap_radius_forward eap_radius_forward
+ * @{ @ingroup eap_radius
+ */
+
+#ifndef EAP_RADIUS_FORWARD_H_
+#define EAP_RADIUS_FORWARD_H_
+
+#include <radius_message.h>
+
+#include <bus/listeners/listener.h>
+
+typedef struct eap_radius_forward_t eap_radius_forward_t;
+
+/**
+ * Forward RADIUS attributes in Notifies between client and AAA backend.
+ */
+struct eap_radius_forward_t {
+
+ /**
+ * Implements a listener.
+ */
+ listener_t listener;
+
+ /**
+ * Destroy a eap_radius_forward_t.
+ */
+ void (*destroy)(eap_radius_forward_t *this);
+};
+
+/**
+ * Create a eap_radius_forward instance.
+ */
+eap_radius_forward_t *eap_radius_forward_create();
+
+/**
+ * Forward RADIUS attributes from IKE notifies to a RADIUS request.
+ *
+ * @param request RADIUS request message to add attributes to
+ */
+void eap_radius_forward_from_ike(radius_message_t *request);
+
+/**
+ * Forward RADIUS attributes from a RADIUS response to IKE notifies.
+ *
+ * @param response RADIUS respose to read notifies from
+ */
+void eap_radius_forward_to_ike(radius_message_t *response);
+
+#endif /** EAP_RADIUS_FORWARD_H_ @}*/
diff --git a/src/libcharon/plugins/eap_radius/eap_radius_plugin.c b/src/libcharon/plugins/eap_radius/eap_radius_plugin.c
index 4119ec571..8ee0ab81a 100644
--- a/src/libcharon/plugins/eap_radius/eap_radius_plugin.c
+++ b/src/libcharon/plugins/eap_radius/eap_radius_plugin.c
@@ -16,16 +16,25 @@
#include "eap_radius_plugin.h"
#include "eap_radius.h"
-#include "radius_client.h"
-#include "radius_server.h"
+#include "eap_radius_accounting.h"
+#include "eap_radius_dae.h"
+#include "eap_radius_forward.h"
+
+#include <radius_client.h>
+#include <radius_config.h>
#include <daemon.h>
#include <threading/rwlock.h>
/**
- * Default RADIUS server port, when not configured
+ * Default RADIUS server port for authentication
+ */
+#define AUTH_PORT 1812
+
+/**
+ * Default RADIUS server port for accounting
*/
-#define RADIUS_PORT 1812
+#define ACCT_PORT 1813
typedef struct private_eap_radius_plugin_t private_eap_radius_plugin_t;
@@ -40,14 +49,29 @@ struct private_eap_radius_plugin_t {
eap_radius_plugin_t public;
/**
- * List of RADIUS servers
+ * List of RADIUS server configurations
*/
- linked_list_t *servers;
+ linked_list_t *configs;
/**
- * Lock for server list
+ * Lock for configs list
*/
rwlock_t *lock;
+
+ /**
+ * RADIUS sessions for accounting
+ */
+ eap_radius_accounting_t *accounting;
+
+ /**
+ * Dynamic authorization extensions
+ */
+ eap_radius_dae_t *dae;
+
+ /**
+ * RADIUS <-> IKE attribute forwarding
+ */
+ eap_radius_forward_t *forward;
};
/**
@@ -58,12 +82,12 @@ static private_eap_radius_plugin_t *instance = NULL;
/**
* Load RADIUS servers from configuration
*/
-static void load_servers(private_eap_radius_plugin_t *this)
+static void load_configs(private_eap_radius_plugin_t *this)
{
enumerator_t *enumerator;
- radius_server_t *server;
+ radius_config_t *config;
char *nas_identifier, *secret, *address, *section;
- int port, sockets, preference;
+ int auth_port, acct_port, sockets, preference;
address = lib->settings->get_str(lib->settings,
"charon.plugins.eap-radius.server", NULL);
@@ -78,18 +102,18 @@ static void load_servers(private_eap_radius_plugin_t *this)
}
nas_identifier = lib->settings->get_str(lib->settings,
"charon.plugins.eap-radius.nas_identifier", "strongSwan");
- port = lib->settings->get_int(lib->settings,
- "charon.plugins.eap-radius.port", RADIUS_PORT);
+ auth_port = lib->settings->get_int(lib->settings,
+ "charon.plugins.eap-radius.port", AUTH_PORT);
sockets = lib->settings->get_int(lib->settings,
"charon.plugins.eap-radius.sockets", 1);
- server = radius_server_create(address, address, port, nas_identifier,
- secret, sockets, 0);
- if (!server)
+ config = radius_config_create(address, address, auth_port, ACCT_PORT,
+ nas_identifier, secret, sockets, 0);
+ if (!config)
{
DBG1(DBG_CFG, "no RADUIS server defined");
return;
}
- this->servers->insert_last(this->servers, server);
+ this->configs->insert_last(this->configs, config);
return;
}
@@ -114,26 +138,32 @@ static void load_servers(private_eap_radius_plugin_t *this)
nas_identifier = lib->settings->get_str(lib->settings,
"charon.plugins.eap-radius.servers.%s.nas_identifier",
"strongSwan", section);
- port = lib->settings->get_int(lib->settings,
- "charon.plugins.eap-radius.servers.%s.port", RADIUS_PORT, section);
+ auth_port = lib->settings->get_int(lib->settings,
+ "charon.plugins.eap-radius.servers.%s.auth_port",
+ lib->settings->get_int(lib->settings,
+ "charon.plugins.eap-radius.servers.%s.port",
+ AUTH_PORT, section),
+ section);
+ acct_port = lib->settings->get_int(lib->settings,
+ "charon.plugins.eap-radius.servers.%s.acct_port", ACCT_PORT, section);
sockets = lib->settings->get_int(lib->settings,
"charon.plugins.eap-radius.servers.%s.sockets", 1, section);
preference = lib->settings->get_int(lib->settings,
"charon.plugins.eap-radius.servers.%s.preference", 0, section);
- server = radius_server_create(section, address, port, nas_identifier,
- secret, sockets, preference);
- if (!server)
+ config = radius_config_create(section, address, auth_port, acct_port,
+ nas_identifier, secret, sockets, preference);
+ if (!config)
{
DBG1(DBG_CFG, "loading RADIUS server '%s' failed, skipped", section);
continue;
}
- this->servers->insert_last(this->servers, server);
+ this->configs->insert_last(this->configs, config);
}
enumerator->destroy(enumerator);
DBG1(DBG_CFG, "loaded %d RADIUS server configuration%s",
- this->servers->get_count(this->servers),
- this->servers->get_count(this->servers) == 1 ? "" : "s");
+ this->configs->get_count(this->configs),
+ this->configs->get_count(this->configs) == 1 ? "" : "s");
}
METHOD(plugin_t, get_name, char*,
@@ -160,10 +190,10 @@ METHOD(plugin_t, reload, bool,
private_eap_radius_plugin_t *this)
{
this->lock->write_lock(this->lock);
- this->servers->destroy_offset(this->servers,
- offsetof(radius_server_t, destroy));
- this->servers = linked_list_create();
- load_servers(this);
+ this->configs->destroy_offset(this->configs,
+ offsetof(radius_config_t, destroy));
+ this->configs = linked_list_create();
+ load_configs(this);
this->lock->unlock(this->lock);
return TRUE;
}
@@ -171,9 +201,17 @@ METHOD(plugin_t, reload, bool,
METHOD(plugin_t, destroy, void,
private_eap_radius_plugin_t *this)
{
- this->servers->destroy_offset(this->servers,
- offsetof(radius_server_t, destroy));
+ if (this->forward)
+ {
+ charon->bus->remove_listener(charon->bus, &this->forward->listener);
+ this->forward->destroy(this->forward);
+ }
+ DESTROY_IF(this->dae);
+ this->configs->destroy_offset(this->configs,
+ offsetof(radius_config_t, destroy));
this->lock->destroy(this->lock);
+ charon->bus->remove_listener(charon->bus, &this->accounting->listener);
+ this->accounting->destroy(this->accounting);
free(this);
instance = NULL;
}
@@ -194,28 +232,73 @@ plugin_t *eap_radius_plugin_create()
.destroy = _destroy,
},
},
- .servers = linked_list_create(),
+ .configs = linked_list_create(),
.lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
+ .accounting = eap_radius_accounting_create(),
+ .forward = eap_radius_forward_create(),
);
- load_servers(this);
+ load_configs(this);
instance = this;
+ if (lib->settings->get_bool(lib->settings,
+ "charon.plugins.eap-radius.accounting", FALSE))
+ {
+ charon->bus->add_listener(charon->bus, &this->accounting->listener);
+ }
+ if (lib->settings->get_bool(lib->settings,
+ "charon.plugins.eap-radius.dae.enable", FALSE))
+ {
+ this->dae = eap_radius_dae_create(this->accounting);
+ }
+ if (this->forward)
+ {
+ charon->bus->add_listener(charon->bus, &this->forward->listener);
+ }
+
return &this->public.plugin;
}
/**
* See header
*/
-enumerator_t *eap_radius_create_server_enumerator()
+radius_client_t *eap_radius_create_client()
{
if (instance)
{
+ enumerator_t *enumerator;
+ radius_config_t *config, *selected = NULL;
+ int current, best = -1;
+
instance->lock->read_lock(instance->lock);
- return enumerator_create_cleaner(
- instance->servers->create_enumerator(instance->servers),
- (void*)instance->lock->unlock, instance->lock);
+ enumerator = instance->configs->create_enumerator(instance->configs);
+ while (enumerator->enumerate(enumerator, &config))
+ {
+ current = config->get_preference(config);
+ if (current > best ||
+ /* for two with equal preference, 50-50 chance */
+ (current == best && random() % 2 == 0))
+ {
+ DBG2(DBG_CFG, "RADIUS server '%s' is candidate: %d",
+ config->get_name(config), current);
+ best = current;
+ DESTROY_IF(selected);
+ selected = config->get_ref(config);
+ }
+ else
+ {
+ DBG2(DBG_CFG, "RADIUS server '%s' skipped: %d",
+ config->get_name(config), current);
+ }
+ }
+ enumerator->destroy(enumerator);
+ instance->lock->unlock(instance->lock);
+
+ if (selected)
+ {
+ return radius_client_create(selected);
+ }
}
- return enumerator_create_empty();
+ return NULL;
}
diff --git a/src/libcharon/plugins/eap_radius/eap_radius_plugin.h b/src/libcharon/plugins/eap_radius/eap_radius_plugin.h
index cb724364a..1570bd566 100644
--- a/src/libcharon/plugins/eap_radius/eap_radius_plugin.h
+++ b/src/libcharon/plugins/eap_radius/eap_radius_plugin.h
@@ -25,7 +25,8 @@
#define EAP_RADIUS_PLUGIN_H_
#include <plugins/plugin.h>
-#include <utils/enumerator.h>
+
+#include <radius_client.h>
typedef struct eap_radius_plugin_t eap_radius_plugin_t;
@@ -44,10 +45,10 @@ struct eap_radius_plugin_t {
};
/**
- * Create an enumerator over all loaded RADIUS servers.
+ * Get a RADIUS client instance to connect to servers.
*
- * @return enumerator over radius_server_t
+ * @return RADIUS client
*/
-enumerator_t *eap_radius_create_server_enumerator();
+radius_client_t *eap_radius_create_client();
#endif /** EAP_RADIUS_PLUGIN_H_ @}*/
diff --git a/src/libcharon/plugins/eap_tls/eap_tls.c b/src/libcharon/plugins/eap_tls/eap_tls.c
index 39e1a60d9..dc0289ba2 100644
--- a/src/libcharon/plugins/eap_tls/eap_tls.c
+++ b/src/libcharon/plugins/eap_tls/eap_tls.c
@@ -39,7 +39,7 @@ struct private_eap_tls_t {
};
/** Maximum number of EAP-TLS messages/fragments allowed */
-#define MAX_MESSAGE_COUNT 32
+#define MAX_MESSAGE_COUNT 32
/** Default size of a EAP-TLS fragment */
#define MAX_FRAGMENT_LEN 1024
@@ -148,8 +148,8 @@ static eap_tls_t *eap_tls_create(identification_t *server,
max_msg_count = lib->settings->get_int(lib->settings,
"charon.plugins.eap-tls.max_message_count", MAX_MESSAGE_COUNT);
include_length = lib->settings->get_bool(lib->settings,
- "charon.plugins.eap-tls.include_length", TRUE);
- tls = tls_create(is_server, server, peer, TLS_PURPOSE_EAP_TLS, NULL);
+ "charon.plugins.eap-tls.include_length", TRUE);
+ tls = tls_create(is_server, server, peer, TLS_PURPOSE_EAP_TLS, NULL, NULL);
this->tls_eap = tls_eap_create(EAP_TLS, tls, frag_size, max_msg_count,
include_length);
if (!this->tls_eap)
diff --git a/src/libcharon/plugins/eap_ttls/Makefile.am b/src/libcharon/plugins/eap_ttls/Makefile.am
index 94ce5cc1e..8cc82cc2e 100644
--- a/src/libcharon/plugins/eap_ttls/Makefile.am
+++ b/src/libcharon/plugins/eap_ttls/Makefile.am
@@ -1,6 +1,7 @@
INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \
- -I$(top_srcdir)/src/libcharon -I$(top_srcdir)/src/libtls
+ -I$(top_srcdir)/src/libcharon -I$(top_srcdir)/src/libtls \
+ -I$(top_srcdir)/src/libradius
AM_CFLAGS = -rdynamic
diff --git a/src/libcharon/plugins/eap_ttls/eap_ttls.c b/src/libcharon/plugins/eap_ttls/eap_ttls.c
index 7193bc9f0..ace62f6b9 100644
--- a/src/libcharon/plugins/eap_ttls/eap_ttls.c
+++ b/src/libcharon/plugins/eap_ttls/eap_ttls.c
@@ -156,7 +156,8 @@ static eap_ttls_t *eap_ttls_create(identification_t *server,
"charon.plugins.eap-ttls.max_message_count", MAX_MESSAGE_COUNT);
include_length = lib->settings->get_bool(lib->settings,
"charon.plugins.eap-ttls.include_length", TRUE);
- tls = tls_create(is_server, server, peer, TLS_PURPOSE_EAP_TTLS, application);
+ tls = tls_create(is_server, server, peer, TLS_PURPOSE_EAP_TTLS,
+ application, NULL);
this->tls_eap = tls_eap_create(EAP_TTLS, tls, frag_size, max_msg_count,
include_length);
if (!this->tls_eap)
diff --git a/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c b/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c
index e75bd2976..767111b3e 100644
--- a/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c
+++ b/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c
@@ -18,7 +18,7 @@
#include <debug.h>
#include <daemon.h>
-
+#include <radius_message.h>
#include <sa/eap/eap_method.h>
typedef struct private_eap_ttls_peer_t private_eap_ttls_peer_t;
@@ -64,8 +64,6 @@ struct private_eap_ttls_peer_t {
eap_ttls_avp_t *avp;
};
-#define MAX_RADIUS_ATTRIBUTE_SIZE 253
-
METHOD(tls_application_t, process, status_t,
private_eap_ttls_peer_t *this, bio_reader_t *reader)
{
diff --git a/src/libcharon/plugins/farp/farp_listener.c b/src/libcharon/plugins/farp/farp_listener.c
index 30709c9eb..d1df4cc27 100644
--- a/src/libcharon/plugins/farp/farp_listener.c
+++ b/src/libcharon/plugins/farp/farp_listener.c
@@ -15,7 +15,7 @@
#include "farp_listener.h"
-#include <utils/hashtable.h>
+#include <utils/linked_list.h>
#include <threading/rwlock.h>
typedef struct private_farp_listener_t private_farp_listener_t;
@@ -31,9 +31,9 @@ struct private_farp_listener_t {
farp_listener_t public;
/**
- * Hashtable with active virtual IPs
+ * List with entry_t
*/
- hashtable_t *ips;
+ linked_list_t *entries;
/**
* RWlock for IP list
@@ -42,88 +42,99 @@ struct private_farp_listener_t {
};
/**
- * Hashtable hash function
+ * Traffic selector cache entry
*/
-static u_int hash(host_t *key)
+typedef struct {
+ /** list of local selectors */
+ linked_list_t *local;
+ /** list of remote selectors */
+ linked_list_t *remote;
+ /** reqid of CHILD_SA */
+ u_int32_t reqid;
+} entry_t;
+
+METHOD(listener_t, child_updown, bool,
+ private_farp_listener_t *this, ike_sa_t *ike_sa, child_sa_t *child_sa,
+ bool up)
{
- return chunk_hash(key->get_address(key));
-}
-
-/**
- * Hashtable equals function
- */
-static bool equals(host_t *a, host_t *b)
-{
- return a->ip_equals(a, b);
-}
+ enumerator_t *enumerator;
+ entry_t *entry;
-METHOD(listener_t, ike_updown, bool,
- private_farp_listener_t *this, ike_sa_t *ike_sa, bool up)
-{
- if (!up)
+ if (up)
{
- host_t *ip;
-
- ip = ike_sa->get_virtual_ip(ike_sa, FALSE);
- if (ip)
- {
- this->lock->write_lock(this->lock);
- ip = this->ips->remove(this->ips, ip);
- this->lock->unlock(this->lock);
- DESTROY_IF(ip);
- }
+ INIT(entry,
+ .local = child_sa->get_traffic_selectors(child_sa, TRUE),
+ .remote = child_sa->get_traffic_selectors(child_sa, FALSE),
+ .reqid = child_sa->get_reqid(child_sa),
+ );
+ entry->local = entry->local->clone_offset(entry->local,
+ offsetof(traffic_selector_t, clone));
+ entry->remote = entry->remote->clone_offset(entry->remote,
+ offsetof(traffic_selector_t, clone));
+
+ this->lock->write_lock(this->lock);
+ this->entries->insert_last(this->entries, entry);
+ this->lock->unlock(this->lock);
}
- return TRUE;
-}
-
-METHOD(listener_t, message_hook, bool,
- private_farp_listener_t *this, ike_sa_t *ike_sa,
- message_t *message, bool incoming, bool plain)
-{
- if (plain && ike_sa->get_state(ike_sa) == IKE_ESTABLISHED &&
- message->get_exchange_type(message) == IKE_AUTH &&
- !message->get_request(message))
+ else
{
- host_t *ip;
-
- ip = ike_sa->get_virtual_ip(ike_sa, FALSE);
- if (ip)
+ this->lock->write_lock(this->lock);
+ enumerator = this->entries->create_enumerator(this->entries);
+ while (enumerator->enumerate(enumerator, &entry))
{
- ip = ip->clone(ip);
- this->lock->write_lock(this->lock);
- ip = this->ips->put(this->ips, ip, ip);
- this->lock->unlock(this->lock);
- DESTROY_IF(ip);
+ if (entry->reqid == child_sa->get_reqid(child_sa))
+ {
+ this->entries->remove_at(this->entries, enumerator);
+ entry->local->destroy_offset(entry->local,
+ offsetof(traffic_selector_t, destroy));
+ entry->remote->destroy_offset(entry->remote,
+ offsetof(traffic_selector_t, destroy));
+ free(entry);
+ }
}
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
}
return TRUE;
}
-METHOD(farp_listener_t, is_active, bool,
- private_farp_listener_t *this, host_t *ip)
+METHOD(farp_listener_t, has_tunnel, bool,
+ private_farp_listener_t *this, host_t *local, host_t *remote)
{
- bool active;
+ enumerator_t *entries, *locals, *remotes;
+ traffic_selector_t *ts;
+ bool found = FALSE;
+ entry_t *entry;
this->lock->read_lock(this->lock);
- active = this->ips->get(this->ips, ip) != NULL;
+ entries = this->entries->create_enumerator(this->entries);
+ while (!found && entries->enumerate(entries, &entry))
+ {
+ remotes = entry->remote->create_enumerator(entry->remote);
+ while (!found && remotes->enumerate(remotes, &ts))
+ {
+ if (ts->includes(ts, remote))
+ {
+ locals = entry->local->create_enumerator(entry->local);
+ while (!found && locals->enumerate(locals, &ts))
+ {
+ found = ts->includes(ts, local);
+ }
+ locals->destroy(locals);
+ }
+ }
+ remotes->destroy(remotes);
+ }
+ entries->destroy(entries);
this->lock->unlock(this->lock);
- return active;
+
+ return found;
}
METHOD(farp_listener_t, destroy, void,
private_farp_listener_t *this)
{
- enumerator_t *enumerator;
- host_t *key, *value;
-
- enumerator = this->ips->create_enumerator(this->ips);
- while (enumerator->enumerate(enumerator, &key, &value))
- {
- value->destroy(value);
- }
- enumerator->destroy(enumerator);
- this->ips->destroy(this->ips);
-
+ this->entries->destroy(this->entries);
this->lock->destroy(this->lock);
free(this);
}
@@ -138,14 +149,12 @@ farp_listener_t *farp_listener_create()
INIT(this,
.public = {
.listener = {
- .ike_updown = _ike_updown,
- .message = _message_hook,
+ .child_updown = _child_updown,
},
- .is_active = _is_active,
+ .has_tunnel = _has_tunnel,
.destroy = _destroy,
},
- .ips = hashtable_create((hashtable_hash_t)hash,
- (hashtable_equals_t)equals, 8),
+ .entries = linked_list_create(),
.lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
);
diff --git a/src/libcharon/plugins/farp/farp_listener.h b/src/libcharon/plugins/farp/farp_listener.h
index bd96d7a1c..3155f60e2 100644
--- a/src/libcharon/plugins/farp/farp_listener.h
+++ b/src/libcharon/plugins/farp/farp_listener.h
@@ -37,12 +37,13 @@ struct farp_listener_t {
listener_t listener;
/**
- * Check if a given IP is currently used as virtual IP by a peer.
+ * Check if we have a tunnel between two IP addresses.
*
- * @param ip IP to check
- * @return TRUE if IP is an active virtual IP
+ * @param local local IP
+ * @param remote remote IP
+ * @return TRUE if a tunnel is active
*/
- bool (*is_active)(farp_listener_t *this, host_t *ip);
+ bool (*has_tunnel)(farp_listener_t *this, host_t *local, host_t *remote);
/**
* Destroy a farp_listener_t.
diff --git a/src/libcharon/plugins/farp/farp_spoofer.c b/src/libcharon/plugins/farp/farp_spoofer.c
index 7a8ca850b..587a3a74e 100644
--- a/src/libcharon/plugins/farp/farp_spoofer.c
+++ b/src/libcharon/plugins/farp/farp_spoofer.c
@@ -108,7 +108,7 @@ static job_requeue_t receive_arp(private_farp_spoofer_t *this)
arp_t arp;
int oldstate;
ssize_t len;
- host_t *ip;
+ host_t *local, *remote;
oldstate = thread_cancelability(TRUE);
len = recvfrom(this->skt, &arp, sizeof(arp), 0,
@@ -117,16 +117,16 @@ static job_requeue_t receive_arp(private_farp_spoofer_t *this)
if (len == sizeof(arp))
{
- ip = host_create_from_chunk(AF_INET,
+ local = host_create_from_chunk(AF_INET,
+ chunk_create((char*)&arp.sender_ip, 4), 0);
+ remote = host_create_from_chunk(AF_INET,
chunk_create((char*)&arp.target_ip, 4), 0);
- if (ip)
+ if (this->listener->has_tunnel(this->listener, local, remote))
{
- if (this->listener->is_active(this->listener, ip))
- {
- send_arp(this, &arp, &addr);
- }
- ip->destroy(ip);
+ send_arp(this, &arp, &addr);
}
+ local->destroy(local);
+ remote->destroy(remote);
}
return JOB_REQUEUE_DIRECT;
diff --git a/src/libcharon/plugins/ha/ha_dispatcher.c b/src/libcharon/plugins/ha/ha_dispatcher.c
index 328b923b0..de5253b37 100644
--- a/src/libcharon/plugins/ha/ha_dispatcher.c
+++ b/src/libcharon/plugins/ha/ha_dispatcher.c
@@ -315,7 +315,7 @@ static void process_ike_update(private_ha_dispatcher_t *this,
ike_sa_t *ike_sa = NULL;
peer_cfg_t *peer_cfg = NULL;
auth_cfg_t *auth;
- bool received_vip = FALSE;
+ bool received_vip = FALSE, first_peer_addr = TRUE;
enumerator = message->create_attribute_enumerator(message);
while (enumerator->enumerate(enumerator, &attribute, &value))
@@ -355,9 +355,13 @@ static void process_ike_update(private_ha_dispatcher_t *this,
ike_sa->set_virtual_ip(ike_sa, FALSE, value.host);
received_vip = TRUE;
break;
- case HA_ADDITIONAL_ADDR:
- ike_sa->add_additional_address(ike_sa,
- value.host->clone(value.host));
+ case HA_PEER_ADDR:
+ if (first_peer_addr)
+ {
+ ike_sa->clear_peer_addresses(ike_sa);
+ first_peer_addr = FALSE;
+ }
+ ike_sa->add_peer_address(ike_sa, value.host->clone(value.host));
break;
case HA_CONFIG_NAME:
peer_cfg = charon->backends->get_peer_cfg_by_name(
diff --git a/src/libcharon/plugins/ha/ha_ike.c b/src/libcharon/plugins/ha/ha_ike.c
index c8ad0f845..2819b9dd5 100644
--- a/src/libcharon/plugins/ha/ha_ike.c
+++ b/src/libcharon/plugins/ha/ha_ike.c
@@ -205,10 +205,10 @@ METHOD(listener_t, ike_updown, bool,
m->add_attribute(m, HA_CONDITIONS, condition);
m->add_attribute(m, HA_EXTENSIONS, extension);
m->add_attribute(m, HA_CONFIG_NAME, peer_cfg->get_name(peer_cfg));
- enumerator = ike_sa->create_additional_address_enumerator(ike_sa);
+ enumerator = ike_sa->create_peer_address_enumerator(ike_sa);
while (enumerator->enumerate(enumerator, (void**)&addr))
{
- m->add_attribute(m, HA_ADDITIONAL_ADDR, addr);
+ m->add_attribute(m, HA_PEER_ADDR, addr);
}
enumerator->destroy(enumerator);
}
diff --git a/src/libcharon/plugins/ha/ha_kernel.c b/src/libcharon/plugins/ha/ha_kernel.c
index 07a201557..2377a2630 100644
--- a/src/libcharon/plugins/ha/ha_kernel.c
+++ b/src/libcharon/plugins/ha/ha_kernel.c
@@ -274,11 +274,14 @@ METHOD(ha_kernel_t, activate, void,
char *file;
enumerator = enumerator_create_directory(CLUSTERIP_DIR);
- while (enumerator->enumerate(enumerator, NULL, &file, NULL))
+ if (enumerator)
{
- enable_disable(this, segment, file, TRUE);
+ while (enumerator->enumerate(enumerator, NULL, &file, NULL))
+ {
+ enable_disable(this, segment, file, TRUE);
+ }
+ enumerator->destroy(enumerator);
}
- enumerator->destroy(enumerator);
}
METHOD(ha_kernel_t, deactivate, void,
@@ -288,11 +291,14 @@ METHOD(ha_kernel_t, deactivate, void,
char *file;
enumerator = enumerator_create_directory(CLUSTERIP_DIR);
- while (enumerator->enumerate(enumerator, NULL, &file, NULL))
+ if (enumerator)
{
- enable_disable(this, segment, file, FALSE);
+ while (enumerator->enumerate(enumerator, NULL, &file, NULL))
+ {
+ enable_disable(this, segment, file, FALSE);
+ }
+ enumerator->destroy(enumerator);
}
- enumerator->destroy(enumerator);
}
/**
@@ -306,23 +312,26 @@ static void disable_all(private_ha_kernel_t *this)
int i;
enumerator = enumerator_create_directory(CLUSTERIP_DIR);
- while (enumerator->enumerate(enumerator, NULL, &file, NULL))
+ if (enumerator)
{
- if (chown(file, charon->uid, charon->gid) != 0)
+ while (enumerator->enumerate(enumerator, NULL, &file, NULL))
{
- DBG1(DBG_CFG, "changing ClusterIP permissions failed: %s",
- strerror(errno));
- }
- active = get_active(this, file);
- for (i = 1; i <= this->count; i++)
- {
- if (active & SEGMENTS_BIT(i))
+ if (chown(file, charon->uid, charon->gid) != 0)
+ {
+ DBG1(DBG_CFG, "changing ClusterIP permissions failed: %s",
+ strerror(errno));
+ }
+ active = get_active(this, file);
+ for (i = 1; i <= this->count; i++)
{
- enable_disable(this, i, file, FALSE);
+ if (active & SEGMENTS_BIT(i))
+ {
+ enable_disable(this, i, file, FALSE);
+ }
}
}
+ enumerator->destroy(enumerator);
}
- enumerator->destroy(enumerator);
}
METHOD(ha_kernel_t, destroy, void,
diff --git a/src/libcharon/plugins/ha/ha_message.c b/src/libcharon/plugins/ha/ha_message.c
index 52317e532..6b00ed83f 100644
--- a/src/libcharon/plugins/ha/ha_message.c
+++ b/src/libcharon/plugins/ha/ha_message.c
@@ -187,7 +187,7 @@ METHOD(ha_message_t, add_attribute, void,
case HA_REMOTE_ADDR:
case HA_LOCAL_VIP:
case HA_REMOTE_VIP:
- case HA_ADDITIONAL_ADDR:
+ case HA_PEER_ADDR:
{
host_encoding_t *enc;
host_t *host;
@@ -395,7 +395,7 @@ METHOD(enumerator_t, attribute_enumerate, bool,
case HA_REMOTE_ADDR:
case HA_LOCAL_VIP:
case HA_REMOTE_VIP:
- case HA_ADDITIONAL_ADDR:
+ case HA_PEER_ADDR:
{
host_encoding_t *enc;
diff --git a/src/libcharon/plugins/ha/ha_message.h b/src/libcharon/plugins/ha/ha_message.h
index 22a5bd46a..8cd30f711 100644
--- a/src/libcharon/plugins/ha/ha_message.h
+++ b/src/libcharon/plugins/ha/ha_message.h
@@ -100,8 +100,8 @@ enum ha_message_attribute_t {
HA_LOCAL_VIP,
/** host_t*, remote virtual IP */
HA_REMOTE_VIP,
- /** host_t*, additional MOBIKE peer address */
- HA_ADDITIONAL_ADDR,
+ /** host_t*, known peer addresses (used for MOBIKE) */
+ HA_PEER_ADDR,
/** u_int8_t, initiator of an exchange, TRUE for local */
HA_INITIATOR,
/** chunk_t, initiators nonce */
diff --git a/src/libcharon/plugins/ha/ha_segments.h b/src/libcharon/plugins/ha/ha_segments.h
index eb9e5c1d5..76da38082 100644
--- a/src/libcharon/plugins/ha/ha_segments.h
+++ b/src/libcharon/plugins/ha/ha_segments.h
@@ -55,7 +55,7 @@ struct ha_segments_t {
* Activate a set of IKE_SAs identified by a segment.
*
* @param segment numerical segment to takeover, 0 for all
- * @param notify wheter to notify other nodes about activation
+ * @param notify whether to notify other nodes about activation
*/
void (*activate)(ha_segments_t *this, u_int segment, bool notify);
@@ -63,7 +63,7 @@ struct ha_segments_t {
* Deactivate a set of IKE_SAs identified by a segment.
*
* @param segment numerical segment to takeover, 0 for all
- * @param notify wheter to notify other nodes about deactivation
+ * @param notify whether to notify other nodes about deactivation
*/
void (*deactivate)(ha_segments_t *this, u_int segment, bool notify);
diff --git a/src/libcharon/plugins/radattr/Makefile.am b/src/libcharon/plugins/radattr/Makefile.am
new file mode 100644
index 000000000..0ea8df5d1
--- /dev/null
+++ b/src/libcharon/plugins/radattr/Makefile.am
@@ -0,0 +1,17 @@
+
+INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \
+ -I$(top_srcdir)/src/libcharon -I$(top_srcdir)/src/libradius
+
+AM_CFLAGS = -rdynamic
+
+if MONOLITHIC
+noinst_LTLIBRARIES = libstrongswan-radattr.la
+else
+libstrongswan_radattr_la_LIBADD = $(top_builddir)/src/libradius/libradius.la
+plugin_LTLIBRARIES = libstrongswan-radattr.la
+endif
+
+libstrongswan_radattr_la_SOURCES = radattr_plugin.h radattr_plugin.c \
+ radattr_listener.h radattr_listener.c
+
+libstrongswan_radattr_la_LDFLAGS = -module -avoid-version
diff --git a/src/libcharon/plugins/radattr/radattr_listener.c b/src/libcharon/plugins/radattr/radattr_listener.c
new file mode 100644
index 000000000..88ab60582
--- /dev/null
+++ b/src/libcharon/plugins/radattr/radattr_listener.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2012 Martin Willi
+ * Copyright (C) 2012 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 "radattr_listener.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <errno.h>
+
+#include <daemon.h>
+
+#include <radius_message.h>
+
+/**
+ * Maximum size of an attribute to add
+ */
+#define MAX_ATTR_SIZE 1024
+
+typedef struct private_radattr_listener_t private_radattr_listener_t;
+
+/**
+ * Private data of an radattr_listener_t object.
+ */
+struct private_radattr_listener_t {
+
+ /**
+ * Public radattr_listener_t interface.
+ */
+ radattr_listener_t public;
+
+ /**
+ * Directory to look for attribute files
+ */
+ char *dir;
+
+ /**
+ * IKE_AUTH message ID to attribute
+ */
+ int mid;
+};
+
+/**
+ * Print RADIUS attributes found in IKE message notifies
+ */
+static void print_radius_attributes(private_radattr_listener_t *this,
+ message_t *message)
+{
+ radius_attribute_type_t type;
+ enumerator_t *enumerator;
+ notify_payload_t *notify;
+ payload_t *payload;
+ chunk_t data;
+
+ enumerator = message->create_payload_enumerator(message);
+ while (enumerator->enumerate(enumerator, &payload))
+ {
+ if (payload->get_type(payload) == NOTIFY)
+ {
+ notify = (notify_payload_t*)payload;
+ if (notify->get_notify_type(notify) == RADIUS_ATTRIBUTE)
+ {
+ data = notify->get_notification_data(notify);
+ if (data.len >= 2)
+ {
+ type = data.ptr[0];
+ data = chunk_skip(data, 2);
+ if (chunk_printable(data, NULL, 0))
+ {
+ DBG1(DBG_IKE, "received RADIUS %N: %.*s",
+ radius_attribute_type_names, type,
+ (int)data.len, data.ptr);
+ }
+ else
+ {
+ DBG1(DBG_IKE, "received RADIUS %N: %#B",
+ radius_attribute_type_names, type, &data);
+
+ }
+ }
+ }
+ }
+ }
+ enumerator->destroy(enumerator);
+}
+
+/**
+ * Add a RADIUS attribute from a client-ID specific file to an IKE message
+ */
+static void add_radius_attribute(private_radattr_listener_t *this,
+ ike_sa_t *ike_sa, message_t *message)
+{
+ if (this->dir &&
+ (this->mid == -1 || message->get_message_id(message) == this->mid))
+ {
+ identification_t *id;
+ auth_cfg_t *auth;
+ char path[PATH_MAX];
+ chunk_t data;
+ struct stat sb;
+ void *addr;
+ int fd;
+
+ auth = ike_sa->get_auth_cfg(ike_sa, TRUE);
+ id = auth->get(auth, AUTH_RULE_EAP_IDENTITY);
+ if (!id)
+ {
+ id = ike_sa->get_my_id(ike_sa);
+ }
+
+ snprintf(path, sizeof(path), "%s/%Y", this->dir, id);
+ fd = open(path, O_RDONLY);
+ if (fd != -1)
+ {
+ if (fstat(fd, &sb) != -1)
+ {
+ if (sb.st_size <= MAX_ATTR_SIZE)
+ {
+ addr = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (addr != MAP_FAILED)
+ {
+ data = chunk_create(addr, sb.st_size);
+ if (data.len >= 2)
+ {
+ DBG1(DBG_CFG, "adding RADIUS %N attribute",
+ radius_attribute_type_names, data.ptr[0]);
+ message->add_notify(message, FALSE,
+ RADIUS_ATTRIBUTE, data);
+ }
+ munmap(addr, sb.st_size);
+ }
+ else
+ {
+ DBG1(DBG_CFG, "mapping RADIUS attribute '%s' failed: %s",
+ path, strerror(errno));
+ }
+ }
+ else
+ {
+ DBG1(DBG_CFG, "RADIUS attribute '%s' exceeds size limit",
+ path);
+ }
+ }
+ else
+ {
+ DBG1(DBG_CFG, "fstat RADIUS attribute '%s' failed: %s",
+ path, strerror(errno));
+ }
+ close(fd);
+ }
+ else
+ {
+ DBG1(DBG_CFG, "reading RADIUS attribute '%s' failed: %s",
+ path, strerror(errno));
+ }
+ }
+}
+
+METHOD(listener_t, message, bool,
+ private_radattr_listener_t *this,
+ ike_sa_t *ike_sa, message_t *message, bool incoming, bool plain)
+{
+ if (plain && ike_sa->supports_extension(ike_sa, EXT_STRONGSWAN) &&
+ message->get_exchange_type(message) == IKE_AUTH &&
+ message->get_payload(message, EXTENSIBLE_AUTHENTICATION))
+ {
+ if (incoming)
+ {
+ print_radius_attributes(this, message);
+ }
+ else
+ {
+ add_radius_attribute(this, ike_sa, message);
+ }
+ }
+ return TRUE;
+}
+
+
+METHOD(radattr_listener_t, destroy, void,
+ private_radattr_listener_t *this)
+{
+ free(this);
+}
+
+/**
+ * See header
+ */
+radattr_listener_t *radattr_listener_create()
+{
+ private_radattr_listener_t *this;
+
+ INIT(this,
+ .public = {
+ .listener = {
+ .message = _message,
+ },
+ .destroy = _destroy,
+ },
+ .dir = lib->settings->get_str(lib->settings,
+ "charon.plugins.radattr.dir", NULL),
+ .mid = lib->settings->get_int(lib->settings,
+ "charon.plugins.radattr.message_id", -1),
+ );
+
+ return &this->public;
+}
diff --git a/src/libcharon/plugins/radattr/radattr_listener.h b/src/libcharon/plugins/radattr/radattr_listener.h
new file mode 100644
index 000000000..9a14827fc
--- /dev/null
+++ b/src/libcharon/plugins/radattr/radattr_listener.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2012 Martin Willi
+ * Copyright (C) 2012 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 radattr_listener radattr_listener
+ * @{ @ingroup
+ */
+
+#ifndef RADATTR_LISTENER_H_
+#define RADATTR_LISTENER_H_
+
+#include <bus/listeners/listener.h>
+
+typedef struct radattr_listener_t radattr_listener_t;
+
+/**
+ * Output received RADIUS attributes, inject custom attributes.
+ */
+struct radattr_listener_t {
+
+ /**
+ * Implements a listener.
+ */
+ listener_t listener;
+
+ /**
+ * Destroy a radattr_listener_t.
+ */
+ void (*destroy)(radattr_listener_t *this);
+};
+
+/**
+ * Create a radattr_listener instance.
+ */
+radattr_listener_t *radattr_listener_create();
+
+#endif /** RADATTR_LISTENER_H_ @}*/
diff --git a/src/libcharon/plugins/radattr/radattr_plugin.c b/src/libcharon/plugins/radattr/radattr_plugin.c
new file mode 100644
index 000000000..85ea326ac
--- /dev/null
+++ b/src/libcharon/plugins/radattr/radattr_plugin.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 Martin Willi
+ * Copyright (C) 2012 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 "radattr_plugin.h"
+
+#include "radattr_listener.h"
+
+#include <daemon.h>
+
+typedef struct private_radattr_plugin_t private_radattr_plugin_t;
+
+/**
+ * private data of radattr plugin
+ */
+struct private_radattr_plugin_t {
+
+ /**
+ * implements plugin interface
+ */
+ radattr_plugin_t public;
+
+ /**
+ * Listener acting on messages
+ */
+ radattr_listener_t *listener;
+};
+
+METHOD(plugin_t, get_name, char*,
+ private_radattr_plugin_t *this)
+{
+ return "radattr";
+}
+
+METHOD(plugin_t, destroy, void,
+ private_radattr_plugin_t *this)
+{
+ charon->bus->remove_listener(charon->bus, &this->listener->listener);
+ this->listener->destroy(this->listener);
+ free(this);
+}
+
+/**
+ * Plugin constructor
+ */
+plugin_t *radattr_plugin_create()
+{
+ private_radattr_plugin_t *this;
+
+ INIT(this,
+ .public = {
+ .plugin = {
+ .get_name = _get_name,
+ .reload = (void*)return_false,
+ .destroy = _destroy,
+ },
+ },
+ .listener = radattr_listener_create(),
+ );
+
+ charon->bus->add_listener(charon->bus, &this->listener->listener);
+
+ return &this->public.plugin;
+}
diff --git a/src/libcharon/plugins/radattr/radattr_plugin.h b/src/libcharon/plugins/radattr/radattr_plugin.h
new file mode 100644
index 000000000..c3bad5a3a
--- /dev/null
+++ b/src/libcharon/plugins/radattr/radattr_plugin.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2012 Martin Willi
+ * Copyright (C) 2012 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 radattr radattr
+ * @ingroup cplugins
+ *
+ * @defgroup radattr_plugin radattr_plugin
+ * @{ @ingroup radattr
+ */
+
+#ifndef RADATTR_PLUGIN_H_
+#define RADATTR_PLUGIN_H_
+
+#include <plugins/plugin.h>
+
+typedef struct radattr_plugin_t radattr_plugin_t;
+
+/**
+ * Plugin to inject/process custom RADIUS attributes.
+ */
+struct radattr_plugin_t {
+
+ /**
+ * implements plugin interface
+ */
+ plugin_t plugin;
+};
+
+#endif /** RADATTR_PLUGIN_H_ @}*/
diff --git a/src/libcharon/plugins/stroke/stroke_control.c b/src/libcharon/plugins/stroke/stroke_control.c
index 3264cb802..a58d904c5 100644
--- a/src/libcharon/plugins/stroke/stroke_control.c
+++ b/src/libcharon/plugins/stroke/stroke_control.c
@@ -609,8 +609,7 @@ METHOD(stroke_control_t, unroute, void,
{
child_sa_t *child_sa;
enumerator_t *enumerator;
- u_int32_t id;
- bool found = FALSE;
+ u_int32_t id = 0;
if (charon->shunts->uninstall(charon->shunts, msg->unroute.name))
{
@@ -624,15 +623,17 @@ METHOD(stroke_control_t, unroute, void,
if (streq(msg->unroute.name, child_sa->get_name(child_sa)))
{
id = child_sa->get_reqid(child_sa);
- enumerator->destroy(enumerator);
- charon->traps->uninstall(charon->traps, id);
- fprintf(out, "configuration '%s' unrouted\n", msg->unroute.name);
- found = TRUE;
+ break;
}
}
enumerator->destroy(enumerator);
- if (!found)
+ if (id)
+ {
+ charon->traps->uninstall(charon->traps, id);
+ fprintf(out, "configuration '%s' unrouted\n", msg->unroute.name);
+ }
+ else
{
fprintf(out, "configuration '%s' not found\n", msg->unroute.name);
}
diff --git a/src/libcharon/plugins/stroke/stroke_cred.c b/src/libcharon/plugins/stroke/stroke_cred.c
index aff0e66b1..cdf69135a 100644
--- a/src/libcharon/plugins/stroke/stroke_cred.c
+++ b/src/libcharon/plugins/stroke/stroke_cred.c
@@ -71,6 +71,12 @@ struct private_stroke_cred_t {
mem_cred_t *creds;
/**
+ * ignore missing CA basic constraint (i.e. treat all certificates in
+ * ipsec.conf ca sections and ipsec.d/cacert as CA certificates)
+ */
+ bool force_ca_cert;
+
+ /**
* cache CRLs to disk?
*/
bool cachecrl;
@@ -91,10 +97,21 @@ METHOD(stroke_cred_t, load_ca, certificate_t*,
snprintf(path, sizeof(path), "%s/%s", CA_CERTIFICATE_DIR, filename);
}
- cert = lib->creds->create(lib->creds,
+ 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;
@@ -171,11 +188,21 @@ static void load_certdir(private_stroke_cred_t *this, char *path,
{
case CERT_X509:
if (flag & X509_CA)
- { /* for CA certificates, we strictly require
- * the CA basic constraint to be set */
- cert = lib->creds->create(lib->creds,
+ {
+ if (this->force_ca_cert)
+ { /* treat this 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);
+ }
+ else
+ {
+ cert = lib->creds->create(lib->creds,
CRED_CERTIFICATE, CERT_X509,
BUILD_FROM_FILE, file, BUILD_END);
+ }
if (cert)
{
x509_t *x509 = (x509_t*)cert;
@@ -1073,6 +1100,9 @@ stroke_cred_t *stroke_cred_create()
lib->credmgr->add_set(lib->credmgr, &this->creds->set);
+ this->force_ca_cert = lib->settings->get_bool(lib->settings,
+ "charon.plugins.stroke.ignore_missing_ca_basic_constraint", FALSE);
+
load_certs(this);
load_secrets(this, SECRETS_FILE, 0, NULL);
diff --git a/src/libcharon/plugins/stroke/stroke_list.c b/src/libcharon/plugins/stroke/stroke_list.c
index 8bb1a98ef..6b256f29b 100644
--- a/src/libcharon/plugins/stroke/stroke_list.c
+++ b/src/libcharon/plugins/stroke/stroke_list.c
@@ -426,7 +426,6 @@ METHOD(stroke_list_t, status, void,
if (all)
{
peer_cfg_t *peer_cfg;
- plugin_t *plugin;
char *pool;
host_t *host;
u_int32_t dpd;
@@ -461,14 +460,8 @@ METHOD(stroke_list_t, status, void,
}
fprintf(out, ", scheduled: %d\n",
lib->scheduler->get_job_load(lib->scheduler));
- fprintf(out, " loaded plugins: ");
- enumerator = lib->plugins->create_plugin_enumerator(lib->plugins);
- while (enumerator->enumerate(enumerator, &plugin, NULL))
- {
- fprintf(out, "%s ", plugin->get_name(plugin));
- }
- enumerator->destroy(enumerator);
- fprintf(out, "\n");
+ fprintf(out, " loaded plugins: %s\n",
+ lib->plugins->loaded_plugins(lib->plugins));
first = TRUE;
enumerator = this->attribute->create_pool_enumerator(this->attribute);
diff --git a/src/libcharon/plugins/stroke/stroke_socket.c b/src/libcharon/plugins/stroke/stroke_socket.c
index 21d15afe6..4956b011f 100644
--- a/src/libcharon/plugins/stroke/stroke_socket.c
+++ b/src/libcharon/plugins/stroke/stroke_socket.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2011 Tobias Brunner
* Copyright (C) 2008 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -25,7 +26,10 @@
#include <hydra.h>
#include <daemon.h>
+#include <threading/mutex.h>
#include <threading/thread.h>
+#include <threading/condvar.h>
+#include <utils/linked_list.h>
#include <processing/jobs/callback_job.h>
#include "stroke_config.h"
@@ -35,6 +39,12 @@
#include "stroke_attribute.h"
#include "stroke_list.h"
+/**
+ * To avoid clogging the thread pool with (blocking) jobs, we limit the number
+ * of concurrently handled stroke commands.
+ */
+#define MAX_CONCURRENT_DEFAULT 4
+
typedef struct stroke_job_context_t stroke_job_context_t;
typedef struct private_stroke_socket_t private_stroke_socket_t;
@@ -56,7 +66,37 @@ struct private_stroke_socket_t {
/**
* job accepting stroke messages
*/
- callback_job_t *job;
+ callback_job_t *receiver;
+
+ /**
+ * job handling stroke messages
+ */
+ callback_job_t *handler;
+
+ /**
+ * queued stroke commands
+ */
+ linked_list_t *commands;
+
+ /**
+ * lock for command list
+ */
+ mutex_t *mutex;
+
+ /**
+ * condvar to signal the arrival or completion of commands
+ */
+ condvar_t *condvar;
+
+ /**
+ * the number of currently handled commands
+ */
+ u_int handling;
+
+ /**
+ * the maximum number of concurrently handled commands
+ */
+ u_int max_concurrent;
/**
* configuration backend
@@ -84,7 +124,7 @@ struct private_stroke_socket_t {
stroke_ca_t *ca;
/**
- * Status information logging
+ * status information logging
*/
stroke_list_t *list;
};
@@ -450,7 +490,7 @@ static void stroke_loglevel(private_stroke_socket_t *this,
msg->loglevel.level, msg->loglevel.type);
group = enum_from_name(debug_names, msg->loglevel.type);
- if (group < 0)
+ if ((int)group < 0)
{
fprintf(out, "invalid type (%s)!\n", msg->loglevel.type);
return;
@@ -492,6 +532,18 @@ static void stroke_job_context_destroy(stroke_job_context_t *this)
}
/**
+ * called to signal the completion of a command
+ */
+static inline job_requeue_t job_processed(private_stroke_socket_t *this)
+{
+ this->mutex->lock(this->mutex);
+ this->handling--;
+ this->condvar->signal(this->condvar);
+ this->mutex->unlock(this->mutex);
+ return JOB_REQUEUE_NONE;
+}
+
+/**
* process a stroke request from the socket pointed by "fd"
*/
static job_requeue_t process(stroke_job_context_t *ctx)
@@ -509,7 +561,7 @@ static job_requeue_t process(stroke_job_context_t *ctx)
{
DBG1(DBG_CFG, "reading length of stroke message failed: %s",
strerror(errno));
- return JOB_REQUEUE_NONE;
+ return job_processed(this);
}
/* read message */
@@ -518,14 +570,14 @@ static job_requeue_t process(stroke_job_context_t *ctx)
if (bytes_read != msg_length)
{
DBG1(DBG_CFG, "reading stroke message failed: %s", strerror(errno));
- return JOB_REQUEUE_NONE;
+ return job_processed(this);
}
out = fdopen(strokefd, "w+");
if (out == NULL)
{
DBG1(DBG_CFG, "opening stroke output channel failed: %s", strerror(errno));
- return JOB_REQUEUE_NONE;
+ return job_processed(this);
}
DBG3(DBG_CFG, "stroke message %b", (void*)msg, msg_length);
@@ -602,11 +654,38 @@ static job_requeue_t process(stroke_job_context_t *ctx)
fclose(out);
/* fclose() closes underlying FD */
ctx->fd = 0;
- return JOB_REQUEUE_NONE;
+ return job_processed(this);
}
/**
- * Implementation of private_stroke_socket_t.stroke_receive.
+ * Handle queued stroke commands
+ */
+static job_requeue_t handle(private_stroke_socket_t *this)
+{
+ stroke_job_context_t *ctx;
+ callback_job_t *job;
+ bool oldstate;
+
+ this->mutex->lock(this->mutex);
+ thread_cleanup_push((thread_cleanup_t)this->mutex->unlock, this->mutex);
+ oldstate = thread_cancelability(TRUE);
+ while (this->commands->get_count(this->commands) == 0 ||
+ this->handling >= this->max_concurrent)
+ {
+ this->condvar->wait(this->condvar, this->mutex);
+ }
+ thread_cancelability(oldstate);
+ this->commands->remove_first(this->commands, (void**)&ctx);
+ this->handling++;
+ thread_cleanup_pop(TRUE);
+ job = callback_job_create_with_prio((callback_job_cb_t)process, ctx,
+ (void*)stroke_job_context_destroy, this->handler, JOB_PRIO_HIGH);
+ lib->processor->queue_job(lib->processor, (job_t*)job);
+ return JOB_REQUEUE_DIRECT;
+}
+
+/**
+ * Accept stroke commands and queue them to be handled
*/
static job_requeue_t receive(private_stroke_socket_t *this)
{
@@ -614,7 +693,6 @@ static job_requeue_t receive(private_stroke_socket_t *this)
int strokeaddrlen = sizeof(strokeaddr);
int strokefd;
bool oldstate;
- callback_job_t *job;
stroke_job_context_t *ctx;
oldstate = thread_cancelability(TRUE);
@@ -627,17 +705,18 @@ static job_requeue_t receive(private_stroke_socket_t *this)
return JOB_REQUEUE_FAIR;
}
- ctx = malloc_thing(stroke_job_context_t);
- ctx->fd = strokefd;
- ctx->this = this;
- job = callback_job_create_with_prio((callback_job_cb_t)process,
- ctx, (void*)stroke_job_context_destroy, this->job, JOB_PRIO_HIGH);
- lib->processor->queue_job(lib->processor, (job_t*)job);
+ INIT(ctx,
+ .fd = strokefd,
+ .this = this,
+ );
+ this->mutex->lock(this->mutex);
+ this->commands->insert_last(this->commands, ctx);
+ this->condvar->signal(this->condvar);
+ this->mutex->unlock(this->mutex);
return JOB_REQUEUE_FAIR;
}
-
/**
* initialize and open stroke socket
*/
@@ -685,7 +764,11 @@ static bool open_socket(private_stroke_socket_t *this)
METHOD(stroke_socket_t, destroy, void,
private_stroke_socket_t *this)
{
- this->job->cancel(this->job);
+ this->handler->cancel(this->handler);
+ this->receiver->cancel(this->receiver);
+ this->commands->destroy_function(this->commands, (void*)stroke_job_context_destroy);
+ this->condvar->destroy(this->condvar);
+ this->mutex->destroy(this->mutex);
lib->credmgr->remove_set(lib->credmgr, &this->ca->set);
lib->credmgr->remove_set(lib->credmgr, &this->cred->set);
charon->backends->remove_backend(charon->backends, &this->config->backend);
@@ -725,14 +808,24 @@ stroke_socket_t *stroke_socket_create()
this->control = stroke_control_create();
this->list = stroke_list_create(this->attribute);
+ this->mutex = mutex_create(MUTEX_TYPE_DEFAULT);
+ this->condvar = condvar_create(CONDVAR_TYPE_DEFAULT);
+ this->commands = linked_list_create();
+ this->max_concurrent = lib->settings->get_int(lib->settings,
+ "charon.plugins.stroke.max_concurrent", MAX_CONCURRENT_DEFAULT);
+
lib->credmgr->add_set(lib->credmgr, &this->ca->set);
lib->credmgr->add_set(lib->credmgr, &this->cred->set);
charon->backends->add_backend(charon->backends, &this->config->backend);
hydra->attributes->add_provider(hydra->attributes, &this->attribute->provider);
- this->job = callback_job_create_with_prio((callback_job_cb_t)receive,
+ this->receiver = callback_job_create_with_prio((callback_job_cb_t)receive,
+ this, NULL, NULL, JOB_PRIO_CRITICAL);
+ lib->processor->queue_job(lib->processor, (job_t*)this->receiver);
+
+ this->handler = callback_job_create_with_prio((callback_job_cb_t)handle,
this, NULL, NULL, JOB_PRIO_CRITICAL);
- lib->processor->queue_job(lib->processor, (job_t*)this->job);
+ lib->processor->queue_job(lib->processor, (job_t*)this->handler);
return &this->public;
}
diff --git a/src/libcharon/plugins/tnc_imc/tnc_imc.c b/src/libcharon/plugins/tnc_imc/tnc_imc.c
index 52e526604..a1f2d770f 100644
--- a/src/libcharon/plugins/tnc_imc/tnc_imc.c
+++ b/src/libcharon/plugins/tnc_imc/tnc_imc.c
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2006 Mike McCauley
- * Copyright (C) 2010 Andreas Steffen, HSR Hochschule fuer Technik Rapperswil
+ * Copyright (C) 2010-2011 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
@@ -17,8 +18,11 @@
#include <dlfcn.h>
+#include <tncif_pa_subtypes.h>
+
#include <debug.h>
#include <library.h>
+#include <utils/linked_list.h>
#include <threading/mutex.h>
typedef struct private_tnc_imc_t private_tnc_imc_t;
@@ -54,9 +58,19 @@ struct private_tnc_imc_t {
TNC_IMCID id;
/**
- * List of message types supported by IMC
+ * list of additional IMC IDs
*/
- TNC_MessageTypeList supported_types;
+ linked_list_t *additional_ids;
+
+ /**
+ * List of message types supported by IMC - Vendor ID part
+ */
+ TNC_VendorIDList supported_vids;
+
+ /**
+ * List of message types supported by IMC - Subtype part
+ */
+ TNC_MessageSubtypeList supported_subtypes;
/**
* Number of supported message types
@@ -81,6 +95,54 @@ METHOD(imc_t, get_id, TNC_IMCID,
return this->id;
}
+METHOD(imc_t, add_id, void,
+ private_tnc_imc_t *this, TNC_IMCID id)
+{
+ void *pointer;
+
+ /* store the scalar value in the pointer */
+ pointer = (void*)id;
+ this->additional_ids->insert_last(this->additional_ids, pointer);
+}
+
+METHOD(imc_t, has_id, bool,
+ private_tnc_imc_t *this, TNC_IMCID id)
+{
+ enumerator_t *enumerator;
+ TNC_IMCID additional_id;
+ void *pointer;
+ bool found = FALSE;
+
+ /* check primary IMC ID */
+ if (id == this->id)
+ {
+ return TRUE;
+ }
+
+ /* return if there are no additional IMC IDs */
+ if (this->additional_ids->get_count(this->additional_ids) == 0)
+ {
+ return FALSE;
+ }
+
+ /* check additional IMC IDs */
+ enumerator = this->additional_ids->create_enumerator(this->additional_ids);
+ while (enumerator->enumerate(enumerator, &pointer))
+ {
+ /* interpret pointer as scalar value */
+ additional_id = (TNC_UInt32)pointer;
+
+ if (id == additional_id)
+ {
+ found = TRUE;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ return found;
+}
+
METHOD(imc_t, get_name, char*,
private_tnc_imc_t *this)
{
@@ -91,66 +153,150 @@ METHOD(imc_t, set_message_types, void,
private_tnc_imc_t *this, TNC_MessageTypeList supported_types,
TNC_UInt32 type_count)
{
- char buf[512];
+ char buf[BUF_LEN];
char *pos = buf;
int len = sizeof(buf);
- int written;
+ int i, written;
+ size_t size;
+ TNC_VendorID vid;
+ TNC_MessageSubtype subtype;
+ enum_name_t *pa_subtype_names;
/* lock the imc_t instance */
this->mutex->lock(this->mutex);
- /* Free an existing MessageType list */
- free(this->supported_types);
- this->supported_types = NULL;
+ /* Free existing VendorID and MessageSubtype lists */
+ free(this->supported_vids);
+ this->supported_vids = NULL;
+ free(this->supported_subtypes);
+ this->supported_subtypes = NULL;
/* Store the new MessageType list */
this->type_count = type_count;
if (type_count && supported_types)
{
- size_t size = type_count * sizeof(TNC_MessageType);
- int i;
+ size = type_count * sizeof(TNC_VendorID);
+ this->supported_vids = malloc(size);
+ size = type_count * sizeof(TNC_MessageSubtype);
+ this->supported_subtypes = malloc(size);
for (i = 0; i < type_count; i++)
{
- written = snprintf(pos, len, " 0x%08x", supported_types[i]);
+ vid = (supported_types[i] >> 8) & TNC_VENDORID_ANY;
+ subtype = supported_types[i] & TNC_SUBTYPE_ANY;
+
+ pa_subtype_names = get_pa_subtype_names(vid);
+ if (pa_subtype_names)
+ {
+ written = snprintf(pos, len," '%N/%N' 0x%06x/0x%02x",
+ pen_names, vid, pa_subtype_names, subtype,
+ vid, subtype);
+ }
+ else
+ {
+ written = snprintf(pos, len," '%N' 0x%06x/0x%02x",
+ pen_names, vid, vid, subtype);
+ }
if (written >= len)
{
break;
}
pos += written;
len -= written;
+
+ this->supported_vids[i] = vid;
+ this->supported_subtypes[i] = subtype;
}
- this->supported_types = malloc(size);
- memcpy(this->supported_types, supported_types, size);
}
*pos = '\0';
DBG2(DBG_TNC, "IMC %u supports %u message type%s:%s",
this->id, type_count, (type_count == 1) ? "":"s", buf);
+ /* unlock the imc_t instance */
+ this->mutex->unlock(this->mutex);
+}
+
+METHOD(imc_t, set_message_types_long, void,
+ private_tnc_imc_t *this, TNC_VendorIDList supported_vids,
+ TNC_MessageSubtypeList supported_subtypes, TNC_UInt32 type_count)
+{
+ char buf[BUF_LEN];
+ char *pos = buf;
+ int len = sizeof(buf);
+ int i, written;
+ size_t size;
+ TNC_VendorID vid;
+ TNC_MessageSubtype subtype;
+ enum_name_t *pa_subtype_names;
+
/* lock the imc_t instance */
+ this->mutex->lock(this->mutex);
+
+ /* Free existing VendorID and MessageSubtype lists */
+ free(this->supported_vids);
+ this->supported_vids = NULL;
+ free(this->supported_subtypes);
+ this->supported_subtypes = NULL;
+
+ /* Store the new MessageType list */
+ this->type_count = type_count;
+ if (type_count && supported_vids && supported_subtypes)
+ {
+ size = type_count * sizeof(TNC_VendorID);
+ this->supported_vids = malloc(size);
+ memcpy(this->supported_vids, supported_vids, size);
+ size = type_count * sizeof(TNC_MessageSubtype);
+ this->supported_subtypes = malloc(size);
+ memcpy(this->supported_subtypes, supported_subtypes, size);
+
+ for (i = 0; i < type_count; i++)
+ {
+ vid = supported_vids[i];
+ subtype = supported_subtypes[i];
+
+ pa_subtype_names = get_pa_subtype_names(vid);
+ if (pa_subtype_names)
+ {
+ written = snprintf(pos, len," '%N/%N' 0x%06x/0x%08x",
+ pen_names, vid, pa_subtype_names, subtype,
+ vid, subtype);
+ }
+ else
+ {
+ written = snprintf(pos, len," '%N' 0x%06x/0x%08x",
+ pen_names, vid, vid, subtype);
+ }
+ if (written >= len)
+ {
+ break;
+ }
+ pos += written;
+ len -= written;
+ }
+ }
+ *pos = '\0';
+ DBG2(DBG_TNC, "IMC %u supports %u message type%s:%s",
+ this->id, type_count, (type_count == 1) ? "":"s", buf);
+
+ /* unlock the imc_t instance */
this->mutex->unlock(this->mutex);
}
METHOD(imc_t, type_supported, bool,
- private_tnc_imc_t *this, TNC_MessageType message_type)
+ private_tnc_imc_t *this, TNC_VendorID msg_vid, TNC_MessageSubtype msg_subtype)
{
- TNC_VendorID msg_vid, vid;
- TNC_MessageSubtype msg_subtype, subtype;
+ TNC_VendorID vid;
+ TNC_MessageSubtype subtype;
int i;
- msg_vid = (message_type >> 8) & TNC_VENDORID_ANY;
- msg_subtype = message_type & TNC_SUBTYPE_ANY;
-
for (i = 0; i < this->type_count; i++)
{
- vid = (this->supported_types[i] >> 8) & TNC_VENDORID_ANY;
- subtype = this->supported_types[i] & TNC_SUBTYPE_ANY;
-
- if (this->supported_types[i] == message_type
- || (subtype == TNC_SUBTYPE_ANY
- && (msg_vid == vid || vid == TNC_VENDORID_ANY))
- || (vid == TNC_VENDORID_ANY
- && (msg_subtype == subtype || subtype == TNC_SUBTYPE_ANY)))
+ vid = this->supported_vids[i];
+ subtype = this->supported_subtypes[i];
+
+ if ((vid == TNC_VENDORID_ANY && subtype == TNC_SUBTYPE_ANY) ||
+ (vid == msg_vid && (subtype == TNC_SUBTYPE_ANY ||
+ subtype == msg_subtype)))
{
return TRUE;
}
@@ -163,7 +309,9 @@ METHOD(imc_t, destroy, void,
{
dlclose(this->handle);
this->mutex->destroy(this->mutex);
- free(this->supported_types);
+ this->additional_ids->destroy(this->additional_ids);
+ free(this->supported_vids);
+ free(this->supported_subtypes);
free(this->name);
free(this->path);
free(this);
@@ -180,13 +328,17 @@ imc_t* tnc_imc_create(char *name, char *path)
.public = {
.set_id = _set_id,
.get_id = _get_id,
+ .add_id = _add_id,
+ .has_id = _has_id,
.get_name = _get_name,
.set_message_types = _set_message_types,
+ .set_message_types_long = _set_message_types_long,
.type_supported = _type_supported,
.destroy = _destroy,
},
.name = name,
.path = path,
+ .additional_ids = linked_list_create(),
.mutex = mutex_create(MUTEX_TYPE_DEFAULT),
);
@@ -220,6 +372,8 @@ imc_t* tnc_imc_create(char *name, char *path)
}
this->public.receive_message =
dlsym(this->handle, "TNC_IMC_ReceiveMessage");
+ this->public.receive_message_long =
+ dlsym(this->handle, "TNC_IMC_ReceiveMessageLong");
this->public.batch_ending =
dlsym(this->handle, "TNC_IMC_BatchEnding");
this->public.terminate =
diff --git a/src/libcharon/plugins/tnc_imc/tnc_imc_bind_function.c b/src/libcharon/plugins/tnc_imc/tnc_imc_bind_function.c
index 46c131b44..90a607ccc 100644
--- a/src/libcharon/plugins/tnc_imc/tnc_imc_bind_function.c
+++ b/src/libcharon/plugins/tnc_imc/tnc_imc_bind_function.c
@@ -19,8 +19,6 @@
#include <debug.h>
-#define TNC_IMVID_ANY 0xffff
-
/**
* Called by the IMC to inform a TNCC about the set of message types the IMC
* is able to receive
@@ -40,6 +38,25 @@ TNC_Result TNC_TNCC_ReportMessageTypes(TNC_IMCID imc_id,
}
/**
+ * Called by the IMC to inform a TNCC about the set of message types the IMC
+ * is able to receive. This function supports long message types.
+ */
+TNC_Result TNC_TNCC_ReportMessageTypesLong(TNC_IMCID imc_id,
+ TNC_VendorIDList supported_vids,
+ TNC_MessageSubtypeList supported_subtypes,
+ TNC_UInt32 type_count)
+{
+ if (!tnc->imcs->is_registered(tnc->imcs, imc_id))
+ {
+ DBG1(DBG_TNC, "ignoring ReportMessageTypesLong() from unregistered IMC %u",
+ imc_id);
+ return TNC_RESULT_INVALID_PARAMETER;
+ }
+ return tnc->imcs->set_message_types_long(tnc->imcs, imc_id, supported_vids,
+ supported_subtypes, type_count);
+}
+
+/**
* Called by the IMC to ask a TNCC to retry an Integrity Check Handshake
*/
TNC_Result TNC_TNCC_RequestHandshakeRetry(TNC_IMCID imc_id,
@@ -65,14 +82,97 @@ TNC_Result TNC_TNCC_SendMessage(TNC_IMCID imc_id,
TNC_UInt32 msg_len,
TNC_MessageType msg_type)
{
+ TNC_VendorID msg_vid;
+ TNC_MessageSubtype msg_subtype;
+
if (!tnc->imcs->is_registered(tnc->imcs, imc_id))
{
DBG1(DBG_TNC, "ignoring SendMessage() from unregistered IMC %u",
imc_id);
return TNC_RESULT_INVALID_PARAMETER;
}
+ msg_vid = (msg_type >> 8) & TNC_VENDORID_ANY;
+ msg_subtype = msg_type & TNC_SUBTYPE_ANY;
+
return tnc->tnccs->send_message(tnc->tnccs, imc_id, TNC_IMVID_ANY,
- connection_id, msg, msg_len, msg_type);
+ connection_id, 0, msg, msg_len, msg_vid, msg_subtype);
+}
+
+/**
+ * Called by the IMC when an IMC-IMV message is to be sent over IF-TNCCS 2.0
+ */
+TNC_Result TNC_TNCC_SendMessageLong(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 imv_id)
+{
+ if (!tnc->imcs->is_registered(tnc->imcs, imc_id))
+ {
+ DBG1(DBG_TNC, "ignoring SendMessage() from unregistered IMC %u",
+ imc_id);
+ return TNC_RESULT_INVALID_PARAMETER;
+ }
+ return tnc->tnccs->send_message(tnc->tnccs, imc_id, imv_id, connection_id,
+ msg_flags, msg, msg_len, msg_vid, msg_subtype);
+}
+
+/**
+ * Called by the IMC to get the value of an attribute associated with a
+ * connection or with the TNCC as a whole.
+ */
+TNC_Result TNC_TNCC_GetAttribute(TNC_IMCID imc_id,
+ TNC_ConnectionID connection_id,
+ TNC_AttributeID attribute_id,
+ TNC_UInt32 buffer_len,
+ TNC_BufferReference buffer,
+ TNC_UInt32 *out_value_len)
+{
+ if (!tnc->imcs->is_registered(tnc->imcs, imc_id))
+ {
+ DBG1(DBG_TNC, "ignoring GetAttribute() from unregistered IMC %u",
+ imc_id);
+ return TNC_RESULT_INVALID_PARAMETER;
+ }
+ return tnc->tnccs->get_attribute(tnc->tnccs, TRUE, imc_id, connection_id,
+ attribute_id, buffer_len, buffer, out_value_len);
+}
+
+/**
+ * Called by the IMC to set the value of an attribute associated with a
+ * connection or with the TNCC as a whole.
+ */
+TNC_Result TNC_TNCC_SetAttribute(TNC_IMCID imc_id,
+ TNC_ConnectionID connection_id,
+ TNC_AttributeID attribute_id,
+ TNC_UInt32 buffer_len,
+ TNC_BufferReference buffer)
+{
+ if (!tnc->imcs->is_registered(tnc->imcs, imc_id))
+ {
+ DBG1(DBG_TNC, "ignoring SetAttribute() from unregistered IMC %u",
+ imc_id);
+ return TNC_RESULT_INVALID_PARAMETER;
+ }
+ return tnc->tnccs->set_attribute(tnc->tnccs, TRUE, imc_id, connection_id,
+ attribute_id, buffer_len, buffer);
+}
+
+/**
+ * Called by the IMC when it wants to reserve an additional IMC ID for itself
+ */
+TNC_Result TNC_TNCC_ReserveAdditionalIMCID(TNC_IMCID imc_id, TNC_UInt32 *new_id)
+{
+ if (tnc->imcs->reserve_id(tnc->imcs, imc_id, new_id))
+ {
+ return TNC_RESULT_SUCCESS;
+ }
+ DBG1(DBG_TNC, "ignoring ReserveAdditionalIMCID() from unregistered IMC %u",
+ imc_id);
+ return TNC_RESULT_INVALID_PARAMETER;
}
/**
@@ -86,6 +186,10 @@ TNC_Result TNC_TNCC_BindFunction(TNC_IMCID id,
{
*function_pointer = (void*)TNC_TNCC_ReportMessageTypes;
}
+ else if (streq(function_name, "TNC_TNCC_ReportMessageTypesLong"))
+ {
+ *function_pointer = (void*)TNC_TNCC_ReportMessageTypesLong;
+ }
else if (streq(function_name, "TNC_TNCC_RequestHandshakeRetry"))
{
*function_pointer = (void*)TNC_TNCC_RequestHandshakeRetry;
@@ -94,6 +198,22 @@ TNC_Result TNC_TNCC_BindFunction(TNC_IMCID id,
{
*function_pointer = (void*)TNC_TNCC_SendMessage;
}
+ else if (streq(function_name, "TNC_TNCC_SendMessageLong"))
+ {
+ *function_pointer = (void*)TNC_TNCC_SendMessageLong;
+ }
+ else if (streq(function_name, "TNC_TNCC_GetAttribute"))
+ {
+ *function_pointer = (void*)TNC_TNCC_GetAttribute;
+ }
+ else if (streq(function_name, "TNC_TNCC_SetAttribute"))
+ {
+ *function_pointer = (void*)TNC_TNCC_SetAttribute;
+ }
+ else if (streq(function_name, "TNC_TNCC_ReserveAdditionalIMCID"))
+ {
+ *function_pointer = (void*)TNC_TNCC_ReserveAdditionalIMCID;
+ }
else
{
return TNC_RESULT_INVALID_PARAMETER;
diff --git a/src/libcharon/plugins/tnc_imc/tnc_imc_manager.c b/src/libcharon/plugins/tnc_imc/tnc_imc_manager.c
index 202df5f5c..e101cf974 100644
--- a/src/libcharon/plugins/tnc_imc/tnc_imc_manager.c
+++ b/src/libcharon/plugins/tnc_imc/tnc_imc_manager.c
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2006 Mike McCauley
- * Copyright (C) 2010 Andreas Steffen, HSR Hochschule fuer Technik Rapperswil
+ * Copyright (C) 2010-2011 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
@@ -130,9 +131,34 @@ METHOD(imc_manager_t, is_registered, bool,
enumerator = this->imcs->create_enumerator(this->imcs);
while (enumerator->enumerate(enumerator, &imc))
{
- if (id == imc->get_id(imc))
+ if (imc->has_id(imc, id))
+ {
+ found = TRUE;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ return found;
+}
+
+METHOD(imc_manager_t, reserve_id, bool,
+ private_tnc_imc_manager_t *this, TNC_IMCID id, TNC_UInt32 *new_id)
+{
+ enumerator_t *enumerator;
+ imc_t *imc;
+ bool found = FALSE;
+
+ enumerator = this->imcs->create_enumerator(this->imcs);
+ while (enumerator->enumerate(enumerator, &imc))
+ {
+ if (imc->get_id(imc))
{
found = TRUE;
+ *new_id = this->next_imc_id++;
+ imc->add_id(imc, *new_id);
+ DBG2(DBG_TNC, "additional ID %u reserved for IMC with primary ID %u",
+ *new_id, id);
break;
}
}
@@ -203,30 +229,77 @@ METHOD(imc_manager_t, set_message_types, TNC_Result,
return result;
}
+METHOD(imc_manager_t, set_message_types_long, TNC_Result,
+ private_tnc_imc_manager_t *this, TNC_IMCID id,
+ TNC_VendorIDList supported_vids,
+ TNC_MessageSubtypeList supported_subtypes,
+ TNC_UInt32 type_count)
+{
+ enumerator_t *enumerator;
+ imc_t *imc;
+ TNC_Result result = TNC_RESULT_FATAL;
+
+ enumerator = this->imcs->create_enumerator(this->imcs);
+ while (enumerator->enumerate(enumerator, &imc))
+ {
+ if (id == imc->get_id(imc))
+ {
+ imc->set_message_types_long(imc, supported_vids, supported_subtypes,
+ type_count);
+ result = TNC_RESULT_SUCCESS;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ return result;
+}
+
METHOD(imc_manager_t, receive_message, void,
private_tnc_imc_manager_t *this, TNC_ConnectionID connection_id,
- TNC_BufferReference message,
- TNC_UInt32 message_len,
- TNC_MessageType message_type)
+ bool excl,
+ 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)
{
bool type_supported = FALSE;
+ TNC_MessageType msg_type;
+ TNC_UInt32 msg_flags;
enumerator_t *enumerator;
imc_t *imc;
enumerator = this->imcs->create_enumerator(this->imcs);
while (enumerator->enumerate(enumerator, &imc))
{
- if (imc->receive_message && imc->type_supported(imc, message_type))
+ if (imc->type_supported(imc, msg_vid, msg_subtype) &&
+ (!excl || (excl && imc->has_id(imc, dst_imc_id)) ))
{
- type_supported = TRUE;
- imc->receive_message(imc->get_id(imc), connection_id,
- message, message_len, message_type);
+ if (imc->receive_message_long && src_imv_id)
+ {
+ type_supported = TRUE;
+ msg_flags = excl ? TNC_MESSAGE_FLAGS_EXCLUSIVE : 0;
+ imc->receive_message_long(imc->get_id(imc), connection_id,
+ msg_flags, msg, msg_len, msg_vid, msg_subtype,
+ src_imv_id, dst_imc_id);
+
+ }
+ else if (imc->receive_message && msg_vid <= TNC_VENDORID_ANY &&
+ msg_subtype <= TNC_SUBTYPE_ANY)
+ {
+ type_supported = TRUE;
+ msg_type = (msg_vid << 8) | msg_subtype;
+ imc->receive_message(imc->get_id(imc), connection_id,
+ msg, msg_len, msg_type);
+ }
}
}
enumerator->destroy(enumerator);
if (!type_supported)
{
- DBG2(DBG_TNC, "message type 0x%08x not supported by any IMC", message_type);
+ DBG2(DBG_TNC, "message type 0x%06x/0x%08x not supported by any IMC",
+ msg_vid, msg_subtype);
}
}
@@ -279,10 +352,12 @@ imc_manager_t* tnc_imc_manager_create(void)
.remove = _remove_, /* avoid name conflict with stdio.h */
.load = _load,
.is_registered = _is_registered,
+ .reserve_id = _reserve_id,
.get_preferred_language = _get_preferred_language,
.notify_connection_change = _notify_connection_change,
.begin_handshake = _begin_handshake,
.set_message_types = _set_message_types,
+ .set_message_types_long = _set_message_types_long,
.receive_message = _receive_message,
.batch_ending = _batch_ending,
.destroy = _destroy,
diff --git a/src/libcharon/plugins/tnc_imv/tnc_imv.c b/src/libcharon/plugins/tnc_imv/tnc_imv.c
index f9cfc3417..f0b150743 100644
--- a/src/libcharon/plugins/tnc_imv/tnc_imv.c
+++ b/src/libcharon/plugins/tnc_imv/tnc_imv.c
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2006 Mike McCauley
- * Copyright (C) 2010 Andreas Steffen, HSR Hochschule fuer Technik Rapperswil
+ * Copyright (C) 2010-2011 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
@@ -17,8 +18,11 @@
#include <dlfcn.h>
+#include <tncif_pa_subtypes.h>
+
#include <debug.h>
#include <library.h>
+#include <utils/linked_list.h>
#include <threading/mutex.h>
typedef struct private_tnc_imv_t private_tnc_imv_t;
@@ -54,9 +58,19 @@ struct private_tnc_imv_t {
TNC_IMVID id;
/**
- * List of message types supported by IMC
+ * List of additional IMV IDs
*/
- TNC_MessageTypeList supported_types;
+ linked_list_t *additional_ids;
+
+ /**
+ * List of message types supported by IMV - Vendor ID part
+ */
+ TNC_VendorIDList supported_vids;
+
+ /**
+ * List of message types supported by IMV - Subtype part
+ */
+ TNC_MessageSubtypeList supported_subtypes;
/**
* Number of supported message types
@@ -81,6 +95,50 @@ METHOD(imv_t, get_id, TNC_IMVID,
return this->id;
}
+METHOD(imv_t, add_id, void,
+ private_tnc_imv_t *this, TNC_IMVID id)
+{
+ TNC_IMVID *new_id;
+
+ new_id = malloc_thing(TNC_IMVID);
+ *new_id = id;
+ this->additional_ids->insert_last(this->additional_ids, new_id);
+}
+
+METHOD(imv_t, has_id, bool,
+ private_tnc_imv_t *this, TNC_IMVID id)
+{
+ enumerator_t *enumerator;
+ TNC_IMVID *additional_id;
+ bool found = FALSE;
+
+ /* check primary IMV ID */
+ if (id == this->id)
+ {
+ return TRUE;
+ }
+
+ /* return if there are no additional IMV IDs */
+ if (this->additional_ids->get_count(this->additional_ids) == 0)
+ {
+ return FALSE;
+ }
+
+ /* check additional IMV IDs */
+ enumerator = this->additional_ids->create_enumerator(this->additional_ids);
+ while (enumerator->enumerate(enumerator, &additional_id))
+ {
+ if (id == *additional_id)
+ {
+ found = TRUE;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ return found;
+}
+
METHOD(imv_t, get_name, char*,
private_tnc_imv_t *this)
{
@@ -91,67 +149,150 @@ METHOD(imv_t, set_message_types, void,
private_tnc_imv_t *this, TNC_MessageTypeList supported_types,
TNC_UInt32 type_count)
{
- char buf[512];
+ char buf[BUF_LEN];
char *pos = buf;
int len = sizeof(buf);
- int written;
+ int i, written;
+ size_t size;
+ TNC_VendorID vid;
+ TNC_MessageSubtype subtype;
+ enum_name_t *pa_subtype_names;
/* lock the imv_t instance */
this->mutex->lock(this->mutex);
- /* Free an existing MessageType list */
- free(this->supported_types);
- this->supported_types = NULL;
+ /* Free existing VendorID and MessageSubtype lists */
+ free(this->supported_vids);
+ this->supported_vids = NULL;
+ free(this->supported_subtypes);
+ this->supported_subtypes = NULL;
/* Store the new MessageType list */
this->type_count = type_count;
if (type_count && supported_types)
{
- size_t size = type_count * sizeof(TNC_MessageType);
-
- int i;
+ size = type_count * sizeof(TNC_VendorID);
+ this->supported_vids = malloc(size);
+ size = type_count * sizeof(TNC_MessageSubtype);
+ this->supported_subtypes = malloc(size);
for (i = 0; i < type_count; i++)
{
- written = snprintf(pos, len, " 0x%08x", supported_types[i]);
+ vid = (supported_types[i] >> 8) & TNC_VENDORID_ANY;
+ subtype = supported_types[i] & TNC_SUBTYPE_ANY;
+
+ pa_subtype_names = get_pa_subtype_names(vid);
+ if (pa_subtype_names)
+ {
+ written = snprintf(pos, len," '%N/%N' 0x%06x/0x%02x",
+ pen_names, vid, pa_subtype_names, subtype,
+ vid, subtype);
+ }
+ else
+ {
+ written = snprintf(pos, len," '%N' 0x%06x/0x%02x",
+ pen_names, vid, vid, subtype);
+ }
if (written >= len)
{
break;
}
pos += written;
len -= written;
+
+ this->supported_vids[i] = vid;
+ this->supported_subtypes[i] = subtype;
}
- this->supported_types = malloc(size);
- memcpy(this->supported_types, supported_types, size);
}
*pos = '\0';
DBG2(DBG_TNC, "IMV %u supports %u message type%s:%s",
this->id, type_count, (type_count == 1) ? "":"s", buf);
+ /* unlock the imv_t instance */
+ this->mutex->unlock(this->mutex);
+}
+
+METHOD(imv_t, set_message_types_long, void,
+ private_tnc_imv_t *this, TNC_VendorIDList supported_vids,
+ TNC_MessageSubtypeList supported_subtypes, TNC_UInt32 type_count)
+{
+ char buf[BUF_LEN];
+ char *pos = buf;
+ int len = sizeof(buf);
+ int i, written;
+ size_t size;
+ TNC_VendorID vid;
+ TNC_MessageSubtype subtype;
+ enum_name_t *pa_subtype_names;
+
/* lock the imv_t instance */
+ this->mutex->lock(this->mutex);
+
+ /* Free existing VendorID and MessageSubtype lists */
+ free(this->supported_vids);
+ this->supported_vids = NULL;
+ free(this->supported_subtypes);
+ this->supported_subtypes = NULL;
+
+ /* Store the new MessageType list */
+ this->type_count = type_count;
+ if (type_count && supported_vids && supported_subtypes)
+ {
+ size = type_count * sizeof(TNC_VendorID);
+ this->supported_vids = malloc(size);
+ memcpy(this->supported_vids, supported_vids, size);
+ size = type_count * sizeof(TNC_MessageSubtype);
+ this->supported_subtypes = malloc(size);
+ memcpy(this->supported_subtypes, supported_subtypes, size);
+
+ for (i = 0; i < type_count; i++)
+ {
+ vid = supported_vids[i];
+ subtype = supported_subtypes[i];
+
+ pa_subtype_names = get_pa_subtype_names(vid);
+ if (pa_subtype_names)
+ {
+ written = snprintf(pos, len," '%N/%N' 0x%06x/0x%08x",
+ pen_names, vid, pa_subtype_names, subtype,
+ vid, subtype);
+ }
+ else
+ {
+ written = snprintf(pos, len," '%N' 0x%06x/0x%08x",
+ pen_names, vid, vid, subtype);
+ }
+ if (written >= len)
+ {
+ break;
+ }
+ pos += written;
+ len -= written;
+ }
+ }
+ *pos = '\0';
+ DBG2(DBG_TNC, "IMV %u supports %u message type%s:%s",
+ this->id, type_count, (type_count == 1) ? "":"s", buf);
+
+ /* unlock the imv_t instance */
this->mutex->unlock(this->mutex);
}
METHOD(imv_t, type_supported, bool,
- private_tnc_imv_t *this, TNC_MessageType message_type)
+ private_tnc_imv_t *this, TNC_VendorID msg_vid, TNC_MessageSubtype msg_subtype)
{
- TNC_VendorID msg_vid, vid;
- TNC_MessageSubtype msg_subtype, subtype;
+ TNC_VendorID vid;
+ TNC_MessageSubtype subtype;
int i;
- msg_vid = (message_type >> 8) & TNC_VENDORID_ANY;
- msg_subtype = message_type & TNC_SUBTYPE_ANY;
-
for (i = 0; i < this->type_count; i++)
{
- vid = (this->supported_types[i] >> 8) & TNC_VENDORID_ANY;
- subtype = this->supported_types[i] & TNC_SUBTYPE_ANY;
-
- if (this->supported_types[i] == message_type
- || (subtype == TNC_SUBTYPE_ANY
- && (msg_vid == vid || vid == TNC_VENDORID_ANY))
- || (vid == TNC_VENDORID_ANY
- && (msg_subtype == subtype || subtype == TNC_SUBTYPE_ANY)))
+ vid = this->supported_vids[i];
+ subtype = this->supported_subtypes[i];
+
+ if ((vid == TNC_VENDORID_ANY && subtype == TNC_SUBTYPE_ANY) ||
+ (vid == msg_vid && (subtype == TNC_SUBTYPE_ANY ||
+ subtype == msg_subtype)))
{
return TRUE;
}
@@ -164,7 +305,9 @@ METHOD(imv_t, destroy, void,
{
dlclose(this->handle);
this->mutex->destroy(this->mutex);
- free(this->supported_types);
+ this->additional_ids->destroy_function(this->additional_ids, free);
+ free(this->supported_vids);
+ free(this->supported_subtypes);
free(this->name);
free(this->path);
free(this);
@@ -181,13 +324,17 @@ imv_t* tnc_imv_create(char *name, char *path)
.public = {
.set_id = _set_id,
.get_id = _get_id,
+ .add_id = _add_id,
+ .has_id = _has_id,
.get_name = _get_name,
.set_message_types = _set_message_types,
+ .set_message_types_long = _set_message_types_long,
.type_supported = _type_supported,
.destroy = _destroy,
},
.name = name,
.path = path,
+ .additional_ids = linked_list_create(),
.mutex = mutex_create(MUTEX_TYPE_DEFAULT),
);
@@ -222,6 +369,8 @@ imv_t* tnc_imv_create(char *name, char *path)
}
this->public.receive_message =
dlsym(this->handle, "TNC_IMV_ReceiveMessage");
+ this->public.receive_message_long =
+ dlsym(this->handle, "TNC_IMV_ReceiveMessageLong");
this->public.batch_ending =
dlsym(this->handle, "TNC_IMV_BatchEnding");
this->public.terminate =
diff --git a/src/libcharon/plugins/tnc_imv/tnc_imv_bind_function.c b/src/libcharon/plugins/tnc_imv/tnc_imv_bind_function.c
index cde1e4fe1..dd11c5009 100644
--- a/src/libcharon/plugins/tnc_imv/tnc_imv_bind_function.c
+++ b/src/libcharon/plugins/tnc_imv/tnc_imv_bind_function.c
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2006 Mike McCauley
- * Copyright (C) 2010 Andreas Steffen, HSR Hochschule fuer Technik Rapperswil
+ * Copyright (C) 2010-2011 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
@@ -19,8 +20,6 @@
#include <debug.h>
-#define TNC_IMCID_ANY 0xffff
-
/**
* Called by the IMV to inform a TNCS about the set of message types the IMV
* is able to receive
@@ -40,6 +39,25 @@ TNC_Result TNC_TNCS_ReportMessageTypes(TNC_IMVID imv_id,
}
/**
+ * Called by the IMV to inform a TNCS about the set of message types the IMV
+ * is able to receive. This function supports long message types.
+ */
+TNC_Result TNC_TNCS_ReportMessageTypesLong(TNC_IMVID imv_id,
+ TNC_VendorIDList supported_vids,
+ TNC_MessageSubtypeList supported_subtypes,
+ TNC_UInt32 type_count)
+{
+ if (!tnc->imvs->is_registered(tnc->imvs, imv_id))
+ {
+ DBG1(DBG_TNC, "ignoring ReportMessageTypesLong() from unregistered IMV %u",
+ imv_id);
+ return TNC_RESULT_INVALID_PARAMETER;
+ }
+ return tnc->imvs->set_message_types_long(tnc->imvs, imv_id, supported_vids,
+ supported_subtypes, type_count);
+}
+
+/**
* Called by the IMV to ask a TNCS to retry an Integrity Check Handshake
*/
TNC_Result TNC_TNCS_RequestHandshakeRetry(TNC_IMVID imv_id,
@@ -65,14 +83,42 @@ TNC_Result TNC_TNCS_SendMessage(TNC_IMVID imv_id,
TNC_UInt32 msg_len,
TNC_MessageType msg_type)
{
+ TNC_VendorID msg_vid;
+ TNC_MessageSubtype msg_subtype;
+
if (!tnc->imvs->is_registered(tnc->imvs, imv_id))
{
DBG1(DBG_TNC, "ignoring SendMessage() from unregistered IMV %u",
imv_id);
return TNC_RESULT_INVALID_PARAMETER;
}
+ msg_vid = (msg_type >> 8) & TNC_VENDORID_ANY;
+ msg_subtype = msg_type & TNC_SUBTYPE_ANY;
+
return tnc->tnccs->send_message(tnc->tnccs, TNC_IMCID_ANY, imv_id,
- connection_id, msg, msg_len, msg_type);
+ connection_id, 0, msg, msg_len, msg_vid, msg_subtype);
+}
+
+/**
+ * Called by the IMV when an IMV-IMC message is to be sent over IF-TNCCS 2.0
+ */
+TNC_Result TNC_TNCS_SendMessageLong(TNC_IMVID imv_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 imc_id)
+{
+ if (!tnc->imvs->is_registered(tnc->imvs, imv_id))
+ {
+ DBG1(DBG_TNC, "ignoring SendMessageLong() from unregistered IMV %u",
+ imv_id);
+ return TNC_RESULT_INVALID_PARAMETER;
+ }
+ return tnc->tnccs->send_message(tnc->tnccs, imc_id, imv_id, connection_id,
+ msg_flags, msg, msg_len, msg_vid, msg_subtype);
}
/**
@@ -111,7 +157,7 @@ TNC_Result TNC_TNCS_GetAttribute(TNC_IMVID imv_id,
imv_id);
return TNC_RESULT_INVALID_PARAMETER;
}
- return tnc->tnccs->get_attribute(tnc->tnccs, imv_id, connection_id,
+ return tnc->tnccs->get_attribute(tnc->tnccs, FALSE, imv_id, connection_id,
attribute_id, buffer_len, buffer, out_value_len);
}
@@ -131,11 +177,25 @@ TNC_Result TNC_TNCS_SetAttribute(TNC_IMVID imv_id,
imv_id);
return TNC_RESULT_INVALID_PARAMETER;
}
- return tnc->tnccs->set_attribute(tnc->tnccs, imv_id, connection_id,
+ return tnc->tnccs->set_attribute(tnc->tnccs, FALSE, imv_id, connection_id,
attribute_id, buffer_len, buffer);
}
/**
+ * Called by the IMV when it wants to reserve an additional IMV ID for itself
+ */
+TNC_Result TNC_TNCS_ReserveAdditionalIMVID(TNC_IMVID imv_id, TNC_UInt32 *new_id)
+{
+ if (tnc->imvs->reserve_id(tnc->imvs, imv_id, new_id))
+ {
+ return TNC_RESULT_SUCCESS;
+ }
+ DBG1(DBG_TNC, "ignoring ReserveAdditionalIMVID() from unregistered IMV %u",
+ imv_id);
+ return TNC_RESULT_INVALID_PARAMETER;
+}
+
+/**
* Called by the IMV when it needs a function pointer
*/
TNC_Result TNC_TNCS_BindFunction(TNC_IMVID id,
@@ -146,6 +206,10 @@ TNC_Result TNC_TNCS_BindFunction(TNC_IMVID id,
{
*function_pointer = (void*)TNC_TNCS_ReportMessageTypes;
}
+ else if (streq(function_name, "TNC_TNCS_ReportMessageTypesLong"))
+ {
+ *function_pointer = (void*)TNC_TNCS_ReportMessageTypesLong;
+ }
else if (streq(function_name, "TNC_TNCS_RequestHandshakeRetry"))
{
*function_pointer = (void*)TNC_TNCS_RequestHandshakeRetry;
@@ -154,6 +218,10 @@ TNC_Result TNC_TNCS_BindFunction(TNC_IMVID id,
{
*function_pointer = (void*)TNC_TNCS_SendMessage;
}
+ else if (streq(function_name, "TNC_TNCS_SendMessageLong"))
+ {
+ *function_pointer = (void*)TNC_TNCS_SendMessageLong;
+ }
else if (streq(function_name, "TNC_TNCS_ProvideRecommendation"))
{
*function_pointer = (void*)TNC_TNCS_ProvideRecommendation;
@@ -166,6 +234,10 @@ TNC_Result TNC_TNCS_BindFunction(TNC_IMVID id,
{
*function_pointer = (void*)TNC_TNCS_SetAttribute;
}
+ else if (streq(function_name, "TNC_TNCS_ReserveAdditionalIMVID"))
+ {
+ *function_pointer = (void*)TNC_TNCS_ReserveAdditionalIMVID;
+ }
else
{
return TNC_RESULT_INVALID_PARAMETER;
diff --git a/src/libcharon/plugins/tnc_imv/tnc_imv_manager.c b/src/libcharon/plugins/tnc_imv/tnc_imv_manager.c
index 4eee69e4d..b1da73156 100644
--- a/src/libcharon/plugins/tnc_imv/tnc_imv_manager.c
+++ b/src/libcharon/plugins/tnc_imv/tnc_imv_manager.c
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2006 Mike McCauley
- * Copyright (C) 2010 Andreas Steffen, HSR Hochschule fuer Technik Rapperswil
+ * Copyright (C) 2010-2011 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
@@ -147,9 +148,34 @@ METHOD(imv_manager_t, is_registered, bool,
enumerator = this->imvs->create_enumerator(this->imvs);
while (enumerator->enumerate(enumerator, &imv))
{
- if (id == imv->get_id(imv))
+ if (imv->has_id(imv, id))
+ {
+ found = TRUE;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ return found;
+}
+
+METHOD(imv_manager_t, reserve_id, bool,
+ private_tnc_imv_manager_t *this, TNC_IMVID id, TNC_UInt32 *new_id)
+{
+ enumerator_t *enumerator;
+ imv_t *imv;
+ bool found = FALSE;
+
+ enumerator = this->imvs->create_enumerator(this->imvs);
+ while (enumerator->enumerate(enumerator, &imv))
+ {
+ if (imv->get_id(imv))
{
found = TRUE;
+ *new_id = this->next_imv_id++;
+ imv->add_id(imv, *new_id);
+ DBG2(DBG_TNC, "additional ID %u reserved for IMV with primary ID %u",
+ *new_id, id);
break;
}
}
@@ -267,6 +293,31 @@ METHOD(imv_manager_t, set_message_types, TNC_Result,
return result;
}
+METHOD(imv_manager_t, set_message_types_long, TNC_Result,
+ private_tnc_imv_manager_t *this, TNC_IMVID id,
+ TNC_VendorIDList supported_vids,
+ TNC_MessageSubtypeList supported_subtypes,
+ TNC_UInt32 type_count)
+{
+ enumerator_t *enumerator;
+ imv_t *imv;
+ TNC_Result result = TNC_RESULT_FATAL;
+
+ enumerator = this->imvs->create_enumerator(this->imvs);
+ while (enumerator->enumerate(enumerator, &imv))
+ {
+ if (id == imv->get_id(imv))
+ {
+ imv->set_message_types_long(imv, supported_vids, supported_subtypes,
+ type_count);
+ result = TNC_RESULT_SUCCESS;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ return result;
+}
+
METHOD(imv_manager_t, solicit_recommendation, void,
private_tnc_imv_manager_t *this, TNC_ConnectionID id)
{
@@ -283,28 +334,52 @@ METHOD(imv_manager_t, solicit_recommendation, void,
METHOD(imv_manager_t, receive_message, void,
private_tnc_imv_manager_t *this, TNC_ConnectionID connection_id,
- TNC_BufferReference message,
- TNC_UInt32 message_len,
- TNC_MessageType message_type)
+ bool excl,
+ TNC_BufferReference msg,
+ TNC_UInt32 msg_len,
+ TNC_VendorID msg_vid,
+ TNC_MessageSubtype msg_subtype,
+ TNC_UInt32 src_imc_id,
+ TNC_UInt32 dst_imv_id)
{
bool type_supported = FALSE;
+ TNC_MessageType msg_type;
+ TNC_UInt32 msg_flags;
enumerator_t *enumerator;
imv_t *imv;
+ msg_type = (msg_vid << 8) | msg_subtype;
+
enumerator = this->imvs->create_enumerator(this->imvs);
while (enumerator->enumerate(enumerator, &imv))
{
- if (imv->receive_message && imv->type_supported(imv, message_type))
+ if (imv->type_supported(imv, msg_vid, msg_subtype) &&
+ (!excl || (excl && imv->has_id(imv, dst_imv_id)) ))
{
- type_supported = TRUE;
- imv->receive_message(imv->get_id(imv), connection_id,
- message, message_len, message_type);
+ if (imv->receive_message_long && src_imc_id)
+ {
+ type_supported = TRUE;
+ msg_flags = excl ? TNC_MESSAGE_FLAGS_EXCLUSIVE : 0;
+ imv->receive_message_long(imv->get_id(imv), connection_id,
+ msg_flags, msg, msg_len, msg_vid, msg_subtype,
+ src_imc_id, dst_imv_id);
+
+ }
+ else if (imv->receive_message && msg_vid <= TNC_VENDORID_ANY &&
+ msg_subtype <= TNC_SUBTYPE_ANY)
+ {
+ type_supported = TRUE;
+ msg_type = (msg_vid << 8) | msg_subtype;
+ imv->receive_message(imv->get_id(imv), connection_id,
+ msg, msg_len, msg_type);
+ }
}
}
enumerator->destroy(enumerator);
if (!type_supported)
{
- DBG2(DBG_TNC, "message type 0x%08x not supported by any IMV", message_type);
+ DBG2(DBG_TNC, "message type 0x%06x/0x%08x not supported by any IMV",
+ msg_vid, msg_subtype);
}
}
@@ -359,11 +434,13 @@ imv_manager_t* tnc_imv_manager_create(void)
.remove = _remove_, /* avoid name conflict with stdio.h */
.load = _load,
.is_registered = _is_registered,
+ .reserve_id = _reserve_id,
.get_recommendation_policy = _get_recommendation_policy,
.create_recommendations = _create_recommendations,
.enforce_recommendation = _enforce_recommendation,
.notify_connection_change = _notify_connection_change,
.set_message_types = _set_message_types,
+ .set_message_types_long = _set_message_types_long,
.solicit_recommendation = _solicit_recommendation,
.receive_message = _receive_message,
.batch_ending = _batch_ending,
diff --git a/src/libcharon/plugins/tnc_pdp/Makefile.am b/src/libcharon/plugins/tnc_pdp/Makefile.am
new file mode 100644
index 000000000..2d4c4d55a
--- /dev/null
+++ b/src/libcharon/plugins/tnc_pdp/Makefile.am
@@ -0,0 +1,24 @@
+
+INCLUDES = \
+ -I$(top_srcdir)/src/libstrongswan \
+ -I$(top_srcdir)/src/libhydra \
+ -I$(top_srcdir)/src/libcharon \
+ -I$(top_srcdir)/src/libradius
+
+AM_CFLAGS = -rdynamic
+
+if MONOLITHIC
+noinst_LTLIBRARIES = libstrongswan-tnc-pdp.la
+else
+plugin_LTLIBRARIES = libstrongswan-tnc-pdp.la
+libstrongswan_tnc_pdp_la_LIBADD = \
+ $(top_builddir)/src/libradius/libradius.la \
+ $(top_builddir)/src/libtls/libtls.la \
+ $(top_builddir)/src/libtnccs/libtnccs.la
+endif
+
+libstrongswan_tnc_pdp_la_SOURCES = \
+ tnc_pdp_plugin.h tnc_pdp_plugin.c \
+ tnc_pdp.h tnc_pdp.c tnc_pdp_connections.h tnc_pdp_connections.c
+
+libstrongswan_tnc_pdp_la_LDFLAGS = -module -avoid-version
diff --git a/src/libcharon/plugins/tnc_pdp/tnc_pdp.c b/src/libcharon/plugins/tnc_pdp/tnc_pdp.c
new file mode 100644
index 000000000..0625baa90
--- /dev/null
+++ b/src/libcharon/plugins/tnc_pdp/tnc_pdp.c
@@ -0,0 +1,648 @@
+/*
+ * 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.
+ */
+
+#include "tnc_pdp.h"
+#include "tnc_pdp_connections.h"
+
+#include <errno.h>
+#include <unistd.h>
+
+#include <radius_message.h>
+#include <radius_mppe.h>
+
+#include <daemon.h>
+#include <debug.h>
+#include <pen/pen.h>
+#include <threading/thread.h>
+#include <processing/jobs/callback_job.h>
+#include <sa/authenticators/eap/eap_method.h>
+
+typedef struct private_tnc_pdp_t private_tnc_pdp_t;
+
+/**
+ * Maximum size of a RADIUS IP packet
+ */
+#define MAX_PACKET 4096
+
+/**
+ * private data of tnc_pdp_t
+ */
+struct private_tnc_pdp_t {
+
+ /**
+ * implements tnc_pdp_t interface
+ */
+ tnc_pdp_t public;
+
+ /**
+ * ID of the server
+ */
+ identification_t *server;
+
+ /**
+ * EAP method type to be used
+ */
+ eap_type_t type;
+
+ /**
+ * IPv4 RADIUS socket
+ */
+ int ipv4;
+
+ /**
+ * IPv6 RADIUS socket
+ */
+ int ipv6;
+
+ /**
+ * Callback job dispatching commands
+ */
+ callback_job_t *job;
+
+ /**
+ * RADIUS shared secret
+ */
+ chunk_t secret;
+
+ /**
+ * MD5 hasher
+ */
+ hasher_t *hasher;
+
+ /**
+ * HMAC MD5 signer, with secret set
+ */
+ signer_t *signer;
+
+ /**
+ * Random number generator for MS-MPPE salt values
+ */
+ rng_t *rng;
+
+ /**
+ * List of registered TNC-PDP connections
+ */
+ tnc_pdp_connections_t *connections;
+};
+
+
+/**
+ * Open IPv4 or IPv6 UDP RADIUS socket
+ */
+static int open_socket(int family, u_int16_t port)
+{
+ int on = TRUE;
+ struct sockaddr_storage addr;
+ socklen_t addrlen;
+ int skt;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.ss_family = family;
+
+ /* precalculate constants depending on address family */
+ switch (family)
+ {
+ case AF_INET:
+ {
+ struct sockaddr_in *sin = (struct sockaddr_in *)&addr;
+
+ htoun32(&sin->sin_addr.s_addr, INADDR_ANY);
+ htoun16(&sin->sin_port, port);
+ addrlen = sizeof(struct sockaddr_in);
+ break;
+ }
+ case AF_INET6:
+ {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&addr;
+
+ memcpy(&sin6->sin6_addr, &in6addr_any, sizeof(in6addr_any));
+ htoun16(&sin6->sin6_port, port);
+ addrlen = sizeof(struct sockaddr_in6);
+ break;
+ }
+ default:
+ return 0;
+ }
+
+ /* open the socket */
+ skt = socket(family, SOCK_DGRAM, IPPROTO_UDP);
+ if (skt < 0)
+ {
+ DBG1(DBG_CFG, "opening RADIUS socket failed: %s", strerror(errno));
+ return 0;
+ }
+ if (setsockopt(skt, SOL_SOCKET, SO_REUSEADDR, (void*)&on, sizeof(on)) < 0)
+ {
+ DBG1(DBG_CFG, "unable to set SO_REUSEADDR on socket: %s", strerror(errno));
+ close(skt);
+ return 0;
+ }
+
+ /* bind the socket */
+ if (bind(skt, (struct sockaddr *)&addr, addrlen) < 0)
+ {
+ DBG1(DBG_CFG, "unable to bind RADIUS socket: %s", strerror(errno));
+ close(skt);
+ return 0;
+ }
+
+ return skt;
+}
+
+/**
+ * Send a RADIUS message to client
+ */
+static void send_message(private_tnc_pdp_t *this, radius_message_t *message,
+ host_t *client)
+{
+ int fd;
+ chunk_t data;
+
+ fd = (client->get_family(client) == AF_INET) ? this->ipv4 : this->ipv6;
+ data = message->get_encoding(message);
+
+ DBG2(DBG_CFG, "sending RADIUS packet to %#H", client);
+ DBG3(DBG_CFG, "%B", &data);
+
+ if (sendto(fd, data.ptr, data.len, 0, client->get_sockaddr(client),
+ *client->get_sockaddr_len(client)) != data.len)
+ {
+ DBG1(DBG_CFG, "sending RADIUS message failed: %s", strerror(errno));
+ }
+}
+
+/**
+ * Encrypt a MS-MPPE-Send/Recv-Key
+ */
+static chunk_t encrypt_mppe_key(private_tnc_pdp_t *this, u_int8_t type,
+ chunk_t key, u_int16_t *salt,
+ radius_message_t *request)
+{
+ chunk_t a, r, seed, data;
+ u_char b[HASH_SIZE_MD5], *c;
+ mppe_key_t *mppe_key;
+
+ /**
+ * From RFC2548 (encryption):
+ * b(1) = MD5(S + R + A) c(1) = p(1) xor b(1) C = c(1)
+ * b(2) = MD5(S + c(1)) c(2) = p(2) xor b(2) C = C + c(2)
+ * . . .
+ * b(i) = MD5(S + c(i-1)) c(i) = p(i) xor b(i) C = C + c(i)
+ */
+
+ data = chunk_alloc(sizeof(mppe_key_t) +
+ HASH_SIZE_MD5 * (1 + key.len / HASH_SIZE_MD5));
+ memset(data.ptr, 0x00, data.len);
+
+ mppe_key = (mppe_key_t*)data.ptr;
+ mppe_key->id = htonl(PEN_MICROSOFT);
+ mppe_key->type = type;
+ mppe_key->length = data.len - sizeof(mppe_key->id);
+ mppe_key->key[0] = key.len;
+
+ memcpy(&mppe_key->key[1], key.ptr, key.len);
+
+ /**
+ * generate a 16 bit unique random salt value for the MPPE stream cipher
+ * the MSB of the salt MUST be set to 1
+ */
+ a = chunk_create((u_char*)&(mppe_key->salt), sizeof(mppe_key->salt));
+ do
+ {
+ this->rng->get_bytes(this->rng, a.len, a.ptr);
+ *a.ptr |= 0x80;
+ }
+ while (mppe_key->salt == *salt);
+
+ /* update the salt value */
+ *salt = mppe_key->salt;
+
+ r = chunk_create(request->get_authenticator(request), HASH_SIZE_MD5);
+ seed = chunk_cata("cc", r, a);
+
+ c = mppe_key->key;
+ while (c < data.ptr + data.len)
+ {
+ /* b(i) = MD5(S + c(i-1)) */
+ this->hasher->get_hash(this->hasher, this->secret, NULL);
+ this->hasher->get_hash(this->hasher, seed, b);
+
+ /* c(i) = b(i) xor p(1) */
+ memxor(c, b, HASH_SIZE_MD5);
+
+ /* prepare next round */
+ seed = chunk_create(c, HASH_SIZE_MD5);
+ c += HASH_SIZE_MD5;
+ }
+
+ return data;
+}
+
+/**
+ * Send a RADIUS response for a request
+ */
+static void send_response(private_tnc_pdp_t *this, radius_message_t *request,
+ radius_message_code_t code, eap_payload_t *eap,
+ identification_t *group, chunk_t msk, host_t *client)
+{
+ radius_message_t *response;
+ chunk_t data, recv, send;
+ u_int32_t tunnel_type;
+ u_int16_t salt = 0;
+
+ response = radius_message_create(code);
+ if (eap)
+ {
+ data = eap->get_data(eap);
+ DBG3(DBG_CFG, "%N payload %B", eap_type_names, this->type, &data);
+
+ /* fragment data suitable for RADIUS */
+ while (data.len > MAX_RADIUS_ATTRIBUTE_SIZE)
+ {
+ response->add(response, RAT_EAP_MESSAGE,
+ chunk_create(data.ptr, MAX_RADIUS_ATTRIBUTE_SIZE));
+ data = chunk_skip(data, MAX_RADIUS_ATTRIBUTE_SIZE);
+ }
+ response->add(response, RAT_EAP_MESSAGE, data);
+ }
+ if (group)
+ {
+ tunnel_type = RADIUS_TUNNEL_TYPE_ESP;
+ htoun32(data.ptr, tunnel_type);
+ data.len = sizeof(tunnel_type);
+ response->add(response, RAT_TUNNEL_TYPE, data);
+ response->add(response, RAT_FILTER_ID, group->get_encoding(group));
+ }
+ if (msk.len)
+ {
+ recv = chunk_create(msk.ptr, msk.len / 2);
+ data = encrypt_mppe_key(this, MS_MPPE_RECV_KEY, recv, &salt, request);
+ response->add(response, RAT_VENDOR_SPECIFIC, data);
+ chunk_free(&data);
+
+ send = chunk_create(msk.ptr + recv.len, msk.len - recv.len);
+ data = encrypt_mppe_key(this, MS_MPPE_SEND_KEY, send, &salt, request);
+ response->add(response, RAT_VENDOR_SPECIFIC, data);
+ chunk_free(&data);
+ }
+ response->set_identifier(response, request->get_identifier(request));
+ response->sign(response, request->get_authenticator(request),
+ this->secret, this->hasher, this->signer, NULL, TRUE);
+
+ DBG1(DBG_CFG, "sending RADIUS %N to client '%H'", radius_message_code_names,
+ code, client);
+ send_message(this, response, client);
+ response->destroy(response);
+}
+
+/**
+ * Process EAP message
+ */
+static void process_eap(private_tnc_pdp_t *this, radius_message_t *request,
+ host_t *source)
+{
+ enumerator_t *enumerator;
+ eap_payload_t *in, *out = NULL;
+ eap_method_t *method;
+ eap_type_t eap_type;
+ u_int32_t eap_vendor;
+ chunk_t data, message = chunk_empty, msk = chunk_empty;
+ chunk_t user_name = chunk_empty, nas_id = chunk_empty;
+ identification_t *group = NULL;
+ radius_message_code_t code = RMC_ACCESS_CHALLENGE;
+ int type;
+
+ enumerator = request->create_enumerator(request);
+ while (enumerator->enumerate(enumerator, &type, &data))
+ {
+ switch (type)
+ {
+ case RAT_USER_NAME:
+ user_name = data;
+ break;
+ case RAT_NAS_IDENTIFIER:
+ nas_id = data;
+ break;
+ case RAT_EAP_MESSAGE:
+ if (data.len)
+ {
+ message = chunk_cat("mc", message, data);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ if (message.len)
+ {
+ in = eap_payload_create_data(message);
+
+ /* apply EAP method selected by RADIUS server */
+ eap_type = in->get_type(in, &eap_vendor);
+
+ DBG3(DBG_CFG, "%N payload %B", eap_type_names, eap_type, &message);
+
+ if (eap_type == EAP_IDENTITY)
+ {
+ identification_t *peer;
+ chunk_t eap_identity;
+
+ if (message.len < 5)
+ {
+ goto end;
+ }
+ eap_identity = chunk_create(message.ptr + 5, message.len - 5);
+ peer = identification_create_from_data(eap_identity);
+ method = charon->eap->create_instance(charon->eap, this->type,
+ 0, EAP_SERVER, this->server, peer);
+ if (!method)
+ {
+ peer->destroy(peer);
+ goto end;
+ }
+ this->connections->add(this->connections, nas_id, user_name, peer,
+ method);
+ method->initiate(method, &out);
+ }
+ else
+ {
+ ike_sa_t *ike_sa;
+ auth_cfg_t *auth;
+ auth_rule_t type;
+ identification_t *data;
+ enumerator_t *e;
+
+ method = this->connections->get_state(this->connections, nas_id,
+ user_name, &ike_sa);
+ if (!method)
+ {
+ goto end;
+ }
+ charon->bus->set_sa(charon->bus, ike_sa);
+
+ switch (method->process(method, in, &out))
+ {
+ case NEED_MORE:
+ code = RMC_ACCESS_CHALLENGE;
+ break;
+ case SUCCESS:
+ code = RMC_ACCESS_ACCEPT;
+ method->get_msk(method, &msk);
+ auth = ike_sa->get_auth_cfg(ike_sa, FALSE);
+ e = auth->create_enumerator(auth);
+ while (e->enumerate(e, &type, &data))
+ {
+ /* look for group memberships */
+ if (type == AUTH_RULE_GROUP)
+ {
+ group = data;
+ }
+ }
+ e->destroy(e);
+
+ DESTROY_IF(out);
+ out = eap_payload_create_code(EAP_SUCCESS,
+ in->get_identifier(in));
+ break;
+ case FAILED:
+ default:
+ code = RMC_ACCESS_REJECT;
+ DESTROY_IF(out);
+ out = eap_payload_create_code(EAP_FAILURE,
+ in->get_identifier(in));
+ }
+ charon->bus->set_sa(charon->bus, NULL);
+ }
+
+ send_response(this, request, code, out, group, msk, source);
+ out->destroy(out);
+
+ if (code == RMC_ACCESS_ACCEPT || code == RMC_ACCESS_REJECT)
+ {
+ this->connections->remove(this->connections, nas_id, user_name);
+ }
+
+end:
+ free(message.ptr);
+ in->destroy(in);
+ }
+}
+
+/**
+ * Process packets received on the RADIUS socket
+ */
+static job_requeue_t receive(private_tnc_pdp_t *this)
+{
+ while (TRUE)
+ {
+ radius_message_t *request;
+ char buffer[MAX_PACKET];
+ int max_fd = 0, selected = 0, bytes_read = 0;
+ fd_set rfds;
+ bool oldstate;
+ host_t *source;
+ struct msghdr msg;
+ struct iovec iov;
+ union {
+ struct sockaddr_in in4;
+ struct sockaddr_in6 in6;
+ } src;
+
+ FD_ZERO(&rfds);
+
+ if (this->ipv4)
+ {
+ FD_SET(this->ipv4, &rfds);
+ }
+ if (this->ipv6)
+ {
+ FD_SET(this->ipv6, &rfds);
+ }
+ max_fd = max(this->ipv4, this->ipv6);
+
+ DBG2(DBG_CFG, "waiting for data on RADIUS sockets");
+ oldstate = thread_cancelability(TRUE);
+ if (select(max_fd + 1, &rfds, NULL, NULL, NULL) <= 0)
+ {
+ thread_cancelability(oldstate);
+ continue;
+ }
+ thread_cancelability(oldstate);
+
+ if (FD_ISSET(this->ipv4, &rfds))
+ {
+ selected = this->ipv4;
+ }
+ else if (FD_ISSET(this->ipv6, &rfds))
+ {
+ selected = this->ipv6;
+ }
+ else
+ {
+ /* oops, shouldn't happen */
+ continue;
+ }
+
+ /* read received packet */
+ msg.msg_name = &src;
+ msg.msg_namelen = sizeof(src);
+ iov.iov_base = buffer;
+ iov.iov_len = MAX_PACKET;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_flags = 0;
+
+ bytes_read = recvmsg(selected, &msg, 0);
+ if (bytes_read < 0)
+ {
+ DBG1(DBG_CFG, "error reading RADIUS socket: %s", strerror(errno));
+ continue;
+ }
+ if (msg.msg_flags & MSG_TRUNC)
+ {
+ DBG1(DBG_CFG, "receive buffer too small, RADIUS packet discarded");
+ continue;
+ }
+ source = host_create_from_sockaddr((sockaddr_t*)&src);
+ DBG2(DBG_CFG, "received RADIUS packet from %#H", source);
+ DBG3(DBG_CFG, "%b", buffer, bytes_read);
+ request = radius_message_parse(chunk_create(buffer, bytes_read));
+ if (request)
+ {
+ DBG1(DBG_CFG, "received RADIUS %N from client '%H'",
+ radius_message_code_names, request->get_code(request), source);
+
+ if (request->verify(request, NULL, this->secret, this->hasher,
+ this->signer))
+ {
+ process_eap(this, request, source);
+ }
+ request->destroy(request);
+
+ }
+ else
+ {
+ DBG1(DBG_CFG, "received invalid RADIUS message, ignored");
+ }
+ source->destroy(source);
+ }
+ return JOB_REQUEUE_FAIR;
+}
+
+METHOD(tnc_pdp_t, destroy, void,
+ private_tnc_pdp_t *this)
+{
+ if (this->job)
+ {
+ this->job->cancel(this->job);
+ }
+ if (this->ipv4)
+ {
+ close(this->ipv4);
+ }
+ if (this->ipv6)
+ {
+ close(this->ipv6);
+ }
+ DESTROY_IF(this->server);
+ DESTROY_IF(this->signer);
+ DESTROY_IF(this->hasher);
+ DESTROY_IF(this->rng);
+ DESTROY_IF(this->connections);
+ free(this);
+}
+
+/*
+ * see header file
+ */
+tnc_pdp_t *tnc_pdp_create(u_int16_t port)
+{
+ private_tnc_pdp_t *this;
+ char *secret, *server, *eap_type_str;
+
+ INIT(this,
+ .public = {
+ .destroy = _destroy,
+ },
+ .ipv4 = open_socket(AF_INET, port),
+ .ipv6 = open_socket(AF_INET6, port),
+ .hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5),
+ .signer = lib->crypto->create_signer(lib->crypto, AUTH_HMAC_MD5_128),
+ .rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK),
+ .connections = tnc_pdp_connections_create(),
+ );
+
+ if (!this->hasher || !this->signer || !this->rng)
+ {
+ DBG1(DBG_CFG, "RADIUS initialization failed, HMAC/MD5/RNG required");
+ destroy(this);
+ return NULL;
+ }
+ if (!this->ipv4 && !this->ipv6)
+ {
+ DBG1(DBG_NET, "could not create any RADIUS sockets");
+ destroy(this);
+ return NULL;
+ }
+ if (!this->ipv4)
+ {
+ DBG1(DBG_NET, "could not open IPv4 RADIUS socket, IPv4 disabled");
+ }
+ if (!this->ipv6)
+ {
+ DBG1(DBG_NET, "could not open IPv6 RADIUS socket, IPv6 disabled");
+ }
+
+ server = lib->settings->get_str(lib->settings,
+ "charon.plugins.tnc-pdp.server", NULL);
+ if (!server)
+ {
+ DBG1(DBG_CFG, "missing PDP server name, PDP disabled");
+ destroy(this);
+ return NULL;
+ }
+ this->server = identification_create_from_string(server);
+
+ secret = lib->settings->get_str(lib->settings,
+ "charon.plugins.tnc-pdp.secret", NULL);
+ if (!secret)
+ {
+ DBG1(DBG_CFG, "missing RADIUS secret, PDP disabled");
+ destroy(this);
+ return NULL;
+ }
+ this->secret = chunk_create(secret, strlen(secret));
+ this->signer->set_key(this->signer, this->secret);
+
+ eap_type_str = lib->settings->get_str(lib->settings,
+ "charon.plugins.tnc-pdp.method", "ttls");
+ this->type = eap_type_from_string(eap_type_str);
+ if (this->type == 0)
+ {
+ DBG1(DBG_CFG, "unrecognized eap method \"%s\"", eap_type_str);
+ destroy(this);
+ return NULL;
+ }
+ DBG1(DBG_IKE, "eap method %N selected", eap_type_names, this->type);
+
+ this->job = callback_job_create_with_prio((callback_job_cb_t)receive,
+ this, NULL, NULL, JOB_PRIO_CRITICAL);
+ lib->processor->queue_job(lib->processor, (job_t*)this->job);
+
+ return &this->public;
+}
+
diff --git a/src/libcharon/plugins/tnc_pdp/tnc_pdp.h b/src/libcharon/plugins/tnc_pdp/tnc_pdp.h
new file mode 100644
index 000000000..e769353b7
--- /dev/null
+++ b/src/libcharon/plugins/tnc_pdp/tnc_pdp.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2011 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 tnc_pdp tnc_pdp
+ * @{ @ingroup tnc_pdp
+ */
+
+#ifndef TNC_PDP_H_
+#define TNC_PDP_H_
+
+typedef struct tnc_pdp_t tnc_pdp_t;
+
+#include <library.h>
+
+/**
+ * Public interface of a TNC Policy Decision Point object
+ */
+struct tnc_pdp_t {
+
+ /**
+ * implements plugin interface
+ */
+ void (*destroy)(tnc_pdp_t *this);
+};
+
+/**
+ * Create a TNC PDP instance
+ *
+ * @param port RADIUS port of TNC PDP
+ */
+tnc_pdp_t* tnc_pdp_create(u_int16_t port);
+
+#endif /** TNC_PDP_PLUGIN_H_ @}*/
diff --git a/src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.c b/src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.c
new file mode 100644
index 000000000..175a57aba
--- /dev/null
+++ b/src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.c
@@ -0,0 +1,220 @@
+/*
+ * 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.
+ */
+
+#include "tnc_pdp_connections.h"
+
+#include <utils/linked_list.h>
+#include <debug.h>
+
+typedef struct private_tnc_pdp_connections_t private_tnc_pdp_connections_t;
+typedef struct entry_t entry_t;
+
+/**
+ * Private data of tnc_pdp_connections_t
+ */
+struct private_tnc_pdp_connections_t {
+
+ /**
+ * Implements tnc_pdp_connections_t interface
+ */
+ tnc_pdp_connections_t public;
+
+ /**
+ * List of TNC PEP RADIUS Connections
+ */
+ linked_list_t *list;
+};
+
+/**
+ * Data entry for a TNC PEP RADIUS connection
+ */
+struct entry_t {
+
+ /**
+ * NAS identifier of PEP
+ */
+ chunk_t nas_id;
+
+ /**
+ * User name of TNC Client
+ */
+ chunk_t user_name;
+
+ /**
+ * EAP method state
+ */
+ eap_method_t *method;
+
+ /**
+ * IKE SA used for bus communication
+ */
+ ike_sa_t *ike_sa;
+};
+
+/**
+ * Free the memory allocated to a data entry
+ */
+static void free_entry(entry_t *this)
+{
+ this->method->destroy(this->method);
+ this->ike_sa->destroy(this->ike_sa);
+ free(this->nas_id.ptr);
+ free(this->user_name.ptr);
+ free(this);
+}
+
+/**
+ * Find a matching data entry
+ */
+static bool equals_entry( entry_t *this, chunk_t nas_id, chunk_t user_name)
+{
+ bool no_nas_id = !this->nas_id.ptr && !nas_id.ptr;
+
+ return (chunk_equals(this->nas_id, nas_id) || no_nas_id) &&
+ chunk_equals(this->user_name, user_name);
+}
+
+/**
+ * Find a matching data entry
+ */
+static void dbg_nas_user(chunk_t nas_id, chunk_t user_name, bool not, char *op)
+{
+ if (nas_id.len)
+ {
+ DBG1(DBG_CFG, "%s RADIUS connection for user '%.*s' NAS '%.*s'",
+ not ? "could not find" : op, user_name.len, user_name.ptr,
+ nas_id.len, nas_id.ptr);
+ }
+ else
+ {
+ DBG1(DBG_CFG, "%s RADIUS connection for user '%.*s'",
+ not ? "could not find" : op, user_name.len, user_name.ptr);
+ }
+}
+
+METHOD(tnc_pdp_connections_t, add, void,
+ private_tnc_pdp_connections_t *this, chunk_t nas_id, chunk_t user_name,
+ identification_t *peer, eap_method_t *method)
+{
+ enumerator_t *enumerator;
+ entry_t *entry;
+ ike_sa_id_t *ike_sa_id;
+ ike_sa_t *ike_sa;
+ bool found = FALSE;
+
+ ike_sa_id = ike_sa_id_create(0, 0, FALSE);
+ ike_sa = ike_sa_create(ike_sa_id);
+ ike_sa_id->destroy(ike_sa_id);
+ ike_sa->set_other_id(ike_sa, peer);
+
+ enumerator = this->list->create_enumerator(this->list);
+ while (enumerator->enumerate(enumerator, &entry))
+ {
+ if (equals_entry(entry, nas_id, user_name))
+ {
+ found = TRUE;
+ entry->method->destroy(entry->method);
+ entry->ike_sa->destroy(entry->ike_sa);
+ DBG1(DBG_CFG, "removed stale RADIUS connection");
+ entry->method = method;
+ entry->ike_sa = ike_sa;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ if (!found)
+ {
+ entry = malloc_thing(entry_t);
+ entry->nas_id = chunk_clone(nas_id);
+ entry->user_name = chunk_clone(user_name);
+ entry->method = method;
+ entry->ike_sa = ike_sa;
+ this->list->insert_last(this->list, entry);
+ }
+ dbg_nas_user(nas_id, user_name, FALSE, "created");
+}
+
+METHOD(tnc_pdp_connections_t, remove_, void,
+ private_tnc_pdp_connections_t *this, chunk_t nas_id, chunk_t user_name)
+{
+ enumerator_t *enumerator;
+ entry_t *entry;
+
+ enumerator = this->list->create_enumerator(this->list);
+ while (enumerator->enumerate(enumerator, &entry))
+ {
+ if (equals_entry(entry, nas_id, user_name))
+ {
+ free_entry(entry);
+ this->list->remove_at(this->list, enumerator);
+ dbg_nas_user(nas_id, user_name, FALSE, "removed");
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+}
+
+METHOD(tnc_pdp_connections_t, get_state, eap_method_t*,
+ private_tnc_pdp_connections_t *this, chunk_t nas_id, chunk_t user_name,
+ ike_sa_t **ike_sa)
+{
+ enumerator_t *enumerator;
+ entry_t *entry;
+ eap_method_t *found = NULL;
+
+ enumerator = this->list->create_enumerator(this->list);
+ while (enumerator->enumerate(enumerator, &entry))
+ {
+ if (equals_entry(entry, nas_id, user_name))
+ {
+ found = entry->method;
+ *ike_sa = entry->ike_sa;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ dbg_nas_user(nas_id, user_name, !found, "found");
+ return found;
+}
+
+METHOD(tnc_pdp_connections_t, destroy, void,
+ private_tnc_pdp_connections_t *this)
+{
+ this->list->destroy_function(this->list, (void*)free_entry);
+ free(this);
+}
+
+/*
+ * see header file
+ */
+tnc_pdp_connections_t *tnc_pdp_connections_create(void)
+{
+ private_tnc_pdp_connections_t *this;
+
+ INIT(this,
+ .public = {
+ .add = _add,
+ .remove = _remove_,
+ .get_state = _get_state,
+ .destroy = _destroy,
+ },
+ .list = linked_list_create(),
+ );
+
+ return &this->public;
+}
+
diff --git a/src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.h b/src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.h
new file mode 100644
index 000000000..b9f5d097b
--- /dev/null
+++ b/src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.h
@@ -0,0 +1,77 @@
+/*
+ * 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 tnc_pdp_connections tnc_pdp_connections
+ * @{ @ingroup tnc_pdp
+ */
+
+#ifndef TNC_PDP_CONNECTIONS_H_
+#define TNC_PDP_CONNECTIONS_H_
+
+typedef struct tnc_pdp_connections_t tnc_pdp_connections_t;
+
+#include <library.h>
+#include <sa/ike_sa.h>
+#include <sa/authenticators/eap/eap_method.h>
+
+/**
+ * Public interface of a tnc_pdp_connections object
+ */
+struct tnc_pdp_connections_t {
+
+ /**
+ * Register a new TNC PEP RADIUS Connection
+ *
+ * @param nas_id NAS identifier of Policy Enforcement Point
+ * @param user_name User name of TNC Client
+ * @param peer Peer identity
+ * @param method EAP method state for this TNC PEP Connection
+ */
+ void (*add)(tnc_pdp_connections_t *this, chunk_t nas_id, chunk_t user_name,
+ identification_t *peer, eap_method_t *method);
+
+ /**
+ * Remove a TNC PEP RADIUS Connection
+ *
+ * @param nas_id NAS identifier of Policy Enforcement Point
+ * @param user_name User name of TNC Client
+ */
+ void (*remove)(tnc_pdp_connections_t *this, chunk_t nas_id,
+ chunk_t user_name);
+
+ /**
+ * Get the EAP method and IKE_SA of a registered TNC PEP RADIUS Connection
+ *
+ * @param nas_id NAS identifier of Policy Enforcement Point
+ * @param user_name User name of TNC Client
+ * @param ike_sa IKE_SA used for bus communication only
+ * @return EAP method for this connection or NULL if not found
+ */
+ eap_method_t* (*get_state)(tnc_pdp_connections_t *this, chunk_t nas_id,
+ chunk_t user_name, ike_sa_t **ike_sa);
+
+ /**
+ * Destroys a tnc_pdp_connections_t object.
+ */
+ void (*destroy)(tnc_pdp_connections_t *this);
+};
+
+/**
+ * Create a tnc_pdp_connections_t instance
+ */
+tnc_pdp_connections_t* tnc_pdp_connections_create(void);
+
+#endif /** TNC_PDP_CONNECTIONS_PLUGIN_H_ @}*/
diff --git a/src/libcharon/plugins/tnc_pdp/tnc_pdp_plugin.c b/src/libcharon/plugins/tnc_pdp/tnc_pdp_plugin.c
new file mode 100644
index 000000000..9abe02aec
--- /dev/null
+++ b/src/libcharon/plugins/tnc_pdp/tnc_pdp_plugin.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2010 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 "tnc_pdp_plugin.h"
+#include "tnc_pdp.h"
+
+typedef struct private_tnc_pdp_plugin_t private_tnc_pdp_plugin_t;
+
+/**
+ * Default RADIUS port, when not configured
+ */
+#define RADIUS_PORT 1812
+
+/**
+ * private data of tnc_pdp plugin
+ */
+struct private_tnc_pdp_plugin_t {
+
+ /**
+ * implements plugin interface
+ */
+ tnc_pdp_plugin_t public;
+
+ /**
+ * Policy Decision Point object
+ */
+ tnc_pdp_t *pdp;
+
+};
+
+METHOD(plugin_t, get_name, char*,
+ private_tnc_pdp_plugin_t *this)
+{
+ return "tnc-pdp";
+}
+
+METHOD(plugin_t, get_features, int,
+ private_tnc_pdp_plugin_t *this, plugin_feature_t *features[])
+{
+ static plugin_feature_t f[] = {
+ PLUGIN_PROVIDE(CUSTOM, "tnc-pdp"),
+ PLUGIN_DEPENDS(CUSTOM, "imv-manager"),
+ };
+ *features = f;
+ return countof(f);
+}
+
+METHOD(plugin_t, destroy, void,
+ private_tnc_pdp_plugin_t *this)
+{
+ DESTROY_IF(this->pdp);
+ free(this);
+}
+
+/*
+ * see header file
+ */
+plugin_t *tnc_pdp_plugin_create()
+{
+ private_tnc_pdp_plugin_t *this;
+ int port;
+
+ port = lib->settings->get_int(lib->settings,
+ "charon.plugins.tnc_pdp.port", RADIUS_PORT);
+
+ INIT(this,
+ .public = {
+ .plugin = {
+ .get_name = _get_name,
+ .get_features = _get_features,
+ .destroy = _destroy,
+ },
+ },
+ .pdp = tnc_pdp_create(port),
+ );
+
+ return &this->public.plugin;
+}
+
diff --git a/src/libcharon/plugins/tnc_pdp/tnc_pdp_plugin.h b/src/libcharon/plugins/tnc_pdp/tnc_pdp_plugin.h
new file mode 100644
index 000000000..9b8b9ff0e
--- /dev/null
+++ b/src/libcharon/plugins/tnc_pdp/tnc_pdp_plugin.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2011 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 tnc_pdp tnc_pdp
+ * @ingroup cplugins
+ *
+ * @defgroup tnc_pdp_plugin tnc_pdp_plugin
+ * @{ @ingroup tnc_pdp
+ */
+
+#ifndef TNC_PDP_PLUGIN_H_
+#define TNC_PDP_PLUGIN_H_
+
+#include <plugins/plugin.h>
+
+typedef struct tnc_pdp_plugin_t tnc_pdp_plugin_t;
+
+/**
+ * TNC-PDP plugin
+ */
+struct tnc_pdp_plugin_t {
+
+ /**
+ * implements plugin interface
+ */
+ plugin_t plugin;
+};
+
+#endif /** TNC_PDP_PLUGIN_H_ @}*/
diff --git a/src/libcharon/plugins/tnc_tnccs/tnc_tnccs_manager.c b/src/libcharon/plugins/tnc_tnccs/tnc_tnccs_manager.c
index f007ce19f..64ed160d9 100644
--- a/src/libcharon/plugins/tnc_tnccs/tnc_tnccs_manager.c
+++ b/src/libcharon/plugins/tnc_tnccs/tnc_tnccs_manager.c
@@ -55,6 +55,11 @@ struct tnccs_connection_entry_t {
TNC_ConnectionID id;
/**
+ * TNCCS protocol type
+ */
+ tnccs_type_t type;
+
+ /**
* TNCCS instance
*/
tnccs_t *tnccs;
@@ -174,13 +179,14 @@ METHOD(tnccs_manager_t, create_instance, tnccs_t*,
}
METHOD(tnccs_manager_t, create_connection, TNC_ConnectionID,
- private_tnc_tnccs_manager_t *this, tnccs_t *tnccs,
+ private_tnc_tnccs_manager_t *this, tnccs_type_t type, tnccs_t *tnccs,
tnccs_send_message_t send_message, bool* request_handshake_retry,
recommendations_t **recs)
{
tnccs_connection_entry_t *entry;
entry = malloc_thing(tnccs_connection_entry_t);
+ entry->type = type;
entry->tnccs = tnccs;
entry->send_message = send_message;
entry->request_handshake_retry = request_handshake_retry;
@@ -295,24 +301,22 @@ METHOD(tnccs_manager_t, request_handshake_retry, TNC_Result,
METHOD(tnccs_manager_t, send_message, TNC_Result,
private_tnc_tnccs_manager_t *this, TNC_IMCID imc_id, TNC_IMVID imv_id,
TNC_ConnectionID id,
+ TNC_UInt32 msg_flags,
TNC_BufferReference msg,
TNC_UInt32 msg_len,
- TNC_MessageType msg_type)
+ TNC_VendorID msg_vid,
+ TNC_MessageSubtype msg_subtype)
{
enumerator_t *enumerator;
tnccs_connection_entry_t *entry;
tnccs_send_message_t send_message = NULL;
tnccs_t *tnccs = NULL;
- TNC_VendorID msg_vid;
- TNC_MessageSubtype msg_subtype;
-
- msg_vid = (msg_type >> 8) & TNC_VENDORID_ANY;
- msg_subtype = msg_type & TNC_SUBTYPE_ANY;
if (msg_vid == TNC_VENDORID_ANY || msg_subtype == TNC_SUBTYPE_ANY)
{
- DBG1(DBG_TNC, "not sending message of invalid type 0x%08x", msg_type);
+ DBG1(DBG_TNC, "not sending message of invalid type 0x%02x/0x%08x",
+ msg_vid, msg_subtype);
return TNC_RESULT_INVALID_PARAMETER;
}
@@ -332,7 +336,8 @@ METHOD(tnccs_manager_t, send_message, TNC_Result,
if (tnccs && send_message)
{
- return send_message(tnccs, imc_id, imv_id, msg, msg_len, msg_type);
+ return send_message(tnccs, imc_id, imv_id, msg_flags, msg, msg_len,
+ msg_vid, msg_subtype);
}
return TNC_RESULT_FATAL;
}
@@ -368,20 +373,150 @@ METHOD(tnccs_manager_t, provide_recommendation, TNC_Result,
return TNC_RESULT_FATAL;
}
+/**
+ * Write the value of a boolean attribute into the buffer
+ */
+static TNC_Result bool_attribute(TNC_UInt32 buffer_len,
+ TNC_BufferReference buffer,
+ TNC_UInt32 *value_len,
+ bool value)
+{
+ *value_len = 1;
+
+ if (buffer && buffer_len > 0)
+ {
+ *buffer = value ? 0x01 : 0x00;
+ return TNC_RESULT_SUCCESS;
+ }
+ else
+ {
+ return TNC_RESULT_INVALID_PARAMETER;
+ }
+}
+
+/**
+ * Write the value of an u_int32_t attribute into the buffer
+ */
+static TNC_Result uint_attribute(TNC_UInt32 buffer_len,
+ TNC_BufferReference buffer,
+ TNC_UInt32 *value_len,
+ u_int32_t value)
+{
+ *value_len = sizeof(u_int32_t);
+
+ if (buffer && buffer_len >= *value_len)
+ {
+ htoun32(buffer, value);
+ return TNC_RESULT_SUCCESS;
+ }
+ else
+ {
+ return TNC_RESULT_INVALID_PARAMETER;
+ }
+}
+
+/**
+ * Write the value of string attribute into the buffer
+ */
+static TNC_Result str_attribute(TNC_UInt32 buffer_len,
+ TNC_BufferReference buffer,
+ TNC_UInt32 *value_len,
+ char *value)
+{
+ *value_len = 1 + strlen(value);
+
+ if (buffer && buffer_len >= *value_len)
+ {
+ snprintf(buffer, buffer_len, "%s", value);
+ return TNC_RESULT_SUCCESS;
+ }
+ else
+ {
+ return TNC_RESULT_INVALID_PARAMETER;
+ }
+}
+
METHOD(tnccs_manager_t, get_attribute, TNC_Result,
- private_tnc_tnccs_manager_t *this, TNC_IMVID imv_id,
+ private_tnc_tnccs_manager_t *this, bool is_imc,
+ TNC_UInt32 imcv_id,
TNC_ConnectionID id,
TNC_AttributeID attribute_id,
TNC_UInt32 buffer_len,
TNC_BufferReference buffer,
- TNC_UInt32 *out_value_len)
+ TNC_UInt32 *value_len)
{
enumerator_t *enumerator;
tnccs_connection_entry_t *entry;
- recommendations_t *recs = NULL;
+ bool attribute_match = FALSE, entry_found = FALSE;
+
+ if (is_imc)
+ {
+ switch (attribute_id)
+ {
+ /* these attributes are unsupported */
+ case TNC_ATTRIBUTEID_SOHR:
+ case TNC_ATTRIBUTEID_SSOHR:
+ return TNC_RESULT_INVALID_PARAMETER;
+
+ /* these attributes are supported */
+ case TNC_ATTRIBUTEID_PRIMARY_IMC_ID:
+ attribute_match = TRUE;
+ break;
+
+ /* these attributes are yet to be matched */
+ default:
+ break;
+ }
+ }
+ else
+ {
+ switch (attribute_id)
+ {
+ /* these attributes are unsupported or invalid */
+ case TNC_ATTRIBUTEID_REASON_STRING:
+ case TNC_ATTRIBUTEID_REASON_LANGUAGE:
+ case TNC_ATTRIBUTEID_SOH:
+ case TNC_ATTRIBUTEID_SSOH:
+ return TNC_RESULT_INVALID_PARAMETER;
+
+ /* these attributes are supported */
+ case TNC_ATTRIBUTEID_PRIMARY_IMV_ID:
+ attribute_match = TRUE;
+ break;
+
+ /* these attributes are yet to be matched */
+ default:
+ break;
+ }
+ }
+
+ if (!attribute_match)
+ {
+ switch (attribute_id)
+ {
+ /* these attributes are supported */
+ case TNC_ATTRIBUTEID_PREFERRED_LANGUAGE:
+ case TNC_ATTRIBUTEID_MAX_ROUND_TRIPS:
+ case TNC_ATTRIBUTEID_MAX_MESSAGE_SIZE:
+ case TNC_ATTRIBUTEID_HAS_LONG_TYPES:
+ case TNC_ATTRIBUTEID_HAS_EXCLUSIVE:
+ case TNC_ATTRIBUTEID_HAS_SOH:
+ case TNC_ATTRIBUTEID_IFTNCCS_PROTOCOL:
+ case TNC_ATTRIBUTEID_IFTNCCS_VERSION:
+ case TNC_ATTRIBUTEID_IFT_PROTOCOL:
+ case TNC_ATTRIBUTEID_IFT_VERSION:
+ break;
- if (id == TNC_CONNECTIONID_ANY ||
- attribute_id != TNC_ATTRIBUTEID_PREFERRED_LANGUAGE)
+ /* these attributes are unsupported or unknown */
+ case TNC_ATTRIBUTEID_DHPN:
+ case TNC_ATTRIBUTEID_TLS_UNIQUE:
+ default:
+ return TNC_RESULT_INVALID_PARAMETER;
+ }
+ }
+
+ /* attributes specific to the TNCC or TNCS are unsupported */
+ if (id == TNC_CONNECTIONID_ANY)
{
return TNC_RESULT_INVALID_PARAMETER;
}
@@ -392,34 +527,104 @@ METHOD(tnccs_manager_t, get_attribute, TNC_Result,
{
if (id == entry->id)
{
- recs = entry->recs;
+ entry_found = TRUE;
break;
}
}
enumerator->destroy(enumerator);
this->connection_lock->unlock(this->connection_lock);
- if (recs)
+ if (!entry_found)
{
- chunk_t pref_lang;
+ return TNC_RESULT_INVALID_PARAMETER;
+ }
- pref_lang = recs->get_preferred_language(recs);
- if (pref_lang.len == 0)
+ switch (attribute_id)
+ {
+ case TNC_ATTRIBUTEID_PREFERRED_LANGUAGE:
{
- return TNC_RESULT_INVALID_PARAMETER;
+ recommendations_t *recs;
+ chunk_t pref_lang;
+
+ recs = entry->recs;
+ if (!recs)
+ {
+ return TNC_RESULT_INVALID_PARAMETER;
+ }
+ pref_lang = recs->get_preferred_language(recs);
+ if (pref_lang.len == 0)
+ {
+ return TNC_RESULT_INVALID_PARAMETER;
+ }
+ *value_len = pref_lang.len;
+ if (buffer && buffer_len >= pref_lang.len)
+ {
+ memcpy(buffer, pref_lang.ptr, pref_lang.len);
+ }
+ return TNC_RESULT_SUCCESS;
}
- *out_value_len = pref_lang.len;
- if (buffer && buffer_len >= pref_lang.len)
+ case TNC_ATTRIBUTEID_MAX_ROUND_TRIPS:
+ return uint_attribute(buffer_len, buffer, value_len, 0xffffffff);
+ case TNC_ATTRIBUTEID_MAX_MESSAGE_SIZE:
+ return uint_attribute(buffer_len, buffer, value_len, 0x00000000);
+ case TNC_ATTRIBUTEID_HAS_LONG_TYPES:
+ case TNC_ATTRIBUTEID_HAS_EXCLUSIVE:
+ return bool_attribute(buffer_len, buffer, value_len,
+ entry->type == TNCCS_2_0);
+ case TNC_ATTRIBUTEID_HAS_SOH:
+ return bool_attribute(buffer_len, buffer, value_len,
+ entry->type == TNCCS_SOH);
+ case TNC_ATTRIBUTEID_IFTNCCS_PROTOCOL:
{
- memcpy(buffer, pref_lang.ptr, pref_lang.len);
+ char *protocol;
+
+ switch (entry->type)
+ {
+ case TNCCS_1_1:
+ case TNCCS_2_0:
+ protocol = "IF-TNCCS";
+ break;
+ case TNCCS_SOH:
+ protocol = "IF-TNCCS-SOH";
+ break;
+ default:
+ return TNC_RESULT_INVALID_PARAMETER;
+ }
+ return str_attribute(buffer_len, buffer, value_len, protocol);
}
- return TNC_RESULT_SUCCESS;
+ case TNC_ATTRIBUTEID_IFTNCCS_VERSION:
+ {
+ char *version;
+
+ switch (entry->type)
+ {
+ case TNCCS_1_1:
+ version = "1.1";
+ break;
+ case TNCCS_2_0:
+ version = "2.0";
+ break;
+ case TNCCS_SOH:
+ version = "1.0";
+ break;
+ default:
+ return TNC_RESULT_INVALID_PARAMETER;
+ }
+ return str_attribute(buffer_len, buffer, value_len, version);
+ }
+ case TNC_ATTRIBUTEID_IFT_PROTOCOL:
+ return str_attribute(buffer_len, buffer, value_len,
+ "IF-T for Tunneled EAP");
+ case TNC_ATTRIBUTEID_IFT_VERSION:
+ return str_attribute(buffer_len, buffer, value_len, "1.1");
+ default:
+ return TNC_RESULT_INVALID_PARAMETER;
}
- return TNC_RESULT_INVALID_PARAMETER;
}
METHOD(tnccs_manager_t, set_attribute, TNC_Result,
- private_tnc_tnccs_manager_t *this, TNC_IMVID imv_id,
+ private_tnc_tnccs_manager_t *this, bool is_imc,
+ TNC_UInt32 imcv_id,
TNC_ConnectionID id,
TNC_AttributeID attribute_id,
TNC_UInt32 buffer_len,
@@ -429,7 +634,7 @@ METHOD(tnccs_manager_t, set_attribute, TNC_Result,
tnccs_connection_entry_t *entry;
recommendations_t *recs = NULL;
- if (id == TNC_CONNECTIONID_ANY ||
+ if (is_imc || id == TNC_CONNECTIONID_ANY ||
(attribute_id != TNC_ATTRIBUTEID_REASON_STRING &&
attribute_id != TNC_ATTRIBUTEID_REASON_LANGUAGE))
{
@@ -455,11 +660,11 @@ METHOD(tnccs_manager_t, set_attribute, TNC_Result,
if (attribute_id == TNC_ATTRIBUTEID_REASON_STRING)
{
- return recs->set_reason_string(recs, imv_id, attribute);
+ return recs->set_reason_string(recs, imcv_id, attribute);
}
else
{
- return recs->set_reason_language(recs, imv_id, attribute);
+ return recs->set_reason_language(recs, imcv_id, attribute);
}
}
return TNC_RESULT_INVALID_PARAMETER;
diff --git a/src/libcharon/plugins/tnccs_11/tnccs_11.c b/src/libcharon/plugins/tnccs_11/tnccs_11.c
index 88a2c8474..3673221e5 100644
--- a/src/libcharon/plugins/tnccs_11/tnccs_11.c
+++ b/src/libcharon/plugins/tnccs_11/tnccs_11.c
@@ -100,12 +100,14 @@ struct private_tnccs_11_t {
METHOD(tnccs_t, send_msg, TNC_Result,
private_tnccs_11_t* this, TNC_IMCID imc_id, TNC_IMVID imv_id,
+ TNC_UInt32 msg_flags,
TNC_BufferReference msg,
TNC_UInt32 msg_len,
- TNC_MessageType msg_type)
+ TNC_VendorID msg_vid,
+ TNC_MessageSubtype msg_subtype)
{
tnccs_msg_t *tnccs_msg;
- u_int32_t vendor_id, subtype;
+ TNC_MessageType msg_type;
enum_name_t *pa_subtype_names;
if (!this->send_msg)
@@ -115,18 +117,23 @@ METHOD(tnccs_t, send_msg, TNC_Result,
this->is_server ? imv_id : imc_id);
return TNC_RESULT_ILLEGAL_OPERATION;
}
- vendor_id = msg_type >> 8;
- subtype = msg_type & 0xff;
- pa_subtype_names = get_pa_subtype_names(vendor_id);
+ if (msg_vid > TNC_VENDORID_ANY || msg_subtype > TNC_SUBTYPE_ANY)
+ {
+ return TNC_RESULT_NO_LONG_MESSAGE_TYPES;
+ }
+ msg_type = (msg_vid << 8) | msg_subtype;
+
+ pa_subtype_names = get_pa_subtype_names(msg_vid);
if (pa_subtype_names)
{
DBG2(DBG_TNC, "creating IMC-IMV message type '%N/%N' 0x%06x/0x%02x",
- pen_names, vendor_id, pa_subtype_names, subtype, vendor_id, subtype);
+ pen_names, msg_vid, pa_subtype_names, msg_subtype,
+ msg_vid, msg_subtype);
}
else
{
DBG2(DBG_TNC, "creating IMC-IMV message type '%N' 0x%06x/0x%02x",
- pen_names, vendor_id, vendor_id, subtype);
+ pen_names, msg_vid, msg_vid, msg_subtype);
}
tnccs_msg = imc_imv_msg_create(msg_type, chunk_create(msg, msg_len));
@@ -153,38 +160,40 @@ static void handle_message(private_tnccs_11_t *this, tnccs_msg_t *msg)
imc_imv_msg_t *imc_imv_msg;
TNC_MessageType msg_type;
chunk_t msg_body;
- u_int32_t vendor_id, subtype;
+ u_int32_t msg_vid, msg_subtype;
enum_name_t *pa_subtype_names;
imc_imv_msg = (imc_imv_msg_t*)msg;
msg_type = imc_imv_msg->get_msg_type(imc_imv_msg);
msg_body = imc_imv_msg->get_msg_body(imc_imv_msg);
- vendor_id = msg_type >> 8;
- subtype = msg_type & 0xff;
+ msg_vid = (msg_type >> 8) & TNC_VENDORID_ANY;
+ msg_subtype = msg_type & TNC_SUBTYPE_ANY;
- pa_subtype_names = get_pa_subtype_names(vendor_id);
+ pa_subtype_names = get_pa_subtype_names(msg_vid);
if (pa_subtype_names)
{
DBG2(DBG_TNC, "handling IMC-IMV message type '%N/%N' 0x%06x/0x%02x",
- pen_names, vendor_id, pa_subtype_names, subtype,
- vendor_id, subtype);
+ pen_names, msg_vid, pa_subtype_names, msg_subtype,
+ msg_vid, msg_subtype);
}
else
{
DBG2(DBG_TNC, "handling IMC-IMV message type '%N' 0x%06x/0x%02x",
- pen_names, vendor_id, vendor_id, subtype);
+ pen_names, msg_vid, msg_vid, msg_subtype);
}
this->send_msg = TRUE;
if (this->is_server)
{
- tnc->imvs->receive_message(tnc->imvs,
- this->connection_id, msg_body.ptr, msg_body.len, msg_type);
+ tnc->imvs->receive_message(tnc->imvs, this->connection_id,
+ FALSE, msg_body.ptr, msg_body.len,
+ msg_vid, msg_subtype, 0, TNC_IMVID_ANY);
}
else
{
- tnc->imcs->receive_message(tnc->imcs,
- this->connection_id, msg_body.ptr, msg_body.len,msg_type);
+ tnc->imcs->receive_message(tnc->imcs, this->connection_id,
+ FALSE, msg_body.ptr, msg_body.len,
+ msg_vid, msg_subtype, 0, TNC_IMCID_ANY);
}
this->send_msg = FALSE;
break;
@@ -280,7 +289,7 @@ METHOD(tls_t, process, status_t,
if (this->is_server && !this->connection_id)
{
this->connection_id = tnc->tnccs->create_connection(tnc->tnccs,
- (tnccs_t*)this, _send_msg,
+ TNCCS_1_1, (tnccs_t*)this, _send_msg,
&this->request_handshake_retry, &this->recs);
if (!this->connection_id)
{
@@ -406,7 +415,7 @@ METHOD(tls_t, build, status_t,
char *pref_lang;
this->connection_id = tnc->tnccs->create_connection(tnc->tnccs,
- (tnccs_t*)this, _send_msg,
+ TNCCS_1_1, (tnccs_t*)this, _send_msg,
&this->request_handshake_retry, NULL);
if (!this->connection_id)
{
diff --git a/src/libcharon/plugins/tnccs_20/messages/pb_pa_msg.c b/src/libcharon/plugins/tnccs_20/messages/pb_pa_msg.c
index b9bbf6bd1..1c4913e5e 100644
--- a/src/libcharon/plugins/tnccs_20/messages/pb_pa_msg.c
+++ b/src/libcharon/plugins/tnccs_20/messages/pb_pa_msg.c
@@ -211,12 +211,6 @@ METHOD(pb_pa_msg_t, get_exclusive_flag, bool,
return this->excl;
}
-METHOD(pb_pa_msg_t, set_exclusive_flag, void,
- private_pb_pa_msg_t *this, bool excl)
-{
- this->excl = excl;
-}
-
/**
* See header
*/
@@ -237,7 +231,6 @@ pb_tnc_msg_t *pb_pa_msg_create_from_data(chunk_t data)
.get_validator_id = _get_validator_id,
.get_body = _get_body,
.get_exclusive_flag = _get_exclusive_flag,
- .set_exclusive_flag = _set_exclusive_flag,
},
.type = PB_MSG_PA,
.encoding = chunk_clone(data),
@@ -251,7 +244,7 @@ pb_tnc_msg_t *pb_pa_msg_create_from_data(chunk_t data)
*/
pb_tnc_msg_t *pb_pa_msg_create(u_int32_t vendor_id, u_int32_t subtype,
u_int16_t collector_id, u_int16_t validator_id,
- chunk_t msg_body)
+ bool excl, chunk_t msg_body)
{
private_pb_pa_msg_t *this;
@@ -269,13 +262,13 @@ pb_tnc_msg_t *pb_pa_msg_create(u_int32_t vendor_id, u_int32_t subtype,
.get_validator_id = _get_validator_id,
.get_body = _get_body,
.get_exclusive_flag = _get_exclusive_flag,
- .set_exclusive_flag = _set_exclusive_flag,
},
.type = PB_MSG_PA,
.vendor_id = vendor_id,
.subtype = subtype,
.collector_id = collector_id,
.validator_id = validator_id,
+ .excl = excl,
.msg_body = chunk_clone(msg_body),
);
diff --git a/src/libcharon/plugins/tnccs_20/messages/pb_pa_msg.h b/src/libcharon/plugins/tnccs_20/messages/pb_pa_msg.h
index eb087e9e7..d9db9a1ce 100644
--- a/src/libcharon/plugins/tnccs_20/messages/pb_pa_msg.h
+++ b/src/libcharon/plugins/tnccs_20/messages/pb_pa_msg.h
@@ -71,12 +71,6 @@ struct pb_pa_msg_t {
*/
bool (*get_exclusive_flag)(pb_pa_msg_t *this);
- /**
- * Set the exclusive flag
- *
- * @param excl vexclusive flag
- */
- void (*set_exclusive_flag)(pb_pa_msg_t *this, bool excl);
};
/**
@@ -86,11 +80,12 @@ struct pb_pa_msg_t {
* @param subtype PA Subtype
* @param collector_id Posture Collector ID
* @param validator_id Posture Validator ID
+ * @param excl Exclusive Flag
* @param msg_body PA Message Body
*/
pb_tnc_msg_t *pb_pa_msg_create(u_int32_t vendor_id, u_int32_t subtype,
u_int16_t collector_id, u_int16_t validator_id,
- chunk_t msg_body);
+ bool excl, chunk_t msg_body);
/**
* Create an unprocessed PB-PA message from raw data
diff --git a/src/libcharon/plugins/tnccs_20/tnccs_20.c b/src/libcharon/plugins/tnccs_20/tnccs_20.c
index d37510880..606fc529b 100644
--- a/src/libcharon/plugins/tnccs_20/tnccs_20.c
+++ b/src/libcharon/plugins/tnccs_20/tnccs_20.c
@@ -99,15 +99,16 @@ struct private_tnccs_20_t {
METHOD(tnccs_t, send_msg, TNC_Result,
private_tnccs_20_t* this, TNC_IMCID imc_id, TNC_IMVID imv_id,
+ TNC_UInt32 msg_flags,
TNC_BufferReference msg,
TNC_UInt32 msg_len,
- TNC_MessageType msg_type)
+ TNC_VendorID msg_vid,
+ TNC_MessageSubtype msg_subtype)
{
- TNC_MessageSubtype msg_sub_type;
- TNC_VendorID msg_vendor_id;
pb_tnc_msg_t *pb_tnc_msg;
pb_tnc_batch_type_t batch_type;
enum_name_t *pa_subtype_names;
+ bool excl;
if (!this->send_msg)
{
@@ -116,24 +117,22 @@ METHOD(tnccs_t, send_msg, TNC_Result,
this->is_server ? imv_id : imc_id);
return TNC_RESULT_ILLEGAL_OPERATION;
}
+ excl = (msg_flags & TNC_MESSAGE_FLAGS_EXCLUSIVE) != 0;
- msg_sub_type = msg_type & TNC_SUBTYPE_ANY;
- msg_vendor_id = (msg_type >> 8) & TNC_VENDORID_ANY;
+ pb_tnc_msg = pb_pa_msg_create(msg_vid, msg_subtype, imc_id, imv_id,
+ excl, chunk_create(msg, msg_len));
- pb_tnc_msg = pb_pa_msg_create(msg_vendor_id, msg_sub_type, imc_id, imv_id,
- chunk_create(msg, msg_len));
-
- pa_subtype_names = get_pa_subtype_names(msg_vendor_id);
+ pa_subtype_names = get_pa_subtype_names(msg_vid);
if (pa_subtype_names)
{
- DBG2(DBG_TNC, "creating PB-PA message type '%N/%N' 0x%06x/0x%02x",
- pen_names, msg_vendor_id, pa_subtype_names, msg_sub_type,
- msg_vendor_id, msg_sub_type);
+ DBG2(DBG_TNC, "creating PB-PA message type '%N/%N' 0x%06x/0x%08x",
+ pen_names, msg_vid, pa_subtype_names, msg_subtype,
+ msg_vid, msg_subtype);
}
else
{
- DBG2(DBG_TNC, "creating PB-PA message type '%N' 0x%06x/0x%02x",
- pen_names, msg_vendor_id, msg_vendor_id, msg_sub_type);
+ DBG2(DBG_TNC, "creating PB-PA message type '%N' 0x%06x/0x%08x",
+ pen_names, msg_vid, msg_vid, msg_subtype);
}
/* adding PA message to SDATA or CDATA batch only */
@@ -168,39 +167,44 @@ static void handle_message(private_tnccs_20_t *this, pb_tnc_msg_t *msg)
case PB_MSG_PA:
{
pb_pa_msg_t *pa_msg;
- TNC_MessageType msg_type;
- u_int32_t vendor_id, subtype;
+ u_int32_t msg_vid, msg_subtype;
+ u_int16_t imc_id, imv_id;
chunk_t msg_body;
+ bool excl;
enum_name_t *pa_subtype_names;
pa_msg = (pb_pa_msg_t*)msg;
- vendor_id = pa_msg->get_vendor_id(pa_msg, &subtype);
- msg_type = (vendor_id << 8) | (subtype & 0xff);
+ msg_vid = pa_msg->get_vendor_id(pa_msg, &msg_subtype);
msg_body = pa_msg->get_body(pa_msg);
+ imc_id = pa_msg->get_collector_id(pa_msg);
+ imv_id = pa_msg->get_validator_id(pa_msg);
+ excl = pa_msg->get_exclusive_flag(pa_msg);
- pa_subtype_names = get_pa_subtype_names(vendor_id);
+ pa_subtype_names = get_pa_subtype_names(msg_vid);
if (pa_subtype_names)
{
- DBG2(DBG_TNC, "handling PB-PA message type '%N/%N' 0x%06x/0x%02x",
- pen_names, vendor_id, pa_subtype_names, subtype,
- vendor_id, subtype);
+ DBG2(DBG_TNC, "handling PB-PA message type '%N/%N' 0x%06x/0x%08x",
+ pen_names, msg_vid, pa_subtype_names, msg_subtype,
+ msg_vid, msg_subtype);
}
else
{
- DBG2(DBG_TNC, "handling PB-PA message type '%N' 0x%06x/0x%02x",
- pen_names, vendor_id, vendor_id, subtype);
+ DBG2(DBG_TNC, "handling PB-PA message type '%N' 0x%06x/0x%08x",
+ pen_names, msg_vid, msg_vid, msg_subtype);
}
this->send_msg = TRUE;
if (this->is_server)
{
- tnc->imvs->receive_message(tnc->imvs,
- this->connection_id, msg_body.ptr, msg_body.len, msg_type);
+ tnc->imvs->receive_message(tnc->imvs, this->connection_id,
+ excl, msg_body.ptr, msg_body.len,
+ msg_vid, msg_subtype, imc_id, imv_id);
}
else
{
- tnc->imcs->receive_message(tnc->imcs,
- this->connection_id, msg_body.ptr, msg_body.len,msg_type);
+ tnc->imcs->receive_message(tnc->imcs, this->connection_id,
+ excl, msg_body.ptr, msg_body.len,
+ msg_vid, msg_subtype, imv_id, imc_id);
}
this->send_msg = FALSE;
break;
@@ -371,7 +375,7 @@ METHOD(tls_t, process, status_t,
if (this->is_server && !this->connection_id)
{
this->connection_id = tnc->tnccs->create_connection(tnc->tnccs,
- (tnccs_t*)this, _send_msg,
+ TNCCS_2_0, (tnccs_t*)this, _send_msg,
&this->request_handshake_retry, &this->recs);
if (!this->connection_id)
{
@@ -552,7 +556,7 @@ METHOD(tls_t, build, status_t,
char *pref_lang;
this->connection_id = tnc->tnccs->create_connection(tnc->tnccs,
- (tnccs_t*)this, _send_msg,
+ TNCCS_2_0, (tnccs_t*)this, _send_msg,
&this->request_handshake_retry, NULL);
if (!this->connection_id)
{
diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c
index bcc98709c..5d0a5aea8 100644
--- a/src/libcharon/sa/ike_sa.c
+++ b/src/libcharon/sa/ike_sa.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006-2011 Tobias Brunner
+ * Copyright (C) 2006-2012 Tobias Brunner
* Copyright (C) 2006 Daniel Roethlisberger
* Copyright (C) 2005-2009 Martin Willi
* Copyright (C) 2005 Jan Hutter
@@ -33,6 +33,7 @@
#include <processing/jobs/send_dpd_job.h>
#include <processing/jobs/send_keepalive_job.h>
#include <processing/jobs/rekey_ike_sa_job.h>
+#include <sa/ikev2/tasks/ike_auth_lifetime.h>
#ifdef ME
#include <sa/ikev2/tasks/ike_me.h>
@@ -195,9 +196,9 @@ struct private_ike_sa_t {
linked_list_t *attributes;
/**
- * list of peers additional addresses, transmitted via MOBIKE
+ * list of peer's addresses, additional ones transmitted via MOBIKE
*/
- linked_list_t *additional_addresses;
+ linked_list_t *peer_addresses;
/**
* previously value of received DESTINATION_IP hash
@@ -668,7 +669,6 @@ METHOD(ike_sa_t, set_state, void,
lib->scheduler->schedule_job(lib->scheduler, job, t);
DBG1(DBG_IKE, "maximum IKE_SA lifetime %ds", t);
}
-
trigger_dpd = this->peer_cfg->get_dpd(this->peer_cfg);
}
break;
@@ -770,28 +770,28 @@ METHOD(ike_sa_t, get_virtual_ip, host_t*,
}
}
-METHOD(ike_sa_t, add_additional_address, void,
+METHOD(ike_sa_t, add_peer_address, void,
private_ike_sa_t *this, host_t *host)
{
- this->additional_addresses->insert_last(this->additional_addresses, host);
+ this->peer_addresses->insert_last(this->peer_addresses, host);
}
-METHOD(ike_sa_t, create_additional_address_enumerator, enumerator_t*,
+METHOD(ike_sa_t, create_peer_address_enumerator, enumerator_t*,
private_ike_sa_t *this)
{
- return this->additional_addresses->create_enumerator(
- this->additional_addresses);
+ return this->peer_addresses->create_enumerator(this->peer_addresses);
}
-METHOD(ike_sa_t, remove_additional_addresses, void,
+METHOD(ike_sa_t, clear_peer_addresses, void,
private_ike_sa_t *this)
{
- enumerator_t *enumerator = create_additional_address_enumerator(this);
+ enumerator_t *enumerator = create_peer_address_enumerator(this);
host_t *host;
+
while (enumerator->enumerate(enumerator, (void**)&host))
{
- this->additional_addresses->remove_at(this->additional_addresses,
- enumerator);
+ this->peer_addresses->remove_at(this->peer_addresses,
+ enumerator);
host->destroy(host);
}
enumerator->destroy(enumerator);
@@ -1386,17 +1386,25 @@ METHOD(ike_sa_t, reauth, status_t,
#endif /* ME */
)
{
- time_t now = time_monotonic(NULL);
+ time_t del, now;
- DBG1(DBG_IKE, "IKE_SA will timeout in %V",
- &now, &this->stats[STAT_DELETE]);
+ del = this->stats[STAT_DELETE];
+ now = time_monotonic(NULL);
+ DBG1(DBG_IKE, "IKE_SA %s[%d] will timeout in %V",
+ get_name(this), this->unique_id, &now, &del);
return FAILED;
}
else
{
- DBG1(DBG_IKE, "reauthenticating actively");
+ DBG0(DBG_IKE, "reauthenticating IKE_SA %s[%d] actively",
+ get_name(this), this->unique_id);
}
}
+ else
+ {
+ DBG0(DBG_IKE, "reauthenticating IKE_SA %s[%d]",
+ get_name(this), this->unique_id);
+ }
this->task_manager->queue_ike_reauth(this->task_manager);
return this->task_manager->initiate(this->task_manager);
}
@@ -1558,6 +1566,7 @@ METHOD(ike_sa_t, retransmit, status_t,
DBG1(DBG_IKE, "peer not responding, trying again (%d/%d)",
this->keyingtry + 1, tries);
reset(this);
+ resolve_hosts(this);
this->task_manager->queue_ike(this->task_manager);
return this->task_manager->initiate(this->task_manager);
}
@@ -1579,35 +1588,67 @@ METHOD(ike_sa_t, retransmit, status_t,
return SUCCESS;
}
-METHOD(ike_sa_t, set_auth_lifetime, void,
+METHOD(ike_sa_t, set_auth_lifetime, status_t,
private_ike_sa_t *this, u_int32_t lifetime)
{
- u_int32_t reduction = this->peer_cfg->get_over_time(this->peer_cfg);
- u_int32_t reauth_time = time_monotonic(NULL) + lifetime - reduction;
+ u_int32_t diff, hard, soft, now;
+ ike_auth_lifetime_t *task;
+ bool send_update;
+
+ diff = this->peer_cfg->get_over_time(this->peer_cfg);
+ now = time_monotonic(NULL);
+ hard = now + lifetime;
+ soft = hard - diff;
- if (lifetime < reduction)
+ /* check if we have to send an AUTH_LIFETIME to enforce the new lifetime.
+ * We send the notify in IKE_AUTH if not yet ESTABLISHED. */
+ send_update = this->state == IKE_ESTABLISHED && this->version == IKEV2 &&
+ !has_condition(this, COND_ORIGINAL_INITIATOR) &&
+ (this->other_virtual_ip != NULL ||
+ has_condition(this, COND_EAP_AUTHENTICATED));
+
+ if (lifetime < diff)
{
- DBG1(DBG_IKE, "received AUTH_LIFETIME of %ds, starting reauthentication",
- lifetime);
- lib->processor->queue_job(lib->processor,
+ this->stats[STAT_REAUTH] = now;
+
+ if (!send_update)
+ {
+ DBG1(DBG_IKE, "received AUTH_LIFETIME of %ds, "
+ "starting reauthentication", lifetime);
+ lib->processor->queue_job(lib->processor,
(job_t*)rekey_ike_sa_job_create(this->ike_sa_id, TRUE));
+ }
}
else if (this->stats[STAT_REAUTH] == 0 ||
- this->stats[STAT_REAUTH] > reauth_time)
+ this->stats[STAT_REAUTH] > soft)
{
- this->stats[STAT_REAUTH] = reauth_time;
- DBG1(DBG_IKE, "received AUTH_LIFETIME of %ds, scheduling reauthentication"
- " in %ds", lifetime, lifetime - reduction);
- lib->scheduler->schedule_job(lib->scheduler,
+ this->stats[STAT_REAUTH] = soft;
+ if (!send_update)
+ {
+ DBG1(DBG_IKE, "received AUTH_LIFETIME of %ds, scheduling "
+ "reauthentication in %ds", lifetime, lifetime - diff);
+ lib->scheduler->schedule_job(lib->scheduler,
(job_t*)rekey_ike_sa_job_create(this->ike_sa_id, TRUE),
- lifetime - reduction);
+ lifetime - diff);
+ }
}
else
{
DBG1(DBG_IKE, "received AUTH_LIFETIME of %ds, "
"reauthentication already scheduled in %ds", lifetime,
this->stats[STAT_REAUTH] - time_monotonic(NULL));
+ send_update = FALSE;
}
+ /* give at least some seconds to reauthenticate */
+ this->stats[STAT_DELETE] = max(hard, now + 10);
+
+ if (send_update)
+ {
+ task = ike_auth_lifetime_create(&this->public, TRUE);
+ this->task_manager->queue_task(this->task_manager, &task->task);
+ return this->task_manager->initiate(this->task_manager);
+ }
+ return SUCCESS;
}
/**
@@ -1639,25 +1680,20 @@ static bool is_any_path_valid(private_ike_sa_t *this)
bool valid = FALSE;
enumerator_t *enumerator;
host_t *src, *addr;
+
DBG1(DBG_IKE, "old path is not available anymore, try to find another");
- src = hydra->kernel_interface->get_source_addr(hydra->kernel_interface,
- this->other_host, NULL);
- if (!src)
+ enumerator = this->peer_addresses->create_enumerator(this->peer_addresses);
+ while (enumerator->enumerate(enumerator, &addr))
{
- enumerator = this->additional_addresses->create_enumerator(
- this->additional_addresses);
- while (enumerator->enumerate(enumerator, &addr))
+ DBG1(DBG_IKE, "looking for a route to %H ...", addr);
+ src = hydra->kernel_interface->get_source_addr(
+ hydra->kernel_interface, addr, NULL);
+ if (src)
{
- DBG1(DBG_IKE, "looking for a route to %H ...", addr);
- src = hydra->kernel_interface->get_source_addr(
- hydra->kernel_interface, addr, NULL);
- if (src)
- {
- break;
- }
+ break;
}
- enumerator->destroy(enumerator);
}
+ enumerator->destroy(enumerator);
if (src)
{
valid = TRUE;
@@ -1900,8 +1936,8 @@ METHOD(ike_sa_t, destroy, void,
}
this->other_virtual_ip->destroy(this->other_virtual_ip);
}
- this->additional_addresses->destroy_offset(this->additional_addresses,
- offsetof(host_t, destroy));
+ this->peer_addresses->destroy_offset(this->peer_addresses,
+ offsetof(host_t, destroy));
#ifdef ME
if (this->is_mediation_server)
{
@@ -1990,9 +2026,9 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator,
.has_condition = _has_condition,
.set_pending_updates = _set_pending_updates,
.get_pending_updates = _get_pending_updates,
- .create_additional_address_enumerator = _create_additional_address_enumerator,
- .add_additional_address = _add_additional_address,
- .remove_additional_addresses = _remove_additional_addresses,
+ .create_peer_address_enumerator = _create_peer_address_enumerator,
+ .add_peer_address = _add_peer_address,
+ .clear_peer_addresses = _clear_peer_addresses,
.has_mapping_changed = _has_mapping_changed,
.retransmit = _retransmit,
.delete = _delete_,
@@ -2051,7 +2087,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator,
.my_auths = linked_list_create(),
.other_auths = linked_list_create(),
.unique_id = ++unique_id,
- .additional_addresses = linked_list_create(),
+ .peer_addresses = linked_list_create(),
.attributes = linked_list_create(),
.keepalive_interval = lib->settings->get_time(lib->settings,
"charon.keep_alive", KEEPALIVE_INTERVAL),
diff --git a/src/libcharon/sa/ike_sa.h b/src/libcharon/sa/ike_sa.h
index 3fc0a7be2..0644bab78 100644
--- a/src/libcharon/sa/ike_sa.h
+++ b/src/libcharon/sa/ike_sa.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006-2011 Tobias Brunner
+ * Copyright (C) 2006-2012 Tobias Brunner
* Copyright (C) 2006 Daniel Roethlisberger
* Copyright (C) 2005-2009 Martin Willi
* Copyright (C) 2005 Jan Hutter
@@ -508,19 +508,19 @@ struct ike_sa_t {
*
* @param host host to add to list
*/
- void (*add_additional_address)(ike_sa_t *this, host_t *host);
+ void (*add_peer_address)(ike_sa_t *this, host_t *host);
/**
- * Create an enumerator over all additional addresses of the peer.
+ * Create an enumerator over all known addresses of the peer.
*
* @return enumerator over addresses
*/
- enumerator_t* (*create_additional_address_enumerator)(ike_sa_t *this);
+ enumerator_t* (*create_peer_address_enumerator)(ike_sa_t *this);
/**
- * Remove all additional addresses of the peer.
+ * Remove all known addresses of the peer.
*/
- void (*remove_additional_addresses)(ike_sa_t *this);
+ void (*clear_peer_addresses)(ike_sa_t *this);
/**
* Check if mappings have changed on a NAT for our source address.
@@ -905,11 +905,15 @@ struct ike_sa_t {
status_t (*reestablish) (ike_sa_t *this);
/**
- * Set the lifetime limit received from a AUTH_LIFETIME notify.
+ * Set the lifetime limit received/to send in a AUTH_LIFETIME notify.
+ *
+ * If the IKE_SA is already ESTABLISHED, an INFORMATIONAL is sent with
+ * an AUTH_LIFETIME notify. The call never fails on unestablished SAs.
*
* @param lifetime lifetime in seconds
+ * @return DESTROY_ME to destroy the IKE_SA
*/
- void (*set_auth_lifetime)(ike_sa_t *this, u_int32_t lifetime);
+ status_t (*set_auth_lifetime)(ike_sa_t *this, u_int32_t lifetime);
/**
* Set the virtual IP to use for this IKE_SA and its children.
diff --git a/src/libcharon/sa/ikev2/task_manager_v2.c b/src/libcharon/sa/ikev2/task_manager_v2.c
index d12f5c977..ba7fdd2da 100644
--- a/src/libcharon/sa/ikev2/task_manager_v2.c
+++ b/src/libcharon/sa/ikev2/task_manager_v2.c
@@ -162,15 +162,15 @@ struct private_task_manager_t {
*/
static void flush(private_task_manager_t *this)
{
- this->queued_tasks->destroy_offset(this->queued_tasks,
- offsetof(task_t, destroy));
- this->queued_tasks = linked_list_create();
this->passive_tasks->destroy_offset(this->passive_tasks,
offsetof(task_t, destroy));
this->passive_tasks = linked_list_create();
this->active_tasks->destroy_offset(this->active_tasks,
offsetof(task_t, destroy));
this->active_tasks = linked_list_create();
+ this->queued_tasks->destroy_offset(this->queued_tasks,
+ offsetof(task_t, destroy));
+ this->queued_tasks = linked_list_create();
}
/**
@@ -369,6 +369,11 @@ METHOD(task_manager_t, initiate, status_t,
exchange = INFORMATIONAL;
break;
}
+ if (activate_task(this, TASK_IKE_AUTH_LIFETIME))
+ {
+ exchange = INFORMATIONAL;
+ break;
+ }
#ifdef ME
if (activate_task(this, TASK_IKE_ME))
{
@@ -640,11 +645,9 @@ static status_t build_response(private_task_manager_t *this, message_t *request)
enumerator);
}
break;
+ case DESTROY_ME:
case FAILED:
default:
- charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
- /* FALL */
- case DESTROY_ME:
/* destroy IKE_SA, but SEND response first */
delete = TRUE;
break;
@@ -679,6 +682,7 @@ static status_t build_response(private_task_manager_t *this, message_t *request)
this->responding.packet->clone(this->responding.packet));
if (delete)
{
+ charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
return DESTROY_ME;
}
return SUCCESS;
diff --git a/src/libcharon/sa/ikev2/tasks/ike_cert_pre.c b/src/libcharon/sa/ikev2/tasks/ike_cert_pre.c
index 0de2efd38..7583710bf 100644
--- a/src/libcharon/sa/ikev2/tasks/ike_cert_pre.c
+++ b/src/libcharon/sa/ikev2/tasks/ike_cert_pre.c
@@ -51,7 +51,7 @@ struct private_ike_cert_pre_t {
bool do_http_lookup;
/**
- * wheter this is the final authentication round
+ * whether this is the final authentication round
*/
bool final;
};
diff --git a/src/libcharon/sa/ikev2/tasks/ike_mobike.c b/src/libcharon/sa/ikev2/tasks/ike_mobike.c
index c533506bb..377714023 100644
--- a/src/libcharon/sa/ikev2/tasks/ike_mobike.c
+++ b/src/libcharon/sa/ikev2/tasks/ike_mobike.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2010-2012 Tobias Brunner
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -134,13 +135,17 @@ static void process_payloads(private_ike_mobike_t *this, message_t *message)
{
if (first)
{ /* an ADDITIONAL_*_ADDRESS means replace, so flush once */
- this->ike_sa->remove_additional_addresses(this->ike_sa);
+ this->ike_sa->clear_peer_addresses(this->ike_sa);
first = FALSE;
+ /* add the peer's current address to the list */
+ host = this->ike_sa->get_other_host(this->ike_sa);
+ this->ike_sa->add_peer_address(this->ike_sa,
+ host->clone(host));
}
data = notify->get_notification_data(notify);
host = host_create_from_chunk(family, data, 0);
DBG2(DBG_IKE, "got additional MOBIKE peer address: %H", host);
- this->ike_sa->add_additional_address(this->ike_sa, host);
+ this->ike_sa->add_peer_address(this->ike_sa, host);
this->addresses_updated = TRUE;
break;
}
@@ -151,7 +156,10 @@ static void process_payloads(private_ike_mobike_t *this, message_t *message)
}
case NO_ADDITIONAL_ADDRESSES:
{
- this->ike_sa->remove_additional_addresses(this->ike_sa);
+ this->ike_sa->clear_peer_addresses(this->ike_sa);
+ /* add the peer's current address to the list */
+ host = this->ike_sa->get_other_host(this->ike_sa);
+ this->ike_sa->add_peer_address(this->ike_sa, host->clone(host));
this->addresses_updated = TRUE;
break;
}
@@ -291,18 +299,7 @@ METHOD(ike_mobike_t, transmit, void,
other_old = this->ike_sa->get_other_host(this->ike_sa);
ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa);
- me = hydra->kernel_interface->get_source_addr(
- hydra->kernel_interface, other_old, NULL);
- if (me)
- {
- apply_port(me, me_old, ike_cfg->get_my_port(ike_cfg));
- DBG1(DBG_IKE, "checking original path %#H - %#H", me, other_old);
- copy = packet->clone(packet);
- copy->set_source(copy, me);
- charon->sender->send(charon->sender, copy);
- }
-
- enumerator = this->ike_sa->create_additional_address_enumerator(this->ike_sa);
+ enumerator = this->ike_sa->create_peer_address_enumerator(this->ike_sa);
while (enumerator->enumerate(enumerator, (void**)&other))
{
me = hydra->kernel_interface->get_source_addr(
diff --git a/src/libcharon/sa/keymat.c b/src/libcharon/sa/keymat.c
index d04d966ad..7ef0b9f5d 100644
--- a/src/libcharon/sa/keymat.c
+++ b/src/libcharon/sa/keymat.c
@@ -79,7 +79,9 @@ int keymat_get_keylen_integ(integrity_algorithm_t alg)
{
keylen_entry_t map[] = {
{AUTH_HMAC_MD5_96, 128},
+ {AUTH_HMAC_MD5_128, 128},
{AUTH_HMAC_SHA1_96, 160},
+ {AUTH_HMAC_SHA1_160, 160},
{AUTH_HMAC_SHA2_256_96, 256},
{AUTH_HMAC_SHA2_256_128, 256},
{AUTH_HMAC_SHA2_384_192, 384},
diff --git a/src/libcharon/sa/trap_manager.c b/src/libcharon/sa/trap_manager.c
index 3f434dae1..9a6d4ebcf 100644
--- a/src/libcharon/sa/trap_manager.c
+++ b/src/libcharon/sa/trap_manager.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2011 Tobias Brunner
* Copyright (C) 2009 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -74,8 +75,10 @@ typedef struct {
peer_cfg_t *peer_cfg;
/** ref to instanciated CHILD_SA */
child_sa_t *child_sa;
+ /** TRUE if an acquire is pending */
+ bool pending;
/** pending IKE_SA connecting upon acquire */
- ike_sa_t *pending;
+ ike_sa_t *ike_sa;
} entry_t;
/**
@@ -170,10 +173,10 @@ METHOD(trap_manager_t, install, u_int32_t,
}
reqid = child_sa->get_reqid(child_sa);
- entry = malloc_thing(entry_t);
- entry->child_sa = child_sa;
- entry->peer_cfg = peer->get_ref(peer);
- entry->pending = NULL;
+ INIT(entry,
+ .child_sa = child_sa,
+ .peer_cfg = peer->get_ref(peer),
+ );
this->lock->write_lock(this->lock);
this->traps->insert_last(this->traps, entry);
@@ -263,38 +266,49 @@ METHOD(trap_manager_t, acquire, void,
if (!found)
{
DBG1(DBG_CFG, "trap not found, unable to acquire reqid %d",reqid);
+ this->lock->unlock(this->lock);
+ return;
}
- else if (found->pending)
+ if (!cas_bool(&found->pending, FALSE, TRUE))
{
DBG1(DBG_CFG, "ignoring acquire, connection attempt pending");
+ this->lock->unlock(this->lock);
+ return;
}
- else
+ 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(
+ charon->ike_sa_manager, peer);
+ if (ike_sa)
{
- child = found->child_sa->get_config(found->child_sa);
- peer = found->peer_cfg;
- 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)
{
- if (ike_sa->get_peer_cfg(ike_sa) == NULL)
- {
- ike_sa->set_peer_cfg(ike_sa, peer);
- }
- child->get_ref(child);
- reqid = found->child_sa->get_reqid(found->child_sa);
- if (ike_sa->initiate(ike_sa, child, reqid, src, dst) != DESTROY_ME)
+ ike_sa->set_peer_cfg(ike_sa, peer);
+ }
+ 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->pending = ike_sa;
- charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+ found->ike_sa = ike_sa;
}
- else
- {
- charon->ike_sa_manager->checkin_and_destroy(
+ this->lock->unlock(this->lock);
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+ }
+ else
+ {
+ charon->ike_sa_manager->checkin_and_destroy(
charon->ike_sa_manager, ike_sa);
- }
}
}
- this->lock->unlock(this->lock);
+ peer->destroy(peer);
}
/**
@@ -310,7 +324,7 @@ static void complete(private_trap_manager_t *this, ike_sa_t *ike_sa,
enumerator = this->traps->create_enumerator(this->traps);
while (enumerator->enumerate(enumerator, &entry))
{
- if (entry->pending != ike_sa)
+ if (entry->ike_sa != ike_sa)
{
continue;
}
@@ -319,7 +333,8 @@ static void complete(private_trap_manager_t *this, ike_sa_t *ike_sa,
{
continue;
}
- entry->pending = NULL;
+ entry->ike_sa = NULL;
+ entry->pending = FALSE;
}
enumerator->destroy(enumerator);
this->lock->unlock(this->lock);
@@ -356,15 +371,21 @@ METHOD(listener_t, child_state_change, bool,
METHOD(trap_manager_t, flush, void,
private_trap_manager_t *this)
{
- this->traps->invoke_function(this->traps, (void*)destroy_entry);
+ 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;
+ this->traps = linked_list_create();
+ this->lock->unlock(this->lock);
+ traps->destroy_function(traps, (void*)destroy_entry);
}
METHOD(trap_manager_t, destroy, void,
private_trap_manager_t *this)
{
charon->bus->remove_listener(charon->bus, &this->listener.listener);
- this->traps->invoke_function(this->traps, (void*)destroy_entry);
- this->traps->destroy(this->traps);
+ this->traps->destroy_function(this->traps, (void*)destroy_entry);
this->lock->destroy(this->lock);
free(this);
}
diff --git a/src/libfast/dispatcher.c b/src/libfast/dispatcher.c
index 8cfad0fd3..e5fca7074 100644
--- a/src/libfast/dispatcher.c
+++ b/src/libfast/dispatcher.c
@@ -183,8 +183,8 @@ static session_entry_t *session_entry_create(private_dispatcher_t *this,
INIT(entry,
.cond = condvar_create(CONDVAR_TYPE_DEFAULT),
.session = load_session(this),
- .used = time_monotonic(NULL),
.host = strdup(host),
+ .used = time_monotonic(NULL),
);
return entry;
}
diff --git a/src/libfast/smtp.h b/src/libfast/smtp.h
index 910f18127..9589ea2a6 100644
--- a/src/libfast/smtp.h
+++ b/src/libfast/smtp.h
@@ -34,7 +34,7 @@ struct smtp_t {
* Send an e-mail message.
*
* @param from sender address
- * @param to receipient address
+ * @param to recipient address
* @param subject mail subject
* @param fmt mail body format string
* @param ... arguments for body format string
diff --git a/src/libfreeswan/Android.mk b/src/libfreeswan/Android.mk
index e9805f0a3..a834d4846 100644
--- a/src/libfreeswan/Android.mk
+++ b/src/libfreeswan/Android.mk
@@ -26,6 +26,8 @@ LOCAL_CFLAGS := $(strongswan_CFLAGS)
LOCAL_MODULE := libfreeswan
+LOCAL_MODULE_TAGS := optional
+
LOCAL_ARM_MODE := arm
LOCAL_PRELINK_MODULE := false
diff --git a/src/libfreeswan/Makefile.am b/src/libfreeswan/Makefile.am
index bc12fe386..b38343d34 100644
--- a/src/libfreeswan/Makefile.am
+++ b/src/libfreeswan/Makefile.am
@@ -19,3 +19,4 @@ dist_man3_MANS = anyaddr.3 atoaddr.3 atoasr.3 atoul.3 goodmask.3 initaddr.3 init
portof.3 rangetosubnet.3 sameaddr.3 subnetof.3 \
ttoaddr.3 ttodata.3 ttosa.3 ttoul.3
+EXTRA_DIST = Android.mk
diff --git a/src/libfreeswan/pfkey_v2_parse.c b/src/libfreeswan/pfkey_v2_parse.c
index 7c0934c25..8fec9d119 100644
--- a/src/libfreeswan/pfkey_v2_parse.c
+++ b/src/libfreeswan/pfkey_v2_parse.c
@@ -40,12 +40,11 @@ char pfkey_v2_parse_c_version[] = "";
#define SENDERR(_x) do { error = -(_x); goto errlab; } while (0)
-struct satype_tbl {
+static struct {
uint8_t proto;
uint8_t satype;
char* name;
-}
-static satype_tbl[] = {
+} satype_tbl[] = {
{ SA_ESP, SADB_SATYPE_ESP, "ESP" },
{ SA_AH, SADB_SATYPE_AH, "AH" },
{ SA_IPIP, SADB_X_SATYPE_IPIP, "IPIP" },
diff --git a/src/libhydra/Android.mk b/src/libhydra/Android.mk
index ccc527f94..075f8dbcb 100644
--- a/src/libhydra/Android.mk
+++ b/src/libhydra/Android.mk
@@ -32,6 +32,8 @@ LOCAL_CFLAGS := $(strongswan_CFLAGS)
LOCAL_MODULE := libhydra
+LOCAL_MODULE_TAGS := optional
+
LOCAL_ARM_MODE := arm
LOCAL_PRELINK_MODULE := false
diff --git a/src/libhydra/kernel/kernel_interface.c b/src/libhydra/kernel/kernel_interface.c
index 922f27094..573557506 100644
--- a/src/libhydra/kernel/kernel_interface.c
+++ b/src/libhydra/kernel/kernel_interface.c
@@ -340,7 +340,7 @@ METHOD(kernel_interface_t, get_address_by_ts, status_t,
if (!found)
{
- DBG1(DBG_KNL, "no local address found in traffic selector %R", ts);
+ DBG2(DBG_KNL, "no local address found in traffic selector %R", ts);
return FAILED;
}
diff --git a/src/libhydra/plugins/attr_sql/sql_attribute.c b/src/libhydra/plugins/attr_sql/sql_attribute.c
index fe7811b36..714bbcd72 100644
--- a/src/libhydra/plugins/attr_sql/sql_attribute.c
+++ b/src/libhydra/plugins/attr_sql/sql_attribute.c
@@ -38,7 +38,7 @@ struct private_sql_attribute_t {
database_t *db;
/**
- * wheter to record lease history in lease table
+ * whether to record lease history in lease table
*/
bool history;
};
diff --git a/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c
index 49f5c3378..3451b673f 100644
--- a/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c
+++ b/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c
@@ -202,7 +202,9 @@ static kernel_algorithm_t encryption_algs[] = {
*/
static kernel_algorithm_t integrity_algs[] = {
{AUTH_HMAC_MD5_96, "md5" },
+ {AUTH_HMAC_MD5_128, "hmac(md5)" },
{AUTH_HMAC_SHA1_96, "sha1" },
+ {AUTH_HMAC_SHA1_160, "hmac(sha1)" },
{AUTH_HMAC_SHA2_256_96, "sha256" },
{AUTH_HMAC_SHA2_256_128, "hmac(sha256)" },
{AUTH_HMAC_SHA2_384_192, "hmac(sha384)" },
@@ -1279,6 +1281,8 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
if (int_alg != AUTH_UNDEFINED)
{
+ u_int trunc_len = 0;
+
alg_name = lookup_algorithm(integrity_algs, int_alg);
if (alg_name == NULL)
{
@@ -1289,12 +1293,26 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
DBG2(DBG_KNL, " using integrity algorithm %N with key size %d",
integrity_algorithm_names, int_alg, int_key.len * 8);
- if (int_alg == AUTH_HMAC_SHA2_256_128)
+ switch (int_alg)
+ {
+ case AUTH_HMAC_MD5_128:
+ case AUTH_HMAC_SHA2_256_128:
+ trunc_len = 128;
+ break;
+ case AUTH_HMAC_SHA1_160:
+ trunc_len = 160;
+ break;
+ default:
+ break;
+ }
+
+ if (trunc_len)
{
struct xfrm_algo_auth* algo;
/* the kernel uses SHA256 with 96 bit truncation by default,
- * use specified truncation size supported by newer kernels */
+ * use specified truncation size supported by newer kernels.
+ * also use this for untruncated MD5 and SHA1. */
rthdr->rta_type = XFRMA_ALG_AUTH_TRUNC;
rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo_auth) +
int_key.len);
@@ -1307,7 +1325,7 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
algo = (struct xfrm_algo_auth*)RTA_DATA(rthdr);
algo->alg_key_len = int_key.len * 8;
- algo->alg_trunc_len = 128;
+ algo->alg_trunc_len = trunc_len;
strcpy(algo->alg_name, alg_name);
memcpy(algo->alg_key, int_key.ptr, int_key.len);
}
@@ -1990,7 +2008,8 @@ METHOD(kernel_ipsec_t, flush_sas, status_t,
/**
* Add or update a policy in the kernel.
*
- * Note: The mutex has to be locked when entering this function.
+ * Note: The mutex has to be locked when entering this function
+ * and is unlocked here in any case.
*/
static status_t add_policy_internal(private_kernel_netlink_ipsec_t *this,
policy_entry_t *policy, policy_sa_t *mapping, bool update)
@@ -2060,6 +2079,7 @@ static status_t add_policy_internal(private_kernel_netlink_ipsec_t *this,
hdr->nlmsg_len += RTA_ALIGN(RTA_LENGTH(sizeof(struct xfrm_user_tmpl)));
if (hdr->nlmsg_len > sizeof(request))
{
+ this->mutex->unlock(this->mutex);
return FAILED;
}
@@ -2096,6 +2116,7 @@ static status_t add_policy_internal(private_kernel_netlink_ipsec_t *this,
hdr->nlmsg_len += RTA_ALIGN(rthdr->rta_len);
if (hdr->nlmsg_len > sizeof(request))
{
+ this->mutex->unlock(this->mutex);
return FAILED;
}
@@ -2544,6 +2565,7 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
hdr->nlmsg_len += RTA_ALIGN(rthdr->rta_len);
if (hdr->nlmsg_len > sizeof(request))
{
+ 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 219657541..cce0ff402 100644
--- a/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c
+++ b/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c
@@ -375,9 +375,13 @@ static void process_link(private_kernel_netlink_net_t *this,
{
if (current->ifindex == msg->ifi_index)
{
- /* we do not remove it, as an address may be added to a
- * "down" interface and we wan't to know that. */
- current->flags = msg->ifi_flags;
+ if (event)
+ {
+ update = TRUE;
+ DBG1(DBG_KNL, "interface %s deleted", current->ifname);
+ }
+ this->ifaces->remove_at(this->ifaces, enumerator);
+ iface_entry_destroy(current);
break;
}
}
@@ -1538,7 +1542,7 @@ kernel_netlink_net_t *kernel_netlink_net_create()
return NULL;
}
addr.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR |
- RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_ROUTE | RTMGRP_LINK;
+ RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE | RTMGRP_LINK;
if (bind(this->socket_events, (struct sockaddr*)&addr, sizeof(addr)))
{
DBG1(DBG_KNL, "unable to bind RT event socket");
diff --git a/src/libhydra/plugins/resolve/resolve_plugin.c b/src/libhydra/plugins/resolve/resolve_plugin.c
index d23d36127..f95827ed9 100644
--- a/src/libhydra/plugins/resolve/resolve_plugin.c
+++ b/src/libhydra/plugins/resolve/resolve_plugin.c
@@ -31,7 +31,7 @@ struct private_resolve_plugin_t {
resolve_plugin_t public;
/**
- * The registerd DNS attribute handler
+ * The registered DNS attribute handler
*/
resolve_handler_t *handler;
};
diff --git a/src/libimcv/Makefile.am b/src/libimcv/Makefile.am
index 1b240a1d9..fae9fd662 100644
--- a/src/libimcv/Makefile.am
+++ b/src/libimcv/Makefile.am
@@ -36,11 +36,3 @@ endif
if USE_IMV_SCANNER
SUBDIRS += plugins/imv_scanner
endif
-
-if USE_IMC_ATTESTATION
- SUBDIRS += plugins/imc_attestation
-endif
-
-if USE_IMV_ATTESTATION
- SUBDIRS += plugins/imv_attestation
-endif
diff --git a/src/libimcv/ietf/ietf_attr_port_filter.c b/src/libimcv/ietf/ietf_attr_port_filter.c
index c9b76dde5..b53019657 100644
--- a/src/libimcv/ietf/ietf_attr_port_filter.c
+++ b/src/libimcv/ietf/ietf_attr_port_filter.c
@@ -81,6 +81,11 @@ struct private_ietf_attr_port_filter_t {
* List of Port Filter entries
*/
linked_list_t *ports;
+
+ /**
+ * Reference count
+ */
+ refcount_t ref;
};
METHOD(pa_tnc_attr_t, get_vendor_id, pen_t,
@@ -166,12 +171,22 @@ METHOD(pa_tnc_attr_t, process, status_t,
return SUCCESS;
}
+METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*,
+ private_ietf_attr_port_filter_t *this)
+{
+ ref_get(&this->ref);
+ return &this->public.pa_tnc_attribute;
+}
+
METHOD(pa_tnc_attr_t, destroy, void,
private_ietf_attr_port_filter_t *this)
{
- this->ports->destroy_function(this->ports, free);
- free(this->value.ptr);
- free(this);
+ if (ref_put(&this->ref))
+ {
+ this->ports->destroy_function(this->ports, free);
+ free(this->value.ptr);
+ free(this);
+ }
}
METHOD(ietf_attr_port_filter_t, add_port, void,
@@ -224,6 +239,7 @@ pa_tnc_attr_t *ietf_attr_port_filter_create(void)
.set_noskip_flag = _set_noskip_flag,
.build = _build,
.process = _process,
+ .get_ref = _get_ref,
.destroy = _destroy,
},
.add_port = _add_port,
@@ -232,6 +248,7 @@ pa_tnc_attr_t *ietf_attr_port_filter_create(void)
.vendor_id = PEN_IETF,
.type = IETF_ATTR_PORT_FILTER,
.ports = linked_list_create(),
+ .ref = 1,
);
return &this->public.pa_tnc_attribute;
@@ -252,6 +269,7 @@ pa_tnc_attr_t *ietf_attr_port_filter_create_from_data(chunk_t data)
.get_value = _get_value,
.build = _build,
.process = _process,
+ .get_ref = _get_ref,
.destroy = _destroy,
},
.add_port = _add_port,
@@ -261,6 +279,7 @@ pa_tnc_attr_t *ietf_attr_port_filter_create_from_data(chunk_t data)
.type = IETF_ATTR_PORT_FILTER,
.value = chunk_clone(data),
.ports = linked_list_create(),
+ .ref = 1,
);
return &this->public.pa_tnc_attribute;
diff --git a/src/libimcv/ietf/ietf_attr_product_info.c b/src/libimcv/ietf/ietf_attr_product_info.c
index 222fef0bf..548793547 100644
--- a/src/libimcv/ietf/ietf_attr_product_info.c
+++ b/src/libimcv/ietf/ietf_attr_product_info.c
@@ -80,6 +80,10 @@ struct private_ietf_attr_product_info_t {
*/
char *product_name;
+ /**
+ * Reference count
+ */
+ refcount_t ref;
};
METHOD(pa_tnc_attr_t, get_vendor_id, pen_t,
@@ -154,12 +158,22 @@ METHOD(pa_tnc_attr_t, process, status_t,
return SUCCESS;
}
+METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*,
+ private_ietf_attr_product_info_t *this)
+{
+ ref_get(&this->ref);
+ return &this->public.pa_tnc_attribute;
+}
+
METHOD(pa_tnc_attr_t, destroy, void,
private_ietf_attr_product_info_t *this)
{
- free(this->product_name);
- free(this->value.ptr);
- free(this);
+ if (ref_put(&this->ref))
+ {
+ free(this->product_name);
+ free(this->value.ptr);
+ free(this);
+ }
}
METHOD(ietf_attr_product_info_t, get_info, char*,
@@ -194,6 +208,7 @@ pa_tnc_attr_t *ietf_attr_product_info_create(pen_t vendor_id, u_int16_t id,
.set_noskip_flag = _set_noskip_flag,
.build = _build,
.process = _process,
+ .get_ref = _get_ref,
.destroy = _destroy,
},
.get_info = _get_info,
@@ -203,6 +218,7 @@ pa_tnc_attr_t *ietf_attr_product_info_create(pen_t vendor_id, u_int16_t id,
.product_vendor_id = vendor_id,
.product_id = id,
.product_name = strdup(name),
+ .ref = 1,
);
return &this->public.pa_tnc_attribute;
@@ -223,6 +239,7 @@ pa_tnc_attr_t *ietf_attr_product_info_create_from_data(chunk_t data)
.get_value = _get_value,
.build = _build,
.process = _process,
+ .get_ref = _get_ref,
.destroy = _destroy,
},
.get_info = _get_info,
@@ -230,6 +247,7 @@ pa_tnc_attr_t *ietf_attr_product_info_create_from_data(chunk_t data)
.vendor_id = PEN_IETF,
.type = IETF_ATTR_PRODUCT_INFORMATION,
.value = chunk_clone(data),
+ .ref = 1,
);
return &this->public.pa_tnc_attribute;
diff --git a/src/libimcv/imc/imc_agent.c b/src/libimcv/imc/imc_agent.c
index 82778a5b6..6bba69733 100644
--- a/src/libimcv/imc/imc_agent.c
+++ b/src/libimcv/imc/imc_agent.c
@@ -39,9 +39,14 @@ struct private_imc_agent_t {
const char *name;
/**
- * message type of IMC
+ * message vendor ID of IMC
*/
- TNC_MessageType type;
+ TNC_VendorID vendor_id;
+
+ /**
+ * message subtype of IMC
+ */
+ TNC_MessageSubtype subtype;
/**
* ID of IMC as assigned by TNCC
@@ -49,17 +54,22 @@ struct private_imc_agent_t {
TNC_IMCID id;
/**
+ * List of additional IMC IDs assigned by TNCC
+ */
+ linked_list_t *additional_ids;
+
+ /**
* list of TNCC connection entries
*/
linked_list_t *connections;
/**
- * rwlock to lock TNCS connection entries
+ * rwlock to lock TNCC connection entries
*/
rwlock_t *connection_lock;
/**
- * Inform a TNCS about the set of message types the IMC is able to receive
+ * Inform a TNCC about the set of message types the IMC is able to receive
*
* @param imc_id IMC ID assigned by TNCC
* @param supported_types list of supported message types
@@ -71,6 +81,20 @@ struct private_imc_agent_t {
TNC_UInt32 type_count);
/**
+ * Inform a TNCC about the set of message types the IMC is able to receive
+ *
+ * @param imc_id IMC ID assigned by TNCC
+ * @param supported_vids list of supported message vendor IDs
+ * @param supported_subtypes list of supported message subtypes
+ * @param type_count number of list elements
+ * @return TNC result code
+ */
+ TNC_Result (*report_message_types_long)(TNC_IMCID imc_id,
+ TNC_VendorIDList supported_vids,
+ TNC_MessageSubtypeList supported_subtypes,
+ TNC_UInt32 type_count);
+
+ /**
* Call when an IMC-IMC message is to be sent
*
* @param imc_id IMC ID assigned by TNCC
@@ -85,6 +109,76 @@ struct private_imc_agent_t {
TNC_BufferReference msg,
TNC_UInt32 msg_len,
TNC_MessageType msg_type);
+
+
+ /**
+ * Call when an IMC-IMC message is to be sent with long message types
+ *
+ * @param imc_id IMC ID assigned by TNCC
+ * @param connection_id network connection ID assigned by TNCC
+ * @param msg_flags message flags
+ * @param msg message to send
+ * @param msg_len message length in bytes
+ * @param msg_vid message vendor ID
+ * @param msg_subtype message subtype
+ * @param dst_imc_id destination IMV ID
+ * @return TNC result code
+ */
+ TNC_Result (*send_message_long)(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 dst_imv_id);
+
+ /**
+ * Get the value of an attribute associated with a connection
+ * or with the TNCC as a whole.
+ *
+ * @param imc_id IMC ID assigned by TNCC
+ * @param connection_id network connection ID assigned by TNCC
+ * @param attribute_id attribute ID
+ * @param buffer_len length of buffer in bytes
+ * @param buffer buffer
+ * @param out_value_len size in bytes of attribute stored in buffer
+ * @return TNC result code
+ */
+ TNC_Result (*get_attribute)(TNC_IMCID imc_id,
+ TNC_ConnectionID connection_id,
+ TNC_AttributeID attribute_id,
+ TNC_UInt32 buffer_len,
+ TNC_BufferReference buffer,
+ TNC_UInt32 *out_value_len);
+
+ /**
+ * Set the value of an attribute associated with a connection
+ * or with the TNCC as a whole.
+ *
+ * @param imc_id IMV ID assigned by TNCC
+ * @param connection_id network connection ID assigned by TNCC
+ * @param attribute_id attribute ID
+ * @param buffer_len length of buffer in bytes
+ * @param buffer buffer
+ * @return TNC result code
+ */
+ TNC_Result (*set_attribute)(TNC_IMCID imc_id,
+ TNC_ConnectionID connection_id,
+ TNC_AttributeID attribute_id,
+ TNC_UInt32 buffer_len,
+ TNC_BufferReference buffer);
+
+ /**
+ * Reserve an additional IMC ID
+ *
+ * @param imc_id primary IMC ID assigned by TNCC
+ * @param out_imc_id additional IMC ID assigned by TNCC
+ * @return TNC result code
+ */
+ TNC_Result (*reserve_additional_id)(TNC_IMCID imc_id,
+ TNC_UInt32 *out_imc_id);
+
};
METHOD(imc_agent_t, bind_functions, TNC_Result,
@@ -100,6 +194,11 @@ METHOD(imc_agent_t, bind_functions, TNC_Result,
{
this->report_message_types = NULL;
}
+ if (bind_function(this->id, "TNC_TNCC_ReportMessageTypesLong",
+ (void**)&this->report_message_types_long) != TNC_RESULT_SUCCESS)
+ {
+ this->report_message_types_long = NULL;
+ }
if (bind_function(this->id, "TNC_TNCC_RequestHandshakeRetry",
(void**)&this->public.request_handshake_retry) != TNC_RESULT_SUCCESS)
{
@@ -110,12 +209,42 @@ METHOD(imc_agent_t, bind_functions, TNC_Result,
{
this->send_message = NULL;
}
+ if (bind_function(this->id, "TNC_TNCC_SendMessageLong",
+ (void**)&this->send_message_long) != TNC_RESULT_SUCCESS)
+ {
+ this->send_message_long = NULL;
+ }
+ if (bind_function(this->id, "TNC_TNCC_GetAttribute",
+ (void**)&this->get_attribute) != TNC_RESULT_SUCCESS)
+ {
+ this->get_attribute = NULL;
+ }
+ if (bind_function(this->id, "TNC_TNCC_SetAttribute",
+ (void**)&this->set_attribute) != TNC_RESULT_SUCCESS)
+ {
+ this->set_attribute = NULL;
+ }
+ if (bind_function(this->id, "TNC_TNCC_ReserveAdditionalIMCID",
+ (void**)&this->reserve_additional_id) != TNC_RESULT_SUCCESS)
+ {
+ this->reserve_additional_id = NULL;
+ }
DBG2(DBG_IMC, "IMC %u \"%s\" provided with bind function",
this->id, this->name);
- if (this->report_message_types)
+ if (this->report_message_types_long)
+ {
+ this->report_message_types_long(this->id, &this->vendor_id,
+ &this->subtype, 1);
+ }
+ else if (this->report_message_types &&
+ this->vendor_id <= TNC_VENDORID_ANY &&
+ this->subtype <= TNC_SUBTYPE_ANY)
{
- this->report_message_types(this->id, &this->type, 1);
+ TNC_MessageType type;
+
+ type = (this->vendor_id << 8) | this->subtype;
+ this->report_message_types(this->id, &type, 1);
}
return TNC_RESULT_SUCCESS;
}
@@ -172,24 +301,78 @@ static bool delete_connection(private_imc_agent_t *this, TNC_ConnectionID id)
return found;
}
+/**
+ * Read a boolean attribute
+ */
+static bool get_bool_attribute(private_imc_agent_t *this, TNC_ConnectionID id,
+ TNC_AttributeID attribute_id)
+{
+ TNC_UInt32 len;
+ char buf[4];
+
+ return this->get_attribute &&
+ this->get_attribute(this->id, id, attribute_id, 4, buf, &len) ==
+ TNC_RESULT_SUCCESS && len == 1 && *buf == 0x01;
+ }
+
+/**
+ * Read a string attribute
+ */
+static char* get_str_attribute(private_imc_agent_t *this, TNC_ConnectionID id,
+ TNC_AttributeID attribute_id)
+{
+ TNC_UInt32 len;
+ char buf[BUF_LEN];
+
+ if (this->get_attribute &&
+ this->get_attribute(this->id, id, attribute_id, BUF_LEN, buf, &len) ==
+ TNC_RESULT_SUCCESS && len <= BUF_LEN)
+ {
+ return strdup(buf);
+ }
+ return NULL;
+ }
+
METHOD(imc_agent_t, create_state, TNC_Result,
private_imc_agent_t *this, imc_state_t *state)
{
- TNC_ConnectionID connection_id;
+ TNC_ConnectionID conn_id;
+ char *tnccs_p = NULL, *tnccs_v = NULL, *t_p = NULL, *t_v = NULL;
+ bool has_long = FALSE, has_excl = FALSE, has_soh = FALSE;
- connection_id = state->get_connection_id(state);
- if (find_connection(this, connection_id))
+ conn_id = state->get_connection_id(state);
+ if (find_connection(this, conn_id))
{
DBG1(DBG_IMC, "IMC %u \"%s\" already created a state for Connection ID %u",
- this->id, this->name, connection_id);
+ this->id, this->name, conn_id);
state->destroy(state);
return TNC_RESULT_OTHER;
}
+
+ /* Get and display attributes from TNCC via IF-IMC */
+ has_long = get_bool_attribute(this, conn_id, TNC_ATTRIBUTEID_HAS_LONG_TYPES);
+ has_excl = get_bool_attribute(this, conn_id, TNC_ATTRIBUTEID_HAS_EXCLUSIVE);
+ has_soh = get_bool_attribute(this, conn_id, TNC_ATTRIBUTEID_HAS_SOH);
+ tnccs_p = get_str_attribute(this, conn_id, TNC_ATTRIBUTEID_IFTNCCS_PROTOCOL);
+ tnccs_v = get_str_attribute(this, conn_id, TNC_ATTRIBUTEID_IFTNCCS_VERSION);
+ t_p = get_str_attribute(this, conn_id, TNC_ATTRIBUTEID_IFT_PROTOCOL);
+ t_v = get_str_attribute(this, conn_id, TNC_ATTRIBUTEID_IFT_VERSION);
+
+ state->set_flags(state, has_long, has_excl);
+
+ DBG2(DBG_IMC, "IMC %u \"%s\" created a state for Connection ID %u: "
+ "%s %s with %slong %sexcl %ssoh over %s %s",
+ this->id, this->name, conn_id, tnccs_p ? tnccs_p:"?",
+ tnccs_v ? tnccs_v:"?", has_long ? "+":"-", has_excl ? "+":"-",
+ has_soh ? "+":"-", t_p ? t_p:"?", t_v ? t_v :"?");
+ free(tnccs_p);
+ free(tnccs_v);
+ free(t_p);
+ free(t_v);
+
this->connection_lock->write_lock(this->connection_lock);
this->connections->insert_last(this->connections, state);
this->connection_lock->unlock(this->connection_lock);
- DBG2(DBG_IMC, "IMC %u \"%s\" created a state for Connection ID %u",
- this->id, this->name, connection_id);
return TNC_RESULT_SUCCESS;
}
@@ -269,27 +452,78 @@ METHOD(imc_agent_t, get_state, bool,
}
METHOD(imc_agent_t, send_message, TNC_Result,
- private_imc_agent_t *this, TNC_ConnectionID connection_id, chunk_t msg)
+ private_imc_agent_t *this, TNC_ConnectionID connection_id, bool excl,
+ TNC_UInt32 src_imc_id, TNC_UInt32 dst_imv_id, chunk_t msg)
{
- if (!this->send_message)
+ TNC_MessageType type;
+ TNC_UInt32 msg_flags;
+ imc_state_t *state;
+
+ state = find_connection(this, connection_id);
+ if (!state)
{
+ DBG1(DBG_IMV, "IMC %u \"%s\" has no state for Connection ID %u",
+ this->id, this->name, connection_id);
return TNC_RESULT_FATAL;
}
- return this->send_message(this->id, connection_id, msg.ptr, msg.len,
- this->type);
+
+ if (state->has_long(state) && this->send_message_long)
+ {
+ if (!src_imc_id)
+ {
+ src_imc_id = this->id;
+ }
+ msg_flags = excl ? TNC_MESSAGE_FLAGS_EXCLUSIVE : 0;
+
+ return this->send_message_long(src_imc_id, connection_id, msg_flags,
+ msg.ptr, msg.len, this->vendor_id,
+ this->subtype, dst_imv_id);
+ }
+ if (this->send_message)
+ {
+ type = (this->vendor_id << 8) | this->subtype;
+
+ return this->send_message(this->id, connection_id, msg.ptr, msg.len,
+ type);
+ }
+ return TNC_RESULT_FATAL;
}
METHOD(imc_agent_t, receive_message, TNC_Result,
- private_imc_agent_t *this, TNC_ConnectionID connection_id, chunk_t msg,
- TNC_MessageType msg_type, pa_tnc_msg_t **pa_tnc_msg)
+ private_imc_agent_t *this, imc_state_t *state, chunk_t msg,
+ TNC_VendorID msg_vid, TNC_MessageSubtype msg_subtype,
+ TNC_UInt32 src_imv_id, TNC_UInt32 dst_imc_id, pa_tnc_msg_t **pa_tnc_msg)
{
pa_tnc_msg_t *pa_msg, *error_msg;
pa_tnc_attr_t *error_attr;
enumerator_t *enumerator;
+ TNC_MessageType msg_type;
+ TNC_UInt32 msg_flags, src_imc_id, dst_imv_id;
+ TNC_ConnectionID connection_id;
TNC_Result result;
- DBG2(DBG_IMV, "IMC %u \"%s\" received message type 0x%08x for Connection ID %u",
- this->id, this->name, msg_type, connection_id);
+ connection_id = state->get_connection_id(state);
+
+ if (state->has_long(state))
+ {
+ if (dst_imc_id != TNC_IMCID_ANY)
+ {
+ DBG2(DBG_IMC, "IMC %u \"%s\" received message for Connection ID %u "
+ "from IMV %u to IMC %u", this->id, this->name,
+ connection_id, src_imv_id, dst_imc_id);
+ }
+ else
+ {
+ DBG2(DBG_IMC, "IMC %u \"%s\" received message for Connection ID %u "
+ "from IMV %u", this->id, this->name, connection_id,
+ src_imv_id);
+ }
+ }
+ else
+ {
+ DBG2(DBG_IMC, "IMC %u \"%s\" received message for Connection ID %u",
+ this->id, this->name, connection_id);
+ }
*pa_tnc_msg = NULL;
pa_msg = pa_tnc_msg_create_from_data(msg);
@@ -300,12 +534,6 @@ METHOD(imc_agent_t, receive_message, TNC_Result,
*pa_tnc_msg = pa_msg;
break;
case VERIFY_ERROR:
- if (!this->send_message)
- {
- /* TNCC doen't have a SendMessage() function */
- return TNC_RESULT_FATAL;
- }
-
/* build error message */
error_msg = pa_tnc_msg_create();
enumerator = pa_msg->create_error_enumerator(pa_msg);
@@ -318,9 +546,36 @@ METHOD(imc_agent_t, receive_message, TNC_Result,
error_msg->build(error_msg);
/* send error message */
- msg = error_msg->get_encoding(error_msg);
- result = this->send_message(this->id, connection_id,
+ if (state->has_long(state) && this->send_message_long)
+ {
+ if (state->has_excl(state))
+ {
+ msg_flags = TNC_MESSAGE_FLAGS_EXCLUSIVE;
+ dst_imv_id = src_imv_id;
+ }
+ else
+ {
+ msg_flags = 0;
+ dst_imv_id = TNC_IMVID_ANY;
+ }
+ src_imc_id = (dst_imc_id == TNC_IMCID_ANY) ? this->id
+ : dst_imc_id;
+
+ result = this->send_message_long(src_imc_id, connection_id,
+ msg_flags, msg.ptr, msg.len, msg_vid,
+ msg_subtype, dst_imv_id);
+ }
+ else if (this->send_message)
+ {
+ msg_type = (msg_vid << 8) | msg_subtype;
+
+ result = this->send_message(this->id, connection_id,
msg.ptr, msg.len, msg_type);
+ }
+ else
+ {
+ result = TNC_RESULT_FATAL;
+ }
/* clean up */
error_msg->destroy(error_msg);
@@ -334,10 +589,56 @@ METHOD(imc_agent_t, receive_message, TNC_Result,
return TNC_RESULT_SUCCESS;
}
+METHOD(imc_agent_t, reserve_additional_ids, TNC_Result,
+ private_imc_agent_t *this, int count)
+{
+ TNC_Result result;
+ TNC_UInt32 id;
+ void *pointer;
+
+ if (!this->reserve_additional_id)
+ {
+ DBG1(DBG_IMC, "IMC %u \"%s\" did not detect the capability to reserve "
+ "additional IMC IDs from the TNCC", this->id, this->name);
+ return TNC_RESULT_ILLEGAL_OPERATION;
+ }
+ while (count > 0)
+ {
+ result = this->reserve_additional_id(this->id, &id);
+ if (result != TNC_RESULT_SUCCESS)
+ {
+ DBG1(DBG_IMC, "IMC %u \"%s\" failed to reserve %d additional IMC IDs",
+ this->id, this->name, count);
+ return result;
+ }
+ count--;
+
+ /* store the scalar value in the pointer */
+ pointer = (void*)id;
+ this->additional_ids->insert_last(this->additional_ids, pointer);
+ DBG2(DBG_IMC, "IMC %u \"%s\" reserved additional ID %u",
+ this->id, this->name, id);
+ }
+ return TNC_RESULT_SUCCESS;
+}
+
+METHOD(imc_agent_t, count_additional_ids, int,
+ private_imc_agent_t *this)
+{
+ return this->additional_ids->get_count(this->additional_ids);
+}
+
+METHOD(imc_agent_t, create_id_enumerator, enumerator_t*,
+ private_imc_agent_t *this)
+{
+ return this->additional_ids->create_enumerator(this->additional_ids);
+}
+
METHOD(imc_agent_t, destroy, void,
private_imc_agent_t *this)
{
DBG1(DBG_IMC, "IMC %u \"%s\" terminated", this->id, this->name);
+ this->additional_ids->destroy(this->additional_ids);
this->connections->destroy_function(this->connections, free);
this->connection_lock->destroy(this->connection_lock);
free(this);
@@ -370,11 +671,16 @@ imc_agent_t *imc_agent_create(const char *name,
.get_state = _get_state,
.send_message = _send_message,
.receive_message = _receive_message,
+ .reserve_additional_ids = _reserve_additional_ids,
+ .count_additional_ids = _count_additional_ids,
+ .create_id_enumerator = _create_id_enumerator,
.destroy = _destroy,
},
.name = name,
- .type = (vendor_id << 8) | (subtype & 0xff),
+ .vendor_id = vendor_id,
+ .subtype = subtype,
.id = id,
+ .additional_ids = linked_list_create(),
.connections = linked_list_create(),
.connection_lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
);
diff --git a/src/libimcv/imc/imc_agent.h b/src/libimcv/imc/imc_agent.h
index 1912a39c1..d1fef4d8d 100644
--- a/src/libimcv/imc/imc_agent.h
+++ b/src/libimcv/imc/imc_agent.h
@@ -101,28 +101,58 @@ struct imc_agent_t {
* Call when an PA-TNC message is to be sent
*
* @param connection_id network connection ID assigned by TNCC
+ * @param excl exclusive flag
+ * @param src_imc_id IMC ID to be set as source
+ * @param dst_imv_id IMV ID to be set as destination
* @param msg message to send
* @return TNC result code
*/
TNC_Result (*send_message)(imc_agent_t *this,
- TNC_ConnectionID connection_id,
+ TNC_ConnectionID connection_id, bool excl,
+ TNC_UInt32 src_imc_id, TNC_UInt32 dst_imv_id,
chunk_t msg);
/**
* Call when a PA-TNC message was received
*
- * @param connection_id network connection ID assigned by TNCC
+ * @param state state for current connection
* @param msg received unparsed message
- * @param msg_type message type of the received message
+ * @param msg_vid message vendorID of the received message
+ * @param msg_subtype message subtype of the received message
+ * @param src_imv_id source IMV ID
+ * @param dst_imc_id destination IMC ID
* @param pa_tnc_message parsed PA-TNC message or NULL if an error occurred
* @return TNC result code
*/
TNC_Result (*receive_message)(imc_agent_t *this,
- TNC_ConnectionID connection_id, chunk_t msg,
- TNC_MessageType msg_type,
+ imc_state_t *state, chunk_t msg,
+ TNC_VendorID msg_vid,
+ TNC_MessageSubtype msg_subtype,
+ TNC_UInt32 src_imv_id,
+ TNC_UInt32 dst_imc_id,
pa_tnc_msg_t **pa_tnc_msg);
/**
+ * Reserve additional IMC IDs from TNCC
+ *
+ * @param count number of additional IMC IDs to be assigned
+ * @return TNC result code
+ */
+ TNC_Result (*reserve_additional_ids)(imc_agent_t *this, int count);
+
+ /**
+ * Return the number of additional IMC IDs assigned by the TNCC
+ *
+ * @return number of additional IMC IDs
+ */
+ int (*count_additional_ids)(imc_agent_t *this);
+
+ /**
+ * Create an enumerator for the additional IMC IDs
+ */
+ enumerator_t* (*create_id_enumerator)(imc_agent_t *this);
+
+ /**
* Destroys an imc_agent_t object
*/
void (*destroy)(imc_agent_t *this);
diff --git a/src/libimcv/imc/imc_state.h b/src/libimcv/imc/imc_state.h
index 73013f8ce..f1b0358c9 100644
--- a/src/libimcv/imc/imc_state.h
+++ b/src/libimcv/imc/imc_state.h
@@ -33,13 +33,37 @@ typedef struct imc_state_t imc_state_t;
struct imc_state_t {
/**
- * Get the TNCS connection ID attached to the state
+ * Get the TNCS connection I
+D attached to the state
*
* @return TNCS connection ID of the state
*/
TNC_ConnectionID (*get_connection_id)(imc_state_t *this);
/**
+ * Checks if long message types are supported for this TNCCS connection
+ *
+ * @return TRUE if set, FALSE otherwise
+ */
+ bool (*has_long)(imc_state_t *this);
+
+ /**
+ * Checks if the exclusive delivery is supported for this TNCCS connection
+ *
+ * @return TRUE if set, FALSE otherwise
+ */
+ bool (*has_excl)(imc_state_t *this);
+
+ /**
+ * Sets the long message types and exclusive flags for this TNCCS connection
+ *
+ * @param has_long TNCCS connection supports long message types
+ * @param has_excl TNCCS connection supports exclusive delivery
+ * @return TRUE if set, FALSE otherwise
+ */
+ void (*set_flags)(imc_state_t *this, bool has_long, bool has_excl);
+
+ /**
* Change the connection state
*
* @param new_state new connection state
diff --git a/src/libimcv/imv/imv_agent.c b/src/libimcv/imv/imv_agent.c
index 290bb1147..56131c547 100644
--- a/src/libimcv/imv/imv_agent.c
+++ b/src/libimcv/imv/imv_agent.c
@@ -39,9 +39,14 @@ struct private_imv_agent_t {
const char *name;
/**
- * message type of IMV
+ * message vendor ID of IMV
*/
- TNC_MessageType type;
+ TNC_VendorID vendor_id;
+
+ /**
+ * message subtype of IMV
+ */
+ TNC_MessageSubtype subtype;
/**
* ID of IMV as assigned by TNCS
@@ -49,6 +54,11 @@ struct private_imv_agent_t {
TNC_IMVID id;
/**
+ * List of additional IMV IDs assigned by TNCS
+ */
+ linked_list_t *additional_ids;
+
+ /**
* list of TNCS connection entries
*/
linked_list_t *connections;
@@ -59,7 +69,7 @@ struct private_imv_agent_t {
rwlock_t *connection_lock;
/**
- * Inform a TNCS about the set of message types the IMV is able to receive
+ * Inform a TNCS about the set of message types the IMV is able to receive
*
* @param imv_id IMV ID assigned by TNCS
* @param supported_types list of supported message types
@@ -71,6 +81,20 @@ struct private_imv_agent_t {
TNC_UInt32 type_count);
/**
+ * Inform a TNCS about the set of message types the IMV is able to receive
+ *
+ * @param imv_id IMV ID assigned by TNCS
+ * @param supported_vids list of supported message vendor IDs
+ * @param supported_subtypes list of supported message subtypes
+ * @param type_count number of list elements
+ * @return TNC result code
+ */
+ TNC_Result (*report_message_types_long)(TNC_IMVID imv_id,
+ TNC_VendorIDList supported_vids,
+ TNC_MessageSubtypeList supported_subtypes,
+ TNC_UInt32 type_count);
+
+ /**
* Call when an IMV-IMC message is to be sent
*
* @param imv_id IMV ID assigned by TNCS
@@ -87,6 +111,28 @@ struct private_imv_agent_t {
TNC_MessageType msg_type);
/**
+ * Call when an IMV-IMC message is to be sent with long message types
+ *
+ * @param imv_id IMV ID assigned by TNCS
+ * @param connection_id network connection ID assigned by TNCS
+ * @param msg_flags message flags
+ * @param msg message to send
+ * @param msg_len message length in bytes
+ * @param msg_vid message vendor ID
+ * @param msg_subtype message subtype
+ * @param dst_imc_id destination IMC ID
+ * @return TNC result code
+ */
+ TNC_Result (*send_message_long)(TNC_IMVID imv_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 dst_imc_id);
+
+ /**
* Deliver IMV Action Recommendation and IMV Evaluation Results to the TNCS
*
* @param imv_id IMV ID assigned by TNCS
@@ -135,6 +181,17 @@ struct private_imv_agent_t {
TNC_AttributeID attribute_id,
TNC_UInt32 buffer_len,
TNC_BufferReference buffer);
+
+ /**
+ * Reserve an additional IMV ID
+ *
+ * @param imv_id primary IMV ID assigned by TNCS
+ * @param out_imv_id additional IMV ID assigned by TNCS
+ * @return TNC result code
+ */
+ TNC_Result (*reserve_additional_id)(TNC_IMVID imv_id,
+ TNC_UInt32 *out_imv_id);
+
};
METHOD(imv_agent_t, bind_functions, TNC_Result,
@@ -150,6 +207,11 @@ METHOD(imv_agent_t, bind_functions, TNC_Result,
{
this->report_message_types = NULL;
}
+ if (bind_function(this->id, "TNC_TNCS_ReportMessageTypesLong",
+ (void**)&this->report_message_types_long) != TNC_RESULT_SUCCESS)
+ {
+ this->report_message_types_long = NULL;
+ }
if (bind_function(this->id, "TNC_TNCS_RequestHandshakeRetry",
(void**)&this->public.request_handshake_retry) != TNC_RESULT_SUCCESS)
{
@@ -160,6 +222,11 @@ METHOD(imv_agent_t, bind_functions, TNC_Result,
{
this->send_message = NULL;
}
+ if (bind_function(this->id, "TNC_TNCS_SendMessageLong",
+ (void**)&this->send_message_long) != TNC_RESULT_SUCCESS)
+ {
+ this->send_message_long = NULL;
+ }
if (bind_function(this->id, "TNC_TNCS_ProvideRecommendation",
(void**)&this->provide_recommendation) != TNC_RESULT_SUCCESS)
{
@@ -175,12 +242,27 @@ METHOD(imv_agent_t, bind_functions, TNC_Result,
{
this->set_attribute = NULL;
}
+ if (bind_function(this->id, "TNC_TNCC_ReserveAdditionalIMVID",
+ (void**)&this->reserve_additional_id) != TNC_RESULT_SUCCESS)
+ {
+ this->reserve_additional_id = NULL;
+ }
DBG2(DBG_IMV, "IMV %u \"%s\" provided with bind function",
this->id, this->name);
- if (this->report_message_types)
+ if (this->report_message_types_long)
+ {
+ this->report_message_types_long(this->id, &this->vendor_id,
+ &this->subtype, 1);
+ }
+ else if (this->report_message_types &&
+ this->vendor_id <= TNC_VENDORID_ANY &&
+ this->subtype <= TNC_SUBTYPE_ANY)
{
- this->report_message_types(this->id, &this->type, 1);
+ TNC_MessageType type;
+
+ type = (this->vendor_id << 8) | this->subtype;
+ this->report_message_types(this->id, &type, 1);
}
return TNC_RESULT_SUCCESS;
}
@@ -237,24 +319,78 @@ static bool delete_connection(private_imv_agent_t *this, TNC_ConnectionID id)
return found;
}
+/**
+ * Read a boolean attribute
+ */
+static bool get_bool_attribute(private_imv_agent_t *this, TNC_ConnectionID id,
+ TNC_AttributeID attribute_id)
+{
+ TNC_UInt32 len;
+ char buf[4];
+
+ return this->get_attribute &&
+ this->get_attribute(this->id, id, attribute_id, 4, buf, &len) ==
+ TNC_RESULT_SUCCESS && len == 1 && *buf == 0x01;
+ }
+
+/**
+ * Read a string attribute
+ */
+static char* get_str_attribute(private_imv_agent_t *this, TNC_ConnectionID id,
+ TNC_AttributeID attribute_id)
+{
+ TNC_UInt32 len;
+ char buf[BUF_LEN];
+
+ if (this->get_attribute &&
+ this->get_attribute(this->id, id, attribute_id, BUF_LEN, buf, &len) ==
+ TNC_RESULT_SUCCESS && len <= BUF_LEN)
+ {
+ return strdup(buf);
+ }
+ return NULL;
+ }
+
METHOD(imv_agent_t, create_state, TNC_Result,
private_imv_agent_t *this, imv_state_t *state)
{
- TNC_ConnectionID connection_id;
+ TNC_ConnectionID conn_id;
+ char *tnccs_p = NULL, *tnccs_v = NULL, *t_p = NULL, *t_v = NULL;
+ bool has_long = FALSE, has_excl = FALSE, has_soh = FALSE;
- connection_id = state->get_connection_id(state);
- if (find_connection(this, connection_id))
+ conn_id = state->get_connection_id(state);
+ if (find_connection(this, conn_id))
{
DBG1(DBG_IMV, "IMV %u \"%s\" already created a state for Connection ID %u",
- this->id, this->name, connection_id);
+ this->id, this->name, conn_id);
state->destroy(state);
return TNC_RESULT_OTHER;
}
+
+ /* Get and display attributes from TNCS via IF-IMV */
+ has_long = get_bool_attribute(this, conn_id, TNC_ATTRIBUTEID_HAS_LONG_TYPES);
+ has_excl = get_bool_attribute(this, conn_id, TNC_ATTRIBUTEID_HAS_EXCLUSIVE);
+ has_soh = get_bool_attribute(this, conn_id, TNC_ATTRIBUTEID_HAS_SOH);
+ tnccs_p = get_str_attribute(this, conn_id, TNC_ATTRIBUTEID_IFTNCCS_PROTOCOL);
+ tnccs_v = get_str_attribute(this, conn_id, TNC_ATTRIBUTEID_IFTNCCS_VERSION);
+ t_p = get_str_attribute(this, conn_id, TNC_ATTRIBUTEID_IFT_PROTOCOL);
+ t_v = get_str_attribute(this, conn_id, TNC_ATTRIBUTEID_IFT_VERSION);
+
+ state->set_flags(state, has_long, has_excl);
+
+ DBG2(DBG_IMV, "IMV %u \"%s\" created a state for Connection ID %u: "
+ "%s %s with %slong %sexcl %ssoh over %s %s",
+ this->id, this->name, conn_id, tnccs_p ? tnccs_p:"?",
+ tnccs_v ? tnccs_v:"?", has_long ? "+":"-", has_excl ? "+":"-",
+ has_soh ? "+":"-", t_p ? t_p:"?", t_v ? t_v :"?");
+ free(tnccs_p);
+ free(tnccs_v);
+ free(t_p);
+ free(t_v);
+
this->connection_lock->write_lock(this->connection_lock);
this->connections->insert_last(this->connections, state);
this->connection_lock->unlock(this->connection_lock);
- DBG2(DBG_IMV, "IMV %u \"%s\" created a state for Connection ID %u",
- this->id, this->name, connection_id);
return TNC_RESULT_SUCCESS;
}
@@ -333,14 +469,41 @@ METHOD(imv_agent_t, get_state, bool,
}
METHOD(imv_agent_t, send_message, TNC_Result,
- private_imv_agent_t *this, TNC_ConnectionID connection_id, chunk_t msg)
+ private_imv_agent_t *this, TNC_ConnectionID connection_id, bool excl,
+ TNC_UInt32 src_imv_id, TNC_UInt32 dst_imc_id, chunk_t msg)
{
- if (!this->send_message)
+ TNC_MessageType type;
+ TNC_UInt32 msg_flags;
+ imv_state_t *state;
+
+ state = find_connection(this, connection_id);
+ if (!state)
{
+ DBG1(DBG_IMV, "IMV %u \"%s\" has no state for Connection ID %u",
+ this->id, this->name, connection_id);
return TNC_RESULT_FATAL;
}
- return this->send_message(this->id, connection_id, msg.ptr, msg.len,
- this->type);
+
+ if (state->has_long(state) && this->send_message_long)
+ {
+ if (!src_imv_id)
+ {
+ src_imv_id = this->id;
+ }
+ msg_flags = excl ? TNC_MESSAGE_FLAGS_EXCLUSIVE : 0;
+
+ return this->send_message_long(src_imv_id, connection_id, msg_flags,
+ msg.ptr, msg.len, this->vendor_id,
+ this->subtype, dst_imc_id);
+ }
+ if (this->send_message)
+ {
+ type = (this->vendor_id << 8) | this->subtype;
+
+ return this->send_message(this->id, connection_id, msg.ptr, msg.len,
+ type);
+ }
+ return TNC_RESULT_FATAL;
}
METHOD(imv_agent_t, set_recommendation, TNC_Result,
@@ -363,16 +526,40 @@ METHOD(imv_agent_t, set_recommendation, TNC_Result,
}
METHOD(imv_agent_t, receive_message, TNC_Result,
- private_imv_agent_t *this, TNC_ConnectionID connection_id, chunk_t msg,
- TNC_MessageType msg_type, pa_tnc_msg_t **pa_tnc_msg)
+ private_imv_agent_t *this, imv_state_t *state, chunk_t msg,
+ TNC_VendorID msg_vid, TNC_MessageSubtype msg_subtype,
+ TNC_UInt32 src_imc_id, TNC_UInt32 dst_imv_id, pa_tnc_msg_t **pa_tnc_msg)
{
pa_tnc_msg_t *pa_msg, *error_msg;
pa_tnc_attr_t *error_attr;
enumerator_t *enumerator;
+ TNC_MessageType msg_type;
+ TNC_UInt32 msg_flags, src_imv_id, dst_imc_id;
+ TNC_ConnectionID connection_id;
TNC_Result result;
- DBG2(DBG_IMV, "IMV %u \"%s\" received message type 0x%08x for Connection ID %u",
- this->id, this->name, msg_type, connection_id);
+ connection_id = state->get_connection_id(state);
+
+ if (state->has_long(state))
+ {
+ if (dst_imv_id != TNC_IMVID_ANY)
+ {
+ DBG2(DBG_IMV, "IMV %u \"%s\" received message for Connection ID %u "
+ "from IMC %u to IMV %u", this->id, this->name,
+ connection_id, src_imc_id, dst_imv_id);
+ }
+ else
+ {
+ DBG2(DBG_IMV, "IMV %u \"%s\" received message for Connection ID %u "
+ "from IMC %u", this->id, this->name, connection_id,
+ src_imc_id);
+ }
+ }
+ else
+ {
+ DBG2(DBG_IMV, "IMV %u \"%s\" received message for Connection ID %u",
+ this->id, this->name, connection_id);
+ }
*pa_tnc_msg = NULL;
pa_msg = pa_tnc_msg_create_from_data(msg);
@@ -383,12 +570,6 @@ METHOD(imv_agent_t, receive_message, TNC_Result,
*pa_tnc_msg = pa_msg;
break;
case VERIFY_ERROR:
- if (!this->send_message)
- {
- /* TNCS doen't have a SendMessage() function */
- return TNC_RESULT_FATAL;
- }
-
/* build error message */
error_msg = pa_tnc_msg_create();
enumerator = pa_msg->create_error_enumerator(pa_msg);
@@ -402,8 +583,37 @@ METHOD(imv_agent_t, receive_message, TNC_Result,
/* send error message */
msg = error_msg->get_encoding(error_msg);
- result = this->send_message(this->id, connection_id,
+
+ if (state->has_long(state) && this->send_message_long)
+ {
+ if (state->has_excl(state))
+ {
+ msg_flags = TNC_MESSAGE_FLAGS_EXCLUSIVE;
+ dst_imc_id = src_imc_id;
+ }
+ else
+ {
+ msg_flags = 0;
+ dst_imc_id = TNC_IMCID_ANY;
+ }
+ src_imv_id = (dst_imv_id == TNC_IMVID_ANY) ? this->id
+ : dst_imv_id;
+
+ result = this->send_message_long(src_imv_id, connection_id,
+ msg_flags, msg.ptr, msg.len, msg_vid,
+ msg_subtype, dst_imc_id);
+ }
+ else if (this->send_message)
+ {
+ msg_type = (msg_vid << 8) | msg_subtype;
+
+ result = this->send_message(this->id, connection_id,
msg.ptr, msg.len, msg_type);
+ }
+ else
+ {
+ result = TNC_RESULT_FATAL;
+ }
/* clean up */
error_msg->destroy(error_msg);
@@ -412,7 +622,10 @@ METHOD(imv_agent_t, receive_message, TNC_Result,
case FAILED:
default:
pa_msg->destroy(pa_msg);
- return set_recommendation(this, connection_id,
+ state->set_recommendation(state,
+ TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION,
+ TNC_IMV_EVALUATION_RESULT_ERROR);
+ return this->provide_recommendation(this->id, connection_id,
TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION,
TNC_IMV_EVALUATION_RESULT_ERROR);
}
@@ -471,10 +684,56 @@ METHOD(imv_agent_t, provide_recommendation, TNC_Result,
return this->provide_recommendation(this->id, connection_id, rec, eval);
}
+METHOD(imv_agent_t, reserve_additional_ids, TNC_Result,
+ private_imv_agent_t *this, int count)
+{
+ TNC_Result result;
+ TNC_UInt32 id;
+ void *pointer;
+
+ if (!this->reserve_additional_id)
+ {
+ DBG1(DBG_IMV, "IMV %u \"%s\" did not detect the capability to reserve "
+ "additional IMV IDs from the TNCS", this->id, this->name);
+ return TNC_RESULT_ILLEGAL_OPERATION;
+ }
+ while (count > 0)
+ {
+ result = this->reserve_additional_id(this->id, &id);
+ if (result != TNC_RESULT_SUCCESS)
+ {
+ DBG1(DBG_IMV, "IMV %u \"%s\" failed to reserve %d additional IMV IDs",
+ this->id, this->name, count);
+ return result;
+ }
+ count--;
+
+ /* store the scalar value in the pointer */
+ pointer = (void*)id;
+ this->additional_ids->insert_last(this->additional_ids, pointer);
+ DBG2(DBG_IMV, "IMV %u \"%s\" reserved additional ID %u",
+ this->id, this->name, id);
+ }
+ return TNC_RESULT_SUCCESS;
+}
+
+METHOD(imv_agent_t, count_additional_ids, int,
+ private_imv_agent_t *this)
+{
+ return this->additional_ids->get_count(this->additional_ids);
+}
+
+METHOD(imv_agent_t, create_id_enumerator, enumerator_t*,
+ private_imv_agent_t *this)
+{
+ return this->additional_ids->create_enumerator(this->additional_ids);
+}
+
METHOD(imv_agent_t, destroy, void,
private_imv_agent_t *this)
{
DBG1(DBG_IMV, "IMV %u \"%s\" terminated", this->id, this->name);
+ this->additional_ids->destroy(this->additional_ids);
this->connections->destroy_offset(this->connections,
offsetof(imv_state_t, destroy));
this->connection_lock->destroy(this->connection_lock);
@@ -510,11 +769,16 @@ imv_agent_t *imv_agent_create(const char *name,
.receive_message = _receive_message,
.set_recommendation = _set_recommendation,
.provide_recommendation = _provide_recommendation,
+ .reserve_additional_ids = _reserve_additional_ids,
+ .count_additional_ids = _count_additional_ids,
+ .create_id_enumerator = _create_id_enumerator,
.destroy = _destroy,
},
.name = name,
- .type = (vendor_id << 8) | (subtype & 0xff),
+ .vendor_id = vendor_id,
+ .subtype = subtype,
.id = id,
+ .additional_ids = linked_list_create(),
.connections = linked_list_create(),
.connection_lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
);
diff --git a/src/libimcv/imv/imv_agent.h b/src/libimcv/imv/imv_agent.h
index b6c8841f2..de70f3bc1 100644
--- a/src/libimcv/imv/imv_agent.h
+++ b/src/libimcv/imv/imv_agent.h
@@ -101,24 +101,35 @@ struct imv_agent_t {
* Call when a PA-TNC message is to be sent
*
* @param connection_id network connection ID assigned by TNCS
+ * @param excl exclusive flag
+ * @param src_imv_id IMV ID to be set as source
+ * @param dst_imc_id IMD ID to be set as destination
* @param msg message to send
* @return TNC result code
*/
TNC_Result (*send_message)(imv_agent_t *this,
- TNC_ConnectionID connection_id, chunk_t msg);
+ TNC_ConnectionID connection_id, bool excl,
+ TNC_UInt32 src_imv_id, TNC_UInt32 dst_imc_id,
+ chunk_t msg);
/**
* Call when a PA-TNC message was received
*
- * @param connection_id network connection ID assigned by TNCS
+ * @param state state for current connection
* @param msg received unparsed message
- * @param msg_type message type of the received message
+ * @param msg_vid message vendorID of the received message
+ * @param msg_subtype message subtype of the received message
+ * @param src_imc_id source IMC ID
+ * @param dst_imv_id destination IMV ID
* @param pa_tnc_message parsed PA-TNC message or NULL if an error occurred
* @return TNC result code
*/
TNC_Result (*receive_message)(imv_agent_t *this,
- TNC_ConnectionID connection_id, chunk_t msg,
- TNC_MessageType msg_type,
+ imv_state_t *state, chunk_t msg,
+ TNC_VendorID msg_vid,
+ TNC_MessageSubtype msg_subtype,
+ TNC_UInt32 src_imc_id,
+ TNC_UInt32 dst_imv_id,
pa_tnc_msg_t **pa_tnc_msg);
/**
@@ -144,6 +155,26 @@ struct imv_agent_t {
TNC_ConnectionID connection_id);
/**
+ * Reserve additional IMV IDs from TNCS
+ *
+ * @param count number of additional IMV IDs to be assigned
+ * @return TNC result code
+ */
+ TNC_Result (*reserve_additional_ids)(imv_agent_t *this, int count);
+
+ /**
+ * Return the number of additional IMV IDs assigned by the TNCS
+ *
+ * @return number of additional IMV IDs
+ */
+ int (*count_additional_ids)(imv_agent_t *this);
+
+ /**
+ * Create an enumerator for the additional IMV IDs
+ */
+ enumerator_t* (*create_id_enumerator)(imv_agent_t *this);
+
+ /**
* Destroys an imv_agent_t object
*/
void (*destroy)(imv_agent_t *this);
diff --git a/src/libimcv/imv/imv_state.h b/src/libimcv/imv/imv_state.h
index 26d07bb02..9e7a29a9f 100644
--- a/src/libimcv/imv/imv_state.h
+++ b/src/libimcv/imv/imv_state.h
@@ -40,6 +40,29 @@ struct imv_state_t {
TNC_ConnectionID (*get_connection_id)(imv_state_t *this);
/**
+ * Checks if long message types are supported for this TNCCS connection
+ *
+ * @return TRUE if set, FALSE otherwise
+ */
+ bool (*has_long)(imv_state_t *this);
+
+ /**
+ * Checks if the exclusive delivery is supported for this TNCCS connection
+ *
+ * @return TRUE if set, FALSE otherwise
+ */
+ bool (*has_excl)(imv_state_t *this);
+
+ /**
+ * Sets the long message types and exclusive flags for this TNCCS connection
+ *
+ * @param has_long TNCCS connection supports long message types
+ * @param has_excl TNCCS connection supports exclusive delivery
+ * @return TRUE if set, FALSE otherwise
+ */
+ void (*set_flags)(imv_state_t *this, bool has_long, bool has_excl);
+
+ /**
* Change the connection state
*
* @param new_state new connection state
diff --git a/src/libimcv/pa_tnc/pa_tnc_msg.c b/src/libimcv/pa_tnc/pa_tnc_msg.c
index f8d3b9d0e..b5df0a5b5 100644
--- a/src/libimcv/pa_tnc/pa_tnc_msg.c
+++ b/src/libimcv/pa_tnc/pa_tnc_msg.c
@@ -311,6 +311,63 @@ err:
return VERIFY_ERROR;
}
+METHOD(pa_tnc_msg_t, process_ietf_std_errors, bool,
+ private_pa_tnc_msg_t *this)
+{
+ enumerator_t *enumerator;
+ pa_tnc_attr_t *attr;
+ bool fatal_error = FALSE;
+
+ enumerator = this->attributes->create_enumerator(this->attributes);
+ while (enumerator->enumerate(enumerator, &attr))
+ {
+ if (attr->get_vendor_id(attr) == PEN_IETF &&
+ attr->get_type(attr) == IETF_ATTR_PA_TNC_ERROR)
+ {
+ ietf_attr_pa_tnc_error_t *error_attr;
+ pen_t error_vendor_id;
+ pa_tnc_error_code_t error_code;
+ chunk_t msg_info, attr_info;
+ u_int32_t offset;
+
+ error_attr = (ietf_attr_pa_tnc_error_t*)attr;
+ error_vendor_id = error_attr->get_vendor_id(error_attr);
+ error_code = error_attr->get_error_code(error_attr);
+ msg_info = error_attr->get_msg_info(error_attr);
+
+ /* skip errors from non-IETF namespaces */
+ if (error_vendor_id != PEN_IETF)
+ {
+ continue;
+ }
+ DBG1(DBG_IMC, "received PA-TNC error '%N' concerning message "
+ "0x%08x/0x%08x", pa_tnc_error_code_names, error_code,
+ untoh32(msg_info.ptr), untoh32(msg_info.ptr + 4));
+
+ switch (error_code)
+ {
+ case PA_ERROR_INVALID_PARAMETER:
+ offset = error_attr->get_offset(error_attr);
+ DBG1(DBG_IMC, " occurred at offset of %u bytes", offset);
+ break;
+ case PA_ERROR_ATTR_TYPE_NOT_SUPPORTED:
+ attr_info = error_attr->get_attr_info(error_attr);
+ DBG1(DBG_IMC, " unsupported attribute %#B", &attr_info);
+ break;
+ default:
+ break;
+ }
+
+ /* remove the processed IETF standard error attribute */
+ this->attributes->remove_at(this->attributes, enumerator);
+ fatal_error = TRUE;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ return fatal_error;
+}
+
METHOD(pa_tnc_msg_t, create_attribute_enumerator, enumerator_t*,
private_pa_tnc_msg_t *this)
{
@@ -347,6 +404,7 @@ pa_tnc_msg_t *pa_tnc_msg_create_from_data(chunk_t data)
.add_attribute = _add_attribute,
.build = _build,
.process = _process,
+ .process_ietf_std_errors = _process_ietf_std_errors,
.create_attribute_enumerator = _create_attribute_enumerator,
.create_error_enumerator = _create_error_enumerator,
.destroy = _destroy,
diff --git a/src/libimcv/pa_tnc/pa_tnc_msg.h b/src/libimcv/pa_tnc/pa_tnc_msg.h
index bff954678..c3ce829d5 100644
--- a/src/libimcv/pa_tnc/pa_tnc_msg.h
+++ b/src/libimcv/pa_tnc/pa_tnc_msg.h
@@ -62,6 +62,13 @@ struct pa_tnc_msg_t {
status_t (*process)(pa_tnc_msg_t *this);
/**
+ * Process and remove all IETF standard error PA-TNC attributes
+ *
+ * @return TRUE if at least one error attribute processed
+ */
+ bool (*process_ietf_std_errors)(pa_tnc_msg_t *this);
+
+ /**
* Enumerates over all PA-TNC attributes
*
* @return return attribute enumerator
diff --git a/src/libimcv/plugins/imc_attestation/imc_attestation.c b/src/libimcv/plugins/imc_attestation/imc_attestation.c
deleted file mode 100644
index 3c26f9b5c..000000000
--- a/src/libimcv/plugins/imc_attestation/imc_attestation.c
+++ /dev/null
@@ -1,507 +0,0 @@
-/*
- * Copyright (C) 2011 Sansar Choinyambuu
- * 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_attestation_state.h"
-
-#include <imc/imc_agent.h>
-#include <pa_tnc/pa_tnc_msg.h>
-#include <ietf/ietf_attr.h>
-#include <ietf/ietf_attr_pa_tnc_error.h>
-#include <ietf/ietf_attr_product_info.h>
-
-#include <libpts.h>
-
-#include <pts/pts_error.h>
-
-#include <tcg/tcg_pts_attr_proto_caps.h>
-#include <tcg/tcg_pts_attr_meas_algo.h>
-#include <tcg/tcg_pts_attr_get_tpm_version_info.h>
-#include <tcg/tcg_pts_attr_tpm_version_info.h>
-#include <tcg/tcg_pts_attr_get_aik.h>
-#include <tcg/tcg_pts_attr_aik.h>
-#include <tcg/tcg_pts_attr_req_funct_comp_evid.h>
-#include <tcg/tcg_pts_attr_gen_attest_evid.h>
-#include <tcg/tcg_pts_attr_simple_comp_evid.h>
-#include <tcg/tcg_pts_attr_simple_evid_final.h>
-#include <tcg/tcg_pts_attr_req_file_meas.h>
-#include <tcg/tcg_pts_attr_file_meas.h>
-
-#include <tncif_pa_subtypes.h>
-
-#include <pen/pen.h>
-#include <debug.h>
-#include <utils/linked_list.h>
-
-/* IMC definitions */
-
-static const char imc_name[] = "Attestation";
-
-#define IMC_VENDOR_ID PEN_TCG
-#define IMC_SUBTYPE PA_SUBTYPE_TCG_PTS
-
-static imc_agent_t *imc_attestation;
-
-/**
- * Supported PTS measurement algorithms
- */
-static pts_meas_algorithms_t supported_algorithms = 0;
-
-/**
- * see section 3.7.1 of TCG TNC IF-IMC Specification 1.2
- */
-TNC_Result TNC_IMC_Initialize(TNC_IMCID imc_id,
- TNC_Version min_version,
- TNC_Version max_version,
- TNC_Version *actual_version)
-{
- if (imc_attestation)
- {
- DBG1(DBG_IMC, "IMC \"%s\" has already been initialized", imc_name);
- return TNC_RESULT_ALREADY_INITIALIZED;
- }
- if (!pts_meas_probe_algorithms(&supported_algorithms))
- {
- return TNC_RESULT_FATAL;
- }
- imc_attestation = imc_agent_create(imc_name, IMC_VENDOR_ID, IMC_SUBTYPE,
- imc_id, actual_version);
- if (!imc_attestation)
- {
- return TNC_RESULT_FATAL;
- }
-
- libpts_init();
-
- 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.7.2 of TCG TNC IF-IMC Specification 1.2
- */
-TNC_Result TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id,
- TNC_ConnectionID connection_id,
- TNC_ConnectionState new_state)
-{
- imc_state_t *state;
- /* TODO: Not used so far */
- //imc_attestation_state_t *attestation_state;
-
- if (!imc_attestation)
- {
- 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_attestation_state_create(connection_id);
- return imc_attestation->create_state(imc_attestation, state);
- case TNC_CONNECTION_STATE_DELETE:
- return imc_attestation->delete_state(imc_attestation, connection_id);
- case TNC_CONNECTION_STATE_HANDSHAKE:
- case TNC_CONNECTION_STATE_ACCESS_ISOLATED:
- case TNC_CONNECTION_STATE_ACCESS_NONE:
- default:
- return imc_attestation->change_state(imc_attestation, connection_id,
- new_state, NULL);
- }
-}
-
-
-/**
- * see section 3.7.3 of TCG TNC IF-IMC Specification 1.2
- */
-TNC_Result TNC_IMC_BeginHandshake(TNC_IMCID imc_id,
- TNC_ConnectionID connection_id)
-{
- imc_state_t *state;
- imc_attestation_state_t *attestation_state;
- pts_t *pts;
- char *platform_info;
- TNC_Result result = TNC_RESULT_SUCCESS;
-
- if (!imc_attestation)
- {
- DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
- return TNC_RESULT_NOT_INITIALIZED;
- }
-
- /* get current IMC state */
- if (!imc_attestation->get_state(imc_attestation, connection_id, &state))
- {
- return TNC_RESULT_FATAL;
- }
- attestation_state = (imc_attestation_state_t*)state;
- pts = attestation_state->get_pts(attestation_state);
-
- platform_info = pts->get_platform_info(pts);
- if (platform_info)
- {
- pa_tnc_msg_t *pa_tnc_msg;
- pa_tnc_attr_t *attr;
-
- pa_tnc_msg = pa_tnc_msg_create();
- attr = ietf_attr_product_info_create(0, 0, platform_info);
- pa_tnc_msg->add_attribute(pa_tnc_msg, attr);
- pa_tnc_msg->build(pa_tnc_msg);
- result = imc_attestation->send_message(imc_attestation, connection_id,
- pa_tnc_msg->get_encoding(pa_tnc_msg));
- pa_tnc_msg->destroy(pa_tnc_msg);
- }
-
- return result;
-}
-
-/**
- * see section 3.7.4 of TCG TNC IF-IMC Specification 1.2
- */
-TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id,
- TNC_ConnectionID connection_id,
- TNC_BufferReference msg,
- TNC_UInt32 msg_len,
- TNC_MessageType msg_type)
-{
- pa_tnc_msg_t *pa_tnc_msg;
- pa_tnc_attr_t *attr;
- linked_list_t *attr_list;
- imc_state_t *state;
- imc_attestation_state_t *attestation_state;
- enumerator_t *enumerator;
- pts_t *pts;
- TNC_Result result;
- bool fatal_error = FALSE;
-
- if (!imc_attestation)
- {
- DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
- return TNC_RESULT_NOT_INITIALIZED;
- }
-
- /* get current IMC state */
- if (!imc_attestation->get_state(imc_attestation, connection_id, &state))
- {
- return TNC_RESULT_FATAL;
- }
- attestation_state = (imc_attestation_state_t*)state;
- pts = attestation_state->get_pts(attestation_state);
-
- /* parse received PA-TNC message and automatically handle any errors */
- result = imc_attestation->receive_message(imc_attestation, connection_id,
- chunk_create(msg, msg_len), msg_type,
- &pa_tnc_msg);
-
- /* no parsed PA-TNC attributes available if an error occurred */
- if (!pa_tnc_msg)
- {
- return result;
- }
-
- attr_list = linked_list_create();
-
- /* analyze PA-TNC attributes */
- enumerator = pa_tnc_msg->create_attribute_enumerator(pa_tnc_msg);
- while (enumerator->enumerate(enumerator, &attr))
- {
- if (attr->get_vendor_id(attr) == PEN_IETF &&
- attr->get_type(attr) == IETF_ATTR_PA_TNC_ERROR)
- {
- ietf_attr_pa_tnc_error_t *error_attr;
- pa_tnc_error_code_t error_code;
- chunk_t msg_info, attr_info;
- u_int32_t offset;
-
- error_attr = (ietf_attr_pa_tnc_error_t*)attr;
- error_code = error_attr->get_error_code(error_attr);
- msg_info = error_attr->get_msg_info(error_attr);
-
- DBG1(DBG_IMC, "received PA-TNC error '%N' concerning message %#B",
- pa_tnc_error_code_names, error_code, &msg_info);
- switch (error_code)
- {
- case PA_ERROR_INVALID_PARAMETER:
- offset = error_attr->get_offset(error_attr);
- DBG1(DBG_IMC, " occurred at offset of %u bytes", offset);
- break;
- case PA_ERROR_ATTR_TYPE_NOT_SUPPORTED:
- attr_info = error_attr->get_attr_info(error_attr);
- DBG1(DBG_IMC, " unsupported attribute %#B", &attr_info);
- break;
- default:
- break;
- }
- fatal_error = TRUE;
- }
- else if (attr->get_vendor_id(attr) == PEN_TCG)
- {
- switch (attr->get_type(attr))
- {
- case TCG_PTS_REQ_PROTO_CAPS:
- {
- tcg_pts_attr_proto_caps_t *attr_cast;
- pts_proto_caps_flag_t imc_flags, imv_flags;
-
- attr_cast = (tcg_pts_attr_proto_caps_t*)attr;
- imv_flags = attr_cast->get_flags(attr_cast);
- imc_flags = pts->get_proto_caps(pts);
- pts->set_proto_caps(pts, imc_flags & imv_flags);
-
- /* Send PTS Protocol Capabilities attribute */
- attr = tcg_pts_attr_proto_caps_create(imc_flags & imv_flags,
- FALSE);
- attr_list->insert_last(attr_list, attr);
- break;
- }
- case TCG_PTS_MEAS_ALGO:
- {
- tcg_pts_attr_meas_algo_t *attr_cast;
- pts_meas_algorithms_t selected_algorithm;
-
- attr_cast = (tcg_pts_attr_meas_algo_t*)attr;
- selected_algorithm = attr_cast->get_algorithms(attr_cast);
-
- if ((supported_algorithms & PTS_MEAS_ALGO_SHA384) &&
- (selected_algorithm & PTS_MEAS_ALGO_SHA384))
- {
- pts->set_meas_algorithm(pts, PTS_MEAS_ALGO_SHA384);
- }
- else if ((supported_algorithms & PTS_MEAS_ALGO_SHA256) &&
- (selected_algorithm & PTS_MEAS_ALGO_SHA256))
- {
- pts->set_meas_algorithm(pts, PTS_MEAS_ALGO_SHA256);
- }
-
- else if ((supported_algorithms & PTS_MEAS_ALGO_SHA1) &&
- (selected_algorithm & PTS_MEAS_ALGO_SHA1))
- {
- pts->set_meas_algorithm(pts, PTS_MEAS_ALGO_SHA1);
- }
- else
- {
- attr = pts_hash_alg_error_create(supported_algorithms);
- attr_list->insert_last(attr_list, attr);
- break;
- }
-
- /* Send Measurement Algorithm Selection attribute */
- selected_algorithm = pts->get_meas_algorithm(pts);
- attr = tcg_pts_attr_meas_algo_create(selected_algorithm,
- TRUE);
- attr_list->insert_last(attr_list, attr);
- break;
- }
-
- case TCG_PTS_GET_TPM_VERSION_INFO:
- {
- chunk_t tpm_version_info, attr_info;
-
- if (!pts->get_tpm_version_info(pts, &tpm_version_info))
- {
- attr_info = attr->get_value(attr);
- attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
- TCG_PTS_TPM_VERS_NOT_SUPPORTED, attr_info);
- attr_list->insert_last(attr_list, attr);
- break;
- }
-
- /* Send TPM Version Info attribute */
- attr = tcg_pts_attr_tpm_version_info_create(tpm_version_info);
- attr_list->insert_last(attr_list, attr);
- break;
- }
-
- case TCG_PTS_GET_AIK:
- {
- certificate_t *aik;
-
- aik = pts->get_aik(pts);
- if (!aik)
- {
- DBG1(DBG_IMC, "no AIK certificate or public key available");
- break;
- }
-
- /* Send AIK attribute */
- attr = tcg_pts_attr_aik_create(aik);
- attr_list->insert_last(attr_list, attr);
- break;
- }
-
- /* PTS-based Attestation Evidence */
- case TCG_PTS_REQ_FUNCT_COMP_EVID:
- break;
- case TCG_PTS_GEN_ATTEST_EVID:
- break;
- case TCG_PTS_REQ_FILE_MEAS:
- {
- tcg_pts_attr_req_file_meas_t *attr_cast;
- char *pathname;
- u_int16_t request_id;
- bool is_directory;
- u_int32_t delimiter;
- pts_file_meas_t *measurements;
- pts_error_code_t pts_error;
- chunk_t attr_info;
-
- attr_info = attr->get_value(attr);
- attr_cast = (tcg_pts_attr_req_file_meas_t*)attr;
- is_directory = attr_cast->get_directory_flag(attr_cast);
- request_id = attr_cast->get_request_id(attr_cast);
- delimiter = attr_cast->get_delimiter(attr_cast);
- pathname = attr_cast->get_pathname(attr_cast);
-
- if (pts->is_path_valid(pts, pathname, &pts_error) && pts_error)
- {
- attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
- pts_error, attr_info);
- attr_list->insert_last(attr_list, attr);
- break;
- }
- else if (!pts->is_path_valid(pts, pathname, &pts_error))
- {
- break;
- }
-
- if (delimiter != SOLIDUS_UTF && delimiter != REVERSE_SOLIDUS_UTF)
- {
- attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
- TCG_PTS_INVALID_DELIMITER, attr_info);
- attr_list->insert_last(attr_list, attr);
- break;
- }
-
- /* Do PTS File Measurements and send them to PTS-IMV */
- DBG2(DBG_IMC, "measurement request %d for %s '%s'",
- request_id, is_directory ? "directory" : "file",
- pathname);
- measurements = pts->do_measurements(pts, request_id,
- pathname, is_directory);
- if (!measurements)
- {
- /* TODO handle error codes from measurements */
- return TNC_RESULT_FATAL;
- }
- attr = tcg_pts_attr_file_meas_create(measurements);
- attr->set_noskip_flag(attr, TRUE);
- attr_list->insert_last(attr_list, attr);
- break;
- }
- /* TODO: Not implemented yet */
- case TCG_PTS_DH_NONCE_PARAMS_REQ:
- case TCG_PTS_DH_NONCE_FINISH:
- case TCG_PTS_REQ_FILE_META:
- case TCG_PTS_REQ_INTEG_MEAS_LOG:
- /* Attributes using XML */
- case TCG_PTS_REQ_TEMPL_REF_MANI_SET_META:
- case TCG_PTS_UPDATE_TEMPL_REF_MANI:
- /* On Windows only*/
- case TCG_PTS_REQ_REGISTRY_VALUE:
- /* Received on IMV side only*/
- case TCG_PTS_PROTO_CAPS:
- case TCG_PTS_DH_NONCE_PARAMS_RESP:
- case TCG_PTS_MEAS_ALGO_SELECTION:
- case TCG_PTS_TPM_VERSION_INFO:
- case TCG_PTS_TEMPL_REF_MANI_SET_META:
- case TCG_PTS_AIK:
- case TCG_PTS_SIMPLE_COMP_EVID:
- case TCG_PTS_SIMPLE_EVID_FINAL:
- case TCG_PTS_VERIFICATION_RESULT:
- case TCG_PTS_INTEG_REPORT:
- case TCG_PTS_UNIX_FILE_META:
- case TCG_PTS_FILE_MEAS:
- case TCG_PTS_INTEG_MEAS_LOG:
- default:
- DBG1(DBG_IMC, "received unsupported attribute '%N'",
- tcg_attr_names, attr->get_type(attr));
- break;
- }
- }
- }
- enumerator->destroy(enumerator);
- pa_tnc_msg->destroy(pa_tnc_msg);
-
- result = TNC_RESULT_SUCCESS;
-
- if (attr_list->get_count(attr_list))
- {
- pa_tnc_msg = pa_tnc_msg_create();
-
- enumerator = attr_list->create_enumerator(attr_list);
- while (enumerator->enumerate(enumerator, &attr))
- {
- pa_tnc_msg->add_attribute(pa_tnc_msg, attr);
- }
- enumerator->destroy(enumerator);
-
- pa_tnc_msg->build(pa_tnc_msg);
- result = imc_attestation->send_message(imc_attestation, connection_id,
- pa_tnc_msg->get_encoding(pa_tnc_msg));
- pa_tnc_msg->destroy(pa_tnc_msg);
- }
- attr_list->destroy(attr_list);
-
- return result;
-}
-
-/**
- * see section 3.7.5 of TCG TNC IF-IMC Specification 1.2
- */
-TNC_Result TNC_IMC_BatchEnding(TNC_IMCID imc_id,
- TNC_ConnectionID connection_id)
-{
- if (!imc_attestation)
- {
- DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
- return TNC_RESULT_NOT_INITIALIZED;
- }
- return TNC_RESULT_SUCCESS;
-}
-
-/**
- * see section 3.7.6 of TCG TNC IF-IMC Specification 1.2
- */
-TNC_Result TNC_IMC_Terminate(TNC_IMCID imc_id)
-{
- if (!imc_attestation)
- {
- DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
- return TNC_RESULT_NOT_INITIALIZED;
- }
-
- libpts_deinit();
-
- imc_attestation->destroy(imc_attestation);
- imc_attestation = NULL;
-
- return TNC_RESULT_SUCCESS;
-}
-
-/**
- * see section 4.2.8.1 of TCG TNC IF-IMC Specification 1.2
- */
-TNC_Result TNC_IMC_ProvideBindFunction(TNC_IMCID imc_id,
- TNC_TNCC_BindFunctionPointer bind_function)
-{
- if (!imc_attestation)
- {
- DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
- return TNC_RESULT_NOT_INITIALIZED;
- }
- return imc_attestation->bind_functions(imc_attestation, bind_function);
-}
diff --git a/src/libimcv/plugins/imc_scanner/imc_scanner.c b/src/libimcv/plugins/imc_scanner/imc_scanner.c
index ecf758ba0..b24c39c3a 100644
--- a/src/libimcv/plugins/imc_scanner/imc_scanner.c
+++ b/src/libimcv/plugins/imc_scanner/imc_scanner.c
@@ -39,7 +39,7 @@ static const char imc_name[] = "Scanner";
static imc_agent_t *imc_scanner;
/**
- * see section 3.7.1 of TCG TNC IF-IMC Specification 1.2
+ * see section 3.8.1 of TCG TNC IF-IMC Specification 1.3
*/
TNC_Result TNC_IMC_Initialize(TNC_IMCID imc_id,
TNC_Version min_version,
@@ -66,7 +66,7 @@ TNC_Result TNC_IMC_Initialize(TNC_IMCID imc_id,
}
/**
- * see section 3.7.2 of TCG TNC IF-IMC Specification 1.2
+ * see section 3.8.2 of TCG TNC IF-IMC Specification 1.3
*/
TNC_Result TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id,
TNC_ConnectionID connection_id,
@@ -237,15 +237,15 @@ static TNC_Result send_message(TNC_ConnectionID connection_id)
msg = pa_tnc_msg_create();
msg->add_attribute(msg, attr);
msg->build(msg);
- result = imc_scanner->send_message(imc_scanner, connection_id,
- msg->get_encoding(msg));
+ result = imc_scanner->send_message(imc_scanner, connection_id, FALSE, 0,
+ TNC_IMVID_ANY, msg->get_encoding(msg));
msg->destroy(msg);
return result;
}
/**
- * see section 3.7.3 of TCG TNC IF-IMC Specification 1.2
+ * see section 3.8.3 of TCG TNC IF-IMC Specification 1.3
*/
TNC_Result TNC_IMC_BeginHandshake(TNC_IMCID imc_id,
TNC_ConnectionID connection_id)
@@ -258,20 +258,19 @@ TNC_Result TNC_IMC_BeginHandshake(TNC_IMCID imc_id,
return send_message(connection_id);
}
-/**
- * see section 3.7.4 of TCG TNC IF-IMC Specification 1.2
- */
-TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id,
+static TNC_Result receive_message(TNC_IMCID imc_id,
TNC_ConnectionID connection_id,
- TNC_BufferReference msg,
- TNC_UInt32 msg_len,
- TNC_MessageType msg_type)
+ TNC_UInt32 msg_flags,
+ chunk_t msg,
+ TNC_VendorID msg_vid,
+ TNC_MessageSubtype msg_subtype,
+ TNC_UInt32 src_imv_id,
+ TNC_UInt32 dst_imc_id)
{
pa_tnc_msg_t *pa_tnc_msg;
- pa_tnc_attr_t *attr;
- enumerator_t *enumerator;
+ imc_state_t *state;
TNC_Result result;
- bool fatal_error = FALSE;
+ bool fatal_error;
if (!imc_scanner)
{
@@ -279,10 +278,15 @@ TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id,
return TNC_RESULT_NOT_INITIALIZED;
}
+ /* get current IMC state */
+ if (!imc_scanner->get_state(imc_scanner, connection_id, &state))
+ {
+ return TNC_RESULT_FATAL;
+ }
+
/* parse received PA-TNC message and automatically handle any errors */
- result = imc_scanner->receive_message(imc_scanner, connection_id,
- chunk_create(msg, msg_len), msg_type,
- &pa_tnc_msg);
+ result = imc_scanner->receive_message(imc_scanner, state, msg, msg_vid,
+ msg_subtype, src_imv_id, dst_imc_id, &pa_tnc_msg);
/* no parsed PA-TNC attributes available if an error occurred */
if (!pa_tnc_msg)
@@ -290,43 +294,8 @@ TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id,
return result;
}
- /* analyze PA-TNC attributes */
- enumerator = pa_tnc_msg->create_attribute_enumerator(pa_tnc_msg);
- while (enumerator->enumerate(enumerator, &attr))
- {
- ietf_attr_pa_tnc_error_t *error_attr;
- pa_tnc_error_code_t error_code;
- chunk_t msg_info, attr_info;
- u_int32_t offset;
-
- if (attr->get_vendor_id(attr) != PEN_IETF &&
- attr->get_type(attr) != IETF_ATTR_PA_TNC_ERROR)
- {
- continue;
- }
-
- error_attr = (ietf_attr_pa_tnc_error_t*)attr;
- error_code = error_attr->get_error_code(error_attr);
- msg_info = error_attr->get_msg_info(error_attr);
- DBG1(DBG_IMC, "received PA-TNC error '%N' concerning message %#B",
- pa_tnc_error_code_names, error_code, &msg_info);
-
- switch (error_code)
- {
- case PA_ERROR_INVALID_PARAMETER:
- offset = error_attr->get_offset(error_attr);
- DBG1(DBG_IMC, " occurred at offset of %u bytes", offset);
- break;
- case PA_ERROR_ATTR_TYPE_NOT_SUPPORTED:
- attr_info = error_attr->get_attr_info(error_attr);
- DBG1(DBG_IMC, " unsupported attribute %#B", &attr_info);
- break;
- default:
- break;
- }
- fatal_error = TRUE;
- }
- enumerator->destroy(enumerator);
+ /* preprocess any IETF standard error attributes */
+ fatal_error = pa_tnc_msg->process_ietf_std_errors(pa_tnc_msg);
pa_tnc_msg->destroy(pa_tnc_msg);
/* if no error occurred then always return the same response */
@@ -334,7 +303,44 @@ TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id,
}
/**
- * see section 3.7.5 of TCG TNC IF-IMC Specification 1.2
+ * see section 3.8.4 of TCG TNC IF-IMC Specification 1.3
+ */
+TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id,
+ TNC_ConnectionID connection_id,
+ TNC_BufferReference msg,
+ TNC_UInt32 msg_len,
+ TNC_MessageType msg_type)
+{
+ TNC_VendorID msg_vid;
+ TNC_MessageSubtype msg_subtype;
+
+ msg_vid = msg_type >> 8;
+ msg_subtype = msg_type & TNC_SUBTYPE_ANY;
+
+ return receive_message(imc_id, connection_id, 0, chunk_create(msg, msg_len),
+ msg_vid, msg_subtype, 0, TNC_IMCID_ANY);
+}
+
+/**
+ * see section 3.8.6 of TCG TNC IF-IMV Specification 1.3
+ */
+TNC_Result 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)
+{
+ return receive_message(imc_id, connection_id, msg_flags,
+ chunk_create(msg, msg_len), msg_vid, msg_subtype,
+ src_imv_id, dst_imc_id);
+}
+
+/**
+ * see section 3.8.7 of TCG TNC IF-IMC Specification 1.3
*/
TNC_Result TNC_IMC_BatchEnding(TNC_IMCID imc_id,
TNC_ConnectionID connection_id)
@@ -348,7 +354,7 @@ TNC_Result TNC_IMC_BatchEnding(TNC_IMCID imc_id,
}
/**
- * see section 3.7.6 of TCG TNC IF-IMC Specification 1.2
+ * see section 3.8.8 of TCG TNC IF-IMC Specification 1.3
*/
TNC_Result TNC_IMC_Terminate(TNC_IMCID imc_id)
{
@@ -364,7 +370,7 @@ TNC_Result TNC_IMC_Terminate(TNC_IMCID imc_id)
}
/**
- * see section 4.2.8.1 of TCG TNC IF-IMC Specification 1.2
+ * see section 4.2.8.1 of TCG TNC IF-IMC Specification 1.3
*/
TNC_Result TNC_IMC_ProvideBindFunction(TNC_IMCID imc_id,
TNC_TNCC_BindFunctionPointer bind_function)
diff --git a/src/libimcv/plugins/imc_scanner/imc_scanner_state.c b/src/libimcv/plugins/imc_scanner/imc_scanner_state.c
index dce7bca13..563105548 100644
--- a/src/libimcv/plugins/imc_scanner/imc_scanner_state.c
+++ b/src/libimcv/plugins/imc_scanner/imc_scanner_state.c
@@ -37,6 +37,17 @@ struct private_imc_scanner_state_t {
* 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;
+
};
METHOD(imc_state_t, get_connection_id, TNC_ConnectionID,
@@ -45,6 +56,25 @@ METHOD(imc_state_t, get_connection_id, TNC_ConnectionID,
return this->connection_id;
}
+METHOD(imc_state_t, has_long, bool,
+ private_imc_scanner_state_t *this)
+{
+ return this->has_long;
+}
+
+METHOD(imc_state_t, has_excl, bool,
+ private_imc_scanner_state_t *this)
+{
+ return this->has_excl;
+}
+
+METHOD(imc_state_t, set_flags, void,
+ private_imc_scanner_state_t *this, bool has_long, bool has_excl)
+{
+ this->has_long = has_long;
+ this->has_excl = has_excl;
+}
+
METHOD(imc_state_t, change_state, void,
private_imc_scanner_state_t *this, TNC_ConnectionState new_state)
{
@@ -68,6 +98,9 @@ imc_state_t *imc_scanner_state_create(TNC_ConnectionID connection_id)
.public = {
.interface = {
.get_connection_id = _get_connection_id,
+ .has_long = _has_long,
+ .has_excl = _has_excl,
+ .set_flags = _set_flags,
.change_state = _change_state,
.destroy = _destroy,
},
diff --git a/src/libimcv/plugins/imc_test/imc_test.c b/src/libimcv/plugins/imc_test/imc_test.c
index 01e70e8af..fe005ed4a 100644
--- a/src/libimcv/plugins/imc_test/imc_test.c
+++ b/src/libimcv/plugins/imc_test/imc_test.c
@@ -37,7 +37,7 @@ static const char imc_name[] = "Test";
static imc_agent_t *imc_test;
/**
- * see section 3.7.1 of TCG TNC IF-IMC Specification 1.2
+ * see section 3.8.1 of TCG TNC IF-IMC Specification 1.3
*/
TNC_Result TNC_IMC_Initialize(TNC_IMCID imc_id,
TNC_Version min_version,
@@ -64,7 +64,7 @@ TNC_Result TNC_IMC_Initialize(TNC_IMCID imc_id,
}
/**
- * see section 3.7.2 of TCG TNC IF-IMC Specification 1.2
+ * see section 3.8.2 of TCG TNC IF-IMC Specification 1.3
*/
TNC_Result TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id,
TNC_ConnectionID connection_id,
@@ -75,21 +75,36 @@ TNC_Result TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id,
TNC_Result result;
char *command;
bool retry;
+ int additional_ids;
if (!imc_test)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
+
switch (new_state)
{
case TNC_CONNECTION_STATE_CREATE:
command = lib->settings->get_str(lib->settings,
- "libimcv.plugins.imc-test.command", "none");
+ "libimcv.plugins.imc-test.command", "none");
retry = lib->settings->get_bool(lib->settings,
"libimcv.plugins.imc-test.retry", FALSE);
state = imc_test_state_create(connection_id, command, retry);
- return imc_test->create_state(imc_test, state);
+
+ result = imc_test->create_state(imc_test, state);
+ if (result != TNC_RESULT_SUCCESS)
+ {
+ return result;
+ }
+
+ /* Optionally reserve additional IMC IDs */
+ additional_ids = lib->settings->get_int(lib->settings,
+ "libimcv.plugins.imc-test.additional_ids", 0);
+ imc_test->reserve_additional_ids(imc_test, additional_ids -
+ imc_test->count_additional_ids(imc_test));
+
+ return TNC_RESULT_SUCCESS;
case TNC_CONNECTION_STATE_HANDSHAKE:
/* get updated IMC state */
@@ -139,56 +154,98 @@ TNC_Result TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id,
}
}
-static TNC_Result send_message(TNC_ConnectionID connection_id)
+static TNC_Result send_message(imc_state_t *state, TNC_UInt32 src_imc_id,
+ TNC_UInt32 dst_imv_id)
{
+ imc_test_state_t *test_state;
pa_tnc_msg_t *msg;
pa_tnc_attr_t *attr;
- imc_state_t *state;
- imc_test_state_t *test_state;
+ bool excl;
+ TNC_ConnectionID connection_id;
TNC_Result result;
- if (!imc_test->get_state(imc_test, connection_id, &state))
- {
- return TNC_RESULT_FATAL;
- }
+ connection_id = state->get_connection_id(state);
test_state = (imc_test_state_t*)state;
attr = ita_attr_command_create(test_state->get_command(test_state));
attr->set_noskip_flag(attr, TRUE);
msg = pa_tnc_msg_create();
msg->add_attribute(msg, attr);
msg->build(msg);
- result = imc_test->send_message(imc_test, connection_id,
- msg->get_encoding(msg));
+ excl = dst_imv_id != TNC_IMVID_ANY;
+ result = imc_test->send_message(imc_test, connection_id, excl, src_imc_id,
+ dst_imv_id, msg->get_encoding(msg));
msg->destroy(msg);
return result;
}
/**
- * see section 3.7.3 of TCG TNC IF-IMC Specification 1.2
+ * see section 3.8.3 of TCG TNC IF-IMC Specification 1.3
*/
TNC_Result TNC_IMC_BeginHandshake(TNC_IMCID imc_id,
TNC_ConnectionID connection_id)
{
+ imc_state_t *state;
+ enumerator_t *enumerator;
+ void *pointer;
+ TNC_UInt32 additional_id;
+ TNC_Result result;
+
if (!imc_test)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
- return send_message(connection_id);
+
+ /* get current IMC state */
+ if (!imc_test->get_state(imc_test, connection_id, &state))
+ {
+ return TNC_RESULT_FATAL;
+ }
+
+ /* send PA message for primary IMC ID */
+ result = send_message(state, imc_id, TNC_IMVID_ANY);
+
+ /* Exit if there are no additional IMC IDs */
+ if (!imc_test->count_additional_ids(imc_test))
+ {
+ return result;
+ }
+
+ /* Do we have support for transporting multiple IMC IDs? */
+ if (!state->has_long(state))
+ {
+ DBG1(DBG_IMC, "IMC %u \"%s\" did not detect support for transporting "
+ "multiple IMC IDs", imc_id, imc_name);
+ return result;
+ }
+
+ /* send PA messages for additional IMC IDs */
+ enumerator = imc_test->create_id_enumerator(imc_test);
+ while (result == TNC_RESULT_SUCCESS &&
+ enumerator->enumerate(enumerator, &pointer))
+ {
+ /* interpret pointer as scalar value */
+ additional_id = (TNC_UInt32)pointer;
+ result = send_message(state, additional_id, TNC_IMVID_ANY);
+ }
+ enumerator->destroy(enumerator);
+
+ return result;
}
-/**
- * see section 3.7.4 of TCG TNC IF-IMC Specification 1.2
- */
-TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id,
+static TNC_Result receive_message(TNC_IMCID imc_id,
TNC_ConnectionID connection_id,
- TNC_BufferReference msg,
- TNC_UInt32 msg_len,
- TNC_MessageType msg_type)
+ TNC_UInt32 msg_flags,
+ chunk_t msg,
+ TNC_VendorID msg_vid,
+ TNC_MessageSubtype msg_subtype,
+ TNC_UInt32 src_imv_id,
+ TNC_UInt32 dst_imc_id)
{
pa_tnc_msg_t *pa_tnc_msg;
pa_tnc_attr_t *attr;
+ imc_state_t *state;
enumerator_t *enumerator;
TNC_Result result;
bool fatal_error = FALSE;
@@ -199,10 +256,15 @@ TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id,
return TNC_RESULT_NOT_INITIALIZED;
}
+ /* get current IMC state */
+ if (!imc_test->get_state(imc_test, connection_id, &state))
+ {
+ return TNC_RESULT_FATAL;
+ }
+
/* parse received PA-TNC message and automatically handle any errors */
- result = imc_test->receive_message(imc_test, connection_id,
- chunk_create(msg, msg_len), msg_type,
- &pa_tnc_msg);
+ result = imc_test->receive_message(imc_test, state, msg, msg_vid,
+ msg_subtype, src_imv_id, dst_imc_id, &pa_tnc_msg);
/* no parsed PA-TNC attributes available if an error occurred */
if (!pa_tnc_msg)
@@ -210,41 +272,15 @@ TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id,
return result;
}
+ /* preprocess any IETF standard error attributes */
+ fatal_error = pa_tnc_msg->process_ietf_std_errors(pa_tnc_msg);
+
/* analyze PA-TNC attributes */
enumerator = pa_tnc_msg->create_attribute_enumerator(pa_tnc_msg);
while (enumerator->enumerate(enumerator, &attr))
{
- if (attr->get_vendor_id(attr) == PEN_IETF &&
- attr->get_type(attr) == IETF_ATTR_PA_TNC_ERROR)
- {
- ietf_attr_pa_tnc_error_t *error_attr;
- pa_tnc_error_code_t error_code;
- chunk_t msg_info, attr_info;
- u_int32_t offset;
-
- error_attr = (ietf_attr_pa_tnc_error_t*)attr;
- error_code = error_attr->get_error_code(error_attr);
- msg_info = error_attr->get_msg_info(error_attr);
-
- DBG1(DBG_IMC, "received PA-TNC error '%N' concerning message %#B",
- pa_tnc_error_code_names, error_code, &msg_info);
- switch (error_code)
- {
- case PA_ERROR_INVALID_PARAMETER:
- offset = error_attr->get_offset(error_attr);
- DBG1(DBG_IMC, " occurred at offset of %u bytes", offset);
- break;
- case PA_ERROR_ATTR_TYPE_NOT_SUPPORTED:
- attr_info = error_attr->get_attr_info(error_attr);
- DBG1(DBG_IMC, " unsupported attribute %#B", &attr_info);
- break;
- default:
- break;
- }
- fatal_error = TRUE;
- }
- else if (attr->get_vendor_id(attr) == PEN_ITA &&
- attr->get_type(attr) == ITA_ATTR_COMMAND)
+ if (attr->get_vendor_id(attr) == PEN_ITA &&
+ attr->get_type(attr) == ITA_ATTR_COMMAND)
{
ita_attr_command_t *ita_attr;
char *command;
@@ -257,11 +293,49 @@ TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id,
pa_tnc_msg->destroy(pa_tnc_msg);
/* if no error occurred then always return the same response */
- return fatal_error ? TNC_RESULT_FATAL : send_message(connection_id);
+ return fatal_error ? TNC_RESULT_FATAL :
+ send_message(state, dst_imc_id, src_imv_id);
+}
+
+/**
+ * see section 3.8.4 of TCG TNC IF-IMC Specification 1.3
+ */
+TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id,
+ TNC_ConnectionID connection_id,
+ TNC_BufferReference msg,
+ TNC_UInt32 msg_len,
+ TNC_MessageType msg_type)
+{
+ TNC_VendorID msg_vid;
+ TNC_MessageSubtype msg_subtype;
+
+ msg_vid = msg_type >> 8;
+ msg_subtype = msg_type & TNC_SUBTYPE_ANY;
+
+ return receive_message(imc_id, connection_id, 0, chunk_create(msg, msg_len),
+ msg_vid, msg_subtype, 0, TNC_IMCID_ANY);
+}
+
+/**
+ * see section 3.8.6 of TCG TNC IF-IMV Specification 1.3
+ */
+TNC_Result 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)
+{
+ return receive_message(imc_id, connection_id, msg_flags,
+ chunk_create(msg, msg_len), msg_vid, msg_subtype,
+ src_imv_id, dst_imc_id);
}
/**
- * see section 3.7.5 of TCG TNC IF-IMC Specification 1.2
+ * see section 3.8.7 of TCG TNC IF-IMC Specification 1.3
*/
TNC_Result TNC_IMC_BatchEnding(TNC_IMCID imc_id,
TNC_ConnectionID connection_id)
@@ -275,7 +349,7 @@ TNC_Result TNC_IMC_BatchEnding(TNC_IMCID imc_id,
}
/**
- * see section 3.7.6 of TCG TNC IF-IMC Specification 1.2
+ * see section 3.8.8 of TCG TNC IF-IMC Specification 1.3
*/
TNC_Result TNC_IMC_Terminate(TNC_IMCID imc_id)
{
@@ -291,7 +365,7 @@ TNC_Result TNC_IMC_Terminate(TNC_IMCID imc_id)
}
/**
- * see section 4.2.8.1 of TCG TNC IF-IMC Specification 1.2
+ * see section 4.2.8.1 of TCG TNC IF-IMC Specification 1.3
*/
TNC_Result TNC_IMC_ProvideBindFunction(TNC_IMCID imc_id,
TNC_TNCC_BindFunctionPointer bind_function)
diff --git a/src/libimcv/plugins/imc_test/imc_test_state.c b/src/libimcv/plugins/imc_test/imc_test_state.c
index cc7e18a4d..2adfd7d64 100644
--- a/src/libimcv/plugins/imc_test/imc_test_state.c
+++ b/src/libimcv/plugins/imc_test/imc_test_state.c
@@ -15,6 +15,7 @@
#include "imc_test_state.h"
#include <debug.h>
+#include <utils/linked_list.h>
typedef struct private_imc_test_state_t private_imc_test_state_t;
@@ -39,6 +40,16 @@ struct private_imc_test_state_t {
TNC_ConnectionState state;
/**
+ * Does the TNCCS connection support long message types?
+ */
+ bool has_long;
+
+ /**
+ * Does the TNCCS connection support exclusive delivery?
+ */
+ bool has_excl;
+
+ /**
* Command to transmit to IMV
*/
char *command;
@@ -52,6 +63,7 @@ struct private_imc_test_state_t {
* Do a handshake retry
*/
bool handshake_retry;
+
};
METHOD(imc_state_t, get_connection_id, TNC_ConnectionID,
@@ -60,6 +72,25 @@ METHOD(imc_state_t, get_connection_id, TNC_ConnectionID,
return this->connection_id;
}
+METHOD(imc_state_t, has_long, bool,
+ private_imc_test_state_t *this)
+{
+ return this->has_long;
+}
+
+METHOD(imc_state_t, has_excl, bool,
+ private_imc_test_state_t *this)
+{
+ return this->has_excl;
+}
+
+METHOD(imc_state_t, set_flags, void,
+ private_imc_test_state_t *this, bool has_long, bool has_excl)
+{
+ this->has_long = has_long;
+ this->has_excl = has_excl;
+}
+
METHOD(imc_state_t, change_state, void,
private_imc_test_state_t *this, TNC_ConnectionState new_state)
{
@@ -123,6 +154,9 @@ imc_state_t *imc_test_state_create(TNC_ConnectionID connection_id,
.public = {
.interface = {
.get_connection_id = _get_connection_id,
+ .has_long = _has_long,
+ .has_excl = _has_excl,
+ .set_flags = _set_flags,
.change_state = _change_state,
.destroy = _destroy,
},
diff --git a/src/libimcv/plugins/imc_test/imc_test_state.h b/src/libimcv/plugins/imc_test/imc_test_state.h
index 384285af8..d9160df94 100644
--- a/src/libimcv/plugins/imc_test/imc_test_state.h
+++ b/src/libimcv/plugins/imc_test/imc_test_state.h
@@ -21,6 +21,7 @@
#ifndef IMC_TEST_STATE_H_
#define IMC_TEST_STATE_H_
+#include <tncifimc.h>
#include <imc/imc_state.h>
#include <library.h>
@@ -63,6 +64,7 @@ struct imc_test_state_t {
* @return TRUE if a handshake retry should be done
*/
bool (*do_handshake_retry)(imc_test_state_t *this);
+
};
/**
diff --git a/src/libimcv/plugins/imv_attestation/Makefile.am b/src/libimcv/plugins/imv_attestation/Makefile.am
deleted file mode 100644
index bfff6e877..000000000
--- a/src/libimcv/plugins/imv_attestation/Makefile.am
+++ /dev/null
@@ -1,17 +0,0 @@
-
-INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libtncif \
- -I$(top_srcdir)/src/libimcv -I$(top_srcdir)/src/libpts
-
-AM_CFLAGS = -rdynamic
-
-imcv_LTLIBRARIES = imv-attestation.la
-
-imv_attestation_la_LIBADD = $(top_builddir)/src/libimcv/libimcv.la \
- $(top_builddir)/src/libstrongswan/libstrongswan.la \
- $(top_builddir)/src/libpts/libpts.la
-
-imv_attestation_la_SOURCES = imv_attestation.c \
- imv_attestation_state.h imv_attestation_state.c
-
-imv_attestation_la_LDFLAGS = -module -avoid-version
-
diff --git a/src/libimcv/plugins/imv_attestation/imv_attestation.c b/src/libimcv/plugins/imv_attestation/imv_attestation.c
deleted file mode 100644
index 86de5a9cf..000000000
--- a/src/libimcv/plugins/imv_attestation/imv_attestation.c
+++ /dev/null
@@ -1,695 +0,0 @@
-/*
- * Copyright (C) 2011 Sansar Choinyambuu
- * 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_attestation_state.h"
-
-#include <imv/imv_agent.h>
-#include <pa_tnc/pa_tnc_msg.h>
-#include <ietf/ietf_attr.h>
-#include <ietf/ietf_attr_pa_tnc_error.h>
-#include <ietf/ietf_attr_product_info.h>
-
-#include <libpts.h>
-
-#include <pts/pts_database.h>
-#include <pts/pts_creds.h>
-#include <pts/pts_error.h>
-
-#include <tcg/tcg_attr.h>
-#include <tcg/tcg_pts_attr_proto_caps.h>
-#include <tcg/tcg_pts_attr_meas_algo.h>
-#include <tcg/tcg_pts_attr_get_tpm_version_info.h>
-#include <tcg/tcg_pts_attr_tpm_version_info.h>
-#include <tcg/tcg_pts_attr_get_aik.h>
-#include <tcg/tcg_pts_attr_aik.h>
-#include <tcg/tcg_pts_attr_req_funct_comp_evid.h>
-#include <tcg/tcg_pts_attr_gen_attest_evid.h>
-#include <tcg/tcg_pts_attr_simple_comp_evid.h>
-#include <tcg/tcg_pts_attr_simple_evid_final.h>
-#include <tcg/tcg_pts_attr_req_file_meas.h>
-#include <tcg/tcg_pts_attr_file_meas.h>
-
-#include <tncif_pa_subtypes.h>
-
-#include <pen/pen.h>
-#include <debug.h>
-#include <credentials/credential_manager.h>
-
-/* IMV definitions */
-
-static const char imv_name[] = "Attestation";
-
-#define IMV_VENDOR_ID PEN_TCG
-#define IMV_SUBTYPE PA_SUBTYPE_TCG_PTS
-
-static imv_agent_t *imv_attestation;
-
-/**
- * Supported PTS measurement algorithms
- */
-static pts_meas_algorithms_t supported_algorithms = 0;
-
-/**
- * PTS file measurement database
- */
-static pts_database_t *pts_db;
-
-/**
- * PTS credentials
- */
-static pts_creds_t *pts_creds;
-
-/**
- * PTS credential manager
- */
-static credential_manager_t *pts_credmgr;
-
-/**
- * see section 3.7.1 of TCG TNC IF-IMV Specification 1.2
- */
-TNC_Result TNC_IMV_Initialize(TNC_IMVID imv_id,
- TNC_Version min_version,
- TNC_Version max_version,
- TNC_Version *actual_version)
-{
- char *hash_alg, *uri, *cadir;
-
- if (imv_attestation)
- {
- DBG1(DBG_IMV, "IMV \"%s\" has already been initialized", imv_name);
- return TNC_RESULT_ALREADY_INITIALIZED;
- }
- if (!pts_meas_probe_algorithms(&supported_algorithms))
- {
- return TNC_RESULT_FATAL;
- }
- imv_attestation = imv_agent_create(imv_name, IMV_VENDOR_ID, IMV_SUBTYPE,
- imv_id, actual_version);
- if (!imv_attestation)
- {
- return TNC_RESULT_FATAL;
- }
-
- libpts_init();
-
- if (min_version > TNC_IFIMV_VERSION_1 || max_version < TNC_IFIMV_VERSION_1)
- {
- DBG1(DBG_IMV, "no common IF-IMV version");
- return TNC_RESULT_NO_COMMON_VERSION;
- }
-
- /**
- * Specify supported PTS measurement algorithms
- *
- * sha1 : PTS_MEAS_ALGO_SHA1
- * sha256: PTS_MEAS_ALGO_SHA1 | PTS_MEAS_ALGO_SHA256
- * sha384: PTS_MEAS_ALGO_SHA1 | PTS_MEAS_ALGO_SHA256 | PTS_MEAS_ALGO_SHA384
- *
- * we expect the PTS-IMC to select the strongest supported algorithm
- */
- hash_alg = lib->settings->get_str(lib->settings,
- "libimcv.plugins.imv-attestation.hash_algorithm", "sha256");
- if (!strcaseeq(hash_alg, "sha384") && !strcaseeq(hash_alg, "sha2_384"))
- {
- /* remove SHA384 algorithm */
- supported_algorithms &= ~PTS_MEAS_ALGO_SHA384;
- }
- if (strcaseeq(hash_alg, "sha1"))
- {
- /* remove SHA256 algorithm */
- supported_algorithms &= ~PTS_MEAS_ALGO_SHA256;
- }
-
- /* create a PTS credential manager */
- pts_credmgr = credential_manager_create();
-
- /* create PTS credential set */
- cadir = lib->settings->get_str(lib->settings,
- "libimcv.plugins.imv-attestation.cadir", NULL);
- pts_creds = pts_creds_create(cadir);
- if (pts_creds)
- {
- pts_credmgr->add_set(pts_credmgr, pts_creds->get_set(pts_creds));
- }
-
- /* attach file measurement database */
- uri = lib->settings->get_str(lib->settings,
- "libimcv.plugins.imv-attestation.database", NULL);
- pts_db = pts_database_create(uri);
-
- return TNC_RESULT_SUCCESS;
-}
-
-/**
- * see section 3.7.2 of TCG TNC IF-IMV Specification 1.2
- */
-TNC_Result TNC_IMV_NotifyConnectionChange(TNC_IMVID imv_id,
- TNC_ConnectionID connection_id,
- TNC_ConnectionState new_state)
-{
- imv_state_t *state;
- imv_attestation_state_t *attestation_state;
- TNC_Result result;
-
- if (!imv_attestation)
- {
- DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
- return TNC_RESULT_NOT_INITIALIZED;
- }
- switch (new_state)
- {
- case TNC_CONNECTION_STATE_CREATE:
- state = imv_attestation_state_create(connection_id);
- return imv_attestation->create_state(imv_attestation, state);
- case TNC_CONNECTION_STATE_DELETE:
- return imv_attestation->delete_state(imv_attestation, connection_id);
- case TNC_CONNECTION_STATE_HANDSHAKE:
- result = imv_attestation->change_state(imv_attestation, connection_id,
- new_state, &state);
- if (result != TNC_RESULT_SUCCESS)
- {
- return result;
- }
- attestation_state = (imv_attestation_state_t*)state;
-
- /* TODO: Get some configurations */
-
- return TNC_RESULT_SUCCESS;
- default:
- return imv_attestation->change_state(imv_attestation, connection_id,
- new_state, NULL);
- }
-}
-
-static TNC_Result send_message(TNC_ConnectionID connection_id)
-{
- pa_tnc_msg_t *msg;
- pa_tnc_attr_t *attr;
- pts_t *pts;
- imv_state_t *state;
- imv_attestation_state_t *attestation_state;
- imv_attestation_handshake_state_t handshake_state;
- TNC_Result result;
-
- if (!imv_attestation->get_state(imv_attestation, connection_id, &state))
- {
- return TNC_RESULT_FATAL;
- }
- attestation_state = (imv_attestation_state_t*)state;
- handshake_state = attestation_state->get_handshake_state(attestation_state);
- pts = attestation_state->get_pts(attestation_state);
-
- msg = pa_tnc_msg_create();
-
-
- /* Switch on the attribute type IMV has received */
- switch (handshake_state)
- {
- case IMV_ATTESTATION_STATE_INIT:
- {
- pts_proto_caps_flag_t flags;
-
- /* Send Request Protocol Capabilities attribute */
- flags = pts->get_proto_caps(pts);
- attr = tcg_pts_attr_proto_caps_create(flags, TRUE);
- attr->set_noskip_flag(attr, TRUE);
- msg->add_attribute(msg, attr);
-
- /* Send Measurement Algorithms attribute */
- attr = tcg_pts_attr_meas_algo_create(supported_algorithms, FALSE);
- attr->set_noskip_flag(attr, TRUE);
- msg->add_attribute(msg, attr);
-
- attestation_state->set_handshake_state(attestation_state,
- IMV_ATTESTATION_STATE_MEAS);
- break;
- }
-
- case IMV_ATTESTATION_STATE_MEAS:
- {
- enumerator_t *enumerator;
- u_int32_t delimiter = SOLIDUS_UTF;
- char *platform_info, *pathname;
- u_int16_t request_id;
- int id, type;
- bool is_dir;
-
- attestation_state->set_handshake_state(attestation_state,
- IMV_ATTESTATION_STATE_END);
-
- /* Does the PTS-IMC have TPM support? */
- if (pts->get_proto_caps(pts) & PTS_PROTO_CAPS_T)
- {
- /* Send Get TPM Version attribute */
- attr = tcg_pts_attr_get_tpm_version_info_create();
- attr->set_noskip_flag(attr, TRUE);
- msg->add_attribute(msg, attr);
-
- /* Send Get AIK attribute */
- attr = tcg_pts_attr_get_aik_create();
- attr->set_noskip_flag(attr, TRUE);
- msg->add_attribute(msg, attr);
- }
-
- /* Get Platform and OS of the PTS-IMC */
- platform_info = pts->get_platform_info(pts);
-
- if (!pts_db || !platform_info)
- {
- DBG1(DBG_IMV, "%s%s%s not available",
- (pts_db) ? "" : "pts database",
- (!pts_db && !platform_info) ? "and" : "",
- (platform_info) ? "" : "platform info");
- break;
- }
- DBG1(DBG_IMV, "platform is '%s'", platform_info);
-
- /* Send Request File Measurement attribute */
- enumerator = pts_db->create_file_enumerator(pts_db, platform_info);
- if (!enumerator)
- {
- break;
- }
- while (enumerator->enumerate(enumerator, &id, &type, &pathname))
- {
- is_dir = (type != 0);
- request_id = attestation_state->add_request(attestation_state,
- id, is_dir);
- DBG2(DBG_IMV, "measurement request %d for %s '%s'",
- request_id, is_dir ? "directory" : "file", pathname);
- attr = tcg_pts_attr_req_file_meas_create(is_dir, request_id,
- delimiter, pathname);
- attr->set_noskip_flag(attr, TRUE);
- msg->add_attribute(msg, attr);
- }
- enumerator->destroy(enumerator);
- break;
- }
- case IMV_ATTESTATION_STATE_COMP_EVID:
- case IMV_ATTESTATION_STATE_IML:
- DBG1(DBG_IMV, "Attestation IMV has nothing to send: \"%s\"",
- handshake_state);
- return TNC_RESULT_FATAL;
- default:
- DBG1(DBG_IMV, "Attestation IMV is in unknown state: \"%s\"",
- handshake_state);
- return TNC_RESULT_FATAL;
- }
-
- msg->build(msg);
- result = imv_attestation->send_message(imv_attestation, connection_id,
- msg->get_encoding(msg));
- msg->destroy(msg);
-
- return result;
-}
-
-/**
- * see section 3.7.3 of TCG TNC IF-IMV Specification 1.2
- */
-TNC_Result TNC_IMV_ReceiveMessage(TNC_IMVID imv_id,
- TNC_ConnectionID connection_id,
- TNC_BufferReference msg,
- TNC_UInt32 msg_len,
- TNC_MessageType msg_type)
-{
- pa_tnc_msg_t *pa_tnc_msg;
- pa_tnc_attr_t *attr;
- imv_state_t *state;
- imv_attestation_state_t *attestation_state;
- pts_t *pts;
- enumerator_t *enumerator;
- TNC_Result result;
- bool fatal_error = FALSE;
- bool measurement_error = FALSE;
-
- if (!imv_attestation)
- {
- DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
- return TNC_RESULT_NOT_INITIALIZED;
- }
-
- /* get current IMV state */
- if (!imv_attestation->get_state(imv_attestation, connection_id, &state))
- {
- return TNC_RESULT_FATAL;
- }
- attestation_state = (imv_attestation_state_t*)state;
- pts = attestation_state->get_pts(attestation_state);
-
- /* parse received PA-TNC message and automatically handle any errors */
- result = imv_attestation->receive_message(imv_attestation, connection_id,
- chunk_create(msg, msg_len), msg_type,
- &pa_tnc_msg);
-
- /* no parsed PA-TNC attributes available if an error occurred */
- if (!pa_tnc_msg)
- {
- return result;
- }
-
- /* analyze PA-TNC attributes */
- enumerator = pa_tnc_msg->create_attribute_enumerator(pa_tnc_msg);
- while (enumerator->enumerate(enumerator, &attr))
- {
- if (attr->get_vendor_id(attr) == PEN_IETF)
- {
- if (attr->get_type(attr) == IETF_ATTR_PA_TNC_ERROR)
- {
- ietf_attr_pa_tnc_error_t *error_attr;
- pen_t error_vendor_id;
- pa_tnc_error_code_t error_code;
- chunk_t msg_info, attr_info;
- u_int32_t offset;
-
- error_attr = (ietf_attr_pa_tnc_error_t*)attr;
- error_vendor_id = error_attr->get_vendor_id(error_attr);
- error_code = error_attr->get_error_code(error_attr);
- msg_info = error_attr->get_msg_info(error_attr);
-
- if (error_vendor_id == PEN_IETF)
- {
- DBG1(DBG_IMV, "received PA-TNC error '%N' "
- "concerning message %#B",
- pa_tnc_error_code_names, error_code, &msg_info);
-
- switch (error_code)
- {
- case PA_ERROR_INVALID_PARAMETER:
- offset = error_attr->get_offset(error_attr);
- DBG1(DBG_IMV, " occurred at offset of %u bytes",
- offset);
- break;
- case PA_ERROR_ATTR_TYPE_NOT_SUPPORTED:
- attr_info = error_attr->get_attr_info(error_attr);
- DBG1(DBG_IMV, " unsupported attribute %#B",
- &attr_info);
- break;
- default:
- break;
- }
- }
- else if (error_vendor_id == PEN_TCG)
- {
- DBG1(DBG_IMV, "received TCG-PTS error '%N'",
- pts_error_code_names, error_code);
- DBG1(DBG_IMV, "error information: %B", &msg_info);
- }
- fatal_error = TRUE;
- }
- else if (attr->get_type(attr) == IETF_ATTR_PRODUCT_INFORMATION)
- {
- ietf_attr_product_info_t *attr_cast;
- char *platform_info;
-
- attr_cast = (ietf_attr_product_info_t*)attr;
- platform_info = attr_cast->get_info(attr_cast, NULL, NULL);
- pts->set_platform_info(pts, platform_info);
- }
- }
- else if (attr->get_vendor_id(attr) == PEN_TCG)
- {
- switch (attr->get_type(attr))
- {
- case TCG_PTS_PROTO_CAPS:
- {
- tcg_pts_attr_proto_caps_t *attr_cast;
- pts_proto_caps_flag_t flags;
-
- attr_cast = (tcg_pts_attr_proto_caps_t*)attr;
- flags = attr_cast->get_flags(attr_cast);
- pts->set_proto_caps(pts, flags);
- break;
- }
- case TCG_PTS_MEAS_ALGO_SELECTION:
- {
- tcg_pts_attr_meas_algo_t *attr_cast;
- pts_meas_algorithms_t selected_algorithm;
-
- attr_cast = (tcg_pts_attr_meas_algo_t*)attr;
- selected_algorithm = attr_cast->get_algorithms(attr_cast);
- pts->set_meas_algorithm(pts, selected_algorithm);
- break;
- }
- case TCG_PTS_TPM_VERSION_INFO:
- {
- tcg_pts_attr_tpm_version_info_t *attr_cast;
- chunk_t tpm_version_info;
-
- attr_cast = (tcg_pts_attr_tpm_version_info_t*)attr;
- tpm_version_info = attr_cast->get_tpm_version_info(attr_cast);
- pts->set_tpm_version_info(pts, tpm_version_info);
- break;
- }
- case TCG_PTS_AIK:
- {
- tcg_pts_attr_aik_t *attr_cast;
- certificate_t *aik, *issuer;
- enumerator_t *e;
- bool trusted = FALSE;
-
- attr_cast = (tcg_pts_attr_aik_t*)attr;
- aik = attr_cast->get_aik(attr_cast);
- if (!aik)
- {
- /* TODO generate error attribute */
- break;
- }
- if (aik->get_type(aik) == CERT_X509)
- {
- DBG1(DBG_IMV, "verifying AIK certificate");
- e = pts_credmgr->create_trusted_enumerator(pts_credmgr,
- KEY_ANY, aik->get_issuer(aik), FALSE);
- while (e->enumerate(e, &issuer))
- {
- if (aik->issued_by(aik, issuer))
- {
- trusted = TRUE;
- break;
- }
- }
- e->destroy(e);
- DBG1(DBG_IMV, "AIK certificate is %strusted",
- trusted ? "" : "not ");
- }
- pts->set_aik(pts, aik);
- break;
- }
-
- /* PTS-based Attestation Evidence */
- case TCG_PTS_SIMPLE_COMP_EVID:
- break;
- case TCG_PTS_SIMPLE_EVID_FINAL:
- break;
- case TCG_PTS_FILE_MEAS:
- {
- tcg_pts_attr_file_meas_t *attr_cast;
- u_int16_t request_id;
- int file_count, file_id;
- pts_meas_algorithms_t algo;
- pts_file_meas_t *measurements;
- char *platform_info;
- enumerator_t *e_hash;
- bool is_dir;
-
- platform_info = pts->get_platform_info(pts);
- if (!pts_db || !platform_info)
- {
- break;
- }
-
- attr_cast = (tcg_pts_attr_file_meas_t*)attr;
- measurements = attr_cast->get_measurements(attr_cast);
- algo = pts->get_meas_algorithm(pts);
- request_id = measurements->get_request_id(measurements);
- file_count = measurements->get_file_count(measurements);
-
- DBG1(DBG_IMV, "measurement request %d returned %d file%s:",
- request_id, file_count, (file_count == 1) ? "":"s");
-
- if (!attestation_state->check_off_request(attestation_state,
- request_id, &file_id, &is_dir))
- {
- DBG1(DBG_IMV, " no entry found for this request");
- break;
- }
-
- /* check hashes from database against measurements */
- e_hash = pts_db->create_hash_enumerator(pts_db,
- platform_info, algo, file_id, is_dir);
- if (!measurements->verify(measurements, e_hash, is_dir))
- {
- measurement_error = TRUE;
- }
- e_hash->destroy(e_hash);
- break;
- }
-
- /* TODO: Not implemented yet */
- case TCG_PTS_DH_NONCE_PARAMS_RESP:
- case TCG_PTS_UNIX_FILE_META:
- case TCG_PTS_INTEG_MEAS_LOG:
- /* Attributes using XML */
- case TCG_PTS_TEMPL_REF_MANI_SET_META:
- case TCG_PTS_VERIFICATION_RESULT:
- case TCG_PTS_INTEG_REPORT:
- /* On Windows only*/
- case TCG_PTS_WIN_FILE_META:
- case TCG_PTS_REGISTRY_VALUE:
- /* Received on IMC side only*/
- case TCG_PTS_REQ_PROTO_CAPS:
- case TCG_PTS_DH_NONCE_PARAMS_REQ:
- case TCG_PTS_DH_NONCE_FINISH:
- case TCG_PTS_MEAS_ALGO:
- case TCG_PTS_GET_TPM_VERSION_INFO:
- case TCG_PTS_REQ_TEMPL_REF_MANI_SET_META:
- case TCG_PTS_UPDATE_TEMPL_REF_MANI:
- case TCG_PTS_GET_AIK:
- case TCG_PTS_REQ_FUNCT_COMP_EVID:
- case TCG_PTS_GEN_ATTEST_EVID:
- case TCG_PTS_REQ_FILE_META:
- case TCG_PTS_REQ_FILE_MEAS:
- case TCG_PTS_REQ_INTEG_MEAS_LOG:
- default:
- DBG1(DBG_IMV, "received unsupported attribute '%N'",
- tcg_attr_names, attr->get_type(attr));
- break;
- }
- }
- }
- enumerator->destroy(enumerator);
- pa_tnc_msg->destroy(pa_tnc_msg);
-
-
- if (fatal_error)
- {
- state->set_recommendation(state,
- TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION,
- TNC_IMV_EVALUATION_RESULT_ERROR);
- return imv_attestation->provide_recommendation(imv_attestation,
- connection_id);
- }
-
- if (attestation_state->get_handshake_state(attestation_state) &
- IMV_ATTESTATION_STATE_END)
- {
- if (attestation_state->get_request_count(attestation_state))
- {
- DBG1(DBG_IMV, "failure due to %d pending file measurements",
- attestation_state->get_request_count(attestation_state));
- measurement_error = TRUE;
- }
- if (measurement_error)
- {
- state->set_recommendation(state,
- TNC_IMV_ACTION_RECOMMENDATION_ISOLATE,
- TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR);
- }
- else
- {
- state->set_recommendation(state,
- TNC_IMV_ACTION_RECOMMENDATION_ALLOW,
- TNC_IMV_EVALUATION_RESULT_COMPLIANT);
- }
- return imv_attestation->provide_recommendation(imv_attestation,
- connection_id);
- }
-
- return send_message(connection_id);
-}
-
-/**
- * see section 3.7.4 of TCG TNC IF-IMV Specification 1.2
- */
-TNC_Result TNC_IMV_SolicitRecommendation(TNC_IMVID imv_id,
- TNC_ConnectionID connection_id)
-{
- if (!imv_attestation)
- {
- DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
- return TNC_RESULT_NOT_INITIALIZED;
- }
- return imv_attestation->provide_recommendation(imv_attestation, connection_id);
-}
-
-/**
- * see section 3.7.5 of TCG TNC IF-IMV Specification 1.2
- */
-TNC_Result TNC_IMV_BatchEnding(TNC_IMVID imv_id,
- TNC_ConnectionID connection_id)
-{
- imv_state_t *state;
- imv_attestation_state_t *attestation_state;
-
- if (!imv_attestation)
- {
- DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
- return TNC_RESULT_NOT_INITIALIZED;
- }
- /* get current IMV state */
- if (!imv_attestation->get_state(imv_attestation, connection_id, &state))
- {
- return TNC_RESULT_FATAL;
- }
- attestation_state = (imv_attestation_state_t*)state;
-
- /* Check if IMV has to initiate the PA-TNC exchange */
- if (attestation_state->get_handshake_state(attestation_state) ==
- IMV_ATTESTATION_STATE_INIT)
- {
- return send_message(connection_id);
- }
- return TNC_RESULT_SUCCESS;
-}
-
-/**
- * see section 3.7.6 of TCG TNC IF-IMV Specification 1.2
- */
-TNC_Result TNC_IMV_Terminate(TNC_IMVID imv_id)
-{
- if (!imv_attestation)
- {
- DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
- return TNC_RESULT_NOT_INITIALIZED;
- }
- if (pts_creds)
- {
- pts_credmgr->remove_set(pts_credmgr, pts_creds->get_set(pts_creds));
- pts_creds->destroy(pts_creds);
- }
- DESTROY_IF(pts_db);
- DESTROY_IF(pts_credmgr);
-
- libpts_deinit();
-
- imv_attestation->destroy(imv_attestation);
- imv_attestation = NULL;
-
- return TNC_RESULT_SUCCESS;
-}
-
-/**
- * see section 4.2.8.1 of TCG TNC IF-IMV Specification 1.2
- */
-TNC_Result TNC_IMV_ProvideBindFunction(TNC_IMVID imv_id,
- TNC_TNCS_BindFunctionPointer bind_function)
-{
- if (!imv_attestation)
- {
- DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
- return TNC_RESULT_NOT_INITIALIZED;
- }
- return imv_attestation->bind_functions(imv_attestation, bind_function);
-}
diff --git a/src/libimcv/plugins/imv_attestation/tables.sql b/src/libimcv/plugins/imv_attestation/tables.sql
deleted file mode 100644
index 8cc0e5588..000000000
--- a/src/libimcv/plugins/imv_attestation/tables.sql
+++ /dev/null
@@ -1,36 +0,0 @@
-/* PTS SQLite database */
-
-DROP TABLE IF EXISTS files;
-CREATE TABLE files (
- id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
- type INTEGER NOT NULL,
- path TEXT NOT NULL
-);
-
-DROP TABLE IF EXISTS products;
-CREATE TABLE products (
- id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
- name TEXT NOT NULL
-);
-DROP INDEX IF EXISTS products_name;
-CREATE INDEX products_name ON products (
- name
-);
-
-DROP TABLE IF EXISTS product_file;
-CREATE TABLE product_file (
- product INTEGER NOT NULL,
- file INTEGER NOT NULL,
- PRIMARY KEY (product, file)
-);
-
-DROP TABLE IF EXISTS file_hashes;
-CREATE TABLE file_hashes (
- file INTEGER NOT NULL,
- directory INTEGER DEFAULT 0,
- product INTEGER NOT NULL,
- algo INTEGER NOT NULL,
- hash BLOB NOT NULL,
- PRIMARY KEY(file, directory, product, algo)
-);
-
diff --git a/src/libimcv/plugins/imv_scanner/imv_scanner.c b/src/libimcv/plugins/imv_scanner/imv_scanner.c
index 5561e6737..845511555 100644
--- a/src/libimcv/plugins/imv_scanner/imv_scanner.c
+++ b/src/libimcv/plugins/imv_scanner/imv_scanner.c
@@ -111,7 +111,7 @@ static linked_list_t* get_port_list(char *label)
/*
- * see section 3.7.1 of TCG TNC IF-IMV Specification 1.2
+ * see section 3.8.1 of TCG TNC IF-IMV Specification 1.3
*/
TNC_Result TNC_IMV_Initialize(TNC_IMVID imv_id,
TNC_Version min_version,
@@ -149,7 +149,7 @@ TNC_Result TNC_IMV_Initialize(TNC_IMVID imv_id,
}
/**
- * see section 3.7.2 of TCG TNC IF-IMV Specification 1.2
+ * see section 3.8.2 of TCG TNC IF-IMV Specification 1.3
*/
TNC_Result TNC_IMV_NotifyConnectionChange(TNC_IMVID imv_id,
TNC_ConnectionID connection_id,
@@ -175,21 +175,21 @@ TNC_Result TNC_IMV_NotifyConnectionChange(TNC_IMVID imv_id,
}
}
-/**
- * see section 3.7.3 of TCG TNC IF-IMV Specification 1.2
- */
-TNC_Result TNC_IMV_ReceiveMessage(TNC_IMVID imv_id,
+static TNC_Result receive_message(TNC_IMVID imv_id,
TNC_ConnectionID connection_id,
- TNC_BufferReference msg,
- TNC_UInt32 msg_len,
- TNC_MessageType msg_type)
+ TNC_UInt32 msg_flags,
+ chunk_t msg,
+ TNC_VendorID msg_vid,
+ TNC_MessageSubtype msg_subtype,
+ TNC_UInt32 src_imc_id,
+ TNC_UInt32 dst_imv_id)
{
pa_tnc_msg_t *pa_tnc_msg;
pa_tnc_attr_t *attr;
imv_state_t *state;
enumerator_t *enumerator;
TNC_Result result;
- bool fatal_error = FALSE;
+ bool fatal_error;
if (!imv_scanner)
{
@@ -204,9 +204,8 @@ TNC_Result TNC_IMV_ReceiveMessage(TNC_IMVID imv_id,
}
/* parse received PA-TNC message and automatically handle any errors */
- result = imv_scanner->receive_message(imv_scanner, connection_id,
- chunk_create(msg, msg_len), msg_type,
- &pa_tnc_msg);
+ result = imv_scanner->receive_message(imv_scanner, state, msg, msg_vid,
+ msg_subtype, src_imc_id, dst_imv_id, &pa_tnc_msg);
/* no parsed PA-TNC attributes available if an error occurred */
if (!pa_tnc_msg)
@@ -214,44 +213,15 @@ TNC_Result TNC_IMV_ReceiveMessage(TNC_IMVID imv_id,
return result;
}
+ /* preprocess any IETF standard error attributes */
+ fatal_error = pa_tnc_msg->process_ietf_std_errors(pa_tnc_msg);
+
/* analyze PA-TNC attributes */
enumerator = pa_tnc_msg->create_attribute_enumerator(pa_tnc_msg);
while (enumerator->enumerate(enumerator, &attr))
{
- if (attr->get_vendor_id(attr) != PEN_IETF)
- {
- continue;
- }
-
- if (attr->get_type(attr) == IETF_ATTR_PA_TNC_ERROR)
- {
- ietf_attr_pa_tnc_error_t *error_attr;
- pa_tnc_error_code_t error_code;
- chunk_t msg_info, attr_info;
- u_int32_t offset;
-
- error_attr = (ietf_attr_pa_tnc_error_t*)attr;
- error_code = error_attr->get_error_code(error_attr);
- msg_info = error_attr->get_msg_info(error_attr);
- DBG1(DBG_IMV, "received PA-TNC error '%N' concerning message %#B",
- pa_tnc_error_code_names, error_code, &msg_info);
-
- switch (error_code)
- {
- case PA_ERROR_INVALID_PARAMETER:
- offset = error_attr->get_offset(error_attr);
- DBG1(DBG_IMV, " occurred at offset of %u bytes", offset);
- break;
- case PA_ERROR_ATTR_TYPE_NOT_SUPPORTED:
- attr_info = error_attr->get_attr_info(error_attr);
- DBG1(DBG_IMV, " unsupported attribute %#B", &attr_info);
- break;
- default:
- break;
- }
- fatal_error = TRUE;
- }
- else if (attr->get_type(attr) == IETF_ATTR_PORT_FILTER)
+ if (attr->get_vendor_id(attr) == PEN_IETF &&
+ attr->get_type(attr) == IETF_ATTR_PORT_FILTER)
{
ietf_attr_port_filter_t *attr_port_filter;
enumerator_t *enumerator;
@@ -339,10 +309,47 @@ TNC_Result TNC_IMV_ReceiveMessage(TNC_IMVID imv_id,
}
return imv_scanner->provide_recommendation(imv_scanner, connection_id);
+ }
+
+/**
+ * see section 3.8.4 of TCG TNC IF-IMV Specification 1.3
+ */
+TNC_Result TNC_IMV_ReceiveMessage(TNC_IMVID imv_id,
+ TNC_ConnectionID connection_id,
+ TNC_BufferReference msg,
+ TNC_UInt32 msg_len,
+ TNC_MessageType msg_type)
+{
+ TNC_VendorID msg_vid;
+ TNC_MessageSubtype msg_subtype;
+
+ msg_vid = msg_type >> 8;
+ msg_subtype = msg_type & TNC_SUBTYPE_ANY;
+
+ return receive_message(imv_id, connection_id, 0, chunk_create(msg, msg_len),
+ msg_vid, msg_subtype, 0, TNC_IMVID_ANY);
+}
+
+/**
+ * see section 3.8.6 of TCG TNC IF-IMV Specification 1.3
+ */
+TNC_Result TNC_IMV_ReceiveMessageLong(TNC_IMVID imv_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_imc_id,
+ TNC_UInt32 dst_imv_id)
+{
+ return receive_message(imv_id, connection_id, msg_flags,
+ chunk_create(msg, msg_len), msg_vid, msg_subtype,
+ src_imc_id, dst_imv_id);
}
/**
- * see section 3.7.4 of TCG TNC IF-IMV Specification 1.2
+ * see section 3.8.7 of TCG TNC IF-IMV Specification 1.3
*/
TNC_Result TNC_IMV_SolicitRecommendation(TNC_IMVID imv_id,
TNC_ConnectionID connection_id)
@@ -356,7 +363,7 @@ TNC_Result TNC_IMV_SolicitRecommendation(TNC_IMVID imv_id,
}
/**
- * see section 3.7.5 of TCG TNC IF-IMV Specification 1.2
+ * see section 3.8.8 of TCG TNC IF-IMV Specification 1.3
*/
TNC_Result TNC_IMV_BatchEnding(TNC_IMVID imv_id,
TNC_ConnectionID connection_id)
@@ -370,7 +377,7 @@ TNC_Result TNC_IMV_BatchEnding(TNC_IMVID imv_id,
}
/**
- * see section 3.7.6 of TCG TNC IF-IMV Specification 1.2
+ * see section 3.8.9 of TCG TNC IF-IMV Specification 1.3
*/
TNC_Result TNC_IMV_Terminate(TNC_IMVID imv_id)
{
@@ -388,7 +395,7 @@ TNC_Result TNC_IMV_Terminate(TNC_IMVID imv_id)
}
/**
- * see section 4.2.8.1 of TCG TNC IF-IMV Specification 1.2
+ * see section 4.2.8.1 of TCG TNC IF-IMV Specification 1.3
*/
TNC_Result TNC_IMV_ProvideBindFunction(TNC_IMVID imv_id,
TNC_TNCS_BindFunctionPointer bind_function)
diff --git a/src/libimcv/plugins/imv_scanner/imv_scanner_state.c b/src/libimcv/plugins/imv_scanner/imv_scanner_state.c
index a9b048bcb..422cb980d 100644
--- a/src/libimcv/plugins/imv_scanner/imv_scanner_state.c
+++ b/src/libimcv/plugins/imv_scanner/imv_scanner_state.c
@@ -40,6 +40,16 @@ struct private_imv_scanner_state_t {
TNC_ConnectionState state;
/**
+ * Does the TNCCS connection support long message types?
+ */
+ bool has_long;
+
+ /**
+ * Does the TNCCS connection support exclusive delivery?
+ */
+ bool has_excl;
+
+ /**
* IMV action recommendation
*/
TNC_IMV_Action_Recommendation rec;
@@ -86,6 +96,25 @@ METHOD(imv_state_t, get_connection_id, TNC_ConnectionID,
return this->connection_id;
}
+METHOD(imv_state_t, has_long, bool,
+ private_imv_scanner_state_t *this)
+{
+ return this->has_long;
+}
+
+METHOD(imv_state_t, has_excl, bool,
+ private_imv_scanner_state_t *this)
+{
+ return this->has_excl;
+}
+
+METHOD(imv_state_t, set_flags, void,
+ private_imv_scanner_state_t *this, bool has_long, bool has_excl)
+{
+ this->has_long = has_long;
+ this->has_excl = has_excl;
+}
+
METHOD(imv_state_t, change_state, void,
private_imv_scanner_state_t *this, TNC_ConnectionState new_state)
{
@@ -191,6 +220,9 @@ imv_state_t *imv_scanner_state_create(TNC_ConnectionID connection_id)
.public = {
.interface = {
.get_connection_id = _get_connection_id,
+ .has_long = _has_long,
+ .has_excl = _has_excl,
+ .set_flags = _set_flags,
.change_state = _change_state,
.get_recommendation = _get_recommendation,
.set_recommendation = _set_recommendation,
diff --git a/src/libimcv/plugins/imv_test/imv_test.c b/src/libimcv/plugins/imv_test/imv_test.c
index 88db24983..0afd81aec 100644
--- a/src/libimcv/plugins/imv_test/imv_test.c
+++ b/src/libimcv/plugins/imv_test/imv_test.c
@@ -37,7 +37,7 @@ static const char imv_name[] = "Test";
static imv_agent_t *imv_test;
/**
- * see section 3.7.1 of TCG TNC IF-IMV Specification 1.2
+ * see section 3.8.1 of TCG TNC IF-IMV Specification 1.3
*/
TNC_Result TNC_IMV_Initialize(TNC_IMVID imv_id,
TNC_Version min_version,
@@ -64,16 +64,13 @@ TNC_Result TNC_IMV_Initialize(TNC_IMVID imv_id,
}
/**
- * see section 3.7.2 of TCG TNC IF-IMV Specification 1.2
+ * see section 3.8.2 of TCG TNC IF-IMV Specification 1.3
*/
TNC_Result TNC_IMV_NotifyConnectionChange(TNC_IMVID imv_id,
TNC_ConnectionID connection_id,
TNC_ConnectionState new_state)
{
imv_state_t *state;
- imv_test_state_t *test_state;
- TNC_Result result;
- int rounds;
if (!imv_test)
{
@@ -87,60 +84,29 @@ TNC_Result TNC_IMV_NotifyConnectionChange(TNC_IMVID imv_id,
return imv_test->create_state(imv_test, state);
case TNC_CONNECTION_STATE_DELETE:
return imv_test->delete_state(imv_test, connection_id);
- case TNC_CONNECTION_STATE_HANDSHAKE:
- /* get updated IMV state */
- result = imv_test->change_state(imv_test, connection_id,
- new_state, &state);
- if (result != TNC_RESULT_SUCCESS)
- {
- return result;
- }
- test_state = (imv_test_state_t*)state;
-
- /* set the number of measurement rounds */
- rounds = lib->settings->get_int(lib->settings,
- "libimcv.plugins.imv-test.rounds", 0);
- test_state->set_rounds(test_state, rounds);
- return TNC_RESULT_SUCCESS;
default:
return imv_test->change_state(imv_test, connection_id,
new_state, NULL);
}
}
-static TNC_Result send_message(TNC_ConnectionID connection_id)
-{
- pa_tnc_msg_t *msg;
- pa_tnc_attr_t *attr;
- TNC_Result result;
-
- attr = ita_attr_command_create("repeat");
- msg = pa_tnc_msg_create();
- msg->add_attribute(msg, attr);
- msg->build(msg);
- result = imv_test->send_message(imv_test, connection_id,
- msg->get_encoding(msg));
- msg->destroy(msg);
-
- return result;
-}
-
-/**
- * see section 3.7.3 of TCG TNC IF-IMV Specification 1.2
- */
-TNC_Result TNC_IMV_ReceiveMessage(TNC_IMVID imv_id,
+static TNC_Result receive_message(TNC_IMVID imv_id,
TNC_ConnectionID connection_id,
- TNC_BufferReference msg,
- TNC_UInt32 msg_len,
- TNC_MessageType msg_type)
+ TNC_UInt32 msg_flags,
+ chunk_t msg,
+ TNC_VendorID msg_vid,
+ TNC_MessageSubtype msg_subtype,
+ TNC_UInt32 src_imc_id,
+ TNC_UInt32 dst_imv_id)
{
pa_tnc_msg_t *pa_tnc_msg;
pa_tnc_attr_t *attr;
imv_state_t *state;
- imv_test_state_t *imv_test_state;
+ imv_test_state_t *test_state;
enumerator_t *enumerator;
TNC_Result result;
- bool fatal_error = FALSE, retry = FALSE;
+ int rounds;
+ bool fatal_error, retry = FALSE;
if (!imv_test)
{
@@ -153,11 +119,11 @@ TNC_Result TNC_IMV_ReceiveMessage(TNC_IMVID imv_id,
{
return TNC_RESULT_FATAL;
}
+ test_state = (imv_test_state_t*)state;
/* parse received PA-TNC message and automatically handle any errors */
- result = imv_test->receive_message(imv_test, connection_id,
- chunk_create(msg, msg_len), msg_type,
- &pa_tnc_msg);
+ result = imv_test->receive_message(imv_test, state, msg, msg_vid,
+ msg_subtype, src_imc_id, dst_imv_id, &pa_tnc_msg);
/* no parsed PA-TNC attributes available if an error occurred */
if (!pa_tnc_msg)
@@ -165,41 +131,20 @@ TNC_Result TNC_IMV_ReceiveMessage(TNC_IMVID imv_id,
return result;
}
+ /* preprocess any IETF standard error attributes */
+ fatal_error = pa_tnc_msg->process_ietf_std_errors(pa_tnc_msg);
+
+ /* add any new IMC and set its number of rounds */
+ rounds = lib->settings->get_int(lib->settings,
+ "libimcv.plugins.imv-test.rounds", 0);
+ test_state->add_imc(test_state, src_imc_id, rounds);
+
/* analyze PA-TNC attributes */
enumerator = pa_tnc_msg->create_attribute_enumerator(pa_tnc_msg);
while (enumerator->enumerate(enumerator, &attr))
{
- if (attr->get_vendor_id(attr) == PEN_IETF &&
- attr->get_type(attr) == IETF_ATTR_PA_TNC_ERROR)
- {
- ietf_attr_pa_tnc_error_t *error_attr;
- pa_tnc_error_code_t error_code;
- chunk_t msg_info, attr_info;
- u_int32_t offset;
-
- error_attr = (ietf_attr_pa_tnc_error_t*)attr;
- error_code = error_attr->get_error_code(error_attr);
- msg_info = error_attr->get_msg_info(error_attr);
-
- DBG1(DBG_IMV, "received PA-TNC error '%N' concerning message %#B",
- pa_tnc_error_code_names, error_code, &msg_info);
- switch (error_code)
- {
- case PA_ERROR_INVALID_PARAMETER:
- offset = error_attr->get_offset(error_attr);
- DBG1(DBG_IMV, " occurred at offset of %u bytes", offset);
- break;
- case PA_ERROR_ATTR_TYPE_NOT_SUPPORTED:
- attr_info = error_attr->get_attr_info(error_attr);
- DBG1(DBG_IMV, " unsupported attribute %#B", &attr_info);
- break;
- default:
- break;
- }
- fatal_error = TRUE;
- }
- else if (attr->get_vendor_id(attr) == PEN_ITA &&
- attr->get_type(attr) == ITA_ATTR_COMMAND)
+ if (attr->get_vendor_id(attr) == PEN_ITA &&
+ attr->get_type(attr) == ITA_ATTR_COMMAND)
{
ita_attr_command_t *ita_attr;
char *command;
@@ -252,22 +197,67 @@ TNC_Result TNC_IMV_ReceiveMessage(TNC_IMVID imv_id,
/* request a handshake retry ? */
if (retry)
{
+ test_state->set_rounds(test_state, rounds);
return imv_test->request_handshake_retry(imv_id, connection_id,
TNC_RETRY_REASON_IMV_SERIOUS_EVENT);
}
/* repeat the measurement ? */
- imv_test_state = (imv_test_state_t*)state;
- if (imv_test_state->another_round(imv_test_state))
+ if (test_state->another_round(test_state, src_imc_id))
{
- return send_message(connection_id);
+ attr = ita_attr_command_create("repeat");
+ pa_tnc_msg = pa_tnc_msg_create();
+ pa_tnc_msg->add_attribute(pa_tnc_msg, attr);
+ pa_tnc_msg->build(pa_tnc_msg);
+ result = imv_test->send_message(imv_test, connection_id, TRUE, imv_id,
+ src_imc_id, pa_tnc_msg->get_encoding(pa_tnc_msg));
+ pa_tnc_msg->destroy(pa_tnc_msg);
+
+ return result;
}
return imv_test->provide_recommendation(imv_test, connection_id);
}
/**
- * see section 3.7.4 of TCG TNC IF-IMV Specification 1.2
+ * see section 3.8.4 of TCG TNC IF-IMV Specification 1.3
+ */
+TNC_Result TNC_IMV_ReceiveMessage(TNC_IMVID imv_id,
+ TNC_ConnectionID connection_id,
+ TNC_BufferReference msg,
+ TNC_UInt32 msg_len,
+ TNC_MessageType msg_type)
+{
+ TNC_VendorID msg_vid;
+ TNC_MessageSubtype msg_subtype;
+
+ msg_vid = msg_type >> 8;
+ msg_subtype = msg_type & TNC_SUBTYPE_ANY;
+
+ return receive_message(imv_id, connection_id, 0, chunk_create(msg, msg_len),
+ msg_vid, msg_subtype, 0, TNC_IMVID_ANY);
+}
+
+/**
+ * see section 3.8.6 of TCG TNC IF-IMV Specification 1.3
+ */
+TNC_Result TNC_IMV_ReceiveMessageLong(TNC_IMVID imv_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_imc_id,
+ TNC_UInt32 dst_imv_id)
+{
+ return receive_message(imv_id, connection_id, msg_flags,
+ chunk_create(msg, msg_len), msg_vid, msg_subtype,
+ src_imc_id, dst_imv_id);
+}
+
+/**
+ * see section 3.8.7 of TCG TNC IF-IMV Specification 1.3
*/
TNC_Result TNC_IMV_SolicitRecommendation(TNC_IMVID imv_id,
TNC_ConnectionID connection_id)
@@ -281,7 +271,7 @@ TNC_Result TNC_IMV_SolicitRecommendation(TNC_IMVID imv_id,
}
/**
- * see section 3.7.5 of TCG TNC IF-IMV Specification 1.2
+ * see section 3.8.8 of TCG TNC IF-IMV Specification 1.3
*/
TNC_Result TNC_IMV_BatchEnding(TNC_IMVID imv_id,
TNC_ConnectionID connection_id)
@@ -295,7 +285,7 @@ TNC_Result TNC_IMV_BatchEnding(TNC_IMVID imv_id,
}
/**
- * see section 3.7.6 of TCG TNC IF-IMV Specification 1.2
+ * see section 3.8.9 of TCG TNC IF-IMV Specification 1.3
*/
TNC_Result TNC_IMV_Terminate(TNC_IMVID imv_id)
{
@@ -311,7 +301,7 @@ TNC_Result TNC_IMV_Terminate(TNC_IMVID imv_id)
}
/**
- * see section 4.2.8.1 of TCG TNC IF-IMV Specification 1.2
+ * see section 4.2.8.1 of TCG TNC IF-IMV Specification 1.3
*/
TNC_Result TNC_IMV_ProvideBindFunction(TNC_IMVID imv_id,
TNC_TNCS_BindFunctionPointer bind_function)
diff --git a/src/libimcv/plugins/imv_test/imv_test_state.c b/src/libimcv/plugins/imv_test/imv_test_state.c
index 930da93e4..530090af7 100644
--- a/src/libimcv/plugins/imv_test/imv_test_state.c
+++ b/src/libimcv/plugins/imv_test/imv_test_state.c
@@ -15,6 +15,7 @@
#include "imv_test_state.h"
#include <utils/lexparser.h>
+#include <utils/linked_list.h>
#include <debug.h>
typedef struct private_imv_test_state_t private_imv_test_state_t;
@@ -40,6 +41,16 @@ struct private_imv_test_state_t {
TNC_ConnectionState state;
/**
+ * Does the TNCCS connection support long message types?
+ */
+ bool has_long;
+
+ /**
+ * Does the TNCCS connection support exclusive delivery?
+ */
+ bool has_excl;
+
+ /**
* IMV action recommendation
*/
TNC_IMV_Action_Recommendation rec;
@@ -50,10 +61,20 @@ struct private_imv_test_state_t {
TNC_IMV_Evaluation_Result eval;
/**
- * IMC-IMV round-trip count
+ * List of IMCs
*/
- int rounds;
+ linked_list_t *imcs;
+
+};
+typedef struct imc_entry_t imc_entry_t;
+
+/**
+ * Define an internal IMC entry
+ */
+struct imc_entry_t {
+ TNC_UInt32 imc_id;
+ int rounds;
};
typedef struct entry_t entry_t;
@@ -82,6 +103,25 @@ METHOD(imv_state_t, get_connection_id, TNC_ConnectionID,
return this->connection_id;
}
+METHOD(imv_state_t, has_long, bool,
+ private_imv_test_state_t *this)
+{
+ return this->has_long;
+}
+
+METHOD(imv_state_t, has_excl, bool,
+ private_imv_test_state_t *this)
+{
+ return this->has_excl;
+}
+
+METHOD(imv_state_t, set_flags, void,
+ private_imv_test_state_t *this, bool has_long, bool has_excl)
+{
+ this->has_long = has_long;
+ this->has_excl = has_excl;
+}
+
METHOD(imv_state_t, change_state, void,
private_imv_test_state_t *this, TNC_ConnectionState new_state)
{
@@ -151,19 +191,73 @@ METHOD(imv_state_t, get_reason_string, bool,
METHOD(imv_state_t, destroy, void,
private_imv_test_state_t *this)
{
+ this->imcs->destroy_function(this->imcs, free);
free(this);
}
+METHOD(imv_test_state_t, add_imc, void,
+ private_imv_test_state_t *this, TNC_UInt32 imc_id, int rounds)
+{
+ enumerator_t *enumerator;
+ imc_entry_t *imc_entry;
+ bool found = FALSE;
+
+ enumerator = this->imcs->create_enumerator(this->imcs);
+ while (enumerator->enumerate(enumerator, &imc_entry))
+ {
+ if (imc_entry->imc_id == imc_id)
+ {
+ found = TRUE;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ if (!found)
+ {
+ imc_entry = malloc_thing(imc_entry_t);
+ imc_entry->imc_id = imc_id;
+ imc_entry->rounds = rounds;
+ this->imcs->insert_last(this->imcs, imc_entry);
+ }
+}
+
METHOD(imv_test_state_t, set_rounds, void,
private_imv_test_state_t *this, int rounds)
{
- this->rounds = rounds;
+ enumerator_t *enumerator;
+ imc_entry_t *imc_entry;
+
+ enumerator = this->imcs->create_enumerator(this->imcs);
+ while (enumerator->enumerate(enumerator, &imc_entry))
+ {
+ imc_entry->rounds = rounds;
+ }
+ enumerator->destroy(enumerator);
}
METHOD(imv_test_state_t, another_round, bool,
- private_imv_test_state_t *this)
+ private_imv_test_state_t *this, TNC_UInt32 imc_id)
{
- return (this->rounds-- > 0);
+ enumerator_t *enumerator;
+ imc_entry_t *imc_entry;
+ bool not_finished = FALSE;
+
+ enumerator = this->imcs->create_enumerator(this->imcs);
+ while (enumerator->enumerate(enumerator, &imc_entry))
+ {
+ if (imc_entry->rounds > 0)
+ {
+ not_finished = TRUE;
+ }
+ if (imc_entry->imc_id == imc_id)
+ {
+ imc_entry->rounds--;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ return not_finished;
}
/**
@@ -177,12 +271,16 @@ imv_state_t *imv_test_state_create(TNC_ConnectionID connection_id)
.public = {
.interface = {
.get_connection_id = _get_connection_id,
+ .has_long = _has_long,
+ .has_excl = _has_excl,
+ .set_flags = _set_flags,
.change_state = _change_state,
.get_recommendation = _get_recommendation,
.set_recommendation = _set_recommendation,
.get_reason_string = _get_reason_string,
.destroy = _destroy,
},
+ .add_imc = _add_imc,
.set_rounds = _set_rounds,
.another_round = _another_round,
},
@@ -190,6 +288,7 @@ imv_state_t *imv_test_state_create(TNC_ConnectionID connection_id)
.rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION,
.eval = TNC_IMV_EVALUATION_RESULT_DONT_KNOW,
.connection_id = connection_id,
+ .imcs = linked_list_create(),
);
return &this->public.interface;
diff --git a/src/libimcv/plugins/imv_test/imv_test_state.h b/src/libimcv/plugins/imv_test/imv_test_state.h
index 7e7b3a8f3..af78d1470 100644
--- a/src/libimcv/plugins/imv_test/imv_test_state.h
+++ b/src/libimcv/plugins/imv_test/imv_test_state.h
@@ -37,6 +37,14 @@ struct imv_test_state_t {
imv_state_t interface;
/**
+ * Add an IMC
+ *
+ * @param imc_id ID of the IMC to be added
+ * @param rounds number of re-measurement rounds
+ */
+ void (*add_imc)(imv_test_state_t *this, TNC_UInt32 imc_id, int rounds);
+
+ /**
* Set the IMC-IMV round-trip count
*
* @param rounds number of re-measurement rounds
@@ -46,9 +54,10 @@ struct imv_test_state_t {
/**
* Check and decrease IMC-IMV round-trip count
*
+ * @param imc_id ID of the IMC to be checked
* @return new connection state
*/
- bool (*another_round)(imv_test_state_t *this);
+ bool (*another_round)(imv_test_state_t *this, TNC_UInt32 imc_id);
};
/**
diff --git a/src/libpts/Makefile.am b/src/libpts/Makefile.am
index ee729c287..3ff941794 100644
--- a/src/libpts/Makefile.am
+++ b/src/libpts/Makefile.am
@@ -3,29 +3,56 @@ INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libimcv
ipseclib_LTLIBRARIES = libpts.la
-libpts_la_LIBADD = -ltspi
+libpts_la_LIBADD = $(top_builddir)/src/libimcv/libimcv.la -ltspi
libpts_la_SOURCES = \
libpts.h libpts.c \
pts/pts.h pts/pts.c \
pts/pts_error.h pts/pts_error.c \
- pts/pts_proto_caps.h pts/pts_funct_comp_name.h pts/pts_file_type.h \
+ pts/pts_proto_caps.h \
+ pts/pts_req_func_comp_evid.h \
+ pts/pts_simple_evid_final.h \
pts/pts_creds.h pts/pts_creds.c \
pts/pts_database.h pts/pts_database.c \
+ pts/pts_dh_group.h pts/pts_dh_group.c \
pts/pts_file_meas.h pts/pts_file_meas.c \
pts/pts_file_meta.h pts/pts_file_meta.c \
+ pts/pts_file_type.h pts/pts_file_type.c \
pts/pts_meas_algo.h pts/pts_meas_algo.c \
+ pts/components/pts_component.h \
+ pts/components/pts_component_manager.h pts/components/pts_component_manager.c \
+ pts/components/pts_comp_evidence.h pts/components/pts_comp_evidence.c \
+ pts/components/pts_comp_func_name.h pts/components/pts_comp_func_name.c \
+ pts/components/ita/ita_comp_func_name.h pts/components/ita/ita_comp_func_name.c \
+ pts/components/ita/ita_comp_ima.h pts/components/ita/ita_comp_ima.c \
+ 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 \
tcg/tcg_attr.h tcg/tcg_attr.c \
tcg/tcg_pts_attr_proto_caps.h tcg/tcg_pts_attr_proto_caps.c \
+ tcg/tcg_pts_attr_dh_nonce_params_req.h tcg/tcg_pts_attr_dh_nonce_params_req.c \
+ tcg/tcg_pts_attr_dh_nonce_params_resp.h tcg/tcg_pts_attr_dh_nonce_params_resp.c \
+ tcg/tcg_pts_attr_dh_nonce_finish.h tcg/tcg_pts_attr_dh_nonce_finish.c \
tcg/tcg_pts_attr_meas_algo.h tcg/tcg_pts_attr_meas_algo.c \
tcg/tcg_pts_attr_get_tpm_version_info.h tcg/tcg_pts_attr_get_tpm_version_info.c \
tcg/tcg_pts_attr_tpm_version_info.h tcg/tcg_pts_attr_tpm_version_info.c \
tcg/tcg_pts_attr_get_aik.h tcg/tcg_pts_attr_get_aik.c \
tcg/tcg_pts_attr_aik.h tcg/tcg_pts_attr_aik.c \
- tcg/tcg_pts_attr_req_funct_comp_evid.h tcg/tcg_pts_attr_req_funct_comp_evid.c \
+ tcg/tcg_pts_attr_req_func_comp_evid.h tcg/tcg_pts_attr_req_func_comp_evid.c \
tcg/tcg_pts_attr_gen_attest_evid.h tcg/tcg_pts_attr_gen_attest_evid.c \
tcg/tcg_pts_attr_simple_comp_evid.h tcg/tcg_pts_attr_simple_comp_evid.c \
tcg/tcg_pts_attr_simple_evid_final.h tcg/tcg_pts_attr_simple_evid_final.c \
tcg/tcg_pts_attr_req_file_meas.h tcg/tcg_pts_attr_req_file_meas.c \
tcg/tcg_pts_attr_file_meas.h tcg/tcg_pts_attr_file_meas.c \
+ tcg/tcg_pts_attr_req_file_meta.h tcg/tcg_pts_attr_req_file_meta.c \
tcg/tcg_pts_attr_unix_file_meta.h tcg/tcg_pts_attr_unix_file_meta.c
+
+SUBDIRS = .
+
+if USE_IMC_ATTESTATION
+ SUBDIRS += plugins/imc_attestation
+endif
+
+if USE_IMV_ATTESTATION
+ SUBDIRS += plugins/imv_attestation
+endif
diff --git a/src/libpts/libpts.c b/src/libpts/libpts.c
index bd4c3a411..384ee4ed7 100644
--- a/src/libpts/libpts.c
+++ b/src/libpts/libpts.c
@@ -14,12 +14,23 @@
#include "libpts.h"
#include "tcg/tcg_attr.h"
+#include "pts/components/pts_component.h"
+#include "pts/components/pts_component_manager.h"
+#include "pts/components/tcg/tcg_comp_func_name.h"
+#include "pts/components/ita/ita_comp_func_name.h"
+#include "pts/components/ita/ita_comp_ima.h"
+#include "pts/components/ita/ita_comp_tboot.h"
+#include "pts/components/ita/ita_comp_tgrub.h"
#include <imcv.h>
-
#include <debug.h>
/**
+ * PTS Functional Component manager
+ */
+pts_component_manager_t *pts_components;
+
+/**
* Reference count for IMC/IMV instances
*/
static refcount_t libpts_ref = 0;
@@ -37,6 +48,25 @@ bool libpts_init(void)
}
imcv_pa_tnc_attributes->add_vendor(imcv_pa_tnc_attributes, PEN_TCG,
tcg_attr_create_from_data, tcg_attr_names);
+
+ pts_components = pts_component_manager_create();
+ pts_components->add_vendor(pts_components, PEN_TCG,
+ pts_tcg_comp_func_names, PTS_TCG_QUALIFIER_TYPE_SIZE,
+ pts_tcg_qualifier_flag_names, pts_tcg_qualifier_type_names);
+ pts_components->add_vendor(pts_components, PEN_ITA,
+ pts_ita_comp_func_names, PTS_ITA_QUALIFIER_TYPE_SIZE,
+ pts_ita_qualifier_flag_names, pts_ita_qualifier_type_names);
+
+ pts_components->add_component(pts_components, PEN_ITA,
+ PTS_ITA_COMP_FUNC_NAME_TGRUB,
+ pts_ita_comp_tgrub_create);
+ pts_components->add_component(pts_components, PEN_ITA,
+ PTS_ITA_COMP_FUNC_NAME_TBOOT,
+ pts_ita_comp_tboot_create);
+ pts_components->add_component(pts_components, PEN_ITA,
+ PTS_ITA_COMP_FUNC_NAME_IMA,
+ pts_ita_comp_ima_create);
+
DBG1(DBG_LIB, "libpts initialized");
}
ref_get(&libpts_ref);
@@ -51,6 +81,10 @@ void libpts_deinit(void)
{
if (ref_put(&libpts_ref))
{
+ pts_components->remove_vendor(pts_components, PEN_TCG);
+ pts_components->remove_vendor(pts_components, PEN_ITA);
+ pts_components->destroy(pts_components);
+
if (!imcv_pa_tnc_attributes)
{
return;
diff --git a/src/libpts/libpts.h b/src/libpts/libpts.h
index 4c771d236..7b2959728 100644
--- a/src/libpts/libpts.h
+++ b/src/libpts/libpts.h
@@ -25,6 +25,8 @@
#ifndef LIBPTS_H_
#define LIBPTS_H_
+#include "pts/components/pts_component_manager.h"
+
#include <library.h>
/**
@@ -39,4 +41,9 @@ bool libpts_init(void);
*/
void libpts_deinit(void);
+/**
+ * PTS Functional Component manager
+ */
+extern pts_component_manager_t* pts_components;
+
#endif /** LIBPTS_H_ @}*/
diff --git a/src/libimcv/plugins/imc_attestation/Makefile.am b/src/libpts/plugins/imc_attestation/Makefile.am
index ee082319d..9d78b935a 100644
--- a/src/libimcv/plugins/imc_attestation/Makefile.am
+++ b/src/libpts/plugins/imc_attestation/Makefile.am
@@ -11,7 +11,8 @@ imc_attestation_la_LIBADD = $(top_builddir)/src/libimcv/libimcv.la \
$(top_builddir)/src/libpts/libpts.la
imc_attestation_la_SOURCES = imc_attestation.c \
- imc_attestation_state.h imc_attestation_state.c
+ imc_attestation_state.h imc_attestation_state.c \
+ imc_attestation_process.h imc_attestation_process.c
imc_attestation_la_LDFLAGS = -module -avoid-version
diff --git a/src/libpts/plugins/imc_attestation/imc_attestation.c b/src/libpts/plugins/imc_attestation/imc_attestation.c
new file mode 100644
index 000000000..4f77ba093
--- /dev/null
+++ b/src/libpts/plugins/imc_attestation/imc_attestation.c
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) 2011 Sansar Choinyambuu
+ * 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_attestation_state.h"
+#include "imc_attestation_process.h"
+
+#include <imc/imc_agent.h>
+#include <pa_tnc/pa_tnc_msg.h>
+#include <ietf/ietf_attr.h>
+#include <ietf/ietf_attr_pa_tnc_error.h>
+#include <ietf/ietf_attr_product_info.h>
+
+#include <libpts.h>
+
+#include <pts/pts_error.h>
+
+#include <tcg/tcg_pts_attr_proto_caps.h>
+#include <tcg/tcg_pts_attr_meas_algo.h>
+
+#include <tncif_pa_subtypes.h>
+
+#include <pen/pen.h>
+#include <debug.h>
+#include <utils/linked_list.h>
+
+/* IMC definitions */
+
+static const char imc_name[] = "Attestation";
+
+#define IMC_VENDOR_ID PEN_TCG
+#define IMC_SUBTYPE PA_SUBTYPE_TCG_PTS
+
+static imc_agent_t *imc_attestation;
+
+/**
+ * Supported PTS measurement algorithms
+ */
+static pts_meas_algorithms_t supported_algorithms = PTS_MEAS_ALGO_NONE;
+
+/**
+ * Supported PTS Diffie Hellman Groups
+ */
+static pts_dh_group_t supported_dh_groups = PTS_DH_GROUP_NONE;
+
+/**
+ * see section 3.8.1 of TCG TNC IF-IMC Specification 1.3
+ */
+TNC_Result TNC_IMC_Initialize(TNC_IMCID imc_id,
+ TNC_Version min_version,
+ TNC_Version max_version,
+ TNC_Version *actual_version)
+{
+ if (imc_attestation)
+ {
+ DBG1(DBG_IMC, "IMC \"%s\" has already been initialized", imc_name);
+ return TNC_RESULT_ALREADY_INITIALIZED;
+ }
+ if (!pts_meas_algo_probe(&supported_algorithms) ||
+ !pts_dh_group_probe(&supported_dh_groups))
+ {
+ return TNC_RESULT_FATAL;
+ }
+ imc_attestation = imc_agent_create(imc_name, IMC_VENDOR_ID, IMC_SUBTYPE,
+ imc_id, actual_version);
+ if (!imc_attestation)
+ {
+ return TNC_RESULT_FATAL;
+ }
+
+ libpts_init();
+
+ 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_NotifyConnectionChange(TNC_IMCID imc_id,
+ TNC_ConnectionID connection_id,
+ TNC_ConnectionState new_state)
+{
+ imc_state_t *state;
+
+ if (!imc_attestation)
+ {
+ 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_attestation_state_create(connection_id);
+ return imc_attestation->create_state(imc_attestation, state);
+ case TNC_CONNECTION_STATE_DELETE:
+ return imc_attestation->delete_state(imc_attestation, connection_id);
+ case TNC_CONNECTION_STATE_HANDSHAKE:
+ case TNC_CONNECTION_STATE_ACCESS_ISOLATED:
+ case TNC_CONNECTION_STATE_ACCESS_NONE:
+ default:
+ return imc_attestation->change_state(imc_attestation, connection_id,
+ new_state, NULL);
+ }
+}
+
+
+/**
+ * see section 3.8.3 of TCG TNC IF-IMC Specification 1.3
+ */
+TNC_Result TNC_IMC_BeginHandshake(TNC_IMCID imc_id,
+ TNC_ConnectionID connection_id)
+{
+ imc_state_t *state;
+ imc_attestation_state_t *attestation_state;
+ pts_t *pts;
+ char *platform_info;
+ TNC_Result result = TNC_RESULT_SUCCESS;
+
+ if (!imc_attestation)
+ {
+ DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
+ return TNC_RESULT_NOT_INITIALIZED;
+ }
+
+ /* get current IMC state */
+ if (!imc_attestation->get_state(imc_attestation, connection_id, &state))
+ {
+ return TNC_RESULT_FATAL;
+ }
+ attestation_state = (imc_attestation_state_t*)state;
+ pts = attestation_state->get_pts(attestation_state);
+
+ platform_info = pts->get_platform_info(pts);
+ if (platform_info)
+ {
+ pa_tnc_msg_t *pa_tnc_msg;
+ pa_tnc_attr_t *attr;
+
+ pa_tnc_msg = pa_tnc_msg_create();
+ attr = ietf_attr_product_info_create(0, 0, platform_info);
+ pa_tnc_msg->add_attribute(pa_tnc_msg, attr);
+ pa_tnc_msg->build(pa_tnc_msg);
+ result = imc_attestation->send_message(imc_attestation, connection_id,
+ FALSE, 0, TNC_IMVID_ANY,
+ pa_tnc_msg->get_encoding(pa_tnc_msg));
+ pa_tnc_msg->destroy(pa_tnc_msg);
+ }
+
+ return result;
+}
+
+static TNC_Result receive_message(TNC_IMCID imc_id,
+ TNC_ConnectionID connection_id,
+ TNC_UInt32 msg_flags,
+ chunk_t msg,
+ TNC_VendorID msg_vid,
+ TNC_MessageSubtype msg_subtype,
+ TNC_UInt32 src_imv_id,
+ TNC_UInt32 dst_imc_id)
+{
+ pa_tnc_msg_t *pa_tnc_msg;
+ pa_tnc_attr_t *attr;
+ linked_list_t *attr_list;
+ imc_state_t *state;
+ imc_attestation_state_t *attestation_state;
+ enumerator_t *enumerator;
+ TNC_Result result;
+
+ if (!imc_attestation)
+ {
+ DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
+ return TNC_RESULT_NOT_INITIALIZED;
+ }
+
+ /* get current IMC state */
+ if (!imc_attestation->get_state(imc_attestation, connection_id, &state))
+ {
+ return TNC_RESULT_FATAL;
+ }
+ attestation_state = (imc_attestation_state_t*)state;
+
+ /* parse received PA-TNC message and automatically handle any errors */
+ result = imc_attestation->receive_message(imc_attestation, state, msg,
+ msg_vid, msg_subtype, src_imv_id, dst_imc_id, &pa_tnc_msg);
+
+ /* no parsed PA-TNC attributes available if an error occurred */
+ if (!pa_tnc_msg)
+ {
+ return result;
+ }
+
+ /* preprocess any IETF standard error attributes */
+ result = pa_tnc_msg->process_ietf_std_errors(pa_tnc_msg) ?
+ TNC_RESULT_FATAL : TNC_RESULT_SUCCESS;
+
+ attr_list = linked_list_create();
+
+ /* analyze PA-TNC attributes */
+ enumerator = pa_tnc_msg->create_attribute_enumerator(pa_tnc_msg);
+ while (enumerator->enumerate(enumerator, &attr))
+ {
+ if (attr->get_vendor_id(attr) == PEN_IETF &&
+ attr->get_type(attr) == IETF_ATTR_PA_TNC_ERROR)
+ {
+ ietf_attr_pa_tnc_error_t *error_attr;
+ pen_t error_vendor_id;
+ pa_tnc_error_code_t error_code;
+ chunk_t msg_info;
+
+ error_attr = (ietf_attr_pa_tnc_error_t*)attr;
+ error_vendor_id = error_attr->get_vendor_id(error_attr);
+
+ if (error_vendor_id == PEN_TCG)
+ {
+ error_code = error_attr->get_error_code(error_attr);
+ msg_info = error_attr->get_msg_info(error_attr);
+
+ DBG1(DBG_IMC, "received TCG-PTS error '%N'",
+ pts_error_code_names, error_code);
+ DBG1(DBG_IMC, "error information: %B", &msg_info);
+
+ result = TNC_RESULT_FATAL;
+ }
+ }
+ else if (attr->get_vendor_id(attr) == PEN_TCG)
+ {
+ if (!imc_attestation_process(attr, attr_list, attestation_state,
+ supported_algorithms, supported_dh_groups))
+ {
+ result = TNC_RESULT_FATAL;
+ break;
+ }
+ }
+ }
+ enumerator->destroy(enumerator);
+ pa_tnc_msg->destroy(pa_tnc_msg);
+
+ if (result == TNC_RESULT_SUCCESS && attr_list->get_count(attr_list))
+ {
+ pa_tnc_msg = pa_tnc_msg_create();
+
+ enumerator = attr_list->create_enumerator(attr_list);
+ while (enumerator->enumerate(enumerator, &attr))
+ {
+ pa_tnc_msg->add_attribute(pa_tnc_msg, attr);
+ }
+ enumerator->destroy(enumerator);
+
+ pa_tnc_msg->build(pa_tnc_msg);
+ result = imc_attestation->send_message(imc_attestation, connection_id,
+ FALSE, 0, TNC_IMVID_ANY,
+ pa_tnc_msg->get_encoding(pa_tnc_msg));
+ pa_tnc_msg->destroy(pa_tnc_msg);
+ }
+
+ attr_list->destroy(attr_list);
+ return result;
+}
+
+/**
+ * see section 3.8.4 of TCG TNC IF-IMC Specification 1.3
+ */
+TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id,
+ TNC_ConnectionID connection_id,
+ TNC_BufferReference msg,
+ TNC_UInt32 msg_len,
+ TNC_MessageType msg_type)
+{
+ TNC_VendorID msg_vid;
+ TNC_MessageSubtype msg_subtype;
+
+ msg_vid = msg_type >> 8;
+ msg_subtype = msg_type & TNC_SUBTYPE_ANY;
+
+ return receive_message(imc_id, connection_id, 0, chunk_create(msg, msg_len),
+ msg_vid, msg_subtype, 0, TNC_IMCID_ANY);
+}
+
+/**
+ * see section 3.8.6 of TCG TNC IF-IMV Specification 1.3
+ */
+TNC_Result 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)
+{
+ return receive_message(imc_id, connection_id, msg_flags,
+ chunk_create(msg, msg_len), msg_vid, msg_subtype,
+ src_imv_id, dst_imc_id);
+}
+
+/**
+ * see section 3.8.7 of TCG TNC IF-IMC Specification 1.3
+ */
+TNC_Result TNC_IMC_BatchEnding(TNC_IMCID imc_id,
+ TNC_ConnectionID connection_id)
+{
+ if (!imc_attestation)
+ {
+ 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_Terminate(TNC_IMCID imc_id)
+{
+ if (!imc_attestation)
+ {
+ DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
+ return TNC_RESULT_NOT_INITIALIZED;
+ }
+
+ libpts_deinit();
+
+ imc_attestation->destroy(imc_attestation);
+ imc_attestation = NULL;
+
+ return TNC_RESULT_SUCCESS;
+}
+
+/**
+ * see section 4.2.8.1 of TCG TNC IF-IMC Specification 1.3
+ */
+TNC_Result TNC_IMC_ProvideBindFunction(TNC_IMCID imc_id,
+ TNC_TNCC_BindFunctionPointer bind_function)
+{
+ if (!imc_attestation)
+ {
+ DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
+ return TNC_RESULT_NOT_INITIALIZED;
+ }
+ return imc_attestation->bind_functions(imc_attestation, bind_function);
+}
diff --git a/src/libpts/plugins/imc_attestation/imc_attestation_process.c b/src/libpts/plugins/imc_attestation/imc_attestation_process.c
new file mode 100644
index 000000000..b70c05370
--- /dev/null
+++ b/src/libpts/plugins/imc_attestation/imc_attestation_process.c
@@ -0,0 +1,466 @@
+/*
+ * Copyright (C) 2011 Sansar Choinyambuu
+ * 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>
+/* for isdigit */
+#include <ctype.h>
+
+#include "imc_attestation_process.h"
+
+#include <ietf/ietf_attr_pa_tnc_error.h>
+
+#include <libpts.h>
+#include <pts/pts.h>
+
+#include <tcg/tcg_pts_attr_proto_caps.h>
+#include <tcg/tcg_pts_attr_meas_algo.h>
+#include <tcg/tcg_pts_attr_dh_nonce_params_req.h>
+#include <tcg/tcg_pts_attr_dh_nonce_params_resp.h>
+#include <tcg/tcg_pts_attr_dh_nonce_finish.h>
+#include <tcg/tcg_pts_attr_get_tpm_version_info.h>
+#include <tcg/tcg_pts_attr_tpm_version_info.h>
+#include <tcg/tcg_pts_attr_get_aik.h>
+#include <tcg/tcg_pts_attr_aik.h>
+#include <tcg/tcg_pts_attr_req_func_comp_evid.h>
+#include <tcg/tcg_pts_attr_gen_attest_evid.h>
+#include <tcg/tcg_pts_attr_simple_comp_evid.h>
+#include <tcg/tcg_pts_attr_simple_evid_final.h>
+#include <tcg/tcg_pts_attr_req_file_meas.h>
+#include <tcg/tcg_pts_attr_file_meas.h>
+#include <tcg/tcg_pts_attr_req_file_meta.h>
+#include <tcg/tcg_pts_attr_unix_file_meta.h>
+
+#include <debug.h>
+#include <utils/lexparser.h>
+
+#define DEFAULT_NONCE_LEN 20
+
+bool imc_attestation_process(pa_tnc_attr_t *attr, linked_list_t *attr_list,
+ imc_attestation_state_t *attestation_state,
+ pts_meas_algorithms_t supported_algorithms,
+ pts_dh_group_t supported_dh_groups)
+{
+ chunk_t attr_info;
+ pts_t *pts;
+ pts_error_code_t pts_error;
+ bool valid_path;
+
+ pts = attestation_state->get_pts(attestation_state);
+ switch (attr->get_type(attr))
+ {
+ case TCG_PTS_REQ_PROTO_CAPS:
+ {
+ tcg_pts_attr_proto_caps_t *attr_cast;
+ pts_proto_caps_flag_t imc_caps, imv_caps;
+
+ attr_cast = (tcg_pts_attr_proto_caps_t*)attr;
+ imv_caps = attr_cast->get_flags(attr_cast);
+ imc_caps = pts->get_proto_caps(pts);
+ pts->set_proto_caps(pts, imc_caps & imv_caps);
+
+ /* Send PTS Protocol Capabilities attribute */
+ attr = tcg_pts_attr_proto_caps_create(imc_caps & imv_caps, FALSE);
+ attr_list->insert_last(attr_list, attr);
+ break;
+ }
+ case TCG_PTS_MEAS_ALGO:
+ {
+ tcg_pts_attr_meas_algo_t *attr_cast;
+ pts_meas_algorithms_t offered_algorithms, selected_algorithm;
+
+ attr_cast = (tcg_pts_attr_meas_algo_t*)attr;
+ offered_algorithms = attr_cast->get_algorithms(attr_cast);
+ selected_algorithm = pts_meas_algo_select(supported_algorithms,
+ offered_algorithms);
+ if (selected_algorithm == PTS_MEAS_ALGO_NONE)
+ {
+ attr = pts_hash_alg_error_create(supported_algorithms);
+ attr_list->insert_last(attr_list, attr);
+ break;
+ }
+
+ /* Send Measurement Algorithm Selection attribute */
+ pts->set_meas_algorithm(pts, selected_algorithm);
+ attr = tcg_pts_attr_meas_algo_create(selected_algorithm, TRUE);
+ attr_list->insert_last(attr_list, attr);
+ break;
+ }
+ case TCG_PTS_DH_NONCE_PARAMS_REQ:
+ {
+ tcg_pts_attr_dh_nonce_params_req_t *attr_cast;
+ pts_dh_group_t offered_dh_groups, selected_dh_group;
+ chunk_t responder_value, responder_nonce;
+ int nonce_len, min_nonce_len;
+
+ nonce_len = lib->settings->get_int(lib->settings,
+ "libimcv.plugins.imc-attestation.nonce_len",
+ DEFAULT_NONCE_LEN);
+
+ attr_cast = (tcg_pts_attr_dh_nonce_params_req_t*)attr;
+ min_nonce_len = attr_cast->get_min_nonce_len(attr_cast);
+ if (nonce_len < PTS_MIN_NONCE_LEN ||
+ (min_nonce_len > 0 && nonce_len < min_nonce_len))
+ {
+ attr = pts_dh_nonce_error_create(nonce_len, PTS_MAX_NONCE_LEN);
+ attr_list->insert_last(attr_list, attr);
+ break;
+ }
+
+ offered_dh_groups = attr_cast->get_dh_groups(attr_cast);
+ selected_dh_group = pts_dh_group_select(supported_dh_groups,
+ offered_dh_groups);
+ if (selected_dh_group == PTS_DH_GROUP_NONE)
+ {
+ attr = pts_dh_group_error_create(supported_dh_groups);
+ attr_list->insert_last(attr_list, attr);
+ break;
+ }
+
+ /* Create own DH factor and nonce */
+ if (!pts->create_dh_nonce(pts, selected_dh_group, nonce_len))
+ {
+ return FALSE;
+ }
+ pts->get_my_public_value(pts, &responder_value, &responder_nonce);
+
+ /* Send DH Nonce Parameters Response attribute */
+ attr = tcg_pts_attr_dh_nonce_params_resp_create(selected_dh_group,
+ supported_algorithms, responder_nonce, responder_value);
+ attr_list->insert_last(attr_list, attr);
+ break;
+ }
+ case TCG_PTS_DH_NONCE_FINISH:
+ {
+ tcg_pts_attr_dh_nonce_finish_t *attr_cast;
+ pts_meas_algorithms_t selected_algorithm;
+ chunk_t initiator_nonce, initiator_value;
+ int nonce_len;
+
+ attr_cast = (tcg_pts_attr_dh_nonce_finish_t*)attr;
+ selected_algorithm = attr_cast->get_hash_algo(attr_cast);
+ if (!(selected_algorithm & supported_algorithms))
+ {
+ DBG1(DBG_IMC, "PTS-IMV selected unsupported DH hash algorithm");
+ return FALSE;
+ }
+ pts->set_dh_hash_algorithm(pts, selected_algorithm);
+
+ initiator_value = attr_cast->get_initiator_value(attr_cast);
+ initiator_nonce = attr_cast->get_initiator_nonce(attr_cast);
+
+ nonce_len = lib->settings->get_int(lib->settings,
+ "libimcv.plugins.imc-attestation.nonce_len",
+ DEFAULT_NONCE_LEN);
+ if (nonce_len != initiator_nonce.len)
+ {
+ DBG1(DBG_IMC, "initiator and responder DH nonces "
+ "have differing lengths");
+ return FALSE;
+ }
+
+ pts->set_peer_public_value(pts, initiator_value, initiator_nonce);
+ if (!pts->calculate_secret(pts))
+ {
+ return FALSE;
+ }
+ break;
+ }
+ case TCG_PTS_GET_TPM_VERSION_INFO:
+ {
+ chunk_t tpm_version_info, attr_info;
+
+ if (!pts->get_tpm_version_info(pts, &tpm_version_info))
+ {
+ attr_info = attr->get_value(attr);
+ attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
+ TCG_PTS_TPM_VERS_NOT_SUPPORTED, attr_info);
+ attr_list->insert_last(attr_list, attr);
+ break;
+ }
+
+ /* Send TPM Version Info attribute */
+ attr = tcg_pts_attr_tpm_version_info_create(tpm_version_info);
+ attr_list->insert_last(attr_list, attr);
+ break;
+ }
+ case TCG_PTS_GET_AIK:
+ {
+ certificate_t *aik;
+
+ aik = pts->get_aik(pts);
+ if (!aik)
+ {
+ DBG1(DBG_IMC, "no AIK certificate or public key available");
+ break;
+ }
+
+ /* Send AIK attribute */
+ attr = tcg_pts_attr_aik_create(aik);
+ attr_list->insert_last(attr_list, attr);
+ break;
+ }
+ case TCG_PTS_REQ_FILE_MEAS:
+ {
+ tcg_pts_attr_req_file_meas_t *attr_cast;
+ char *pathname;
+ u_int16_t request_id;
+ bool is_directory;
+ u_int32_t delimiter;
+ pts_file_meas_t *measurements;
+
+ attr_info = attr->get_value(attr);
+ attr_cast = (tcg_pts_attr_req_file_meas_t*)attr;
+ is_directory = attr_cast->get_directory_flag(attr_cast);
+ request_id = attr_cast->get_request_id(attr_cast);
+ delimiter = attr_cast->get_delimiter(attr_cast);
+ pathname = attr_cast->get_pathname(attr_cast);
+ valid_path = pts->is_path_valid(pts, pathname, &pts_error);
+
+ if (valid_path && pts_error)
+ {
+ attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
+ pts_error, attr_info);
+ attr_list->insert_last(attr_list, attr);
+ break;
+ }
+ else if (!valid_path)
+ {
+ break;
+ }
+
+ if (delimiter != SOLIDUS_UTF && delimiter != REVERSE_SOLIDUS_UTF)
+ {
+ attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
+ TCG_PTS_INVALID_DELIMITER, attr_info);
+ attr_list->insert_last(attr_list, attr);
+ break;
+ }
+
+ /* Do PTS File Measurements and send them to PTS-IMV */
+ DBG2(DBG_IMC, "measurement request %d for %s '%s'",
+ request_id, is_directory ? "directory" : "file",
+ pathname);
+ measurements = pts->do_measurements(pts, request_id,
+ pathname, is_directory);
+ if (!measurements)
+ {
+ /* TODO handle error codes from measurements */
+ return FALSE;
+ }
+ attr = tcg_pts_attr_file_meas_create(measurements);
+ attr->set_noskip_flag(attr, TRUE);
+ attr_list->insert_last(attr_list, attr);
+ break;
+ }
+ case TCG_PTS_REQ_FILE_META:
+ {
+ tcg_pts_attr_req_file_meta_t *attr_cast;
+ char *pathname;
+ bool is_directory;
+ u_int8_t delimiter;
+ pts_file_meta_t *metadata;
+
+ attr_info = attr->get_value(attr);
+ attr_cast = (tcg_pts_attr_req_file_meta_t*)attr;
+ is_directory = attr_cast->get_directory_flag(attr_cast);
+ delimiter = attr_cast->get_delimiter(attr_cast);
+ pathname = attr_cast->get_pathname(attr_cast);
+
+ valid_path = pts->is_path_valid(pts, pathname, &pts_error);
+ if (valid_path && pts_error)
+ {
+ attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
+ pts_error, attr_info);
+ attr_list->insert_last(attr_list, attr);
+ break;
+ }
+ else if (!valid_path)
+ {
+ break;
+ }
+ if (delimiter != SOLIDUS_UTF && delimiter != REVERSE_SOLIDUS_UTF)
+ {
+ attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
+ TCG_PTS_INVALID_DELIMITER, attr_info);
+ attr_list->insert_last(attr_list, attr);
+ break;
+ }
+ /* Get File Metadata and send them to PTS-IMV */
+ DBG2(DBG_IMC, "metadata request for %s '%s'",
+ is_directory ? "directory" : "file",
+ pathname);
+ metadata = pts->get_metadata(pts, pathname, is_directory);
+
+ if (!metadata)
+ {
+ /* TODO handle error codes from measurements */
+ return FALSE;
+ }
+ attr = tcg_pts_attr_unix_file_meta_create(metadata);
+ attr->set_noskip_flag(attr, TRUE);
+ attr_list->insert_last(attr_list, attr);
+
+ break;
+ }
+ case TCG_PTS_REQ_FUNC_COMP_EVID:
+ {
+ tcg_pts_attr_req_func_comp_evid_t *attr_cast;
+ pts_proto_caps_flag_t negotiated_caps;
+ pts_comp_func_name_t *name;
+ pts_comp_evidence_t *evid;
+ pts_component_t *comp;
+ u_int32_t depth;
+ u_int8_t flags;
+ status_t status;
+ enumerator_t *e;
+
+ attr_info = attr->get_value(attr);
+ attr_cast = (tcg_pts_attr_req_func_comp_evid_t*)attr;
+
+ DBG1(DBG_IMC, "evidence requested for %d functional components",
+ attr_cast->get_count(attr_cast));
+
+ e = attr_cast->create_enumerator(attr_cast);
+ while (e->enumerate(e, &flags, &depth, &name))
+ {
+ name->log(name, "* ");
+ negotiated_caps = pts->get_proto_caps(pts);
+
+ if (flags & PTS_REQ_FUNC_COMP_EVID_TTC)
+ {
+ attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
+ TCG_PTS_UNABLE_DET_TTC, attr_info);
+ attr_list->insert_last(attr_list, attr);
+ break;
+ }
+ if (flags & PTS_REQ_FUNC_COMP_EVID_VER &&
+ !(negotiated_caps & PTS_PROTO_CAPS_V))
+ {
+ attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
+ TCG_PTS_UNABLE_LOCAL_VAL, attr_info);
+ attr_list->insert_last(attr_list, attr);
+ break;
+ }
+ if (flags & PTS_REQ_FUNC_COMP_EVID_CURR &&
+ !(negotiated_caps & PTS_PROTO_CAPS_C))
+ {
+ attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
+ TCG_PTS_UNABLE_CUR_EVID, attr_info);
+ attr_list->insert_last(attr_list, attr);
+ break;
+ }
+ if (flags & PTS_REQ_FUNC_COMP_EVID_PCR &&
+ !(negotiated_caps & PTS_PROTO_CAPS_T))
+ {
+ attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
+ TCG_PTS_UNABLE_DET_PCR, attr_info);
+ attr_list->insert_last(attr_list, attr);
+ break;
+ }
+ if (depth > 0)
+ {
+ DBG1(DBG_IMC, "the Attestation IMC currently does not "
+ "support sub component measurements");
+ return FALSE;
+ }
+ comp = pts_components->create(pts_components, name, depth, NULL);
+ if (!comp)
+ {
+ DBG2(DBG_IMC, " not registered: no evidence provided");
+ continue;
+ }
+
+ /* do the component evidence measurement[s] */
+ do
+ {
+ status = comp->measure(comp, pts, &evid);
+ if (status == FAILED)
+ {
+ break;
+ }
+ attestation_state->add_evidence(attestation_state, evid);
+ }
+ while (status == NEED_MORE);
+ comp->destroy(comp);
+ }
+ e->destroy(e);
+ break;
+ }
+ case TCG_PTS_GEN_ATTEST_EVID:
+ {
+ pts_simple_evid_final_flag_t flags;
+ pts_meas_algorithms_t comp_hash_algorithm;
+ pts_comp_evidence_t *evid;
+ chunk_t pcr_composite, quote_sig;
+ bool use_quote2;
+
+ /* Send buffered Simple Component Evidences */
+ while (attestation_state->next_evidence(attestation_state, &evid))
+ {
+ pts->select_pcr(pts, evid->get_extended_pcr(evid));
+
+ /* Send Simple Component Evidence */
+ attr = tcg_pts_attr_simple_comp_evid_create(evid);
+ attr_list->insert_last(attr_list, attr);
+ }
+
+ use_quote2 = lib->settings->get_bool(lib->settings,
+ "libimcv.plugins.imc-attestation.use_quote2", TRUE);
+ if (!pts->quote_tpm(pts, use_quote2, &pcr_composite, &quote_sig))
+ {
+ DBG1(DBG_IMC, "error occurred during TPM quote operation");
+ return FALSE;
+ }
+
+ /* Send Simple Evidence Final attribute */
+ flags = use_quote2 ? PTS_SIMPLE_EVID_FINAL_QUOTE_INFO2 :
+ PTS_SIMPLE_EVID_FINAL_QUOTE_INFO;
+ comp_hash_algorithm = PTS_MEAS_ALGO_SHA1;
+
+ attr = tcg_pts_attr_simple_evid_final_create(flags,
+ comp_hash_algorithm, pcr_composite, quote_sig);
+ attr_list->insert_last(attr_list, attr);
+ break;
+ }
+ /* TODO: Not implemented yet */
+ case TCG_PTS_REQ_INTEG_MEAS_LOG:
+ /* Attributes using XML */
+ case TCG_PTS_REQ_TEMPL_REF_MANI_SET_META:
+ case TCG_PTS_UPDATE_TEMPL_REF_MANI:
+ /* On Windows only*/
+ case TCG_PTS_REQ_REGISTRY_VALUE:
+ /* Received on IMV side only*/
+ case TCG_PTS_PROTO_CAPS:
+ case TCG_PTS_DH_NONCE_PARAMS_RESP:
+ case TCG_PTS_MEAS_ALGO_SELECTION:
+ case TCG_PTS_TPM_VERSION_INFO:
+ case TCG_PTS_TEMPL_REF_MANI_SET_META:
+ case TCG_PTS_AIK:
+ case TCG_PTS_SIMPLE_COMP_EVID:
+ case TCG_PTS_SIMPLE_EVID_FINAL:
+ case TCG_PTS_VERIFICATION_RESULT:
+ case TCG_PTS_INTEG_REPORT:
+ case TCG_PTS_UNIX_FILE_META:
+ case TCG_PTS_FILE_MEAS:
+ case TCG_PTS_INTEG_MEAS_LOG:
+ default:
+ DBG1(DBG_IMC, "received unsupported attribute '%N'",
+ tcg_attr_names, attr->get_type(attr));
+ break;
+ }
+ return TRUE;
+}
diff --git a/src/libpts/plugins/imc_attestation/imc_attestation_process.h b/src/libpts/plugins/imc_attestation/imc_attestation_process.h
new file mode 100644
index 000000000..b6dca1f56
--- /dev/null
+++ b/src/libpts/plugins/imc_attestation/imc_attestation_process.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2011 Sansar Choinyambuu
+ * 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_attestation_process_t imc_attestation_process
+ * @{ @ingroup imc_attestation_process
+ */
+
+#ifndef IMC_ATTESTATION_PROCESS_H_
+#define IMC_ATTESTATION_PROCESS_H_
+
+#include "imc_attestation_state.h"
+
+#include <library.h>
+
+#include <pa_tnc/pa_tnc_attr.h>
+
+#include <pts/pts_dh_group.h>
+#include <pts/pts_meas_algo.h>
+
+/**
+ * Process a TCG PTS attribute
+ *
+ * @param attr PA-TNC attribute to be processed
+ * @param attr_list list with PA-TNC error attributes
+ * @param attestation_state attestation state of a given connection
+ * @param supported_algorithms supported PTS measurement algorithms
+ * @param supported_dh_groups supported DH groups
+ * @return TRUE if successful
+ */
+bool imc_attestation_process(pa_tnc_attr_t *attr, linked_list_t *attr_list,
+ imc_attestation_state_t *attestation_state,
+ pts_meas_algorithms_t supported_algorithms,
+ pts_dh_group_t supported_dh_groups);
+
+#endif /** IMC_ATTESTATION_PROCESS_H_ @}*/
diff --git a/src/libimcv/plugins/imc_attestation/imc_attestation_state.c b/src/libpts/plugins/imc_attestation/imc_attestation_state.c
index 9087b711c..72a55f60e 100644
--- a/src/libimcv/plugins/imc_attestation/imc_attestation_state.c
+++ b/src/libpts/plugins/imc_attestation/imc_attestation_state.c
@@ -15,6 +15,7 @@
#include "imc_attestation_state.h"
+#include <utils/linked_list.h>
#include <debug.h>
typedef struct private_imc_attestation_state_t private_imc_attestation_state_t;
@@ -40,10 +41,25 @@ struct private_imc_attestation_state_t {
TNC_ConnectionState state;
/**
+ * Does the TNCCS connection support long message types?
+ */
+ bool has_long;
+
+ /**
+ * Does the TNCCS connection support exclusive delivery?
+ */
+ bool has_excl;
+
+ /**
* PTS object
*/
pts_t *pts;
+ /**
+ * PTS Component Evidence list
+ */
+ linked_list_t *list;
+
};
METHOD(imc_state_t, get_connection_id, TNC_ConnectionID,
@@ -52,16 +68,37 @@ METHOD(imc_state_t, get_connection_id, TNC_ConnectionID,
return this->connection_id;
}
+METHOD(imc_state_t, has_long, bool,
+ private_imc_attestation_state_t *this)
+{
+ return this->has_long;
+}
+
+METHOD(imc_state_t, has_excl, bool,
+ private_imc_attestation_state_t *this)
+{
+ return this->has_excl;
+}
+
+METHOD(imc_state_t, set_flags, void,
+ private_imc_attestation_state_t *this, bool has_long, bool has_excl)
+{
+ this->has_long = has_long;
+ this->has_excl = has_excl;
+}
+
METHOD(imc_state_t, change_state, void,
private_imc_attestation_state_t *this, TNC_ConnectionState new_state)
{
this->state = new_state;
}
+
METHOD(imc_state_t, destroy, void,
private_imc_attestation_state_t *this)
{
this->pts->destroy(this->pts);
+ this->list->destroy_offset(this->list, offsetof(pts_comp_evidence_t, destroy));
free(this);
}
@@ -71,6 +108,18 @@ METHOD(imc_attestation_state_t, get_pts, pts_t*,
return this->pts;
}
+METHOD(imc_attestation_state_t, add_evidence, void,
+ private_imc_attestation_state_t *this, pts_comp_evidence_t *evidence)
+{
+ this->list->insert_last(this->list, evidence);
+}
+
+METHOD(imc_attestation_state_t, next_evidence, bool,
+ private_imc_attestation_state_t *this, pts_comp_evidence_t **evid)
+{
+ return this->list->remove_first(this->list, (void**)evid) == SUCCESS;
+}
+
/**
* Described in header.
*/
@@ -83,14 +132,20 @@ imc_state_t *imc_attestation_state_create(TNC_ConnectionID connection_id)
.public = {
.interface = {
.get_connection_id = _get_connection_id,
+ .has_long = _has_long,
+ .has_excl = _has_excl,
+ .set_flags = _set_flags,
.change_state = _change_state,
.destroy = _destroy,
},
.get_pts = _get_pts,
+ .add_evidence = _add_evidence,
+ .next_evidence = _next_evidence,
},
.connection_id = connection_id,
.state = TNC_CONNECTION_STATE_CREATE,
.pts = pts_create(TRUE),
+ .list = linked_list_create(),
);
platform_info = lib->settings->get_str(lib->settings,
diff --git a/src/libimcv/plugins/imc_attestation/imc_attestation_state.h b/src/libpts/plugins/imc_attestation/imc_attestation_state.h
index d083f3b57..22b0bba23 100644
--- a/src/libimcv/plugins/imc_attestation/imc_attestation_state.h
+++ b/src/libpts/plugins/imc_attestation/imc_attestation_state.h
@@ -24,6 +24,7 @@
#include <imc/imc_state.h>
#include <pts/pts.h>
+#include <pts/components/pts_comp_evidence.h>
#include <library.h>
typedef struct imc_attestation_state_t imc_attestation_state_t;
@@ -45,6 +46,21 @@ struct imc_attestation_state_t {
*/
pts_t* (*get_pts)(imc_attestation_state_t *this);
+ /**
+ * Add an entry to the Component Evidence list
+ *
+ * @param entry Component Evidence entry
+ */
+ void (*add_evidence)(imc_attestation_state_t *this, pts_comp_evidence_t *entry);
+
+ /**
+ * Removes next Component Evidence entry from list and returns it
+ *
+ * @param evid Next Component Evidence entry
+ * @return TRUE if next entry is available
+ */
+ bool (*next_evidence)(imc_attestation_state_t *this, pts_comp_evidence_t** evid);
+
};
/**
diff --git a/src/libpts/plugins/imv_attestation/.gitignore b/src/libpts/plugins/imv_attestation/.gitignore
new file mode 100644
index 000000000..79548ebac
--- /dev/null
+++ b/src/libpts/plugins/imv_attestation/.gitignore
@@ -0,0 +1 @@
+attest
diff --git a/src/libpts/plugins/imv_attestation/Makefile.am b/src/libpts/plugins/imv_attestation/Makefile.am
new file mode 100644
index 000000000..a550a3552
--- /dev/null
+++ b/src/libpts/plugins/imv_attestation/Makefile.am
@@ -0,0 +1,33 @@
+
+INCLUDES = \
+ -I$(top_srcdir)/src/libstrongswan \
+ -I$(top_srcdir)/src/libtncif \
+ -I$(top_srcdir)/src/libimcv \
+ -I$(top_srcdir)/src/libpts
+
+AM_CFLAGS = -rdynamic -DPLUGINS=\""${attest_plugins}\""
+
+imcv_LTLIBRARIES = imv-attestation.la
+
+imv_attestation_la_LIBADD = \
+ $(top_builddir)/src/libimcv/libimcv.la \
+ $(top_builddir)/src/libstrongswan/libstrongswan.la \
+ $(top_builddir)/src/libpts/libpts.la
+
+imv_attestation_la_SOURCES = imv_attestation.c \
+ imv_attestation_state.h imv_attestation_state.c \
+ imv_attestation_process.h imv_attestation_process.c \
+ imv_attestation_build.h imv_attestation_build.c
+
+imv_attestation_la_LDFLAGS = -module -avoid-version
+
+ipsec_PROGRAMS = attest
+attest_SOURCES = attest.c \
+ attest_usage.h attest_usage.c \
+ attest_db.h attest_db.c \
+ tables.sql data.sql
+attest_LDADD = \
+ $(top_builddir)/src/libimcv/libimcv.la \
+ $(top_builddir)/src/libpts/libpts.la \
+ $(top_builddir)/src/libstrongswan/libstrongswan.la
+attest.o : $(top_builddir)/config.status
diff --git a/src/libpts/plugins/imv_attestation/attest.c b/src/libpts/plugins/imv_attestation/attest.c
new file mode 100644
index 000000000..9200820e8
--- /dev/null
+++ b/src/libpts/plugins/imv_attestation/attest.c
@@ -0,0 +1,373 @@
+/*
+ * Copyright (C) 2011 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 <getopt.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <syslog.h>
+
+#include <library.h>
+#include <debug.h>
+
+#include <imcv.h>
+#include <libpts.h>
+#include <pts/pts_meas_algo.h>
+
+#include "attest_db.h"
+#include "attest_usage.h"
+
+/**
+ * global debug output variables
+ */
+static int debug_level = 2;
+static bool stderr_quiet = TRUE;
+
+/**
+ * attest dbg function
+ */
+static void attest_dbg(debug_t group, level_t level, char *fmt, ...)
+{
+ int priority = LOG_INFO;
+ char buffer[8192];
+ char *current = buffer, *next;
+ va_list args;
+
+ if (level <= debug_level)
+ {
+ if (!stderr_quiet)
+ {
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ fprintf(stderr, "\n");
+ va_end(args);
+ }
+
+ /* write in memory buffer first */
+ va_start(args, fmt);
+ vsnprintf(buffer, sizeof(buffer), fmt, args);
+ va_end(args);
+
+ /* do a syslog with every line */
+ while (current)
+ {
+ next = strchr(current, '\n');
+ if (next)
+ {
+ *(next++) = '\0';
+ }
+ syslog(priority, "%s\n", current);
+ current = next;
+ }
+ }
+}
+
+/**
+ * global attestation database object
+ */
+attest_db_t *attest;
+
+/**
+ * atexit handler to close db on shutdown
+ */
+static void cleanup(void)
+{
+ attest->destroy(attest);
+ libpts_deinit();
+ libimcv_deinit();
+ closelog();
+}
+
+static void do_args(int argc, char *argv[])
+{
+ enum {
+ OP_UNDEF,
+ OP_USAGE,
+ OP_KEYS,
+ OP_COMPONENTS,
+ OP_FILES,
+ OP_HASHES,
+ OP_MEASUREMENTS,
+ OP_PRODUCTS,
+ OP_ADD,
+ OP_DEL,
+ } op = OP_UNDEF;
+
+ /* reinit getopt state */
+ optind = 0;
+
+ while (TRUE)
+ {
+ int c;
+
+ struct option long_opts[] = {
+ { "help", no_argument, NULL, 'h' },
+ { "components", no_argument, NULL, 'c' },
+ { "files", no_argument, NULL, 'f' },
+ { "keys", no_argument, NULL, 'k' },
+ { "products", no_argument, NULL, 'p' },
+ { "hashes", no_argument, NULL, 'H' },
+ { "measurements", no_argument, NULL, 'm' },
+ { "add", no_argument, NULL, 'a' },
+ { "delete", no_argument, NULL, 'd' },
+ { "del", no_argument, NULL, 'd' },
+ { "aik", required_argument, NULL, 'A' },
+ { "component", required_argument, NULL, 'C' },
+ { "comp", required_argument, NULL, 'C' },
+ { "directory", required_argument, NULL, 'D' },
+ { "dir", required_argument, NULL, 'D' },
+ { "file", required_argument, NULL, 'F' },
+ { "key", required_argument, NULL, 'K' },
+ { "owner", required_argument, NULL, 'O' },
+ { "product", required_argument, NULL, 'P' },
+ { "sha1", no_argument, NULL, '1' },
+ { "sha256", no_argument, NULL, '2' },
+ { "sha384", no_argument, NULL, '3' },
+ { "did", required_argument, NULL, '4' },
+ { "fid", required_argument, NULL, '5' },
+ { "pid", required_argument, NULL, '6' },
+ { "cid", required_argument, NULL, '7' },
+ { "kid", required_argument, NULL, '8' },
+ { 0,0,0,0 }
+ };
+
+ c = getopt_long(argc, argv, "", long_opts, NULL);
+ switch (c)
+ {
+ case EOF:
+ break;
+ case 'h':
+ op = OP_USAGE;
+ break;
+ case 'c':
+ op = OP_COMPONENTS;
+ continue;
+ case 'f':
+ op = OP_FILES;
+ continue;
+ case 'k':
+ op = OP_KEYS;
+ continue;
+ case 'p':
+ op = OP_PRODUCTS;
+ continue;
+ case 'H':
+ op = OP_HASHES;
+ continue;
+ case 'm':
+ op = OP_MEASUREMENTS;
+ continue;
+ case 'a':
+ op = OP_ADD;
+ continue;
+ case 'd':
+ op = OP_DEL;
+ continue;
+ case 'A':
+ {
+ certificate_t *aik_cert;
+ public_key_t *aik_key;
+ chunk_t aik;
+
+ aik_cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
+ CERT_X509, BUILD_FROM_FILE, optarg, BUILD_END);
+ if (!aik_cert)
+ {
+ printf("AIK certificate '%s' could not be loaded\n", optarg);
+ exit(EXIT_FAILURE);
+ }
+ aik_key = aik_cert->get_public_key(aik_cert);
+ aik_cert->destroy(aik_cert);
+
+ if (!aik_key)
+ {
+ printf("AIK public key could not be retrieved\n");
+ exit(EXIT_FAILURE);
+ }
+ if (!aik_key->get_fingerprint(aik_key, KEYID_PUBKEY_INFO_SHA1,
+ &aik))
+ {
+ printf("AIK fingerprint could not be computed\n");
+ aik_key->destroy(aik_key);
+ exit(EXIT_FAILURE);
+ }
+ aik = chunk_clone(aik);
+ aik_key->destroy(aik_key);
+
+ if (!attest->set_key(attest, aik, op == OP_ADD))
+ {
+ exit(EXIT_FAILURE);
+ }
+ continue;
+ }
+ case 'C':
+ if (!attest->set_component(attest, optarg, op == OP_ADD))
+ {
+ exit(EXIT_FAILURE);
+ }
+ continue;
+ case 'D':
+ if (!attest->set_directory(attest, optarg, op == OP_ADD))
+ {
+ exit(EXIT_FAILURE);
+ }
+ continue;
+ case 'F':
+ if (!attest->set_file(attest, optarg, op == OP_ADD))
+ {
+ exit(EXIT_FAILURE);
+ }
+ continue;
+ case 'K':
+ {
+ chunk_t aik;
+
+ aik = chunk_from_hex(chunk_create(optarg, strlen(optarg)), NULL);
+ if (!attest->set_key(attest, aik, op == OP_ADD))
+ {
+ exit(EXIT_FAILURE);
+ }
+ continue;
+ }
+ case 'O':
+ attest->set_owner(attest, optarg);
+ continue;
+ case 'P':
+ if (!attest->set_product(attest, optarg, op == OP_ADD))
+ {
+ exit(EXIT_FAILURE);
+ }
+ continue;
+ case '1':
+ attest->set_algo(attest, PTS_MEAS_ALGO_SHA1);
+ continue;
+ case '2':
+ attest->set_algo(attest, PTS_MEAS_ALGO_SHA256);
+ continue;
+ case '3':
+ attest->set_algo(attest, PTS_MEAS_ALGO_SHA384);
+ continue;
+ case '4':
+ if (!attest->set_did(attest, atoi(optarg)))
+ {
+ exit(EXIT_FAILURE);
+ }
+ continue;
+ case '5':
+ if (!attest->set_fid(attest, atoi(optarg)))
+ {
+ exit(EXIT_FAILURE);
+ }
+ continue;
+ case '6':
+ if (!attest->set_pid(attest, atoi(optarg)))
+ {
+ exit(EXIT_FAILURE);
+ }
+ continue;
+ case '7':
+ if (!attest->set_cid(attest, atoi(optarg)))
+ {
+ exit(EXIT_FAILURE);
+ }
+ continue;
+ case '8':
+ if (!attest->set_kid(attest, atoi(optarg)))
+ {
+ exit(EXIT_FAILURE);
+ }
+ continue;
+ }
+ break;
+ }
+
+ switch (op)
+ {
+ case OP_USAGE:
+ usage();
+ break;
+ case OP_PRODUCTS:
+ attest->list_products(attest);
+ break;
+ case OP_KEYS:
+ attest->list_keys(attest);
+ break;
+ case OP_COMPONENTS:
+ attest->list_components(attest);
+ break;
+ case OP_FILES:
+ attest->list_files(attest);
+ break;
+ case OP_HASHES:
+ attest->list_hashes(attest);
+ break;
+ case OP_MEASUREMENTS:
+ attest->list_measurements(attest);
+ break;
+ case OP_ADD:
+ attest->add(attest);
+ break;
+ case OP_DEL:
+ attest->delete(attest);
+ break;
+ default:
+ usage();
+ exit(EXIT_FAILURE);
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ char *uri;
+
+ /* enable attest debugging hook */
+ dbg = attest_dbg;
+ openlog("attest", 0, LOG_DEBUG);
+
+ atexit(library_deinit);
+
+ /* initialize library */
+ if (!library_init(NULL))
+ {
+ exit(SS_RC_LIBSTRONGSWAN_INTEGRITY);
+ }
+ if (!lib->plugins->load(lib->plugins, NULL,
+ lib->settings->get_str(lib->settings, "attest.load", PLUGINS)))
+ {
+ exit(SS_RC_INITIALIZATION_FAILED);
+ }
+
+ uri = lib->settings->get_str(lib->settings, "attest.database", NULL);
+ if (!uri)
+ {
+ fprintf(stderr, "database URI attest.database not set.\n");
+ exit(SS_RC_INITIALIZATION_FAILED);
+ }
+ attest = attest_db_create(uri);
+ if (!attest)
+ {
+ exit(SS_RC_INITIALIZATION_FAILED);
+ }
+ atexit(cleanup);
+ libimcv_init();
+ libpts_init();
+
+ do_args(argc, argv);
+
+ exit(EXIT_SUCCESS);
+}
+
diff --git a/src/libpts/plugins/imv_attestation/attest_db.c b/src/libpts/plugins/imv_attestation/attest_db.c
new file mode 100644
index 000000000..88d19eee1
--- /dev/null
+++ b/src/libpts/plugins/imv_attestation/attest_db.c
@@ -0,0 +1,1200 @@
+/*
+ * Copyright (C) 2011 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 "attest_db.h"
+
+#include "libpts.h"
+#include "pts/components/pts_comp_func_name.h"
+
+typedef struct private_attest_db_t private_attest_db_t;
+
+/**
+ * Private data of an attest_db_t object.
+ */
+struct private_attest_db_t {
+
+ /**
+ * Public members of attest_db_state_t
+ */
+ attest_db_t public;
+
+ /**
+ * Component Functional Name to be queried
+ */
+ pts_comp_func_name_t *cfn;
+
+ /**
+ * Primary key of the Component Functional Name to be queried
+ */
+ int cid;
+
+ /**
+ * TRUE if Component Functional Name has been set
+ */
+ bool comp_set;
+
+ /**
+ * Directory containing the Measurement file to be queried
+ */
+ char *dir;
+
+ /**
+ * Primary key of the directory to be queried
+ */
+ int did;
+
+ /**
+ * TRUE if directory has been set
+ */
+ bool dir_set;
+
+ /**
+ * Measurement file to be queried
+ */
+ char *file;
+
+ /**
+ * Primary key of measurement file to be queried
+ */
+ int fid;
+
+ /**
+ * TRUE if file has been set
+ */
+ bool file_set;
+
+ /**
+ * AIK to be queried
+ */
+ chunk_t key;
+
+ /**
+ * Primary key of the AIK to be queried
+ */
+ int kid;
+
+ /**
+ * TRUE if AIK has been set
+ */
+ bool key_set;
+
+ /**
+ * Software product to be queried
+ */
+ char *product;
+
+ /**
+ * Primary key of software product to be queried
+ */
+ int pid;
+
+ /**
+ * TRUE if product has been set
+ */
+ bool product_set;
+
+ /**
+ * File measurement hash algorithm
+ */
+ pts_meas_algorithms_t algo;
+
+ /**
+ * Optional owner (user/host name)
+ */
+ char *owner;
+
+ /**
+ * Attestation database
+ */
+ database_t *db;
+
+};
+
+char* print_cfn(pts_comp_func_name_t *cfn)
+{
+ static char buf[BUF_LEN];
+ char flags[8];
+ int type, vid, name, qualifier, n;
+ enum_name_t *names, *types;
+
+ vid = cfn->get_vendor_id(cfn),
+ name = cfn->get_name(cfn);
+ qualifier = cfn->get_qualifier(cfn);
+ n = snprintf(buf, BUF_LEN, "0x%06x/0x%08x-0x%02x", vid, name, qualifier);
+
+ names = pts_components->get_comp_func_names(pts_components, vid);
+ types = pts_components->get_qualifier_type_names(pts_components, vid);
+ type = pts_components->get_qualifier(pts_components, cfn, flags);
+ if (names && types)
+ {
+ n = snprintf(buf + n, BUF_LEN - n, " %N/%N [%s] %N",
+ pen_names, vid, names, name, flags, types, type);
+ }
+ return buf;
+}
+
+METHOD(attest_db_t, set_component, bool,
+ private_attest_db_t *this, char *comp, bool create)
+{
+ enumerator_t *e;
+ char *pos1, *pos2;
+ int vid, name, qualifier;
+ pts_comp_func_name_t *cfn;
+
+ if (this->comp_set)
+ {
+ printf("component has already been set\n");
+ return FALSE;
+ }
+
+ /* parse component string */
+ pos1 = strchr(comp, '/');
+ pos2 = strchr(comp, '-');
+ if (!pos1 || !pos2)
+ {
+ printf("component string must have the form \"vendor_id/name-qualifier\"\n");
+ return FALSE;
+ }
+ vid = atoi(comp);
+ name = atoi(pos1 + 1);
+ qualifier = atoi(pos2 + 1);
+ cfn = pts_comp_func_name_create(vid, name, qualifier);
+
+ e = this->db->query(this->db,
+ "SELECT id FROM components "
+ "WHERE vendor_id = ? AND name = ? AND qualifier = ?",
+ DB_INT, vid, DB_INT, name, DB_INT, qualifier, DB_INT);
+ if (e)
+ {
+ if (e->enumerate(e, &this->cid))
+ {
+ this->comp_set = TRUE;
+ this->cfn = cfn;
+ }
+ e->destroy(e);
+ }
+ if (this->comp_set)
+ {
+ return TRUE;
+ }
+
+ if (!create)
+ {
+ printf("component '%s' not found in database\n", print_cfn(cfn));
+ cfn->destroy(cfn);
+ return FALSE;
+ }
+
+ /* Add a new database entry */
+ this->comp_set = this->db->execute(this->db, &this->cid,
+ "INSERT INTO components (vendor_id, name, qualifier) "
+ "VALUES (?, ?, ?)",
+ DB_INT, vid, DB_INT, name, DB_INT, qualifier) == 1;
+
+ printf("component '%s' %sinserted into database\n", print_cfn(cfn),
+ this->comp_set ? "" : "could not be ");
+ if (this->comp_set)
+ {
+ this->cfn = cfn;
+ }
+ else
+ {
+ cfn->destroy(cfn);
+ }
+ return this->comp_set;
+}
+
+METHOD(attest_db_t, set_cid, bool,
+ private_attest_db_t *this, int cid)
+{
+ enumerator_t *e;
+ int vid, name, qualifier;
+
+ if (this->comp_set)
+ {
+ printf("component has already been set\n");
+ return FALSE;
+ }
+ this->cid = cid;
+
+ e = this->db->query(this->db, "SELECT vendor_id, name, qualifier "
+ "FROM components WHERE id = ?",
+ DB_INT, cid, DB_INT, DB_INT, DB_INT);
+ if (e)
+ {
+ if (e->enumerate(e, &vid, &name, &qualifier))
+ {
+ this->cfn = pts_comp_func_name_create(vid, name, qualifier);
+ this->comp_set = TRUE;
+ }
+ else
+ {
+ printf("no component found with cid %d\n", cid);
+ }
+ e->destroy(e);
+ }
+ return this->comp_set;
+}
+
+METHOD(attest_db_t, set_directory, bool,
+ private_attest_db_t *this, char *dir, bool create)
+{
+ enumerator_t *e;
+
+ if (this->dir_set)
+ {
+ printf("directory has already been set\n");
+ return FALSE;
+ }
+ free(this->dir);
+ this->dir = strdup(dir);
+
+ e = this->db->query(this->db,
+ "SELECT id FROM files WHERE type = 1 AND path = ?",
+ DB_TEXT, dir, DB_INT);
+ if (e)
+ {
+ if (e->enumerate(e, &this->did))
+ {
+ this->dir_set = TRUE;
+ }
+ e->destroy(e);
+ }
+ if (this->dir_set)
+ {
+ return TRUE;
+ }
+
+ if (!create)
+ {
+ printf("directory '%s' not found in database\n", dir);
+ return FALSE;
+ }
+
+ /* Add a new database entry */
+ this->dir_set = this->db->execute(this->db, &this->did,
+ "INSERT INTO files (type, path) VALUES (1, ?)",
+ DB_TEXT, dir) == 1;
+
+ printf("directory '%s' %sinserted into database\n", dir,
+ this->dir_set ? "" : "could not be ");
+
+ return this->dir_set;
+}
+
+METHOD(attest_db_t, set_did, bool,
+ private_attest_db_t *this, int did)
+{
+ enumerator_t *e;
+ char *dir;
+
+ if (this->dir_set)
+ {
+ printf("directory has already been set\n");
+ return FALSE;
+ }
+ this->did = did;
+
+ e = this->db->query(this->db, "SELECT path FROM files WHERE id = ?",
+ DB_INT, did, DB_TEXT);
+ if (e)
+ {
+ if (e->enumerate(e, &dir))
+ {
+ free(this->dir);
+ this->dir = strdup(dir);
+ this->dir_set = TRUE;
+ }
+ else
+ {
+ printf("no directory found with did %d\n", did);
+ }
+ e->destroy(e);
+ }
+ return this->dir_set;
+}
+
+METHOD(attest_db_t, set_file, bool,
+ private_attest_db_t *this, char *file, bool create)
+{
+ enumerator_t *e;
+
+ if (this->file_set)
+ {
+ printf("file has already been set\n");
+ return FALSE;
+ }
+ this->file = strdup(file);
+
+ e = this->db->query(this->db, "SELECT id FROM files WHERE path = ?",
+ DB_TEXT, file, DB_INT);
+ if (e)
+ {
+ if (e->enumerate(e, &this->fid))
+ {
+ this->file_set = TRUE;
+ }
+ e->destroy(e);
+ }
+ if (this->file_set)
+ {
+ return TRUE;
+ }
+
+ if (!create)
+ {
+ printf("file '%s' not found in database\n", file);
+ return FALSE;
+ }
+
+ /* Add a new database entry */
+ this->file_set = this->db->execute(this->db, &this->fid,
+ "INSERT INTO files (type, path) VALUES (0, ?)",
+ DB_TEXT, file) == 1;
+
+ printf("file '%s' %sinserted into database\n", file,
+ this->file_set ? "" : "could not be ");
+
+ return this->file_set;
+}
+
+METHOD(attest_db_t, set_fid, bool,
+ private_attest_db_t *this, int fid)
+{
+ enumerator_t *e;
+ char *file;
+
+ if (this->file_set)
+ {
+ printf("file has already been set\n");
+ return FALSE;
+ }
+ this->fid = fid;
+
+ e = this->db->query(this->db, "SELECT path FROM files WHERE id = ?",
+ DB_INT, fid, DB_TEXT);
+ if (e)
+ {
+ if (e->enumerate(e, &file))
+ {
+ this->file = strdup(file);
+ this->file_set = TRUE;
+ }
+ else
+ {
+ printf("no file found with fid %d\n", fid);
+ }
+ e->destroy(e);
+ }
+ return this->file_set;
+}
+
+METHOD(attest_db_t, set_key, bool,
+ private_attest_db_t *this, chunk_t key, bool create)
+{
+ enumerator_t *e;
+ char *owner;
+
+ if (this->key_set)
+ {
+ printf("key has already been set\n");
+ return FALSE;
+ }
+ this->key = key;
+
+ e = this->db->query(this->db, "SELECT id, owner FROM keys WHERE keyid= ?",
+ DB_BLOB, this->key, DB_INT, DB_TEXT);
+ if (e)
+ {
+ if (e->enumerate(e, &this->kid, &owner))
+ {
+ free(this->owner);
+ this->owner = strdup(owner);
+ this->key_set = TRUE;
+ }
+ e->destroy(e);
+ }
+ if (this->key_set)
+ {
+ return TRUE;
+ }
+
+ if (!create)
+ {
+ printf("key '%#B' not found in database\n", &this->key);
+ return FALSE;
+ }
+
+ /* Add a new database entry */
+ if (!this->owner)
+ {
+ this->owner = strdup("");
+ }
+ this->key_set = this->db->execute(this->db, &this->kid,
+ "INSERT INTO keys (keyid, owner) VALUES (?, ?)",
+ DB_BLOB, this->key, DB_TEXT, this->owner) == 1;
+
+ printf("key '%#B' %sinserted into database\n", &this->key,
+ this->key_set ? "" : "could not be ");
+
+ return this->key_set;
+
+};
+
+METHOD(attest_db_t, set_kid, bool,
+ private_attest_db_t *this, int kid)
+{
+ enumerator_t *e;
+ chunk_t key;
+ char *owner;
+
+ if (this->key_set)
+ {
+ printf("key has already been set\n");
+ return FALSE;
+ }
+ this->kid = kid;
+
+ e = this->db->query(this->db, "SELECT keyid, owner FROM keys WHERE id = ?",
+ DB_INT, kid, DB_BLOB, DB_TEXT);
+ if (e)
+ {
+ if (e->enumerate(e, &key, &owner))
+ {
+ this->owner = strdup(owner);
+ this->key = chunk_clone(key);
+ this->key_set = TRUE;
+ }
+ else
+ {
+ printf("no key found with kid %d\n", kid);
+ }
+ e->destroy(e);
+ }
+ return this->key_set;
+
+};
+
+METHOD(attest_db_t, set_product, bool,
+ private_attest_db_t *this, char *product, bool create)
+{
+ enumerator_t *e;
+
+ if (this->product_set)
+ {
+ printf("product has already been set\n");
+ return FALSE;
+ }
+ this->product = strdup(product);
+
+ e = this->db->query(this->db, "SELECT id FROM products WHERE name = ?",
+ DB_TEXT, product, DB_INT);
+ if (e)
+ {
+ if (e->enumerate(e, &this->pid))
+ {
+ this->product_set = TRUE;
+ }
+ e->destroy(e);
+ }
+ if (this->product_set)
+ {
+ return TRUE;
+ }
+
+ if (!create)
+ {
+ printf("product '%s' not found in database\n", product);
+ return FALSE;
+ }
+
+ /* Add a new database entry */
+ this->product_set = this->db->execute(this->db, &this->pid,
+ "INSERT INTO products (name) VALUES (?)",
+ DB_TEXT, product) == 1;
+
+ printf("product '%s' %sinserted into database\n", product,
+ this->product_set ? "" : "could not be ");
+
+ return this->product_set;
+}
+
+METHOD(attest_db_t, set_pid, bool,
+ private_attest_db_t *this, int pid)
+{
+ enumerator_t *e;
+ char *product;
+
+ if (this->product_set)
+ {
+ printf("product has already been set\n");
+ return FALSE;
+ }
+ this->pid = pid;
+
+ e = this->db->query(this->db, "SELECT name FROM products WHERE id = ?",
+ DB_INT, pid, DB_TEXT);
+ if (e)
+ {
+ if (e->enumerate(e, &product))
+ {
+ this->product = strdup(product);
+ this->product_set = TRUE;
+ }
+ else
+ {
+ printf("no product found with pid %d in database\n", pid);
+ }
+ e->destroy(e);
+ }
+ return this->product_set;
+}
+
+METHOD(attest_db_t, set_algo, void,
+ private_attest_db_t *this, pts_meas_algorithms_t algo)
+{
+ this->algo = algo;
+}
+
+METHOD(attest_db_t, set_owner, void,
+ private_attest_db_t *this, char *owner)
+{
+ free(this->owner);
+ this->owner = strdup(owner);
+}
+
+METHOD(attest_db_t, list_components, void,
+ private_attest_db_t *this)
+{
+ enumerator_t *e;
+ pts_comp_func_name_t *cfn;
+ int cid, vid, name, qualifier, count = 0;
+
+ if (this->kid)
+ {
+ e = this->db->query(this->db,
+ "SELECT c.id, c.vendor_id, c.name, c.qualifier "
+ "FROM components AS c "
+ "JOIN key_component AS kc ON c.id = kc.component "
+ "WHERE kc.key = ? ORDER BY c.vendor_id, c.name, c.qualifier",
+ DB_INT, this->kid, DB_INT, DB_INT, DB_INT, DB_INT);
+ }
+ else
+ {
+ e = this->db->query(this->db,
+ "SELECT id, vendor_id, name, qualifier FROM components "
+ "ORDER BY vendor_id, name, qualifier",
+ DB_INT, DB_INT, DB_INT, DB_INT);
+ }
+ if (e)
+ {
+ while (e->enumerate(e, &cid, &vid, &name, &qualifier))
+ {
+ cfn = pts_comp_func_name_create(vid, name, qualifier);
+ printf("%3d: %s\n", cid, print_cfn(cfn));
+ cfn->destroy(cfn);
+ count++;
+ }
+ e->destroy(e);
+
+ printf("%d component%s found", count, (count == 1) ? "" : "s");
+ if (this->key_set)
+ {
+ printf(" for key %#B", &this->key);
+ }
+ printf("\n");
+ }
+}
+
+METHOD(attest_db_t, list_keys, void,
+ private_attest_db_t *this)
+{
+ enumerator_t *e;
+ chunk_t keyid;
+ char *owner;
+ int kid, count = 0;
+
+ if (this->cid)
+ {
+ e = this->db->query(this->db,
+ "SELECT k.id, k.keyid, k.owner FROM keys AS k "
+ "JOIN key_component AS kc ON k.id = kc.key "
+ "WHERE kc.component = ? ORDER BY k.keyid",
+ DB_INT, this->cid, DB_INT, DB_BLOB, DB_TEXT);
+ if (e)
+ {
+ while (e->enumerate(e, &kid, &keyid, &owner))
+ {
+ printf("%3d: %#B '%s'\n", kid, &keyid, owner);
+ count++;
+ }
+ e->destroy(e);
+ }
+ }
+ else
+ {
+ e = this->db->query(this->db, "SELECT id, keyid, owner FROM keys "
+ "ORDER BY keyid",
+ DB_INT, DB_BLOB, DB_TEXT);
+ if (e)
+ {
+ while (e->enumerate(e, &kid, &keyid, &owner))
+ {
+ printf("%3d: %#B '%s'\n", kid, &keyid, owner);
+ count++;
+ }
+ e->destroy(e);
+ }
+ }
+
+ printf("%d key%s found", count, (count == 1) ? "" : "s");
+ if (this->comp_set)
+ {
+ printf(" for component '%s'", print_cfn(this->cfn));
+ }
+ printf("\n");
+}
+
+METHOD(attest_db_t, list_files, void,
+ private_attest_db_t *this)
+{
+ enumerator_t *e;
+ char *file, *file_type[] = { " ", "d", "r" };
+ int fid, type, meas, meta, count = 0;
+
+ if (this->pid)
+ {
+ e = this->db->query(this->db,
+ "SELECT f.id, f.type, f.path, pf.measurement, pf.metadata "
+ "FROM files AS f "
+ "JOIN product_file AS pf ON f.id = pf.file "
+ "WHERE pf.product = ? ORDER BY f.path",
+ DB_INT, this->pid, DB_INT, DB_INT, DB_TEXT, DB_INT, DB_INT);
+ if (e)
+ {
+ while (e->enumerate(e, &fid, &type, &file, &meas, &meta))
+ {
+ type = (type < 0 || type > 2) ? 0 : type;
+ printf("%3d: |%s%s| %s %s\n", fid, meas ? "M":" ", meta ? "T":" ",
+ file_type[type], file);
+ count++;
+ }
+ e->destroy(e);
+ }
+ }
+ else
+ {
+ e = this->db->query(this->db,
+ "SELECT id, type, path FROM files "
+ "ORDER BY path",
+ DB_INT, DB_INT, DB_TEXT);
+ if (e)
+ {
+ while (e->enumerate(e, &fid, &type, &file))
+ {
+ type = (type < 0 || type > 2) ? 0 : type;
+ printf("%3d: %s %s\n", fid, file_type[type], file);
+ count++;
+ }
+ e->destroy(e);
+ }
+ }
+
+ printf("%d file%s found", count, (count == 1) ? "" : "s");
+ if (this->product_set)
+ {
+ printf(" for product '%s'", this->product);
+ }
+ printf("\n");
+}
+
+METHOD(attest_db_t, list_products, void,
+ private_attest_db_t *this)
+{
+ enumerator_t *e;
+ char *product;
+ int pid, meas, meta, count = 0;
+
+ if (this->fid)
+ {
+ e = this->db->query(this->db,
+ "SELECT p.id, p.name, pf.measurement, pf.metadata "
+ "FROM products AS p "
+ "JOIN product_file AS pf ON p.id = pf.product "
+ "WHERE pf.file = ? ORDER BY p.name",
+ DB_INT, this->fid, DB_INT, DB_TEXT, DB_INT, DB_INT);
+ if (e)
+ {
+ while (e->enumerate(e, &pid, &product, &meas, &meta))
+ {
+ printf("%3d: |%s%s| %s\n", pid, meas ? "M":" ", meta ? "T":" ",
+ product);
+ count++;
+ }
+ e->destroy(e);
+ }
+ }
+ else
+ {
+ e = this->db->query(this->db, "SELECT id, name FROM products "
+ "ORDER BY name",
+ DB_INT, DB_TEXT);
+ if (e)
+ {
+ while (e->enumerate(e, &pid, &product))
+ {
+ printf("%3d: %s\n", pid, product);
+ count++;
+ }
+ e->destroy(e);
+ }
+ }
+
+ printf("%d product%s found", count, (count == 1) ? "" : "s");
+ if (this->file_set)
+ {
+ printf(" for file '%s'", this->file);
+ }
+ printf("\n");
+}
+
+/**
+ * get the directory if there is one from the files tables
+ */
+static void get_directory(private_attest_db_t *this, int did, char **directory)
+{
+ enumerator_t *e;
+ char *dir;
+
+ free(*directory);
+ *directory = strdup("");
+
+ if (did)
+ {
+ e = this->db->query(this->db,
+ "SELECT path from files WHERE id = ?",
+ DB_INT, did, DB_TEXT);
+ if (e)
+ {
+ if (e->enumerate(e, &dir))
+ {
+ free(*directory);
+ *directory = strdup(dir);
+ }
+ e->destroy(e);
+ }
+ }
+}
+
+static bool slash(char *directory, char *file)
+{
+ return *file != '/' && directory[max(0, strlen(directory)-1)] != '/';
+}
+
+METHOD(attest_db_t, list_hashes, void,
+ private_attest_db_t *this)
+{
+ enumerator_t *e;
+ chunk_t hash;
+ char *file, *dir, *product;
+ int fid, fid_old = 0, did, did_old = 0, count = 0;
+
+ dir = strdup("");
+
+ if (this->pid && this->fid)
+ {
+ e = this->db->query(this->db,
+ "SELECT hash FROM file_hashes "
+ "WHERE algo = ? AND file = ? AND directory = ? AND product = ?",
+ DB_INT, this->algo, DB_INT, this->fid, DB_INT, this->did,
+ DB_INT, this->pid, DB_BLOB);
+ if (e)
+ {
+ while (e->enumerate(e, &hash))
+ {
+ if (this->fid != fid_old)
+ {
+ printf("%3d: %s%s%s\n", this->fid, this->dir,
+ slash(this->dir, this->file) ? "/" : "", this->file);
+ fid_old = this->fid;
+ }
+ printf(" %#B\n", &hash);
+ count++;
+ }
+ e->destroy(e);
+
+ printf("%d %N value%s found for product '%s'\n", count,
+ hash_algorithm_names, pts_meas_algo_to_hash(this->algo),
+ (count == 1) ? "" : "s", this->product);
+ }
+ }
+ else if (this->pid)
+ {
+ e = this->db->query(this->db,
+ "SELECT f.id, f. f.path, fh.hash, fh.directory "
+ "FROM file_hashes AS fh "
+ "JOIN files AS f ON f.id = fh.file "
+ "WHERE fh.algo = ? AND fh.product = ? "
+ "ORDER BY fh.directory, f.path",
+ DB_INT, this->algo, DB_INT, this->pid,
+ DB_INT, DB_TEXT, DB_BLOB, DB_INT);
+ if (e)
+ {
+ while (e->enumerate(e, &fid, &file, &hash, &did))
+ {
+ if (fid != fid_old || did != did_old)
+ {
+ if (did != did_old)
+ {
+ get_directory(this, did, &dir);
+ }
+ printf("%3d: %s%s%s\n", fid,
+ dir, slash(dir, file) ? "/" : "", file);
+ fid_old = fid;
+ did_old = did;
+ }
+ printf(" %#B\n", &hash);
+ count++;
+ }
+ e->destroy(e);
+
+ printf("%d %N value%s found for product '%s'\n", count,
+ hash_algorithm_names, pts_meas_algo_to_hash(this->algo),
+ (count == 1) ? "" : "s", this->product);
+ }
+ }
+ else if (this->fid)
+ {
+ e = this->db->query(this->db,
+ "SELECT p.name, fh.hash, fh.directory "
+ "FROM file_hashes AS fh "
+ "JOIN products AS p ON p.id = fh.product "
+ "WHERE fh.algo = ? AND fh.file = ? AND fh.directory = ?"
+ "ORDER BY p.name",
+ DB_INT, this->algo, DB_INT, this->fid, DB_INT, this->did,
+ DB_TEXT, DB_BLOB, DB_INT);
+ if (e)
+ {
+ while (e->enumerate(e, &product, &hash, &did))
+ {
+ printf("%#B '%s'\n", &hash, product);
+ count++;
+ }
+ e->destroy(e);
+
+ printf("%d %N value%s found for file '%s%s%s'\n",
+ count, hash_algorithm_names, pts_meas_algo_to_hash(this->algo),
+ (count == 1) ? "" : "s", this->dir,
+ slash(this->dir, this->file) ? "/" : "", this->file);
+ }
+ }
+ else
+ {
+ e = this->db->query(this->db,
+ "SELECT f.id, f.path, p.name, fh.hash, fh.directory "
+ "FROM file_hashes AS fh "
+ "JOIN files AS f ON f.id = fh.file "
+ "JOIN products AS p ON p.id = fh.product "
+ "WHERE fh.algo = ? "
+ "ORDER BY fh.directory, f.path, p.name",
+ DB_INT, this->algo,
+ DB_INT, DB_TEXT, DB_TEXT, DB_BLOB, DB_INT);
+ if (e)
+ {
+ while (e->enumerate(e, &fid, &file, &product, &hash, &did))
+ {
+ if (fid != fid_old || did != did_old)
+ {
+ if (did != did_old)
+ {
+ get_directory(this, did, &dir);
+ did_old = did;
+ }
+ printf("%3d: %s%s%s\n", fid,
+ dir, slash(dir, file) ? "/" : "", file);
+ fid_old = fid;
+ }
+ printf(" %#B '%s'\n", &hash, product);
+ count++;
+ }
+ e->destroy(e);
+
+ printf("%d %N value%s found\n", count, hash_algorithm_names,
+ pts_meas_algo_to_hash(this->algo), (count == 1) ? "" : "s");
+ }
+ }
+ free(dir);
+}
+
+METHOD(attest_db_t, list_measurements, void,
+ private_attest_db_t *this)
+{
+ enumerator_t *e;
+ chunk_t hash, keyid;
+ pts_comp_func_name_t *cfn;
+ char *owner;
+ int seq_no, pcr, vid, name, qualifier;
+ int cid, cid_old = 0, kid, kid_old = 0, count = 0;
+
+ if (this->kid && this->cid)
+ {
+ e = this->db->query(this->db,
+ "SELECT ch.seq_no, ch.pcr, ch.hash, k.owner "
+ "FROM component_hashes AS ch "
+ "JOIN keys AS k ON k.id = ch.key "
+ "WHERE ch.algo = ? AND ch.key = ? AND ch.component = ? "
+ "ORDER BY seq_no",
+ DB_INT, this->algo, DB_INT, this->kid, DB_INT, this->cid,
+ DB_INT, DB_INT, DB_BLOB, DB_TEXT);
+ if (e)
+ {
+ while (e->enumerate(e, &seq_no, &pcr, &hash, &owner))
+ {
+ if (this->kid != kid_old)
+ {
+ printf("%3d: %#B '%s'\n", this->kid, &this->key, owner);
+ kid_old = this->kid;
+ }
+ printf("%5d %02d %#B\n", seq_no, pcr, &hash);
+ count++;
+ }
+ e->destroy(e);
+
+ printf("%d %N value%s found for component '%s'\n", count,
+ hash_algorithm_names, pts_meas_algo_to_hash(this->algo),
+ (count == 1) ? "" : "s", print_cfn(this->cfn));
+ }
+ }
+ else if (this->cid)
+ {
+ e = this->db->query(this->db,
+ "SELECT ch.seq_no, ch.pcr, ch.hash, k.id, k.keyid, k.owner "
+ "FROM component_hashes AS ch "
+ "JOIN keys AS k ON k.id = ch.key "
+ "WHERE ch.algo = ? AND ch.component = ? "
+ "ORDER BY keyid, seq_no",
+ DB_INT, this->algo, DB_INT, this->cid,
+ DB_INT, DB_INT, DB_BLOB, DB_INT, DB_BLOB, DB_TEXT);
+ if (e)
+ {
+ while (e->enumerate(e, &seq_no, &pcr, &hash, &kid, &keyid, &owner))
+ {
+ if (kid != kid_old)
+ {
+ printf("%3d: %#B '%s'\n", kid, &keyid, owner);
+ kid_old = kid;
+ }
+ printf("%5d %02d %#B\n", seq_no, pcr, &hash);
+ count++;
+ }
+ e->destroy(e);
+
+ printf("%d %N value%s found for component '%s'\n", count,
+ hash_algorithm_names, pts_meas_algo_to_hash(this->algo),
+ (count == 1) ? "" : "s", print_cfn(this->cfn));
+ }
+
+ }
+ else if (this->kid)
+ {
+ e = this->db->query(this->db,
+ "SELECT ch.seq_no, ch.pcr, ch.hash, "
+ "c.id, c.vendor_id, c.name, c.qualifier "
+ "FROM component_hashes AS ch "
+ "JOIN components AS c ON c.id = ch.component "
+ "WHERE ch.algo = ? AND ch.key = ? "
+ "ORDER BY vendor_id, name, qualifier, seq_no",
+ DB_INT, this->algo, DB_INT, this->kid, DB_INT, DB_INT, DB_BLOB,
+ DB_INT, DB_INT, DB_INT, DB_INT);
+ if (e)
+ {
+ while (e->enumerate(e, &seq_no, &pcr, &hash, &cid, &vid, &name,
+ &qualifier))
+ {
+ if (cid != cid_old)
+ {
+ cfn = pts_comp_func_name_create(vid, name, qualifier);
+ printf("%3d: %s\n", cid, print_cfn(cfn));
+ cfn->destroy(cfn);
+ cid_old = cid;
+ }
+ printf("%5d %02d %#B\n", seq_no, pcr, &hash);
+ count++;
+ }
+ e->destroy(e);
+
+ printf("%d %N value%s found for key %#B '%s'\n", count,
+ hash_algorithm_names, pts_meas_algo_to_hash(this->algo),
+ (count == 1) ? "" : "s", &this->key, this->owner);
+ }
+ }
+}
+
+METHOD(attest_db_t, add, bool,
+ private_attest_db_t *this)
+{
+ bool success = FALSE;
+
+ if (this->kid && this->cid)
+ {
+ success = this->db->execute(this->db, NULL,
+ "INSERT INTO key_component (key, component) VALUES (?, ?)",
+ DB_UINT, this->kid, DB_UINT, this->cid) == 1;
+
+ printf("key/component pair (%d/%d) %sinserted into database\n",
+ this->kid, this->cid, success ? "" : "could not be ");
+ }
+ return success;
+}
+
+METHOD(attest_db_t, delete, bool,
+ private_attest_db_t *this)
+{
+ bool success;
+
+ if (this->pid && (this->fid || this->did))
+ {
+ printf("deletion of product/file entries not supported yet\n");
+ return FALSE;
+ }
+
+ if (this->kid && this->cid)
+ {
+ success = this->db->execute(this->db, NULL,
+ "DELETE FROM key_component "
+ "WHERE key = ? AND component = ?",
+ DB_UINT, this->kid, DB_UINT, this->cid) > 0;
+
+ printf("key/component pair (%d/%d) %sdeleted from database\n",
+ this->kid, this->cid, success ? "" : "could not be ");
+ return success;
+ }
+
+ if (this->cid)
+ {
+ success = this->db->execute(this->db, NULL,
+ "DELETE FROM components WHERE id = ?",
+ DB_UINT, this->cid) > 0;
+
+ printf("component '%s' %sdeleted from database\n", print_cfn(this->cfn),
+ success ? "" : "could not be ");
+ return success;
+ }
+
+ if (this->did)
+ {
+ success = this->db->execute(this->db, NULL,
+ "DELETE FROM files WHERE type = 1 AND id = ?",
+ DB_UINT, this->did) > 0;
+
+ printf("directory '%s' %sdeleted from database\n", this->dir,
+ success ? "" : "could not be ");
+ return success;
+ }
+
+ if (this->fid)
+ {
+ success = this->db->execute(this->db, NULL,
+ "DELETE FROM files WHERE id = ?",
+ DB_UINT, this->fid) > 0;
+
+ printf("file '%s' %sdeleted from database\n", this->file,
+ success ? "" : "could not be ");
+ return success;
+ }
+
+ if (this->kid)
+ {
+ success = this->db->execute(this->db, NULL,
+ "DELETE FROM keys WHERE id = ?",
+ DB_UINT, this->kid) > 0;
+
+ printf("key %#B %sdeleted from database\n", &this->key,
+ success ? "" : "could not be ");
+ return success;
+ }
+ if (this->pid)
+ {
+ success = this->db->execute(this->db, NULL,
+ "DELETE FROM products WHERE id = ?",
+ DB_UINT, this->pid) > 0;
+
+ printf("product '%s' %sdeleted from database\n", this->product,
+ success ? "" : "could not be ");
+ return success;
+ }
+
+ printf("empty delete command\n");
+ return FALSE;
+}
+
+METHOD(attest_db_t, destroy, void,
+ private_attest_db_t *this)
+{
+ DESTROY_IF(this->db);
+ DESTROY_IF(this->cfn);
+ free(this->product);
+ free(this->file);
+ free(this->dir);
+ free(this->owner);
+ free(this->key.ptr);
+ free(this);
+}
+
+/**
+ * Described in header.
+ */
+attest_db_t *attest_db_create(char *uri)
+{
+ private_attest_db_t *this;
+
+ INIT(this,
+ .public = {
+ .set_component = _set_component,
+ .set_cid = _set_cid,
+ .set_directory = _set_directory,
+ .set_did = _set_did,
+ .set_file = _set_file,
+ .set_fid = _set_fid,
+ .set_key = _set_key,
+ .set_kid = _set_kid,
+ .set_product = _set_product,
+ .set_pid = _set_pid,
+ .set_algo = _set_algo,
+ .set_owner = _set_owner,
+ .list_products = _list_products,
+ .list_files = _list_files,
+ .list_components = _list_components,
+ .list_keys = _list_keys,
+ .list_hashes = _list_hashes,
+ .list_measurements = _list_measurements,
+ .add = _add,
+ .delete = _delete,
+ .destroy = _destroy,
+ },
+ .dir = strdup(""),
+ .algo = PTS_MEAS_ALGO_SHA256,
+ .db = lib->db->create(lib->db, uri),
+ );
+
+ if (!this->db)
+ {
+ fprintf(stderr, "opening database failed.\n");
+ destroy(this);
+ return NULL;
+ }
+
+ return &this->public;
+}
diff --git a/src/libpts/plugins/imv_attestation/attest_db.h b/src/libpts/plugins/imv_attestation/attest_db.h
new file mode 100644
index 000000000..9c9a9dcba
--- /dev/null
+++ b/src/libpts/plugins/imv_attestation/attest_db.h
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2011 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 attest_db_t attest_db
+ * @{ @ingroup attest_db
+ */
+
+#ifndef ATTEST_DB_H_
+#define ATTEST_DB_H_
+
+#include <pts/pts_meas_algo.h>
+
+#include <library.h>
+
+typedef struct attest_db_t attest_db_t;
+
+/**
+ * Attestation database object
+ */
+struct attest_db_t {
+
+ /**
+ * Set functional component to be queried
+ *
+ * @param comp functional component
+ * @param create if TRUE create database entry if it doesn't exist
+ * @return TRUE if successful
+ */
+ bool (*set_component)(attest_db_t *this, char *comp, bool create);
+
+ /**
+ * Set primary key of the functional component to be queried
+ *
+ * @param fid primary key of functional component
+ * @return TRUE if successful
+ */
+ bool (*set_cid)(attest_db_t *this, int fid);
+
+ /**
+ * Set directory to be queried
+ *
+ * @param dir directory
+ * @param create if TRUE create database entry if it doesn't exist
+ * @return TRUE if successful
+ */
+ bool (*set_directory)(attest_db_t *this, char *dir, bool create);
+
+ /**
+ * Set primary key of the directory to be queried
+ *
+ * @param did primary key of directory
+ * @return TRUE if successful
+ */
+ bool (*set_did)(attest_db_t *this, int did);
+
+ /**
+ * Set measurement file to be queried
+ *
+ * @param file measurement file
+ * @param create if TRUE create database entry if it doesn't exist
+ * @return TRUE if successful
+ */
+ bool (*set_file)(attest_db_t *this, char *file, bool create);
+
+ /**
+ * Set primary key of the measurement file to be queried
+ *
+ * @param fid primary key of measurement file
+ * @return TRUE if successful
+ */
+ bool (*set_fid)(attest_db_t *this, int fid);
+
+ /**
+ * Set functional component to be queried
+ *
+ * @param key AIK
+ * @param create if TRUE create database entry if it doesn't exist
+ * @return TRUE if successful
+ */
+ bool (*set_key)(attest_db_t *this, chunk_t key, bool create);
+
+ /**
+ * Set primary key of the AIK to be queried
+ *
+ * @param kid primary key of AIK
+ * @return TRUE if successful
+ */
+ bool (*set_kid)(attest_db_t *this, int kid);
+
+ /**
+ * Set software product to be queried
+ *
+ * @param product software product
+ * @param create if TRUE create database entry if it doesn't exist
+ * @return TRUE if successful
+ */
+ bool (*set_product)(attest_db_t *this, char *product, bool create);
+
+ /**
+ * Set primary key of the software product to be queried
+ *
+ * @param pid primary key of software product
+ * @return TRUE if successful
+ */
+ bool (*set_pid)(attest_db_t *this, int pid);
+
+ /**
+ * Set measurement hash algorithm
+ *
+ * @param algo hash algorithm
+ */
+ void (*set_algo)(attest_db_t *this, pts_meas_algorithms_t algo);
+
+ /**
+ * Set owner [user/host] of an AIK
+ *
+ * @param owner user/host name
+ * @return TRUE if successful
+ */
+ void (*set_owner)(attest_db_t *this, char *owner);
+
+ /**
+ * List all products stored in the database
+ */
+ void (*list_products)(attest_db_t *this);
+
+ /**
+ * List selected files stored in the database
+ */
+ void (*list_files)(attest_db_t *this);
+
+ /**
+ * List all components stored in the database
+ */
+ void (*list_components)(attest_db_t *this);
+
+ /**
+ * List all AIKs stored in the database
+ */
+ void (*list_keys)(attest_db_t *this);
+
+ /**
+ * List selected measurement hashes stored in the database
+ */
+ void (*list_hashes)(attest_db_t *this);
+
+ /**
+ * List selected component measurement stored in the database
+ */
+ void (*list_measurements)(attest_db_t *this);
+
+ /**
+ * Add an entry to the database
+ */
+ bool (*add)(attest_db_t *this);
+
+ /**
+ * Delete an entry from the database
+ */
+ bool (*delete)(attest_db_t *this);
+
+ /**
+ * Destroy attest_db_t object
+ */
+ void (*destroy)(attest_db_t *this);
+
+};
+
+/**
+ * Create an attest_db_t instance
+ *
+ * @param uri database URI
+ */
+attest_db_t* attest_db_create(char *uri);
+
+#endif /** ATTEST_DB_H_ @}*/
diff --git a/src/libpts/plugins/imv_attestation/attest_usage.c b/src/libpts/plugins/imv_attestation/attest_usage.c
new file mode 100644
index 000000000..e58f821e0
--- /dev/null
+++ b/src/libpts/plugins/imv_attestation/attest_usage.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2011 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 <stdio.h>
+
+#include "attest_usage.h"
+
+/**
+ * print attest usage info
+ */
+void usage(void)
+{
+ printf("\
+Usage:\n\
+ ipsec attest --files|--products|--keys|--hashes [options]\n\
+ \n\
+ ipsec attest --components|-keys|--measurements|--add|--del [options]\n\
+ \n\
+ ipsec attest --files [--product <name>|--pid <id>]\n\
+ Show a list of files with a software product name or\n\
+ its primary key as an optional selector.\n\
+ \n\
+ ipsec attest --products [--file <path>|--fid <id>]\n\
+ Show a list of supported software products with a file path or\n\
+ its primary key as an optional selector.\n\
+ \n\
+ ipsec attest --hashes [--sha1|--sha256|--sha384] [--product <name>|--pid <id>]\n\
+ Show a list of measurement hashes for a given software product or\n\
+ its primary key as an optional selector.\n\
+ \n\
+ ipsec attest --hashes [--sha1|--sha256|--sha384] [--file <path>|--fid <id>]\n\
+ Show a list of measurement hashes for a given file or\n\
+ its primary key as an optional selector.\n\
+ \n\
+ ipsec attest --components [--key <digest>|--kid <id>]\n\
+ Show a list of components with an AIK digest or\n\
+ its primary key as an optional selector.\n\
+ \n\
+ ipsec attest --keys [--components <cfn>|--cid <id>]\n\
+ Show a list of AIK key digests with a component or\n\
+ its primary key as an optional selector.\n\
+ \n\
+ ipsec attest --measurements [--sha1|--sha256|--sha384] [--component <cfn>|--cid <id>]\n\
+ Show a list of component measurements for a given component or\n\
+ its primary key as an optional selector.\n\
+ \n\
+ ipsec attest --measurements [--sha1|--sha256|--sha384] [--key <digest>|--kid <id>|--aik <path>]\n\
+ Show a list of component measurements for a given AIK or\n\
+ its primary key as an optional selector.\n\
+ \n\
+ ipsec attest --add --file <path>|--dir <path>|--product <name>|--component <cfn>\n\
+ Add a file, directory, product or component entry\n\
+ Component <cfn> entries must be of the form <vendor_id>/<name>-<qualifier>\n\
+ \n\
+ ipsec attest --add [--owner <name>] --key <digest>|--aik <path>\n\
+ Add an AIK public key digest entry preceded by an optional owner name\n\
+ \n\
+ ipsec attest --del --file <path>|--fid <id>|--dir <path>|--did <id>\n\
+ Delete a file or directory entry referenced either by value or primary key\n\
+ \n\
+ ipsec attest --del --product <name>|--pid <id>|--component <cfn>|--cid <id>\n\
+ Delete a product or component entry referenced either by value or primary key\n\
+ \n\
+ ipsec attest --del --key <digest>|--kid <id>|--aik <path>\n\
+ Delete an AIK entry referenced either by value or primary key\n\
+ \n");
+}
+
diff --git a/src/libpts/plugins/imv_attestation/attest_usage.h b/src/libpts/plugins/imv_attestation/attest_usage.h
new file mode 100644
index 000000000..bce801e9d
--- /dev/null
+++ b/src/libpts/plugins/imv_attestation/attest_usage.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+#ifndef ATTEST_USAGE_H_
+#define ATTEST_USAGE_H_
+
+/**
+ * print attest usage info
+ */
+void usage(void);
+
+
+#endif /* ATTEST_USAGE_H_ */
diff --git a/src/libimcv/plugins/imv_attestation/data.sql b/src/libpts/plugins/imv_attestation/data.sql
index 60620dd45..e6e03627a 100644
--- a/src/libimcv/plugins/imv_attestation/data.sql
+++ b/src/libpts/plugins/imv_attestation/data.sql
@@ -36,272 +36,356 @@ INSERT INTO products (
'Gentoo Base System release 1.12.11.1 i686'
);
+INSERT INTO products (
+ name
+) VALUES (
+ 'Ubuntu 11.10 i686'
+);
+
/* Files */
-INSERT INTO files (
+INSERT INTO files ( /* 1 */
type, path
- ) VALUES (
+) VALUES (
0, '/lib/i386-linux-gnu/libdl.so.2'
);
INSERT INTO files (
type, path
- ) VALUES (
+) VALUES (
0, '/lib/x86_64-linux-gnu/libdl.so.2'
);
INSERT INTO files (
type, path
- ) VALUES (
+) VALUES (
0, '/lib/libdl.so.2'
);
INSERT INTO files (
type, path
- ) VALUES (
+) VALUES (
0, '/sbin/iptables'
);
-INSERT INTO files (
+INSERT INTO files ( /* 5 */
type, path
- ) VALUES (
+) VALUES (
0, '/lib/libxtables.so.5'
);
INSERT INTO files (
type, path
- ) VALUES (
+) VALUES (
0, '/lib/libxtables.so.2'
);
INSERT INTO files (
type, path
- ) VALUES (
+) VALUES (
1, '/lib/xtables/'
);
INSERT INTO files (
type, path
- ) VALUES (
+) VALUES (
0, 'libxt_udp.so'
);
INSERT INTO files (
type, path
- ) VALUES (
+) VALUES (
0, 'libxt_tcp.so'
);
-INSERT INTO files (
+INSERT INTO files ( /* 10 */
type, path
- ) VALUES (
+) VALUES (
0, 'libxt_esp.so'
);
INSERT INTO files (
type, path
- ) VALUES (
+) VALUES (
0, 'libxt_policy.so'
);
INSERT INTO files (
type, path
- ) VALUES (
+) VALUES (
0, 'libxt_conntrack.so'
);
INSERT INTO files (
type, path
- ) VALUES (
+) VALUES (
0, 'libipt_SNAT.so'
);
INSERT INTO files (
type, path
- ) VALUES (
+) VALUES (
0, 'libipt_DNAT.so'
);
-INSERT INTO files (
+INSERT INTO files ( /* 15 */
type, path
- ) VALUES (
+) VALUES (
0, 'libipt_MASQUERADE.so'
);
INSERT INTO files (
type, path
- ) VALUES (
+) VALUES (
0, 'libipt_LOG.so'
);
INSERT INTO files (
type, path
- ) VALUES (
+) VALUES (
0, '/sbin/ip6tables'
);
INSERT INTO files (
type, path
- ) VALUES (
+) VALUES (
0, 'libip6t_LOG.so'
);
INSERT INTO files (
type, path
- ) VALUES (
+) VALUES (
0, 'libxt_mark.so'
);
-INSERT INTO files (
+INSERT INTO files ( /* 20 */
type, path
- ) VALUES (
+) VALUES (
0, 'libxt_MARK.so'
);
INSERT INTO files (
type, path
- ) VALUES (
+) VALUES (
1, '/lib/iptables'
);
+INSERT INTO files (
+ type, path
+) VALUES (
+ 0, '/etc/tnc_config'
+);
+
/* Product-File */
INSERT INTO product_file (
- product, file
+ product, file, measurement
+) VALUES (
+ 1, 1, 1
+);
+
+INSERT INTO product_file (
+ product, file, measurement
+) VALUES (
+ 1, 4, 1
+);
+
+INSERT INTO product_file (
+ product, file, measurement
) VALUES (
- 1, 1
+ 1, 5, 1
);
INSERT INTO product_file (
- product, file
+ product, file, measurement
) VALUES (
- 1, 4
+ 1, 7, 1
);
INSERT INTO product_file (
- product, file
+ product, file, measurement
) VALUES (
- 1, 5
+ 1, 17, 1
);
INSERT INTO product_file (
- product, file
+ product, file, metadata
) VALUES (
- 1, 7
+ 1, 22, 1
);
INSERT INTO product_file (
- product, file
+ product, file, measurement
) VALUES (
- 1, 17
+ 2, 2, 1
);
INSERT INTO product_file (
- product, file
+ product, file, measurement
) VALUES (
- 2, 2
+ 2, 4, 1
);
INSERT INTO product_file (
- product, file
+ product, file, measurement
) VALUES (
- 2, 4
+ 2, 5, 1
);
INSERT INTO product_file (
- product, file
+ product, file, measurement
) VALUES (
- 2, 5
+ 2, 7, 1
);
INSERT INTO product_file (
- product, file
+ product, file, metadata
) VALUES (
- 2, 7
+ 2, 22, 1
);
INSERT INTO product_file (
- product, file
+ product, file, measurement
) VALUES (
- 3, 3
+ 3, 3, 1
);
INSERT INTO product_file (
- product, file
+ product, file, measurement
) VALUES (
- 3, 4
+ 3, 4, 1
);
INSERT INTO product_file (
- product, file
+ product, file, metadata
) VALUES (
- 4, 3
+ 3, 22, 1
);
INSERT INTO product_file (
- product, file
+ product, file, measurement
) VALUES (
- 4, 4
+ 4, 3, 1
);
INSERT INTO product_file (
- product, file
+ product, file, measurement
) VALUES (
- 4, 6
+ 4, 4, 1
);
INSERT INTO product_file (
- product, file
+ product, file, measurement
) VALUES (
- 4, 7
+ 4, 6, 1
);
INSERT INTO product_file (
- product, file
+ product, file, measurement
) VALUES (
- 5, 3
+ 4, 7, 1
);
INSERT INTO product_file (
- product, file
+ product, file, metadata
) VALUES (
- 5, 4
+ 4, 22, 1
);
INSERT INTO product_file (
- product, file
+ product, file, measurement
) VALUES (
- 5, 6
+ 5, 3, 1
);
INSERT INTO product_file (
- product, file
+ product, file, measurement
) VALUES (
- 5, 7
+ 5, 4, 1
);
INSERT INTO product_file (
- product, file
+ product, file, measurement
) VALUES (
- 6, 3
+ 5, 6, 1
);
INSERT INTO product_file (
- product, file
+ product, file, measurement
) VALUES (
- 6, 4
+ 5, 7, 1
);
INSERT INTO product_file (
- product, file
+ product, file, metadata
) VALUES (
- 6, 17
+ 5, 22, 1
);
INSERT INTO product_file (
- product, file
+ product, file, measurement
) VALUES (
- 6, 21
+ 6, 3, 1
+);
+
+INSERT INTO product_file (
+ product, file, measurement
+) VALUES (
+ 6, 4, 1
+);
+
+INSERT INTO product_file (
+ product, file, measurement
+) VALUES (
+ 6, 17, 1
+);
+
+INSERT INTO product_file (
+ product, file, measurement
+) VALUES (
+ 6, 21, 1
+);
+
+INSERT INTO product_file (
+ product, file, metadata
+) VALUES (
+ 6, 22, 1
+);
+
+INSERT INTO product_file (
+ product, file, measurement
+) VALUES (
+ 7, 1, 1
+);
+
+INSERT INTO product_file (
+ product, file, measurement
+) VALUES (
+ 7, 4, 1
+);
+
+INSERT INTO product_file (
+ product, file, measurement
+) VALUES (
+ 7, 5, 1
+);
+
+INSERT INTO product_file (
+ product, file, measurement
+) VALUES (
+ 7, 7, 1
+);
+
+INSERT INTO product_file (
+ product, file, measurement
+) VALUES (
+ 7, 17, 1
+);
+
+INSERT INTO product_file (
+ product, file, metadata
+) VALUES (
+ 7, 22, 1
);
/* File Hashes */
@@ -327,6 +411,24 @@ INSERT INTO file_hashes (
INSERT INTO file_hashes (
file, product, algo, hash
) VALUES (
+ 1, 7, 32768, X'40763935cdea25119002c42f984b994d8d2a6d75'
+);
+
+INSERT INTO file_hashes (
+ file, product, algo, hash
+) VALUES (
+ 1, 7, 16384, X'27c4f867d3f994a361e0b25d7846b3698d29f82b38662f233a97cafc60c44189'
+);
+
+INSERT INTO file_hashes (
+ file, product, algo, hash
+) VALUES (
+ 1, 7, 8192, X'301dad8829308f5a68c603a87bf961b91365f0346ac2f322de3ddcbb4645f56c0e6d2dc503ec2abff8fe8e895ce9304d'
+);
+
+INSERT INTO file_hashes (
+ file, product, algo, hash
+) VALUES (
2, 2, 32768, X'2a4047437e6fb346e2d854fc415e16b80e75bf6b'
);
@@ -489,6 +591,24 @@ INSERT INTO file_hashes (
INSERT INTO file_hashes (
file, product, algo, hash
) VALUES (
+ 4, 7, 32768, X'ff6deca0eeb7a257205c5f0ab5f5d821ea184098'
+);
+
+INSERT INTO file_hashes (
+ file, product, algo, hash
+) VALUES (
+ 4, 7, 16384, X'5c84fdf7c529d3c65a001587eda641fe489f83961a621fe514e7852a842690d6'
+);
+
+INSERT INTO file_hashes (
+ file, product, algo, hash
+) VALUES (
+ 4, 7, 8192, X'8bd699f85f5b3efb27204b4699c518f871ef245d03b4bf8d1cc00456025017546030c2f493525754cffcd24cdbc03b21'
+);
+
+INSERT INTO file_hashes (
+ file, product, algo, hash
+) VALUES (
5, 1, 32768, X'7a3ca72158e60b0c91e48a420848f1b693aea26c'
);
@@ -525,6 +645,25 @@ INSERT INTO file_hashes (
INSERT INTO file_hashes (
file, product, algo, hash
) VALUES (
+ 5, 7, 32768, X'7a3ca72158e60b0c91e48a420848f1b693aea26c'
+);
+
+INSERT INTO file_hashes (
+ file, product, algo, hash
+) VALUES (
+ 5, 7, 16384, X'f9693c7d36c087d51f5012897fa0e8bb94081854d080c84f831f4d693d22f645'
+);
+
+INSERT INTO file_hashes (
+ file, product, algo, hash
+) VALUES (
+ 5, 7, 8192, X'4ec135e54c8840ab575fcdf00c66f996f763863ad30800b0f0a0b02e7899697d6ab9ccfe185ccbc16c19f38d0a27becb'
+);
+
+
+INSERT INTO file_hashes (
+ file, product, algo, hash
+) VALUES (
6, 4, 32768, X'92e66ae282947f66544682039a33fd1dbd402244'
);
@@ -579,6 +718,24 @@ INSERT INTO file_hashes (
INSERT INTO file_hashes (
file, directory, product, algo, hash
) VALUES (
+ 8, 7, 7, 32768, X'11ce3b45feb3e66a75490d42ba95071ac6f40a7f'
+);
+
+INSERT INTO file_hashes (
+ file, directory, product, algo, hash
+) VALUES (
+ 8, 7, 7, 16384, X'468ef70f19372bc4a2b1805ffa3621515061fc19fa361374788bd362d638ac02'
+);
+
+INSERT INTO file_hashes (
+ file, directory, product, algo, hash
+) VALUES (
+ 8, 7, 7, 8192, X'63076ae505ce52c37878c9b6891ac516320046403aec25bf347c7011c2d28d5db7e2946d1fae3006ab4ef43716ff4558'
+);
+
+INSERT INTO file_hashes (
+ file, directory, product, algo, hash
+) VALUES (
8, 21, 6, 32768, X'010873de0d682a26e1c6795dd4992248cc47cdd1'
);
@@ -633,6 +790,24 @@ INSERT INTO file_hashes (
INSERT INTO file_hashes (
file, directory, product, algo, hash
) VALUES (
+ 9, 7, 7, 32768, X'1d740abd38f9f4bc81ca434a0e25b6e21704248b'
+);
+
+INSERT INTO file_hashes (
+ file, directory, product, algo, hash
+) VALUES (
+ 9, 7, 7, 16384, X'e26bb7175956dc8747a81431e810f830413b6c63756bf5156ab51367fe4f48a0'
+);
+
+INSERT INTO file_hashes (
+ file, directory, product, algo, hash
+) VALUES (
+ 9, 7, 7, 8192, X'5d3637413b9e318d0e0be6a9da86121062b99d1bdb084dfda4222baa71b250de644b4024281760b4eae926e03fac4fdb'
+);
+
+INSERT INTO file_hashes (
+ file, directory, product, algo, hash
+) VALUES (
9, 21, 6, 32768, X'e1df4f3949b09c25e15b9c9b7088a60d683903a8'
);
@@ -669,6 +844,24 @@ INSERT INTO file_hashes (
INSERT INTO file_hashes (
file, directory, product, algo, hash
) VALUES (
+ 10, 7, 7, 32768, X'339a58a1b313830c3cc74cb3fb52a5b8152f44e6'
+);
+
+INSERT INTO file_hashes (
+ file, directory, product, algo, hash
+) VALUES (
+ 10, 7, 7, 16384, X'789f2c6a9382bb342964a12947ddf84735d3e3ed3aefbae407098738cdf7c686'
+);
+
+INSERT INTO file_hashes (
+ file, directory, product, algo, hash
+) VALUES (
+ 10, 7, 7, 8192, X'858310a6e4b6311c491c4370990bfd6b9f03a49bb5ddf45b0d788f7043f130016e11be6bd95db66e49e2906a87adf8cb'
+);
+
+INSERT INTO file_hashes (
+ file, directory, product, algo, hash
+) VALUES (
10, 21, 6, 32768, X'87df2d01b85d8354819b431bae0a0a65bfc5d2db'
);
@@ -705,6 +898,24 @@ INSERT INTO file_hashes (
INSERT INTO file_hashes (
file, directory, product, algo, hash
) VALUES (
+ 11, 7, 7, 32768, X'2d32ef93126abf8c660d57c67e5076c6394cabe8'
+);
+
+INSERT INTO file_hashes (
+ file, directory, product, algo, hash
+) VALUES (
+ 11, 7, 7, 16384, X'ced29aca7fc2dd0b01d5d544dfb2e1640a6a79c657f589e7dd6636cfd63eda3b'
+);
+
+INSERT INTO file_hashes (
+ file, directory, product, algo, hash
+) VALUES (
+ 11, 7, 7, 8192, X'a2d33fa2d0ee7bffa5e628f88ccb83cd61bb4c5fe6d2edb8b853b83d8c43f498fa6e8da70510f0a1a3ddb36060bbd4d8'
+);
+
+INSERT INTO file_hashes (
+ file, directory, product, algo, hash
+) VALUES (
12, 7, 1, 32768, X'6c0b2df4fc4c9122b5762ae140d53fdd1cf9e89b'
);
@@ -723,6 +934,24 @@ INSERT INTO file_hashes (
INSERT INTO file_hashes (
file, directory, product, algo, hash
) VALUES (
+ 12, 7, 7, 32768, X'6c0b2df4fc4c9122b5762ae140d53fdd1cf9e89b'
+);
+
+INSERT INTO file_hashes (
+ file, directory, product, algo, hash
+) VALUES (
+ 12, 7, 7, 16384, X'53c3f2bd5aaf8ef4c40f9af92a67621f5e67840b5ff2db67d1bccbcb56f7eef1'
+);
+
+INSERT INTO file_hashes (
+ file, directory, product, algo, hash
+) VALUES (
+ 12, 7, 7, 8192, X'1a4a6d91bda3ce59e6c444ccc1e758c9c6f0e223fd8c5aac369260cdfa83081c0e8f3753f100490910ec161902f10ba7'
+);
+
+INSERT INTO file_hashes (
+ file, directory, product, algo, hash
+) VALUES (
13, 7, 1, 32768, X'e2f7b92abda769f82796f57a29801870585dcea3'
);
@@ -741,6 +970,24 @@ INSERT INTO file_hashes (
INSERT INTO file_hashes (
file, directory, product, algo, hash
) VALUES (
+ 13, 7, 7, 32768, X'e2f7b92abda769f82796f57a29801870585dcea3'
+);
+
+INSERT INTO file_hashes (
+ file, directory, product, algo, hash
+) VALUES (
+ 13, 7, 7, 16384, X'6d3fe67a040dbb469ef498b26cece45806cb7ca04787bba53b7ba1c18e2abd0a'
+);
+
+INSERT INTO file_hashes (
+ file, directory, product, algo, hash
+) VALUES (
+ 13, 7, 7, 8192, X'014852b73cd3eabfa955b7bd56b269d5a0590a2770cf3d656b3d68dbad30884327fc81ff96c6f661c9c4189c3aefa346'
+);
+
+INSERT INTO file_hashes (
+ file, directory, product, algo, hash
+) VALUES (
14, 7, 1, 32768, X'160d2b04d11eb225fb148615b699081869e15b6c'
);
@@ -759,6 +1006,24 @@ INSERT INTO file_hashes (
INSERT INTO file_hashes (
file, directory, product, algo, hash
) VALUES (
+ 14, 7, 7, 32768, X'160d2b04d11eb225fb148615b699081869e15b6c'
+);
+
+INSERT INTO file_hashes (
+ file, directory, product, algo, hash
+) VALUES (
+ 14, 7, 7, 16384, X'1f5a2ceae1418f9c1fbf51eb7d84f74d488908cde5931a5461746d1e24682a25'
+);
+
+INSERT INTO file_hashes (
+ file, directory, product, algo, hash
+) VALUES (
+ 14, 7, 7, 8192, X'f701cb25b0e9a9f32d3bba9b274ca0e8838363d13b7283b842d6c9673442890e538127c3b64ca4b177de1d243b44cf0d'
+);
+
+INSERT INTO file_hashes (
+ file, directory, product, algo, hash
+) VALUES (
15, 7, 1, 32768, X'5a0d07ab036603a76759e5f61f7d04f2d3c056cc'
);
@@ -777,6 +1042,24 @@ INSERT INTO file_hashes (
INSERT INTO file_hashes (
file, directory, product, algo, hash
) VALUES (
+ 15, 7, 7, 32768, X'5a0d07ab036603a76759e5f61f7d04f2d3c056cc'
+);
+
+INSERT INTO file_hashes (
+ file, directory, product, algo, hash
+) VALUES (
+ 15, 7, 7, 16384, X'85491714e860062c441ff50d93ad79350449596b89b2e409b513c2d883321c9d'
+);
+
+INSERT INTO file_hashes (
+ file, directory, product, algo, hash
+) VALUES (
+ 15, 7, 7, 8192, X'8038830a994c779bc200e844d8768280feca9dd5d58de6cd359b87cc68846799edfd16e36e83002da4bb309cfd3b353d'
+);
+
+INSERT INTO file_hashes (
+ file, directory, product, algo, hash
+) VALUES (
16, 7, 1, 32768, X'd6c8dfbaae7ab28b5cef2626a2af3f99a6ea4365'
);
@@ -793,6 +1076,24 @@ INSERT INTO file_hashes (
);
INSERT INTO file_hashes (
+ file, directory, product, algo, hash
+) VALUES (
+ 16, 7, 7, 32768, X'd6c8dfbaae7ab28b5cef2626a2af3f99a6ea4365'
+);
+
+INSERT INTO file_hashes (
+ file, directory, product, algo, hash
+) VALUES (
+ 16, 7, 7, 16384, X'd0d6f784e937227cce99e3be860be078d0397a6fb5a5bc9d95a19ef855609dbc'
+);
+
+INSERT INTO file_hashes (
+ file, directory, product, algo, hash
+) VALUES (
+ 16, 7, 7, 8192, X'4be6e7978a6e4fb8a792815f2bbe28c2e66276401fb98ca90e49a5c2f2c94a1c7aac635d501d35d1db0fd53a0cb9d0fa'
+);
+
+INSERT INTO file_hashes (
file, product, algo, hash
) VALUES (
17, 1, 32768, X'8a7c41167bc0fcc1dec8329a868ba265c23857f5'
@@ -829,6 +1130,24 @@ INSERT INTO file_hashes (
);
INSERT INTO file_hashes (
+ file, product, algo, hash
+) VALUES (
+ 17, 7, 32768, X'8a7c41167bc0fcc1dec8329a868ba265c23857f5'
+);
+
+INSERT INTO file_hashes (
+ file, product, algo, hash
+) VALUES (
+ 17, 7, 16384, X'f8eb857d7bb850f44c15363ba699442c2810663ac5a83a5f49e06e0fd8144b0e'
+);
+
+INSERT INTO file_hashes (
+ file, product, algo, hash
+) VALUES (
+ 17, 7, 8192, X'f40cb6e557ab18d70080e7995e3f96cc272842e822bf52bc1c59075313c2cd832f96cf03a8524905f3d3f7a61441c651'
+);
+
+INSERT INTO file_hashes (
file, directory, product, algo, hash
) VALUES (
18, 7, 1, 32768, X'23296f48276e160b6d99b1b42a9114df720bb1ab'
@@ -849,6 +1168,24 @@ INSERT INTO file_hashes (
INSERT INTO file_hashes (
file, directory, product, algo, hash
) VALUES (
+ 18, 7, 7, 32768, X'23296f48276e160b6d99b1b42a9114df720bb1ab'
+);
+
+INSERT INTO file_hashes (
+ file, directory, product, algo, hash
+) VALUES (
+ 18, 7, 7, 16384, X'78cd0a598080e31453f477e8d8a12ec794e859f4076ed92e53d2053d6d16762c'
+);
+
+INSERT INTO file_hashes (
+ file, directory, product, algo, hash
+) VALUES (
+ 18, 7, 7, 8192, X'4da3955f1fd968ecf95cff825d42715b544e577f28f411a020a270834235125bc0c8872bac8dd3466349ac8ab0aa2d74'
+);
+
+INSERT INTO file_hashes (
+ file, directory, product, algo, hash
+) VALUES (
19, 7, 1, 32768, X'd537d437f058136eb3d7be517dbe7647b623c619'
);
@@ -867,6 +1204,24 @@ INSERT INTO file_hashes (
INSERT INTO file_hashes (
file, directory, product, algo, hash
) VALUES (
+ 19, 7, 7, 32768, X'd537d437f058136eb3d7be517dbe7647b623c619'
+);
+
+INSERT INTO file_hashes (
+ file, directory, product, algo, hash
+) VALUES (
+ 19, 7, 7, 16384, X'6a837037ad3fc4d06270d99cee2714dcf96b91aeb54d3483009219337961f834'
+);
+
+INSERT INTO file_hashes (
+ file, directory, product, algo, hash
+) VALUES (
+ 19, 7, 7, 8192, X'7b5b16840da590a995fab23533f41982c5b136bff8e9b9a90b3c919a12cee20d312091455057a8bba9d9fbe314e6203d'
+);
+
+INSERT INTO file_hashes (
+ file, directory, product, algo, hash
+) VALUES (
20, 7, 1, 32768, X'f9e3531abb67a020cf667d46ca823675dd0a0dd4'
);
@@ -882,3 +1237,69 @@ INSERT INTO file_hashes (
20, 7, 1, 8192, X'84200bd318bb022915150842ddf4002e061ef593604ad0d07021dc662cc40bfa749cce084ddf25d0e5137f6380f613d8'
);
+INSERT INTO file_hashes (
+ file, directory, product, algo, hash
+) VALUES (
+ 20, 7, 7, 32768, X'f9e3531abb67a020cf667d46ca823675dd0a0dd4'
+);
+
+INSERT INTO file_hashes (
+ file, directory, product, algo, hash
+) VALUES (
+ 20, 7, 7, 16384, X'569bafa2dabbcfa0ba9c7c411eacfeb8930f9d856a1a43cf8aa3662a67c13e35'
+);
+
+INSERT INTO file_hashes (
+ file, directory, product, algo, hash
+) VALUES (
+ 20, 7, 7, 8192, X'84200bd318bb022915150842ddf4002e061ef593604ad0d07021dc662cc40bfa749cce084ddf25d0e5137f6380f613d8'
+);
+
+/* AIKs */
+
+INSERT INTO keys (
+ keyid, owner
+) VALUES (
+ X'b772a6730776b9f028e5adfccd40b55c320a13b6', 'Andreas, merthyr (Fujitsu Siemens Lifebook S6420)'
+);
+
+/* Components */
+
+INSERT INTO components (
+ vendor_id, name, qualifier
+) VALUES (
+ 36906, 1, 33 /* ITA TGRUB */
+);
+
+INSERT INTO components (
+ vendor_id, name, qualifier
+) VALUES (
+ 36906, 2, 33 /* ITA TBOOT */
+);
+
+INSERT INTO components (
+ vendor_id, name, qualifier
+) VALUES (
+ 36906, 3, 33 /* ITA IMA */
+);
+
+/* AIK Component */
+
+INSERT INTO key_component (
+ key, component, depth, seq_no
+) VALUES (
+ 2, 2, 0, 1
+);
+
+INSERT INTO key_component (
+ key, component, depth, seq_no
+) VALUES (
+ 1, 3, 0, 1
+);
+
+INSERT INTO key_component (
+ key, component, depth, seq_no
+) VALUES (
+ 1, 2, 0, 2
+);
+
diff --git a/src/libpts/plugins/imv_attestation/imv_attestation.c b/src/libpts/plugins/imv_attestation/imv_attestation.c
new file mode 100644
index 000000000..6bd5984e0
--- /dev/null
+++ b/src/libpts/plugins/imv_attestation/imv_attestation.c
@@ -0,0 +1,520 @@
+/*
+ * Copyright (C) 2011 Sansar Choinyambuu
+ * 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_attestation_state.h"
+#include "imv_attestation_process.h"
+#include "imv_attestation_build.h"
+
+#include <imv/imv_agent.h>
+#include <pa_tnc/pa_tnc_msg.h>
+#include <ietf/ietf_attr.h>
+#include <ietf/ietf_attr_pa_tnc_error.h>
+#include <ietf/ietf_attr_product_info.h>
+
+#include <libpts.h>
+
+#include <pts/pts.h>
+#include <pts/pts_database.h>
+#include <pts/pts_creds.h>
+
+#include <tcg/tcg_attr.h>
+
+#include <tncif_pa_subtypes.h>
+
+#include <pen/pen.h>
+#include <debug.h>
+#include <credentials/credential_manager.h>
+#include <utils/linked_list.h>
+
+/* IMV definitions */
+
+static const char imv_name[] = "Attestation";
+
+#define IMV_VENDOR_ID PEN_TCG
+#define IMV_SUBTYPE PA_SUBTYPE_TCG_PTS
+
+static imv_agent_t *imv_attestation;
+
+/**
+ * Supported PTS measurement algorithms
+ */
+static pts_meas_algorithms_t supported_algorithms = PTS_MEAS_ALGO_NONE;
+
+/**
+ * Supported PTS Diffie Hellman Groups
+ */
+static pts_dh_group_t supported_dh_groups = PTS_DH_GROUP_NONE;
+
+/**
+ * PTS file measurement database
+ */
+static pts_database_t *pts_db;
+
+/**
+ * PTS credentials
+ */
+static pts_creds_t *pts_creds;
+
+/**
+ * PTS credential manager
+ */
+static credential_manager_t *pts_credmgr;
+
+/**
+ * see section 3.8.1 of TCG TNC IF-IMV Specification 1.3
+ */
+TNC_Result TNC_IMV_Initialize(TNC_IMVID imv_id,
+ TNC_Version min_version,
+ TNC_Version max_version,
+ TNC_Version *actual_version)
+{
+ char *hash_alg, *dh_group, *uri, *cadir;
+
+ if (imv_attestation)
+ {
+ DBG1(DBG_IMV, "IMV \"%s\" has already been initialized", imv_name);
+ return TNC_RESULT_ALREADY_INITIALIZED;
+ }
+ if (!pts_meas_algo_probe(&supported_algorithms) ||
+ !pts_dh_group_probe(&supported_dh_groups))
+ {
+ return TNC_RESULT_FATAL;
+ }
+ imv_attestation = imv_agent_create(imv_name, IMV_VENDOR_ID, IMV_SUBTYPE,
+ imv_id, actual_version);
+ if (!imv_attestation)
+ {
+ return TNC_RESULT_FATAL;
+ }
+
+ libpts_init();
+
+ if (min_version > TNC_IFIMV_VERSION_1 || max_version < TNC_IFIMV_VERSION_1)
+ {
+ DBG1(DBG_IMV, "no common IF-IMV version");
+ return TNC_RESULT_NO_COMMON_VERSION;
+ }
+
+ hash_alg = lib->settings->get_str(lib->settings,
+ "libimcv.plugins.imv-attestation.hash_algorithm", "sha256");
+ dh_group = lib->settings->get_str(lib->settings,
+ "libimcv.plugins.imv-attestation.dh_group", "ecp256");
+
+ if (!pts_meas_algo_update(hash_alg, &supported_algorithms) ||
+ !pts_dh_group_update(dh_group, &supported_dh_groups))
+ {
+ return TNC_RESULT_FATAL;
+ }
+
+ /* create a PTS credential manager */
+ pts_credmgr = credential_manager_create();
+
+ /* create PTS credential set */
+ cadir = lib->settings->get_str(lib->settings,
+ "libimcv.plugins.imv-attestation.cadir", NULL);
+ pts_creds = pts_creds_create(cadir);
+ if (pts_creds)
+ {
+ pts_credmgr->add_set(pts_credmgr, pts_creds->get_set(pts_creds));
+ }
+
+ /* attach file measurement database */
+ uri = lib->settings->get_str(lib->settings,
+ "libimcv.plugins.imv-attestation.database", NULL);
+ pts_db = pts_database_create(uri);
+
+ return TNC_RESULT_SUCCESS;
+}
+
+/**
+ * see section 3.8.2 of TCG TNC IF-IMV Specification 1.3
+ */
+TNC_Result TNC_IMV_NotifyConnectionChange(TNC_IMVID imv_id,
+ TNC_ConnectionID connection_id,
+ TNC_ConnectionState new_state)
+{
+ imv_state_t *state;
+
+ if (!imv_attestation)
+ {
+ DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
+ return TNC_RESULT_NOT_INITIALIZED;
+ }
+ switch (new_state)
+ {
+ case TNC_CONNECTION_STATE_CREATE:
+ state = imv_attestation_state_create(connection_id);
+ return imv_attestation->create_state(imv_attestation, state);
+ case TNC_CONNECTION_STATE_DELETE:
+ return imv_attestation->delete_state(imv_attestation, connection_id);
+ case TNC_CONNECTION_STATE_HANDSHAKE:
+ default:
+ return imv_attestation->change_state(imv_attestation, connection_id,
+ new_state, NULL);
+ }
+}
+
+static TNC_Result send_message(TNC_ConnectionID connection_id)
+{
+ pa_tnc_msg_t *msg;
+ pa_tnc_attr_t *attr;
+ imv_state_t *state;
+ imv_attestation_state_t *attestation_state;
+ TNC_Result result;
+ linked_list_t *attr_list;
+ enumerator_t *enumerator;
+
+ if (!imv_attestation->get_state(imv_attestation, connection_id, &state))
+ {
+ return TNC_RESULT_FATAL;
+ }
+ attestation_state = (imv_attestation_state_t*)state;
+ attr_list = linked_list_create();
+
+ if (imv_attestation_build(attr_list, attestation_state, supported_algorithms,
+ supported_dh_groups, pts_db))
+ {
+ if (attr_list->get_count(attr_list))
+ {
+ msg = pa_tnc_msg_create();
+
+ /* move PA-TNC attributes to PA-TNC message */
+ enumerator = attr_list->create_enumerator(attr_list);
+ while (enumerator->enumerate(enumerator, &attr))
+ {
+ msg->add_attribute(msg, attr);
+ }
+ enumerator->destroy(enumerator);
+
+ msg->build(msg);
+ result = imv_attestation->send_message(imv_attestation,
+ connection_id, FALSE, 0, TNC_IMCID_ANY,
+ msg->get_encoding(msg));
+ msg->destroy(msg);
+ }
+ else
+ {
+ result = TNC_RESULT_SUCCESS;
+ }
+ attr_list->destroy(attr_list);
+ }
+ else
+ {
+ attr_list->destroy_offset(attr_list, offsetof(pa_tnc_attr_t, destroy));
+ result = TNC_RESULT_FATAL;
+ }
+
+ return result;
+}
+
+static TNC_Result receive_message(TNC_IMVID imv_id,
+ TNC_ConnectionID connection_id,
+ TNC_UInt32 msg_flags,
+ chunk_t msg,
+ TNC_VendorID msg_vid,
+ TNC_MessageSubtype msg_subtype,
+ TNC_UInt32 src_imc_id,
+ TNC_UInt32 dst_imv_id)
+{
+ pa_tnc_msg_t *pa_tnc_msg;
+ pa_tnc_attr_t *attr;
+ linked_list_t *attr_list;
+ imv_state_t *state;
+ imv_attestation_state_t *attestation_state;
+ pts_t *pts;
+ enumerator_t *enumerator;
+ TNC_Result result;
+
+ if (!imv_attestation)
+ {
+ DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
+ return TNC_RESULT_NOT_INITIALIZED;
+ }
+
+ /* get current IMV state */
+ if (!imv_attestation->get_state(imv_attestation, connection_id, &state))
+ {
+ return TNC_RESULT_FATAL;
+ }
+ attestation_state = (imv_attestation_state_t*)state;
+ pts = attestation_state->get_pts(attestation_state);
+
+ /* parse received PA-TNC message and automatically handle any errors */
+ result = imv_attestation->receive_message(imv_attestation, state, msg,
+ msg_vid, msg_subtype, src_imc_id, dst_imv_id, &pa_tnc_msg);
+
+ /* no parsed PA-TNC attributes available if an error occurred */
+ if (!pa_tnc_msg)
+ {
+ return result;
+ }
+
+ /* preprocess any IETF standard error attributes */
+ result = pa_tnc_msg->process_ietf_std_errors(pa_tnc_msg) ?
+ TNC_RESULT_FATAL : TNC_RESULT_SUCCESS;
+
+ attr_list = linked_list_create();
+
+ /* analyze PA-TNC attributes */
+ enumerator = pa_tnc_msg->create_attribute_enumerator(pa_tnc_msg);
+ while (enumerator->enumerate(enumerator, &attr))
+ {
+ if (attr->get_vendor_id(attr) == PEN_IETF)
+ {
+ if (attr->get_type(attr) == IETF_ATTR_PA_TNC_ERROR)
+ {
+ ietf_attr_pa_tnc_error_t *error_attr;
+ pen_t error_vendor_id;
+ pa_tnc_error_code_t error_code;
+ chunk_t msg_info;
+
+ error_attr = (ietf_attr_pa_tnc_error_t*)attr;
+ error_vendor_id = error_attr->get_vendor_id(error_attr);
+
+ if (error_vendor_id == PEN_TCG)
+ {
+ error_code = error_attr->get_error_code(error_attr);
+ msg_info = error_attr->get_msg_info(error_attr);
+
+ DBG1(DBG_IMV, "received TCG-PTS error '%N'",
+ pts_error_code_names, error_code);
+ DBG1(DBG_IMV, "error information: %B", &msg_info);
+
+ result = TNC_RESULT_FATAL;
+ }
+ }
+ else if (attr->get_type(attr) == IETF_ATTR_PRODUCT_INFORMATION)
+ {
+ ietf_attr_product_info_t *attr_cast;
+ char *platform_info;
+
+ attr_cast = (ietf_attr_product_info_t*)attr;
+ platform_info = attr_cast->get_info(attr_cast, NULL, NULL);
+ pts->set_platform_info(pts, platform_info);
+ }
+ }
+ else if (attr->get_vendor_id(attr) == PEN_TCG)
+ {
+ if (!imv_attestation_process(attr, attr_list, attestation_state,
+ supported_algorithms,supported_dh_groups, pts_db, pts_credmgr))
+ {
+ result = TNC_RESULT_FATAL;
+ break;
+ }
+ }
+ }
+ enumerator->destroy(enumerator);
+ pa_tnc_msg->destroy(pa_tnc_msg);
+
+ if (result != TNC_RESULT_SUCCESS)
+ {
+ attr_list->destroy_offset(attr_list, offsetof(pa_tnc_attr_t, destroy));
+ state->set_recommendation(state,
+ TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION,
+ TNC_IMV_EVALUATION_RESULT_ERROR);
+ return imv_attestation->provide_recommendation(imv_attestation,
+ connection_id);
+ }
+
+ if (attr_list->get_count(attr_list))
+ {
+ pa_tnc_msg = pa_tnc_msg_create();
+
+ /* move PA-TNC attributes to PA-TNC message */
+ enumerator = attr_list->create_enumerator(attr_list);
+ while (enumerator->enumerate(enumerator, &attr))
+ {
+ pa_tnc_msg->add_attribute(pa_tnc_msg, attr);
+ }
+ enumerator->destroy(enumerator);
+
+ pa_tnc_msg->build(pa_tnc_msg);
+ result = imv_attestation->send_message(imv_attestation, connection_id,
+ FALSE, 0, TNC_IMCID_ANY,
+ pa_tnc_msg->get_encoding(pa_tnc_msg));
+
+ pa_tnc_msg->destroy(pa_tnc_msg);
+ attr_list->destroy(attr_list);
+
+ return result;
+ }
+ attr_list->destroy(attr_list);
+
+ /* check the IMV state for the next PA-TNC attributes to send */
+ result = send_message(connection_id);
+ if (result != TNC_RESULT_SUCCESS)
+ {
+ state->set_recommendation(state,
+ TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION,
+ TNC_IMV_EVALUATION_RESULT_ERROR);
+ return imv_attestation->provide_recommendation(imv_attestation,
+ connection_id);
+ }
+
+ if (attestation_state->get_handshake_state(attestation_state) ==
+ IMV_ATTESTATION_STATE_END)
+ {
+ if (attestation_state->get_file_meas_request_count(attestation_state))
+ {
+ DBG1(DBG_IMV, "failure due to %d pending file measurements",
+ attestation_state->get_file_meas_request_count(attestation_state));
+ attestation_state->set_measurement_error(attestation_state);
+ }
+ if (attestation_state->get_component_count(attestation_state))
+ {
+ DBG1(DBG_IMV, "failure due to %d components waiting for evidence",
+ attestation_state->get_component_count(attestation_state));
+ attestation_state->set_measurement_error(attestation_state);
+ }
+ if (attestation_state->get_measurement_error(attestation_state))
+ {
+ state->set_recommendation(state,
+ TNC_IMV_ACTION_RECOMMENDATION_ISOLATE,
+ TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR);
+ }
+ else
+ {
+ state->set_recommendation(state,
+ TNC_IMV_ACTION_RECOMMENDATION_ALLOW,
+ TNC_IMV_EVALUATION_RESULT_COMPLIANT);
+ }
+ return imv_attestation->provide_recommendation(imv_attestation,
+ connection_id);
+ }
+
+ return result;
+}
+
+/**
+ * see section 3.8.4 of TCG TNC IF-IMV Specification 1.3
+ */
+TNC_Result TNC_IMV_ReceiveMessage(TNC_IMVID imv_id,
+ TNC_ConnectionID connection_id,
+ TNC_BufferReference msg,
+ TNC_UInt32 msg_len,
+ TNC_MessageType msg_type)
+{
+ TNC_VendorID msg_vid;
+ TNC_MessageSubtype msg_subtype;
+
+ msg_vid = msg_type >> 8;
+ msg_subtype = msg_type & TNC_SUBTYPE_ANY;
+
+ return receive_message(imv_id, connection_id, 0, chunk_create(msg, msg_len),
+ msg_vid, msg_subtype, 0, TNC_IMVID_ANY);
+}
+
+/**
+ * see section 3.8.6 of TCG TNC IF-IMV Specification 1.3
+ */
+TNC_Result TNC_IMV_ReceiveMessageLong(TNC_IMVID imv_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_imc_id,
+ TNC_UInt32 dst_imv_id)
+{
+ return receive_message(imv_id, connection_id, msg_flags,
+ chunk_create(msg, msg_len), msg_vid, msg_subtype,
+ src_imc_id, dst_imv_id);
+}
+
+/**
+ * see section 3.8.7 of TCG TNC IF-IMV Specification 1.3
+ */
+TNC_Result TNC_IMV_SolicitRecommendation(TNC_IMVID imv_id,
+ TNC_ConnectionID connection_id)
+{
+ if (!imv_attestation)
+ {
+ DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
+ return TNC_RESULT_NOT_INITIALIZED;
+ }
+ return imv_attestation->provide_recommendation(imv_attestation,
+ connection_id);
+}
+
+/**
+ * see section 3.8.8 of TCG TNC IF-IMV Specification 1.3
+ */
+TNC_Result TNC_IMV_BatchEnding(TNC_IMVID imv_id,
+ TNC_ConnectionID connection_id)
+{
+ imv_state_t *state;
+ imv_attestation_state_t *attestation_state;
+
+ if (!imv_attestation)
+ {
+ DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
+ return TNC_RESULT_NOT_INITIALIZED;
+ }
+ /* get current IMV state */
+ if (!imv_attestation->get_state(imv_attestation, connection_id, &state))
+ {
+ return TNC_RESULT_FATAL;
+ }
+ attestation_state = (imv_attestation_state_t*)state;
+
+ /* Check if IMV has to initiate the PA-TNC exchange */
+ if (attestation_state->get_handshake_state(attestation_state) ==
+ IMV_ATTESTATION_STATE_INIT)
+ {
+ return send_message(connection_id);
+ }
+ return TNC_RESULT_SUCCESS;
+}
+
+/**
+ * see section 3.8.9 of TCG TNC IF-IMV Specification 1.3
+ */
+TNC_Result TNC_IMV_Terminate(TNC_IMVID imv_id)
+{
+ if (!imv_attestation)
+ {
+ DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
+ return TNC_RESULT_NOT_INITIALIZED;
+ }
+ if (pts_creds)
+ {
+ pts_credmgr->remove_set(pts_credmgr, pts_creds->get_set(pts_creds));
+ pts_creds->destroy(pts_creds);
+ }
+ DESTROY_IF(pts_db);
+ DESTROY_IF(pts_credmgr);
+
+ libpts_deinit();
+
+ imv_attestation->destroy(imv_attestation);
+ imv_attestation = NULL;
+
+ return TNC_RESULT_SUCCESS;
+}
+
+/**
+ * see section 4.2.8.1 of TCG TNC IF-IMV Specification 1.3
+ */
+TNC_Result TNC_IMV_ProvideBindFunction(TNC_IMVID imv_id,
+ TNC_TNCS_BindFunctionPointer bind_function)
+{
+ if (!imv_attestation)
+ {
+ DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
+ return TNC_RESULT_NOT_INITIALIZED;
+ }
+ return imv_attestation->bind_functions(imv_attestation, bind_function);
+}
diff --git a/src/libpts/plugins/imv_attestation/imv_attestation_build.c b/src/libpts/plugins/imv_attestation/imv_attestation_build.c
new file mode 100644
index 000000000..4f2cc1e95
--- /dev/null
+++ b/src/libpts/plugins/imv_attestation/imv_attestation_build.c
@@ -0,0 +1,300 @@
+/*
+ * Copyright (C) 2011 Sansar Choinyambuu
+ * 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_attestation_build.h"
+#include "imv_attestation_state.h"
+
+#include <libpts.h>
+#include <tcg/tcg_pts_attr_proto_caps.h>
+#include <tcg/tcg_pts_attr_meas_algo.h>
+#include <tcg/tcg_pts_attr_dh_nonce_params_req.h>
+#include <tcg/tcg_pts_attr_dh_nonce_finish.h>
+#include <tcg/tcg_pts_attr_get_tpm_version_info.h>
+#include <tcg/tcg_pts_attr_get_aik.h>
+#include <tcg/tcg_pts_attr_req_func_comp_evid.h>
+#include <tcg/tcg_pts_attr_gen_attest_evid.h>
+#include <tcg/tcg_pts_attr_req_file_meas.h>
+#include <tcg/tcg_pts_attr_req_file_meta.h>
+
+#include <debug.h>
+
+bool imv_attestation_build(linked_list_t *attr_list,
+ imv_attestation_state_t *attestation_state,
+ pts_meas_algorithms_t supported_algorithms,
+ pts_dh_group_t supported_dh_groups,
+ pts_database_t *pts_db)
+{
+ imv_attestation_handshake_state_t handshake_state;
+ pts_t *pts;
+ pa_tnc_attr_t *attr = NULL;
+
+ handshake_state = attestation_state->get_handshake_state(attestation_state);
+ pts = attestation_state->get_pts(attestation_state);
+
+ /**
+ * Skip DH Nonce Parameters Request attribute when
+ * DH Nonce Exchange is not selected by PTS-IMC side
+ */
+ if (handshake_state == IMV_ATTESTATION_STATE_NONCE_REQ &&
+ !(pts->get_proto_caps(pts) & PTS_PROTO_CAPS_D))
+ {
+ DBG2(DBG_IMV, "PTS-IMC does not support DH Nonce negotiation - "
+ "advancing to TPM Initialization");
+ handshake_state = IMV_ATTESTATION_STATE_TPM_INIT;
+ }
+
+ /**
+ * Skip TPM Version Info and AIK attributes when
+ * no TPM is available on the PTS-IMC side
+ */
+ if (handshake_state == IMV_ATTESTATION_STATE_TPM_INIT &&
+ !(pts->get_proto_caps(pts) & PTS_PROTO_CAPS_T))
+ {
+ DBG2(DBG_IMV, "PTS-IMC made no TPM available - "
+ "advancing to File Measurements");
+ handshake_state = IMV_ATTESTATION_STATE_MEAS;
+ }
+
+ switch (handshake_state)
+ {
+ case IMV_ATTESTATION_STATE_INIT:
+ {
+ pts_proto_caps_flag_t flags;
+
+ /* Send Request Protocol Capabilities attribute */
+ flags = pts->get_proto_caps(pts);
+ attr = tcg_pts_attr_proto_caps_create(flags, TRUE);
+ attr->set_noskip_flag(attr, TRUE);
+ attr_list->insert_last(attr_list, attr);
+
+ /* Send Measurement Algorithms attribute */
+ attr = tcg_pts_attr_meas_algo_create(supported_algorithms, FALSE);
+ attr->set_noskip_flag(attr, TRUE);
+ attr_list->insert_last(attr_list, attr);
+
+ attestation_state->set_handshake_state(attestation_state,
+ IMV_ATTESTATION_STATE_NONCE_REQ);
+ break;
+ }
+ case IMV_ATTESTATION_STATE_NONCE_REQ:
+ {
+ int min_nonce_len;
+
+ /* Send DH nonce parameters request attribute */
+ min_nonce_len = lib->settings->get_int(lib->settings,
+ "libimcv.plugins.imv-attestation.min_nonce_len", 0);
+ attr = tcg_pts_attr_dh_nonce_params_req_create(min_nonce_len,
+ supported_dh_groups);
+ attr->set_noskip_flag(attr, TRUE);
+ attr_list->insert_last(attr_list, attr);
+
+ attestation_state->set_handshake_state(attestation_state,
+ IMV_ATTESTATION_STATE_TPM_INIT);
+ break;
+ }
+ case IMV_ATTESTATION_STATE_TPM_INIT:
+ {
+ pts_meas_algorithms_t selected_algorithm;
+ chunk_t initiator_value, initiator_nonce;
+
+ if ((pts->get_proto_caps(pts) & PTS_PROTO_CAPS_D))
+ {
+ /* Send DH nonce finish attribute */
+ selected_algorithm = pts->get_meas_algorithm(pts);
+ pts->get_my_public_value(pts, &initiator_value, &initiator_nonce);
+ attr = tcg_pts_attr_dh_nonce_finish_create(selected_algorithm,
+ initiator_value, initiator_nonce);
+ attr->set_noskip_flag(attr, TRUE);
+ attr_list->insert_last(attr_list, attr);
+ }
+
+ /* Send Get TPM Version attribute */
+ attr = tcg_pts_attr_get_tpm_version_info_create();
+ attr->set_noskip_flag(attr, TRUE);
+ attr_list->insert_last(attr_list, attr);
+
+ /* Send Get AIK attribute */
+ attr = tcg_pts_attr_get_aik_create();
+ attr->set_noskip_flag(attr, TRUE);
+ attr_list->insert_last(attr_list, attr);
+
+ attestation_state->set_handshake_state(attestation_state,
+ IMV_ATTESTATION_STATE_MEAS);
+ break;
+ }
+ case IMV_ATTESTATION_STATE_MEAS:
+ {
+ enumerator_t *enumerator;
+ u_int32_t delimiter = SOLIDUS_UTF;
+ char *platform_info, *pathname;
+ u_int16_t request_id;
+ int id, type;
+ bool is_dir;
+
+ attestation_state->set_handshake_state(attestation_state,
+ IMV_ATTESTATION_STATE_COMP_EVID);
+
+ /* Get Platform and OS of the PTS-IMC */
+ platform_info = pts->get_platform_info(pts);
+
+ if (!pts_db || !platform_info)
+ {
+ DBG1(DBG_IMV, "%s%s%s not available",
+ (pts_db) ? "" : "pts database",
+ (!pts_db && !platform_info) ? "and" : "",
+ (platform_info) ? "" : "platform info");
+ break;
+ }
+ DBG1(DBG_IMV, "platform is '%s'", platform_info);
+
+ /* Send Request File Metadata attribute */
+ enumerator = pts_db->create_file_meta_enumerator(pts_db,
+ platform_info);
+ if (!enumerator)
+ {
+ break;
+ }
+ while (enumerator->enumerate(enumerator, &type, &pathname))
+ {
+ is_dir = (type != 0);
+ DBG2(DBG_IMV, "metadata request for %s '%s'",
+ is_dir ? "directory" : "file", pathname);
+ attr = tcg_pts_attr_req_file_meta_create(is_dir, delimiter,
+ pathname);
+ attr->set_noskip_flag(attr, TRUE);
+ attr_list->insert_last(attr_list, attr);
+ }
+ enumerator->destroy(enumerator);
+
+ /* Send Request File Measurement attribute */
+ enumerator = pts_db->create_file_meas_enumerator(pts_db,
+ platform_info);
+ if (!enumerator)
+ {
+ break;
+ }
+ while (enumerator->enumerate(enumerator, &id, &type, &pathname))
+ {
+ is_dir = (type != 0);
+ request_id = attestation_state->add_file_meas_request(
+ attestation_state, id, is_dir);
+ DBG2(DBG_IMV, "measurement request %d for %s '%s'",
+ request_id, is_dir ? "directory" : "file", pathname);
+ attr = tcg_pts_attr_req_file_meas_create(is_dir, request_id,
+ delimiter, pathname);
+ attr->set_noskip_flag(attr, TRUE);
+ attr_list->insert_last(attr_list, attr);
+ }
+ enumerator->destroy(enumerator);
+ break;
+ }
+ case IMV_ATTESTATION_STATE_COMP_EVID:
+ {
+ tcg_pts_attr_req_func_comp_evid_t *attr_cast;
+ enumerator_t *enumerator;
+ pts_component_t *comp;
+ pts_comp_func_name_t *comp_name;
+ chunk_t keyid;
+ int kid, vid, name, qualifier;
+ u_int8_t flags;
+ u_int32_t depth;
+ bool first = TRUE, first_component = TRUE;
+
+ attestation_state->set_handshake_state(attestation_state,
+ IMV_ATTESTATION_STATE_END);
+
+ if (!(pts->get_proto_caps(pts) & PTS_PROTO_CAPS_T) ||
+ !(pts->get_proto_caps(pts) & PTS_PROTO_CAPS_D))
+ {
+ DBG2(DBG_IMV, "PTS-IMC made no TPM available - "
+ "skipping Component Measurements");
+ break;
+ }
+ if (!pts->get_aik_keyid(pts, &keyid))
+ {
+ DBG1(DBG_IMV, "retrieval of AIK keyid failed");
+ return FALSE;
+ }
+ if (!pts_db)
+ {
+ DBG1(DBG_IMV, "pts database not available");
+ break;
+ }
+ if (pts_db->check_aik_keyid(pts_db, keyid, &kid) != SUCCESS)
+ {
+ return FALSE;
+ }
+ enumerator = pts_db->create_comp_evid_enumerator(pts_db, kid);
+ if (!enumerator)
+ {
+ break;
+ }
+ while (enumerator->enumerate(enumerator, &vid, &name,
+ &qualifier, &depth))
+ {
+ if (first)
+ {
+ DBG2(DBG_IMV, "evidence request by");
+ first = FALSE;
+ }
+ comp_name = pts_comp_func_name_create(vid, name, qualifier);
+ comp_name->log(comp_name, " ");
+
+ comp = pts_components->create(pts_components, comp_name,
+ depth, pts_db);
+ if (!comp)
+ {
+ DBG2(DBG_IMV, " not registered: removed from request");
+ comp_name->destroy(comp_name);
+ continue;
+ }
+ attestation_state->add_component(attestation_state, comp);
+ if (first_component)
+ {
+ attr = tcg_pts_attr_req_func_comp_evid_create();
+ attr->set_noskip_flag(attr, TRUE);
+ first_component = FALSE;
+ }
+ flags = comp->get_evidence_flags(comp);
+ /* TODO check flags against negotiated_caps */
+ attr_cast = (tcg_pts_attr_req_func_comp_evid_t *)attr;
+ attr_cast->add_component(attr_cast, flags, depth, comp_name);
+ }
+ enumerator->destroy(enumerator);
+
+ if (attr)
+ {
+ /* Send Request Functional Component Evidence attribute */
+ attr_list->insert_last(attr_list, attr);
+
+ /* Send Generate Attestation Evidence attribute */
+ attr = tcg_pts_attr_gen_attest_evid_create();
+ attr->set_noskip_flag(attr, TRUE);
+ attr_list->insert_last(attr_list, attr);
+
+ attestation_state->set_handshake_state(attestation_state,
+ IMV_ATTESTATION_STATE_EVID_FINAL);
+ }
+ break;
+ }
+ case IMV_ATTESTATION_STATE_EVID_FINAL:
+ attestation_state->set_handshake_state(attestation_state,
+ IMV_ATTESTATION_STATE_END);
+ break;
+ case IMV_ATTESTATION_STATE_END:
+ break;
+ }
+ return TRUE;
+}
diff --git a/src/libpts/plugins/imv_attestation/imv_attestation_build.h b/src/libpts/plugins/imv_attestation/imv_attestation_build.h
new file mode 100644
index 000000000..7f934fd09
--- /dev/null
+++ b/src/libpts/plugins/imv_attestation/imv_attestation_build.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2011 Sansar Choinyambuu
+ * 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_attestation_build_t imv_attestation_build
+ * @{ @ingroup imv_attestation_build
+ */
+
+#ifndef IMV_ATTESTATION_BUILD_H_
+#define IMV_ATTESTATION_BUILD_H_
+
+#include "imv_attestation_state.h"
+
+#include <pa_tnc/pa_tnc_msg.h>
+#include <library.h>
+
+#include <pts/pts_database.h>
+#include <pts/pts_dh_group.h>
+#include <pts/pts_meas_algo.h>
+
+/**
+ * Process a TCG PTS attribute
+ *
+ * @param attr_list list of PA-TNC attriubutes to be built
+ * @param attestation_state attestation state of a given connection
+ * @param supported_algorithms supported PTS measurement algorithms
+ * @param supported_dh_groups supported DH groups
+ * @param pts_db PTS configuration database
+ * @return TRUE if successful
+ */
+bool imv_attestation_build(linked_list_t *attr_list,
+ imv_attestation_state_t *attestation_state,
+ pts_meas_algorithms_t supported_algorithms,
+ pts_dh_group_t supported_dh_groups,
+ pts_database_t *pts_db);
+
+#endif /** IMV_ATTESTATION_BUILD_H_ @}*/
diff --git a/src/libpts/plugins/imv_attestation/imv_attestation_process.c b/src/libpts/plugins/imv_attestation/imv_attestation_process.c
new file mode 100644
index 000000000..a742b6697
--- /dev/null
+++ b/src/libpts/plugins/imv_attestation/imv_attestation_process.c
@@ -0,0 +1,399 @@
+/*
+ * Copyright (C) 2011 Sansar Choinyambuu
+ * 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_attestation_process.h"
+
+#include <ietf/ietf_attr_pa_tnc_error.h>
+
+#include <pts/pts.h>
+
+#include <tcg/tcg_pts_attr_aik.h>
+#include <tcg/tcg_pts_attr_dh_nonce_params_resp.h>
+#include <tcg/tcg_pts_attr_file_meas.h>
+#include <tcg/tcg_pts_attr_meas_algo.h>
+#include <tcg/tcg_pts_attr_proto_caps.h>
+#include <tcg/tcg_pts_attr_simple_comp_evid.h>
+#include <tcg/tcg_pts_attr_simple_evid_final.h>
+#include <tcg/tcg_pts_attr_tpm_version_info.h>
+#include <tcg/tcg_pts_attr_unix_file_meta.h>
+
+#include <debug.h>
+#include <crypto/hashers/hasher.h>
+
+#include <inttypes.h>
+
+bool imv_attestation_process(pa_tnc_attr_t *attr, linked_list_t *attr_list,
+ imv_attestation_state_t *attestation_state,
+ pts_meas_algorithms_t supported_algorithms,
+ pts_dh_group_t supported_dh_groups,
+ pts_database_t *pts_db,
+ credential_manager_t *pts_credmgr)
+{
+ pts_t *pts;
+
+ pts = attestation_state->get_pts(attestation_state);
+
+ switch (attr->get_type(attr))
+ {
+ case TCG_PTS_PROTO_CAPS:
+ {
+ tcg_pts_attr_proto_caps_t *attr_cast;
+ pts_proto_caps_flag_t flags;
+
+ attr_cast = (tcg_pts_attr_proto_caps_t*)attr;
+ flags = attr_cast->get_flags(attr_cast);
+ pts->set_proto_caps(pts, flags);
+ break;
+ }
+ case TCG_PTS_MEAS_ALGO_SELECTION:
+ {
+ tcg_pts_attr_meas_algo_t *attr_cast;
+ pts_meas_algorithms_t selected_algorithm;
+
+ attr_cast = (tcg_pts_attr_meas_algo_t*)attr;
+ selected_algorithm = attr_cast->get_algorithms(attr_cast);
+ if (!(selected_algorithm & supported_algorithms))
+ {
+ DBG1(DBG_IMV, "PTS-IMC selected unsupported"
+ " measurement algorithm");
+ return FALSE;
+ }
+ pts->set_meas_algorithm(pts, selected_algorithm);
+ break;
+ }
+ case TCG_PTS_DH_NONCE_PARAMS_RESP:
+ {
+ tcg_pts_attr_dh_nonce_params_resp_t *attr_cast;
+ int nonce_len, min_nonce_len;
+ pts_dh_group_t dh_group;
+ pts_meas_algorithms_t offered_algorithms, selected_algorithm;
+ chunk_t responder_value, responder_nonce;
+
+ attr_cast = (tcg_pts_attr_dh_nonce_params_resp_t*)attr;
+ responder_nonce = attr_cast->get_responder_nonce(attr_cast);
+
+ /* check compliance of responder nonce length */
+ min_nonce_len = lib->settings->get_int(lib->settings,
+ "libimcv.plugins.imv-attestation.min_nonce_len", 0);
+ nonce_len = responder_nonce.len;
+ if (nonce_len < PTS_MIN_NONCE_LEN ||
+ (min_nonce_len > 0 && nonce_len < min_nonce_len))
+ {
+ attr = pts_dh_nonce_error_create(
+ max(PTS_MIN_NONCE_LEN, min_nonce_len),
+ PTS_MAX_NONCE_LEN);
+ attr_list->insert_last(attr_list, attr);
+ break;
+ }
+
+ dh_group = attr_cast->get_dh_group(attr_cast);
+ if (!(dh_group & supported_dh_groups))
+ {
+ DBG1(DBG_IMV, "PTS-IMC selected unsupported DH group");
+ return FALSE;
+ }
+
+ offered_algorithms = attr_cast->get_hash_algo_set(attr_cast);
+ selected_algorithm = pts_meas_algo_select(supported_algorithms,
+ offered_algorithms);
+ if (selected_algorithm == PTS_MEAS_ALGO_NONE)
+ {
+ attr = pts_hash_alg_error_create(supported_algorithms);
+ attr_list->insert_last(attr_list, attr);
+ break;
+ }
+ pts->set_dh_hash_algorithm(pts, selected_algorithm);
+
+ if (!pts->create_dh_nonce(pts, dh_group, nonce_len))
+ {
+ return FALSE;
+ }
+
+ responder_value = attr_cast->get_responder_value(attr_cast);
+ pts->set_peer_public_value(pts, responder_value,
+ responder_nonce);
+
+ /* Calculate secret assessment value */
+ if (!pts->calculate_secret(pts))
+ {
+ return FALSE;
+ }
+ break;
+ }
+ case TCG_PTS_TPM_VERSION_INFO:
+ {
+ tcg_pts_attr_tpm_version_info_t *attr_cast;
+ chunk_t tpm_version_info;
+
+ attr_cast = (tcg_pts_attr_tpm_version_info_t*)attr;
+ tpm_version_info = attr_cast->get_tpm_version_info(attr_cast);
+ pts->set_tpm_version_info(pts, tpm_version_info);
+ break;
+ }
+ case TCG_PTS_AIK:
+ {
+ tcg_pts_attr_aik_t *attr_cast;
+ certificate_t *aik, *issuer;
+ public_key_t *public;
+ chunk_t keyid;
+ enumerator_t *e;
+ bool trusted = FALSE;
+
+ attr_cast = (tcg_pts_attr_aik_t*)attr;
+ aik = attr_cast->get_aik(attr_cast);
+ if (!aik)
+ {
+ DBG1(DBG_IMV, "AIK unavailable");
+ return FALSE;
+ }
+ if (aik->get_type(aik) == CERT_X509)
+ {
+ public = aik->get_public_key(aik);
+ public->get_fingerprint(public, KEYID_PUBKEY_INFO_SHA1, &keyid);
+ DBG1(DBG_IMV, "verifying AIK certificate with keyid %#B", &keyid);
+ public->destroy(public);
+
+ e = pts_credmgr->create_trusted_enumerator(pts_credmgr,
+ KEY_ANY, aik->get_issuer(aik), FALSE);
+ while (e->enumerate(e, &issuer))
+ {
+ if (aik->issued_by(aik, issuer))
+ {
+ trusted = TRUE;
+ break;
+ }
+ }
+ e->destroy(e);
+ DBG1(DBG_IMV, "AIK certificate is %strusted",
+ trusted ? "" : "not ");
+ if (!trusted)
+ {
+ return FALSE;
+ }
+ }
+ pts->set_aik(pts, aik);
+ break;
+ }
+ case TCG_PTS_FILE_MEAS:
+ {
+ tcg_pts_attr_file_meas_t *attr_cast;
+ u_int16_t request_id;
+ int file_count, file_id;
+ pts_meas_algorithms_t algo;
+ pts_file_meas_t *measurements;
+ char *platform_info;
+ enumerator_t *e_hash;
+ bool is_dir;
+
+ platform_info = pts->get_platform_info(pts);
+ if (!pts_db || !platform_info)
+ {
+ DBG1(DBG_IMV, "%s%s%s not available",
+ (pts_db) ? "" : "pts database",
+ (!pts_db && !platform_info) ? "and" : "",
+ (platform_info) ? "" : "platform info");
+ break;
+ }
+
+ attr_cast = (tcg_pts_attr_file_meas_t*)attr;
+ measurements = attr_cast->get_measurements(attr_cast);
+ algo = pts->get_meas_algorithm(pts);
+ request_id = measurements->get_request_id(measurements);
+ file_count = measurements->get_file_count(measurements);
+
+ DBG1(DBG_IMV, "measurement request %d returned %d file%s:",
+ request_id, file_count, (file_count == 1) ? "":"s");
+
+ if (!attestation_state->check_off_file_meas_request(attestation_state,
+ request_id, &file_id, &is_dir))
+ {
+ DBG1(DBG_IMV, " no entry found for file measurement request %d",
+ request_id);
+ break;
+ }
+
+ /* check hashes from database against measurements */
+ e_hash = pts_db->create_file_hash_enumerator(pts_db,
+ platform_info, algo, file_id, is_dir);
+ if (!measurements->verify(measurements, e_hash, is_dir))
+ {
+ attestation_state->set_measurement_error(attestation_state);
+ }
+ e_hash->destroy(e_hash);
+ break;
+ }
+ case TCG_PTS_UNIX_FILE_META:
+ {
+ tcg_pts_attr_file_meta_t *attr_cast;
+ int file_count;
+ pts_file_meta_t *metadata;
+ pts_file_metadata_t *entry;
+ time_t created, modified, accessed;
+ bool utc = FALSE;
+ enumerator_t *e;
+
+ attr_cast = (tcg_pts_attr_file_meta_t*)attr;
+ metadata = attr_cast->get_metadata(attr_cast);
+ file_count = metadata->get_file_count(metadata);
+
+ DBG1(DBG_IMV, "metadata request returned %d file%s:",
+ file_count, (file_count == 1) ? "":"s");
+
+ e = metadata->create_enumerator(metadata);
+ while (e->enumerate(e, &entry))
+ {
+ DBG1(DBG_IMV, " '%s' (%"PRIu64" bytes)"
+ " owner %"PRIu64", group %"PRIu64", type %N",
+ entry->filename, entry->filesize, entry->owner,
+ entry->group, pts_file_type_names, entry->type);
+
+ created = entry->created;
+ modified = entry->modified;
+ accessed = entry->accessed;
+
+ DBG1(DBG_IMV, " created %T, modified %T, accessed %T",
+ &created, utc, &modified, utc, &accessed, utc);
+ }
+ e->destroy(e);
+ break;
+ }
+ case TCG_PTS_SIMPLE_COMP_EVID:
+ {
+ tcg_pts_attr_simple_comp_evid_t *attr_cast;
+ pts_comp_func_name_t *name;
+ pts_comp_evidence_t *evidence;
+ pts_component_t *comp;
+ u_int32_t depth;
+ status_t status;
+
+ attr_cast = (tcg_pts_attr_simple_comp_evid_t*)attr;
+ evidence = attr_cast->get_comp_evidence(attr_cast);
+ name = evidence->get_comp_func_name(evidence, &depth);
+
+ comp = attestation_state->check_off_component(attestation_state, name);
+ if (!comp)
+ {
+ DBG1(DBG_IMV, " no entry found for component evidence request");
+ break;
+ }
+ status = comp->verify(comp, pts, evidence);
+
+ switch (status)
+ {
+ default:
+ case FAILED:
+ attestation_state->set_measurement_error(attestation_state);
+ comp->destroy(comp);
+ break;
+ case SUCCESS:
+ name->log(name, " successfully measured ");
+ comp->destroy(comp);
+ break;
+ case NEED_MORE:
+ /* re-enter component into list */
+ attestation_state->add_component(attestation_state, comp);
+ }
+ break;
+ }
+ case TCG_PTS_SIMPLE_EVID_FINAL:
+ {
+ tcg_pts_attr_simple_evid_final_t *attr_cast;
+ u_int8_t flags;
+ pts_meas_algorithms_t comp_hash_algorithm;
+ chunk_t pcr_comp, tpm_quote_sig, evid_sig;
+ chunk_t pcr_composite, quote_info;
+ bool use_quote2, use_ver_info;
+
+ attr_cast = (tcg_pts_attr_simple_evid_final_t*)attr;
+ flags = attr_cast->get_quote_info(attr_cast, &comp_hash_algorithm,
+ &pcr_comp, &tpm_quote_sig);
+
+ if (flags != PTS_SIMPLE_EVID_FINAL_NO)
+ {
+ use_quote2 = (flags == PTS_SIMPLE_EVID_FINAL_QUOTE_INFO2 ||
+ flags == PTS_SIMPLE_EVID_FINAL_QUOTE_INFO2_CAP_VER);
+ use_ver_info = (flags == PTS_SIMPLE_EVID_FINAL_QUOTE_INFO2_CAP_VER);
+
+ /* Construct PCR Composite and TPM Quote Info structures */
+ if (!pts->get_quote_info(pts, use_quote2, use_ver_info,
+ comp_hash_algorithm, &pcr_composite, &quote_info))
+ {
+ DBG1(DBG_IMV, "unable to construct TPM Quote Info");
+ return FALSE;
+ }
+
+ if (!chunk_equals(pcr_comp, pcr_composite))
+ {
+ DBG1(DBG_IMV, "received PCR Composite does not match "
+ "constructed one");
+ free(pcr_composite.ptr);
+ free(quote_info.ptr);
+ return FALSE;
+ }
+ DBG2(DBG_IMV, "received PCR Composite matches constructed one");
+ free(pcr_composite.ptr);
+
+ if (!pts->verify_quote_signature(pts, quote_info, tpm_quote_sig))
+ {
+ free(quote_info.ptr);
+ return FALSE;
+ }
+ DBG2(DBG_IMV, "TPM Quote Info signature verification successful");
+ free(quote_info.ptr);
+
+ /* Finalize any pending measurement registrations */
+ attestation_state->check_off_registrations(attestation_state);
+ }
+
+ if (attr_cast->get_evid_sig(attr_cast, &evid_sig))
+ {
+ /** TODO: What to do with Evidence Signature */
+ DBG1(DBG_IMV, "this version of the Attestation IMV can not "
+ "handle Evidence Signatures");
+ }
+ break;
+ }
+
+ /* TODO: Not implemented yet */
+ case TCG_PTS_INTEG_MEAS_LOG:
+ /* Attributes using XML */
+ case TCG_PTS_TEMPL_REF_MANI_SET_META:
+ case TCG_PTS_VERIFICATION_RESULT:
+ case TCG_PTS_INTEG_REPORT:
+ /* On Windows only*/
+ case TCG_PTS_WIN_FILE_META:
+ case TCG_PTS_REGISTRY_VALUE:
+ /* Received on IMC side only*/
+ case TCG_PTS_REQ_PROTO_CAPS:
+ case TCG_PTS_DH_NONCE_PARAMS_REQ:
+ case TCG_PTS_DH_NONCE_FINISH:
+ case TCG_PTS_MEAS_ALGO:
+ case TCG_PTS_GET_TPM_VERSION_INFO:
+ case TCG_PTS_REQ_TEMPL_REF_MANI_SET_META:
+ case TCG_PTS_UPDATE_TEMPL_REF_MANI:
+ case TCG_PTS_GET_AIK:
+ case TCG_PTS_REQ_FUNC_COMP_EVID:
+ case TCG_PTS_GEN_ATTEST_EVID:
+ case TCG_PTS_REQ_FILE_META:
+ case TCG_PTS_REQ_FILE_MEAS:
+ case TCG_PTS_REQ_INTEG_MEAS_LOG:
+ default:
+ DBG1(DBG_IMV, "received unsupported attribute '%N'",
+ tcg_attr_names, attr->get_type(attr));
+ break;
+ }
+ return TRUE;
+}
+
diff --git a/src/libpts/plugins/imv_attestation/imv_attestation_process.h b/src/libpts/plugins/imv_attestation/imv_attestation_process.h
new file mode 100644
index 000000000..4d4eeefbb
--- /dev/null
+++ b/src/libpts/plugins/imv_attestation/imv_attestation_process.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2011 Sansar Choinyambuu
+ * 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_attestation_process_t imv_attestation_process
+ * @{ @ingroup imv_attestation_process
+ */
+
+#ifndef IMV_ATTESTATION_PROCESS_H_
+#define IMV_ATTESTATION_PROCESS_H_
+
+#include "imv_attestation_state.h"
+
+#include <library.h>
+#include <utils/linked_list.h>
+#include <credentials/credential_manager.h>
+#include <crypto/hashers/hasher.h>
+
+#include <pa_tnc/pa_tnc_attr.h>
+
+#include <pts/pts_database.h>
+#include <pts/pts_dh_group.h>
+#include <pts/pts_meas_algo.h>
+
+/**
+ * Process a TCG PTS attribute
+ *
+ * @param attr PA-TNC attribute to be processed
+ * @param attr_list list with PA-TNC error attributes
+ * @param attestation_state attestation state of a given connection
+ * @param supported_algorithms supported PTS measurement algorithms
+ * @param supported_dh_groups supported DH groups
+ * @param pts_db PTS configuration database
+ * @param pts_credmgr PTS credential manager
+ * @return TRUE if successful
+ */
+bool imv_attestation_process(pa_tnc_attr_t *attr, linked_list_t *attr_list,
+ imv_attestation_state_t *attestation_state,
+ pts_meas_algorithms_t supported_algorithms,
+ pts_dh_group_t supported_dh_groups,
+ pts_database_t *pts_db,
+ credential_manager_t *pts_credmgr);
+
+#endif /** IMV_ATTESTATION_PROCESS_H_ @}*/
diff --git a/src/libimcv/plugins/imv_attestation/imv_attestation_state.c b/src/libpts/plugins/imv_attestation/imv_attestation_state.c
index 6305dac2f..a58fd3ec3 100644
--- a/src/libimcv/plugins/imv_attestation/imv_attestation_state.c
+++ b/src/libpts/plugins/imv_attestation/imv_attestation_state.c
@@ -20,12 +20,12 @@
#include <debug.h>
typedef struct private_imv_attestation_state_t private_imv_attestation_state_t;
-typedef struct request_t request_t;
+typedef struct file_meas_request_t file_meas_request_t;
/**
* PTS File/Directory Measurement request entry
*/
-struct request_t {
+struct file_meas_request_t {
u_int16_t id;
int file_id;
bool is_dir;
@@ -52,6 +52,16 @@ struct private_imv_attestation_state_t {
TNC_ConnectionState state;
/**
+ * Does the TNCCS connection support long message types?
+ */
+ bool has_long;
+
+ /**
+ * Does the TNCCS connection support exclusive delivery?
+ */
+ bool has_excl;
+
+ /**
* IMV Attestation handshake state
*/
imv_attestation_handshake_state_t handshake_state;
@@ -67,20 +77,30 @@ struct private_imv_attestation_state_t {
TNC_IMV_Evaluation_Result eval;
/**
- * Request counter
+ * File Measurement Request counter
*/
- u_int16_t request_counter;
+ u_int16_t file_meas_request_counter;
/**
* List of PTS File/Directory Measurement requests
*/
- linked_list_t *requests;
+ linked_list_t *file_meas_requests;
+
+ /**
+ * List of Functional Components
+ */
+ linked_list_t *components;
/**
* PTS object
*/
pts_t *pts;
+ /**
+ * Measurement error
+ */
+ bool measurement_error;
+
};
typedef struct entry_t entry_t;
@@ -97,9 +117,12 @@ struct entry_t {
* Table of multi-lingual reason string entries
*/
static entry_t reasons[] = {
- { "en", "IMC Attestation Measurement/s of requested file didn't match" },
- { "mn", "IMC Attestation Шалгахаар тохируулсан файлуудын хэмжилтүүд таарсангүй" },
- { "de", "IMC Attestation Messung/en von angefordeten Datein stimmt nicht überein" },
+ { "en", "IMV Attestation: Incorrect/pending file measurement/component"
+ " evidence or invalid TPM Quote signature received" },
+ { "mn", "IMV Attestation: Буруу/хүлээгдэж байгаа файл/компонент хэмжилт "
+ "эсвэл буруу TPM Quote гарын үсэг" },
+ { "de", "IMV Attestation: Falsche/Fehlende Dateimessung/Komponenten Beweis "
+ "oder ungültige TPM Quote Unterschrift ist erhalten" },
};
METHOD(imv_state_t, get_connection_id, TNC_ConnectionID,
@@ -108,6 +131,25 @@ METHOD(imv_state_t, get_connection_id, TNC_ConnectionID,
return this->connection_id;
}
+METHOD(imv_state_t, has_long, bool,
+ private_imv_attestation_state_t *this)
+{
+ return this->has_long;
+}
+
+METHOD(imv_state_t, has_excl, bool,
+ private_imv_attestation_state_t *this)
+{
+ return this->has_excl;
+}
+
+METHOD(imv_state_t, set_flags, void,
+ private_imv_attestation_state_t *this, bool has_long, bool has_excl)
+{
+ this->has_long = has_long;
+ this->has_excl = has_excl;
+}
+
METHOD(imv_state_t, change_state, void,
private_imv_attestation_state_t *this, TNC_ConnectionState new_state)
{
@@ -177,19 +219,22 @@ METHOD(imv_state_t, get_reason_string, bool,
METHOD(imv_state_t, destroy, void,
private_imv_attestation_state_t *this)
{
- this->requests->destroy_function(this->requests, free);
+ this->file_meas_requests->destroy_function(this->file_meas_requests, free);
+ this->components->destroy_offset(this->components,
+ offsetof(pts_component_t, destroy));
this->pts->destroy(this->pts);
free(this);
}
-METHOD(imv_attestation_state_t, get_handshake_state, imv_attestation_handshake_state_t,
- private_imv_attestation_state_t *this)
+METHOD(imv_attestation_state_t, get_handshake_state,
+ imv_attestation_handshake_state_t, private_imv_attestation_state_t *this)
{
return this->handshake_state;
}
METHOD(imv_attestation_state_t, set_handshake_state, void,
- private_imv_attestation_state_t *this, imv_attestation_handshake_state_t new_state)
+ private_imv_attestation_state_t *this,
+ imv_attestation_handshake_state_t new_state)
{
this->handshake_state = new_state;
}
@@ -200,29 +245,29 @@ METHOD(imv_attestation_state_t, get_pts, pts_t*,
return this->pts;
}
-METHOD(imv_attestation_state_t, add_request, u_int16_t,
+METHOD(imv_attestation_state_t, add_file_meas_request, u_int16_t,
private_imv_attestation_state_t *this, int file_id, bool is_dir)
{
- request_t *request;
+ file_meas_request_t *request;
- request = malloc_thing(request_t);
- request->id = ++this->request_counter;
+ request = malloc_thing(file_meas_request_t);
+ request->id = ++this->file_meas_request_counter;
request->file_id = file_id;
request->is_dir = is_dir;
- this->requests->insert_last(this->requests, request);
+ this->file_meas_requests->insert_last(this->file_meas_requests, request);
- return this->request_counter;
+ return this->file_meas_request_counter;
}
-METHOD(imv_attestation_state_t, check_off_request, bool,
+METHOD(imv_attestation_state_t, check_off_file_meas_request, bool,
private_imv_attestation_state_t *this, u_int16_t id, int *file_id,
bool* is_dir)
{
enumerator_t *enumerator;
- request_t *request;
+ file_meas_request_t *request;
bool found = FALSE;
- enumerator = this->requests->create_enumerator(this->requests);
+ enumerator = this->file_meas_requests->create_enumerator(this->file_meas_requests);
while (enumerator->enumerate(enumerator, &request))
{
if (request->id == id)
@@ -230,7 +275,7 @@ METHOD(imv_attestation_state_t, check_off_request, bool,
found = TRUE;
*file_id = request->file_id;
*is_dir = request->is_dir;
- this->requests->remove_at(this->requests, enumerator);
+ this->file_meas_requests->remove_at(this->file_meas_requests, enumerator);
free(request);
break;
}
@@ -239,10 +284,72 @@ METHOD(imv_attestation_state_t, check_off_request, bool,
return found;
}
-METHOD(imv_attestation_state_t, get_request_count, int,
+METHOD(imv_attestation_state_t, get_file_meas_request_count, int,
+ private_imv_attestation_state_t *this)
+{
+ return this->file_meas_requests->get_count(this->file_meas_requests);
+}
+
+METHOD(imv_attestation_state_t, add_component, void,
+ private_imv_attestation_state_t *this, pts_component_t *entry)
+{
+ this->components->insert_last(this->components, entry);
+}
+
+METHOD(imv_attestation_state_t, check_off_component, pts_component_t*,
+ private_imv_attestation_state_t *this, pts_comp_func_name_t *name)
+{
+ enumerator_t *enumerator;
+ pts_component_t *entry, *found = NULL;
+
+ enumerator = this->components->create_enumerator(this->components);
+ while (enumerator->enumerate(enumerator, &entry))
+ {
+ if (name->equals(name, entry->get_comp_func_name(entry)))
+ {
+ found = entry;
+ this->components->remove_at(this->components, enumerator);
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ return found;
+}
+
+METHOD(imv_attestation_state_t, check_off_registrations, void,
+ private_imv_attestation_state_t *this)
+{
+ enumerator_t *enumerator;
+ pts_component_t *entry;
+
+ enumerator = this->components->create_enumerator(this->components);
+ while (enumerator->enumerate(enumerator, &entry))
+ {
+ if (entry->check_off_registrations(entry))
+ {
+ this->components->remove_at(this->components, enumerator);
+ entry->destroy(entry);
+ }
+ }
+ enumerator->destroy(enumerator);
+}
+
+METHOD(imv_attestation_state_t, get_component_count, int,
+ private_imv_attestation_state_t *this)
+{
+ return this->components->get_count(this->components);
+}
+
+METHOD(imv_attestation_state_t, get_measurement_error, bool,
+ private_imv_attestation_state_t *this)
+{
+ return this->measurement_error;
+}
+
+METHOD(imv_attestation_state_t, set_measurement_error, void,
private_imv_attestation_state_t *this)
{
- return this->requests->get_count(this->requests);
+ this->measurement_error = TRUE;
}
/**
@@ -257,6 +364,9 @@ imv_state_t *imv_attestation_state_create(TNC_ConnectionID connection_id)
.public = {
.interface = {
.get_connection_id = _get_connection_id,
+ .has_long = _has_long,
+ .has_excl = _has_excl,
+ .set_flags = _set_flags,
.change_state = _change_state,
.get_recommendation = _get_recommendation,
.set_recommendation = _set_recommendation,
@@ -266,16 +376,23 @@ imv_state_t *imv_attestation_state_create(TNC_ConnectionID connection_id)
.get_handshake_state = _get_handshake_state,
.set_handshake_state = _set_handshake_state,
.get_pts = _get_pts,
- .add_request = _add_request,
- .check_off_request = _check_off_request,
- .get_request_count = _get_request_count,
+ .add_file_meas_request = _add_file_meas_request,
+ .check_off_file_meas_request = _check_off_file_meas_request,
+ .get_file_meas_request_count = _get_file_meas_request_count,
+ .add_component = _add_component,
+ .check_off_component = _check_off_component,
+ .check_off_registrations = _check_off_registrations,
+ .get_component_count = _get_component_count,
+ .get_measurement_error = _get_measurement_error,
+ .set_measurement_error = _set_measurement_error,
},
.connection_id = connection_id,
.state = TNC_CONNECTION_STATE_CREATE,
.handshake_state = IMV_ATTESTATION_STATE_INIT,
.rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION,
.eval = TNC_IMV_EVALUATION_RESULT_DONT_KNOW,
- .requests = linked_list_create(),
+ .file_meas_requests = linked_list_create(),
+ .components = linked_list_create(),
.pts = pts_create(FALSE),
);
diff --git a/src/libimcv/plugins/imv_attestation/imv_attestation_state.h b/src/libpts/plugins/imv_attestation/imv_attestation_state.h
index a79fc91cc..0e2c04da4 100644
--- a/src/libimcv/plugins/imv_attestation/imv_attestation_state.h
+++ b/src/libpts/plugins/imv_attestation/imv_attestation_state.h
@@ -24,6 +24,7 @@
#include <imv/imv_state.h>
#include <pts/pts.h>
+#include <pts/components/pts_component.h>
#include <library.h>
typedef struct imv_attestation_state_t imv_attestation_state_t;
@@ -34,9 +35,11 @@ typedef enum imv_attestation_handshake_state_t imv_attestation_handshake_state_t
*/
enum imv_attestation_handshake_state_t {
IMV_ATTESTATION_STATE_INIT,
+ IMV_ATTESTATION_STATE_NONCE_REQ,
+ IMV_ATTESTATION_STATE_TPM_INIT,
IMV_ATTESTATION_STATE_MEAS,
IMV_ATTESTATION_STATE_COMP_EVID,
- IMV_ATTESTATION_STATE_IML,
+ IMV_ATTESTATION_STATE_EVID_FINAL,
IMV_ATTESTATION_STATE_END,
};
@@ -55,7 +58,8 @@ struct imv_attestation_state_t {
*
* @return the handshake state of IMV
*/
- imv_attestation_handshake_state_t (*get_handshake_state)(imv_attestation_state_t *this);
+ imv_attestation_handshake_state_t (*get_handshake_state)(
+ imv_attestation_state_t *this);
/**
* Set state of the handshake
@@ -79,15 +83,15 @@ struct imv_attestation_state_t {
* @param is_dir TRUE if directory
* @return unique request ID
*/
- u_int16_t (*add_request)(imv_attestation_state_t *this, int file_id,
- bool is_dir);
+ u_int16_t (*add_file_meas_request)(imv_attestation_state_t *this,
+ int file_id, bool is_dir);
/**
* Returns the number of pending file/directory measurement requests
*
* @return number of pending requests
*/
- int (*get_request_count)(imv_attestation_state_t *this);
+ int (*get_file_meas_request_count)(imv_attestation_state_t *this);
/**
* Check for presence of request_id and if found remove it from the list
@@ -97,8 +101,48 @@ struct imv_attestation_state_t {
* @param is_dir return TRUE if request was for a directory
* @return TRUE if request ID found, FALSE otherwise
*/
- bool (*check_off_request)(imv_attestation_state_t *this, u_int16_t id,
- int *file_id, bool *is_dir);
+ bool (*check_off_file_meas_request)(imv_attestation_state_t *this,
+ u_int16_t id, int *file_id, bool *is_dir);
+
+ /**
+ * Add an entry to the list of Functional Components waiting for evidence
+ *
+ * @param entry Functional Component
+ */
+ void (*add_component)(imv_attestation_state_t *this, pts_component_t *entry);
+
+ /**
+ * Returns the number of Functional Component waiting for evidence
+ *
+ * @return Number of waiting Functional Components
+ */
+ int (*get_component_count)(imv_attestation_state_t *this);
+
+ /**
+ * Check for presence of Functional Component and remove and return it
+ *
+ * @param name Name of the requested Functional Component
+ * @return Functional Component if found, NULL otherwise
+ */
+ pts_component_t* (*check_off_component)(imv_attestation_state_t *this,
+ pts_comp_func_name_t *name);
+
+ /**
+ * Tell the Functional Components to finalize any measurement registrations
+ */
+ void (*check_off_registrations)(imv_attestation_state_t *this);
+
+ /**
+ * Indicates if a file measurement error occurred
+ *
+ * @return TRUE in case of measurement error
+ */
+ bool (*get_measurement_error)(imv_attestation_state_t *this);
+
+ /**
+ * Call if a file measurement error is encountered
+ */
+ void (*set_measurement_error)(imv_attestation_state_t *this);
};
diff --git a/src/libpts/plugins/imv_attestation/tables.sql b/src/libpts/plugins/imv_attestation/tables.sql
new file mode 100644
index 000000000..703557a07
--- /dev/null
+++ b/src/libpts/plugins/imv_attestation/tables.sql
@@ -0,0 +1,82 @@
+/* PTS SQLite database */
+
+DROP TABLE IF EXISTS files;
+CREATE TABLE files (
+ id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+ type INTEGER NOT NULL,
+ path TEXT NOT NULL
+);
+
+DROP TABLE IF EXISTS products;
+CREATE TABLE products (
+ id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+ name TEXT NOT NULL
+);
+DROP INDEX IF EXISTS products_name;
+CREATE INDEX products_name ON products (
+ name
+);
+
+DROP TABLE IF EXISTS product_file;
+CREATE TABLE product_file (
+ product INTEGER NOT NULL,
+ file INTEGER NOT NULL,
+ measurement INTEGER DEFAULT 0,
+ metadata INTEGER DEFAULT 0,
+ PRIMARY KEY (product, file)
+);
+
+DROP TABLE IF EXISTS file_hashes;
+CREATE TABLE file_hashes (
+ file INTEGER NOT NULL,
+ directory INTEGER DEFAULT 0,
+ product INTEGER NOT NULL,
+ algo INTEGER NOT NULL,
+ hash BLOB NOT NULL,
+ PRIMARY KEY(file, directory, product, algo)
+);
+
+DROP TABLE IF EXISTS keys;
+CREATE TABLE keys (
+ id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+ keyid BLOB NOT NULL,
+ owner TEXT NOT NULL
+);
+DROP INDEX IF EXISTS keys_keyid;
+CREATE INDEX keys_keyid ON keys (
+ keyid
+);
+DROP INDEX IF EXISTS keys_owner;
+CREATE INDEX keys_owner ON keys (
+ owner
+);
+
+DROP TABLE IF EXISTS components;
+CREATE TABLE components (
+ id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+ vendor_id INTEGER NOT NULL,
+ name INTEGER NOT NULL,
+ qualifier INTEGER DEFAULT 0
+);
+
+
+DROP TABLE IF EXISTS key_component;
+CREATE TABLE key_component (
+ key INTEGER NOT NULL,
+ component INTEGER NOT NULL,
+ depth INTEGER DEFAULT 0,
+ seq_no INTEGER DEFAULT 0,
+ PRIMARY KEY (key, component)
+);
+
+
+DROP TABLE IF EXISTS component_hashes;
+CREATE TABLE component_hashes (
+ component INTEGER NOT NULL,
+ key INTEGER NOT NULL,
+ seq_no INTEGER NOT NULL,
+ pcr INTEGER NOT NULL,
+ algo INTEGER NOT NULL,
+ hash BLOB NOT NULL,
+ PRIMARY KEY(component, key, seq_no, algo)
+);
diff --git a/src/libpts/pts/components/ita/ita_comp_func_name.c b/src/libpts/pts/components/ita/ita_comp_func_name.c
new file mode 100644
index 000000000..a593281ba
--- /dev/null
+++ b/src/libpts/pts/components/ita/ita_comp_func_name.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2011 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 "ita_comp_func_name.h"
+
+char pts_ita_qualifier_flag_names[] = { 'K', 'S' };
+
+ENUM_BEGIN(pts_ita_qualifier_type_names, PTS_ITA_QUALIFIER_TYPE_UNKNOWN,
+ PTS_ITA_QUALIFIER_TYPE_TNC,
+ "Unknown",
+ "Trusted Platform",
+ "Operating System",
+ "Graphical User Interface",
+ "Application",
+ "Networking",
+ "Library",
+ "TNC Defined Component"
+);
+ENUM_NEXT(pts_ita_qualifier_type_names, PTS_ITA_QUALIFIER_TYPE_ALL,
+ PTS_ITA_QUALIFIER_TYPE_ALL,
+ PTS_ITA_QUALIFIER_TYPE_TNC,
+ "All Matching Components"
+);
+ENUM_END(pts_ita_qualifier_type_names, PTS_ITA_QUALIFIER_TYPE_ALL);
+
+ENUM(pts_ita_comp_func_names, PTS_ITA_COMP_FUNC_NAME_IGNORE,
+ PTS_ITA_COMP_FUNC_NAME_IMA,
+ "Ignore",
+ "Trusted GRUB Boot Loader",
+ "Trusted Boot",
+ "Linux IMA"
+);
+
diff --git a/src/libpts/pts/components/ita/ita_comp_func_name.h b/src/libpts/pts/components/ita/ita_comp_func_name.h
new file mode 100644
index 000000000..eb2f363f3
--- /dev/null
+++ b/src/libpts/pts/components/ita/ita_comp_func_name.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2011 Sansar Choinyambuu
+ * 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 pts_ita_comp_func_name pts_ita_comp_func_name
+ * @{ @ingroup pts
+ */
+
+#ifndef PTS_ITA_COMP_FUNC_NAME_H_
+#define PTS_ITA_COMP_FUNC_NAME_H_
+
+typedef enum pts_ita_qualifier_type_t pts_ita_qualifier_type_t;
+typedef enum pts_ita_comp_func_name_t pts_ita_comp_func_name_t;
+
+#include <library.h>
+
+/**
+ * PTS Component Functional Name Qualifier Flags for the ITA namespace
+ */
+#define PTS_ITA_QUALIFIER_FLAG_KERNEL (1<<5)
+#define PTS_ITA_QUALIFIER_FLAG_SUB (1<<4)
+
+extern char pts_ita_qualifier_flag_names[];
+
+/**
+ * Size of the PTS Component Functional Name Qualifier Type field
+ */
+#define PTS_ITA_QUALIFIER_TYPE_SIZE 4
+
+/**
+ * PTS Component Functional Name Qualifier Types for the ITA namespace
+ * equal to section 5.2 of PTS Protocol: Binding to TNC IF-M Specification
+ */
+enum pts_ita_qualifier_type_t {
+ /** Unknown */
+ PTS_ITA_QUALIFIER_TYPE_UNKNOWN = 0x0,
+ /** Trusted Platform */
+ PTS_ITA_QUALIFIER_TYPE_TRUSTED = 0x1,
+ /** Operating System */
+ PTS_ITA_QUALIFIER_TYPE_OS = 0x2,
+ /** Graphical User Interface */
+ PTS_ITA_QUALIFIER_TYPE_GUI = 0x3,
+ /** Application */
+ PTS_ITA_QUALIFIER_TYPE_APP = 0x4,
+ /** Networking */
+ PTS_ITA_QUALIFIER_TYPE_NET = 0x5,
+ /** Library */
+ PTS_ITA_QUALIFIER_TYPE_LIB = 0x6,
+ /** TNC Defined Component */
+ PTS_ITA_QUALIFIER_TYPE_TNC = 0x7,
+ /** All Matching Components */
+ PTS_ITA_QUALIFIER_TYPE_ALL = 0xF,
+};
+
+extern enum_name_t *pts_ita_qualifier_type_names;
+
+/**
+ * PTS Component Functional Name Binary Enumeration for the ITA namespace
+ */
+enum pts_ita_comp_func_name_t {
+ /** Ignore */
+ PTS_ITA_COMP_FUNC_NAME_IGNORE = 0x0000,
+ /** Trusted GRUB Boot Loader */
+ PTS_ITA_COMP_FUNC_NAME_TGRUB = 0x0001,
+ /** Trusted Boot */
+ PTS_ITA_COMP_FUNC_NAME_TBOOT = 0x0002,
+ /** Linux Integrity Measurement Architecture */
+ PTS_ITA_COMP_FUNC_NAME_IMA = 0x0003,
+};
+
+extern enum_name_t *pts_ita_comp_func_names;
+
+#endif /** PTS_ITA_COMP_FUNC_NAME_H_ @}*/
diff --git a/src/libpts/pts/components/ita/ita_comp_ima.c b/src/libpts/pts/components/ita/ita_comp_ima.c
new file mode 100644
index 000000000..a7da76651
--- /dev/null
+++ b/src/libpts/pts/components/ita/ita_comp_ima.c
@@ -0,0 +1,439 @@
+/*
+ * Copyright (C) 2011 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 "ita_comp_ima.h"
+#include "ita_comp_func_name.h"
+
+#include "libpts.h"
+#include "pts/components/pts_component.h"
+
+#include <debug.h>
+#include <pen/pen.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#define IMA_SECURITY_DIR "/sys/kernel/security/tpm0/"
+#define IMA_BIOS_MEASUREMENT_PATH IMA_SECURITY_DIR "binary_bios_measurements"
+#define IMA_PCR_MAX 16
+
+typedef struct pts_ita_comp_ima_t pts_ita_comp_ima_t;
+
+/**
+ * Private data of a pts_ita_comp_ima_t object.
+ *
+ */
+struct pts_ita_comp_ima_t {
+
+ /**
+ * Public pts_component_t interface.
+ */
+ pts_component_t public;
+
+ /**
+ * Component Functional Name
+ */
+ pts_comp_func_name_t *name;
+
+ /**
+ * AIK keyid
+ */
+ chunk_t keyid;
+
+ /**
+ * Sub-component depth
+ */
+ u_int32_t depth;
+
+ /**
+ * PTS measurement database
+ */
+ pts_database_t *pts_db;
+
+ /**
+ * Primary key for Component Functional Name database entry
+ */
+ int cid;
+
+ /**
+ * Primary key for AIK database entry
+ */
+ int kid;
+
+ /**
+ * Component is registering measurements
+ */
+ bool is_registering;
+
+ /**
+ * IMA BIOS measurement time
+ */
+ time_t bios_measurement_time;
+
+ /**
+ * IMA BIOS measurements
+ */
+ linked_list_t *list;
+
+ /**
+ * Expected measurement count
+ */
+ int count;
+
+ /**
+ * Measurement sequence number
+ */
+ int seq_no;
+
+ /**
+ * Shadow PCR registers
+ */
+ chunk_t pcrs[IMA_PCR_MAX];
+};
+
+typedef struct entry_t entry_t;
+
+/**
+ * Linux IMA measurement entry
+ */
+struct entry_t {
+
+ /**
+ * PCR register
+ */
+ u_int32_t pcr;
+
+ /**
+ * SHA1 measurement hash
+ */
+ chunk_t measurement;
+};
+
+/**
+ * Free an entry_t object
+ */
+static void free_entry(entry_t *this)
+{
+ free(this->measurement.ptr);
+ free(this);
+}
+
+/**
+ * Load a PCR measurement file and determine the creation date
+ */
+static bool load_measurements(char *file, linked_list_t *list, time_t *created)
+{
+ u_int32_t pcr, num, len;
+ entry_t *entry;
+ struct stat st;
+ ssize_t res;
+ int fd;
+
+ fd = open(file, O_RDONLY);
+ if (fd == -1)
+ {
+ DBG1(DBG_PTS, " opening '%s' failed: %s", file, strerror(errno));
+ return FALSE;
+ }
+
+ if (fstat(fd, &st) == -1)
+ {
+ DBG1(DBG_PTS, " getting statistics of '%s' failed: %s", file,
+ strerror(errno));
+ close(fd);
+ return FALSE;
+ }
+ *created = st.st_ctime;
+
+ while (TRUE)
+ {
+ res = read(fd, &pcr, 4);
+ if (res == 0)
+ {
+ DBG2(DBG_PTS, "loaded bios measurements '%s' (%d entries)",
+ file, list->get_count(list));
+ close(fd);
+ return TRUE;
+ }
+
+ entry = malloc_thing(entry_t);
+ entry->pcr = pcr;
+ entry->measurement = chunk_alloc(HASH_SIZE_SHA1);
+
+ if (res != 4)
+ {
+ break;
+ }
+ if (read(fd, &num, 4) != 4)
+ {
+ break;
+ }
+ if (read(fd, entry->measurement.ptr, HASH_SIZE_SHA1) != HASH_SIZE_SHA1)
+ {
+ break;
+ }
+ if (read(fd, &len, 4) != 4)
+ {
+ break;
+ }
+ if (lseek(fd, len, SEEK_CUR) == -1)
+ {
+ break;
+ }
+ list->insert_last(list, entry);
+ }
+
+ DBG1(DBG_PTS, "loading bios measurements '%s' failed: %s",
+ file, strerror(errno));
+ close(fd);
+ return FALSE;
+}
+
+METHOD(pts_component_t, get_comp_func_name, pts_comp_func_name_t*,
+ pts_ita_comp_ima_t *this)
+{
+ return this->name;
+}
+
+METHOD(pts_component_t, get_evidence_flags, u_int8_t,
+ pts_ita_comp_ima_t *this)
+{
+ return PTS_REQ_FUNC_COMP_EVID_PCR;
+}
+
+METHOD(pts_component_t, get_depth, u_int32_t,
+ pts_ita_comp_ima_t *this)
+{
+ return this->depth;
+}
+
+METHOD(pts_component_t, measure, status_t,
+ pts_ita_comp_ima_t *this, pts_t *pts, pts_comp_evidence_t **evidence)
+{
+ pts_comp_evidence_t *evid;
+ chunk_t pcr_before, pcr_after;
+ pts_pcr_transform_t pcr_transform;
+ pts_meas_algorithms_t hash_algo;
+ size_t pcr_len;
+ entry_t *entry;
+ hasher_t *hasher;
+
+ hash_algo = PTS_MEAS_ALGO_SHA1;
+ pcr_len = pts->get_pcr_len(pts);
+ pcr_transform = pts_meas_algo_to_pcr_transform(hash_algo, pcr_len);
+
+ if (this->list->get_count(this->list) == 0)
+ {
+ if (!load_measurements(IMA_BIOS_MEASUREMENT_PATH, this->list,
+ &this->bios_measurement_time))
+ {
+ return FAILED;
+ }
+ }
+
+ if (this->list->remove_first(this->list, (void**)&entry) != SUCCESS)
+ {
+ DBG1(DBG_PTS, "could not retrieve measurement entry");
+ return FAILED;
+ }
+
+ pcr_before = chunk_clone(this->pcrs[entry->pcr]);
+
+ hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
+ hasher->get_hash(hasher, pcr_before, NULL);
+ hasher->get_hash(hasher, entry->measurement, this->pcrs[entry->pcr].ptr);
+ hasher->destroy(hasher);
+
+ pcr_after = chunk_clone(this->pcrs[entry->pcr]);
+
+ evid = *evidence = pts_comp_evidence_create(this->name->clone(this->name),
+ this->depth, entry->pcr, hash_algo, pcr_transform,
+ this->bios_measurement_time, entry->measurement);
+ evid->set_pcr_info(evid, pcr_before, pcr_after);
+
+ free(entry);
+
+ return (this->list->get_count(this->list)) ? NEED_MORE : SUCCESS;
+}
+
+METHOD(pts_component_t, verify, status_t,
+ pts_ita_comp_ima_t *this, pts_t *pts, pts_comp_evidence_t *evidence)
+{
+ bool has_pcr_info;
+ u_int32_t extended_pcr, vid, name;
+ enum_name_t *names;
+ pts_meas_algorithms_t algo;
+ pts_pcr_transform_t transform;
+ time_t measurement_time;
+ chunk_t measurement, pcr_before, pcr_after;
+
+ measurement = evidence->get_measurement(evidence, &extended_pcr,
+ &algo, &transform, &measurement_time);
+
+ if (!this->keyid.ptr)
+ {
+ if (!pts->get_aik_keyid(pts, &this->keyid))
+ {
+ return FAILED;
+ }
+ this->keyid = chunk_clone(this->keyid);
+
+ if (!this->pts_db)
+ {
+ DBG1(DBG_PTS, "pts database not available");
+ return FAILED;
+ }
+ if (this->pts_db->get_comp_measurement_count(this->pts_db,
+ this->name, this->keyid, algo,
+ &this->cid, &this->kid, &this->count) != SUCCESS)
+ {
+ return FAILED;
+ }
+ vid = this->name->get_vendor_id(this->name);
+ name = this->name->get_name(this->name);
+ names = pts_components->get_comp_func_names(pts_components, vid);
+
+ if (this->count)
+ {
+ DBG1(DBG_PTS, "checking %d %N '%N' functional component evidence "
+ "measurements", this->count, pen_names, vid, names, name);
+ }
+ else
+ {
+ DBG1(DBG_PTS, "registering %N '%N' functional component evidence "
+ "measurements", pen_names, vid, names, name);
+ this->is_registering = TRUE;
+ }
+ }
+
+ if (this->is_registering)
+ {
+ if (this->pts_db->insert_comp_measurement(this->pts_db, measurement,
+ this->cid, this->kid, ++this->seq_no,
+ extended_pcr, algo) != SUCCESS)
+ {
+ return FAILED;
+ }
+ this->count = this->seq_no + 1;
+ }
+ else
+ {
+ if (this->pts_db->check_comp_measurement(this->pts_db, measurement,
+ this->cid, this->kid, ++this->seq_no,
+ extended_pcr, algo) != SUCCESS)
+ {
+ return FAILED;
+ }
+ }
+
+ has_pcr_info = evidence->get_pcr_info(evidence, &pcr_before, &pcr_after);
+ if (has_pcr_info)
+ {
+ if (!pts->add_pcr(pts, extended_pcr, pcr_before, pcr_after))
+ {
+ return FAILED;
+ }
+ }
+
+ return (this->seq_no < this->count) ? NEED_MORE : SUCCESS;
+}
+
+METHOD(pts_component_t, check_off_registrations, bool,
+ pts_ita_comp_ima_t *this)
+{
+ u_int32_t vid, name;
+ enum_name_t *names;
+
+ if (!this->is_registering)
+ {
+ return FALSE;
+ }
+
+ /* Finalize registration */
+ this->is_registering = FALSE;
+
+ vid = this->name->get_vendor_id(this->name);
+ name = this->name->get_name(this->name);
+ names = pts_components->get_comp_func_names(pts_components, vid);
+ DBG1(DBG_PTS, "registered %d %N '%N' functional component evidence "
+ "measurements", this->seq_no, pen_names, vid, names, name);
+ return TRUE;
+}
+
+METHOD(pts_component_t, destroy, void,
+ pts_ita_comp_ima_t *this)
+{
+ int i, count;
+ u_int32_t vid, name;
+ enum_name_t *names;
+
+ for (i = 0; i < IMA_PCR_MAX; i++)
+ {
+ free(this->pcrs[i].ptr);
+ }
+ if (this->is_registering)
+ {
+ count = this->pts_db->delete_comp_measurements(this->pts_db,
+ this->cid, this->kid);
+ vid = this->name->get_vendor_id(this->name);
+ name = this->name->get_name(this->name);
+ names = pts_components->get_comp_func_names(pts_components, vid);
+ DBG1(DBG_PTS, "deleted %d registered %N '%N' functional component "
+ "evidence measurements", count, pen_names, vid, names, name);
+ }
+ this->list->destroy_function(this->list, (void *)free_entry);
+ this->name->destroy(this->name);
+ free(this->keyid.ptr);
+ free(this);
+}
+
+/**
+ * See header
+ */
+pts_component_t *pts_ita_comp_ima_create(u_int8_t qualifier, u_int32_t depth,
+ pts_database_t *pts_db)
+{
+ pts_ita_comp_ima_t *this;
+ int i;
+
+ INIT(this,
+ .public = {
+ .get_comp_func_name = _get_comp_func_name,
+ .get_evidence_flags = _get_evidence_flags,
+ .get_depth = _get_depth,
+ .measure = _measure,
+ .verify = _verify,
+ .check_off_registrations = _check_off_registrations,
+ .destroy = _destroy,
+ },
+ .name = pts_comp_func_name_create(PEN_ITA, PTS_ITA_COMP_FUNC_NAME_IMA,
+ qualifier),
+ .depth = depth,
+ .pts_db = pts_db,
+ .list = linked_list_create(),
+ );
+
+ for (i = 0; i < IMA_PCR_MAX; i++)
+ {
+ this->pcrs[i] = chunk_alloc(HASH_SIZE_SHA1);
+ memset(this->pcrs[i].ptr, 0x00, HASH_SIZE_SHA1);
+ }
+ return &this->public;
+}
+
diff --git a/src/libpts/pts/components/ita/ita_comp_ima.h b/src/libpts/pts/components/ita/ita_comp_ima.h
new file mode 100644
index 000000000..1ca27e6f0
--- /dev/null
+++ b/src/libpts/pts/components/ita/ita_comp_ima.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2011 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 pts_ita_comp_func_name pts_ita_comp_func_name
+ * @{ @ingroup pts
+ */
+
+#ifndef PTS_ITA_COMP_IMA_H_
+#define PTS_ITA_COMP_IMA_H_
+
+#include "pts/components/pts_component.h"
+
+/**
+ * Create a PTS ITS Functional Component object
+ *
+ * @param qualifier PTS Component Functional Name Qualifier
+ * @param depth Sub-component depth
+ * @param pts_db PTS measurement database
+ */
+pts_component_t* pts_ita_comp_ima_create(u_int8_t qualifier, u_int32_t depth,
+ pts_database_t *pts_db);
+
+#endif /** PTS_ITA_COMP_IMA_H_ @}*/
diff --git a/src/libpts/pts/components/ita/ita_comp_tboot.c b/src/libpts/pts/components/ita/ita_comp_tboot.c
new file mode 100644
index 000000000..287aae727
--- /dev/null
+++ b/src/libpts/pts/components/ita/ita_comp_tboot.c
@@ -0,0 +1,330 @@
+/*
+ * Copyright (C) 2011 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 "ita_comp_tboot.h"
+#include "ita_comp_func_name.h"
+
+#include "libpts.h"
+#include "pts/components/pts_component.h"
+
+#include <debug.h>
+#include <pen/pen.h>
+
+typedef struct pts_ita_comp_tboot_t pts_ita_comp_tboot_t;
+
+/**
+ * Private data of a pts_ita_comp_tboot_t object.
+ *
+ */
+struct pts_ita_comp_tboot_t {
+
+ /**
+ * Public pts_component_t interface.
+ */
+ pts_component_t public;
+
+ /**
+ * Component Functional Name
+ */
+ pts_comp_func_name_t *name;
+
+ /**
+ * AIK keyid
+ */
+ chunk_t keyid;
+
+ /**
+ * Sub-component depth
+ */
+ u_int32_t depth;
+
+ /**
+ * PTS measurement database
+ */
+ pts_database_t *pts_db;
+
+ /**
+ * Primary key for Component Functional Name database entry
+ */
+ int cid;
+
+ /**
+ * Primary key for AIK database entry
+ */
+ int kid;
+
+ /**
+ * Component is registering measurements
+ */
+ bool is_registering;
+
+ /**
+ * Time of TBOOT measurement
+ */
+ time_t measurement_time;
+
+ /**
+ * Expected measurement count
+ */
+ int count;
+
+ /**
+ * Measurement sequence number
+ */
+ int seq_no;
+
+};
+
+METHOD(pts_component_t, get_comp_func_name, pts_comp_func_name_t*,
+ pts_ita_comp_tboot_t *this)
+{
+ return this->name;
+}
+
+METHOD(pts_component_t, get_evidence_flags, u_int8_t,
+ pts_ita_comp_tboot_t *this)
+{
+ return PTS_REQ_FUNC_COMP_EVID_PCR;
+}
+
+METHOD(pts_component_t, get_depth, u_int32_t,
+ pts_ita_comp_tboot_t *this)
+{
+ return this->depth;
+}
+
+METHOD(pts_component_t, measure, status_t,
+ pts_ita_comp_tboot_t *this, pts_t *pts, pts_comp_evidence_t **evidence)
+{
+ pts_comp_evidence_t *evid;
+ char *meas_hex, *pcr_before_hex, *pcr_after_hex;
+ chunk_t measurement, pcr_before, pcr_after;
+ size_t hash_size, pcr_len;
+ u_int32_t extended_pcr;
+ pts_pcr_transform_t pcr_transform;
+ pts_meas_algorithms_t hash_algo;
+
+ switch (this->seq_no++)
+ {
+ case 0:
+ /* dummy data since currently the TBOOT log is not retrieved */
+ time(&this->measurement_time);
+ meas_hex = lib->settings->get_str(lib->settings,
+ "libimcv.plugins.imc-attestation.pcr17_meas", NULL);
+ pcr_before_hex = lib->settings->get_str(lib->settings,
+ "libimcv.plugins.imc-attestation.pcr17_before", NULL);
+ pcr_after_hex = lib->settings->get_str(lib->settings,
+ "libimcv.plugins.imc-attestation.pcr17_after", NULL);
+ extended_pcr = PCR_TBOOT_POLICY;
+ break;
+ case 1:
+ /* dummy data since currently the TBOOT log is not retrieved */
+ meas_hex = lib->settings->get_str(lib->settings,
+ "libimcv.plugins.imc-attestation.pcr18_meas", NULL);
+ pcr_before_hex = lib->settings->get_str(lib->settings,
+ "libimcv.plugins.imc-attestation.pcr18_before", NULL);
+ pcr_after_hex = lib->settings->get_str(lib->settings,
+ "libimcv.plugins.imc-attestation.pcr18_after", NULL);
+ extended_pcr = PCR_TBOOT_MLE;
+ break;
+ default:
+ return FAILED;
+ }
+
+ hash_algo = pts->get_meas_algorithm(pts);
+ hash_size = pts_meas_algo_hash_size(hash_algo);
+ pcr_len = pts->get_pcr_len(pts);
+ pcr_transform = pts_meas_algo_to_pcr_transform(hash_algo, pcr_len);
+
+ /* get and check the measurement data */
+ measurement = chunk_from_hex(
+ chunk_create(meas_hex, strlen(meas_hex)), NULL);
+ pcr_before = chunk_from_hex(
+ chunk_create(pcr_before_hex, strlen(pcr_before_hex)), NULL);
+ pcr_after = chunk_from_hex(
+ chunk_create(pcr_after_hex, strlen(pcr_after_hex)), NULL);
+ if (pcr_before.len != pcr_len || pcr_after.len != pcr_len ||
+ measurement.len != hash_size)
+ {
+ DBG1(DBG_PTS, "TBOOT measurement or pcr data have the wrong size");
+ free(measurement.ptr);
+ free(pcr_before.ptr);
+ free(pcr_after.ptr);
+ return FAILED;
+ }
+
+ evid = *evidence = pts_comp_evidence_create(this->name->clone(this->name),
+ this->depth, extended_pcr,
+ hash_algo, pcr_transform,
+ this->measurement_time, measurement);
+ evid->set_pcr_info(evid, pcr_before, pcr_after);
+
+ return (this->seq_no < 2) ? NEED_MORE : SUCCESS;
+}
+
+METHOD(pts_component_t, verify, status_t,
+ pts_ita_comp_tboot_t *this, pts_t *pts, pts_comp_evidence_t *evidence)
+{
+ bool has_pcr_info;
+ u_int32_t extended_pcr, vid, name;
+ enum_name_t *names;
+ pts_meas_algorithms_t algo;
+ pts_pcr_transform_t transform;
+ time_t measurement_time;
+ chunk_t measurement, pcr_before, pcr_after;
+
+ measurement = evidence->get_measurement(evidence, &extended_pcr,
+ &algo, &transform, &measurement_time);
+
+ if (!this->keyid.ptr)
+ {
+ if (!pts->get_aik_keyid(pts, &this->keyid))
+ {
+ return FAILED;
+ }
+ this->keyid = chunk_clone(this->keyid);
+
+ if (!this->pts_db)
+ {
+ DBG1(DBG_PTS, "pts database not available");
+ return FAILED;
+ }
+ if (this->pts_db->get_comp_measurement_count(this->pts_db,
+ this->name, this->keyid, algo,
+ &this->cid, &this->kid, &this->count) != SUCCESS)
+ {
+ return FAILED;
+ }
+ vid = this->name->get_vendor_id(this->name);
+ name = this->name->get_name(this->name);
+ names = pts_components->get_comp_func_names(pts_components, vid);
+
+ if (this->count)
+ {
+ DBG1(DBG_PTS, "checking %d %N '%N' functional component evidence "
+ "measurements", this->count, pen_names, vid, names, name);
+ }
+ else
+ {
+ DBG1(DBG_PTS, "registering %N '%N' functional component evidence "
+ "measurements", pen_names, vid, names, name);
+ this->is_registering = TRUE;
+ }
+ }
+
+ if (this->is_registering)
+ {
+ if (this->pts_db->insert_comp_measurement(this->pts_db, measurement,
+ this->cid, this->kid, ++this->seq_no,
+ extended_pcr, algo) != SUCCESS)
+ {
+ return FAILED;
+ }
+ this->count = this->seq_no + 1;
+ }
+ else
+ {
+ if (this->pts_db->check_comp_measurement(this->pts_db, measurement,
+ this->cid, this->kid, ++this->seq_no,
+ extended_pcr, algo) != SUCCESS)
+ {
+ return FAILED;
+ }
+ }
+
+ has_pcr_info = evidence->get_pcr_info(evidence, &pcr_before, &pcr_after);
+ if (has_pcr_info)
+ {
+ if (!pts->add_pcr(pts, extended_pcr, pcr_before, pcr_after))
+ {
+ return FAILED;
+ }
+ }
+
+ return (this->seq_no < this->count) ? NEED_MORE : SUCCESS;
+}
+
+METHOD(pts_component_t, check_off_registrations, bool,
+ pts_ita_comp_tboot_t *this)
+{
+ u_int32_t vid, name;
+ enum_name_t *names;
+
+ if (!this->is_registering)
+ {
+ return FALSE;
+ }
+
+ /* Finalize registration */
+ this->is_registering = FALSE;
+
+ vid = this->name->get_vendor_id(this->name);
+ name = this->name->get_name(this->name);
+ names = pts_components->get_comp_func_names(pts_components, vid);
+ DBG1(DBG_PTS, "registered %d %N '%N' functional component evidence "
+ "measurements", this->seq_no, pen_names, vid, names, name);
+ return TRUE;
+}
+
+METHOD(pts_component_t, destroy, void,
+ pts_ita_comp_tboot_t *this)
+{
+ int count;
+ u_int32_t vid, name;
+ enum_name_t *names;
+
+ if (this->is_registering)
+ {
+ count = this->pts_db->delete_comp_measurements(this->pts_db,
+ this->cid, this->kid);
+ vid = this->name->get_vendor_id(this->name);
+ name = this->name->get_name(this->name);
+ names = pts_components->get_comp_func_names(pts_components, vid);
+ DBG1(DBG_PTS, "deleted %d registered %N '%N' functional component "
+ "evidence measurements", count, pen_names, vid, names, name);
+ }
+ this->name->destroy(this->name);
+ free(this->keyid.ptr);
+ free(this);
+}
+
+/**
+ * See header
+ */
+pts_component_t *pts_ita_comp_tboot_create(u_int8_t qualifier, u_int32_t depth,
+ pts_database_t *pts_db)
+{
+ pts_ita_comp_tboot_t *this;
+
+ INIT(this,
+ .public = {
+ .get_comp_func_name = _get_comp_func_name,
+ .get_evidence_flags = _get_evidence_flags,
+ .get_depth = _get_depth,
+ .measure = _measure,
+ .verify = _verify,
+ .check_off_registrations = _check_off_registrations,
+ .destroy = _destroy,
+ },
+ .name = pts_comp_func_name_create(PEN_ITA, PTS_ITA_COMP_FUNC_NAME_TBOOT,
+ qualifier),
+ .depth = depth,
+ .pts_db = pts_db,
+ );
+
+ return &this->public;
+}
+
diff --git a/src/libpts/pts/components/ita/ita_comp_tboot.h b/src/libpts/pts/components/ita/ita_comp_tboot.h
new file mode 100644
index 000000000..39554fbc7
--- /dev/null
+++ b/src/libpts/pts/components/ita/ita_comp_tboot.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2011 Sansar Choinyambuu
+ * 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 pts_ita_comp_func_name pts_ita_comp_func_name
+ * @{ @ingroup pts
+ */
+
+#ifndef PTS_ITA_COMP_TBOOT_H_
+#define PTS_ITA_COMP_TBOOT_H_
+
+#include "pts/components/pts_component.h"
+
+/**
+ * Create a PTS ITS Functional Component object
+ *
+ * @param qualifier PTS Component Functional Name Qualifier
+ * @param depth Sub-component depth
+ * @param pts_db PTS measurement database
+ */
+pts_component_t* pts_ita_comp_tboot_create(u_int8_t qualifier, u_int32_t depth,
+ pts_database_t *pts_db);
+
+#endif /** PTS_ITA_COMP_TBOOT_H_ @}*/
diff --git a/src/libpts/pts/components/ita/ita_comp_tgrub.c b/src/libpts/pts/components/ita/ita_comp_tgrub.c
new file mode 100644
index 000000000..0dfd5fd41
--- /dev/null
+++ b/src/libpts/pts/components/ita/ita_comp_tgrub.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2011 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 "ita_comp_tgrub.h"
+#include "ita_comp_func_name.h"
+
+#include "pts/components/pts_component.h"
+
+#include <debug.h>
+#include <pen/pen.h>
+
+typedef struct pts_ita_comp_tgrub_t pts_ita_comp_tgrub_t;
+
+/**
+ * Private data of a pts_ita_comp_tgrub_t object.
+ *
+ */
+struct pts_ita_comp_tgrub_t {
+
+ /**
+ * Public pts_component_t interface.
+ */
+ pts_component_t public;
+
+ /**
+ * Component Functional Name
+ */
+ pts_comp_func_name_t *name;
+
+ /**
+ * Sub-component depth
+ */
+ u_int32_t depth;
+
+ /**
+ * PTS measurement database
+ */
+ pts_database_t *pts_db;
+
+};
+
+METHOD(pts_component_t, get_comp_func_name, pts_comp_func_name_t*,
+ pts_ita_comp_tgrub_t *this)
+{
+ return this->name;
+}
+
+METHOD(pts_component_t, get_evidence_flags, u_int8_t,
+ pts_ita_comp_tgrub_t *this)
+{
+ return PTS_REQ_FUNC_COMP_EVID_PCR;
+}
+
+METHOD(pts_component_t, get_depth, u_int32_t,
+ pts_ita_comp_tgrub_t *this)
+{
+ return this->depth;
+}
+
+METHOD(pts_component_t, measure, status_t,
+ pts_ita_comp_tgrub_t *this, pts_t *pts, pts_comp_evidence_t **evidence)
+{
+ pts_comp_evidence_t *evid;
+ u_int32_t extended_pcr;
+ time_t measurement_time;
+ chunk_t measurement, pcr_before, pcr_after;
+ pts_pcr_transform_t pcr_transform;
+ pts_meas_algorithms_t hash_algo;
+ size_t hash_size, pcr_len;
+
+ /* Provisional implementation for TGRUB */
+ extended_pcr = PCR_DEBUG;
+ time(&measurement_time);
+
+ if (!pts->read_pcr(pts, extended_pcr, &pcr_after))
+ {
+ DBG1(DBG_PTS, "error occurred while reading PCR: %d", extended_pcr);
+ return FAILED;
+ }
+
+ hash_algo = pts->get_meas_algorithm(pts);
+ hash_size = pts_meas_algo_hash_size(hash_algo);
+ pcr_len = pts->get_pcr_len(pts);
+ pcr_transform = pts_meas_algo_to_pcr_transform(hash_algo, pcr_len);
+
+ measurement = chunk_alloc(hash_size);
+ memset(measurement.ptr, 0x00, measurement.len);
+
+ pcr_before = chunk_alloc(pcr_len);
+ memset(pcr_before.ptr, 0x00, pcr_before.len);
+
+ evid = *evidence = pts_comp_evidence_create(this->name->clone(this->name),
+ this->depth, extended_pcr,
+ hash_algo, pcr_transform,
+ measurement_time, measurement);
+ evid->set_pcr_info(evid, pcr_before, pcr_after);
+
+ return SUCCESS;
+}
+
+METHOD(pts_component_t, verify, status_t,
+ pts_ita_comp_tgrub_t *this, pts_t *pts, pts_comp_evidence_t *evidence)
+{
+ bool has_pcr_info;
+ u_int32_t extended_pcr;
+ pts_meas_algorithms_t algo;
+ pts_pcr_transform_t transform;
+ time_t measurement_time;
+ chunk_t measurement, pcr_before, pcr_after;
+
+ measurement = evidence->get_measurement(evidence, &extended_pcr,
+ &algo, &transform, &measurement_time);
+ if (extended_pcr != PCR_DEBUG)
+ {
+ return FAILED;
+ }
+
+ /* TODO check measurement in database */
+
+ has_pcr_info = evidence->get_pcr_info(evidence, &pcr_before, &pcr_after);
+ if (has_pcr_info)
+ {
+ if (!pts->add_pcr(pts, extended_pcr, pcr_before, pcr_after))
+ {
+ return FAILED;
+ }
+ }
+
+ return SUCCESS;
+}
+
+METHOD(pts_component_t, check_off_registrations, bool,
+ pts_ita_comp_tgrub_t *this)
+{
+ return FALSE;
+}
+
+METHOD(pts_component_t, destroy, void,
+ pts_ita_comp_tgrub_t *this)
+{
+ this->name->destroy(this->name);
+ free(this);
+}
+
+/**
+ * See header
+ */
+pts_component_t *pts_ita_comp_tgrub_create(u_int8_t qualifier, u_int32_t depth,
+ pts_database_t *pts_db)
+{
+ pts_ita_comp_tgrub_t *this;
+
+ INIT(this,
+ .public = {
+ .get_comp_func_name = _get_comp_func_name,
+ .get_evidence_flags = _get_evidence_flags,
+ .get_depth = _get_depth,
+ .measure = _measure,
+ .verify = _verify,
+ .check_off_registrations = _check_off_registrations,
+ .destroy = _destroy,
+ },
+ .name = pts_comp_func_name_create(PEN_ITA, PTS_ITA_COMP_FUNC_NAME_TGRUB,
+ qualifier),
+ .depth = depth,
+ .pts_db = pts_db,
+ );
+
+ return &this->public;
+}
+
diff --git a/src/libpts/pts/components/ita/ita_comp_tgrub.h b/src/libpts/pts/components/ita/ita_comp_tgrub.h
new file mode 100644
index 000000000..52ecc325c
--- /dev/null
+++ b/src/libpts/pts/components/ita/ita_comp_tgrub.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2011 Sansar Choinyambuu
+ * 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 pts_ita_comp_func_name pts_ita_comp_func_name
+ * @{ @ingroup pts
+ */
+
+#ifndef PTS_ITA_COMP_TGRUB_H_
+#define PTS_ITA_COMP_TGRUB_H_
+
+#include "pts/components/pts_component.h"
+
+/**
+ * Create a PTS ITS Functional Component object
+ *
+ * @param qualifier PTS Component Functional Name Qualifier
+ * @param depth Sub-component depth
+ * @param pts_db PTS measurement database
+ */
+pts_component_t* pts_ita_comp_tgrub_create(u_int8_t qualifier, u_int32_t depth,
+ pts_database_t *pts_db);
+
+#endif /** PTS_ITA_COMP_TGRUB_H_ @}*/
diff --git a/src/libpts/pts/components/pts_comp_evidence.c b/src/libpts/pts/components/pts_comp_evidence.c
new file mode 100644
index 000000000..9eb8dae75
--- /dev/null
+++ b/src/libpts/pts/components/pts_comp_evidence.c
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2011 Sansar Choinyambuu, 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 "pts/components/pts_comp_evidence.h"
+
+#include <debug.h>
+
+typedef struct private_pts_comp_evidence_t private_pts_comp_evidence_t;
+
+/**
+ * Private data of a pts_comp_evidence_t object.
+ */
+struct private_pts_comp_evidence_t {
+
+ /**
+ * Public pts_comp_evidence_t interface.
+ */
+ pts_comp_evidence_t public;
+
+ /**
+ * Component Functional Name
+ */
+ pts_comp_func_name_t *name;
+
+ /**
+ * Sub-Component Depth
+ */
+ u_int32_t depth;
+
+ /**
+ * Measurement Time
+ */
+ time_t measurement_time;
+
+ /**
+ * Measurement Time
+ */
+ chunk_t measurement;
+
+ /**
+ * Measurement Hash Algorithm
+ */
+ pts_meas_algorithms_t hash_algorithm;
+
+ /**
+ * Is PCR Information included?
+ */
+ bool has_pcr_info;
+
+ /**
+ * PCR the measurement was extended into
+ */
+ u_int32_t extended_pcr;
+
+ /**
+ * PCR value before extension
+ */
+ chunk_t pcr_before;
+
+ /**
+ * PCR value after extension
+ */
+ chunk_t pcr_after;
+
+ /**
+ * Transformation used for extending measurement into PCR
+ */
+ pts_pcr_transform_t transform;
+
+ /**
+ * Component Validation Result
+ */
+ pts_comp_evid_validation_t validation;
+
+ /**
+ * Verification Policy URI
+ */
+ chunk_t policy_uri;
+
+};
+
+METHOD(pts_comp_evidence_t, get_comp_func_name, pts_comp_func_name_t*,
+ private_pts_comp_evidence_t *this, u_int32_t *depth)
+{
+ if (depth)
+ {
+ *depth = this->depth;
+ }
+ return this->name;
+}
+
+METHOD(pts_comp_evidence_t, get_extended_pcr, u_int32_t,
+ private_pts_comp_evidence_t *this)
+{
+ return this->extended_pcr;
+}
+
+METHOD(pts_comp_evidence_t, get_measurement, chunk_t,
+ private_pts_comp_evidence_t *this, u_int32_t *extended_pcr,
+ pts_meas_algorithms_t *algo, pts_pcr_transform_t *transform,
+ time_t *measurement_time)
+{
+ if (extended_pcr)
+ {
+ *extended_pcr = this->extended_pcr;
+ }
+ if (algo)
+ {
+ *algo = this->hash_algorithm;
+ }
+ if (transform)
+ {
+ *transform = this->transform;
+ }
+ if (measurement_time)
+ {
+ *measurement_time = this->measurement_time;
+ }
+ return this->measurement;
+}
+
+METHOD(pts_comp_evidence_t, get_pcr_info, bool,
+ private_pts_comp_evidence_t *this, chunk_t *pcr_before, chunk_t *pcr_after)
+{
+ if (pcr_before)
+ {
+ *pcr_before = this->pcr_before;
+ }
+ if (pcr_after)
+ {
+ *pcr_after = this->pcr_after;
+ }
+ return this->has_pcr_info;
+}
+
+METHOD(pts_comp_evidence_t, set_pcr_info, void,
+ private_pts_comp_evidence_t *this, chunk_t pcr_before, chunk_t pcr_after)
+{
+ this->has_pcr_info = TRUE;
+ this->pcr_before = pcr_before;
+ this->pcr_after = pcr_after;
+
+ DBG2(DBG_PTS, "PCR %2d before value : %#B", this->extended_pcr, &pcr_before);
+ DBG2(DBG_PTS, "PCR %2d after value : %#B", this->extended_pcr, &pcr_after);
+}
+
+METHOD(pts_comp_evidence_t, get_validation, pts_comp_evid_validation_t,
+ private_pts_comp_evidence_t *this, chunk_t *uri)
+{
+ if (uri)
+ {
+ *uri = this->policy_uri;
+ }
+ return this->validation;
+}
+
+METHOD(pts_comp_evidence_t, set_validation, void,
+ private_pts_comp_evidence_t *this, pts_comp_evid_validation_t validation,
+ chunk_t uri)
+{
+ this->validation = validation;
+ this->policy_uri = chunk_clone(uri);
+}
+
+METHOD(pts_comp_evidence_t, destroy, void,
+ private_pts_comp_evidence_t *this)
+{
+ this->name->destroy(this->name);
+ free(this->measurement.ptr);
+ free(this->pcr_before.ptr);
+ free(this->pcr_after.ptr);
+ free(this->policy_uri.ptr);
+ free(this);
+}
+
+/**
+ * See header
+ */
+pts_comp_evidence_t *pts_comp_evidence_create(pts_comp_func_name_t *name,
+ u_int32_t depth,
+ u_int32_t extended_pcr,
+ pts_meas_algorithms_t algo,
+ pts_pcr_transform_t transform,
+ time_t measurement_time,
+ chunk_t measurement)
+{
+ private_pts_comp_evidence_t *this;
+
+ INIT(this,
+ .public = {
+ .get_comp_func_name = _get_comp_func_name,
+ .get_extended_pcr = _get_extended_pcr,
+ .get_measurement = _get_measurement,
+ .get_pcr_info = _get_pcr_info,
+ .set_pcr_info = _set_pcr_info,
+ .get_validation = _get_validation,
+ .set_validation = _set_validation,
+ .destroy = _destroy,
+ },
+ .name = name,
+ .depth = depth,
+ .extended_pcr = extended_pcr,
+ .hash_algorithm = algo,
+ .transform = transform,
+ .measurement_time = measurement_time,
+ .measurement = measurement,
+ );
+
+ name->log(name, "");
+ DBG2(DBG_PTS, "measurement time: %T", &measurement_time, FALSE);
+ DBG2(DBG_PTS, "PCR %2d extended with: %#B", extended_pcr, &measurement);
+
+ return &this->public;
+}
+
+/**
+ * See header
+ */
+pts_pcr_transform_t pts_meas_algo_to_pcr_transform(pts_meas_algorithms_t algo,
+ size_t pcr_len)
+{
+ size_t hash_size;
+
+ hash_size = pts_meas_algo_hash_size(algo);
+ if (hash_size == 0)
+ {
+ return PTS_PCR_TRANSFORM_NO;
+ }
+ if (hash_size == pcr_len)
+ {
+ return PTS_PCR_TRANSFORM_MATCH;
+ }
+ if (hash_size > pcr_len)
+ {
+ return PTS_PCR_TRANSFORM_LONG;
+ }
+ return PTS_PCR_TRANSFORM_SHORT;
+}
+
diff --git a/src/libpts/pts/components/pts_comp_evidence.h b/src/libpts/pts/components/pts_comp_evidence.h
new file mode 100644
index 000000000..fe86aa940
--- /dev/null
+++ b/src/libpts/pts/components/pts_comp_evidence.h
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2011 Sansar Choinyambuu, 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 pts_comp_evidence pts_comp_evidence
+ * @{ @ingroup pts
+ */
+
+#ifndef PTS_COMP_EVIDENCE_H_
+#define PTS_COMP_EVIDENCE_H_
+
+typedef struct pts_comp_evidence_t pts_comp_evidence_t;
+typedef enum pts_pcr_transform_t pts_pcr_transform_t;
+typedef enum pts_comp_evid_validation_t pts_comp_evid_validation_t;
+
+#include "pts/pts_meas_algo.h"
+#include "pts/components/pts_comp_func_name.h"
+
+#include <library.h>
+
+/**
+ * PTS PCR Transformations
+ */
+enum pts_pcr_transform_t {
+ /** No Transformation */
+ PTS_PCR_TRANSFORM_NO = 0,
+ /** Hash Value matched PCR size */
+ PTS_PCR_TRANSFORM_MATCH = 1,
+ /** Hash value shorter than PCR size */
+ PTS_PCR_TRANSFORM_SHORT = 2,
+ /** Hash value longer than PCR size */
+ PTS_PCR_TRANSFORM_LONG = 3,
+};
+
+/**
+ * PTS Component Evidence Validation Result Flags
+ */
+enum pts_comp_evid_validation_t {
+ /** No Validation was attempted */
+ PTS_COMP_EVID_VALIDATION_NONE = 0x00,
+ /** Attempted validation, unable to verify */
+ PTS_COMP_EVID_VALIDATION_UNABLE = 0x20,
+ /** Attempted validation, verification failed */
+ PTS_COMP_EVID_VALIDATION_FAILED = 0x40,
+ /** Attempted validation, verification passed */
+ PTS_COMP_EVID_VALIDATION_PASSED = 0x60,
+};
+
+/**
+ * PTS Functional Component Interface
+ */
+struct pts_comp_evidence_t {
+
+ /**
+ * Gets the Component Functional Name and Sub-Component Depth
+ *
+ * @param depth Sub-Component Depth
+ * @result Component Functional Name
+ */
+ pts_comp_func_name_t* (*get_comp_func_name)(pts_comp_evidence_t *this,
+ u_int32_t *depth);
+
+ /**
+ * Gets the PCR the measurement was extended into
+ *
+ * @result PCR the measurement was extended into
+ */
+ u_int32_t (*get_extended_pcr)(pts_comp_evidence_t *this);
+
+ /**
+ * Gets the measurement and the algorithms used
+ *
+ * @param extended_pcr PCR the measurement was extended into
+ * @param algo Measurement hash algorithm
+ * @param transform Transformation used for PCR extension
+ * @param measurement_time Time the measurement was taken
+ * @result Measurement hash value
+ */
+ chunk_t (*get_measurement)(pts_comp_evidence_t *this,
+ u_int32_t *extended_pcr,
+ pts_meas_algorithms_t *algo,
+ pts_pcr_transform_t *transform,
+ time_t *measurement_time);
+
+ /**
+ * Gets the PCR information if available
+ *
+ * @param pcr_before PCR value before extension
+ * @param pcr_after PCR value after extension
+ * @result TRUE if PCR information is available
+ */
+ bool (*get_pcr_info)(pts_comp_evidence_t *this, chunk_t *pcr_before,
+ chunk_t *pcr_after);
+
+ /**
+ * Sets PCR information if available
+ *
+ * @param pcr_before PCR value before extension
+ * @param pcr_after PCR value after extension
+ */
+ void (*set_pcr_info)(pts_comp_evidence_t *this, chunk_t pcr_before,
+ chunk_t pcr_after);
+
+ /**
+ * Gets Validation Result if available
+ *
+ * @param uri Verification Policy URI
+ * @return validation Validation Result
+ */
+ pts_comp_evid_validation_t (*get_validation)(pts_comp_evidence_t *this,
+ chunk_t *uri);
+
+ /**
+ * Sets Validation Result if available
+ *
+ * @param validation Validation Result
+ * @param uri Verification Policy URI
+ */
+ void (*set_validation)(pts_comp_evidence_t *this,
+ pts_comp_evid_validation_t validation, chunk_t uri);
+
+ /**
+ * Destroys a pts_comp_evidence_t object.
+ */
+ void (*destroy)(pts_comp_evidence_t *this);
+
+};
+
+/**
+ * Creates a pts_comp_evidence_t object
+ *
+ * @param name Component Functional Name
+ * @param depth Sub-component depth
+ * @param extended_pcr PCR the measurement was extended into
+ * @param algo Measurement hash algorithm
+ * @param transform Transformation used for PCR extension
+ * @param measurement_time Time the measurement was taken, 0 if unknown
+ * @param measurement Measurement hash value
+ */
+pts_comp_evidence_t* pts_comp_evidence_create(pts_comp_func_name_t *name,
+ u_int32_t depth,
+ u_int32_t extended_pcr,
+ pts_meas_algorithms_t algo,
+ pts_pcr_transform_t transform,
+ time_t measurement_time,
+ chunk_t measurement);
+
+/**
+ * Determine transform to fit measurement hash into PCR register
+ *
+ * @param algo Measurement hash algorithm
+ * @param pcr_len Length of the PCR registers in bytes
+ * @return PCR transform type
+ */
+pts_pcr_transform_t pts_meas_algo_to_pcr_transform(pts_meas_algorithms_t algo,
+ size_t pcr_len);
+
+#endif /** PTS_COMP_EVIDENCE_H_ @}*/
diff --git a/src/libpts/pts/components/pts_comp_func_name.c b/src/libpts/pts/components/pts_comp_func_name.c
new file mode 100644
index 000000000..d98850d78
--- /dev/null
+++ b/src/libpts/pts/components/pts_comp_func_name.c
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2011 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 "libpts.h"
+#include "pts/components/pts_comp_func_name.h"
+
+#include <debug.h>
+
+typedef struct private_pts_comp_func_name_t private_pts_comp_func_name_t;
+
+/**
+ * Private data of a pts_comp_func_name_t object.
+ *
+ */
+struct private_pts_comp_func_name_t {
+
+ /**
+ * Public pts_comp_func_name_t interface.
+ */
+ pts_comp_func_name_t public;
+
+ /**
+ * PTS Component Functional Name Vendor ID
+ */
+ u_int32_t vid;
+
+ /**
+ * PTS Component Functional Name
+ */
+ u_int32_t name;
+
+ /**
+ * PTS Component Functional Name Qualifier
+ */
+ u_int8_t qualifier;
+
+};
+
+METHOD(pts_comp_func_name_t, get_vendor_id, u_int32_t,
+ private_pts_comp_func_name_t *this)
+{
+ return this->vid;
+}
+
+METHOD(pts_comp_func_name_t, get_name, u_int32_t,
+ private_pts_comp_func_name_t *this)
+{
+ return this->name;
+}
+
+METHOD(pts_comp_func_name_t, get_qualifier, u_int8_t,
+ private_pts_comp_func_name_t *this)
+{
+ return this->qualifier;
+}
+
+static bool equals(private_pts_comp_func_name_t *this,
+ private_pts_comp_func_name_t *other)
+{
+ if (this->vid != other->vid || this->name != other->name)
+ {
+ return FALSE;
+ }
+ if (this->qualifier == PTS_QUALIFIER_UNKNOWN ||
+ other->qualifier == PTS_QUALIFIER_UNKNOWN)
+ {
+ return TRUE;
+ }
+ /* TODO handle qualifier wildcards */
+
+ return this->qualifier == other->qualifier;
+}
+
+METHOD(pts_comp_func_name_t, clone_, pts_comp_func_name_t*,
+ private_pts_comp_func_name_t *this)
+{
+ private_pts_comp_func_name_t *clone;
+
+ clone = malloc_thing(private_pts_comp_func_name_t);
+ memcpy(clone, this, sizeof(private_pts_comp_func_name_t));
+
+ return &clone->public;
+}
+
+METHOD(pts_comp_func_name_t, log_, void,
+ private_pts_comp_func_name_t *this, char *label)
+{
+ enum_name_t *names, *types;
+ char flags[8];
+ int type;
+
+ names = pts_components->get_comp_func_names(pts_components, this->vid);
+ types = pts_components->get_qualifier_type_names(pts_components, this->vid);
+ type = pts_components->get_qualifier(pts_components, &this->public, flags);
+
+ if (names && types)
+ {
+ DBG2(DBG_PTS, "%s%N functional component '%N' [%s] '%N'",
+ label, pen_names, this->vid, names, this->name, flags, types, type);
+ }
+ else
+ {
+ DBG2(DBG_PTS, "%s0x%06x functional component 0x%08x 0x%02x",
+ label, this->vid, this->name, this->qualifier);
+ }
+}
+
+METHOD(pts_comp_func_name_t, destroy, void,
+ private_pts_comp_func_name_t *this)
+{
+ free(this);
+}
+
+/**
+ * See header
+ */
+pts_comp_func_name_t* pts_comp_func_name_create(u_int32_t vid, u_int32_t name,
+ u_int8_t qualifier)
+{
+ private_pts_comp_func_name_t *this;
+
+ INIT(this,
+ .public = {
+ .get_vendor_id = _get_vendor_id,
+ .get_name = _get_name,
+ .get_qualifier = _get_qualifier,
+ .equals = (bool(*)(pts_comp_func_name_t*,pts_comp_func_name_t*))equals,
+ .clone = _clone_,
+ .log = _log_,
+ .destroy = _destroy,
+ },
+ .vid = vid,
+ .name = name,
+ .qualifier = qualifier,
+ );
+
+ return &this->public;
+}
+
diff --git a/src/libpts/pts/components/pts_comp_func_name.h b/src/libpts/pts/components/pts_comp_func_name.h
new file mode 100644
index 000000000..2c7a84177
--- /dev/null
+++ b/src/libpts/pts/components/pts_comp_func_name.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2011 Sansar Choinyambuu
+ * 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 pts_comp_func_name pts_comp_func_name
+ * @{ @ingroup pts
+ */
+
+#ifndef PTS_FUNC_COMP_NAME_H_
+#define PTS_FUNC_COMP_NAME_H_
+
+typedef struct pts_comp_func_name_t pts_comp_func_name_t;
+
+#include <library.h>
+
+#define PTS_QUALIFIER_UNKNOWN 0x00
+#define PTS_QUALIFIER_WILDCARD 0x3F
+
+/**
+ * PTS Component Functional Name object
+ */
+struct pts_comp_func_name_t {
+
+ /**
+ * Get the PTS Component Functional Name Vendor ID
+ *
+ * @return PTS Component Functional Name Vendor ID
+ */
+ u_int32_t (*get_vendor_id)(pts_comp_func_name_t *this);
+
+ /**
+ * Get the PTS Component Functional Name
+ *
+ * @return PTS Component Functional Name
+ */
+ u_int32_t (*get_name)(pts_comp_func_name_t *this);
+
+ /**
+ * Get the PTS Component Functional Name Qualifier
+ *
+ * @return PTS Component Functional Name Qualifier
+ */
+ u_int8_t (*get_qualifier)(pts_comp_func_name_t *this);
+
+ /**
+ * Check to PTS Component Functional Names for equality
+ *
+ * @param other Other PTS Component Functional Name
+ * @return TRUE if equal
+ */
+ bool (*equals)(pts_comp_func_name_t *this, pts_comp_func_name_t *other);
+
+ /**
+ * Clone a PTS Component Functional Name
+ *
+ * @return Cloned PTS Component Functional Name
+ */
+ pts_comp_func_name_t* (*clone)(pts_comp_func_name_t *this);
+
+ /**
+ * Write PTS Component Functional Name information to the standard logfile
+ *
+ * @param label Label added to log output
+ */
+ void (*log)(pts_comp_func_name_t *this, char *label);
+
+ /**
+ * Destroys a pts_component_t object.
+ */
+ void (*destroy)(pts_comp_func_name_t *this);
+
+};
+
+/**
+ * Create a PTS Component Functional Name object
+ *
+ * @param vid PTS Component Functional Name Vendor ID
+ * @param name PTS Component Functional Name
+ * @param PTS Component Functional Name Qualifier
+ */
+pts_comp_func_name_t* pts_comp_func_name_create(u_int32_t vid, u_int32_t name,
+ u_int8_t qualifier);
+
+#endif /** PTS_FUNC_COMP_NAME_H_ @}*/
diff --git a/src/libpts/pts/components/pts_component.h b/src/libpts/pts/components/pts_component.h
new file mode 100644
index 000000000..524ff332d
--- /dev/null
+++ b/src/libpts/pts/components/pts_component.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2011 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 pts_component pts_component
+ * @{ @ingroup pts
+ */
+
+#ifndef PTS_COMPONENT_H_
+#define PTS_COMPONENT_H_
+
+typedef struct pts_component_t pts_component_t;
+
+#include "pts/pts.h"
+#include "pts/pts_database.h"
+#include "pts/components/pts_comp_func_name.h"
+#include "pts/components/pts_comp_evidence.h"
+
+#include <library.h>
+
+/**
+ * PTS Functional Component Interface
+ */
+struct pts_component_t {
+
+ /**
+ * Get the PTS Component Functional Name
+ *
+ * @return PTS Component Functional Name
+ */
+ pts_comp_func_name_t* (*get_comp_func_name)(pts_component_t *this);
+
+ /**
+ * Get the PTS Component Evidence Flags
+ *
+ * @return PTS Component Functional Name
+ */
+ u_int8_t (*get_evidence_flags)(pts_component_t *this);
+
+ /**
+ * Get the PTS Sub-component Depth
+ *
+ * @return PTS Sub-component Depth
+ */
+ u_int32_t (*get_depth)(pts_component_t *this);
+
+ /**
+ * Do evidence measurements on the PTS Functional Component
+ *
+ * @param pts PTS interface
+ * @param evidence returns component evidence measureemt
+ * @return status return code
+ */
+ status_t (*measure)(pts_component_t *this, pts_t *pts,
+ pts_comp_evidence_t** evidence);
+
+ /**
+ * Verify the evidence measurements of the PTS Functional Component
+ *
+ * @param pts PTS interface
+ * @param evidence component evidence measurement to be verified
+ * @return status return code
+ */
+ status_t (*verify)(pts_component_t *this, pts_t *pts,
+ pts_comp_evidence_t *evidence);
+
+
+ /**
+ * Tell the PTS Functional Component to finalize pending registrations
+ *
+ * @return TRUE if there are pending registrations
+ */
+ bool (*check_off_registrations)(pts_component_t *this);
+
+ /**
+ * Destroys a pts_component_t object.
+ */
+ void (*destroy)(pts_component_t *this);
+
+};
+
+#endif /** PTS_COMPONENT_H_ @}*/
diff --git a/src/libpts/pts/components/pts_component_manager.c b/src/libpts/pts/components/pts_component_manager.c
new file mode 100644
index 000000000..8ac4767bf
--- /dev/null
+++ b/src/libpts/pts/components/pts_component_manager.c
@@ -0,0 +1,317 @@
+/*
+ * Copyright (C) 2011 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 "pts/components/pts_component_manager.h"
+
+#include <utils/linked_list.h>
+#include <debug.h>
+
+typedef struct private_pts_component_manager_t private_pts_component_manager_t;
+typedef struct vendor_entry_t vendor_entry_t;
+typedef struct component_entry_t component_entry_t;
+
+#define PTS_QUALIFIER_SIZE 6
+
+/**
+ * Vendor-specific namespace information and list of registered components
+ */
+struct vendor_entry_t {
+
+ /**
+ * Vendor ID
+ */
+ pen_t vendor_id;
+
+ /**
+ * Vendor-specific Component Functional names
+ */
+ enum_name_t *comp_func_names;
+
+ /**
+ * Vendor-specific Qualifier Type names
+ */
+ enum_name_t *qualifier_type_names;
+
+ /**
+ * Vendor-specific Qualifier Flag names
+ */
+ char *qualifier_flag_names;
+
+ /**
+ * Vendor-specific size of Qualfiier Type field
+ */
+ int qualifier_type_size;
+
+ /**
+ * List of vendor-specific registered Functional Components
+ */
+ linked_list_t *components;
+};
+
+/**
+ * Destroy a vendor_entry_t object
+ */
+static void vendor_entry_destroy(vendor_entry_t *entry)
+{
+ entry->components->destroy_function(entry->components, free);
+ free(entry);
+}
+
+/**
+ * Creation method for a vendor-specific Functional Component
+ */
+struct component_entry_t {
+
+ /**
+ * Vendor-Specific Component Functional Name
+ */
+ u_int32_t name;
+
+ /**
+ * Functional Component creation method
+ */
+ pts_component_create_t create;
+};
+
+/**
+ * Private data of a pts_component_manager_t object.
+ *
+ */
+struct private_pts_component_manager_t {
+
+ /**
+ * Public pts_component_manager_t interface.
+ */
+ pts_component_manager_t public;
+
+ /**
+ * List of vendor-specific namespaces and registered components
+ */
+ linked_list_t *list;
+};
+
+METHOD(pts_component_manager_t, add_vendor, void,
+ private_pts_component_manager_t *this, pen_t vendor_id,
+ enum_name_t *comp_func_names, int qualifier_type_size,
+ char *qualifier_flag_names, enum_name_t *qualifier_type_names)
+{
+ vendor_entry_t *entry;
+
+ entry = malloc_thing(vendor_entry_t);
+ entry->vendor_id = vendor_id;
+ entry->comp_func_names = comp_func_names;
+ entry->qualifier_type_size = qualifier_type_size;
+ entry->qualifier_flag_names = qualifier_flag_names;
+ entry->qualifier_type_names = qualifier_type_names;
+ entry->components = linked_list_create();
+
+ this->list->insert_last(this->list, entry);
+ DBG2(DBG_PTS, "added %N functional component namespace",
+ pen_names, vendor_id);
+}
+
+METHOD(pts_component_manager_t, get_comp_func_names, enum_name_t*,
+ private_pts_component_manager_t *this, pen_t vendor_id)
+{
+ enumerator_t *enumerator;
+ vendor_entry_t *entry;
+ enum_name_t *names = NULL;
+
+ enumerator = this->list->create_enumerator(this->list);
+ while (enumerator->enumerate(enumerator, &entry))
+ {
+ if (entry->vendor_id == vendor_id)
+ {
+ names = entry->comp_func_names;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ return names;
+}
+
+METHOD(pts_component_manager_t, get_qualifier_type_names, enum_name_t*,
+ private_pts_component_manager_t *this, pen_t vendor_id)
+{
+ enumerator_t *enumerator;
+ vendor_entry_t *entry;
+ enum_name_t *names = NULL;
+
+ enumerator = this->list->create_enumerator(this->list);
+ while (enumerator->enumerate(enumerator, &entry))
+ {
+ if (entry->vendor_id == vendor_id)
+ {
+ names = entry->qualifier_type_names;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ return names;
+}
+
+METHOD(pts_component_manager_t, add_component, void,
+ private_pts_component_manager_t *this, pen_t vendor_id, u_int32_t name,
+ pts_component_create_t create)
+{
+ enumerator_t *enumerator;
+ vendor_entry_t *entry;
+ component_entry_t *component;
+
+ enumerator = this->list->create_enumerator(this->list);
+ while (enumerator->enumerate(enumerator, &entry))
+ {
+ if (entry->vendor_id == vendor_id)
+ {
+ component = malloc_thing(component_entry_t);
+ component->name = name;
+ component->create = create;
+
+ entry->components->insert_last(entry->components, component);
+ DBG2(DBG_PTS, "added %N functional component '%N'",
+ pen_names, vendor_id,
+ get_comp_func_names(this, vendor_id), name);
+ }
+ }
+ enumerator->destroy(enumerator);
+}
+
+METHOD(pts_component_manager_t, remove_vendor, void,
+ private_pts_component_manager_t *this, pen_t vendor_id)
+{
+ enumerator_t *enumerator;
+ vendor_entry_t *entry;
+
+ enumerator = this->list->create_enumerator(this->list);
+ while (enumerator->enumerate(enumerator, &entry))
+ {
+ if (entry->vendor_id == vendor_id)
+ {
+ this->list->remove_at(this->list, enumerator);
+ vendor_entry_destroy(entry);
+ DBG2(DBG_PTS, "removed %N functional component namespace",
+ pen_names, vendor_id);
+ }
+ }
+ enumerator->destroy(enumerator);
+}
+
+METHOD(pts_component_manager_t, get_qualifier, u_int8_t,
+ private_pts_component_manager_t *this, pts_comp_func_name_t *name,
+ char *flags)
+{
+ enumerator_t *enumerator;
+ vendor_entry_t *entry;
+ u_int8_t qualifier, size, flag, type = 0;
+ int i;
+
+ enumerator = this->list->create_enumerator(this->list);
+ while (enumerator->enumerate(enumerator, &entry))
+ {
+ if (entry->vendor_id == name->get_vendor_id(name))
+ {
+ qualifier = name->get_qualifier(name);
+ size = entry->qualifier_type_size;
+
+ /* mask qualifier type field */
+ type = qualifier & ((1 << size) - 1);
+
+ /* determine flags */
+ size = PTS_QUALIFIER_SIZE - size;
+ flag = (1 << (PTS_QUALIFIER_SIZE - 1));
+ if (flags)
+ {
+ for (i = 0 ; i < size; i++)
+ {
+ flags[i] = (qualifier & flag) ?
+ entry->qualifier_flag_names[i] : '.';
+ flag >>= 1;
+ }
+ flags[size] = '\0';
+ }
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ return type;
+}
+
+METHOD(pts_component_manager_t, create, pts_component_t*,
+ private_pts_component_manager_t *this,
+ pts_comp_func_name_t *name, u_int32_t depth, pts_database_t *pts_db)
+{
+ enumerator_t *enumerator, *e2;
+ vendor_entry_t *entry;
+ component_entry_t *entry2;
+ pts_component_t *component = NULL;
+
+ enumerator = this->list->create_enumerator(this->list);
+ while (enumerator->enumerate(enumerator, &entry))
+ {
+ if (entry->vendor_id == name->get_vendor_id(name))
+ {
+ e2 = entry->components->create_enumerator(entry->components);
+ while (e2->enumerate(e2, &entry2))
+ {
+ if (entry2->name == name->get_name(name) && entry2->create)
+ {
+ component = entry2->create(name->get_qualifier(name),
+ depth, pts_db);
+ break;
+ }
+ }
+ e2->destroy(e2);
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ return component;
+}
+
+METHOD(pts_component_manager_t, destroy, void,
+ private_pts_component_manager_t *this)
+{
+ this->list->destroy_function(this->list, (void *)vendor_entry_destroy);
+ free(this);
+}
+
+/**
+ * See header
+ */
+pts_component_manager_t *pts_component_manager_create(void)
+{
+ private_pts_component_manager_t *this;
+
+ INIT(this,
+ .public = {
+ .add_vendor = _add_vendor,
+ .add_component = _add_component,
+ .remove_vendor = _remove_vendor,
+ .get_comp_func_names = _get_comp_func_names,
+ .get_qualifier_type_names = _get_qualifier_type_names,
+ .get_qualifier = _get_qualifier,
+ .create = _create,
+ .destroy = _destroy,
+ },
+ .list = linked_list_create(),
+ );
+
+ return &this->public;
+}
+
diff --git a/src/libpts/pts/components/pts_component_manager.h b/src/libpts/pts/components/pts_component_manager.h
new file mode 100644
index 000000000..0079d0e26
--- /dev/null
+++ b/src/libpts/pts/components/pts_component_manager.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2011 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 pts_component_manager pts_component_manager
+ * @{ @ingroup pts
+ */
+
+#ifndef PTS_COMPONENT_MANAGER_H_
+#define PTS_COMPONENT_MANAGER_H_
+
+typedef struct pts_component_manager_t pts_component_manager_t;
+
+#include "pts/pts_database.h"
+#include "pts/components/pts_component.h"
+#include "pts/components/pts_comp_func_name.h"
+
+#include <library.h>
+#include <pen/pen.h>
+
+typedef pts_component_t* (*pts_component_create_t)(u_int8_t qualifier,
+ u_int32_t depth,
+ pts_database_t *pts_db);
+
+/**
+ * Manages PTS Functional Components
+ */
+struct pts_component_manager_t {
+
+ /**
+ * Add vendor-specific functional component names
+ *
+ * @param vendor_id Private Enterprise Number (PEN)
+ * @param comp_func_names Vendor-specific Component Functional names
+ * @param qualifier_type_size Vendor-specific Qualifier Type size
+ * @param qualifier_flag_names Vendor-specific Qualifier Flag names
+ * @param qualifier_type_names Vendor-specific Qualifier Type names
+ */
+ void (*add_vendor)(pts_component_manager_t *this, pen_t vendor_id,
+ enum_name_t *comp_func_names,
+ int qualifier_type_size,
+ char *qualifier_flag_names,
+ enum_name_t *qualifier_type_names);
+
+ /**
+ * Add vendor-specific functional component
+ *
+ * @param vendor_id Private Enterprise Number (PEN)
+ * @param names Component Functional Name
+ * @param create Functional Component creation method
+ */
+ void (*add_component)(pts_component_manager_t *this, pen_t vendor_id,
+ u_int32_t name, pts_component_create_t create);
+
+ /**
+ * Remove vendor-specific components and associated namespace
+ *
+ * @param vendor_id Private Enterprise Number (PEN)
+ */
+ void (*remove_vendor)(pts_component_manager_t *this, pen_t vendor_id);
+
+ /**
+ * Return the Functional Component names for a given vendor ID
+ *
+ * @param vendor_id Private Enterprise Number (PEN)
+ * @return Comp. Func. names if found, NULL else
+ */
+ enum_name_t* (*get_comp_func_names)(pts_component_manager_t *this,
+ pen_t vendor_id);
+
+ /**
+ * Return the Functional Component Qualifier Type names for a given vendor ID
+ *
+ * @param vendor_id Private Enterprise Number (PEN)
+ * @return Qualifier Type names if found, NULL else
+ */
+ enum_name_t* (*get_qualifier_type_names)(pts_component_manager_t *this,
+ pen_t vendor_id);
+
+ /**
+ * Return the Qualifier Type and Flags
+ *
+ * @param name Component Functional Name
+ * @param flags Qualifier Flags as a string in a char buffer
+ * @return Qualifier Type
+ */
+ u_int8_t (*get_qualifier)(pts_component_manager_t *this,
+ pts_comp_func_name_t *name, char *flags);
+
+ /**
+ * Create a PTS Component object from a Functional Component Name object
+ *
+ * @param name Component Functional Name
+ * @param depth Sub-component Depth
+ * @param pts_db PTS measurement database
+ * @return Component object if supported, NULL else
+ */
+ pts_component_t* (*create)(pts_component_manager_t *this,
+ pts_comp_func_name_t *name, u_int32_t depth,
+ pts_database_t *pts_db);
+
+ /**
+ * Destroys a pts_component_manager_t object.
+ */
+ void (*destroy)(pts_component_manager_t *this);
+};
+
+/**
+ * Create a PA-TNC attribute manager
+ */
+pts_component_manager_t* pts_component_manager_create(void);
+
+#endif /** PTS_COMPONENT_MANAGER_H_ @}*/
diff --git a/src/libpts/pts/components/tcg/tcg_comp_func_name.c b/src/libpts/pts/components/tcg/tcg_comp_func_name.c
new file mode 100644
index 000000000..a70c84e48
--- /dev/null
+++ b/src/libpts/pts/components/tcg/tcg_comp_func_name.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2011 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 "tcg_comp_func_name.h"
+
+char pts_tcg_qualifier_flag_names[] = { 'K', 'S' };
+
+ENUM_BEGIN(pts_tcg_qualifier_type_names, PTS_TCG_QUALIFIER_TYPE_UNKNOWN,
+ PTS_TCG_QUALIFIER_TYPE_TNC,
+ "Unknown",
+ "Trusted Platform",
+ "Operating System",
+ "Graphical User Interface",
+ "Application",
+ "Networking",
+ "Library",
+ "TNC Defined Component"
+);
+ENUM_NEXT(pts_tcg_qualifier_type_names, PTS_TCG_QUALIFIER_TYPE_ALL,
+ PTS_TCG_QUALIFIER_TYPE_ALL,
+ PTS_TCG_QUALIFIER_TYPE_TNC,
+ "All Matching Components"
+);
+ENUM_END(pts_tcg_qualifier_type_names, PTS_TCG_QUALIFIER_TYPE_ALL);
+
+ENUM(pts_tcg_comp_func_names, PTS_TCG_COMP_FUNC_NAME_IGNORE,
+ PTS_TCG_COMP_FUNC_NAME_OPT_ROMS,
+ "Ignore",
+ "CRTM",
+ "BIOS",
+ "Platform Extensions",
+ "Motherboard Firmware",
+ "Initial Program Loader",
+ "Option ROMs"
+);
+
diff --git a/src/libpts/pts/components/tcg/tcg_comp_func_name.h b/src/libpts/pts/components/tcg/tcg_comp_func_name.h
new file mode 100644
index 000000000..9708ad09d
--- /dev/null
+++ b/src/libpts/pts/components/tcg/tcg_comp_func_name.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2011 Sansar Choinyambuu
+ * 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 pts_tcg_comp_func_name pts_tcg_comp_func_name
+ * @{ @ingroup pts
+ */
+
+#ifndef PTS_TCG_COMP_FUNC_NAME_H_
+#define PTS_TCG_COMP_FUNC_NAME_H_
+
+typedef enum pts_tcg_qualifier_type_t pts_tcg_qualifier_type_t;
+typedef enum pts_tcg_comp_func_name_t pts_tcp_comp_func_name_t;
+
+#include <library.h>
+
+/**
+ * PTS Component Functional Name Qualifier Flags for the TCG namespace
+ * see section 5.2 of PTS Protocol: Binding to TNC IF-M Specification
+ *
+ * 0 1 2 3 4 5
+ * +-+-+-+-+-+-+
+ * |K|S| Type |
+ * +-+-+-+-+-+-+
+ */
+#define PTS_TCG_QUALIFIER_FLAG_KERNEL (1<<5)
+#define PTS_TCG_QUALIFIER_FLAG_SUB (1<<4)
+
+extern char pts_tcg_qualifier_flag_names[];
+
+/**
+ * Size of the PTS Component Functional Name Qualifier Type field
+ */
+#define PTS_TCG_QUALIFIER_TYPE_SIZE 4
+
+/**
+ * PTS Component Functional Name Qualifier Types for the TCG namespace
+ * see section 5.2 of PTS Protocol: Binding to TNC IF-M Specification
+ */
+enum pts_tcg_qualifier_type_t {
+ /** Unknown */
+ PTS_TCG_QUALIFIER_TYPE_UNKNOWN = 0x0,
+ /** Trusted Platform */
+ PTS_TCG_QUALIFIER_TYPE_TRUSTED = 0x1,
+ /** Operating System */
+ PTS_TCG_QUALIFIER_TYPE_OS = 0x2,
+ /** Graphical User Interface */
+ PTS_TCG_QUALIFIER_TYPE_GUI = 0x3,
+ /** Application */
+ PTS_TCG_QUALIFIER_TYPE_APP = 0x4,
+ /** Networking */
+ PTS_TCG_QUALIFIER_TYPE_NET = 0x5,
+ /** Library */
+ PTS_TCG_QUALIFIER_TYPE_LIB = 0x6,
+ /** TNC Defined Component */
+ PTS_TCG_QUALIFIER_TYPE_TNC = 0x7,
+ /** All matching Components */
+ PTS_TCG_QUALIFIER_TYPE_ALL = 0xF,
+};
+
+extern enum_name_t *pts_tcg_qualifier_type_names;
+
+/**
+ * PTS Component Functional Name Binary Enumeration for the TCG namespace
+ * see section 5.3 of PTS Protocol: Binding to TNC IF-M Specification
+ */
+enum pts_tcg_comp_func_name_t {
+ /** Ignore */
+ PTS_TCG_COMP_FUNC_NAME_IGNORE = 0x0000,
+ /** CRTM */
+ PTS_TCG_COMP_FUNC_NAME_CRTM = 0x0001,
+ /** BIOS */
+ PTS_TCG_COMP_FUNC_NAME_BIOS = 0x0002,
+ /** Platform Extensions */
+ PTS_TCG_COMP_FUNC_NAME_PLATFORM_EXT = 0x0003,
+ /** Motherboard Firmware */
+ PTS_TCG_COMP_FUNC_NAME_BOARD = 0x0004,
+ /** Initial Program Loader */
+ PTS_TCG_COMP_FUNC_NAME_INIT_LOADER = 0x0005,
+ /** Option ROMs */
+ PTS_TCG_COMP_FUNC_NAME_OPT_ROMS = 0x0006,
+};
+
+extern enum_name_t *pts_tcg_comp_func_names;
+
+#endif /** PTS_TCG_COMP_FUNC_NAME_H_ @}*/
diff --git a/src/libpts/pts/pts.c b/src/libpts/pts/pts.c
index f768b4679..65ae2b2d2 100644
--- a/src/libpts/pts/pts.c
+++ b/src/libpts/pts/pts.c
@@ -17,6 +17,8 @@
#include <debug.h>
#include <crypto/hashers/hasher.h>
+#include <bio/bio_writer.h>
+#include <bio/bio_reader.h>
#include <trousers/tss.h>
#include <trousers/trousers.h>
@@ -27,6 +29,16 @@
#define PTS_BUF_SIZE 4096
+/**
+ * Maximum number of PCR's of TPM, TPM Spec 1.2
+ */
+#define PCR_MAX_NUM 24
+
+/**
+ * Number of bytes that can be saved in a PCR of TPM, TPM Spec 1.2
+ */
+#define PCR_LEN 20
+
typedef struct private_pts_t private_pts_t;
/**
@@ -51,11 +63,41 @@ struct private_pts_t {
pts_meas_algorithms_t algorithm;
/**
+ * DH Hash Algorithm
+ */
+ pts_meas_algorithms_t dh_hash_algorithm;
+
+ /**
+ * PTS Diffie-Hellman Secret
+ */
+ diffie_hellman_t *dh;
+
+ /**
+ * PTS Diffie-Hellman Initiator Nonce
+ */
+ chunk_t initiator_nonce;
+
+ /**
+ * PTS Diffie-Hellman Responder Nonce
+ */
+ chunk_t responder_nonce;
+
+ /**
+ * Secret assessment value to be used for TPM Quote as an external data
+ */
+ chunk_t secret;
+
+ /**
* Platform and OS Info
*/
char *platform_info;
/**
+ * TRUE if IMC-PTS, FALSE if IMV-PTS
+ */
+ bool is_imc;
+
+ /**
* Do we have an activated TPM
*/
bool has_tpm;
@@ -66,10 +108,40 @@ struct private_pts_t {
chunk_t tpm_version_info;
/**
+ * Contains TSS Blob structure for AIK
+ */
+ chunk_t aik_blob;
+
+ /**
* Contains a Attestation Identity Key or Certificate
*/
certificate_t *aik;
+ /**
+ * Table of extended PCRs with corresponding values
+ */
+ u_char* pcrs[PCR_MAX_NUM];
+
+ /**
+ * Length of PCR registers
+ */
+ size_t pcr_len;
+
+ /**
+ * Number of extended PCR registers
+ */
+ u_int32_t pcr_count;
+
+ /**
+ * Highest extended PCR register
+ */
+ u_int32_t pcr_max;
+
+ /**
+ * Bitmap of extended PCR registers
+ */
+ u_int8_t pcr_select[PCR_MAX_NUM / 8];
+
};
METHOD(pts_t, get_proto_caps, pts_proto_caps_flag_t,
@@ -79,7 +151,7 @@ METHOD(pts_t, get_proto_caps, pts_proto_caps_flag_t,
}
METHOD(pts_t, set_proto_caps, void,
- private_pts_t *this, pts_proto_caps_flag_t flags)
+ private_pts_t *this, pts_proto_caps_flag_t flags)
{
this->proto_caps = flags;
DBG2(DBG_PTS, "supported PTS protocol capabilities: %s%s%s%s%s",
@@ -91,25 +163,143 @@ METHOD(pts_t, set_proto_caps, void,
}
METHOD(pts_t, get_meas_algorithm, pts_meas_algorithms_t,
- private_pts_t *this)
+ private_pts_t *this)
{
return this->algorithm;
}
METHOD(pts_t, set_meas_algorithm, void,
- private_pts_t *this, pts_meas_algorithms_t algorithm)
+ private_pts_t *this, pts_meas_algorithms_t algorithm)
{
hash_algorithm_t hash_alg;
- hash_alg = pts_meas_to_hash_algorithm(algorithm);
+ hash_alg = pts_meas_algo_to_hash(algorithm);
DBG2(DBG_PTS, "selected PTS measurement algorithm is %N",
- hash_algorithm_names, hash_alg);
+ hash_algorithm_names, hash_alg);
if (hash_alg != HASH_UNKNOWN)
{
this->algorithm = algorithm;
}
}
+METHOD(pts_t, get_dh_hash_algorithm, pts_meas_algorithms_t,
+ private_pts_t *this)
+{
+ return this->dh_hash_algorithm;
+}
+
+METHOD(pts_t, set_dh_hash_algorithm, void,
+ private_pts_t *this, pts_meas_algorithms_t algorithm)
+{
+ hash_algorithm_t hash_alg;
+
+ hash_alg = pts_meas_algo_to_hash(algorithm);
+ DBG2(DBG_PTS, "selected DH hash algorithm is %N",
+ hash_algorithm_names, hash_alg);
+ if (hash_alg != HASH_UNKNOWN)
+ {
+ this->dh_hash_algorithm = algorithm;
+ }
+}
+
+
+METHOD(pts_t, create_dh_nonce, bool,
+ private_pts_t *this, pts_dh_group_t group, int nonce_len)
+{
+ diffie_hellman_group_t dh_group;
+ chunk_t *nonce;
+ rng_t *rng;
+
+ dh_group = pts_dh_group_to_ike(group);
+ DBG2(DBG_PTS, "selected PTS DH group is %N",
+ diffie_hellman_group_names, dh_group);
+ DESTROY_IF(this->dh);
+ this->dh = lib->crypto->create_dh(lib->crypto, dh_group);
+
+ rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG);
+ if (!rng)
+ {
+ DBG1(DBG_PTS, "no rng available");
+ return FALSE;
+ }
+ DBG2(DBG_PTS, "nonce length is %d", nonce_len);
+ nonce = this->is_imc ? &this->responder_nonce : &this->initiator_nonce;
+ chunk_free(nonce);
+ rng->allocate_bytes(rng, nonce_len, nonce);
+ rng->destroy(rng);
+
+ return TRUE;
+}
+
+METHOD(pts_t, get_my_public_value, void,
+ private_pts_t *this, chunk_t *value, chunk_t *nonce)
+{
+ this->dh->get_my_public_value(this->dh, value);
+ *nonce = this->is_imc ? this->responder_nonce : this->initiator_nonce;
+}
+
+METHOD(pts_t, set_peer_public_value, void,
+ private_pts_t *this, chunk_t value, chunk_t nonce)
+{
+ this->dh->set_other_public_value(this->dh, value);
+
+ nonce = chunk_clone(nonce);
+ if (this->is_imc)
+ {
+ this->initiator_nonce = nonce;
+ }
+ else
+ {
+ this->responder_nonce = nonce;
+ }
+}
+
+METHOD(pts_t, calculate_secret, bool,
+ private_pts_t *this)
+{
+ hasher_t *hasher;
+ hash_algorithm_t hash_alg;
+ chunk_t shared_secret;
+
+ /* Check presence of nonces */
+ if (!this->initiator_nonce.len || !this->responder_nonce.len)
+ {
+ DBG1(DBG_PTS, "initiator and/or responder nonce is not available");
+ return FALSE;
+ }
+ DBG3(DBG_PTS, "initiator nonce: %B", &this->initiator_nonce);
+ DBG3(DBG_PTS, "responder nonce: %B", &this->responder_nonce);
+
+ /* Calculate the DH secret */
+ if (this->dh->get_shared_secret(this->dh, &shared_secret) != SUCCESS)
+ {
+ DBG1(DBG_PTS, "shared DH secret computation failed");
+ return FALSE;
+ }
+ DBG3(DBG_PTS, "shared DH secret: %B", &shared_secret);
+
+ /* Calculate the secret assessment value */
+ hash_alg = pts_meas_algo_to_hash(this->dh_hash_algorithm);
+ hasher = lib->crypto->create_hasher(lib->crypto, hash_alg);
+
+ hasher->allocate_hash(hasher, chunk_from_chars('1'), NULL);
+ hasher->allocate_hash(hasher, this->initiator_nonce, NULL);
+ hasher->allocate_hash(hasher, this->responder_nonce, NULL);
+ hasher->allocate_hash(hasher, shared_secret, &this->secret);
+ hasher->destroy(hasher);
+
+ /* The DH secret must be destroyed */
+ chunk_clear(&shared_secret);
+
+ /*
+ * Truncate the hash to 20 bytes to fit the ExternalData
+ * argument of the TPM Quote command
+ */
+ this->secret.len = min(this->secret.len, 20);
+ DBG3(DBG_PTS, "secret assessment value: %B", &this->secret);
+ return TRUE;
+}
+
/**
* Print TPM 1.2 Version Info
*/
@@ -138,20 +328,20 @@ static void print_tpm_version_info(private_pts_t *this)
}
METHOD(pts_t, get_platform_info, char*,
- private_pts_t *this)
+ private_pts_t *this)
{
return this->platform_info;
}
METHOD(pts_t, set_platform_info, void,
- private_pts_t *this, char *info)
+ private_pts_t *this, char *info)
{
free(this->platform_info);
this->platform_info = strdup(info);
}
METHOD(pts_t, get_tpm_version_info, bool,
- private_pts_t *this, chunk_t *info)
+ private_pts_t *this, chunk_t *info)
{
if (!this->has_tpm)
{
@@ -163,14 +353,62 @@ METHOD(pts_t, get_tpm_version_info, bool,
}
METHOD(pts_t, set_tpm_version_info, void,
- private_pts_t *this, chunk_t info)
+ private_pts_t *this, chunk_t info)
{
this->tpm_version_info = chunk_clone(info);
print_tpm_version_info(this);
}
+METHOD(pts_t, get_pcr_len, size_t,
+ private_pts_t *this)
+{
+ return this->pcr_len;
+}
+
+/**
+ * Load an AIK Blob (TSS_TSPATTRIB_KEYBLOB_BLOB attribute)
+ */
+static void load_aik_blob(private_pts_t *this)
+{
+ char *blob_path;
+ FILE *fp;
+ u_int32_t aikBlobLen;
+
+ blob_path = lib->settings->get_str(lib->settings,
+ "libimcv.plugins.imc-attestation.aik_blob", NULL);
+
+ if (blob_path)
+ {
+ /* Read aik key blob from a file */
+ if ((fp = fopen(blob_path, "r")) == NULL)
+ {
+ DBG1(DBG_PTS, "unable to open AIK Blob file: %s", blob_path);
+ return;
+ }
+
+ fseek(fp, 0, SEEK_END);
+ aikBlobLen = ftell(fp);
+ fseek(fp, 0L, SEEK_SET);
+
+ this->aik_blob = chunk_alloc(aikBlobLen);
+ if (fread(this->aik_blob.ptr, 1, aikBlobLen, fp))
+ {
+ DBG2(DBG_PTS, "loaded AIK Blob from '%s'", blob_path);
+ DBG3(DBG_PTS, "AIK Blob: %B", &this->aik_blob);
+ }
+ else
+ {
+ DBG1(DBG_PTS, "unable to read AIK Blob file '%s'", blob_path);
+ }
+ fclose(fp);
+ return;
+ }
+
+ DBG1(DBG_PTS, "AIK Blob is not available");
+}
+
/**
- * Load an AIK certificate or public key,
+ * Load an AIK certificate or public key
* the certificate having precedence over the public key if both are present
*/
static void load_aik(private_pts_t *this)
@@ -204,26 +442,52 @@ static void load_aik(private_pts_t *this)
return;
}
}
+
DBG1(DBG_PTS, "neither AIK certificate nor public key is available");
}
METHOD(pts_t, get_aik, certificate_t*,
- private_pts_t *this)
+ private_pts_t *this)
{
- return this->aik;
+ return this->aik;
}
METHOD(pts_t, set_aik, void,
- private_pts_t *this, certificate_t *aik)
+ private_pts_t *this, certificate_t *aik)
{
DESTROY_IF(this->aik);
this->aik = aik->get_ref(aik);
}
-/**
- * Compute a hash over a file
- */
-static bool hash_file(hasher_t *hasher, char *pathname, u_char *hash)
+METHOD(pts_t, get_aik_keyid, bool,
+ private_pts_t *this, chunk_t *keyid)
+{
+ public_key_t *public;
+ bool success;
+
+ if (!this->aik)
+ {
+ DBG1(DBG_PTS, "no AIK certificate available");
+ return FALSE;
+ }
+ public = this->aik->get_public_key(this->aik);
+ if (!public)
+ {
+ DBG1(DBG_PTS, "no AIK public key available");
+ return FALSE;
+ }
+ success = public->get_fingerprint(public, KEYID_PUBKEY_INFO_SHA1, keyid);
+ if (!success)
+ {
+ DBG1(DBG_PTS, "no SHA-1 AIK public key info ID available");
+ }
+ public->destroy(public);
+
+ return success;
+}
+
+METHOD(pts_t, hash_file, bool,
+ private_pts_t *this, hasher_t *hasher, char *pathname, u_char *hash)
{
u_char buffer[PTS_BUF_SIZE];
FILE *file;
@@ -270,24 +534,23 @@ static char* get_filename(char *pathname)
return filename;
}
-METHOD(pts_t, is_path_valid, bool, private_pts_t *this, char *path,
- pts_error_code_t *error_code)
+METHOD(pts_t, is_path_valid, bool,
+ private_pts_t *this, char *path, pts_error_code_t *error_code)
{
- int error;
- struct stat sb;
-
+ struct stat st;
+
*error_code = 0;
- error = stat(path, &sb);
- if (error == 0)
+
+ if (!stat(path, &st))
{
return TRUE;
}
- else if (error == ENOENT || error == ENOTDIR)
+ else if (errno == ENOENT || errno == ENOTDIR)
{
DBG1(DBG_PTS, "file/directory does not exist %s", path);
*error_code = TCG_PTS_FILE_NOT_FOUND;
}
- else if (error == EFAULT)
+ else if (errno == EFAULT)
{
DBG1(DBG_PTS, "bad address %s", path);
*error_code = TCG_PTS_INVALID_PATH;
@@ -295,7 +558,7 @@ METHOD(pts_t, is_path_valid, bool, private_pts_t *this, char *path,
else
{
DBG1(DBG_PTS, "error: %s occurred while validating path: %s",
- strerror(error), path);
+ strerror(errno), path);
return FALSE;
}
@@ -303,7 +566,7 @@ METHOD(pts_t, is_path_valid, bool, private_pts_t *this, char *path,
}
METHOD(pts_t, do_measurements, pts_file_meas_t*,
- private_pts_t *this, u_int16_t request_id, char *pathname, bool is_directory)
+ private_pts_t *this, u_int16_t request_id, char *pathname, bool is_directory)
{
hasher_t *hasher;
hash_algorithm_t hash_alg;
@@ -312,11 +575,11 @@ METHOD(pts_t, do_measurements, pts_file_meas_t*,
pts_file_meas_t *measurements;
/* Create a hasher */
- hash_alg = pts_meas_to_hash_algorithm(this->algorithm);
+ hash_alg = pts_meas_algo_to_hash(this->algorithm);
hasher = lib->crypto->create_hasher(lib->crypto, hash_alg);
if (!hasher)
{
- DBG1(DBG_PTS, " hasher %N not available", hash_algorithm_names, hash_alg);
+ DBG1(DBG_PTS, "hasher %N not available", hash_algorithm_names, hash_alg);
return NULL;
}
@@ -346,7 +609,7 @@ METHOD(pts_t, do_measurements, pts_file_meas_t*,
/* measure regular files only */
if (S_ISREG(st.st_mode) && *rel_name != '.')
{
- if (!hash_file(hasher, abs_name, hash))
+ if (!hash_file(this, hasher, abs_name, hash))
{
enumerator->destroy(enumerator);
hasher->destroy(hasher);
@@ -363,7 +626,7 @@ METHOD(pts_t, do_measurements, pts_file_meas_t*,
{
char *filename;
- if (!hash_file(hasher, pathname, hash))
+ if (!hash_file(this, hasher, pathname, hash))
{
hasher->destroy(hasher);
measurements->destroy(measurements);
@@ -378,23 +641,683 @@ METHOD(pts_t, do_measurements, pts_file_meas_t*,
return measurements;
}
+/**
+ * Obtain statistical information describing a file
+ */
+static bool file_metadata(char *pathname, pts_file_metadata_t **entry)
+{
+ struct stat st;
+ pts_file_metadata_t *this;
+
+ this = malloc_thing(pts_file_metadata_t);
+
+ if (stat(pathname, &st))
+ {
+ DBG1(DBG_PTS, "unable to obtain statistics about '%s'", pathname);
+ return FALSE;
+ }
+
+ if (S_ISREG(st.st_mode))
+ {
+ this->type = PTS_FILE_REGULAR;
+ }
+ else if (S_ISDIR(st.st_mode))
+ {
+ this->type = PTS_FILE_DIRECTORY;
+ }
+ else if (S_ISCHR(st.st_mode))
+ {
+ this->type = PTS_FILE_CHAR_SPEC;
+ }
+ else if (S_ISBLK(st.st_mode))
+ {
+ this->type = PTS_FILE_BLOCK_SPEC;
+ }
+ else if (S_ISFIFO(st.st_mode))
+ {
+ this->type = PTS_FILE_FIFO;
+ }
+ else if (S_ISLNK(st.st_mode))
+ {
+ this->type = PTS_FILE_SYM_LINK;
+ }
+ else if (S_ISSOCK(st.st_mode))
+ {
+ this->type = PTS_FILE_SOCKET;
+ }
+ else
+ {
+ this->type = PTS_FILE_OTHER;
+ }
+
+ this->filesize = st.st_size;
+ this->created = st.st_ctime;
+ this->modified = st.st_mtime;
+ this->accessed = st.st_atime;
+ this->owner = st.st_uid;
+ this->group = st.st_gid;
+
+ *entry = this;
+ return TRUE;
+}
+
+METHOD(pts_t, get_metadata, pts_file_meta_t*,
+ private_pts_t *this, char *pathname, bool is_directory)
+{
+ pts_file_meta_t *metadata;
+ pts_file_metadata_t *entry;
+
+ /* Create a metadata object */
+ metadata = pts_file_meta_create();
+
+ if (is_directory)
+ {
+ enumerator_t *enumerator;
+ char *rel_name, *abs_name;
+ struct stat st;
+
+ enumerator = enumerator_create_directory(pathname);
+ if (!enumerator)
+ {
+ DBG1(DBG_PTS," directory '%s' can not be opened, %s", pathname,
+ strerror(errno));
+ metadata->destroy(metadata);
+ return NULL;
+ }
+ while (enumerator->enumerate(enumerator, &rel_name, &abs_name, &st))
+ {
+ /* measure regular files only */
+ if (S_ISREG(st.st_mode) && *rel_name != '.')
+ {
+ if (!file_metadata(abs_name, &entry))
+ {
+ enumerator->destroy(enumerator);
+ metadata->destroy(metadata);
+ return NULL;
+ }
+ entry->filename = strdup(rel_name);
+ metadata->add(metadata, entry);
+ }
+ }
+ enumerator->destroy(enumerator);
+ }
+ else
+ {
+ if (!file_metadata(pathname, &entry))
+ {
+ metadata->destroy(metadata);
+ return NULL;
+ }
+ entry->filename = strdup(get_filename(pathname));
+ metadata->add(metadata, entry);
+ }
+
+ return metadata;
+}
+
+METHOD(pts_t, read_pcr, bool,
+ private_pts_t *this, u_int32_t pcr_num, chunk_t *pcr_value)
+{
+ TSS_HCONTEXT hContext;
+ TSS_HTPM hTPM;
+ TSS_RESULT result;
+ chunk_t rgbPcrValue;
+
+ bool success = FALSE;
+
+ result = Tspi_Context_Create(&hContext);
+ if (result != TSS_SUCCESS)
+ {
+ DBG1(DBG_PTS, "TPM context could not be created: tss error 0x%x", result);
+ return FALSE;
+ }
+
+ result = Tspi_Context_Connect(hContext, NULL);
+ if (result != TSS_SUCCESS)
+ {
+ goto err;
+ }
+ result = Tspi_Context_GetTpmObject (hContext, &hTPM);
+ if (result != TSS_SUCCESS)
+ {
+ goto err;
+ }
+ result = Tspi_TPM_PcrRead(hTPM, pcr_num, (UINT32*)&rgbPcrValue.len, &rgbPcrValue.ptr);
+ if (result != TSS_SUCCESS)
+ {
+ goto err;
+ }
+ *pcr_value = chunk_clone(rgbPcrValue);
+ DBG3(DBG_PTS, "PCR %d value:%B", pcr_num, pcr_value);
+ success = TRUE;
+
+err:
+ if (!success)
+ {
+ DBG1(DBG_PTS, "TPM not available: tss error 0x%x", result);
+ }
+ Tspi_Context_FreeMemory(hContext, NULL);
+ Tspi_Context_Close(hContext);
+
+ return success;
+}
+
+METHOD(pts_t, extend_pcr, bool,
+ private_pts_t *this, u_int32_t pcr_num, chunk_t input, chunk_t *output)
+{
+ TSS_HCONTEXT hContext;
+ TSS_HTPM hTPM;
+ TSS_RESULT result;
+ u_int32_t pcr_length;
+ chunk_t pcr_value;
+
+ result = Tspi_Context_Create(&hContext);
+ if (result != TSS_SUCCESS)
+ {
+ DBG1(DBG_PTS, "TPM context could not be created: tss error 0x%x",
+ result);
+ return FALSE;
+ }
+ result = Tspi_Context_Connect(hContext, NULL);
+ if (result != TSS_SUCCESS)
+ {
+ goto err;
+ }
+ result = Tspi_Context_GetTpmObject (hContext, &hTPM);
+ if (result != TSS_SUCCESS)
+ {
+ goto err;
+ }
+
+ pcr_value = chunk_alloc(PCR_LEN);
+ result = Tspi_TPM_PcrExtend(hTPM, pcr_num, PCR_LEN, input.ptr,
+ NULL, &pcr_length, &pcr_value.ptr);
+ if (result != TSS_SUCCESS)
+ {
+ goto err;
+ }
+
+ *output = pcr_value;
+ *output = chunk_clone(*output);
+
+ DBG3(DBG_PTS, "PCR %d extended with: %B", pcr_num, &input);
+ DBG3(DBG_PTS, "PCR %d value after extend: %B", pcr_num, output);
+
+ chunk_clear(&pcr_value);
+ Tspi_Context_FreeMemory(hContext, NULL);
+ Tspi_Context_Close(hContext);
+
+ return TRUE;
+
+err:
+ DBG1(DBG_PTS, "TPM not available: tss error 0x%x", result);
+
+ chunk_clear(&pcr_value);
+ Tspi_Context_FreeMemory(hContext, NULL);
+ Tspi_Context_Close(hContext);
+
+ return FALSE;
+}
+
+
+static void clear_pcrs(private_pts_t *this)
+{
+ int i;
+
+ for (i = 0; i <= this->pcr_max; i++)
+ {
+ free(this->pcrs[i]);
+ this->pcrs[i] = NULL;
+ }
+ this->pcr_count = 0;
+ this->pcr_max = 0;
+
+ memset(this->pcr_select, 0x00, sizeof(this->pcr_select));
+}
+
+METHOD(pts_t, quote_tpm, bool,
+ private_pts_t *this, bool use_quote2, chunk_t *pcr_comp, chunk_t *quote_sig)
+{
+ TSS_HCONTEXT hContext;
+ TSS_HTPM hTPM;
+ TSS_HKEY hAIK;
+ TSS_HKEY hSRK;
+ TSS_HPOLICY srkUsagePolicy;
+ TSS_UUID SRK_UUID = TSS_UUID_SRK;
+ BYTE secret[] = TSS_WELL_KNOWN_SECRET;
+ TSS_HPCRS hPcrComposite;
+ TSS_VALIDATION valData;
+ TSS_RESULT result;
+ chunk_t quote_info;
+ BYTE* versionInfo;
+ u_int32_t versionInfoSize, pcr, i = 0, f = 1;
+ bool success = FALSE;
+
+ result = Tspi_Context_Create(&hContext);
+ if (result != TSS_SUCCESS)
+ {
+ DBG1(DBG_PTS, "TPM context could not be created: tss error 0x%x",
+ result);
+ return FALSE;
+ }
+ result = Tspi_Context_Connect(hContext, NULL);
+ if (result != TSS_SUCCESS)
+ {
+ goto err1;
+ }
+ result = Tspi_Context_GetTpmObject (hContext, &hTPM);
+ if (result != TSS_SUCCESS)
+ {
+ goto err1;
+ }
+
+ /* Retrieve SRK from TPM and set the authentication to well known secret*/
+ result = Tspi_Context_LoadKeyByUUID(hContext, TSS_PS_TYPE_SYSTEM,
+ SRK_UUID, &hSRK);
+ if (result != TSS_SUCCESS)
+ {
+ goto err1;
+ }
+
+ result = Tspi_GetPolicyObject(hSRK, TSS_POLICY_USAGE, &srkUsagePolicy);
+ if (result != TSS_SUCCESS)
+ {
+ goto err1;
+ }
+ result = Tspi_Policy_SetSecret(srkUsagePolicy, TSS_SECRET_MODE_SHA1,
+ 20, secret);
+ if (result != TSS_SUCCESS)
+ {
+ goto err1;
+ }
+
+ result = Tspi_Context_LoadKeyByBlob (hContext, hSRK, this->aik_blob.len,
+ this->aik_blob.ptr, &hAIK);
+ if (result != TSS_SUCCESS)
+ {
+ goto err1;
+ }
+
+ /* Create PCR composite object */
+ result = use_quote2 ?
+ Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_PCRS,
+ TSS_PCRS_STRUCT_INFO_SHORT, &hPcrComposite) :
+ Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_PCRS,
+ 0, &hPcrComposite);
+ if (result != TSS_SUCCESS)
+ {
+ goto err2;
+ }
+
+ /* Select PCRs */
+ for (pcr = 0; pcr <= this->pcr_max ; pcr++)
+ {
+ if (f == 256)
+ {
+ i++;
+ f = 1;
+ }
+ if (this->pcr_select[i] & f)
+ {
+ result = use_quote2 ?
+ Tspi_PcrComposite_SelectPcrIndexEx(hPcrComposite, pcr,
+ TSS_PCRS_DIRECTION_RELEASE) :
+ Tspi_PcrComposite_SelectPcrIndex(hPcrComposite, pcr);
+ if (result != TSS_SUCCESS)
+ {
+ goto err3;
+ }
+ }
+ f <<= 1;
+ }
+
+ /* Set the Validation Data */
+ valData.ulExternalDataLength = this->secret.len;
+ valData.rgbExternalData = (BYTE *)this->secret.ptr;
+
+
+ /* TPM Quote */
+ result = use_quote2 ?
+ Tspi_TPM_Quote2(hTPM, hAIK, FALSE, hPcrComposite, &valData,
+ &versionInfoSize, &versionInfo):
+ Tspi_TPM_Quote(hTPM, hAIK, hPcrComposite, &valData);
+ if (result != TSS_SUCCESS)
+ {
+ goto err4;
+ }
+
+ /* Set output chunks */
+ *pcr_comp = chunk_alloc(HASH_SIZE_SHA1);
+
+ if (use_quote2)
+ {
+ /* TPM_Composite_Hash is last 20 bytes of TPM_Quote_Info2 structure */
+ memcpy(pcr_comp->ptr, valData.rgbData + valData.ulDataLength - HASH_SIZE_SHA1,
+ HASH_SIZE_SHA1);
+ }
+ else
+ {
+ /* TPM_Composite_Hash is 8-28th bytes of TPM_Quote_Info structure */
+ memcpy(pcr_comp->ptr, valData.rgbData + 8, HASH_SIZE_SHA1);
+ }
+ DBG3(DBG_PTS, "Hash of PCR Composite: %#B", pcr_comp);
+
+ quote_info = chunk_create(valData.rgbData, valData.ulDataLength);
+ DBG3(DBG_PTS, "TPM Quote Info: %B",&quote_info);
+
+ *quote_sig = chunk_clone(chunk_create(valData.rgbValidationData,
+ valData.ulValidationDataLength));
+ DBG3(DBG_PTS, "TPM Quote Signature: %B",quote_sig);
+
+ success = TRUE;
+
+ /* Cleanup */
+err4:
+ Tspi_Context_FreeMemory(hContext, NULL);
+
+err3:
+ Tspi_Context_CloseObject(hContext, hPcrComposite);
+
+err2:
+ Tspi_Context_CloseObject(hContext, hAIK);
+
+err1:
+ Tspi_Context_Close(hContext);
+
+ if (!success)
+ {
+ DBG1(DBG_PTS, "TPM not available: tss error 0x%x", result);
+ }
+ clear_pcrs(this);
+
+ return success;
+}
+
+METHOD(pts_t, select_pcr, bool,
+ private_pts_t *this, u_int32_t pcr)
+{
+ u_int32_t i, f;
+
+ if (pcr >= PCR_MAX_NUM)
+ {
+ DBG1(DBG_PTS, "PCR %u: number is larger than maximum of %u",
+ pcr, PCR_MAX_NUM-1);
+ return FALSE;
+ }
+
+ /* Determine PCR selection flag */
+ i = pcr / 8;
+ f = 1 << (pcr - 8*i);
+
+ /* Has this PCR already been selected? */
+ if (!(this->pcr_select[i] & f))
+ {
+ this->pcr_select[i] |= f;
+ this->pcr_max = max(this->pcr_max, pcr);
+ this->pcr_count++;
+ }
+
+ return TRUE;
+}
+
+METHOD(pts_t, add_pcr, bool,
+ private_pts_t *this, u_int32_t pcr, chunk_t pcr_before, chunk_t pcr_after)
+{
+ if (pcr >= PCR_MAX_NUM)
+ {
+ DBG1(DBG_PTS, "PCR %u: number is larger than maximum of %u",
+ pcr, PCR_MAX_NUM-1);
+ return FALSE;
+ }
+
+ /* Is the length of the PCR registers already set? */
+ if (this->pcr_len)
+ {
+ if (pcr_after.len != this->pcr_len)
+ {
+ DBG1(DBG_PTS, "PCR %02u: length is %d bytes but should be %d bytes",
+ pcr_after.len, this->pcr_len);
+ return FALSE;
+ }
+ }
+ else
+ {
+ this->pcr_len = pcr_after.len;
+ }
+
+ /* Has the value of the PCR register already been assigned? */
+ if (this->pcrs[pcr])
+ {
+ if (!memeq(this->pcrs[pcr], pcr_before.ptr, this->pcr_len))
+ {
+ DBG1(DBG_PTS, "PCR %02u: new pcr_before value does not equal "
+ "old pcr_after value");
+ }
+ /* remove the old PCR value */
+ free(this->pcrs[pcr]);
+ }
+ else
+ {
+ /* add extended PCR Register */
+ this->pcr_select[pcr / 8] |= 1 << (pcr % 8);
+ this->pcr_max = max(this->pcr_max, pcr);
+ this->pcr_count++;
+ }
+
+ /* Duplicate and store current PCR value */
+ pcr_after = chunk_clone(pcr_after);
+ this->pcrs[pcr] = pcr_after.ptr;
+
+ return TRUE;
+}
+
+/**
+ * TPM_QUOTE_INFO structure:
+ * 4 bytes of version
+ * 4 bytes 'Q' 'U' 'O' 'T'
+ * 20 byte SHA1 of TCPA_PCR_COMPOSITE
+ * 20 byte nonce
+ *
+ * TPM_QUOTE_INFO2 structure:
+ * 2 bytes Tag 0x0036 TPM_Tag_Quote_info2
+ * 4 bytes 'Q' 'U' 'T' '2'
+ * 20 bytes nonce
+ * 26 bytes PCR_INFO_SHORT
+ */
+
+METHOD(pts_t, get_quote_info, bool,
+ private_pts_t *this, bool use_quote2, bool use_ver_info,
+ pts_meas_algorithms_t comp_hash_algo,
+ chunk_t *out_pcr_comp, chunk_t *out_quote_info)
+{
+ u_int8_t size_of_select;
+ int pcr_comp_len, i;
+ chunk_t pcr_comp, hash_pcr_comp;
+ bio_writer_t *writer;
+ hasher_t *hasher;
+
+ if (this->pcr_count == 0)
+ {
+ DBG1(DBG_PTS, "No extended PCR entries available, "
+ "unable to construct TPM Quote Info");
+ return FALSE;
+ }
+ if (!this->secret.ptr)
+ {
+ DBG1(DBG_PTS, "Secret assessment value unavailable, ",
+ "unable to construct TPM Quote Info");
+ return FALSE;
+ }
+ if (use_quote2 && use_ver_info && !this->tpm_version_info.ptr)
+ {
+ DBG1(DBG_PTS, "TPM Version Information unavailable, ",
+ "unable to construct TPM Quote Info2");
+ return FALSE;
+ }
+
+ /**
+ * A TPM v1.2 has 24 PCR Registers
+ * so the bitmask field length used by TrouSerS is at least 3 bytes
+ */
+ size_of_select = max(PCR_MAX_NUM / 8, 1 + this->pcr_max / 8);
+ pcr_comp_len = 2 + size_of_select + 4 + this->pcr_count * this->pcr_len;
+
+ writer = bio_writer_create(pcr_comp_len);
+
+ writer->write_uint16(writer, size_of_select);
+ for (i = 0; i < size_of_select; i++)
+ {
+ writer->write_uint8(writer, this->pcr_select[i]);
+ }
+
+ writer->write_uint32(writer, this->pcr_count * this->pcr_len);
+ for (i = 0; i < 8 * size_of_select; i++)
+ {
+ if (this->pcrs[i])
+ {
+ writer->write_data(writer, chunk_create(this->pcrs[i], this->pcr_len));
+ }
+ }
+ pcr_comp = chunk_clone(writer->get_buf(writer));
+ DBG3(DBG_PTS, "constructed PCR Composite: %B", &pcr_comp);
+
+ writer->destroy(writer);
+
+ /* Output the TPM_PCR_COMPOSITE expected from IMC */
+ if (comp_hash_algo)
+ {
+ hash_algorithm_t algo;
+
+ algo = pts_meas_algo_to_hash(comp_hash_algo);
+ hasher = lib->crypto->create_hasher(lib->crypto, algo);
+
+ /* Hash the PCR Composite Structure */
+ hasher->allocate_hash(hasher, pcr_comp, out_pcr_comp);
+ DBG3(DBG_PTS, "constructed PCR Composite hash: %#B", out_pcr_comp);
+ hasher->destroy(hasher);
+ }
+ else
+ {
+ *out_pcr_comp = chunk_clone(pcr_comp);
+ }
+
+ /* SHA1 hash of PCR Composite to construct TPM_QUOTE_INFO */
+ hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
+ hasher->allocate_hash(hasher, pcr_comp, &hash_pcr_comp);
+ hasher->destroy(hasher);
+
+ /* Construct TPM_QUOTE_INFO/TPM_QUOTE_INFO2 structure */
+ writer = bio_writer_create(TPM_QUOTE_INFO_LEN);
+
+ if (use_quote2)
+ {
+ /* TPM Structure Tag */
+ writer->write_uint16(writer, TPM_TAG_QUOTE_INFO2);
+
+ /* Magic QUT2 value */
+ writer->write_data(writer, chunk_create("QUT2", 4));
+
+ /* Secret assessment value 20 bytes (nonce) */
+ writer->write_data(writer, this->secret);
+
+ /* Length of the PCR selection field */
+ writer->write_uint16(writer, size_of_select);
+
+ /* PCR selection */
+ for (i = 0; i < size_of_select ; i++)
+ {
+ writer->write_uint8(writer, this->pcr_select[i]);
+ }
+
+ /* TPM Locality Selection */
+ writer->write_uint8(writer, TPM_LOC_ZERO);
+
+ /* PCR Composite Hash */
+ writer->write_data(writer, hash_pcr_comp);
+
+ if (use_ver_info)
+ {
+ /* TPM version Info */
+ writer->write_data(writer, this->tpm_version_info);
+ }
+ }
+ else
+ {
+ /* Version number */
+ writer->write_data(writer, chunk_from_chars(1, 1, 0, 0));
+
+ /* Magic QUOT value */
+ writer->write_data(writer, chunk_create("QUOT", 4));
+
+ /* PCR Composite Hash */
+ writer->write_data(writer, hash_pcr_comp);
+
+ /* Secret assessment value 20 bytes (nonce) */
+ writer->write_data(writer, this->secret);
+ }
+
+ /* TPM Quote Info */
+ *out_quote_info = chunk_clone(writer->get_buf(writer));
+ DBG3(DBG_PTS, "constructed TPM Quote Info: %B", out_quote_info);
+
+ writer->destroy(writer);
+ free(pcr_comp.ptr);
+ free(hash_pcr_comp.ptr);
+ clear_pcrs(this);
+
+ return TRUE;
+}
+
+METHOD(pts_t, verify_quote_signature, bool,
+ private_pts_t *this, chunk_t data, chunk_t signature)
+{
+ public_key_t *aik_pub_key;
+
+ aik_pub_key = this->aik->get_public_key(this->aik);
+ if (!aik_pub_key)
+ {
+ DBG1(DBG_PTS, "failed to get public key from AIK certificate");
+ return FALSE;
+ }
+
+ if (!aik_pub_key->verify(aik_pub_key, SIGN_RSA_EMSA_PKCS1_SHA1,
+ data, signature))
+ {
+ DBG1(DBG_PTS, "signature verification failed for TPM Quote Info");
+ DESTROY_IF(aik_pub_key);
+ return FALSE;
+ }
+
+ aik_pub_key->destroy(aik_pub_key);
+ return TRUE;
+}
+
METHOD(pts_t, destroy, void,
- private_pts_t *this)
+ private_pts_t *this)
{
+ clear_pcrs(this);
DESTROY_IF(this->aik);
+ DESTROY_IF(this->dh);
+ free(this->initiator_nonce.ptr);
+ free(this->responder_nonce.ptr);
+ free(this->secret.ptr);
free(this->platform_info);
+ free(this->aik_blob.ptr);
free(this->tpm_version_info.ptr);
free(this);
}
+#define RELEASE_LSB 0
+#define RELEASE_DEBIAN 1
+
/**
* Determine Linux distribution and hardware platform
*/
static char* extract_platform_info(void)
{
FILE *file;
- char buf[BUF_LEN], *pos, *value = NULL;
- int i, len;
+ char buf[BUF_LEN], *pos = buf, *value = NULL;
+ int i, len = BUF_LEN - 1;
struct utsname uninfo;
/* Linux/Unix distribution release info (from http://linuxmafia.com) */
@@ -420,6 +1343,7 @@ static char* extract_platform_info(void)
};
const char description[] = "DISTRIB_DESCRIPTION=\"";
+ const char str_debian[] = "Debian ";
for (i = 0; i < countof(releases); i++)
{
@@ -428,11 +1352,19 @@ static char* extract_platform_info(void)
{
continue;
}
+
+ if (i == RELEASE_DEBIAN)
+ {
+ strcpy(buf, str_debian);
+ pos += strlen(str_debian);
+ len -= strlen(str_debian);
+ }
+
fseek(file, 0, SEEK_END);
- len = min(ftell(file), sizeof(buf)-1);
+ len = min(ftell(file), len);
rewind(file);
- buf[len] = '\0';
- if (fread(buf, 1, len, file) != len)
+ pos[len] = '\0';
+ if (fread(pos, 1, len, file) != len)
{
DBG1(DBG_PTS, "failed to read file '%s'", releases[i]);
fclose(file);
@@ -440,7 +1372,7 @@ static char* extract_platform_info(void)
}
fclose(file);
- if (i == 0) /* LSB release */
+ if (i == RELEASE_LSB)
{
pos = strstr(buf, description);
if (!pos)
@@ -461,7 +1393,7 @@ static char* extract_platform_info(void)
else
{
value = buf;
- pos = strchr(value, '\n');
+ pos = strchr(pos, '\n');
if (!pos)
{
DBG1(DBG_PTS, "failed to find end of release string");
@@ -504,7 +1436,8 @@ static bool has_tpm(private_pts_t *this)
result = Tspi_Context_Create(&hContext);
if (result != TSS_SUCCESS)
{
- DBG1(DBG_PTS, "TPM context could not be created: tss error 0x%x", result);
+ DBG1(DBG_PTS, "TPM context could not be created: tss error 0x%x",
+ result);
return FALSE;
}
result = Tspi_Context_Connect(hContext, NULL);
@@ -526,10 +1459,14 @@ static bool has_tpm(private_pts_t *this)
goto err;
}
this->tpm_version_info = chunk_clone(this->tpm_version_info);
+
+ Tspi_Context_FreeMemory(hContext, NULL);
+ Tspi_Context_Close(hContext);
return TRUE;
err:
DBG1(DBG_PTS, "TPM not available: tss error 0x%x", result);
+ Tspi_Context_FreeMemory(hContext, NULL);
Tspi_Context_Close(hContext);
return FALSE;
}
@@ -542,23 +1479,42 @@ pts_t *pts_create(bool is_imc)
private_pts_t *this;
INIT(this,
- .public = {
- .get_proto_caps = _get_proto_caps,
- .set_proto_caps = _set_proto_caps,
- .get_meas_algorithm = _get_meas_algorithm,
- .set_meas_algorithm = _set_meas_algorithm,
- .get_platform_info = _get_platform_info,
- .set_platform_info = _set_platform_info,
- .get_tpm_version_info = _get_tpm_version_info,
- .set_tpm_version_info = _set_tpm_version_info,
- .get_aik = _get_aik,
- .set_aik = _set_aik,
- .is_path_valid = _is_path_valid,
- .do_measurements = _do_measurements,
- .destroy = _destroy,
- },
- .proto_caps = PTS_PROTO_CAPS_V,
- .algorithm = PTS_MEAS_ALGO_SHA256,
+ .public = {
+ .get_proto_caps = _get_proto_caps,
+ .set_proto_caps = _set_proto_caps,
+ .get_meas_algorithm = _get_meas_algorithm,
+ .set_meas_algorithm = _set_meas_algorithm,
+ .get_dh_hash_algorithm = _get_dh_hash_algorithm,
+ .set_dh_hash_algorithm = _set_dh_hash_algorithm,
+ .create_dh_nonce = _create_dh_nonce,
+ .get_my_public_value = _get_my_public_value,
+ .set_peer_public_value = _set_peer_public_value,
+ .calculate_secret = _calculate_secret,
+ .get_platform_info = _get_platform_info,
+ .set_platform_info = _set_platform_info,
+ .get_tpm_version_info = _get_tpm_version_info,
+ .set_tpm_version_info = _set_tpm_version_info,
+ .get_pcr_len = _get_pcr_len,
+ .get_aik = _get_aik,
+ .set_aik = _set_aik,
+ .get_aik_keyid = _get_aik_keyid,
+ .is_path_valid = _is_path_valid,
+ .hash_file = _hash_file,
+ .do_measurements = _do_measurements,
+ .get_metadata = _get_metadata,
+ .read_pcr = _read_pcr,
+ .extend_pcr = _extend_pcr,
+ .quote_tpm = _quote_tpm,
+ .select_pcr = _select_pcr,
+ .add_pcr = _add_pcr,
+ .get_quote_info = _get_quote_info,
+ .verify_quote_signature = _verify_quote_signature,
+ .destroy = _destroy,
+ },
+ .is_imc = is_imc,
+ .proto_caps = PTS_PROTO_CAPS_V,
+ .algorithm = PTS_MEAS_ALGO_SHA256,
+ .dh_hash_algorithm = PTS_MEAS_ALGO_SHA256,
);
if (is_imc)
@@ -568,15 +1524,16 @@ pts_t *pts_create(bool is_imc)
if (has_tpm(this))
{
this->has_tpm = TRUE;
- this->proto_caps |= PTS_PROTO_CAPS_T;
+ this->pcr_len = PCR_LEN;
+ this->proto_caps |= PTS_PROTO_CAPS_T | PTS_PROTO_CAPS_D;
load_aik(this);
+ load_aik_blob(this);
}
}
else
{
- this->proto_caps |= PTS_PROTO_CAPS_T | PTS_PROTO_CAPS_C;
+ this->proto_caps |= PTS_PROTO_CAPS_T | PTS_PROTO_CAPS_D;
}
return &this->public;
}
-
diff --git a/src/libpts/pts/pts.h b/src/libpts/pts/pts.h
index ef408c43f..212acb02a 100644
--- a/src/libpts/pts/pts.h
+++ b/src/libpts/pts/pts.h
@@ -27,17 +27,59 @@ typedef struct pts_t pts_t;
#include "pts_proto_caps.h"
#include "pts_meas_algo.h"
#include "pts_file_meas.h"
+#include "pts_file_meta.h"
+#include "pts_dh_group.h"
+#include "pts_req_func_comp_evid.h"
+#include "pts_simple_evid_final.h"
+#include "components/pts_comp_func_name.h"
#include <library.h>
+#include <utils/linked_list.h>
/**
* UTF-8 encoding of the character used to delimiter the filename
*/
-#define SOLIDUS_UTF 0x002F
-#define REVERSE_SOLIDUS_UTF 0x005C
+#define SOLIDUS_UTF 0x2F
+#define REVERSE_SOLIDUS_UTF 0x5C
/**
- * Class implementing the TCG Platform Trust System (PTS)
+ * PCR indices used for measurements of various functional components
+ */
+#define PCR_BIOS 0
+#define PCR_PLATFORM_EXT 1
+#define PCR_MOTHERBOARD 1
+#define PCR_OPTION_ROMS 2
+#define PCR_IPL 4
+
+#define PCR_TBOOT_POLICY 17
+#define PCR_TBOOT_MLE 18
+
+#define PCR_TGRUB_MBR_STAGE1 4
+#define PCR_TGRUB_STAGE2_PART1 8
+#define PCR_TGRUB_STAGE2_PART2 9
+#define PCR_TGRUB_CMD_LINE_ARGS 12
+#define PCR_TGRUB_CHECKFILE 13
+#define PCR_TGRUB_LOADED_FILES 14
+
+#define PCR_DEBUG 16
+
+/**
+ * Length of the generated nonce used for calculation of shared secret
+ */
+#define ASSESSMENT_SECRET_LEN 20
+
+/**
+ * Length of the TPM_QUOTE_INFO structure, TPM Spec 1.2
+ */
+#define TPM_QUOTE_INFO_LEN 48
+
+/**
+ * Hashing algorithm used by tboot and trustedGRUB
+ */
+#define TRUSTED_HASH_ALGO PTS_MEAS_ALGO_SHA1
+
+/**
+ * Class implementing the TCG Platform Trust Service (PTS)
*
*/
struct pts_t {
@@ -45,96 +87,255 @@ struct pts_t {
/**
* Get PTS Protocol Capabilities
*
- * @return protocol capabilities flags
+ * @return Protocol capabilities flags
*/
pts_proto_caps_flag_t (*get_proto_caps)(pts_t *this);
/**
* Set PTS Protocol Capabilities
*
- * @param flags protocol capabilities flags
+ * @param flags Protocol capabilities flags
*/
void (*set_proto_caps)(pts_t *this, pts_proto_caps_flag_t flags);
/**
* Get PTS Measurement Algorithm
*
- * @return measurement algorithm
+ * @return PTS measurement algorithm
*/
pts_meas_algorithms_t (*get_meas_algorithm)(pts_t *this);
/**
* Set PTS Measurement Algorithm
*
- * @param algorithm measurement algorithm
+ * @param algorithm PTS measurement algorithm
*/
void (*set_meas_algorithm)(pts_t *this, pts_meas_algorithms_t algorithm);
/**
+ * Get DH Hash Algorithm
+ *
+ * @return DH hash algorithm
+ */
+ pts_meas_algorithms_t (*get_dh_hash_algorithm)(pts_t *this);
+
+ /**
+ * Set DH Hash Algorithm
+ *
+ * @param algorithm DH hash algorithm
+ */
+ void (*set_dh_hash_algorithm)(pts_t *this, pts_meas_algorithms_t algorithm);
+
+ /**
+ * Create PTS Diffie-Hellman object and nonce
+ *
+ * @param group PTS DH group
+ * @param nonce_len Nonce length
+ * @return TRUE if creation was successful
+ *
+ */
+ bool (*create_dh_nonce)(pts_t *this, pts_dh_group_t group, int nonce_len);
+
+ /**
+ * Get my Diffie-Hellman public value
+ *
+ * @param value My public DH value
+ * @param nonce My DH nonce
+ */
+ void (*get_my_public_value)(pts_t *this, chunk_t *value, chunk_t *nonce);
+
+ /**
+ * Set peer Diffie.Hellman public value
+ *
+ * @param value Peer public DH value
+ * @param nonce Peer DH nonce
+ */
+ void (*set_peer_public_value) (pts_t *this, chunk_t value, chunk_t nonce);
+
+ /**
+ * Calculates assessment secret to be used for TPM Quote as ExternalData
+ *
+ * @return TRUE unless both DH public values
+ * and nonces are set
+ */
+ bool (*calculate_secret) (pts_t *this);
+
+ /**
* Get Platform and OS Info
*
- * @return platform and OS info
+ * @return Platform and OS info
*/
char* (*get_platform_info)(pts_t *this);
/**
* Set Platform and OS Info
*
- * @param info platform and OS info
+ * @param info Platform and OS info
*/
void (*set_platform_info)(pts_t *this, char *info);
/**
* Get TPM 1.2 Version Info
*
- * @param info chunk containing a TPM_CAP_VERSION_INFO struct
- * @return TRUE if TPM Version Info available
+ * @param info chunk containing a TPM_CAP_VERSION_INFO struct
+ * @return TRUE if TPM Version Info available
*/
bool (*get_tpm_version_info)(pts_t *this, chunk_t *info);
/**
* Set TPM 1.2 Version Info
*
- * @param info chunk containing a TPM_CAP_VERSION_INFO struct
+ * @param info chunk containing a TPM_CAP_VERSION_INFO struct
*/
void (*set_tpm_version_info)(pts_t *this, chunk_t info);
-
+
+ /**
+ * Get the length of the TPM PCR registers
+ *
+ * @return Length of PCR registers in bytes, 0 if undefined
+ */
+ size_t (*get_pcr_len)(pts_t *this);
+
/**
* Get Attestation Identity Certificate or Public Key
*
- * @return AIK Certificate or Public Key
+ * @return AIK Certificate or Public Key
*/
certificate_t* (*get_aik)(pts_t *this);
-
+
/**
* Set Attestation Identity Certificate or Public Key
*
- * @param aik AIK Certificate or Public Key
+ * @param aik AIK Certificate or Public Key
*/
void (*set_aik)(pts_t *this, certificate_t *aik);
/**
+ * Get SHA-1 Attestation Identity Public Key Info ID
+ *
+ * @param keyid AIK ID
+ * @return TRUE if AIK ID exists
+ */
+ bool (*get_aik_keyid)(pts_t *this, chunk_t *keyid);
+
+ /**
* Check whether path is valid file/directory on filesystem
*
- * @param path Absolute path
- * @param error_code Output variable for PTS error code
- * @return TRUE if path is valid or file/directory doesn't exist
- * or path is invalid
+ * @param path Absolute path
+ * @param error_code Output variable for PTS error code
+ * @return TRUE if path is valid or file/directory
+ * doesn't exist or path is invalid
* FALSE if local error occurred within stat function
*/
bool (*is_path_valid)(pts_t *this, char *path, pts_error_code_t *error_code);
/**
+ * Compute a hash over a file
+ * @param hasher Hasher to be used
+ * @param pathname Absolute path of a file
+ * @param hash Buffer to keep hash output
+ * @return TRUE if path is valid and hashing succeeded
+ */
+ bool (*hash_file)(pts_t *this, hasher_t *hasher, char *pathname, u_char *hash);
+
+ /**
* Do PTS File Measurements
*
- * @param request_id ID of PTS File Measurement Request
- * @param pathname Absolute pathname of file to be measured
- * @param is_directory if TRUE directory contents are measured
- * @return PTS File Measurements of NULL if FAILED
+ * @param request_id ID of PTS File Measurement Request
+ * @param pathname Absolute pathname of file to be measured
+ * @param is_directory TRUE if directory contents are measured
+ * @return PTS File Measurements of NULL if FAILED
*/
pts_file_meas_t* (*do_measurements)(pts_t *this, u_int16_t request_id,
char *pathname, bool is_directory);
-
+
+ /**
+ * Obtain file metadata
+ *
+ * @param pathname Absolute pathname of file/directory
+ * @param is_directory TRUE if directory contents are requested
+ * @return PTS File Metadata or NULL if FAILED
+ */
+ pts_file_meta_t* (*get_metadata)(pts_t *this, char *pathname,
+ bool is_directory);
+
+ /**
+ * Reads given PCR value and returns it
+ * Expects owner secret to be WELL_KNOWN_SECRET
+ *
+ * @param pcr_num Number of PCR to read
+ * @param pcr_value Chunk to save pcr read output
+ * @return NULL in case of TSS error, PCR value otherwise
+ */
+ bool (*read_pcr)(pts_t *this, u_int32_t pcr_num, chunk_t *pcr_value);
+
+ /**
+ * Extends given PCR with given value
+ * Expects owner secret to be WELL_KNOWN_SECRET
+ *
+ * @param pcr_num Number of PCR to extend
+ * @param input Value to extend
+ * @param output Chunk to save PCR value after extension
+ * @return FALSE in case of TSS error, TRUE otherwise
+ */
+ bool (*extend_pcr)(pts_t *this, u_int32_t pcr_num, chunk_t input,
+ chunk_t *output);
+
+ /**
+ * Quote over PCR's
+ * Expects owner and SRK secret to be WELL_KNOWN_SECRET and no password set for AIK
+ *
+ * @param use_quote2 Version of the Quote function to be used
+ * @param pcr_comp Chunk to save PCR composite structure
+ * @param quote_sig Chunk to save quote operation output
+ * without external data (anti-replay protection)
+ * @return FALSE in case of TSS error, TRUE otherwise
+ */
+ bool (*quote_tpm)(pts_t *this, bool use_quote2, chunk_t *pcr_comp,
+ chunk_t *quote_sig);
+
+ /**
+ * Mark an extended PCR as selected
+ *
+ * @param pcr Number of the extended PCR
+ * @return TRUE if PCR number is valid
+ */
+ bool (*select_pcr)(pts_t *this, u_int32_t pcr);
+
+ /**
+ * Add an extended PCR with its corresponding value
+ *
+ * @param pcr Number of the extended PCR
+ * @param pcr_before PCR value before extension
+ * @param pcr_after PCR value after extension
+ * @return TRUE if PCR number and register length is valid
+ */
+ bool (*add_pcr)(pts_t *this, u_int32_t pcr, chunk_t pcr_before,
+ chunk_t pcr_after);
+
+ /**
+ * Constructs and returns TPM Quote Info structure expected from IMC
+ *
+ * @param use_quote2 Version of the TPM_QUOTE_INFO to be constructed
+ * @param use_ver_info Version info is concatenated to TPM_QUOTE_INFO2
+ * @param comp_hash_algo Composite Hash Algorithm
+ * @param pcr_comp Output variable to store PCR Composite
+ * @param quote_info Output variable to store TPM Quote Info
+ * @return FALSE in case of any error, TRUE otherwise
+ */
+ bool (*get_quote_info)(pts_t *this, bool use_quote2, bool ver_info_included,
+ pts_meas_algorithms_t comp_hash_algo,
+ chunk_t *pcr_comp, chunk_t *quote_info);
+
+ /**
+ * Constructs and returns PCR Quote Digest structure expected from IMC
+ *
+ * @param data Calculated TPM Quote Digest
+ * @param signature TPM Quote Signature received from IMC
+ * @return FALSE if signature is not verified
+ */
+ bool (*verify_quote_signature)(pts_t *this, chunk_t data, chunk_t signature);
+
/**
* Destroys a pts_t object.
*/
diff --git a/src/libpts/pts/pts_database.c b/src/libpts/pts/pts_database.c
index 2706173ab..282755c0a 100644
--- a/src/libpts/pts/pts_database.c
+++ b/src/libpts/pts/pts_database.c
@@ -39,7 +39,7 @@ struct private_pts_database_t {
};
-METHOD(pts_database_t, create_file_enumerator, enumerator_t*,
+METHOD(pts_database_t, create_file_meas_enumerator, enumerator_t*,
private_pts_database_t *this, char *product)
{
enumerator_t *e;
@@ -49,12 +49,27 @@ METHOD(pts_database_t, create_file_enumerator, enumerator_t*,
"SELECT f.id, f.type, f.path FROM files AS f "
"JOIN product_file AS pf ON f.id = pf.file "
"JOIN products AS p ON p.id = pf.product "
- "WHERE p.name = ?",
+ "WHERE p.name = ? AND pf.measurement = 1",
DB_TEXT, product, DB_INT, DB_INT, DB_TEXT);
return e;
}
-METHOD(pts_database_t, create_hash_enumerator, enumerator_t*,
+METHOD(pts_database_t, create_file_meta_enumerator, enumerator_t*,
+ private_pts_database_t *this, char *product)
+{
+ enumerator_t *e;
+
+ /* look for all entries belonging to a product in the files table */
+ e = this->db->query(this->db,
+ "SELECT f.type, f.path FROM files AS f "
+ "JOIN product_file AS pf ON f.id = pf.file "
+ "JOIN products AS p ON p.id = pf.product "
+ "WHERE p.name = ? AND pf.metadata = 1",
+ DB_TEXT, product, DB_INT, DB_TEXT);
+ return e;
+}
+
+METHOD(pts_database_t, create_file_hash_enumerator, enumerator_t*,
private_pts_database_t *this, char *product, pts_meas_algorithms_t algo,
int id, bool is_dir)
{
@@ -82,6 +97,178 @@ METHOD(pts_database_t, create_hash_enumerator, enumerator_t*,
return e;
}
+METHOD(pts_database_t, check_aik_keyid, status_t,
+ private_pts_database_t *this, chunk_t keyid, int *kid)
+{
+ enumerator_t *e;
+
+ /* If the AIK is registered get the primary key */
+ e = this->db->query(this->db,
+ "SELECT id FROM keys WHERE keyid = ?", DB_BLOB, keyid, DB_INT);
+ if (!e)
+ {
+ DBG1(DBG_PTS, "no database query enumerator returned");
+ return FAILED;
+ }
+ if (!e->enumerate(e, kid))
+ {
+ DBG1(DBG_PTS, "AIK %#B is not registered in database", &keyid);
+ e->destroy(e);
+ return FAILED;
+ }
+ e->destroy(e);
+
+ return SUCCESS;
+}
+
+METHOD(pts_database_t, create_comp_evid_enumerator, enumerator_t*,
+ private_pts_database_t *this, int kid)
+{
+ enumerator_t *e;
+
+ /* look for all entries belonging to an AIK in the components table */
+ e = this->db->query(this->db,
+ "SELECT c.vendor_id, c.name, c.qualifier, kc.depth "
+ "FROM components AS c "
+ "JOIN key_component AS kc ON c.id = kc.component "
+ "WHERE kc.key = ? ORDER BY kc.seq_no",
+ DB_INT, kid, DB_INT, DB_INT, DB_INT, DB_INT);
+ return e;
+}
+
+METHOD(pts_database_t, check_comp_measurement, status_t,
+ private_pts_database_t *this, chunk_t measurement, int cid, int kid,
+ int seq_no, int pcr, pts_meas_algorithms_t algo)
+{
+ enumerator_t *e;
+ chunk_t hash;
+ status_t status = NOT_FOUND;
+
+ e = this->db->query(this->db,
+ "SELECT hash FROM component_hashes "
+ "WHERE component = ? AND key = ? "
+ "AND seq_no = ? AND pcr = ? AND algo = ? ",
+ DB_INT, cid, DB_INT, kid, DB_INT, seq_no,
+ DB_INT, pcr, DB_INT, algo, DB_BLOB);
+ if (!e)
+ {
+ DBG1(DBG_PTS, "no database query enumerator returned");
+ return FAILED;
+ }
+
+ while (e->enumerate(e, &hash))
+ {
+ if (chunk_equals(hash, measurement))
+ {
+ status = SUCCESS;
+ break;
+ }
+ else
+ {
+ DBG1(DBG_PTS, "PCR %2d no matching component measurement #%d "
+ "found in database", pcr, seq_no);
+ DBG1(DBG_PTS, " expected: %#B", &hash);
+ DBG1(DBG_PTS, " received: %#B", &measurement);
+ status = FAILED;
+ break;
+ }
+ }
+ e->destroy(e);
+
+ if (status == NOT_FOUND)
+ {
+ DBG1(DBG_PTS, "PCR %2d no measurement #%d "
+ "found in database", pcr, seq_no);
+ }
+
+ return status;
+}
+
+METHOD(pts_database_t, insert_comp_measurement, status_t,
+ private_pts_database_t *this, chunk_t measurement, int cid, int kid,
+ int seq_no, int pcr, pts_meas_algorithms_t algo)
+{
+ int id;
+
+ if (this->db->execute(this->db, &id,
+ "INSERT INTO component_hashes "
+ "(component, key, seq_no, pcr, algo, hash) "
+ "VALUES (?, ?, ?, ?, ?, ?)",
+ DB_INT, cid, DB_INT, kid, DB_INT, seq_no, DB_INT, pcr,
+ DB_INT, algo, DB_BLOB, measurement) == 1)
+ {
+ return SUCCESS;
+ }
+
+ DBG1(DBG_PTS, "could not insert component measurement into database");
+ return FAILED;
+}
+
+METHOD(pts_database_t, delete_comp_measurements, int,
+ private_pts_database_t *this, int cid, int kid)
+{
+ return this->db->execute(this->db, NULL,
+ "DELETE FROM component_hashes "
+ "WHERE component = ? AND key = ?",
+ DB_INT, cid, DB_INT, kid);
+}
+
+METHOD(pts_database_t, get_comp_measurement_count, status_t,
+ private_pts_database_t *this, pts_comp_func_name_t *comp_name,
+ chunk_t keyid, pts_meas_algorithms_t algo, int *cid, int *kid, int *count)
+{
+ enumerator_t *e;
+ status_t status = SUCCESS;
+
+ /* Initialize count */
+ *count = 0;
+
+ if (_check_aik_keyid(this, keyid, kid) != SUCCESS)
+ {
+ return FAILED;
+ }
+
+ /* Get the primary key of the Component Functional Name */
+ e = this->db->query(this->db,
+ "SELECT id FROM components "
+ " WHERE vendor_id = ? AND name = ? AND qualifier = ?",
+ DB_INT, comp_name->get_vendor_id(comp_name),
+ DB_INT, comp_name->get_name(comp_name),
+ DB_INT, comp_name->get_qualifier(comp_name),
+ DB_INT);
+ if (!e)
+ {
+ DBG1(DBG_PTS, "no database query enumerator returned");
+ return FAILED;
+ }
+ if (!e->enumerate(e, cid))
+ {
+ DBG1(DBG_PTS, "component functional name not found in database");
+ e->destroy(e);
+ return FAILED;
+ }
+ e->destroy(e);
+
+ /* Get the number of stored measurements for a given AIK and component */
+ e = this->db->query(this->db,
+ "SELECT COUNT(*) FROM component_hashes AS ch "
+ "WHERE component = ? AND key = ? AND algo = ?",
+ DB_INT, *cid, DB_INT, *kid, DB_INT, algo, DB_INT);
+ if (!e)
+ {
+ DBG1(DBG_PTS, "no database query enumerator returned");
+ return FAILED;
+ }
+ if (!e->enumerate(e, count))
+ {
+ DBG1(DBG_PTS, "no component measurement count returned from database");
+ status = FAILED;
+ }
+ e->destroy(e);
+
+ return status;
+}
+
METHOD(pts_database_t, destroy, void,
private_pts_database_t *this)
{
@@ -98,8 +285,15 @@ pts_database_t *pts_database_create(char *uri)
INIT(this,
.public = {
- .create_file_enumerator = _create_file_enumerator,
- .create_hash_enumerator = _create_hash_enumerator,
+ .create_file_meas_enumerator = _create_file_meas_enumerator,
+ .create_file_meta_enumerator = _create_file_meta_enumerator,
+ .create_comp_evid_enumerator = _create_comp_evid_enumerator,
+ .create_file_hash_enumerator = _create_file_hash_enumerator,
+ .check_aik_keyid = _check_aik_keyid,
+ .check_comp_measurement = _check_comp_measurement,
+ .insert_comp_measurement = _insert_comp_measurement,
+ .delete_comp_measurements = _delete_comp_measurements,
+ .get_comp_measurement_count = _get_comp_measurement_count,
.destroy = _destroy,
},
.db = lib->db->create(lib->db, uri),
@@ -107,8 +301,8 @@ pts_database_t *pts_database_create(char *uri)
if (!this->db)
{
- DBG1(DBG_PTS, "failed to connect to PTS file measurement database '%s'",
- uri);
+ DBG1(DBG_PTS,
+ "failed to connect to PTS file measurement database '%s'", uri);
free(this);
return NULL;
}
diff --git a/src/libpts/pts/pts_database.h b/src/libpts/pts/pts_database.h
index f2a6854a5..a9a68ac76 100644
--- a/src/libpts/pts/pts_database.h
+++ b/src/libpts/pts/pts_database.h
@@ -24,6 +24,7 @@
typedef struct pts_database_t pts_database_t;
#include "pts_meas_algo.h"
+#include "components/pts_comp_func_name.h"
#include <library.h>
/**
@@ -33,25 +34,107 @@ typedef struct pts_database_t pts_database_t;
struct pts_database_t {
/**
- * Get files to be measured by PTS
+ * Get files/directories to be measured by PTS
*
- * @param product software product (os, vpn client, etc.)
- * @return enumerator over all matching files
+ * @param product Software product (os, vpn client, etc.)
+ * @return Enumerator over all matching files/directories
*/
- enumerator_t* (*create_file_enumerator)(pts_database_t *this, char *product);
+ enumerator_t* (*create_file_meas_enumerator)(pts_database_t *this,
+ char *product);
+
+ /**
+ * Get files/directories to request metadata of
+ *
+ * @param product Software product (os, vpn client, etc.)
+ * @return Enumerator over all matching files/directories
+ */
+ enumerator_t* (*create_file_meta_enumerator)(pts_database_t *this,
+ char *product);
/**
* Get stored measurement hash for single file or directory entries
*
- * @param product software product (os, vpn client, etc.)
- * @param algo hash algorithm used for measurement
- * @param id primary key of measured file/directory
+ * @param product Software product (os, vpn client, etc.)
+ * @param algo Hash algorithm used for measurement
+ * @param id Primary key of measured file/directory
* @param is_dir TRUE if directory was measured
- * @return enumerator over all matching measurement hashes
+ * @return Enumerator over all matching measurement hashes
+ */
+ enumerator_t* (*create_file_hash_enumerator)(pts_database_t *this,
+ char *product, pts_meas_algorithms_t algo,
+ int id, bool is_dir);
+
+ /**
+ * Check if an AIK given by its keyid is registered in the database
+ *
+ * @param keyid AIK keyid (SHA-1 hash of the AIK public key info)
+ * @param kid Primary key of AIK entry in keys table
+ * @return SUCCESS if AIK is present, FAILED otherwise
+ */
+ status_t (*check_aik_keyid)(pts_database_t *this, chunk_t keyid, int *kid);
+
+ /**
+ * Get functional components to request evidence of
+ *
+ * @param kid Primary key of AIK entry in keys table
+ * @return Enumerator over all matching components
+ */
+ enumerator_t* (*create_comp_evid_enumerator)(pts_database_t *this, int kid);
+
+ /**
+ * Check a functional component measurement against value stored in database
+ *
+ * @param measurement measurement hash
+ * @param cid Primary key of Component Functional Name entry
+ * @param kid Primary key of AIK entry in keys table
+ * @param seq_no Measurement sequence number
+ * @param prc Number of the PCR the measurement was extended into
+ * @param algo Hash algorithm used for measurement
+ * @return SUCCESS if check was successful
+ */
+ status_t (*check_comp_measurement)(pts_database_t *this, chunk_t measurement,
+ int cid, int kid, int seq_no, int pcr,
+ pts_meas_algorithms_t algo);
+
+ /**
+ * Insert a functional component measurement into the database
+ *
+ * @param measurement Measurement hash
+ * @param cid Primary key of Component Functional Name entry
+ * @param kid Primary key of AIK entry in keys table
+ * @param seq_no Measurement sequence number
+ * @param prc Number of the PCR the measurement was extended into
+ * @param algo Hash algorithm used for measurement
+ * @return SUCCESS if INSERT was successful
+ */
+ status_t (*insert_comp_measurement)(pts_database_t *this, chunk_t measurement,
+ int cid, int kid, int seq_no, int pcr,
+ pts_meas_algorithms_t algo);
+
+ /**
+ * Delete functional component measurements from the database
+ *
+ * @param cid Primary key of Component Functional Name entry
+ * @param kid Primary key of AIK entry in keys table
+ * @return number of deleted measurement entries
+ */
+ int (*delete_comp_measurements)(pts_database_t *this, int cid, int kid);
+
+ /**
+ * Get the number of measurements for a functional component and AIK
+ *
+ * @param comp_name Component Functional Name
+ * @param keyid SHA-1 hash of AIK public key info
+ * @param algo Hash algorithm used for measurement
+ * @param cid Primary key of Component Functional Name entry
+ * @param kid Primary key of AIK entry in keys table
+ * @param count measurement count
+ * @return SUCCESS if COUNT was successful
*/
- enumerator_t* (*create_hash_enumerator)(pts_database_t *this, char *product,
- pts_meas_algorithms_t algo,
- int id, bool is_dir);
+ status_t (*get_comp_measurement_count)(pts_database_t *this,
+ pts_comp_func_name_t *comp_name, chunk_t keyid,
+ pts_meas_algorithms_t algo, int *cid, int *kid,
+ int *count);
/**
* Destroys a pts_database_t object.
diff --git a/src/libpts/pts/pts_dh_group.c b/src/libpts/pts/pts_dh_group.c
new file mode 100644
index 000000000..fb141327f
--- /dev/null
+++ b/src/libpts/pts/pts_dh_group.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2011 Sansar Choinyambuu
+ * 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 "pts_dh_group.h"
+
+#include <debug.h>
+
+/**
+ * Described in header.
+ */
+bool pts_dh_group_probe(pts_dh_group_t *dh_groups)
+{
+ enumerator_t *enumerator;
+ diffie_hellman_group_t dh_group;
+ const char *plugin_name;
+ char format1[] = " %s PTS DH group %N[%s] available";
+ char format2[] = " %s PTS DH group %N not available";
+
+ *dh_groups = PTS_DH_GROUP_NONE;
+
+ enumerator = lib->crypto->create_dh_enumerator(lib->crypto);
+ while (enumerator->enumerate(enumerator, &dh_group, &plugin_name))
+ {
+ if (dh_group == MODP_1024_BIT)
+ {
+ *dh_groups |= PTS_DH_GROUP_IKE2;
+ DBG2(DBG_PTS, format1, "optional ", diffie_hellman_group_names,
+ dh_group, plugin_name);
+ }
+ else if (dh_group == MODP_1536_BIT)
+ {
+ *dh_groups |= PTS_DH_GROUP_IKE5;
+ DBG2(DBG_PTS, format1, "optional ", diffie_hellman_group_names,
+ dh_group, plugin_name);
+ }
+ else if (dh_group == MODP_2048_BIT)
+ {
+ *dh_groups |= PTS_DH_GROUP_IKE14;
+ DBG2(DBG_PTS, format1, "optional ", diffie_hellman_group_names,
+ dh_group, plugin_name);
+ }
+ else if (dh_group == ECP_256_BIT)
+ {
+ *dh_groups |= PTS_DH_GROUP_IKE19;
+ DBG2(DBG_PTS, format1, "mandatory", diffie_hellman_group_names,
+ dh_group, plugin_name);
+ }
+ else if (dh_group == ECP_384_BIT)
+ {
+ *dh_groups |= PTS_DH_GROUP_IKE20;
+ DBG2(DBG_PTS, format1, "optional ", diffie_hellman_group_names,
+ dh_group, plugin_name);
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ if (*dh_groups & PTS_DH_GROUP_IKE19)
+ {
+ return TRUE;
+ }
+ else
+ {
+ DBG1(DBG_PTS, format2, "mandatory", diffie_hellman_group_names,
+ ECP_256_BIT);
+ }
+ return FALSE;
+}
+
+/**
+ * Described in header.
+ */
+bool pts_dh_group_update(char *dh_group, pts_dh_group_t *dh_groups)
+{
+ if (strcaseeq(dh_group, "ecp384"))
+ {
+ /* nothing to update, all groups are supported */
+ return TRUE;
+ }
+ if (strcaseeq(dh_group, "ecp256"))
+ {
+ /* remove DH group 20 */
+ *dh_groups &= ~PTS_DH_GROUP_IKE20;
+ return TRUE;
+ }
+ if (strcaseeq(dh_group, "modp2048"))
+ {
+ /* remove DH groups 19 and 20 */
+ *dh_groups &= ~(PTS_DH_GROUP_IKE20 | PTS_DH_GROUP_IKE19);
+ return TRUE;
+ }
+ if (strcaseeq(dh_group, "modp1536"))
+ {
+ /* remove DH groups 14, 19 and 20 */
+ *dh_groups &= ~(PTS_DH_GROUP_IKE20 | PTS_DH_GROUP_IKE19 |
+ PTS_DH_GROUP_IKE14);
+ return TRUE;
+ }
+ if (strcaseeq(dh_group, "modp1024"))
+ {
+ /* remove DH groups 5, 14, 19 and 20 */
+ *dh_groups &= ~(PTS_DH_GROUP_IKE20 | PTS_DH_GROUP_IKE19 |
+ PTS_DH_GROUP_IKE14 | PTS_DH_GROUP_IKE5);
+ return TRUE;
+ }
+ DBG1(DBG_PTS, "unknown DH group '%s' configured", dh_group);
+ return FALSE;
+}
+
+/**
+ * Described in header.
+ */
+pts_dh_group_t pts_dh_group_select(pts_dh_group_t supported_dh_groups,
+ pts_dh_group_t offered_dh_groups)
+{
+ if ((supported_dh_groups & PTS_DH_GROUP_IKE20) &&
+ (offered_dh_groups & PTS_DH_GROUP_IKE20))
+ {
+ return PTS_DH_GROUP_IKE20;
+ }
+ if ((supported_dh_groups & PTS_DH_GROUP_IKE19) &&
+ (offered_dh_groups & PTS_DH_GROUP_IKE19))
+ {
+ return PTS_DH_GROUP_IKE19;
+ }
+ if ((supported_dh_groups & PTS_DH_GROUP_IKE14) &&
+ (offered_dh_groups & PTS_DH_GROUP_IKE14))
+ {
+ return PTS_DH_GROUP_IKE14;
+ }
+ if ((supported_dh_groups & PTS_DH_GROUP_IKE5) &&
+ (offered_dh_groups & PTS_DH_GROUP_IKE5))
+ {
+ return PTS_DH_GROUP_IKE5;
+ }
+ if ((supported_dh_groups & PTS_DH_GROUP_IKE2) &&
+ (offered_dh_groups & PTS_DH_GROUP_IKE2))
+ {
+ return PTS_DH_GROUP_IKE2;
+ }
+ return PTS_DH_GROUP_NONE;
+}
+
+/**
+ * Described in header.
+ */
+diffie_hellman_group_t pts_dh_group_to_ike(pts_dh_group_t dh_group)
+{
+ switch (dh_group)
+ {
+ case PTS_DH_GROUP_IKE2:
+ return MODP_1024_BIT;
+ case PTS_DH_GROUP_IKE5:
+ return MODP_1536_BIT;
+ case PTS_DH_GROUP_IKE14:
+ return MODP_2048_BIT;
+ case PTS_DH_GROUP_IKE19:
+ return ECP_256_BIT;
+ case PTS_DH_GROUP_IKE20:
+ return ECP_384_BIT;
+ default:
+ return MODP_NONE;
+ }
+}
diff --git a/src/libpts/pts/pts_dh_group.h b/src/libpts/pts/pts_dh_group.h
new file mode 100644
index 000000000..8664a4b84
--- /dev/null
+++ b/src/libpts/pts/pts_dh_group.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2011 Sansar Choinyambuu
+ * 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 pts_dh_group pts_dh_group
+ * @{ @ingroup pts
+ */
+
+#ifndef PTS_DH_GROUP_H_
+#define PTS_DH_GROUP_H_
+
+#include <library.h>
+#include <crypto/diffie_hellman.h>
+
+typedef enum pts_dh_group_t pts_dh_group_t;
+
+/**
+ * PTS Diffie Hellman Group Values
+ */
+enum pts_dh_group_t {
+ /** No DH Group */
+ PTS_DH_GROUP_NONE = 0,
+ /** IKE Group 2 */
+ PTS_DH_GROUP_IKE2 = (1<<15),
+ /** IKE Group 5 */
+ PTS_DH_GROUP_IKE5 = (1<<14),
+ /** IKE Group 14 */
+ PTS_DH_GROUP_IKE14 = (1<<13),
+ /** IKE Group 19 */
+ PTS_DH_GROUP_IKE19 = (1<<12),
+ /** IKE Group 20 */
+ PTS_DH_GROUP_IKE20 = (1<<11),
+};
+
+/**
+ * Diffie-Hellman Group Values
+ * see section 3.8.6 of PTS Protocol: Binding to TNC IF-M Specification
+ *
+ * 1
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |1|2|3|4|5|R|R|R|R|R|R|R|R|R|R|R|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ */
+
+/**
+ * Probe available PTS Diffie-Hellman groups
+ *
+ * @param dh_groups returns set of available DH groups
+ * @return TRUE if mandatory DH groups are available
+ */
+bool pts_dh_group_probe(pts_dh_group_t *dh_groups);
+
+/**
+ * Update supported Diffie-Hellman groups according to configuration
+ *
+ * modp1024: PTS_DH_GROUP_IKE2
+ * modp1536: PTS_DH_GROUP_IKE2 | PTS_DH_GROUP_IKE5
+ * modp2048: PTS_DH_GROUP_IKE2 | PTS_DH_GROUP_IKE5 | PTS_DH_GROUP_IKE14
+ * ecp256: PTS_DH_GROUP_IKE2 | PTS_DH_GROUP_IKE5 | PTS_DH_GROUP_IKE14 |
+ * PTS_DH_GROUP_IKE19
+ * ecp384: PTS_DH_GROUP_IKE2 | PTS_DH_GROUP_IKE5 | PTS_DH_GROUP_IKE14 |
+ * PTS_DH_GROUP_IKE19 | PTS_DH_GROUP_IKE20
+ *
+ * The PTS-IMC is expected to select the strongest supported group
+ *
+ * @param dh_group configured DH group
+ * @param dh_groups returns set of available DH groups
+ */
+bool pts_dh_group_update(char *dh_group, pts_dh_group_t *dh_groups);
+
+/**
+ * Select the strongest supported Diffie-Hellman group
+ * among a set of offered DH groups
+ *
+ * @param supported_groups set of supported DH groups
+ * @param offered_groups set of offered DH groups
+ * @return selected DH group
+ */
+pts_dh_group_t pts_dh_group_select(pts_dh_group_t supported_dh_groups,
+ pts_dh_group_t offered_dh_groups);
+
+/**
+ * Convert pts_dh_group_t to diffie_hellman_group_t
+ *
+ * @param dh_group PTS DH group type
+ * @return IKE DH group type
+ */
+diffie_hellman_group_t pts_dh_group_to_ike(pts_dh_group_t dh_group);
+
+#endif /** PTS_DH_GROUP_H_ @}*/
diff --git a/src/libpts/pts/pts_error.c b/src/libpts/pts/pts_error.c
index ec1e6c014..6e914b2a9 100644
--- a/src/libpts/pts/pts_error.c
+++ b/src/libpts/pts/pts_error.c
@@ -56,4 +56,44 @@ pa_tnc_attr_t* pts_hash_alg_error_create(pts_meas_algorithms_t algorithms)
writer->destroy(writer);
return attr;
-} \ No newline at end of file
+}
+
+/**
+ * Described in header.
+ */
+pa_tnc_attr_t* pts_dh_group_error_create(pts_dh_group_t dh_groups)
+{
+ bio_writer_t *writer;
+ chunk_t msg_info;
+ pa_tnc_attr_t *attr;
+
+ writer = bio_writer_create(4);
+ writer->write_uint16(writer, 0x0000);
+ writer->write_uint16(writer, dh_groups);
+ msg_info = writer->get_buf(writer);
+ attr = ietf_attr_pa_tnc_error_create(PEN_TCG, TCG_PTS_DH_GRPS_NOT_SUPPORTED,
+ msg_info);
+ writer->destroy(writer);
+
+ return attr;
+}
+
+/**
+ * Described in header.
+ */
+pa_tnc_attr_t* pts_dh_nonce_error_create(int min_nonce_len, int max_nonce_len)
+{
+ bio_writer_t *writer;
+ chunk_t msg_info;
+ pa_tnc_attr_t *attr;
+
+ writer = bio_writer_create(4);
+ writer->write_uint16(writer, min_nonce_len);
+ writer->write_uint16(writer, max_nonce_len);
+ msg_info = writer->get_buf(writer);
+ attr = ietf_attr_pa_tnc_error_create(PEN_TCG, TCG_PTS_BAD_NONCE_LENGTH,
+ msg_info);
+ writer->destroy(writer);
+
+ return attr;
+}
diff --git a/src/libpts/pts/pts_error.h b/src/libpts/pts/pts_error.h
index 6eeab0792..9a53abd98 100644
--- a/src/libpts/pts/pts_error.h
+++ b/src/libpts/pts/pts_error.h
@@ -24,32 +24,36 @@
typedef enum pts_error_code_t pts_error_code_t;
#include "pts_meas_algo.h"
+#include "pts_dh_group.h"
#include "pa_tnc/pa_tnc_attr.h"
#include <library.h>
+#define PTS_MIN_NONCE_LEN 17
+#define PTS_MAX_NONCE_LEN 0xffff
+
/**
* PTS Attestation Error Codes
* see section 3.14.2 of PTS Protocol: Binding to TNC IF-M Specification
*/
enum pts_error_code_t {
- TCG_PTS_RESERVED_ERROR = 0,
+ TCG_PTS_RESERVED_ERROR = 0,
TCG_PTS_HASH_ALG_NOT_SUPPORTED = 1,
- TCG_PTS_INVALID_PATH = 2,
- TCG_PTS_FILE_NOT_FOUND = 3,
- TCG_PTS_REG_NOT_SUPPORTED = 4,
- TCG_PTS_REG_KEY_NOT_FOUND = 5,
- TCG_PTS_DH_GRPS_NOT_SUPPORTED = 6,
- TCG_PTS_BAD_NONCE_LENGTH = 7,
- TCG_PTS_INVALID_NAME_FAM = 8,
+ TCG_PTS_INVALID_PATH = 2,
+ TCG_PTS_FILE_NOT_FOUND = 3,
+ TCG_PTS_REG_NOT_SUPPORTED = 4,
+ TCG_PTS_REG_KEY_NOT_FOUND = 5,
+ TCG_PTS_DH_GRPS_NOT_SUPPORTED = 6,
+ TCG_PTS_BAD_NONCE_LENGTH = 7,
+ TCG_PTS_INVALID_NAME_FAM = 8,
TCG_PTS_TPM_VERS_NOT_SUPPORTED = 9,
- TCG_PTS_INVALID_DELIMITER = 10,
+ TCG_PTS_INVALID_DELIMITER = 10,
TCG_PTS_OPERATION_NOT_SUPPORTED = 11,
- TCG_PTS_RM_ERROR = 12,
- TCG_PTS_UNABLE_LOCAL_VAL = 13,
- TCG_PTS_UNABLE_CUR_EVID = 14,
- TCG_PTS_UNABLE_DET_TTC = 15,
- TCG_PTS_UNABLE_DET_PCR = 16,
+ TCG_PTS_RM_ERROR = 12,
+ TCG_PTS_UNABLE_LOCAL_VAL = 13,
+ TCG_PTS_UNABLE_CUR_EVID = 14,
+ TCG_PTS_UNABLE_DET_TTC = 15,
+ TCG_PTS_UNABLE_DET_PCR = 16,
};
/**
@@ -61,8 +65,25 @@ extern enum_name_t *pts_error_code_names;
* Creates a PTS Hash Algorithm Not Supported Error Attribute
* see section 4.2.2 of PTS Protocol: Binding to TNC IF-M Specification
*
- * @param algorithms supported measurement hash algorithms
+ * @param algorithms supported measurement hash algorithms
*/
pa_tnc_attr_t* pts_hash_alg_error_create(pts_meas_algorithms_t algorithms);
+/**
+ * Creates a PTS DH Group Not Supported Error Attribute
+ * see section 4.2.4 of PTS Protocol: Binding to TNC IF-M Specification
+ *
+ * @param dh_groups supported DH groups
+ */
+pa_tnc_attr_t* pts_dh_group_error_create(pts_dh_group_t dh_groups);
+
+/**
+ * Creates a PTS DH PN Nonce Not Supported Error Attribute
+ * see section 4.2.5 of PTS Protocol: Binding to TNC IF-M Specification
+ *
+ * @param min_nonce_len minimum nonce length
+ * @param max_nonce_len maximum nonce length
+ */
+pa_tnc_attr_t* pts_dh_nonce_error_create(int min_nonce_len, int max_nonce_len);
+
#endif /** PTS_ERROR_H_ @}*/
diff --git a/src/libpts/pts/pts_file_meta.c b/src/libpts/pts/pts_file_meta.c
index 0924b3b25..6ed1c01b4 100644
--- a/src/libpts/pts/pts_file_meta.c
+++ b/src/libpts/pts/pts_file_meta.c
@@ -56,54 +56,15 @@ METHOD(pts_file_meta_t, get_file_count, int,
}
METHOD(pts_file_meta_t, add, void,
- private_pts_file_meta_t *this, char *filename, pts_file_type_t type,
- u_int64_t filesize, time_t create_time, time_t last_modify_time, time_t last_access_time,
- u_int64_t owner_id, u_int64_t group_id)
+ private_pts_file_meta_t *this, pts_file_metadata_t *metadata)
{
- pts_file_metadata_t *entry;
-
- entry = malloc_thing(pts_file_metadata_t);
-
- entry->filename = strdup(filename);
- entry->meta_length = PTS_FILE_METADATA_SIZE + strlen(entry->filename);
- entry->type = type;
- entry->filesize = filesize;
- entry->create_time = create_time;
- entry->last_modify_time = last_modify_time;
- entry->last_access_time = last_access_time;
- entry->owner_id = owner_id;
- entry->group_id = group_id;
-
- this->list->insert_last(this->list, entry);
-}
-
-/**
- * Enumerate file metadata entries
- */
-static bool entry_filter(void *null, pts_file_metadata_t **entry,
- char **filename, void *i2, u_int16_t *meta_length, void *i3,
- pts_file_type_t *type, void *i4, u_int64_t *filesize, void *i5,
- time_t *create_time, void *i6, time_t *last_modify_time, void *i7,
- time_t *last_access_time, void *i8, u_int64_t *owner_id, void *i9,
- u_int64_t *group_id)
-{
- *filename = (*entry)->filename;
- *meta_length = (*entry)->meta_length;
- *type = (*entry)->type;
- *filesize = (*entry)->filesize;
- *create_time = (*entry)->create_time;
- *last_modify_time = (*entry)->last_modify_time;
- *last_access_time = (*entry)->last_access_time;
- *owner_id = (*entry)->owner_id;
- *group_id = (*entry)->group_id;
- return TRUE;
+ this->list->insert_last(this->list, metadata);
}
METHOD(pts_file_meta_t, create_enumerator, enumerator_t*,
private_pts_file_meta_t *this)
{
- return enumerator_create_filter(this->list->create_enumerator(this->list),
- (void*)entry_filter, NULL, NULL);
+ return this->list->create_enumerator(this->list);
}
METHOD(pts_file_meta_t, destroy, void,
diff --git a/src/libpts/pts/pts_file_meta.h b/src/libpts/pts/pts_file_meta.h
index 36a4b6294..3f1813306 100644
--- a/src/libpts/pts/pts_file_meta.h
+++ b/src/libpts/pts/pts_file_meta.h
@@ -29,22 +29,18 @@
typedef struct pts_file_meta_t pts_file_meta_t;
typedef struct pts_file_metadata_t pts_file_metadata_t;
-/* Without filename field included */
-#define PTS_FILE_METADATA_SIZE 52
-
/**
* Structure holding file metadata
*/
struct pts_file_metadata_t {
- u_int16_t meta_length;
- pts_file_type_t type;
- u_int64_t filesize;
- time_t create_time;
- time_t last_modify_time;
- time_t last_access_time;
- u_int64_t owner_id;
- u_int64_t group_id;
- char *filename;
+ pts_file_type_t type;
+ u_int64_t filesize;
+ u_int64_t created;
+ u_int64_t modified;
+ u_int64_t accessed;
+ u_int64_t owner;
+ u_int64_t group;
+ char *filename;
};
/**
@@ -60,14 +56,12 @@ struct pts_file_meta_t {
int (*get_file_count)(pts_file_meta_t *this);
/**
- * Add a PTS File Metadata
+ * Add PTS File Metadata
*
* @param filename Name of measured file or directory
* @param metadata File metadata
*/
- void (*add)(pts_file_meta_t *this, char *filename, pts_file_type_t type,
- u_int64_t filesize, time_t create_time, time_t last_modfy_time, time_t last_access_time,
- u_int64_t owner_id, u_int64_t group_id);
+ void (*add)(pts_file_meta_t *this, pts_file_metadata_t *metadata);
/**
* Create a PTS File Metadata enumerator
diff --git a/src/libpts/pts/pts_file_type.c b/src/libpts/pts/pts_file_type.c
new file mode 100644
index 000000000..fe849dea4
--- /dev/null
+++ b/src/libpts/pts/pts_file_type.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2011 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 "pts_file_type.h"
+
+ENUM(pts_file_type_names, PTS_FILE_OTHER, PTS_FILE_SOCKET,
+ "Other",
+ "FIFO",
+ "Character-Special",
+ "Reserved-3",
+ "Directory",
+ "Reserved-5",
+ "Block-Special",
+ "Reserved-7",
+ "Regular",
+ "Reserved-9",
+ "Symbolic-Link",
+ "Reserved-11",
+ "Socket"
+);
+
diff --git a/src/libpts/pts/pts_file_type.h b/src/libpts/pts/pts_file_type.h
index f3c5b94dd..c1d236888 100644
--- a/src/libpts/pts/pts_file_type.h
+++ b/src/libpts/pts/pts_file_type.h
@@ -21,6 +21,8 @@
#ifndef PTS_FILE_TYPE_H_
#define PTS_FILE_TYPE_H_
+#include <library.h>
+
typedef enum pts_file_type_t pts_file_type_t;
/**
@@ -28,22 +30,34 @@ typedef enum pts_file_type_t pts_file_type_t;
* see section 3.17.3 of PTS Protocol: Binding to TNC IF-M Specification
*/
enum pts_file_type_t {
- /** Ignore */
+ /** Either unknown or different from standardized types */
PTS_FILE_OTHER = 0x0000,
- /** CRTM */
+ /** Pipe communication file */
PTS_FILE_FIFO = 0x0001,
- /** BIOS */
+ /** Character special file */
PTS_FILE_CHAR_SPEC = 0x0002,
- /** Platform Extensions */
+ /** Reserved */
+ PTS_FILE_RESERVED_3 = 0x0003,
+ /** Directory */
PTS_FILE_DIRECTORY = 0x0004,
- /** Motherboard firmware */
+ /** Reserved */
+ PTS_FILE_RESERVED_5 = 0x0005,
+ /** Block special file */
PTS_FILE_BLOCK_SPEC = 0x0006,
- /** Initial Program Loader */
+ /** Reserved */
+ PTS_FILE_RESERVED_7 = 0x0007,
+ /** Regular file */
PTS_FILE_REGULAR = 0x0008,
- /** Option ROMs */
+ /** Reserved */
+ PTS_FILE_RESERVED_9 = 0x0009,
+ /** Symbolic link */
PTS_FILE_SYM_LINK = 0x000A,
- /** Option ROMs */
+ /** Reserved */
+ PTS_FILE_RESERVED_11 = 0x000B,
+ /** Socket communication special file */
PTS_FILE_SOCKET = 0x000C,
};
+extern enum_name_t *pts_file_type_names;
+
#endif /** PTS_FILE_TYPE_H_ @}*/
diff --git a/src/libpts/pts/pts_funct_comp_name.h b/src/libpts/pts/pts_funct_comp_name.h
deleted file mode 100644
index 0926a2bc7..000000000
--- a/src/libpts/pts/pts_funct_comp_name.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2011 Sansar Choinyambuu
- * 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 pts_funct_comp_name pts_funct_comp_name
- * @{ @ingroup pts
- */
-
-#ifndef PTS_FUNCT_COMP_NAME_H_
-#define PTS_FUNCT_COMP_NAME_H_
-
-typedef enum pts_funct_comp_type_t pts_funct_comp_type_t;
-typedef enum pts_funct_comp_name_t pts_funct_comp_name_t;
-typedef struct pts_qualifier_t pts_qualifier_t;
-
-/**
- * PTS Component Functional Type for Qualifier field
- */
-enum pts_funct_comp_type_t {
- /** Unknown */
- PTS_FUNC_COMP_TYPE_UNKNOWN = 0x0,
- /** Trusted Platform */
- PTS_FUNC_COMP_TYPE_TRUSTED = 0x1,
- /** Operating System */
- PTS_FUNC_COMP_TYPE_OS = 0x2,
- /** Graphical User Interface */
- PTS_FUNC_COMP_TYPE_GUI = 0x3,
- /** Application */
- PTS_FUNC_COMP_TYPE_APP = 0x4,
- /** Networking */
- PTS_FUNC_COMP_TYPE_NET = 0x5,
- /** Library */
- PTS_FUNC_COMP_TYPE_LIB = 0x6,
- /** TNC Defined Component */
- PTS_FUNC_COMP_TYPE_TNC = 0x7,
- /** All matching Components */
- PTS_FUNC_COMP_TYPE_ALL = 0xF,
-};
-
-/**
- * PTS Component Functional Name Binary Enumeration
- */
-enum pts_funct_comp_name_t {
- /** Ignore */
- PTS_FUNC_COMP_NAME_IGNORE = 0x0000,
- /** CRTM */
- PTS_FUNC_COMP_NAME_CRTM = 0x0001,
- /** BIOS */
- PTS_FUNC_COMP_NAME_BIOS = 0x0002,
- /** Platform Extensions */
- PTS_FUNC_COMP_NAME_PLATFORM_EXT = 0x0003,
- /** Motherboard firmware */
- PTS_FUNC_COMP_NAME_BOARD = 0x0004,
- /** Initial Program Loader */
- PTS_FUNC_COMP_NAME_INIT_LOADER = 0x0005,
- /** Option ROMs */
- PTS_FUNC_COMP_NAME_OPT_ROMS = 0x0006,
-};
-
-/**
- * Qualifier for Functional Component
- */
-struct pts_qualifier_t {
- bool kernel;
- bool sub_component;
- pts_funct_comp_type_t type;
-};
-
-#endif /** PTS_FUNCT_COMP_NAME_H_ @}*/
diff --git a/src/libpts/pts/pts_meas_algo.c b/src/libpts/pts/pts_meas_algo.c
index 260c844d8..865857d3c 100644
--- a/src/libpts/pts/pts_meas_algo.c
+++ b/src/libpts/pts/pts_meas_algo.c
@@ -17,10 +17,17 @@
#include <debug.h>
+ENUM(pts_meas_algorithm_names, PTS_MEAS_ALGO_NONE, PTS_MEAS_ALGO_SHA384,
+ "None",
+ "SHA1",
+ "SHA256",
+ "SHA384"
+);
+
/**
* Described in header.
*/
-bool pts_meas_probe_algorithms(pts_meas_algorithms_t *algorithms)
+bool pts_meas_algo_probe(pts_meas_algorithms_t *algorithms)
{
enumerator_t *enumerator;
hash_algorithm_t hash_alg;
@@ -77,7 +84,57 @@ bool pts_meas_probe_algorithms(pts_meas_algorithms_t *algorithms)
/**
* Described in header.
*/
-hash_algorithm_t pts_meas_to_hash_algorithm(pts_meas_algorithms_t algorithm)
+bool pts_meas_algo_update(char *hash_alg, pts_meas_algorithms_t *algorithms)
+{
+ if (strcaseeq(hash_alg, "sha384") || strcaseeq(hash_alg, "sha2_384"))
+ {
+ /* nothing to update, all algorithms are supported */
+ return TRUE;
+ }
+ if (strcaseeq(hash_alg, "sha256") || strcaseeq(hash_alg, "sha2_256"))
+ {
+ /* remove SHA384algorithm */
+ *algorithms &= ~PTS_MEAS_ALGO_SHA384;
+ return TRUE;
+ }
+ if (strcaseeq(hash_alg, "sha1"))
+ {
+ /* remove SHA384 and SHA256 algorithms */
+ *algorithms &= ~(PTS_MEAS_ALGO_SHA384 | PTS_MEAS_ALGO_SHA256);
+ return TRUE;
+ }
+ DBG1(DBG_PTS, "unknown hash algorithm '%s' configured", hash_alg);
+ return FALSE;
+}
+
+/**
+ * Described in header.
+ */
+pts_meas_algorithms_t pts_meas_algo_select(pts_meas_algorithms_t supported_algos,
+ pts_meas_algorithms_t offered_algos)
+{
+ if ((supported_algos & PTS_MEAS_ALGO_SHA384) &&
+ (offered_algos & PTS_MEAS_ALGO_SHA384))
+ {
+ return PTS_MEAS_ALGO_SHA384;
+ }
+ if ((supported_algos & PTS_MEAS_ALGO_SHA256) &&
+ (offered_algos & PTS_MEAS_ALGO_SHA256))
+ {
+ return PTS_MEAS_ALGO_SHA256;
+ }
+ if ((supported_algos & PTS_MEAS_ALGO_SHA1) &&
+ (offered_algos & PTS_MEAS_ALGO_SHA1))
+ {
+ return PTS_MEAS_ALGO_SHA1;
+ }
+ return PTS_MEAS_ALGO_NONE;
+}
+
+/**
+ * Described in header.
+ */
+hash_algorithm_t pts_meas_algo_to_hash(pts_meas_algorithms_t algorithm)
{
switch (algorithm)
{
@@ -91,3 +148,23 @@ hash_algorithm_t pts_meas_to_hash_algorithm(pts_meas_algorithms_t algorithm)
return HASH_UNKNOWN;
}
}
+
+/**
+ * Described in header.
+ */
+size_t pts_meas_algo_hash_size(pts_meas_algorithms_t algorithm)
+{
+ switch (algorithm)
+ {
+ case PTS_MEAS_ALGO_SHA1:
+ return HASH_SIZE_SHA1;
+ case PTS_MEAS_ALGO_SHA256:
+ return HASH_SIZE_SHA256;
+ case PTS_MEAS_ALGO_SHA384:
+ return HASH_SIZE_SHA384;
+ case PTS_MEAS_ALGO_NONE:
+ default:
+ return 0;
+ }
+}
+
diff --git a/src/libpts/pts/pts_meas_algo.h b/src/libpts/pts/pts_meas_algo.h
index 6aa0ce695..1d96a4946 100644
--- a/src/libpts/pts/pts_meas_algo.h
+++ b/src/libpts/pts/pts_meas_algo.h
@@ -30,12 +30,18 @@ typedef enum pts_meas_algorithms_t pts_meas_algorithms_t;
* PTS Measurement Algorithms
*/
enum pts_meas_algorithms_t {
- PTS_MEAS_ALGO_SHA1 = (1<<15),
- PTS_MEAS_ALGO_SHA256 = (1<<14),
- PTS_MEAS_ALGO_SHA384 = (1<<13),
+ PTS_MEAS_ALGO_NONE = 0,
+ PTS_MEAS_ALGO_SHA1 = (1<<15),
+ PTS_MEAS_ALGO_SHA256 = (1<<14),
+ PTS_MEAS_ALGO_SHA384 = (1<<13),
};
/**
+ * enum name for pts_meas_algorithms_t.
+ */
+extern enum_name_t *pts_meas_algorithm_names;
+
+/**
* Diffie-Hellman Hash Algorithm Values
* see section 3.8.5 of PTS Protocol: Binding to TNC IF-M Specification
*
@@ -53,7 +59,32 @@ enum pts_meas_algorithms_t {
* @param algorithms set of available algorithms
* @return TRUE if mandatory algorithms are available
*/
-bool pts_meas_probe_algorithms(pts_meas_algorithms_t *algorithms);
+bool pts_meas_algo_probe(pts_meas_algorithms_t *algorithms);
+
+/**
+ * Update supported PTS measurement algorithms according to configuration
+ *
+ * sha1 : PTS_MEAS_ALGO_SHA1
+ * sha256: PTS_MEAS_ALGO_SHA1 | PTS_MEAS_ALGO_SHA256
+ * sha384: PTS_MEAS_ALGO_SHA1 | PTS_MEAS_ALGO_SHA256 | PTS_MEAS_ALGO_SHA384
+ *
+ * The PTS-IMC is expected to select the strongest supported algorithm
+ *
+ * @param hash_alg configured hash algorithm
+ * @param algorithms returns set of available PTS measurement algorithms
+ */
+bool pts_meas_algo_update(char *hash_alg, pts_meas_algorithms_t *algorithms);
+
+/**
+ * Select the strongest PTS measurement algorithm
+ * among a set of offered PTS measurement algorithms
+ *
+ * @param supported_algos set of supported PTS measurement algorithms
+ * @param offered_algos set of offered PTS measurements algorithms
+ * @return selected algorithm
+ */
+pts_meas_algorithms_t pts_meas_algo_select(pts_meas_algorithms_t supported_algos,
+ pts_meas_algorithms_t offered_algos);
/**
* Convert pts_meas_algorithms_t to hash_algorithm_t
@@ -61,6 +92,14 @@ bool pts_meas_probe_algorithms(pts_meas_algorithms_t *algorithms);
* @param algorithm PTS measurement algorithm type
* @return libstrongswan hash algorithm type
*/
-hash_algorithm_t pts_meas_to_hash_algorithm(pts_meas_algorithms_t algorithm);
+hash_algorithm_t pts_meas_algo_to_hash(pts_meas_algorithms_t algorithm);
+
+/**
+ * Return the hash size of a pts_meas_algorithm
+ *
+ * @param algorithm PTS measurement algorithm type
+ * @return hash size in bytes
+ */
+size_t pts_meas_algo_hash_size(pts_meas_algorithms_t algorithm);
#endif /** PTS_MEAS_ALGO_H_ @}*/
diff --git a/src/libpts/pts/pts_req_func_comp_evid.h b/src/libpts/pts/pts_req_func_comp_evid.h
new file mode 100644
index 000000000..bbf5bbf5b
--- /dev/null
+++ b/src/libpts/pts/pts_req_func_comp_evid.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2011 Sansar Choinyambuu
+ * 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 pts_req_func_comp_evid pts_req_func_comp_evid
+ * @{ @ingroup pts
+ */
+
+#ifndef PTS_REQ_FUNC_COMP_EVID_H_
+#define PTS_REQ_FUNC_COMP_EVID_H_
+
+typedef enum pts_req_func_comp_evid_t pts_req_func_comp_evid_t;
+
+#include <library.h>
+
+/**
+ * PTS Request Functional Component Evidence Flags
+ */
+enum pts_req_func_comp_evid_t {
+ /** Transitive Trust Chain flag */
+ PTS_REQ_FUNC_COMP_EVID_TTC = (1<<7),
+ /** Verify Component flag */
+ PTS_REQ_FUNC_COMP_EVID_VER = (1<<6),
+ /** Current Evidence flag */
+ PTS_REQ_FUNC_COMP_EVID_CURR = (1<<5),
+ /** PCR Information flag */
+ PTS_REQ_FUNC_COMP_EVID_PCR = (1<<4),
+};
+
+#endif /** PTS_FUNCT_COMP_EVID_REQ_H_ @}*/
diff --git a/src/libpts/pts/pts_simple_evid_final.h b/src/libpts/pts/pts_simple_evid_final.h
new file mode 100644
index 000000000..0c8dea0cc
--- /dev/null
+++ b/src/libpts/pts/pts_simple_evid_final.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2011 Sansar Choinyambuu
+ * 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 pts_simple_evid_final pts_rsimple_evid_final
+ * @{ @ingroup pts
+ */
+
+#ifndef PTS_SIMPLE_EVID_FINAL_H_
+#define PTS_SIMPLE_EVID_FINAL_H_
+
+typedef enum pts_simple_evid_final_flag_t pts_simple_evid_final_flag_t;
+
+#include <library.h>
+
+/**
+ * PTS Simple Evidence Final Flags
+ */
+enum pts_simple_evid_final_flag_t {
+ /** TPM PCR Composite and TPM Quote Signature not included */
+ PTS_SIMPLE_EVID_FINAL_NO = 0x00,
+ /** TPM PCR Composite and TPM Quote Signature included
+ * using TPM_QUOTE_INFO */
+ PTS_SIMPLE_EVID_FINAL_QUOTE_INFO = 0x40,
+ /** TPM PCR Composite and TPM Quote Signature included
+ * using TPM_QUOTE_INFO2, TPM_CAP_VERSION_INFO not appended */
+ PTS_SIMPLE_EVID_FINAL_QUOTE_INFO2 = 0x80,
+ /** TPM PCR Composite and TPM Quote Signature included
+ * using TPM_QUOTE_INFO2, TPM_CAP_VERSION_INFO appended */
+ PTS_SIMPLE_EVID_FINAL_QUOTE_INFO2_CAP_VER = 0xC0,
+ /** Evidence Signature included */
+ PTS_SIMPLE_EVID_FINAL_EVID_SIG = 0x20,
+};
+
+#endif /** PTS_SIMPLE_EVID_FINAL_H_ @}*/
diff --git a/src/libpts/tcg/tcg_attr.c b/src/libpts/tcg/tcg_attr.c
index 51acb6792..656791a8f 100644
--- a/src/libpts/tcg/tcg_attr.c
+++ b/src/libpts/tcg/tcg_attr.c
@@ -14,24 +14,29 @@
#include "tcg_attr.h"
#include "tcg/tcg_pts_attr_proto_caps.h"
+#include "tcg/tcg_pts_attr_dh_nonce_params_req.h"
+#include "tcg/tcg_pts_attr_dh_nonce_params_resp.h"
+#include "tcg/tcg_pts_attr_dh_nonce_finish.h"
#include "tcg/tcg_pts_attr_meas_algo.h"
#include "tcg/tcg_pts_attr_get_tpm_version_info.h"
#include "tcg/tcg_pts_attr_tpm_version_info.h"
#include "tcg/tcg_pts_attr_get_aik.h"
#include "tcg/tcg_pts_attr_aik.h"
-#include "tcg/tcg_pts_attr_req_funct_comp_evid.h"
+#include "tcg/tcg_pts_attr_req_func_comp_evid.h"
#include "tcg/tcg_pts_attr_gen_attest_evid.h"
#include "tcg/tcg_pts_attr_simple_comp_evid.h"
#include "tcg/tcg_pts_attr_simple_evid_final.h"
#include "tcg/tcg_pts_attr_req_file_meas.h"
#include "tcg/tcg_pts_attr_file_meas.h"
+#include "tcg/tcg_pts_attr_req_file_meta.h"
+#include "tcg/tcg_pts_attr_unix_file_meta.h"
-ENUM_BEGIN(tcg_attr_names, TCG_PTS_REQ_FUNCT_COMP_EVID,
- TCG_PTS_REQ_FUNCT_COMP_EVID,
+ENUM_BEGIN(tcg_attr_names, TCG_PTS_REQ_FUNC_COMP_EVID,
+ TCG_PTS_REQ_FUNC_COMP_EVID,
"Request Functional Component Evidence");
ENUM_NEXT(tcg_attr_names, TCG_PTS_GEN_ATTEST_EVID,
TCG_PTS_GEN_ATTEST_EVID,
- TCG_PTS_REQ_FUNCT_COMP_EVID,
+ TCG_PTS_REQ_FUNC_COMP_EVID,
"Generate Attestation Evidence");
ENUM_NEXT(tcg_attr_names, TCG_PTS_SIMPLE_COMP_EVID,
TCG_PTS_SIMPLE_COMP_EVID,
@@ -154,6 +159,12 @@ pa_tnc_attr_t* tcg_attr_create_from_data(u_int32_t type, chunk_t value)
return tcg_pts_attr_proto_caps_create_from_data(value, TRUE);
case TCG_PTS_PROTO_CAPS:
return tcg_pts_attr_proto_caps_create_from_data(value, FALSE);
+ case TCG_PTS_DH_NONCE_PARAMS_REQ:
+ return tcg_pts_attr_dh_nonce_params_req_create_from_data(value);
+ case TCG_PTS_DH_NONCE_PARAMS_RESP:
+ return tcg_pts_attr_dh_nonce_params_resp_create_from_data(value);
+ case TCG_PTS_DH_NONCE_FINISH:
+ return tcg_pts_attr_dh_nonce_finish_create_from_data(value);
case TCG_PTS_MEAS_ALGO:
return tcg_pts_attr_meas_algo_create_from_data(value, FALSE);
case TCG_PTS_MEAS_ALGO_SELECTION:
@@ -166,8 +177,8 @@ pa_tnc_attr_t* tcg_attr_create_from_data(u_int32_t type, chunk_t value)
return tcg_pts_attr_get_aik_create_from_data(value);
case TCG_PTS_AIK:
return tcg_pts_attr_aik_create_from_data(value);
- case TCG_PTS_REQ_FUNCT_COMP_EVID:
- return tcg_pts_attr_req_funct_comp_evid_create_from_data(value);
+ case TCG_PTS_REQ_FUNC_COMP_EVID:
+ return tcg_pts_attr_req_func_comp_evid_create_from_data(value);
case TCG_PTS_GEN_ATTEST_EVID:
return tcg_pts_attr_gen_attest_evid_create_from_data(value);
case TCG_PTS_SIMPLE_COMP_EVID:
@@ -178,17 +189,16 @@ pa_tnc_attr_t* tcg_attr_create_from_data(u_int32_t type, chunk_t value)
return tcg_pts_attr_req_file_meas_create_from_data(value);
case TCG_PTS_FILE_MEAS:
return tcg_pts_attr_file_meas_create_from_data(value);
- case TCG_PTS_DH_NONCE_PARAMS_REQ:
- case TCG_PTS_DH_NONCE_PARAMS_RESP:
- case TCG_PTS_DH_NONCE_FINISH:
+ case TCG_PTS_REQ_FILE_META:
+ return tcg_pts_attr_req_file_meta_create_from_data(value);
+ case TCG_PTS_UNIX_FILE_META:
+ return tcg_pts_attr_unix_file_meta_create_from_data(value);
case TCG_PTS_REQ_TEMPL_REF_MANI_SET_META:
case TCG_PTS_TEMPL_REF_MANI_SET_META:
case TCG_PTS_UPDATE_TEMPL_REF_MANI:
case TCG_PTS_VERIFICATION_RESULT:
case TCG_PTS_INTEG_REPORT:
- case TCG_PTS_REQ_FILE_META:
case TCG_PTS_WIN_FILE_META:
- case TCG_PTS_UNIX_FILE_META:
case TCG_PTS_REQ_REGISTRY_VALUE:
case TCG_PTS_REGISTRY_VALUE:
case TCG_PTS_REQ_INTEG_MEAS_LOG:
diff --git a/src/libpts/tcg/tcg_attr.h b/src/libpts/tcg/tcg_attr.h
index 71ecc1e0a..b45e1488f 100644
--- a/src/libpts/tcg/tcg_attr.h
+++ b/src/libpts/tcg/tcg_attr.h
@@ -48,7 +48,7 @@ enum tcg_attr_t {
TCG_PTS_AIK = 0x0E000000,
/* PTS-based Attestation Evidence */
- TCG_PTS_REQ_FUNCT_COMP_EVID = 0x00100000,
+ TCG_PTS_REQ_FUNC_COMP_EVID = 0x00100000,
TCG_PTS_GEN_ATTEST_EVID = 0x00200000,
TCG_PTS_SIMPLE_COMP_EVID = 0x00300000,
TCG_PTS_SIMPLE_EVID_FINAL = 0x00400000,
diff --git a/src/libpts/tcg/tcg_pts_attr_aik.c b/src/libpts/tcg/tcg_pts_attr_aik.c
index ffef15f29..9be3794b6 100644
--- a/src/libpts/tcg/tcg_pts_attr_aik.c
+++ b/src/libpts/tcg/tcg_pts_attr_aik.c
@@ -72,6 +72,11 @@ struct private_tcg_pts_attr_aik_t {
* AIK Certificate or Public Key
*/
certificate_t *aik;
+
+ /**
+ * Reference count
+ */
+ refcount_t ref;
};
METHOD(pa_tnc_attr_t, get_vendor_id, pen_t,
@@ -126,6 +131,7 @@ METHOD(pa_tnc_attr_t, build, void,
writer->write_uint8(writer, flags);
writer->write_data (writer, aik_blob);
this->value = chunk_clone(writer->get_buf(writer));
+ free(aik_blob.ptr);
writer->destroy(writer);
}
@@ -162,12 +168,22 @@ METHOD(pa_tnc_attr_t, process, status_t,
return SUCCESS;
}
+METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*,
+ private_tcg_pts_attr_aik_t *this)
+{
+ ref_get(&this->ref);
+ return &this->public.pa_tnc_attribute;
+}
+
METHOD(pa_tnc_attr_t, destroy, void,
private_tcg_pts_attr_aik_t *this)
{
- DESTROY_IF(this->aik);
- free(this->value.ptr);
- free(this);
+ if (ref_put(&this->ref))
+ {
+ DESTROY_IF(this->aik);
+ free(this->value.ptr);
+ free(this);
+ }
}
METHOD(tcg_pts_attr_aik_t, get_aik, certificate_t*,
@@ -193,6 +209,7 @@ pa_tnc_attr_t *tcg_pts_attr_aik_create(certificate_t *aik)
.set_noskip_flag = _set_noskip_flag,
.build = _build,
.process = _process,
+ .get_ref = _get_ref,
.destroy = _destroy,
},
.get_aik = _get_aik,
@@ -200,6 +217,7 @@ pa_tnc_attr_t *tcg_pts_attr_aik_create(certificate_t *aik)
.vendor_id = PEN_TCG,
.type = TCG_PTS_AIK,
.aik = aik->get_ref(aik),
+ .ref = 1,
);
return &this->public.pa_tnc_attribute;
@@ -223,6 +241,7 @@ pa_tnc_attr_t *tcg_pts_attr_aik_create_from_data(chunk_t data)
.set_noskip_flag = _set_noskip_flag,
.build = _build,
.process = _process,
+ .get_ref = _get_ref,
.destroy = _destroy,
},
.get_aik = _get_aik,
@@ -230,6 +249,7 @@ pa_tnc_attr_t *tcg_pts_attr_aik_create_from_data(chunk_t data)
.vendor_id = PEN_TCG,
.type = TCG_PTS_AIK,
.value = chunk_clone(data),
+ .ref = 1,
);
return &this->public.pa_tnc_attribute;
diff --git a/src/libpts/tcg/tcg_pts_attr_dh_nonce_finish.c b/src/libpts/tcg/tcg_pts_attr_dh_nonce_finish.c
new file mode 100644
index 000000000..dce98e87d
--- /dev/null
+++ b/src/libpts/tcg/tcg_pts_attr_dh_nonce_finish.c
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2011 Sansar Choinyambuu
+ * 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 "tcg_pts_attr_dh_nonce_finish.h"
+
+#include <pa_tnc/pa_tnc_msg.h>
+#include <bio/bio_writer.h>
+#include <bio/bio_reader.h>
+#include <debug.h>
+
+typedef struct private_tcg_pts_attr_dh_nonce_finish_t
+ private_tcg_pts_attr_dh_nonce_finish_t;
+
+/**
+ * PTS DH Nonce Finish
+ * see section 3.8.3 of PTS Protocol: Binding to TNC IF-M Specification
+ *
+ * 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
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Reserved | Nonce Len | Selected Hash Algorithm |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | D-H Initiator Public Value ... |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | D-H Initiator Nonce ... |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ */
+
+#define PTS_DH_NONCE_FINISH_SIZE 12
+#define PTS_DH_NONCE_FINISH_RESERVED 0x00
+
+/**
+ * Private data of an tcg_pts_attr_dh_nonce_finish_t object.
+ */
+struct private_tcg_pts_attr_dh_nonce_finish_t {
+
+ /**
+ * Public members of tcg_pts_attr_dh_nonce_finish_t
+ */
+ tcg_pts_attr_dh_nonce_finish_t public;
+
+ /**
+ * Attribute vendor ID
+ */
+ pen_t vendor_id;
+
+ /**
+ * Attribute type
+ */
+ u_int32_t type;
+
+ /**
+ * Attribute value
+ */
+ chunk_t value;
+
+ /**
+ * Noskip flag
+ */
+ bool noskip_flag;
+
+ /**
+ * Selected Hashing Algorithm
+ */
+ pts_meas_algorithms_t hash_algo;
+
+ /**
+ * DH Initiator Public Value
+ */
+ chunk_t initiator_value;
+
+ /**
+ * DH Initiator Nonce
+ */
+ chunk_t initiator_nonce;
+
+ /**
+ * Reference count
+ */
+ refcount_t ref;
+};
+
+METHOD(pa_tnc_attr_t, get_vendor_id, pen_t,
+ private_tcg_pts_attr_dh_nonce_finish_t *this)
+{
+ return this->vendor_id;
+}
+
+METHOD(pa_tnc_attr_t, get_type, u_int32_t,
+ private_tcg_pts_attr_dh_nonce_finish_t *this)
+{
+ return this->type;
+}
+
+METHOD(pa_tnc_attr_t, get_value, chunk_t,
+ private_tcg_pts_attr_dh_nonce_finish_t *this)
+{
+ return this->value;
+}
+
+METHOD(pa_tnc_attr_t, get_noskip_flag, bool,
+ private_tcg_pts_attr_dh_nonce_finish_t *this)
+{
+ return this->noskip_flag;
+}
+
+METHOD(pa_tnc_attr_t, set_noskip_flag,void,
+ private_tcg_pts_attr_dh_nonce_finish_t *this, bool noskip)
+{
+ this->noskip_flag = noskip;
+}
+
+METHOD(pa_tnc_attr_t, build, void,
+ private_tcg_pts_attr_dh_nonce_finish_t *this)
+{
+ bio_writer_t *writer;
+
+ writer = bio_writer_create(PTS_DH_NONCE_FINISH_SIZE);
+ writer->write_uint8 (writer, PTS_DH_NONCE_FINISH_RESERVED);
+ writer->write_uint8 (writer, this->initiator_nonce.len);
+ writer->write_uint16(writer, this->hash_algo);
+ writer->write_data (writer, this->initiator_value);
+ writer->write_data (writer, this->initiator_nonce);
+
+ this->value = chunk_clone(writer->get_buf(writer));
+ writer->destroy(writer);
+}
+
+METHOD(pa_tnc_attr_t, process, status_t,
+ private_tcg_pts_attr_dh_nonce_finish_t *this, u_int32_t *offset)
+{
+ bio_reader_t *reader;
+ u_int8_t reserved, nonce_len;
+ u_int16_t hash_algo;
+
+ if (this->value.len < PTS_DH_NONCE_FINISH_SIZE)
+ {
+ DBG1(DBG_TNC, "insufficient data for PTS DH Nonce Finish");
+ *offset = 0;
+ return FAILED;
+ }
+ reader = bio_reader_create(this->value);
+ reader->read_uint8 (reader, &reserved);
+ reader->read_uint8 (reader, &nonce_len);
+ reader->read_uint16(reader, &hash_algo);
+ reader->read_data(reader, reader->remaining(reader) - nonce_len,
+ &this->initiator_value);
+ reader->read_data(reader, nonce_len, &this->initiator_nonce);
+ this->hash_algo = hash_algo;
+ this->initiator_value = chunk_clone(this->initiator_value);
+ this->initiator_nonce = chunk_clone(this->initiator_nonce);
+ reader->destroy(reader);
+
+ return SUCCESS;
+}
+
+METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*,
+ private_tcg_pts_attr_dh_nonce_finish_t *this)
+{
+ ref_get(&this->ref);
+ return &this->public.pa_tnc_attribute;
+}
+
+METHOD(pa_tnc_attr_t, destroy, void,
+ private_tcg_pts_attr_dh_nonce_finish_t *this)
+{
+ if (ref_put(&this->ref))
+ {
+ free(this->value.ptr);
+ free(this->initiator_value.ptr);
+ free(this->initiator_nonce.ptr);
+ free(this);
+ }
+}
+
+METHOD(tcg_pts_attr_dh_nonce_finish_t, get_hash_algo, pts_meas_algorithms_t,
+ private_tcg_pts_attr_dh_nonce_finish_t *this)
+{
+ return this->hash_algo;
+}
+
+METHOD(tcg_pts_attr_dh_nonce_finish_t, get_initiator_value, chunk_t,
+ private_tcg_pts_attr_dh_nonce_finish_t *this)
+{
+ return this->initiator_value;
+}
+
+METHOD(tcg_pts_attr_dh_nonce_finish_t, get_initiator_nonce, chunk_t,
+ private_tcg_pts_attr_dh_nonce_finish_t *this)
+{
+ return this->initiator_nonce;
+}
+
+/**
+ * Described in header.
+ */
+pa_tnc_attr_t *tcg_pts_attr_dh_nonce_finish_create(
+ pts_meas_algorithms_t hash_algo,
+ chunk_t initiator_value,
+ chunk_t initiator_nonce)
+{
+ private_tcg_pts_attr_dh_nonce_finish_t *this;
+
+ INIT(this,
+ .public = {
+ .pa_tnc_attribute = {
+ .get_vendor_id = _get_vendor_id,
+ .get_type = _get_type,
+ .get_value = _get_value,
+ .get_noskip_flag = _get_noskip_flag,
+ .set_noskip_flag = _set_noskip_flag,
+ .build = _build,
+ .process = _process,
+ .get_ref = _get_ref,
+ .destroy = _destroy,
+ },
+ .get_hash_algo = _get_hash_algo,
+ .get_initiator_nonce = _get_initiator_nonce,
+ .get_initiator_value = _get_initiator_value,
+ },
+ .vendor_id = PEN_TCG,
+ .type = TCG_PTS_DH_NONCE_FINISH,
+ .hash_algo = hash_algo,
+ .initiator_value = initiator_value,
+ .initiator_nonce = chunk_clone(initiator_nonce),
+ .ref = 1,
+ );
+
+ return &this->public.pa_tnc_attribute;
+}
+
+/**
+ * Described in header.
+ */
+pa_tnc_attr_t *tcg_pts_attr_dh_nonce_finish_create_from_data(chunk_t value)
+{
+ private_tcg_pts_attr_dh_nonce_finish_t *this;
+
+ INIT(this,
+ .public = {
+ .pa_tnc_attribute = {
+ .get_vendor_id = _get_vendor_id,
+ .get_type = _get_type,
+ .get_value = _get_value,
+ .get_noskip_flag = _get_noskip_flag,
+ .set_noskip_flag = _set_noskip_flag,
+ .build = _build,
+ .process = _process,
+ .get_ref = _get_ref,
+ .destroy = _destroy,
+ },
+ .get_hash_algo = _get_hash_algo,
+ .get_initiator_nonce = _get_initiator_nonce,
+ .get_initiator_value = _get_initiator_value,
+ },
+ .vendor_id = PEN_TCG,
+ .type = TCG_PTS_DH_NONCE_FINISH,
+ .value = chunk_clone(value),
+ .ref = 1,
+ );
+
+ return &this->public.pa_tnc_attribute;
+}
diff --git a/src/libpts/tcg/tcg_pts_attr_dh_nonce_finish.h b/src/libpts/tcg/tcg_pts_attr_dh_nonce_finish.h
new file mode 100644
index 000000000..7148065c5
--- /dev/null
+++ b/src/libpts/tcg/tcg_pts_attr_dh_nonce_finish.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2011 Sansar Choinyambuu
+ * 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 tcg_pts_attr_dh_nonce_finish tcg_pts_attr_dh_nonce_finish
+ * @{ @ingroup tcg_pts_attr_dh_nonce_finish
+ */
+
+#ifndef TCG_PTS_ATTR_DH_NONCE_FINISH_H_
+#define TCG_PTS_ATTR_DH_NONCE_FINISH_H_
+
+typedef struct tcg_pts_attr_dh_nonce_finish_t tcg_pts_attr_dh_nonce_finish_t;
+
+#include "tcg_attr.h"
+#include "pa_tnc/pa_tnc_attr.h"
+#include "pts/pts_meas_algo.h"
+
+/**
+ * Class implementing the TCG PTS DH Nonce Finish Attribute
+ */
+struct tcg_pts_attr_dh_nonce_finish_t {
+
+ /**
+ * Public PA-TNC attribute interface
+ */
+ pa_tnc_attr_t pa_tnc_attribute;
+
+ /**
+ * Get nonce length
+ *
+ * @return Length of nonce
+ */
+ u_int8_t (*get_nonce_len)(tcg_pts_attr_dh_nonce_finish_t *this);
+
+ /**
+ * Get selected hash algorithm
+ *
+ * @return Selected hash algorithm
+ */
+ pts_meas_algorithms_t (*get_hash_algo)(tcg_pts_attr_dh_nonce_finish_t *this);
+
+ /**
+ * Get DH Initiator Public Value
+ *
+ * @return DH Initiator Public Value
+ */
+ chunk_t (*get_initiator_value)(tcg_pts_attr_dh_nonce_finish_t *this);
+
+ /**
+ * Get DH Initiator Nonce
+ *
+ * @return DH Initiator Nonce
+ */
+ chunk_t (*get_initiator_nonce)(tcg_pts_attr_dh_nonce_finish_t *this);
+
+};
+
+/**
+ * Creates an tcg_pts_attr_dh_nonce_finish_t object
+ *
+ * @param hash_algo Selected hash algorithm
+ * @param initiator_value DH Initiator Public Value
+ * @param initiator_nonce DH Initiator Nonce
+ */
+pa_tnc_attr_t* tcg_pts_attr_dh_nonce_finish_create(
+ pts_meas_algorithms_t hash_algo,
+ chunk_t initiator_value,
+ chunk_t initiator_nonce);
+
+/**
+ * Creates an tcg_pts_attr_dh_nonce_finish_t object from received data
+ *
+ * @param value unparsed attribute value
+ */
+pa_tnc_attr_t* tcg_pts_attr_dh_nonce_finish_create_from_data(chunk_t value);
+
+#endif /** TCG_PTS_ATTR_DH_NONCE_FINISH_H_ @}*/
diff --git a/src/libpts/tcg/tcg_pts_attr_dh_nonce_params_req.c b/src/libpts/tcg/tcg_pts_attr_dh_nonce_params_req.c
new file mode 100644
index 000000000..36266fe12
--- /dev/null
+++ b/src/libpts/tcg/tcg_pts_attr_dh_nonce_params_req.c
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2011 Sansar Choinyambuu
+ * 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 "tcg_pts_attr_dh_nonce_params_req.h"
+
+#include <pa_tnc/pa_tnc_msg.h>
+#include <bio/bio_writer.h>
+#include <bio/bio_reader.h>
+#include <debug.h>
+
+typedef struct private_tcg_pts_attr_dh_nonce_params_req_t
+ private_tcg_pts_attr_dh_nonce_params_req_t;
+
+/**
+ * PTS DH Nonce Parameters Request
+ * see section 3.8.1 of PTS Protocol: Binding to TNC IF-M Specification
+ *
+ * 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
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Reserved | Min. Nonce Len | D-H Group Set |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ */
+
+#define PTS_DH_NONCE_PARAMS_REQ_SIZE 4
+#define PTS_DH_NONCE_PARAMS_REQ_RESERVED 0x00
+
+/**
+ * Private data of an tcg_pts_attr_dh_nonce_params_req_t object.
+ */
+struct private_tcg_pts_attr_dh_nonce_params_req_t {
+
+ /**
+ * Public members of tcg_pts_attr_dh_nonce_params_req_t
+ */
+ tcg_pts_attr_dh_nonce_params_req_t public;
+
+ /**
+ * Attribute vendor ID
+ */
+ pen_t vendor_id;
+
+ /**
+ * Attribute type
+ */
+ u_int32_t type;
+
+ /**
+ * Attribute value
+ */
+ chunk_t value;
+
+ /**
+ * Noskip flag
+ */
+ bool noskip_flag;
+
+ /**
+ * Minimum acceptable length of nonce
+ */
+ u_int8_t min_nonce_len;
+
+ /**
+ * Diffie Hellman group set
+ */
+ pts_dh_group_t dh_groups;
+
+ /**
+ * Reference count
+ */
+ refcount_t ref;
+};
+
+METHOD(pa_tnc_attr_t, get_vendor_id, pen_t,
+ private_tcg_pts_attr_dh_nonce_params_req_t *this)
+{
+ return this->vendor_id;
+}
+
+METHOD(pa_tnc_attr_t, get_type, u_int32_t,
+ private_tcg_pts_attr_dh_nonce_params_req_t *this)
+{
+ return this->type;
+}
+
+METHOD(pa_tnc_attr_t, get_value, chunk_t,
+ private_tcg_pts_attr_dh_nonce_params_req_t *this)
+{
+ return this->value;
+}
+
+METHOD(pa_tnc_attr_t, get_noskip_flag, bool,
+ private_tcg_pts_attr_dh_nonce_params_req_t *this)
+{
+ return this->noskip_flag;
+}
+
+METHOD(pa_tnc_attr_t, set_noskip_flag,void,
+ private_tcg_pts_attr_dh_nonce_params_req_t *this, bool noskip)
+{
+ this->noskip_flag = noskip;
+}
+
+METHOD(pa_tnc_attr_t, build, void,
+ private_tcg_pts_attr_dh_nonce_params_req_t *this)
+{
+ bio_writer_t *writer;
+
+ writer = bio_writer_create(PTS_DH_NONCE_PARAMS_REQ_SIZE);
+ writer->write_uint8 (writer, PTS_DH_NONCE_PARAMS_REQ_RESERVED);
+ writer->write_uint8 (writer, this->min_nonce_len);
+ writer->write_uint16(writer, this->dh_groups);
+
+ this->value = chunk_clone(writer->get_buf(writer));
+ writer->destroy(writer);
+}
+
+METHOD(pa_tnc_attr_t, process, status_t,
+ private_tcg_pts_attr_dh_nonce_params_req_t *this, u_int32_t *offset)
+{
+ bio_reader_t *reader;
+ u_int8_t reserved;
+ u_int16_t dh_groups;
+
+ if (this->value.len < PTS_DH_NONCE_PARAMS_REQ_SIZE)
+ {
+ DBG1(DBG_TNC, "insufficient data for PTS DH Nonce Parameters Request");
+ *offset = 0;
+ return FAILED;
+ }
+ reader = bio_reader_create(this->value);
+ reader->read_uint8(reader, &reserved);
+ reader->read_uint8(reader, &this->min_nonce_len);
+ reader->read_uint16(reader, &dh_groups);
+ this->dh_groups = dh_groups;
+ reader->destroy(reader);
+
+ return SUCCESS;
+}
+
+METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*,
+ private_tcg_pts_attr_dh_nonce_params_req_t *this)
+{
+ ref_get(&this->ref);
+ return &this->public.pa_tnc_attribute;
+}
+
+METHOD(pa_tnc_attr_t, destroy, void,
+ private_tcg_pts_attr_dh_nonce_params_req_t *this)
+{
+ if (ref_put(&this->ref))
+ {
+ free(this->value.ptr);
+ free(this);
+ }
+}
+
+METHOD(tcg_pts_attr_dh_nonce_params_req_t, get_min_nonce_len, u_int8_t,
+ private_tcg_pts_attr_dh_nonce_params_req_t *this)
+{
+ return this->min_nonce_len;
+}
+
+METHOD(tcg_pts_attr_dh_nonce_params_req_t, get_dh_groups, pts_dh_group_t,
+ private_tcg_pts_attr_dh_nonce_params_req_t *this)
+{
+ return this->dh_groups;
+}
+
+/**
+ * Described in header.
+ */
+pa_tnc_attr_t *tcg_pts_attr_dh_nonce_params_req_create(u_int8_t min_nonce_len,
+ pts_dh_group_t dh_groups)
+{
+ private_tcg_pts_attr_dh_nonce_params_req_t *this;
+
+ INIT(this,
+ .public = {
+ .pa_tnc_attribute = {
+ .get_vendor_id = _get_vendor_id,
+ .get_type = _get_type,
+ .get_value = _get_value,
+ .get_noskip_flag = _get_noskip_flag,
+ .set_noskip_flag = _set_noskip_flag,
+ .build = _build,
+ .process = _process,
+ .get_ref = _get_ref,
+ .destroy = _destroy,
+ },
+ .get_min_nonce_len = _get_min_nonce_len,
+ .get_dh_groups = _get_dh_groups,
+ },
+ .vendor_id = PEN_TCG,
+ .type = TCG_PTS_DH_NONCE_PARAMS_REQ,
+ .min_nonce_len = min_nonce_len,
+ .dh_groups = dh_groups,
+ .ref = 1,
+ );
+
+ return &this->public.pa_tnc_attribute;
+}
+
+/**
+ * Described in header.
+ */
+pa_tnc_attr_t *tcg_pts_attr_dh_nonce_params_req_create_from_data(chunk_t value)
+{
+ private_tcg_pts_attr_dh_nonce_params_req_t *this;
+
+ INIT(this,
+ .public = {
+ .pa_tnc_attribute = {
+ .get_vendor_id = _get_vendor_id,
+ .get_type = _get_type,
+ .get_value = _get_value,
+ .get_noskip_flag = _get_noskip_flag,
+ .set_noskip_flag = _set_noskip_flag,
+ .build = _build,
+ .process = _process,
+ .get_ref = _get_ref,
+ .destroy = _destroy,
+ },
+ .get_min_nonce_len = _get_min_nonce_len,
+ .get_dh_groups = _get_dh_groups,
+ },
+ .vendor_id = PEN_TCG,
+ .type = TCG_PTS_DH_NONCE_PARAMS_REQ,
+ .value = chunk_clone(value),
+ .ref = 1,
+ );
+
+ return &this->public.pa_tnc_attribute;
+}
diff --git a/src/libpts/tcg/tcg_pts_attr_dh_nonce_params_req.h b/src/libpts/tcg/tcg_pts_attr_dh_nonce_params_req.h
new file mode 100644
index 000000000..170077156
--- /dev/null
+++ b/src/libpts/tcg/tcg_pts_attr_dh_nonce_params_req.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2011 Sansar Choinyambuu
+ * 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 tcg_pts_attr_dh_nonce_params_req tcg_pts_attr_dh_nonce_params_req
+ * @{ @ingroup tcg_pts_attr_dh_nonce_params_req
+ */
+
+#ifndef TCG_PTS_ATTR_DH_NONCE_PARAMS_REQ_H_
+#define TCG_PTS_ATTR_DH_NONCE_PARAMS_REQ_H_
+
+typedef struct tcg_pts_attr_dh_nonce_params_req_t
+ tcg_pts_attr_dh_nonce_params_req_t;
+
+#include "tcg_attr.h"
+#include "pa_tnc/pa_tnc_attr.h"
+#include "pts/pts_dh_group.h"
+
+/**
+ * Class implementing the TCG PTS DH Nonce Parameters Request Attribute
+ */
+struct tcg_pts_attr_dh_nonce_params_req_t {
+
+ /**
+ * Public PA-TNC attribute interface
+ */
+ pa_tnc_attr_t pa_tnc_attribute;
+
+ /**
+ * Get Minimum nonce length
+ *
+ * @return Minimum acceptable length of nonce
+ */
+ u_int8_t (*get_min_nonce_len)(tcg_pts_attr_dh_nonce_params_req_t *this);
+
+ /**
+ * Get supported Diffie Hellman Groups
+ *
+ * @return Supported Diffie Hellman Groups
+ */
+ pts_dh_group_t (*get_dh_groups)(tcg_pts_attr_dh_nonce_params_req_t *this);
+};
+
+/**
+ * Creates an tcg_pts_attr_dh_nonce_params_req_t object
+ *
+ * @param min_nonce_len Minimum acceptable length of nonce
+ * @param dh_groups Initiator's supported DH groups
+ */
+pa_tnc_attr_t* tcg_pts_attr_dh_nonce_params_req_create(u_int8_t min_nonce_len,
+ pts_dh_group_t dh_groups);
+
+/**
+ * Creates an tcg_pts_attr_dh_nonce_params_req_t object from received data
+ *
+ * @param value unparsed attribute value
+ */
+pa_tnc_attr_t* tcg_pts_attr_dh_nonce_params_req_create_from_data(chunk_t value);
+
+#endif /** TCG_PTS_ATTR_DH_NONCE_PARAMS_REQ_H_ @}*/
diff --git a/src/libpts/tcg/tcg_pts_attr_dh_nonce_params_resp.c b/src/libpts/tcg/tcg_pts_attr_dh_nonce_params_resp.c
new file mode 100644
index 000000000..09bfa3aac
--- /dev/null
+++ b/src/libpts/tcg/tcg_pts_attr_dh_nonce_params_resp.c
@@ -0,0 +1,295 @@
+/*
+ * Copyright (C) 2011 Sansar Choinyambuu
+ * 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 "tcg_pts_attr_dh_nonce_params_resp.h"
+
+#include <pa_tnc/pa_tnc_msg.h>
+#include <bio/bio_writer.h>
+#include <bio/bio_reader.h>
+#include <debug.h>
+
+typedef struct private_tcg_pts_attr_dh_nonce_params_resp_t
+ private_tcg_pts_attr_dh_nonce_params_resp_t;
+
+/**
+ * PTS DH Nonce Parameters Response
+ * see section 3.8.2 of PTS Protocol: Binding to TNC IF-M Specification
+ *
+ * 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
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Reserved | Nonce Len |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Selected D-H Group | Hash Algorithm Set |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | D-H Responder Nonce ... |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | D-H Responder Public Value ... |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ */
+
+#define PTS_DH_NONCE_PARAMS_RESP_SIZE 16
+#define PTS_DH_NONCE_PARAMS_RESP_RESERVED 0x0000
+
+/**
+ * Private data of an tcg_pts_attr_dh_nonce_params_resp_t object.
+ */
+struct private_tcg_pts_attr_dh_nonce_params_resp_t {
+
+ /**
+ * Public members of tcg_pts_attr_dh_nonce_params_resp_t
+ */
+ tcg_pts_attr_dh_nonce_params_resp_t public;
+
+ /**
+ * Attribute vendor ID
+ */
+ pen_t vendor_id;
+
+ /**
+ * Attribute type
+ */
+ u_int32_t type;
+
+ /**
+ * Attribute value
+ */
+ chunk_t value;
+
+ /**
+ * Noskip flag
+ */
+ bool noskip_flag;
+
+ /**
+ * Selected Diffie Hellman group
+ */
+ pts_dh_group_t dh_group;
+
+ /**
+ * Supported Hashing Algorithms
+ */
+ pts_meas_algorithms_t hash_algo_set;
+
+ /**
+ * DH Responder Nonce
+ */
+ chunk_t responder_nonce;
+
+ /**
+ * DH Responder Public Value
+ */
+ chunk_t responder_value;
+
+ /**
+ * Reference count
+ */
+ refcount_t ref;
+};
+
+METHOD(pa_tnc_attr_t, get_vendor_id, pen_t,
+ private_tcg_pts_attr_dh_nonce_params_resp_t *this)
+{
+ return this->vendor_id;
+}
+
+METHOD(pa_tnc_attr_t, get_type, u_int32_t,
+ private_tcg_pts_attr_dh_nonce_params_resp_t *this)
+{
+ return this->type;
+}
+
+METHOD(pa_tnc_attr_t, get_value, chunk_t,
+ private_tcg_pts_attr_dh_nonce_params_resp_t *this)
+{
+ return this->value;
+}
+
+METHOD(pa_tnc_attr_t, get_noskip_flag, bool,
+ private_tcg_pts_attr_dh_nonce_params_resp_t *this)
+{
+ return this->noskip_flag;
+}
+
+METHOD(pa_tnc_attr_t, set_noskip_flag,void,
+ private_tcg_pts_attr_dh_nonce_params_resp_t *this, bool noskip)
+{
+ this->noskip_flag = noskip;
+}
+
+METHOD(pa_tnc_attr_t, build, void,
+ private_tcg_pts_attr_dh_nonce_params_resp_t *this)
+{
+ bio_writer_t *writer;
+
+ writer = bio_writer_create(PTS_DH_NONCE_PARAMS_RESP_SIZE);
+ writer->write_uint24(writer, PTS_DH_NONCE_PARAMS_RESP_RESERVED);
+ writer->write_uint8 (writer, this->responder_nonce.len);
+ writer->write_uint16(writer, this->dh_group);
+ writer->write_uint16(writer, this->hash_algo_set);
+ writer->write_data (writer, this->responder_nonce);
+ writer->write_data (writer, this->responder_value);
+
+ this->value = chunk_clone(writer->get_buf(writer));
+ writer->destroy(writer);
+}
+
+METHOD(pa_tnc_attr_t, process, status_t,
+ private_tcg_pts_attr_dh_nonce_params_resp_t *this, u_int32_t *offset)
+{
+ bio_reader_t *reader;
+ u_int32_t reserved;
+ u_int8_t nonce_len;
+ u_int16_t dh_group, hash_algo_set;
+
+ if (this->value.len < PTS_DH_NONCE_PARAMS_RESP_SIZE)
+ {
+ DBG1(DBG_TNC, "insufficient data for PTS DH Nonce Parameters Response");
+ *offset = 0;
+ return FAILED;
+ }
+ reader = bio_reader_create(this->value);
+ reader->read_uint24(reader, &reserved);
+ reader->read_uint8 (reader, &nonce_len);
+ reader->read_uint16(reader, &dh_group);
+ reader->read_uint16(reader, &hash_algo_set);
+ reader->read_data(reader, nonce_len, &this->responder_nonce);
+ reader->read_data(reader, reader->remaining(reader), &this->responder_value);
+ this->dh_group = dh_group;
+ this->hash_algo_set = hash_algo_set;
+ this->responder_nonce = chunk_clone(this->responder_nonce);
+ this->responder_value = chunk_clone(this->responder_value);
+ reader->destroy(reader);
+
+ return SUCCESS;
+}
+
+METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*,
+ private_tcg_pts_attr_dh_nonce_params_resp_t *this)
+{
+ ref_get(&this->ref);
+ return &this->public.pa_tnc_attribute;
+}
+
+METHOD(pa_tnc_attr_t, destroy, void,
+ private_tcg_pts_attr_dh_nonce_params_resp_t *this)
+{
+ if (ref_put(&this->ref))
+ {
+ free(this->value.ptr);
+ free(this->responder_nonce.ptr);
+ free(this->responder_value.ptr);
+ free(this);
+ }
+}
+
+METHOD(tcg_pts_attr_dh_nonce_params_resp_t, get_dh_group, pts_dh_group_t,
+ private_tcg_pts_attr_dh_nonce_params_resp_t *this)
+{
+ return this->dh_group;
+}
+
+METHOD(tcg_pts_attr_dh_nonce_params_resp_t, get_hash_algo_set,
+ pts_meas_algorithms_t, private_tcg_pts_attr_dh_nonce_params_resp_t *this)
+{
+ return this->hash_algo_set;
+}
+
+METHOD(tcg_pts_attr_dh_nonce_params_resp_t, get_responder_nonce, chunk_t,
+ private_tcg_pts_attr_dh_nonce_params_resp_t *this)
+{
+ return this->responder_nonce;
+}
+
+METHOD(tcg_pts_attr_dh_nonce_params_resp_t, get_responder_value, chunk_t,
+ private_tcg_pts_attr_dh_nonce_params_resp_t *this)
+{
+ return this->responder_value;
+}
+
+/**
+ * Described in header.
+ */
+pa_tnc_attr_t *tcg_pts_attr_dh_nonce_params_resp_create(pts_dh_group_t dh_group,
+ pts_meas_algorithms_t hash_algo_set,
+ chunk_t responder_nonce,
+ chunk_t responder_value)
+{
+ private_tcg_pts_attr_dh_nonce_params_resp_t *this;
+
+ INIT(this,
+ .public = {
+ .pa_tnc_attribute = {
+ .get_vendor_id = _get_vendor_id,
+ .get_type = _get_type,
+ .get_value = _get_value,
+ .get_noskip_flag = _get_noskip_flag,
+ .set_noskip_flag = _set_noskip_flag,
+ .build = _build,
+ .process = _process,
+ .get_ref = _get_ref,
+ .destroy = _destroy,
+ },
+ .get_dh_group = _get_dh_group,
+ .get_hash_algo_set = _get_hash_algo_set,
+ .get_responder_nonce = _get_responder_nonce,
+ .get_responder_value = _get_responder_value,
+ },
+ .vendor_id = PEN_TCG,
+ .type = TCG_PTS_DH_NONCE_PARAMS_RESP,
+ .dh_group = dh_group,
+ .hash_algo_set = hash_algo_set,
+ .responder_nonce = chunk_clone(responder_nonce),
+ .responder_value = responder_value,
+ .ref = 1,
+ );
+
+ return &this->public.pa_tnc_attribute;
+}
+
+/**
+ * Described in header.
+ */
+pa_tnc_attr_t *tcg_pts_attr_dh_nonce_params_resp_create_from_data(chunk_t value)
+{
+ private_tcg_pts_attr_dh_nonce_params_resp_t *this;
+
+ INIT(this,
+ .public = {
+ .pa_tnc_attribute = {
+ .get_vendor_id = _get_vendor_id,
+ .get_type = _get_type,
+ .get_value = _get_value,
+ .get_noskip_flag = _get_noskip_flag,
+ .set_noskip_flag = _set_noskip_flag,
+ .build = _build,
+ .process = _process,
+ .get_ref = _get_ref,
+ .destroy = _destroy,
+ },
+ .get_dh_group = _get_dh_group,
+ .get_hash_algo_set = _get_hash_algo_set,
+ .get_responder_nonce = _get_responder_nonce,
+ .get_responder_value = _get_responder_value,
+ },
+ .vendor_id = PEN_TCG,
+ .type = TCG_PTS_DH_NONCE_PARAMS_RESP,
+ .value = chunk_clone(value),
+ .ref = 1,
+ );
+
+ return &this->public.pa_tnc_attribute;
+}
diff --git a/src/libpts/tcg/tcg_pts_attr_dh_nonce_params_resp.h b/src/libpts/tcg/tcg_pts_attr_dh_nonce_params_resp.h
new file mode 100644
index 000000000..d2141f8b9
--- /dev/null
+++ b/src/libpts/tcg/tcg_pts_attr_dh_nonce_params_resp.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2011 Sansar Choinyambuu
+ * 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 tcg_pts_attr_dh_nonce_params_resp tcg_pts_attr_dh_nonce_params_resp
+ * @{ @ingroup tcg_pts_attr_dh_nonce_params_resp
+ */
+
+#ifndef TCG_PTS_ATTR_DH_NONCE_PARAMS_RESP_H_
+#define TCG_PTS_ATTR_DH_NONCE_PARAMS_RESP_H_
+
+typedef struct tcg_pts_attr_dh_nonce_params_resp_t
+ tcg_pts_attr_dh_nonce_params_resp_t;
+
+#include "tcg_attr.h"
+#include "pa_tnc/pa_tnc_attr.h"
+#include "pts/pts_dh_group.h"
+#include "pts/pts_meas_algo.h"
+
+/**
+ * Class implementing the TCG PTS DH Nonce Parameters Response Attribute
+ */
+struct tcg_pts_attr_dh_nonce_params_resp_t {
+
+ /**
+ * Public PA-TNC attribute interface
+ */
+ pa_tnc_attr_t pa_tnc_attribute;
+
+ /**
+ * Get selected Diffie Hellman Group
+ *
+ * @return Selected Diffie Hellman Group
+ */
+ pts_dh_group_t (*get_dh_group)(tcg_pts_attr_dh_nonce_params_resp_t *this);
+
+ /**
+ * Get supported hash algorithms
+ *
+ * @return Hash algorithm set
+ */
+ pts_meas_algorithms_t (*get_hash_algo_set)(
+ tcg_pts_attr_dh_nonce_params_resp_t *this);
+
+ /**
+ * Get DH Responder Nonce
+ *
+ * @return DH Responder Nonce
+ */
+ chunk_t (*get_responder_nonce)(tcg_pts_attr_dh_nonce_params_resp_t *this);
+
+ /**
+ * Get DH Responder Public Value
+ *
+ * @return DH Responder Public Value
+ */
+ chunk_t (*get_responder_value)(tcg_pts_attr_dh_nonce_params_resp_t *this);
+
+};
+
+/**
+ * Creates an tcg_pts_attr_dh_nonce_params_resp_t object
+ *
+ * @param dh_group Selected DH group
+ * @param hash_algo_set Set of supported hash algorithms
+ * @param responder_nonce DH Responder Nonce
+ * @param responder_pub_val DH Responder Public value
+ */
+pa_tnc_attr_t* tcg_pts_attr_dh_nonce_params_resp_create(pts_dh_group_t dh_group,
+ pts_meas_algorithms_t hash_algo_set,
+ chunk_t responder_nonce,
+ chunk_t responder_value);
+
+/**
+ * Creates an tcg_pts_attr_dh_nonce_params_resp_t object from received data
+ *
+ * @param value unparsed attribute value
+ */
+pa_tnc_attr_t* tcg_pts_attr_dh_nonce_params_resp_create_from_data(chunk_t value);
+
+#endif /** TCG_PTS_ATTR_DH_NONCE_PARAMS_RESP_H_ @}*/
diff --git a/src/libpts/tcg/tcg_pts_attr_file_meas.c b/src/libpts/tcg/tcg_pts_attr_file_meas.c
index fe559d004..737da65c1 100644
--- a/src/libpts/tcg/tcg_pts_attr_file_meas.c
+++ b/src/libpts/tcg/tcg_pts_attr_file_meas.c
@@ -88,6 +88,10 @@ struct private_tcg_pts_attr_file_meas_t {
*/
pts_file_meas_t *measurements;
+ /**
+ * Reference count
+ */
+ refcount_t ref;
};
METHOD(pa_tnc_attr_t, get_vendor_id, pen_t,
@@ -133,11 +137,9 @@ METHOD(pa_tnc_attr_t, build, void,
number_of_files = this->measurements->get_file_count(this->measurements);
request_id = this->measurements->get_request_id(this->measurements);
- writer = bio_writer_create(PTS_FILE_MEAS_SIZE);
- /* Write the 64 bit integer as two 32 bit parts */
- writer->write_uint32(writer, number_of_files >> 32);
- writer->write_uint32(writer, number_of_files & 0xffffffff);
+ writer = bio_writer_create(PTS_FILE_MEAS_SIZE);
+ writer->write_uint64(writer, number_of_files);
writer->write_uint16(writer, request_id);
enumerator = this->measurements->create_enumerator(this->measurements);
@@ -168,8 +170,7 @@ METHOD(pa_tnc_attr_t, process, status_t,
private_tcg_pts_attr_file_meas_t *this, u_int32_t *offset)
{
bio_reader_t *reader;
- int count;
- u_int32_t number_of_files;
+ u_int64_t number_of_files;
u_int16_t request_id, meas_len, filename_len;
size_t len;
chunk_t measurement, filename;
@@ -182,18 +183,15 @@ METHOD(pa_tnc_attr_t, process, status_t,
*offset = 0;
return FAILED;
}
- reader = bio_reader_create(this->value);
- reader->read_uint32(reader, &number_of_files);
- count = (sizeof(count) > 4) ? number_of_files << 32 : 0;
- reader->read_uint32(reader, &number_of_files);
- count += number_of_files;
+ reader = bio_reader_create(this->value);
+ reader->read_uint64(reader, &number_of_files);
reader->read_uint16(reader, &request_id);
reader->read_uint16(reader, &meas_len);
this->measurements = pts_file_meas_create(request_id);
- while (count--)
+ while (number_of_files--)
{
if (!reader->read_data(reader, meas_len, &measurement))
{
@@ -223,12 +221,21 @@ end:
return status;
}
+METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*,
+ private_tcg_pts_attr_file_meas_t *this)
+{
+ ref_get(&this->ref);
+ return &this->public.pa_tnc_attribute;
+}
METHOD(pa_tnc_attr_t, destroy, void,
private_tcg_pts_attr_file_meas_t *this)
{
- this->measurements->destroy(this->measurements);
- free(this->value.ptr);
- free(this);
+ if (ref_put(&this->ref))
+ {
+ this->measurements->destroy(this->measurements);
+ free(this->value.ptr);
+ free(this);
+ }
}
METHOD(tcg_pts_attr_file_meas_t, get_measurements, pts_file_meas_t*,
@@ -254,6 +261,7 @@ pa_tnc_attr_t *tcg_pts_attr_file_meas_create(pts_file_meas_t *measurements)
.set_noskip_flag = _set_noskip_flag,
.build = _build,
.process = _process,
+ .get_ref = _get_ref,
.destroy = _destroy,
},
.get_measurements = _get_measurements,
@@ -261,6 +269,7 @@ pa_tnc_attr_t *tcg_pts_attr_file_meas_create(pts_file_meas_t *measurements)
.vendor_id = PEN_TCG,
.type = TCG_PTS_FILE_MEAS,
.measurements = measurements,
+ .ref = 1,
);
return &this->public.pa_tnc_attribute;
@@ -284,6 +293,7 @@ pa_tnc_attr_t *tcg_pts_attr_file_meas_create_from_data(chunk_t data)
.set_noskip_flag = _set_noskip_flag,
.build = _build,
.process = _process,
+ .get_ref = _get_ref,
.destroy = _destroy,
},
.get_measurements = _get_measurements,
@@ -291,6 +301,7 @@ pa_tnc_attr_t *tcg_pts_attr_file_meas_create_from_data(chunk_t data)
.vendor_id = PEN_TCG,
.type = TCG_PTS_FILE_MEAS,
.value = chunk_clone(data),
+ .ref = 1,
);
return &this->public.pa_tnc_attribute;
diff --git a/src/libpts/tcg/tcg_pts_attr_gen_attest_evid.c b/src/libpts/tcg/tcg_pts_attr_gen_attest_evid.c
index 4d8aa7bee..054285c4e 100644
--- a/src/libpts/tcg/tcg_pts_attr_gen_attest_evid.c
+++ b/src/libpts/tcg/tcg_pts_attr_gen_attest_evid.c
@@ -20,7 +20,8 @@
#include <bio/bio_reader.h>
#include <debug.h>
-typedef struct private_tcg_pts_attr_gen_attest_evid_t private_tcg_pts_attr_gen_attest_evid_t;
+typedef struct private_tcg_pts_attr_gen_attest_evid_t
+ private_tcg_pts_attr_gen_attest_evid_t;
/**
* Generate Attestation Evidence
@@ -67,6 +68,11 @@ struct private_tcg_pts_attr_gen_attest_evid_t {
* Noskip flag
*/
bool noskip_flag;
+
+ /**
+ * Reference count
+ */
+ refcount_t ref;
};
METHOD(pa_tnc_attr_t, get_vendor_id, pen_t,
@@ -130,11 +136,21 @@ METHOD(pa_tnc_attr_t, process, status_t,
return SUCCESS;
}
+METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*,
+ private_tcg_pts_attr_gen_attest_evid_t *this)
+{
+ ref_get(&this->ref);
+ return &this->public.pa_tnc_attribute;
+}
+
METHOD(pa_tnc_attr_t, destroy, void,
private_tcg_pts_attr_gen_attest_evid_t *this)
{
- free(this->value.ptr);
- free(this);
+ if (ref_put(&this->ref))
+ {
+ free(this->value.ptr);
+ free(this);
+ }
}
/**
@@ -154,11 +170,13 @@ pa_tnc_attr_t *tcg_pts_attr_gen_attest_evid_create()
.set_noskip_flag = _set_noskip_flag,
.build = _build,
.process = _process,
+ .get_ref = _get_ref,
.destroy = _destroy,
},
},
.vendor_id = PEN_TCG,
.type = TCG_PTS_GEN_ATTEST_EVID,
+ .ref = 1,
);
return &this->public.pa_tnc_attribute;
@@ -182,12 +200,14 @@ pa_tnc_attr_t *tcg_pts_attr_gen_attest_evid_create_from_data(chunk_t data)
.set_noskip_flag = _set_noskip_flag,
.build = _build,
.process = _process,
+ .get_ref = _get_ref,
.destroy = _destroy,
},
},
.vendor_id = PEN_TCG,
.type = TCG_PTS_GEN_ATTEST_EVID,
.value = chunk_clone(data),
+ .ref = 1,
);
return &this->public.pa_tnc_attribute;
diff --git a/src/libpts/tcg/tcg_pts_attr_get_aik.c b/src/libpts/tcg/tcg_pts_attr_get_aik.c
index 727c7a211..1875375a4 100644
--- a/src/libpts/tcg/tcg_pts_attr_get_aik.c
+++ b/src/libpts/tcg/tcg_pts_attr_get_aik.c
@@ -65,6 +65,11 @@ struct private_tcg_pts_attr_get_aik_t {
* Noskip flag
*/
bool noskip_flag;
+
+ /**
+ * Reference count
+ */
+ refcount_t ref;
};
METHOD(pa_tnc_attr_t, get_vendor_id, pen_t,
@@ -128,11 +133,21 @@ METHOD(pa_tnc_attr_t, process, status_t,
return SUCCESS;
}
+METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*,
+ private_tcg_pts_attr_get_aik_t *this)
+{
+ ref_get(&this->ref);
+ return &this->public.pa_tnc_attribute;
+}
+
METHOD(pa_tnc_attr_t, destroy, void,
private_tcg_pts_attr_get_aik_t *this)
{
- free(this->value.ptr);
- free(this);
+ if (ref_put(&this->ref))
+ {
+ free(this->value.ptr);
+ free(this);
+ }
}
/**
@@ -152,11 +167,13 @@ pa_tnc_attr_t *tcg_pts_attr_get_aik_create()
.set_noskip_flag = _set_noskip_flag,
.build = _build,
.process = _process,
+ .get_ref = _get_ref,
.destroy = _destroy,
},
},
.vendor_id = PEN_TCG,
.type = TCG_PTS_GET_AIK,
+ .ref = 1,
);
return &this->public.pa_tnc_attribute;
@@ -180,12 +197,14 @@ pa_tnc_attr_t *tcg_pts_attr_get_aik_create_from_data(chunk_t data)
.set_noskip_flag = _set_noskip_flag,
.build = _build,
.process = _process,
+ .get_ref = _get_ref,
.destroy = _destroy,
},
},
.vendor_id = PEN_TCG,
.type = TCG_PTS_GET_AIK,
.value = chunk_clone(data),
+ .ref = 1,
);
return &this->public.pa_tnc_attribute;
diff --git a/src/libpts/tcg/tcg_pts_attr_get_tpm_version_info.c b/src/libpts/tcg/tcg_pts_attr_get_tpm_version_info.c
index 51cb99a8e..cb6834ca5 100644
--- a/src/libpts/tcg/tcg_pts_attr_get_tpm_version_info.c
+++ b/src/libpts/tcg/tcg_pts_attr_get_tpm_version_info.c
@@ -20,7 +20,8 @@
#include <bio/bio_reader.h>
#include <debug.h>
-typedef struct private_tcg_pts_attr_get_tpm_version_info_t private_tcg_pts_attr_get_tpm_version_info_t;
+typedef struct private_tcg_pts_attr_get_tpm_version_info_t
+ private_tcg_pts_attr_get_tpm_version_info_t;
/**
* Get TPM Version Information
@@ -67,6 +68,11 @@ struct private_tcg_pts_attr_get_tpm_version_info_t {
* Noskip flag
*/
bool noskip_flag;
+
+ /**
+ * Reference count
+ */
+ refcount_t ref;
};
METHOD(pa_tnc_attr_t, get_vendor_id, pen_t,
@@ -130,11 +136,21 @@ METHOD(pa_tnc_attr_t, process, status_t,
return SUCCESS;
}
+METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*,
+ private_tcg_pts_attr_get_tpm_version_info_t *this)
+{
+ ref_get(&this->ref);
+ return &this->public.pa_tnc_attribute;
+}
+
METHOD(pa_tnc_attr_t, destroy, void,
private_tcg_pts_attr_get_tpm_version_info_t *this)
{
- free(this->value.ptr);
- free(this);
+ if (ref_put(&this->ref))
+ {
+ free(this->value.ptr);
+ free(this);
+ }
}
/**
@@ -154,11 +170,13 @@ pa_tnc_attr_t *tcg_pts_attr_get_tpm_version_info_create()
.set_noskip_flag = _set_noskip_flag,
.build = _build,
.process = _process,
+ .get_ref = _get_ref,
.destroy = _destroy,
},
},
.vendor_id = PEN_TCG,
.type = TCG_PTS_GET_TPM_VERSION_INFO,
+ .ref = 1,
);
return &this->public.pa_tnc_attribute;
@@ -182,12 +200,14 @@ pa_tnc_attr_t *tcg_pts_attr_get_tpm_version_info_create_from_data(chunk_t data)
.set_noskip_flag = _set_noskip_flag,
.build = _build,
.process = _process,
+ .get_ref = _get_ref,
.destroy = _destroy,
},
},
.vendor_id = PEN_TCG,
.type = TCG_PTS_GET_TPM_VERSION_INFO,
.value = chunk_clone(data),
+ .ref = 1,
);
return &this->public.pa_tnc_attribute;
diff --git a/src/libpts/tcg/tcg_pts_attr_get_tpm_version_info.h b/src/libpts/tcg/tcg_pts_attr_get_tpm_version_info.h
index 255efaafa..1b693402a 100644
--- a/src/libpts/tcg/tcg_pts_attr_get_tpm_version_info.h
+++ b/src/libpts/tcg/tcg_pts_attr_get_tpm_version_info.h
@@ -21,7 +21,8 @@
#ifndef TCG_PTS_ATTR_GET_TPM_VERSION_INFO_H_
#define TCG_PTS_ATTR_GET_TPM_VERSION_INFO_H_
-typedef struct tcg_pts_attr_get_tpm_version_info_t tcg_pts_attr_get_tpm_version_info_t;
+typedef struct tcg_pts_attr_get_tpm_version_info_t
+ tcg_pts_attr_get_tpm_version_info_t;
#include "tcg_attr.h"
#include "pa_tnc/pa_tnc_attr.h"
diff --git a/src/libpts/tcg/tcg_pts_attr_meas_algo.c b/src/libpts/tcg/tcg_pts_attr_meas_algo.c
index dffc15320..ed520e3cd 100644
--- a/src/libpts/tcg/tcg_pts_attr_meas_algo.c
+++ b/src/libpts/tcg/tcg_pts_attr_meas_algo.c
@@ -72,6 +72,10 @@ struct private_tcg_pts_attr_meas_algo_t {
*/
pts_meas_algorithms_t algorithms;
+ /**
+ * Reference count
+ */
+ refcount_t ref;
};
METHOD(pa_tnc_attr_t, get_vendor_id, pen_t,
@@ -140,8 +144,18 @@ METHOD(pa_tnc_attr_t, process, status_t,
METHOD(pa_tnc_attr_t, destroy, void,
private_tcg_pts_attr_meas_algo_t *this)
{
- free(this->value.ptr);
- free(this);
+ if (ref_put(&this->ref))
+ {
+ free(this->value.ptr);
+ free(this);
+ }
+}
+
+METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*,
+ private_tcg_pts_attr_meas_algo_t *this)
+{
+ ref_get(&this->ref);
+ return &this->public.pa_tnc_attribute;
}
METHOD(tcg_pts_attr_meas_algo_t, get_algorithms, pts_meas_algorithms_t,
@@ -168,6 +182,7 @@ pa_tnc_attr_t *tcg_pts_attr_meas_algo_create(pts_meas_algorithms_t algorithms,
.set_noskip_flag = _set_noskip_flag,
.build = _build,
.process = _process,
+ .get_ref = _get_ref,
.destroy = _destroy,
},
.get_algorithms = _get_algorithms,
@@ -175,6 +190,7 @@ pa_tnc_attr_t *tcg_pts_attr_meas_algo_create(pts_meas_algorithms_t algorithms,
.vendor_id = PEN_TCG,
.type = selection ? TCG_PTS_MEAS_ALGO_SELECTION : TCG_PTS_MEAS_ALGO,
.algorithms = algorithms,
+ .ref = 1,
);
return &this->public.pa_tnc_attribute;
@@ -199,6 +215,7 @@ pa_tnc_attr_t *tcg_pts_attr_meas_algo_create_from_data(chunk_t data,
.set_noskip_flag = _set_noskip_flag,
.build = _build,
.process = _process,
+ .get_ref = _get_ref,
.destroy = _destroy,
},
.get_algorithms = _get_algorithms,
@@ -206,6 +223,7 @@ pa_tnc_attr_t *tcg_pts_attr_meas_algo_create_from_data(chunk_t data,
.vendor_id = PEN_TCG,
.type = selection ? TCG_PTS_MEAS_ALGO_SELECTION : TCG_PTS_MEAS_ALGO,
.value = chunk_clone(data),
+ .ref = 1,
);
return &this->public.pa_tnc_attribute;
diff --git a/src/libpts/tcg/tcg_pts_attr_proto_caps.c b/src/libpts/tcg/tcg_pts_attr_proto_caps.c
index 6d078905d..055c750ff 100644
--- a/src/libpts/tcg/tcg_pts_attr_proto_caps.c
+++ b/src/libpts/tcg/tcg_pts_attr_proto_caps.c
@@ -72,6 +72,10 @@ struct private_tcg_pts_attr_proto_caps_t {
*/
pts_proto_caps_flag_t flags;
+ /**
+ * Reference count
+ */
+ refcount_t ref;
};
METHOD(pa_tnc_attr_t, get_vendor_id, pen_t,
@@ -141,8 +145,18 @@ METHOD(pa_tnc_attr_t, process, status_t,
METHOD(pa_tnc_attr_t, destroy, void,
private_tcg_pts_attr_proto_caps_t *this)
{
- free(this->value.ptr);
- free(this);
+ if (ref_put(&this->ref))
+ {
+ free(this->value.ptr);
+ free(this);
+ }
+}
+
+METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*,
+ private_tcg_pts_attr_proto_caps_t *this)
+{
+ ref_get(&this->ref);
+ return &this->public.pa_tnc_attribute;
}
METHOD(tcg_pts_attr_proto_caps_t, get_flags, pts_proto_caps_flag_t,
@@ -169,6 +183,7 @@ pa_tnc_attr_t *tcg_pts_attr_proto_caps_create(pts_proto_caps_flag_t flags,
.set_noskip_flag = _set_noskip_flag,
.build = _build,
.process = _process,
+ .get_ref = _get_ref,
.destroy = _destroy,
},
.get_flags = _get_flags,
@@ -176,6 +191,7 @@ pa_tnc_attr_t *tcg_pts_attr_proto_caps_create(pts_proto_caps_flag_t flags,
.vendor_id = PEN_TCG,
.type = request ? TCG_PTS_REQ_PROTO_CAPS : TCG_PTS_PROTO_CAPS,
.flags = flags,
+ .ref = 1,
);
return &this->public.pa_tnc_attribute;
@@ -199,6 +215,7 @@ pa_tnc_attr_t *tcg_pts_attr_proto_caps_create_from_data(chunk_t data,
.set_noskip_flag = _set_noskip_flag,
.build = _build,
.process = _process,
+ .get_ref = _get_ref,
.destroy = _destroy,
},
.get_flags = _get_flags,
@@ -206,6 +223,7 @@ pa_tnc_attr_t *tcg_pts_attr_proto_caps_create_from_data(chunk_t data,
.vendor_id = PEN_TCG,
.type = request ? TCG_PTS_REQ_PROTO_CAPS : TCG_PTS_PROTO_CAPS,
.value = chunk_clone(data),
+ .ref = 1,
);
return &this->public.pa_tnc_attribute;
diff --git a/src/libpts/tcg/tcg_pts_attr_req_file_meas.c b/src/libpts/tcg/tcg_pts_attr_req_file_meas.c
index 68ecfa8f1..17781f745 100644
--- a/src/libpts/tcg/tcg_pts_attr_req_file_meas.c
+++ b/src/libpts/tcg/tcg_pts_attr_req_file_meas.c
@@ -93,6 +93,10 @@ struct private_tcg_pts_attr_req_file_meas_t {
*/
char *pathname;
+ /**
+ * Reference count
+ */
+ refcount_t ref;
};
METHOD(pa_tnc_attr_t, get_vendor_id, pen_t,
@@ -181,12 +185,22 @@ METHOD(pa_tnc_attr_t, process, status_t,
return SUCCESS;
}
+METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*,
+ private_tcg_pts_attr_req_file_meas_t *this)
+{
+ ref_get(&this->ref);
+ return &this->public.pa_tnc_attribute;
+}
+
METHOD(pa_tnc_attr_t, destroy, void,
private_tcg_pts_attr_req_file_meas_t *this)
{
- free(this->pathname);
- free(this->value.ptr);
- free(this);
+ if (ref_put(&this->ref))
+ {
+ free(this->pathname);
+ free(this->value.ptr);
+ free(this);
+ }
}
METHOD(tcg_pts_attr_req_file_meas_t, get_directory_flag, bool,
@@ -233,6 +247,7 @@ pa_tnc_attr_t *tcg_pts_attr_req_file_meas_create(bool directory_flag,
.set_noskip_flag = _set_noskip_flag,
.build = _build,
.process = _process,
+ .get_ref = _get_ref,
.destroy = _destroy,
},
.get_directory_flag = _get_directory_flag,
@@ -246,6 +261,7 @@ pa_tnc_attr_t *tcg_pts_attr_req_file_meas_create(bool directory_flag,
.request_id = request_id,
.delimiter = delimiter,
.pathname = strdup(pathname),
+ .ref = 1,
);
return &this->public.pa_tnc_attribute;
@@ -269,6 +285,7 @@ pa_tnc_attr_t *tcg_pts_attr_req_file_meas_create_from_data(chunk_t data)
.set_noskip_flag = _set_noskip_flag,
.build = _build,
.process = _process,
+ .get_ref = _get_ref,
.destroy = _destroy,
},
.get_directory_flag = _get_directory_flag,
@@ -279,6 +296,7 @@ pa_tnc_attr_t *tcg_pts_attr_req_file_meas_create_from_data(chunk_t data)
.vendor_id = PEN_TCG,
.type = TCG_PTS_REQ_FILE_MEAS,
.value = chunk_clone(data),
+ .ref = 1,
);
return &this->public.pa_tnc_attribute;
diff --git a/src/libpts/tcg/tcg_pts_attr_req_file_meta.c b/src/libpts/tcg/tcg_pts_attr_req_file_meta.c
index f42903e03..bef6b5db6 100644
--- a/src/libpts/tcg/tcg_pts_attr_req_file_meta.c
+++ b/src/libpts/tcg/tcg_pts_attr_req_file_meta.c
@@ -86,6 +86,10 @@ struct private_tcg_pts_attr_req_file_meta_t {
*/
char *pathname;
+ /**
+ * Reference count
+ */
+ refcount_t ref;
};
METHOD(pa_tnc_attr_t, get_vendor_id, pen_t,
@@ -177,9 +181,19 @@ METHOD(pa_tnc_attr_t, process, status_t,
METHOD(pa_tnc_attr_t, destroy, void,
private_tcg_pts_attr_req_file_meta_t *this)
{
- free(this->pathname);
- free(this->value.ptr);
- free(this);
+ if (ref_put(&this->ref))
+ {
+ free(this->pathname);
+ free(this->value.ptr);
+ free(this);
+ }
+}
+
+METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*,
+ private_tcg_pts_attr_req_file_meta_t *this)
+{
+ ref_get(&this->ref);
+ return &this->public.pa_tnc_attribute;
}
METHOD(tcg_pts_attr_req_file_meta_t, get_directory_flag, bool,
@@ -188,7 +202,7 @@ METHOD(tcg_pts_attr_req_file_meta_t, get_directory_flag, bool,
return this->directory_flag;
}
-METHOD(tcg_pts_attr_req_file_meta_t, get_delimiter, u_int32_t,
+METHOD(tcg_pts_attr_req_file_meta_t, get_delimiter, u_int8_t,
private_tcg_pts_attr_req_file_meta_t *this)
{
return this->delimiter;
@@ -203,7 +217,7 @@ METHOD(tcg_pts_attr_req_file_meta_t, get_pathname, char*,
/**
* Described in header.
*/
-pa_tnc_attr_t *tcg_pts_attr_req_file_meas_create(bool directory_flag,
+pa_tnc_attr_t *tcg_pts_attr_req_file_meta_create(bool directory_flag,
u_int8_t delimiter,
char *pathname)
{
@@ -219,6 +233,7 @@ pa_tnc_attr_t *tcg_pts_attr_req_file_meas_create(bool directory_flag,
.set_noskip_flag = _set_noskip_flag,
.build = _build,
.process = _process,
+ .get_ref = _get_ref,
.destroy = _destroy,
},
.get_directory_flag = _get_directory_flag,
@@ -230,6 +245,7 @@ pa_tnc_attr_t *tcg_pts_attr_req_file_meas_create(bool directory_flag,
.directory_flag = directory_flag,
.delimiter = delimiter,
.pathname = strdup(pathname),
+ .ref = 1,
);
return &this->public.pa_tnc_attribute;
@@ -239,7 +255,7 @@ pa_tnc_attr_t *tcg_pts_attr_req_file_meas_create(bool directory_flag,
/**
* Described in header.
*/
-pa_tnc_attr_t *tcg_pts_attr_req_file_meas_create_from_data(chunk_t data)
+pa_tnc_attr_t *tcg_pts_attr_req_file_meta_create_from_data(chunk_t data)
{
private_tcg_pts_attr_req_file_meta_t *this;
@@ -253,6 +269,7 @@ pa_tnc_attr_t *tcg_pts_attr_req_file_meas_create_from_data(chunk_t data)
.set_noskip_flag = _set_noskip_flag,
.build = _build,
.process = _process,
+ .get_ref = _get_ref,
.destroy = _destroy,
},
.get_directory_flag = _get_directory_flag,
@@ -262,6 +279,7 @@ pa_tnc_attr_t *tcg_pts_attr_req_file_meas_create_from_data(chunk_t data)
.vendor_id = PEN_TCG,
.type = TCG_PTS_REQ_FILE_META,
.value = chunk_clone(data),
+ .ref = 1,
);
return &this->public.pa_tnc_attribute;
diff --git a/src/libpts/tcg/tcg_pts_attr_req_func_comp_evid.c b/src/libpts/tcg/tcg_pts_attr_req_func_comp_evid.c
new file mode 100644
index 000000000..bfd108b9f
--- /dev/null
+++ b/src/libpts/tcg/tcg_pts_attr_req_func_comp_evid.c
@@ -0,0 +1,378 @@
+/*
+ * Copyright (C) 2011 Sansar Choinyambuu
+ * 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 "tcg_pts_attr_req_func_comp_evid.h"
+
+#include <pa_tnc/pa_tnc_msg.h>
+#include <bio/bio_writer.h>
+#include <bio/bio_reader.h>
+#include <utils/linked_list.h>
+#include <debug.h>
+
+typedef struct private_tcg_pts_attr_req_func_comp_evid_t private_tcg_pts_attr_req_func_comp_evid_t;
+
+/**
+ * Request Functional Component Evidence
+ * see section 3.14.1 of PTS Protocol: Binding to TNC IF-M Specification
+ *
+ * 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
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Flags | Sub-component Depth (for Component #1) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Component Functional Name #1 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Component Functional Name #1 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | ........ |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Flags | Sub-component Depth (for Component #N) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Component Functional Name #N |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Component Functional Name #N |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+/**
+ * Component Functional Name Structure
+ * (see section 5.1 of PTS Protocol: Binding to TNC IF-M Specification)
+ *
+ * 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
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Component Functional Name Vendor ID |Fam| Qualifier |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Component Functional Name |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+#define PTS_REQ_FUNC_COMP_EVID_SIZE 12
+#define PTS_REQ_FUNC_COMP_FAMILY_MASK 0xC0
+
+/**
+ * Private data of an tcg_pts_attr_req_func_comp_evid_t object.
+ */
+struct private_tcg_pts_attr_req_func_comp_evid_t {
+
+ /**
+ * Public members of tcg_pts_attr_req_func_comp_evid_t
+ */
+ tcg_pts_attr_req_func_comp_evid_t public;
+
+ /**
+ * Attribute vendor ID
+ */
+ pen_t vendor_id;
+
+ /**
+ * Attribute type
+ */
+ u_int32_t type;
+
+ /**
+ * Attribute value
+ */
+ chunk_t value;
+
+ /**
+ * Noskip flag
+ */
+ bool noskip_flag;
+
+ /**
+ * List of Functional Components
+ */
+ linked_list_t *list;
+
+ /**
+ * Reference count
+ */
+ refcount_t ref;
+};
+
+typedef struct entry_t entry_t;
+
+/**
+ * Functional component entry
+ */
+struct entry_t {
+ u_int8_t flags;
+ u_int32_t depth;
+ pts_comp_func_name_t *name;
+};
+
+/**
+ * Enumerate functional component entries
+ */
+static bool entry_filter(void *null, entry_t **entry, u_int8_t *flags,
+ void *i2, u_int32_t *depth, void *i3,
+ pts_comp_func_name_t **name)
+{
+ *flags = (*entry)->flags;
+ *depth = (*entry)->depth;
+ *name = (*entry)->name;
+
+ return TRUE;
+}
+
+/**
+ * Free an entry_t object
+ */
+static void free_entry(entry_t *this)
+{
+ if (this)
+ {
+ this->name->destroy(this->name);
+ free(this);
+ }
+}
+
+METHOD(pa_tnc_attr_t, get_vendor_id, pen_t,
+ private_tcg_pts_attr_req_func_comp_evid_t *this)
+{
+ return this->vendor_id;
+}
+
+METHOD(pa_tnc_attr_t, get_type, u_int32_t,
+ private_tcg_pts_attr_req_func_comp_evid_t *this)
+{
+ return this->type;
+}
+
+METHOD(pa_tnc_attr_t, get_value, chunk_t,
+ private_tcg_pts_attr_req_func_comp_evid_t *this)
+{
+ return this->value;
+}
+
+METHOD(pa_tnc_attr_t, get_noskip_flag, bool,
+ private_tcg_pts_attr_req_func_comp_evid_t *this)
+{
+ return this->noskip_flag;
+}
+
+METHOD(pa_tnc_attr_t, set_noskip_flag,void,
+ private_tcg_pts_attr_req_func_comp_evid_t *this, bool noskip)
+{
+ this->noskip_flag = noskip;
+}
+
+METHOD(pa_tnc_attr_t, build, void,
+ private_tcg_pts_attr_req_func_comp_evid_t *this)
+{
+ bio_writer_t *writer;
+ enumerator_t *enumerator;
+ entry_t *entry;
+
+ writer = bio_writer_create(PTS_REQ_FUNC_COMP_EVID_SIZE);
+
+ enumerator = this->list->create_enumerator(this->list);
+ while (enumerator->enumerate(enumerator, &entry))
+ {
+ writer->write_uint8 (writer, entry->flags);
+ writer->write_uint24(writer, entry->depth);
+ writer->write_uint24(writer, entry->name->get_vendor_id(entry->name));
+ writer->write_uint8 (writer, entry->name->get_qualifier(entry->name));
+ writer->write_uint32(writer, entry->name->get_name(entry->name));
+ }
+ enumerator->destroy(enumerator);
+
+ this->value = chunk_clone(writer->get_buf(writer));
+ writer->destroy(writer);
+}
+
+METHOD(pa_tnc_attr_t, process, status_t,
+ private_tcg_pts_attr_req_func_comp_evid_t *this, u_int32_t *offset)
+{
+ bio_reader_t *reader;
+ u_int32_t depth, vendor_id, name;
+ u_int8_t flags, fam_and_qualifier, qualifier;
+ status_t status = FAILED;
+ entry_t *entry = NULL;
+
+ if (this->value.len < PTS_REQ_FUNC_COMP_EVID_SIZE)
+ {
+ DBG1(DBG_TNC, "insufficient data for Request Functional "
+ "Component Evidence");
+ *offset = 0;
+ return FAILED;
+ }
+ reader = bio_reader_create(this->value);
+
+ while (reader->remaining(reader))
+ {
+ if (!reader->read_uint8(reader, &flags))
+ {
+ DBG1(DBG_TNC, "insufficient data for PTS Request Functional "
+ "Component Evidence Flags");
+ goto end;
+ }
+ if (!reader->read_uint24(reader, &depth))
+ {
+ DBG1(DBG_TNC, "insufficient data for PTS Request Functional "
+ "Component Evidence Sub Component Depth");
+ goto end;
+ }
+ if (!reader->read_uint24(reader, &vendor_id))
+ {
+ DBG1(DBG_TNC, "insufficient data for PTS Request Functional "
+ "Component Evidence Component Name Vendor ID");
+ goto end;
+ }
+ if (!reader->read_uint8(reader, &fam_and_qualifier))
+ {
+ DBG1(DBG_TNC, "insufficient data for PTS Request Functional "
+ "Component Evidence Family and Qualifier");
+ goto end;
+ }
+ if (fam_and_qualifier & PTS_REQ_FUNC_COMP_FAMILY_MASK)
+ {
+ DBG1(DBG_TNC, "the Functional Name Encoding Family "
+ "is not Binary Enumeration");
+ goto end;
+ }
+ if (!reader->read_uint32(reader, &name))
+ {
+ DBG1(DBG_TNC, "insufficient data for PTS Request Functional "
+ "Component Evidence Component Functional Name");
+ goto end;
+ }
+ qualifier = fam_and_qualifier & ~PTS_REQ_FUNC_COMP_FAMILY_MASK;
+
+ entry = malloc_thing(entry_t);
+ entry->flags = flags;
+ entry->depth = depth;
+ entry->name = pts_comp_func_name_create(vendor_id, name, qualifier);
+
+ this->list->insert_last(this->list, entry);
+ }
+ status = SUCCESS;
+
+end:
+ reader->destroy(reader);
+ return status;
+}
+
+METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*,
+ private_tcg_pts_attr_req_func_comp_evid_t *this)
+{
+ ref_get(&this->ref);
+ return &this->public.pa_tnc_attribute;
+}
+
+METHOD(pa_tnc_attr_t, destroy, void,
+ private_tcg_pts_attr_req_func_comp_evid_t *this)
+{
+ if (ref_put(&this->ref))
+ {
+ this->list->destroy_function(this->list, (void *)free_entry);
+ free(this->value.ptr);
+ free(this);
+ }
+}
+
+METHOD(tcg_pts_attr_req_func_comp_evid_t, add_component, void,
+ private_tcg_pts_attr_req_func_comp_evid_t *this, u_int8_t flags,
+ u_int32_t depth, pts_comp_func_name_t *name)
+{
+ entry_t *entry;
+
+ entry = malloc_thing(entry_t);
+ entry->flags = flags;
+ entry->depth = depth;
+ entry->name = name;
+ this->list->insert_last(this->list, entry);
+}
+
+METHOD(tcg_pts_attr_req_func_comp_evid_t, get_count, int,
+ private_tcg_pts_attr_req_func_comp_evid_t *this)
+{
+ return this->list->get_count(this->list);
+}
+
+METHOD(tcg_pts_attr_req_func_comp_evid_t, create_enumerator, enumerator_t*,
+ private_tcg_pts_attr_req_func_comp_evid_t *this)
+{
+ return enumerator_create_filter(this->list->create_enumerator(this->list),
+ (void*)entry_filter, NULL, NULL);
+}
+
+/**
+ * Described in header.
+ */
+pa_tnc_attr_t *tcg_pts_attr_req_func_comp_evid_create(void)
+{
+ private_tcg_pts_attr_req_func_comp_evid_t *this;
+
+ INIT(this,
+ .public = {
+ .pa_tnc_attribute = {
+ .get_vendor_id = _get_vendor_id,
+ .get_type = _get_type,
+ .get_value = _get_value,
+ .get_noskip_flag = _get_noskip_flag,
+ .set_noskip_flag = _set_noskip_flag,
+ .build = _build,
+ .process = _process,
+ .get_ref = _get_ref,
+ .destroy = _destroy,
+ },
+ .add_component = _add_component,
+ .get_count = _get_count,
+ .create_enumerator = _create_enumerator,
+ },
+ .vendor_id = PEN_TCG,
+ .type = TCG_PTS_REQ_FUNC_COMP_EVID,
+ .list = linked_list_create(),
+ .ref = 1,
+ );
+
+ return &this->public.pa_tnc_attribute;
+}
+
+/**
+ * Described in header.
+ */
+pa_tnc_attr_t *tcg_pts_attr_req_func_comp_evid_create_from_data(chunk_t data)
+{
+ private_tcg_pts_attr_req_func_comp_evid_t *this;
+
+ INIT(this,
+ .public = {
+ .pa_tnc_attribute = {
+ .get_vendor_id = _get_vendor_id,
+ .get_type = _get_type,
+ .get_value = _get_value,
+ .get_noskip_flag = _get_noskip_flag,
+ .set_noskip_flag = _set_noskip_flag,
+ .build = _build,
+ .process = _process,
+ .get_ref = _get_ref,
+ .destroy = _destroy,
+ },
+ .add_component = _add_component,
+ .get_count = _get_count,
+ .create_enumerator = _create_enumerator,
+ },
+ .vendor_id = PEN_TCG,
+ .type = TCG_PTS_REQ_FUNC_COMP_EVID,
+ .list = linked_list_create(),
+ .value = chunk_clone(data),
+ .ref = 1,
+ );
+
+ return &this->public.pa_tnc_attribute;
+}
diff --git a/src/libpts/tcg/tcg_pts_attr_req_func_comp_evid.h b/src/libpts/tcg/tcg_pts_attr_req_func_comp_evid.h
new file mode 100644
index 000000000..031955aca
--- /dev/null
+++ b/src/libpts/tcg/tcg_pts_attr_req_func_comp_evid.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2011 Sansar Choinyambuu
+ * 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 tcg_pts_attr_req_func_comp_evid tcg_pts_attr_req_func_comp_evid
+ * @{ @ingroup tcg_pts_attr_req_func_comp_evid
+ */
+
+#ifndef TCG_PTS_ATTR_REQ_FUNC_COMP_EVID_H_
+#define TCG_PTS_ATTR_REQ_FUNC_COMP_EVID_H_
+
+typedef struct tcg_pts_attr_req_func_comp_evid_t tcg_pts_attr_req_func_comp_evid_t;
+
+#include "tcg_attr.h"
+#include "pts/components/pts_comp_func_name.h"
+#include "pa_tnc/pa_tnc_attr.h"
+
+/**
+ * Class implementing the TCG PTS Request Functional Component Evidence attribute
+ *
+ */
+struct tcg_pts_attr_req_func_comp_evid_t {
+
+ /**
+ * Public PA-TNC attribute interface
+ */
+ pa_tnc_attr_t pa_tnc_attribute;
+
+ /**
+ * Add a component to the Functional Component Evidence Request
+ *
+ * @param flags Component Evidence Request Flags
+ * @param depth Sub-component Depth
+ * @param name Functional Component Name
+ */
+ void (*add_component)(tcg_pts_attr_req_func_comp_evid_t *this,
+ u_int8_t flags, u_int32_t depth,
+ pts_comp_func_name_t *name);
+
+ /**
+ * Returns the number of Functional Component entries
+ *
+ * @return Number of entries
+ */
+ int (*get_count)(tcg_pts_attr_req_func_comp_evid_t *this);
+
+ /**
+ * Enumerator over Functional Component entries
+ *
+ * @return Entry enumerator
+ */
+ enumerator_t* (*create_enumerator)(tcg_pts_attr_req_func_comp_evid_t *this);
+
+};
+
+/**
+ * Creates a tcg_pts_attr_req_func_comp_evid_t object
+ */
+pa_tnc_attr_t* tcg_pts_attr_req_func_comp_evid_create(void);
+
+/**
+ * Creates a tcg_pts_attr_req_func_comp_evid_t object from received data
+ *
+ * @param value Unparsed attribute value
+ */
+pa_tnc_attr_t* tcg_pts_attr_req_func_comp_evid_create_from_data(chunk_t value);
+
+#endif /** TCG_PTS_ATTR_REQ_FUNC_COMP_EVID_H_ @}*/
diff --git a/src/libpts/tcg/tcg_pts_attr_req_funct_comp_evid.c b/src/libpts/tcg/tcg_pts_attr_req_funct_comp_evid.c
deleted file mode 100644
index 0f460580b..000000000
--- a/src/libpts/tcg/tcg_pts_attr_req_funct_comp_evid.c
+++ /dev/null
@@ -1,425 +0,0 @@
-/*
- * Copyright (C) 2011 Sansar Choinyambuu
- * 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 "tcg_pts_attr_req_funct_comp_evid.h"
-
-#include <pa_tnc/pa_tnc_msg.h>
-#include <bio/bio_writer.h>
-#include <bio/bio_reader.h>
-#include <debug.h>
-
-typedef struct private_tcg_pts_attr_req_funct_comp_evid_t private_tcg_pts_attr_req_funct_comp_evid_t;
-
-/**
- * Request Functional Component Evidence
- * see section 3.14.1 of PTS Protocol: Binding to TNC IF-M Specification
- *
- * 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
- *
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Flags | Sub-component Depth |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Component Functional Name |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *
- */
-
-/**
- * Component Functional Name Structure (see section 5.1 of PTS Protocol: Binding to TNC IF-M Specification)
- *
- * 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
- *
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Component Functional Name Vendor ID |Fam| Qualifier |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Component Functional Name |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *
- */
-
-/**
- * Qualifier for Functional Component
- * see section 5.2 of PTS Protocol: Binding to TNC IF-M Specification
- *
- *
- * 0 1 2 3 4 5
- * +-+-+-+-+-+-+
- * |K|S| Type |
- * +-+-+-+-+-+-+
- */
-
-#define PTS_REQ_FUNCT_COMP_EVID_SIZE 12
-#define PTS_REQ_FUNCT_COMP_FAM_BIN_ENUM 0x00
-
-/**
- * Private data of an tcg_pts_attr_req_funct_comp_evid_t object.
- */
-struct private_tcg_pts_attr_req_funct_comp_evid_t {
-
- /**
- * Public members of tcg_pts_attr_req_funct_comp_evid_t
- */
- tcg_pts_attr_req_funct_comp_evid_t public;
-
- /**
- * Attribute vendor ID
- */
- pen_t vendor_id;
-
- /**
- * Attribute type
- */
- u_int32_t type;
-
- /**
- * Attribute value
- */
- chunk_t value;
-
- /**
- * Noskip flag
- */
- bool noskip_flag;
-
- /**
- * Set of flags for Request Functional Component
- */
- pts_attr_req_funct_comp_evid_flag_t flags;
-
- /**
- * Sub-component Depth
- */
- u_int32_t depth;
-
- /**
- * Component Functional Name Vendor ID
- */
- u_int32_t comp_vendor_id;
-
- /**
- * Functional Name Encoding Family
- */
- u_int8_t family;
-
- /**
- * Functional Name Category Qualifier
- */
- pts_qualifier_t qualifier;
-
- /**
- * Component Functional Name
- */
- pts_funct_comp_name_t name;
-};
-
-METHOD(pa_tnc_attr_t, get_vendor_id, pen_t,
- private_tcg_pts_attr_req_funct_comp_evid_t *this)
-{
- return this->vendor_id;
-}
-
-METHOD(pa_tnc_attr_t, get_type, u_int32_t,
- private_tcg_pts_attr_req_funct_comp_evid_t *this)
-{
- return this->type;
-}
-
-METHOD(pa_tnc_attr_t, get_value, chunk_t,
- private_tcg_pts_attr_req_funct_comp_evid_t *this)
-{
- return this->value;
-}
-
-METHOD(pa_tnc_attr_t, get_noskip_flag, bool,
- private_tcg_pts_attr_req_funct_comp_evid_t *this)
-{
- return this->noskip_flag;
-}
-
-METHOD(pa_tnc_attr_t, set_noskip_flag,void,
- private_tcg_pts_attr_req_funct_comp_evid_t *this, bool noskip)
-{
- this->noskip_flag = noskip;
-}
-
-METHOD(pa_tnc_attr_t, build, void,
- private_tcg_pts_attr_req_funct_comp_evid_t *this)
-{
- bio_writer_t *writer;
- u_int8_t flags = 0;
- u_int8_t qualifier = 0;
-
- writer = bio_writer_create(PTS_REQ_FUNCT_COMP_EVID_SIZE);
-
- /* Determine the flags to set*/
- if (this->flags & PTS_REQ_FUNC_COMP_FLAG_PCR)
- {
- flags += 128;
- }
- if (this->flags & PTS_REQ_FUNC_COMP_FLAG_CURR)
- {
- flags += 64;
- }
- if (this->flags & PTS_REQ_FUNC_COMP_FLAG_VER)
- {
- flags += 32;
- }
- if (this->flags & PTS_REQ_FUNC_COMP_FLAG_TTC)
- {
- flags += 16;
- }
- writer->write_uint8(writer, flags);
-
- writer->write_uint24 (writer, this->depth);
- writer->write_uint24 (writer, this->comp_vendor_id);
-
- if (this->family != PTS_REQ_FUNCT_COMP_FAM_BIN_ENUM)
- {
- DBG1(DBG_TNC, "Functional Name Encoding Family is not set to 00");
- }
-
- qualifier += this->qualifier.type;
- if (this->qualifier.kernel)
- {
- qualifier += 16;
- }
- if (this->qualifier.sub_component)
- {
- qualifier += 32;
- }
- writer->write_uint8 (writer, qualifier);
- writer->write_uint32 (writer, this->name);
-
- this->value = chunk_clone(writer->get_buf(writer));
- writer->destroy(writer);
-}
-
-METHOD(pa_tnc_attr_t, process, status_t,
- private_tcg_pts_attr_req_funct_comp_evid_t *this, u_int32_t *offset)
-{
- bio_reader_t *reader;
- u_int8_t flags;
- u_int8_t fam_and_qualifier;
-
- if (this->value.len < PTS_REQ_FUNCT_COMP_EVID_SIZE)
- {
- DBG1(DBG_TNC, "insufficient data for Request Functional Component Evidence");
- *offset = 0;
- return FAILED;
- }
- reader = bio_reader_create(this->value);
-
- reader->read_uint8(reader, &flags);
- if ((flags >> 4) & 1)
- {
- this->flags |= PTS_REQ_FUNC_COMP_FLAG_PCR;
- }
- if ((flags >> 5) & 1)
- {
- this->flags |= PTS_REQ_FUNC_COMP_FLAG_CURR;
- }
- if ((flags >> 6) & 1)
- {
- this->flags |= PTS_REQ_FUNC_COMP_FLAG_VER;
- }
- if ((flags >> 7) & 1)
- {
- this->flags |= PTS_REQ_FUNC_COMP_FLAG_TTC;
- }
-
- reader->read_uint24(reader, &this->depth);
- reader->read_uint24(reader, &this->comp_vendor_id);
- reader->read_uint8(reader, &fam_and_qualifier);
-
- if (((fam_and_qualifier >> 6) & 1) )
- {
- this->family += 1;
- }
- if (((fam_and_qualifier >> 7) & 1) )
- {
- this->family += 2;
- }
-
- /* TODO: Generate an IF-M error attribute indicating */
- /* TCG_PTS_INVALID_NAME_FAM */
- //if (&this->comp_vendor_id==PEN_TCG && this->family != PTS_REQ_FUNCT_COMP_FAM_BIN_ENUM)
- //{
- // DBG1(DBG_TNC, "Functional Name Encoding Family is not set to 00");
- //}
-
- if (((fam_and_qualifier >> 5) & 1) )
- {
- this->qualifier.kernel = true;
- }
- if (((fam_and_qualifier >> 4) & 1) )
- {
- this->qualifier.sub_component = true;
- }
- this->qualifier.type = ( fam_and_qualifier & 0xF );
- /* TODO: Check the type is defined in pts_attr_req_funct_comp_type_t */
-
- reader->read_uint32(reader, &this->name);
- /* TODO: Check the name is defined in pts_funct_comp_name_t */
-
- reader->destroy(reader);
- return SUCCESS;
-}
-
-METHOD(pa_tnc_attr_t, destroy, void,
- private_tcg_pts_attr_req_funct_comp_evid_t *this)
-{
- free(this->value.ptr);
- free(this);
-}
-
-METHOD(tcg_pts_attr_req_funct_comp_evid_t, get_flags, pts_attr_req_funct_comp_evid_flag_t,
- private_tcg_pts_attr_req_funct_comp_evid_t *this)
-{
- return this->flags;
-}
-
-METHOD(tcg_pts_attr_req_funct_comp_evid_t, set_flags, void,
- private_tcg_pts_attr_req_funct_comp_evid_t *this, pts_attr_req_funct_comp_evid_flag_t flags)
-{
- this->flags = flags;
-}
-
-METHOD(tcg_pts_attr_req_funct_comp_evid_t, get_sub_component_depth, u_int32_t,
- private_tcg_pts_attr_req_funct_comp_evid_t *this)
-{
- return this->depth;
-}
-
-METHOD(tcg_pts_attr_req_funct_comp_evid_t, get_comp_funct_name_vendor_id, u_int32_t,
- private_tcg_pts_attr_req_funct_comp_evid_t *this)
-{
- return this->comp_vendor_id;
-}
-
-METHOD(tcg_pts_attr_req_funct_comp_evid_t, get_family, u_int8_t,
- private_tcg_pts_attr_req_funct_comp_evid_t *this)
-{
- return this->family;
-}
-
-METHOD(tcg_pts_attr_req_funct_comp_evid_t, get_qualifier, pts_qualifier_t,
- private_tcg_pts_attr_req_funct_comp_evid_t *this)
-{
- return this->qualifier;
-}
-
-METHOD(tcg_pts_attr_req_funct_comp_evid_t, set_qualifier, void,
- private_tcg_pts_attr_req_funct_comp_evid_t *this, pts_qualifier_t qualifier)
-{
- this->qualifier = qualifier;
-}
-
-METHOD(tcg_pts_attr_req_funct_comp_evid_t, get_comp_funct_name, pts_funct_comp_name_t,
- private_tcg_pts_attr_req_funct_comp_evid_t *this)
-{
- return this->name;
-}
-
-METHOD(tcg_pts_attr_req_funct_comp_evid_t, set_comp_funct_name, void,
- private_tcg_pts_attr_req_funct_comp_evid_t *this, pts_funct_comp_name_t name)
-{
- this->name = name;
-}
-
-/**
- * Described in header.
- */
-pa_tnc_attr_t *tcg_pts_attr_req_funct_comp_evid_create(
- pts_attr_req_funct_comp_evid_flag_t flags,
- u_int32_t depth, u_int32_t vendor_id,
- pts_qualifier_t qualifier,
- pts_funct_comp_name_t name)
-{
- private_tcg_pts_attr_req_funct_comp_evid_t *this;
-
- INIT(this,
- .public = {
- .pa_tnc_attribute = {
- .get_vendor_id = _get_vendor_id,
- .get_type = _get_type,
- .get_value = _get_value,
- .get_noskip_flag = _get_noskip_flag,
- .set_noskip_flag = _set_noskip_flag,
- .build = _build,
- .process = _process,
- .destroy = _destroy,
- },
- .get_flags= _get_flags,
- .set_flags= _set_flags,
- .get_sub_component_depth = _get_sub_component_depth,
- .get_comp_funct_name_vendor_id = _get_comp_funct_name_vendor_id,
- .get_family = _get_family,
- .get_qualifier = _get_qualifier,
- .set_qualifier = _set_qualifier,
- .get_comp_funct_name = _get_comp_funct_name,
- .set_comp_funct_name = _set_comp_funct_name,
- },
- .vendor_id = PEN_TCG,
- .type = TCG_PTS_REQ_FUNCT_COMP_EVID,
- .flags = flags,
- .depth = depth,
- .comp_vendor_id = vendor_id,
- .family = PTS_REQ_FUNCT_COMP_FAM_BIN_ENUM,
- .qualifier = qualifier,
- .name = name,
- );
-
- return &this->public.pa_tnc_attribute;
-}
-
-
-/**
- * Described in header.
- */
-pa_tnc_attr_t *tcg_pts_attr_req_funct_comp_evid_create_from_data(chunk_t data)
-{
- private_tcg_pts_attr_req_funct_comp_evid_t *this;
-
- INIT(this,
- .public = {
- .pa_tnc_attribute = {
- .get_vendor_id = _get_vendor_id,
- .get_type = _get_type,
- .get_value = _get_value,
- .get_noskip_flag = _get_noskip_flag,
- .set_noskip_flag = _set_noskip_flag,
- .build = _build,
- .process = _process,
- .destroy = _destroy,
- },
- .get_flags= _get_flags,
- .set_flags= _set_flags,
- .get_sub_component_depth = _get_sub_component_depth,
- .get_comp_funct_name_vendor_id = _get_comp_funct_name_vendor_id,
- .get_family = _get_family,
- .get_qualifier = _get_qualifier,
- .set_qualifier = _set_qualifier,
- .get_comp_funct_name = _get_comp_funct_name,
- .set_comp_funct_name = _set_comp_funct_name,
- },
- .vendor_id = PEN_TCG,
- .type = TCG_PTS_REQ_FUNCT_COMP_EVID,
- .value = chunk_clone(data),
- );
-
- return &this->public.pa_tnc_attribute;
-}
diff --git a/src/libpts/tcg/tcg_pts_attr_req_funct_comp_evid.h b/src/libpts/tcg/tcg_pts_attr_req_funct_comp_evid.h
deleted file mode 100644
index 215ce6408..000000000
--- a/src/libpts/tcg/tcg_pts_attr_req_funct_comp_evid.h
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright (C) 2011 Sansar Choinyambuu
- * 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 tcg_pts_attr_req_funct_comp_evid tcg_pts_attr_req_funct_comp_evid
- * @{ @ingroup tcg_pts_attr_req_funct_comp_evid
- */
-
-#ifndef TCG_PTS_ATTR_REQ_FUNCT_COMP_EVID_H_
-#define TCG_PTS_ATTR_REQ_FUNCT_COMP_EVID_H_
-
-typedef struct tcg_pts_attr_req_funct_comp_evid_t tcg_pts_attr_req_funct_comp_evid_t;
-typedef enum pts_attr_req_funct_comp_evid_flag_t pts_attr_req_funct_comp_evid_flag_t;
-
-#include "tcg_attr.h"
-#include "pts/pts_funct_comp_name.h"
-#include "pa_tnc/pa_tnc_attr.h"
-
-/**
- * PTS Request Functional Component Evidence Flags
- */
-enum pts_attr_req_funct_comp_evid_flag_t {
- /** Transitive Trust Chain flag */
- PTS_REQ_FUNC_COMP_FLAG_TTC = (1<<7),
- /** Verify Component flag */
- PTS_REQ_FUNC_COMP_FLAG_VER = (1<<6),
- /** Current Evidence flag */
- PTS_REQ_FUNC_COMP_FLAG_CURR = (1<<5),
- /** PCR Information flag */
- PTS_REQ_FUNC_COMP_FLAG_PCR = (1<<4),
-};
-
-/**
- * Class implementing the TCG PTS Request Functional Component Evidence attribute
- *
- */
-struct tcg_pts_attr_req_funct_comp_evid_t {
-
- /**
- * Public PA-TNC attribute interface
- */
- pa_tnc_attr_t pa_tnc_attribute;
-
- /**
- * Get flags for PTS Request Functional Component Evidence
- *
- * @return Set of flags
- */
- pts_attr_req_funct_comp_evid_flag_t (*get_flags)(tcg_pts_attr_req_funct_comp_evid_t *this);
-
- /**
- * Set flags for PTS Request Functional Component Evidence
- *
- * @param flags Set of flags
- */
- void (*set_flags)(tcg_pts_attr_req_funct_comp_evid_t *this,
- pts_attr_req_funct_comp_evid_flag_t flags);
-
- /**
- * Get Sub-component Depth
- *
- * @return Sub-component Depth
- */
- u_int32_t (*get_sub_component_depth)(tcg_pts_attr_req_funct_comp_evid_t *this);
-
- /**
- * Get Component Functional Name Vendor ID
- *
- * @return Component Functional Name Vendor ID
- */
- u_int32_t (*get_comp_funct_name_vendor_id)(tcg_pts_attr_req_funct_comp_evid_t *this);
-
- /**
- * Get Family
- *
- * @return Functional Name Family
- */
- u_int8_t (*get_family)(tcg_pts_attr_req_funct_comp_evid_t *this);
-
- /**
- * Get Qualifier
- *
- * @return Functional Name Category Qualifier
- */
- pts_qualifier_t (*get_qualifier)(tcg_pts_attr_req_funct_comp_evid_t *this);
-
- /**
- * Set qualifier for Component Functional Name
- *
- * @param qualifier Functional Name Category Qualifier
- */
- void (*set_qualifier)(tcg_pts_attr_req_funct_comp_evid_t *this,
- pts_qualifier_t qualifier);
-
- /**
- * Get Component Functional Name
- *
- * @return Component Functional Name
- */
- pts_funct_comp_name_t (*get_comp_funct_name)(tcg_pts_attr_req_funct_comp_evid_t *this);
-
-
- /**
- * Set Component Functional Name
- *
- * @param name Component Functional Name
- */
- void (*set_comp_funct_name)(tcg_pts_attr_req_funct_comp_evid_t *this,
- pts_funct_comp_name_t name);
-
-
-};
-
-/**
- * Creates an tcg_pts_attr_req_funct_comp_evid_t object
- *
- * @param flags Set of flags
- * @param depth Sub-component Depth
- * @param vendor_id Component Functional Name Vendor ID
- * @param qualifier Functional Name Category Qualifier
- * @param name Component Functional Name
- */
-pa_tnc_attr_t* tcg_pts_attr_req_funct_comp_evid_create(pts_attr_req_funct_comp_evid_flag_t flags,
- u_int32_t depth, u_int32_t vendor_id,
- pts_qualifier_t qualifier,
- pts_funct_comp_name_t name);
-
-/**
- * Creates an tcg_pts_attr_req_funct_comp_evid_t object from received data
- *
- * @param value Unparsed attribute value
- */
-pa_tnc_attr_t* tcg_pts_attr_req_funct_comp_evid_create_from_data(chunk_t value);
-
-#endif /** TCG_PTS_ATTR_REQ_FUNCT_COMP_EVID_H_ @}*/
diff --git a/src/libpts/tcg/tcg_pts_attr_simple_comp_evid.c b/src/libpts/tcg/tcg_pts_attr_simple_comp_evid.c
index 84b31724e..d2c197ac4 100644
--- a/src/libpts/tcg/tcg_pts_attr_simple_comp_evid.c
+++ b/src/libpts/tcg/tcg_pts_attr_simple_comp_evid.c
@@ -20,6 +20,8 @@
#include <bio/bio_reader.h>
#include <debug.h>
+#include <time.h>
+
typedef struct private_tcg_pts_attr_simple_comp_evid_t private_tcg_pts_attr_simple_comp_evid_t;
/**
@@ -29,37 +31,37 @@ typedef struct private_tcg_pts_attr_simple_comp_evid_t private_tcg_pts_attr_simp
* 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
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Flags | Sub-Component Depth |
+ * | Flags | Sub-Component Depth |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Specific Functional Component |
+ * | Specific Functional Component |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Specific Functional Component |
+ * | Specific Functional Component |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Measure. Type | Extended into PCR |
+ * | Measure. Type | Extended into PCR |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Hash Algorithm | PCR Transform | Reserved |
+ * | Hash Algorithm | PCR Transform | Reserved |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Measurement Date/Time |
+ * | Measurement Date/Time |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Measurement Date/Time |
+ * | Measurement Date/Time |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Measurement Date/Time |
+ * | Measurement Date/Time |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Measurement Date/Time |
+ * | Measurement Date/Time |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Measurement Date/Time |
+ * | Measurement Date/Time |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Optional Policy URI Length | Opt. Verification Policy URI ~
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * ~ Optional Verification Policy URI ~
+ * ~ Optional Verification Policy URI ~
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Optional PCR Length | Optional PCR Before Value ~
+ * | Optional PCR Length | Optional PCR Before Value ~
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * ~ Optional PCR Before Value (Variable Length) ~
+ * ~ Optional PCR Before Value (Variable Length) ~
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * ~ Optional PCR After Value (Variable Length) ~
+ * ~ Optional PCR After Value (Variable Length) ~
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * ~ Component Measurement (Variable Length) ~
+ * ~ Component Measurement (Variable Length) ~
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
@@ -70,30 +72,22 @@ typedef struct private_tcg_pts_attr_simple_comp_evid_t private_tcg_pts_attr_simp
* 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
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Component Functional Name Vendor ID |Fam| Qualifier |
+ * | Component Functional Name Vendor ID |Fam| Qualifier |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Component Functional Name |
+ * | Component Functional Name |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
*/
-/**
- * Qualifier for Functional Component
- * see section 5.2 of PTS Protocol: Binding to TNC IF-M Specification
- *
- *
- * 0 1 2 3 4 5
- * +-+-+-+-+-+-+
- * |K|S| Type |
- * +-+-+-+-+-+-+
- */
-
-
-
#define PTS_SIMPLE_COMP_EVID_SIZE 40
-#define PTS_SIMPLE_COMP_EVID_MEASUREMENT_TIME_SIZE 20
+#define PTS_SIMPLE_COMP_EVID_MEAS_TIME_SIZE 20
#define PTS_SIMPLE_COMP_EVID_RESERVED 0x00
-#define PTS_REQ_FUNCT_COMP_FAM_BIN_ENUM 0x00
+#define PTS_SIMPLE_COMP_EVID_FAMILY_MASK 0xC0
+#define PTS_SIMPLE_COMP_EVID_VALIDATION_MASK 0x60
+#define PTS_SIMPLE_COMP_EVID_MEAS_TYPE (1<<7)
+#define PTS_SIMPLE_COMP_EVID_FLAG_PCR (1<<7)
+
+static char *utc_undefined_time_str = "0000-00-00T00:00:00Z";
/**
* Private data of an tcg_pts_attr_simple_comp_evid_t object.
@@ -126,80 +120,14 @@ struct private_tcg_pts_attr_simple_comp_evid_t {
bool noskip_flag;
/**
- * Set of flags for Simple Component Evidence
+ * PTS Component Evidence
*/
- pts_attr_simple_comp_evid_flag_t flags;
+ pts_comp_evidence_t *evidence;
/**
- * Sub-component Depth
- */
- u_int32_t depth;
-
- /**
- * Component Functional Name Vendor ID
- */
- u_int32_t comp_vendor_id;
-
- /**
- * Functional Name Encoding Family
- */
- u_int8_t family;
-
- /**
- * Functional Name Category Qualifier
- */
- pts_qualifier_t qualifier;
-
- /**
- * Component Functional Name
- */
- pts_funct_comp_name_t name;
-
- /**
- * Measurement type
- */
- u_int8_t measurement_type;
-
- /**
- * Which PCR the functional component is extended into
- */
- u_int32_t extended_pcr;
-
- /**
- * Hash Algorithm
+ * Reference count
*/
- pts_meas_algorithms_t hash_algorithm;
-
- /**
- * Transformation type for PCR
- */
- pts_pcr_transform_t transformation;
-
- /**
- * Measurement time
- */
- chunk_t measurement_time;
-
- /**
- * Optional Policy URI
- */
- chunk_t policy_uri;
-
- /**
- * Optional PCR before value
- */
- chunk_t pcr_before;
-
- /**
- * Optional PCR after value
- */
- chunk_t pcr_after;
-
- /**
- * Component Measurement
- */
- chunk_t measurement;
-
+ refcount_t ref;
};
METHOD(pa_tnc_attr_t, get_vendor_id, pen_t,
@@ -232,101 +160,157 @@ METHOD(pa_tnc_attr_t, set_noskip_flag,void,
this->noskip_flag = noskip;
}
-METHOD(pa_tnc_attr_t, build, void,
- private_tcg_pts_attr_simple_comp_evid_t *this)
+/**
+ * Convert time_t to Simple Component Evidence UTS string format
+ */
+void measurement_time_to_utc(time_t measurement_time, chunk_t *utc_time)
{
- bio_writer_t *writer;
- u_int8_t flags = 0;
- u_int8_t qualifier = 0;
-
- writer = bio_writer_create(PTS_SIMPLE_COMP_EVID_SIZE);
-
- /* Determine the flags to set*/
- if (this->flags & PTS_SIMPLE_COMP_EVID_FLAG_PCR)
- {
- flags += 128;
- }
- if (this->flags & PTS_SIMPLE_COMP_EVID_FLAG_NO_VER)
- {
- flags += 32;
- }
- else if (this->flags & PTS_SIMPLE_COMP_EVID_FLAG_VER_FAIL)
+ struct tm t;
+
+ if (measurement_time == UNDEFINED_TIME)
{
- flags += 64;
+ utc_time->ptr = utc_undefined_time_str;
}
- else if (this->flags & PTS_SIMPLE_COMP_EVID_FLAG_VER_PASS)
+ else
{
- flags += 96;
+ gmtime_r(&measurement_time, &t);
+ sprintf(utc_time->ptr, "%04d-%02d-%02dT%02d:%02d:%02dZ",
+ t.tm_year + 1900, t.tm_mon + 1, t.tm_mday,
+ t.tm_hour, t.tm_min, t.tm_sec);
}
+}
+
+METHOD(pa_tnc_attr_t, build, void,
+ private_tcg_pts_attr_simple_comp_evid_t *this)
+{
+ bio_writer_t *writer;
+ bool has_pcr_info;
+ char utc_time_buf[25];
+ u_int8_t flags;
+ u_int32_t depth, extended_pcr;
+ pts_comp_func_name_t *name;
+ pts_meas_algorithms_t hash_algorithm;
+ pts_pcr_transform_t transform;
+ pts_comp_evid_validation_t validation;
+ time_t measurement_time;
+ chunk_t measurement, utc_time, pcr_before, pcr_after, policy_uri;
+
+ /* Extract parameters from comp_evidence_t object */
+ name = this->evidence->get_comp_func_name(this->evidence,
+ &depth);
+ measurement = this->evidence->get_measurement(this->evidence,
+ &extended_pcr, &hash_algorithm, &transform,
+ &measurement_time);
+ has_pcr_info = this->evidence->get_pcr_info(this->evidence,
+ &pcr_before, &pcr_after);
+ validation = this->evidence->get_validation(this->evidence,
+ &policy_uri);
- writer->write_uint8(writer, flags);
-
- writer->write_uint24 (writer, this->depth);
- writer->write_uint24 (writer, this->comp_vendor_id);
-
- if (this->family != PTS_REQ_FUNCT_COMP_FAM_BIN_ENUM)
+ /* Determine the flags to set*/
+ flags = validation;
+ if (has_pcr_info)
{
- DBG1(DBG_TNC, "Functional Name Encoding Family is not set to 00");
+ flags |= PTS_SIMPLE_COMP_EVID_FLAG_PCR;
}
+
+ utc_time = chunk_create(utc_time_buf, PTS_SIMPLE_COMP_EVID_MEAS_TIME_SIZE);
+ measurement_time_to_utc(measurement_time, &utc_time);
+
+ writer = bio_writer_create(PTS_SIMPLE_COMP_EVID_SIZE);
+
+ writer->write_uint8 (writer, flags);
+ writer->write_uint24(writer, depth);
+ writer->write_uint24(writer, name->get_vendor_id(name));
+ writer->write_uint8 (writer, name->get_qualifier(name));
+ writer->write_uint32(writer, name->get_name(name));
+ writer->write_uint8 (writer, PTS_SIMPLE_COMP_EVID_MEAS_TYPE);
+ writer->write_uint24(writer, extended_pcr);
+ writer->write_uint16(writer, hash_algorithm);
+ writer->write_uint8 (writer, transform);
+ writer->write_uint8 (writer, PTS_SIMPLE_COMP_EVID_RESERVED);
+ writer->write_data (writer, utc_time);
- qualifier += this->qualifier.type;
- if (this->qualifier.kernel)
+ /* Optional fields */
+ if (validation == PTS_COMP_EVID_VALIDATION_FAILED ||
+ validation == PTS_COMP_EVID_VALIDATION_PASSED)
{
- qualifier += 16;
+ writer->write_uint16(writer, policy_uri.len);
+ writer->write_data (writer, policy_uri);
}
- if (this->qualifier.sub_component)
+ if (has_pcr_info)
{
- qualifier += 32;
+ writer->write_uint16(writer, pcr_before.len);
+ writer->write_data (writer, pcr_before);
+ writer->write_data (writer, pcr_after);
}
+
+ writer->write_data(writer, measurement);
- /* Unknown or Wildcard should not be used for Qualification*/
- if (!qualifier || qualifier == 63)
+ this->value = chunk_clone(writer->get_buf(writer));
+ writer->destroy(writer);
+}
+
+static const int days[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
+static const int tm_leap_1970 = 477;
+
+/**
+ * Convert Simple Component Evidence UTS string format to time_t
+ */
+bool measurement_time_from_utc(time_t *measurement_time, chunk_t utc_time)
+{
+ int tm_year, tm_mon, tm_day, tm_days, tm_hour, tm_min, tm_sec, tm_secs;
+ int tm_leap_4, tm_leap_100, tm_leap_400, tm_leap;
+
+ if (memeq(utc_undefined_time_str, utc_time.ptr, utc_time.len))
{
- DBG1(DBG_TNC, "Unknown or Wildcard should not be used for"
- " Functional Name Qualifier");
+ *measurement_time = 0;
+ return TRUE;
}
-
- writer->write_uint8 (writer, qualifier);
- writer->write_uint32(writer, this->name);
-
- writer->write_uint8 (writer, (this->measurement_type << 7));
- writer->write_uint24(writer, this->extended_pcr);
- writer->write_uint16(writer, this->hash_algorithm);
- writer->write_uint8 (writer, this->transformation);
- writer->write_data (writer, this->measurement_time);
-
- /* Optional fields */
- if (this->policy_uri.ptr && this->policy_uri.len > 0)
+ if (sscanf(utc_time.ptr, "%4d-%2d-%2dT%2d:%2d:%2dZ",
+ &tm_year, &tm_mon, &tm_day, &tm_hour, &tm_min, &tm_sec) != 6)
{
- writer->write_uint16(writer, this->policy_uri.len);
- writer->write_data (writer, this->policy_uri);
+ return FALSE;
}
- if (this->pcr_before.ptr && this->pcr_after.ptr &&
- this->pcr_before.len == this->pcr_after.len &&
- this->pcr_before.len > 0 && this->pcr_after.len > 0)
+
+ /* representation of months as 0..11 */
+ tm_mon--;
+
+ /* representation of days as 0..30 */
+ tm_day--;
+
+ /* number of leap years between last year and 1970? */
+ tm_leap_4 = (tm_year - 1) / 4;
+ tm_leap_100 = tm_leap_4 / 25;
+ tm_leap_400 = tm_leap_100 / 4;
+ tm_leap = tm_leap_4 - tm_leap_100 + tm_leap_400 - tm_leap_1970;
+
+ /* if date later then February, is the current year a leap year? */
+ if (tm_mon > 1 && (tm_year % 4 == 0) &&
+ (tm_year % 100 != 0 || tm_year % 400 == 0))
{
- writer->write_uint16(writer, this->pcr_before.len);
- writer->write_data (writer, this->pcr_before);
- writer->write_data (writer, this->pcr_after);
+ tm_leap++;
}
-
- writer->write_data (writer, this->measurement);
-
- this->value = chunk_clone(writer->get_buf(writer));
- writer->destroy(writer);
+ tm_days = 365 * (tm_year - 1970) + days[tm_mon] + tm_day + tm_leap;
+ tm_secs = 60 * (60 * (24 * tm_days + tm_hour) + tm_min) + tm_sec;
+
+ *measurement_time = tm_secs;
+ return TRUE;
}
METHOD(pa_tnc_attr_t, process, status_t,
private_tcg_pts_attr_simple_comp_evid_t *this, u_int32_t *offset)
{
bio_reader_t *reader;
- u_int8_t flags;
- u_int8_t fam_and_qualifier;
- u_int8_t measurement_type;
- u_int16_t algorithm;
- u_int8_t transformation;
- u_int32_t measurement_len;
-
+ pts_comp_func_name_t *name;
+ u_int8_t flags, fam_and_qualifier, qualifier, reserved;
+ u_int8_t measurement_type, transform, validation;
+ u_int16_t hash_algorithm, len;
+ u_int32_t depth, vendor_id, comp_name, extended_pcr;
+ chunk_t measurement, utc_time, policy_uri, pcr_before, pcr_after;
+ time_t measurement_time;
+ bool has_pcr_info = FALSE, has_validation = FALSE;
+ status_t status = FAILED;
+
if (this->value.len < PTS_SIMPLE_COMP_EVID_SIZE)
{
DBG1(DBG_TNC, "insufficient data for Simple Component Evidence");
@@ -335,315 +319,144 @@ METHOD(pa_tnc_attr_t, process, status_t,
}
reader = bio_reader_create(this->value);
- reader->read_uint8(reader, &flags);
-
- /* Determine the flags to set*/
- if ((flags >> 7) & 1)
- {
- this->flags |= PTS_SIMPLE_COMP_EVID_FLAG_PCR;
- }
- if (!((flags >> 6) & 1) && !((flags >> 5) & 1))
- {
- this->flags |= PTS_SIMPLE_COMP_EVID_FLAG_NO_VALID;
- }
- else if (!((flags >> 6) & 1) && ((flags >> 5) & 1))
- {
- this->flags |= PTS_SIMPLE_COMP_EVID_FLAG_NO_VER;
- }
- else if (((flags >> 6) & 1) && !((flags >> 5) & 1))
- {
- this->flags |= PTS_SIMPLE_COMP_EVID_FLAG_VER_FAIL;
- }
- else if (((flags >> 6) & 1) && ((flags >> 5) & 1))
- {
- this->flags |= PTS_SIMPLE_COMP_EVID_FLAG_VER_PASS;
- }
-
- reader->read_uint24(reader, &this->depth);
- reader->read_uint24(reader, &this->comp_vendor_id);
- reader->read_uint8(reader, &fam_and_qualifier);
-
- if (((fam_and_qualifier >> 6) & 1) )
- {
- this->family += 1;
- }
- if (((fam_and_qualifier >> 7) & 1) )
+ reader->read_uint8 (reader, &flags);
+ reader->read_uint24(reader, &depth);
+ reader->read_uint24(reader, &vendor_id);
+ reader->read_uint8 (reader, &fam_and_qualifier);
+ reader->read_uint32(reader, &comp_name);
+ reader->read_uint8 (reader, &measurement_type);
+ reader->read_uint24(reader, &extended_pcr);
+ reader->read_uint16(reader, &hash_algorithm);
+ reader->read_uint8 (reader, &transform);
+ reader->read_uint8 (reader, &reserved);
+ reader->read_data (reader, PTS_SIMPLE_COMP_EVID_MEAS_TIME_SIZE, &utc_time);
+
+ if (measurement_type != PTS_SIMPLE_COMP_EVID_MEAS_TYPE)
{
- this->family += 2;
- }
-
- /* TODO: Generate an IF-M error attribute indicating */
- /* TCG_PTS_INVALID_NAME_FAM */
- //if (&this->comp_vendor_id==PEN_TCG && this->family != PTS_REQ_FUNCT_COMP_FAM_BIN_ENUM)
- //{
- // DBG1(DBG_TNC, "Functional Name Encoding Family is not set to 00");
- //}
-
- if (((fam_and_qualifier >> 5) & 1) )
- {
- this->qualifier.kernel = true;
+ DBG1(DBG_TNC, "unsupported Measurement Type in "
+ "Simple Component Evidence");
+ *offset = 12;
+ reader->destroy(reader);
+ return FAILED;
}
- if (((fam_and_qualifier >> 4) & 1) )
+ if (!measurement_time_from_utc(&measurement_time, utc_time))
{
- this->qualifier.sub_component = true;
+ DBG1(DBG_TNC, "invalid Measurement Time field in "
+ "Simple Component Evidence");
+ *offset = 20;
+ reader->destroy(reader);
+ return FAILED;
}
- this->qualifier.type = ( fam_and_qualifier & 0xF );
- /* TODO: Check the type is defined in pts_attr_req_funct_comp_type_t */
+ validation = flags & PTS_SIMPLE_COMP_EVID_VALIDATION_MASK;
+ qualifier = fam_and_qualifier & ~PTS_SIMPLE_COMP_EVID_FAMILY_MASK;
- /* Unknown or Wildcard should not be used for Qualification*/
- if (!(fam_and_qualifier & 0x3F) || (fam_and_qualifier & 0x3F) == 0x3F)
+ /* Is optional Policy URI field included? */
+ if (validation == PTS_COMP_EVID_VALIDATION_FAILED ||
+ validation == PTS_COMP_EVID_VALIDATION_PASSED)
{
- DBG1(DBG_TNC, "Unknown or Wildcard should not be used for"
- " Functional Name Qualifier");
+ if (!reader->read_uint16(reader, &len))
+ {
+ DBG1(DBG_TNC, "insufficient data for PTS Simple Component Evidence "
+ "Verification Policy URI Length");
+ goto end;
+ }
+ if (!reader->read_data(reader, len, &policy_uri))
+ {
+ DBG1(DBG_TNC, "insufficient data for PTS Simple Component Evidence "
+ "Verification Policy URI");
+ goto end;
+ }
+ has_validation = TRUE;
}
- reader->read_uint32(reader, &this->name);
- /* TODO: Check the name is defined in pts_funct_comp_name_t */
-
- reader->read_uint8(reader, &measurement_type);
- this->measurement_type = (measurement_type >> 7 ) & 1;
-
- reader->read_uint24(reader, &this->extended_pcr);
- reader->read_uint16(reader, &algorithm);
- this->hash_algorithm = algorithm;
-
- reader->read_uint8(reader, &transformation);
- this->transformation = transformation;
- /* TODO: Check the transformation is defined in pts_pcr_transform_t */
-
- reader->read_data(reader, PTS_SIMPLE_COMP_EVID_MEASUREMENT_TIME_SIZE,
- &this->measurement_time);
- this->measurement_time = chunk_clone(this->measurement_time);
-
- /* Optional Policy URI field is included */
- if (this->flags & PTS_SIMPLE_COMP_EVID_FLAG_VER_FAIL ||
- this->flags & PTS_SIMPLE_COMP_EVID_FLAG_VER_PASS)
- {
- u_int16_t policy_uri_len;
- reader->read_uint16(reader, &policy_uri_len);
- reader->read_data(reader, policy_uri_len, &this->policy_uri);
- this->policy_uri = chunk_clone(this->policy_uri);
- }
-
- /* Optional PCR value fields are included */
- if (this->flags & PTS_SIMPLE_COMP_EVID_FLAG_PCR)
+ /* Are optional PCR value fields included? */
+ if (flags & PTS_SIMPLE_COMP_EVID_FLAG_PCR)
{
- u_int16_t pcr_value_len;
- reader->read_uint16(reader, &pcr_value_len);
- reader->read_data(reader, pcr_value_len, &this->pcr_before);
- this->pcr_before = chunk_clone(this->pcr_before);
- reader->read_data(reader, pcr_value_len, &this->pcr_after);
- this->pcr_after = chunk_clone(this->pcr_after);
+ if (!reader->read_uint16(reader, &len))
+ {
+ DBG1(DBG_TNC, "insufficient data for PTS Simple Component Evidence "
+ "PCR Value length");
+ goto end;
+ }
+ if (!reader->read_data(reader, len, &pcr_before))
+ {
+ DBG1(DBG_TNC, "insufficient data for PTS Simple Component Evidence "
+ "PCR Before Value");
+ goto end;
+ }
+ if (!reader->read_data(reader, len, &pcr_after))
+ {
+ DBG1(DBG_TNC, "insufficient data for PTS Simple Component Evidence "
+ "PCR After Value");
+ goto end;
+ }
+ has_pcr_info = TRUE;
}
-
- measurement_len = reader->remaining(reader);
- reader->read_data(reader, measurement_len, &this->measurement);
- this->measurement = chunk_clone(this->measurement);
+ /* Measurement field comes at the very end */
+ reader->read_data(reader,reader->remaining(reader), &measurement);
reader->destroy(reader);
- return SUCCESS;
-}
-
-METHOD(pa_tnc_attr_t, destroy, void,
- private_tcg_pts_attr_simple_comp_evid_t *this)
-{
- free(this->value.ptr);
- free(this->measurement_time.ptr);
- free(this->policy_uri.ptr);
- free(this->pcr_before.ptr);
- free(this->pcr_after.ptr);
- free(this->measurement.ptr);
- free(this);
-}
-
-METHOD(tcg_pts_attr_simple_comp_evid_t, get_flags, pts_attr_simple_comp_evid_flag_t,
- private_tcg_pts_attr_simple_comp_evid_t *this)
-{
- return this->flags;
-}
-
-METHOD(tcg_pts_attr_simple_comp_evid_t, set_flags, void,
- private_tcg_pts_attr_simple_comp_evid_t *this, pts_attr_simple_comp_evid_flag_t flags)
-{
- this->flags = flags;
-}
-
-METHOD(tcg_pts_attr_simple_comp_evid_t, get_sub_component_depth, u_int32_t,
- private_tcg_pts_attr_simple_comp_evid_t *this)
-{
- return this->depth;
-}
-
-METHOD(tcg_pts_attr_simple_comp_evid_t, get_spec_comp_funct_name_vendor_id, u_int32_t,
- private_tcg_pts_attr_simple_comp_evid_t *this)
-{
- return this->comp_vendor_id;
-}
-
-METHOD(tcg_pts_attr_simple_comp_evid_t, get_family, u_int8_t,
- private_tcg_pts_attr_simple_comp_evid_t *this)
-{
- return this->family;
-}
-
-METHOD(tcg_pts_attr_simple_comp_evid_t, get_qualifier, pts_qualifier_t,
- private_tcg_pts_attr_simple_comp_evid_t *this)
-{
- return this->qualifier;
-}
-
-METHOD(tcg_pts_attr_simple_comp_evid_t, set_qualifier, void,
- private_tcg_pts_attr_simple_comp_evid_t *this,
- pts_qualifier_t qualifier)
-{
- this->qualifier = qualifier;
-}
-
-METHOD(tcg_pts_attr_simple_comp_evid_t, get_comp_funct_name, pts_funct_comp_name_t,
- private_tcg_pts_attr_simple_comp_evid_t *this)
-{
- return this->name;
-}
-
-METHOD(tcg_pts_attr_simple_comp_evid_t, set_comp_funct_name, void,
- private_tcg_pts_attr_simple_comp_evid_t *this, pts_funct_comp_name_t name)
-{
- this->name = name;
-}
-
-METHOD(tcg_pts_attr_simple_comp_evid_t, get_measurement_type, u_int8_t,
- private_tcg_pts_attr_simple_comp_evid_t *this)
-{
- return this->measurement_type;
-}
-
-METHOD(tcg_pts_attr_simple_comp_evid_t, get_extended_pcr, u_int32_t,
- private_tcg_pts_attr_simple_comp_evid_t *this)
-{
- return this->extended_pcr;
-}
-
-METHOD(tcg_pts_attr_simple_comp_evid_t, set_extended_pcr, void,
- private_tcg_pts_attr_simple_comp_evid_t *this, u_int32_t extended_pcr)
-{
- this->extended_pcr = extended_pcr;
-}
-
-METHOD(tcg_pts_attr_simple_comp_evid_t, get_hash_algorithm, pts_meas_algorithms_t,
- private_tcg_pts_attr_simple_comp_evid_t *this)
-{
- return this->hash_algorithm;
-}
-
-METHOD(tcg_pts_attr_simple_comp_evid_t, set_hash_algorithm, void,
- private_tcg_pts_attr_simple_comp_evid_t *this,
- pts_meas_algorithms_t hash_algorithm)
-{
- this->hash_algorithm = hash_algorithm;
-}
-
-METHOD(tcg_pts_attr_simple_comp_evid_t, get_pcr_trans, pts_pcr_transform_t,
- private_tcg_pts_attr_simple_comp_evid_t *this)
-{
- return this->transformation;
-}
-
-METHOD(tcg_pts_attr_simple_comp_evid_t, set_pcr_trans, void,
- private_tcg_pts_attr_simple_comp_evid_t *this, pts_pcr_transform_t transformation)
-{
- this->transformation = transformation;
-}
-
-METHOD(tcg_pts_attr_simple_comp_evid_t, get_measurement_time, chunk_t,
- private_tcg_pts_attr_simple_comp_evid_t *this)
-{
- return this->measurement_time;
-}
-METHOD(tcg_pts_attr_simple_comp_evid_t, set_measurement_time, void,
- private_tcg_pts_attr_simple_comp_evid_t *this, chunk_t measurement_time)
-{
- this->measurement_time = measurement_time;
-}
+ /* Create Component Functional Name object */
+ name = pts_comp_func_name_create(vendor_id, comp_name, qualifier);
-METHOD(tcg_pts_attr_simple_comp_evid_t, get_policy_uri, chunk_t,
- private_tcg_pts_attr_simple_comp_evid_t *this)
-{
- return this->policy_uri;
-}
+ /* Create Component Evidence object */
+ measurement = chunk_clone(measurement);
+ this->evidence = pts_comp_evidence_create(name, depth, extended_pcr,
+ hash_algorithm, transform,
+ measurement_time, measurement);
-METHOD(tcg_pts_attr_simple_comp_evid_t, set_policy_uri, void,
- private_tcg_pts_attr_simple_comp_evid_t *this, chunk_t policy_uri)
-{
- this->policy_uri = policy_uri;
-}
+ /* Add options */
+ if (has_validation)
+ {
+ policy_uri = chunk_clone(policy_uri);
+ this->evidence->set_validation(this->evidence, validation, policy_uri);
+ }
+ if (has_pcr_info)
+ {
+ pcr_before = chunk_clone(pcr_before);
+ pcr_after = chunk_clone(pcr_after);
+ this->evidence->set_pcr_info(this->evidence, pcr_before, pcr_after);
+ }
-METHOD(tcg_pts_attr_simple_comp_evid_t, get_pcr_before_value, chunk_t,
- private_tcg_pts_attr_simple_comp_evid_t *this)
-{
- return this->pcr_before;
-}
+ return SUCCESS;
-METHOD(tcg_pts_attr_simple_comp_evid_t, set_pcr_before_value, void,
- private_tcg_pts_attr_simple_comp_evid_t *this, chunk_t pcr_before)
-{
- this->pcr_before = pcr_before;
+end:
+ reader->destroy(reader);
+ return status;
}
-METHOD(tcg_pts_attr_simple_comp_evid_t, get_pcr_after_value, chunk_t,
+METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*,
private_tcg_pts_attr_simple_comp_evid_t *this)
{
- return this->pcr_after;
-}
-
-METHOD(tcg_pts_attr_simple_comp_evid_t, set_pcr_after_value, void,
- private_tcg_pts_attr_simple_comp_evid_t *this, chunk_t pcr_after)
-{
- this->pcr_after = pcr_after;
+ ref_get(&this->ref);
+ return &this->public.pa_tnc_attribute;
}
-METHOD(tcg_pts_attr_simple_comp_evid_t, get_pcr_len, u_int16_t,
+METHOD(pa_tnc_attr_t, destroy, void,
private_tcg_pts_attr_simple_comp_evid_t *this)
{
- if (this->pcr_before.ptr && this->pcr_after.ptr &&
- this->pcr_before.len == this->pcr_after.len &&
- this->pcr_before.len > 0 && this->pcr_after.len > 0)
+ if (ref_put(&this->ref))
{
- return this->pcr_before.len;
+ this->evidence->destroy(this->evidence);
+ free(this->value.ptr);
+ free(this);
}
- return 0;
}
-METHOD(tcg_pts_attr_simple_comp_evid_t, get_comp_measurement, chunk_t,
+METHOD(tcg_pts_attr_simple_comp_evid_t, get_comp_evidence, pts_comp_evidence_t*,
private_tcg_pts_attr_simple_comp_evid_t *this)
{
- return this->measurement;
-}
-
-METHOD(tcg_pts_attr_simple_comp_evid_t, set_comp_measurement, void,
- private_tcg_pts_attr_simple_comp_evid_t *this, chunk_t measurement)
-{
- this->measurement = measurement;
+ return this->evidence;
}
/**
* Described in header.
*/
-pa_tnc_attr_t *tcg_pts_attr_simple_comp_evid_create(
- pts_attr_simple_comp_evid_flag_t flags,
- u_int32_t depth, u_int32_t vendor_id,
- pts_qualifier_t qualifier,
- pts_funct_comp_name_t name,
- u_int32_t extended_pcr,
- pts_meas_algorithms_t hash_algorithm,
- pts_pcr_transform_t transformation,
- chunk_t measurement_time,
- chunk_t policy_uri,
- chunk_t pcr_before, chunk_t pcr_after,
- chunk_t measurement)
+pa_tnc_attr_t *tcg_pts_attr_simple_comp_evid_create(pts_comp_evidence_t *evid)
{
private_tcg_pts_attr_simple_comp_evid_t *this;
-
+
INIT(this,
.public = {
.pa_tnc_attribute = {
@@ -654,52 +467,15 @@ pa_tnc_attr_t *tcg_pts_attr_simple_comp_evid_create(
.set_noskip_flag = _set_noskip_flag,
.build = _build,
.process = _process,
+ .get_ref = _get_ref,
.destroy = _destroy,
},
- .get_flags= _get_flags,
- .set_flags= _set_flags,
- .get_sub_component_depth = _get_sub_component_depth,
- .get_spec_comp_funct_name_vendor_id = _get_spec_comp_funct_name_vendor_id,
- .get_family = _get_family,
- .get_qualifier = _get_qualifier,
- .set_qualifier = _set_qualifier,
- .get_comp_funct_name = _get_comp_funct_name,
- .set_comp_funct_name = _set_comp_funct_name,
- .get_measurement_type = _get_measurement_type,
- .get_extended_pcr = _get_extended_pcr,
- .set_extended_pcr = _set_extended_pcr,
- .get_hash_algorithm = _get_hash_algorithm,
- .set_hash_algorithm = _set_hash_algorithm,
- .get_pcr_trans = _get_pcr_trans,
- .set_pcr_trans = _set_pcr_trans,
- .get_measurement_time = _get_measurement_time,
- .set_measurement_time = _set_measurement_time,
- .get_policy_uri = _get_policy_uri,
- .set_policy_uri = _set_policy_uri,
- .get_pcr_before_value = _get_pcr_before_value,
- .set_pcr_before_value = _set_pcr_before_value,
- .get_pcr_after_value = _get_pcr_after_value,
- .set_pcr_after_value = _set_pcr_after_value,
- .get_pcr_len = _get_pcr_len,
- .get_comp_measurement = _get_comp_measurement,
- .set_comp_measurement = _set_comp_measurement,
+ .get_comp_evidence = _get_comp_evidence,
},
.vendor_id = PEN_TCG,
.type = TCG_PTS_SIMPLE_COMP_EVID,
- .flags = flags,
- .depth = depth,
- .comp_vendor_id = vendor_id,
- .family = PTS_REQ_FUNCT_COMP_FAM_BIN_ENUM,
- .qualifier = qualifier,
- .name = name,
- .extended_pcr = extended_pcr,
- .hash_algorithm = hash_algorithm,
- .transformation = transformation,
- .measurement_time = measurement_time,
- .policy_uri = policy_uri,
- .pcr_before = pcr_before,
- .pcr_after = pcr_after,
- .measurement = measurement,
+ .evidence = evid,
+ .ref = 1,
);
return &this->public.pa_tnc_attribute;
@@ -723,39 +499,15 @@ pa_tnc_attr_t *tcg_pts_attr_simple_comp_evid_create_from_data(chunk_t data)
.set_noskip_flag = _set_noskip_flag,
.build = _build,
.process = _process,
+ .get_ref = _get_ref,
.destroy = _destroy,
},
- .get_flags= _get_flags,
- .set_flags= _set_flags,
- .get_sub_component_depth = _get_sub_component_depth,
- .get_spec_comp_funct_name_vendor_id = _get_spec_comp_funct_name_vendor_id,
- .get_family = _get_family,
- .get_qualifier = _get_qualifier,
- .set_qualifier = _set_qualifier,
- .get_comp_funct_name = _get_comp_funct_name,
- .set_comp_funct_name = _set_comp_funct_name,
- .get_measurement_type = _get_measurement_type,
- .get_extended_pcr = _get_extended_pcr,
- .set_extended_pcr = _set_extended_pcr,
- .get_hash_algorithm = _get_hash_algorithm,
- .set_hash_algorithm = _set_hash_algorithm,
- .get_pcr_trans = _get_pcr_trans,
- .set_pcr_trans = _set_pcr_trans,
- .get_measurement_time = _get_measurement_time,
- .set_measurement_time = _set_measurement_time,
- .get_policy_uri = _get_policy_uri,
- .set_policy_uri = _set_policy_uri,
- .get_pcr_before_value = _get_pcr_before_value,
- .set_pcr_before_value = _set_pcr_before_value,
- .get_pcr_after_value = _get_pcr_after_value,
- .set_pcr_after_value = _set_pcr_after_value,
- .get_pcr_len = _get_pcr_len,
- .get_comp_measurement = _get_comp_measurement,
- .set_comp_measurement = _set_comp_measurement,
+ .get_comp_evidence = _get_comp_evidence,
},
.vendor_id = PEN_TCG,
.type = TCG_PTS_SIMPLE_COMP_EVID,
.value = chunk_clone(data),
+ .ref = 1,
);
return &this->public.pa_tnc_attribute;
diff --git a/src/libpts/tcg/tcg_pts_attr_simple_comp_evid.h b/src/libpts/tcg/tcg_pts_attr_simple_comp_evid.h
index 5da20e96e..3a80904c8 100644
--- a/src/libpts/tcg/tcg_pts_attr_simple_comp_evid.h
+++ b/src/libpts/tcg/tcg_pts_attr_simple_comp_evid.h
@@ -22,45 +22,12 @@
#define TCG_PTS_ATTR_SIMPLE_COMP_EVID_H_
typedef struct tcg_pts_attr_simple_comp_evid_t tcg_pts_attr_simple_comp_evid_t;
-typedef enum pts_attr_simple_comp_evid_flag_t pts_attr_simple_comp_evid_flag_t;
-typedef enum pts_pcr_transform_t pts_pcr_transform_t;
#include "tcg_attr.h"
-#include "pts/pts_meas_algo.h"
-#include "pts/pts_funct_comp_name.h"
+#include "pts/components/pts_comp_evidence.h"
#include "pa_tnc/pa_tnc_attr.h"
/**
- * PTS Simple Component Evidence Flags
- */
-enum pts_attr_simple_comp_evid_flag_t {
- /** PCR information fields inlcuded */
- PTS_SIMPLE_COMP_EVID_FLAG_PCR = 0,
- /** No Validation was attempted */
- PTS_SIMPLE_COMP_EVID_FLAG_NO_VALID = 1,
- /** Attempted validation, unable to verify */
- PTS_SIMPLE_COMP_EVID_FLAG_NO_VER = 2,
- /** Attempted validation, verification failed */
- PTS_SIMPLE_COMP_EVID_FLAG_VER_FAIL = 3,
- /** Attempted validation, verification passed */
- PTS_SIMPLE_COMP_EVID_FLAG_VER_PASS = 4,
-};
-
-/**
- * PTS PCR Transformations
- */
-enum pts_pcr_transform_t {
- /** No Transformation */
- PTS_PCR_TRANSFORM_NO = 0,
- /** Hash Value matched PCR size */
- PTS_PCR_TRANSFORM_MATCH = 1,
- /** Hash value shorter than PCR size */
- PTS_PCR_TRANSFORM_SHORT = 2,
- /** Hash value longer than PCR size */
- PTS_PCR_TRANSFORM_LONG = 3,
-};
-
-/**
* Class implementing the TCG PTS Simple Component Evidence attribute
*
*/
@@ -70,240 +37,22 @@ struct tcg_pts_attr_simple_comp_evid_t {
* Public PA-TNC attribute interface
*/
pa_tnc_attr_t pa_tnc_attribute;
-
- /**
- * Get flags for PTS Simple Component Evidence
- *
- * @return Set of flags
- */
- pts_attr_simple_comp_evid_flag_t (*get_flags)(tcg_pts_attr_simple_comp_evid_t *this);
/**
- * Set flags for PTS Simple Component Evidence
- *
- * @param flags Set of flags
- */
- void (*set_flags)(tcg_pts_attr_simple_comp_evid_t *this,
- pts_attr_simple_comp_evid_flag_t flags);
-
- /**
- * Get Sub-component Depth
- *
- * @return Sub-component Depth
- */
- u_int32_t (*get_sub_component_depth)(tcg_pts_attr_simple_comp_evid_t *this);
-
- /**
- * Get Specific Component Functional Name Vendor ID
- *
- * @return Component Functional Name Vendor ID
- */
- u_int32_t (*get_spec_comp_funct_name_vendor_id)(tcg_pts_attr_simple_comp_evid_t *this);
-
- /**
- * Get Family
- *
- * @return Functional Name Family
- */
- u_int8_t (*get_family)(tcg_pts_attr_simple_comp_evid_t *this);
-
- /**
- * Get Qualifier
- *
- * @return Functional Name Category Qualifier
- */
- pts_qualifier_t (*get_qualifier)(tcg_pts_attr_simple_comp_evid_t *this);
-
- /**
- * Set qualifier for Component Functional Name
- *
- * @param qualifier Functional Name Category Qualifier
- */
- void (*set_qualifier)(tcg_pts_attr_simple_comp_evid_t *this,
- pts_qualifier_t qualifier);
-
- /**
- * Get Special Component Functional Name
- *
- * @return Component Functional Name
- */
- pts_funct_comp_name_t (*get_comp_funct_name)(tcg_pts_attr_simple_comp_evid_t *this);
-
-
- /**
- * Set Component Functional Name
- *
- * @param name Component Functional Name
- */
- void (*set_comp_funct_name)(tcg_pts_attr_simple_comp_evid_t *this,
- pts_funct_comp_name_t name);
-
- /**
- * Get Measurement Type
- *
- * @return Measurement Type
- */
- u_int8_t (*get_measurement_type)(tcg_pts_attr_simple_comp_evid_t *this);
-
- /**
- * Get which PCR the functional component is extended into
- *
- * @return Number of PCR
- */
- u_int32_t (*get_extended_pcr)(tcg_pts_attr_simple_comp_evid_t *this);
-
- /**
- * Set which PCR the functional component is extended into
- *
- * @param pcr_number Number of PCR
- */
- void (*set_extended_pcr)(tcg_pts_attr_simple_comp_evid_t *this,
- u_int32_t extended_pcr);
-
- /**
- * Get Hash Algorithm
- *
- * @return Hash Algorithm
- */
- pts_meas_algorithms_t (*get_hash_algorithm)(tcg_pts_attr_simple_comp_evid_t *this);
-
- /**
- * Set Hash Algorithm
- *
- * @param hash_algorithm Hash Algorithm
- */
- void (*set_hash_algorithm)(tcg_pts_attr_simple_comp_evid_t *this,
- pts_meas_algorithms_t hash_algorithm);
-
- /**
- * Get PCR Transformation
- *
- * @return Transformation type of PCR
- */
- pts_pcr_transform_t (*get_pcr_trans)(tcg_pts_attr_simple_comp_evid_t *this);
-
- /**
- * Set PCR Transformation
- *
- * @param transformation Transformation type of PCR
- */
- void (*set_pcr_trans)(tcg_pts_attr_simple_comp_evid_t *this,
- pts_pcr_transform_t transformation);
-
- /**
- * Get Measurement Time
- *
- * @return Measurement time
- */
- chunk_t (*get_measurement_time)(tcg_pts_attr_simple_comp_evid_t *this);
-
- /**
- * Set Measurement Time
- *
- * @param time Measurement time
- */
- void (*set_measurement_time)(tcg_pts_attr_simple_comp_evid_t *this,
- chunk_t time);
-
- /**
- * Get Optional Policy URI
- *
- * @return Policy URI
- */
- chunk_t (*get_policy_uri)(tcg_pts_attr_simple_comp_evid_t *this);
-
- /**
- * Set Optional Policy URI
- *
- * @param policy_uri Policy URI
- */
- void (*set_policy_uri)(tcg_pts_attr_simple_comp_evid_t *this,
- chunk_t policy_uri);
-
- /**
- * Get Optional PCR Length
- *
- * @return Length of PCR before/after values
- */
- u_int16_t (*get_pcr_len)(tcg_pts_attr_simple_comp_evid_t *this);
-
- /**
- * Get Optional PCR before value
- *
- * @return PCR before value
- */
- chunk_t (*get_pcr_before_value)(tcg_pts_attr_simple_comp_evid_t *this);
-
- /**
- * Set Optional PCR before value
- *
- * @param pcr_before PCR before value
- */
- void (*set_pcr_before_value)(tcg_pts_attr_simple_comp_evid_t *this,
- chunk_t pcr_before);
-
- /**
- * Get Optional PCR after value
- *
- * @return PCR after value
- */
- chunk_t (*get_pcr_after_value)(tcg_pts_attr_simple_comp_evid_t *this);
-
- /**
- * Set Optional PCR after value
- *
- * @param pcr_after PCR after value
- */
- void (*set_pcr_after_value)(tcg_pts_attr_simple_comp_evid_t *this,
- chunk_t pcr_after);
-
- /**
- * Get Component Measurement
- *
- * @return Component Measurement Hash
- */
- chunk_t (*get_comp_measurement)(tcg_pts_attr_simple_comp_evid_t *this);
-
- /**
- * Set Component Measurement
+ * Get Component Evidence
*
- * @param measurement Component Measurement Hash
+ * @return Component Evidence
*/
- void (*set_comp_measurement)(tcg_pts_attr_simple_comp_evid_t *this,
- chunk_t measurement);
+ pts_comp_evidence_t* (*get_comp_evidence)(tcg_pts_attr_simple_comp_evid_t *this);
};
/**
* Creates an tcg_pts_attr_simple_comp_evid_t object
*
- * @param flags Set of flags
- * @param depth Sub-component Depth
- * @param vendor_id Component Functional Name Vendor ID
- * @param qualifier Functional Name Category Qualifier
- * @param name Component Functional Name
- * @param extended_pcr Which PCR the functional component is extended into
- * @param hash_algorithm Hash Algorithm
- * @param transformation Transformation type for PCR
- * @param measurement_time Measurement time
- * @param policy_uri Optional Policy URI
- * @param pcr_before Optional PCR before value
- * @param pcr_after Optional PCR after value
- * @param measurement Component Measurement
+ * @param evid Component Evidence
*/
-pa_tnc_attr_t* tcg_pts_attr_simple_comp_evid_create(pts_attr_simple_comp_evid_flag_t flags,
- u_int32_t depth,
- u_int32_t vendor_id,
- pts_qualifier_t qualifier,
- pts_funct_comp_name_t name,
- u_int32_t extended_pcr,
- pts_meas_algorithms_t hash_algorithm,
- pts_pcr_transform_t transformation,
- chunk_t measurement_time,
- chunk_t policy_uri,
- chunk_t pcr_before,
- chunk_t pcr_after,
- chunk_t measurement);
+pa_tnc_attr_t* tcg_pts_attr_simple_comp_evid_create(pts_comp_evidence_t *evid);
/**
* Creates an tcg_pts_attr_simple_comp_evid_t object from received data
diff --git a/src/libpts/tcg/tcg_pts_attr_simple_evid_final.c b/src/libpts/tcg/tcg_pts_attr_simple_evid_final.c
index fa2f6e5c6..27720d509 100644
--- a/src/libpts/tcg/tcg_pts_attr_simple_evid_final.c
+++ b/src/libpts/tcg/tcg_pts_attr_simple_evid_final.c
@@ -14,6 +14,7 @@
*/
#include "tcg_pts_attr_simple_evid_final.h"
+#include "pts/pts_simple_evid_final.h"
#include <pa_tnc/pa_tnc_msg.h>
#include <bio/bio_writer.h>
@@ -29,23 +30,23 @@ typedef struct private_tcg_pts_attr_simple_evid_final_t private_tcg_pts_attr_sim
* 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
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Flags | Reserved | Optional Composite Hash Alg |
+ * | Flags | Reserved | Optional Composite Hash Alg |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Optional TPM PCR Composite Length |
+ * | Optional TPM PCR Composite Length |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * ~ Optional TPM PCR Composite (Variable Length) ~
+ * ~ Optional TPM PCR Composite (Variable Length) ~
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Optional TPM Quote Signature Length |
+ * | Optional TPM Quote Signature Length |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * ~ Optional TPM Quote Signature (Variable Length) ~
+ * ~ Optional TPM Quote Signature (Variable Length) ~
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * ~ Optional Evidence Signature (Variable Length) ~
+ * ~ Optional Evidence Signature (Variable Length) ~
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
-#define PTS_SIMPLE_EVID_FINAL_SIZE 4
+#define PTS_SIMPLE_EVID_FINAL_SIZE 2
#define PTS_SIMPLE_EVID_FINAL_RESERVED 0x00
-
+#define PTS_SIMPLE_EVID_FINAL_FLAG_MASK 0xC0
/**
* Private data of an tcg_pts_attr_simple_evid_final_t object.
*/
@@ -75,11 +76,11 @@ struct private_tcg_pts_attr_simple_evid_final_t {
* Noskip flag
*/
bool noskip_flag;
-
+
/**
* Set of flags for Simple Evidence Final
*/
- pts_simple_evid_final_flag_t flags;
+ u_int8_t flags;
/**
* Optional Composite Hash Algorithm
@@ -94,13 +95,22 @@ struct private_tcg_pts_attr_simple_evid_final_t {
/**
* Optional TPM Quote Signature
*/
- chunk_t tpm_quote_sign;
+ chunk_t tpm_quote_sig;
+
+ /**
+ * Is Evidence Signature included?
+ */
+ bool has_evid_sig;
/**
* Optional Evidence Signature
*/
- chunk_t evid_sign;
+ chunk_t evid_sig;
+ /**
+ * Reference count
+ */
+ refcount_t ref;
};
METHOD(pa_tnc_attr_t, get_vendor_id, pen_t,
@@ -133,49 +143,62 @@ METHOD(pa_tnc_attr_t, set_noskip_flag,void,
this->noskip_flag = noskip;
}
+METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*,
+ private_tcg_pts_attr_simple_evid_final_t *this)
+{
+ ref_get(&this->ref);
+ return &this->public.pa_tnc_attribute;
+}
+
+METHOD(pa_tnc_attr_t, destroy, void,
+ private_tcg_pts_attr_simple_evid_final_t *this)
+{
+ if (ref_put(&this->ref))
+ {
+ free(this->value.ptr);
+ free(this->pcr_comp.ptr);
+ free(this->tpm_quote_sig.ptr);
+ free(this->evid_sig.ptr);
+ free(this);
+ }
+}
+
METHOD(pa_tnc_attr_t, build, void,
private_tcg_pts_attr_simple_evid_final_t *this)
{
bio_writer_t *writer;
- u_int8_t flags = 0;
-
- writer = bio_writer_create(PTS_SIMPLE_EVID_FINAL_SIZE);
+ u_int8_t flags;
- /* Determine the flags to set*/
- if (this->flags & PTS_SIMPLE_EVID_FINAL_FLAG_TPM_QUOTE_INFO)
- {
- flags += 64;
- }
- else if (this->flags & PTS_SIMPLE_EVID_FINAL_FLAG_TPM_QUOTE_INFO2)
- {
- flags += 128;
- }
- else if (this->flags & PTS_SIMPLE_EVID_FINAL_FLAG_TPM_QUOTE_INFO2_CAP_VER)
- {
- flags += 192;
- }
- if (this->flags & PTS_SIMPLE_EVID_FINAL_FLAG_EVID)
+ flags = this->flags & PTS_SIMPLE_EVID_FINAL_FLAG_MASK;
+
+ if (this->has_evid_sig)
{
- flags += 32;
+ flags |= PTS_SIMPLE_EVID_FINAL_EVID_SIG;
}
+
+ writer = bio_writer_create(PTS_SIMPLE_EVID_FINAL_SIZE);
writer->write_uint8 (writer, flags);
writer->write_uint8 (writer, PTS_SIMPLE_EVID_FINAL_RESERVED);
+
+ /** Optional Composite Hash Algorithm field is always present
+ * Field has value of all zeroes if not used.
+ * Implemented adhering the suggestion of Paul Sangster 28.Oct.2011
+ */
writer->write_uint16(writer, this->comp_hash_algorithm);
/* Optional fields */
- if (this->pcr_comp.ptr && this->pcr_comp.len > 0)
+ if (this->flags != PTS_SIMPLE_EVID_FINAL_NO)
{
writer->write_uint32 (writer, this->pcr_comp.len);
writer->write_data (writer, this->pcr_comp);
+
+ writer->write_uint32 (writer, this->tpm_quote_sig.len);
+ writer->write_data (writer, this->tpm_quote_sig);
}
- if (this->tpm_quote_sign.ptr && this->tpm_quote_sign.len > 0)
- {
- writer->write_uint32 (writer, this->tpm_quote_sign.len);
- writer->write_data (writer, this->tpm_quote_sign);
- }
- if (this->evid_sign.ptr && this->evid_sign.len > 0)
+
+ if (this->has_evid_sig)
{
- writer->write_data (writer, this->evid_sign);
+ writer->write_data (writer, this->evid_sig);
}
this->value = chunk_clone(writer->get_buf(writer));
@@ -186,9 +209,10 @@ METHOD(pa_tnc_attr_t, process, status_t,
private_tcg_pts_attr_simple_evid_final_t *this, u_int32_t *offset)
{
bio_reader_t *reader;
- u_int8_t flags;
- u_int8_t reserved;
+ u_int8_t flags, reserved;
u_int16_t algorithm;
+ u_int32_t pcr_comp_len, tpm_quote_sig_len, evid_sig_len;
+ status_t status = FAILED;
if (this->value.len < PTS_SIMPLE_EVID_FINAL_SIZE)
{
@@ -199,157 +223,110 @@ METHOD(pa_tnc_attr_t, process, status_t,
reader = bio_reader_create(this->value);
reader->read_uint8(reader, &flags);
-
- /* Determine the flags to set*/
- if (!((flags >> 7) & 1) && !((flags >> 6) & 1))
- {
- this->flags |= PTS_SIMPLE_EVID_FINAL_FLAG_NO;
- }
- else if (!((flags >> 7) & 1) && ((flags >> 6) & 1))
- {
- this->flags |= PTS_SIMPLE_EVID_FINAL_FLAG_TPM_QUOTE_INFO;
- }
- else if (((flags >> 7) & 1) && !((flags >> 6) & 1))
- {
- this->flags |= PTS_SIMPLE_EVID_FINAL_FLAG_TPM_QUOTE_INFO2;
- }
- else if (((flags >> 7) & 1) && ((flags >> 6) & 1))
- {
- this->flags |= PTS_SIMPLE_EVID_FINAL_FLAG_TPM_QUOTE_INFO2_CAP_VER;
- }
- if ((flags >> 5) & 1)
- {
- this->flags |= PTS_SIMPLE_EVID_FINAL_FLAG_EVID;
- }
-
reader->read_uint8(reader, &reserved);
+
+ this->flags = flags & PTS_SIMPLE_EVID_FINAL_FLAG_MASK;
+
+ this->has_evid_sig = (flags & PTS_SIMPLE_EVID_FINAL_EVID_SIG) != 0;
+
+ /** Optional Composite Hash Algorithm field is always present
+ * Field has value of all zeroes if not used.
+ * Implemented adhering the suggestion of Paul Sangster 28.Oct.2011
+ */
+
reader->read_uint16(reader, &algorithm);
this->comp_hash_algorithm = algorithm;
- /* Optional TPM PCR Composite field is included */
- if (!(this->flags & PTS_SIMPLE_EVID_FINAL_FLAG_NO))
+ /* Optional Composite Hash Algorithm and TPM PCR Composite fields */
+ if (this->flags != PTS_SIMPLE_EVID_FINAL_NO)
{
- u_int32_t pcr_comp_len;
- u_int32_t tpm_quote_sign_len;
- reader->read_uint32(reader, &pcr_comp_len);
- reader->read_data(reader, pcr_comp_len, &this->pcr_comp);
+ if (!reader->read_uint32(reader, &pcr_comp_len))
+ {
+ DBG1(DBG_TNC, "insufficient data for PTS Simple Evidence Final "
+ "PCR Composite Length");
+ goto end;
+ }
+ if (!reader->read_data(reader, pcr_comp_len, &this->pcr_comp))
+ {
+ DBG1(DBG_TNC, "insufficient data for PTS Simple Evidence Final "
+ "PCR Composite");
+ goto end;
+ }
this->pcr_comp = chunk_clone(this->pcr_comp);
- reader->read_uint32(reader, &tpm_quote_sign_len);
- reader->read_data(reader, tpm_quote_sign_len, &this->tpm_quote_sign);
- this->tpm_quote_sign = chunk_clone(this->tpm_quote_sign);
+
+ if (!reader->read_uint32(reader, &tpm_quote_sig_len))
+ {
+ DBG1(DBG_TNC, "insufficient data for PTS Simple Evidence Final "
+ "TPM Quote Singature Length");
+ goto end;
+ }
+ if (!reader->read_data(reader, tpm_quote_sig_len, &this->tpm_quote_sig))
+ {
+ DBG1(DBG_TNC, "insufficient data for PTS Simple Evidence Final "
+ "TPM Quote Singature");
+ goto end;
+ }
+ this->tpm_quote_sig = chunk_clone(this->tpm_quote_sig);
}
- /* Optional Evidence Signature field is included */
- if (this->flags & PTS_SIMPLE_EVID_FINAL_FLAG_EVID)
+ /* Optional Evidence Signature field */
+ if (this->has_evid_sig)
{
- u_int32_t evid_sign_len = reader->remaining(reader);
- reader->read_data(reader, evid_sign_len, &this->evid_sign);
- this->evid_sign = chunk_clone(this->evid_sign);
+ evid_sig_len = reader->remaining(reader);
+ reader->read_data(reader, evid_sig_len, &this->evid_sig);
+ this->evid_sig = chunk_clone(this->evid_sig);
}
reader->destroy(reader);
return SUCCESS;
-}
-
-METHOD(pa_tnc_attr_t, destroy, void,
- private_tcg_pts_attr_simple_evid_final_t *this)
-{
- free(this->value.ptr);
- free(this->pcr_comp.ptr);
- free(this->tpm_quote_sign.ptr);
- free(this->evid_sign.ptr);
- free(this);
-}
-
-METHOD(tcg_pts_attr_simple_evid_final_t, get_flags, pts_simple_evid_final_flag_t,
- private_tcg_pts_attr_simple_evid_final_t *this)
-{
- return this->flags;
-}
-
-METHOD(tcg_pts_attr_simple_evid_final_t, set_flags, void,
- private_tcg_pts_attr_simple_evid_final_t *this, pts_simple_evid_final_flag_t flags)
-{
- this->flags = flags;
-}
-METHOD(tcg_pts_attr_simple_evid_final_t, get_comp_hash_algorithm, pts_meas_algorithms_t,
- private_tcg_pts_attr_simple_evid_final_t *this)
-{
- return this->comp_hash_algorithm;
+end:
+ reader->destroy(reader);
+ return status;
}
-METHOD(tcg_pts_attr_simple_evid_final_t, set_comp_hash_algorithm, void,
- private_tcg_pts_attr_simple_evid_final_t *this, pts_meas_algorithms_t comp_hash_algorithm)
+METHOD(tcg_pts_attr_simple_evid_final_t, get_quote_info, u_int8_t,
+ private_tcg_pts_attr_simple_evid_final_t *this,
+ pts_meas_algorithms_t *comp_hash_algo, chunk_t *pcr_comp, chunk_t *tpm_quote_sig)
{
- this->comp_hash_algorithm = comp_hash_algorithm;
-}
-
-METHOD(tcg_pts_attr_simple_evid_final_t, get_comp_pcr_len, u_int32_t,
- private_tcg_pts_attr_simple_evid_final_t *this)
-{
- if (this->pcr_comp.ptr && this->pcr_comp.len > 0)
+ if (comp_hash_algo)
{
- return this->pcr_comp.len;
+ *comp_hash_algo = this->comp_hash_algorithm;
}
- return 0;
-}
-
-METHOD(tcg_pts_attr_simple_evid_final_t, get_pcr_comp, chunk_t,
- private_tcg_pts_attr_simple_evid_final_t *this)
-{
- return this->pcr_comp;
-}
-
-METHOD(tcg_pts_attr_simple_evid_final_t, set_pcr_comp, void,
- private_tcg_pts_attr_simple_evid_final_t *this, chunk_t pcr_comp)
-{
- this->pcr_comp = pcr_comp;
-}
-
-METHOD(tcg_pts_attr_simple_evid_final_t, get_tpm_quote_sign_len, u_int32_t,
- private_tcg_pts_attr_simple_evid_final_t *this)
-{
- if (this->tpm_quote_sign.ptr && this->tpm_quote_sign.len > 0)
+ if (pcr_comp)
{
- return this->tpm_quote_sign.len;
+ *pcr_comp = this->pcr_comp;
}
- return 0;
-}
-
-METHOD(tcg_pts_attr_simple_evid_final_t, get_tpm_quote_sign, chunk_t,
- private_tcg_pts_attr_simple_evid_final_t *this)
-{
- return this->tpm_quote_sign;
-}
-
-METHOD(tcg_pts_attr_simple_evid_final_t, set_tpm_quote_sign, void,
- private_tcg_pts_attr_simple_evid_final_t *this, chunk_t tpm_quote_sign)
-{
- this->tpm_quote_sign = tpm_quote_sign;
+ if (tpm_quote_sig)
+ {
+ *tpm_quote_sig = this->tpm_quote_sig;
+ }
+ return this->flags;
}
-METHOD(tcg_pts_attr_simple_evid_final_t, get_evid_sign, chunk_t,
- private_tcg_pts_attr_simple_evid_final_t *this)
+METHOD(tcg_pts_attr_simple_evid_final_t, get_evid_sig, bool,
+ private_tcg_pts_attr_simple_evid_final_t *this, chunk_t *evid_sig)
{
- return this->evid_sign;
+ if (evid_sig)
+ {
+ *evid_sig = this->evid_sig;
+ }
+ return this->has_evid_sig;
}
-METHOD(tcg_pts_attr_simple_evid_final_t, set_evid_sign, void,
- private_tcg_pts_attr_simple_evid_final_t *this, chunk_t evid_sign)
+METHOD(tcg_pts_attr_simple_evid_final_t, set_evid_sig, void,
+ private_tcg_pts_attr_simple_evid_final_t *this, chunk_t evid_sig)
{
- this->evid_sign = evid_sign;
+ this->evid_sig = evid_sig;
+ this->has_evid_sig = TRUE;
}
/**
* Described in header.
*/
-pa_tnc_attr_t *tcg_pts_attr_simple_evid_final_create(
- pts_simple_evid_final_flag_t flags,
- pts_meas_algorithms_t comp_hash_algorithm,
- chunk_t pcr_comp,
- chunk_t tpm_quote_sign,
- chunk_t evid_sign)
+pa_tnc_attr_t *tcg_pts_attr_simple_evid_final_create(u_int8_t flags,
+ pts_meas_algorithms_t comp_hash_algorithm,
+ chunk_t pcr_comp, chunk_t tpm_quote_sig)
{
private_tcg_pts_attr_simple_evid_final_t *this;
@@ -363,28 +340,20 @@ pa_tnc_attr_t *tcg_pts_attr_simple_evid_final_create(
.set_noskip_flag = _set_noskip_flag,
.build = _build,
.process = _process,
+ .get_ref = _get_ref,
.destroy = _destroy,
},
- .get_flags= _get_flags,
- .set_flags= _set_flags,
- .get_comp_hash_algorithm = _get_comp_hash_algorithm,
- .set_comp_hash_algorithm = _set_comp_hash_algorithm,
- .get_comp_pcr_len = _get_comp_pcr_len,
- .get_pcr_comp = _get_pcr_comp,
- .set_pcr_comp = _set_pcr_comp,
- .get_tpm_quote_sign_len = _get_tpm_quote_sign_len,
- .get_tpm_quote_sign = _get_tpm_quote_sign,
- .set_tpm_quote_sign = _set_tpm_quote_sign,
- .get_evid_sign = _get_evid_sign,
- .set_evid_sign = _set_evid_sign,
+ .get_quote_info = _get_quote_info,
+ .get_evid_sig = _get_evid_sig,
+ .set_evid_sig = _set_evid_sig,
},
.vendor_id = PEN_TCG,
.type = TCG_PTS_SIMPLE_EVID_FINAL,
.flags = flags,
.comp_hash_algorithm = comp_hash_algorithm,
.pcr_comp = pcr_comp,
- .tpm_quote_sign = tpm_quote_sign,
- .evid_sign = evid_sign,
+ .tpm_quote_sig = tpm_quote_sig,
+ .ref = 1,
);
return &this->public.pa_tnc_attribute;
@@ -408,24 +377,17 @@ pa_tnc_attr_t *tcg_pts_attr_simple_evid_final_create_from_data(chunk_t data)
.set_noskip_flag = _set_noskip_flag,
.build = _build,
.process = _process,
+ .get_ref = _get_ref,
.destroy = _destroy,
},
- .get_flags= _get_flags,
- .set_flags= _set_flags,
- .get_comp_hash_algorithm = _get_comp_hash_algorithm,
- .set_comp_hash_algorithm = _set_comp_hash_algorithm,
- .get_comp_pcr_len = _get_comp_pcr_len,
- .get_pcr_comp = _get_pcr_comp,
- .set_pcr_comp = _set_pcr_comp,
- .get_tpm_quote_sign_len = _get_tpm_quote_sign_len,
- .get_tpm_quote_sign = _get_tpm_quote_sign,
- .set_tpm_quote_sign = _set_tpm_quote_sign,
- .get_evid_sign = _get_evid_sign,
- .set_evid_sign = _set_evid_sign,
+ .get_quote_info = _get_quote_info,
+ .get_evid_sig = _get_evid_sig,
+ .set_evid_sig = _set_evid_sig,
},
.vendor_id = PEN_TCG,
.type = TCG_PTS_SIMPLE_EVID_FINAL,
.value = chunk_clone(data),
+ .ref = 1,
);
return &this->public.pa_tnc_attribute;
diff --git a/src/libpts/tcg/tcg_pts_attr_simple_evid_final.h b/src/libpts/tcg/tcg_pts_attr_simple_evid_final.h
index 351981921..3d98bfce7 100644
--- a/src/libpts/tcg/tcg_pts_attr_simple_evid_final.h
+++ b/src/libpts/tcg/tcg_pts_attr_simple_evid_final.h
@@ -22,32 +22,12 @@
#define TCG_PTS_ATTR_SIMPLE_EVID_FINAL_H_
typedef struct tcg_pts_attr_simple_evid_final_t tcg_pts_attr_simple_evid_final_t;
-typedef enum pts_simple_evid_final_flag_t pts_simple_evid_final_flag_t;
#include "tcg_attr.h"
#include "tcg_pts_attr_meas_algo.h"
#include "pa_tnc/pa_tnc_attr.h"
/**
- * PTS Simple Evidence Final Flags
- */
-enum pts_simple_evid_final_flag_t {
- /** No Optional TPM PCR Composite nor Optional TPM Quote Signature fields included */
- PTS_SIMPLE_EVID_FINAL_FLAG_NO = 0,
- /** Optional TPM PCR Composite and Optional TPM Quote Signature fields included */
- /** using TPM_QUOTE_INFO */
- PTS_SIMPLE_EVID_FINAL_FLAG_TPM_QUOTE_INFO = 1,
- /** Optional TPM PCR Composite and Optional TPM Quote Signature fields included */
- /** using TPM_QUOTE_INFO2, TPM_CAP_VERSION_INFO was not appended */
- PTS_SIMPLE_EVID_FINAL_FLAG_TPM_QUOTE_INFO2 = 2,
- /** Optional TPM PCR Composite and Optional TPM Quote Signature fields included */
- /** using TPM_QUOTE_INFO2, TPM_CAP_VERSION_INFO was appended */
- PTS_SIMPLE_EVID_FINAL_FLAG_TPM_QUOTE_INFO2_CAP_VER = 3,
- /** Optional Evidence Signature included */
- PTS_SIMPLE_EVID_FINAL_FLAG_EVID = 4,
-};
-
-/**
* Class implementing the TCG PTS Simple Evidence Final attribute
*
*/
@@ -57,112 +37,49 @@ struct tcg_pts_attr_simple_evid_final_t {
* Public PA-TNC attribute interface
*/
pa_tnc_attr_t pa_tnc_attribute;
-
- /**
- * Get flags for PTS Simple Evidence Final
- *
- * @return Set of flags
- */
- pts_simple_evid_final_flag_t (*get_flags)(tcg_pts_attr_simple_evid_final_t *this);
/**
- * Set flags for PTS Simple Evidence Final
- *
- * @param flags Set of flags
- */
- void (*set_flags)(tcg_pts_attr_simple_evid_final_t *this,
- pts_simple_evid_final_flag_t flags);
-
- /**
- * Get Optional Composite Hash Algorithm
- *
- * @return Composite Hash Algorithm
- */
- pts_meas_algorithms_t (*get_comp_hash_algorithm)(tcg_pts_attr_simple_evid_final_t *this);
-
- /**
- * Set Optional Composite Hash Algorithm
+ * Get Optional PCR Composite and TPM Quote Signature
*
- * @param hash_algorithm Composite Hash Algorithm
+ * @param comp_hash_algo Optional Composite Hash Algorithm
+ * @param pcr_comp Optional PCR Composite
+ * @param tpm_quote sig Optional TPM Quote Signature
+ * @return PTS_SIMPLE_EVID_FINAL flags
*/
- void (*set_comp_hash_algorithm)(tcg_pts_attr_simple_evid_final_t *this,
- pts_meas_algorithms_t hash_algorithm);
-
- /**
- * Get Optional TPM PCR Composite Length
- *
- * @return Length of Composite PCR Length
- */
- u_int32_t (*get_comp_pcr_len)(tcg_pts_attr_simple_evid_final_t *this);
-
- /**
- * Get Optional TPM PCR Composite
- *
- * @return PCR Composite
- */
- chunk_t (*get_pcr_comp)(tcg_pts_attr_simple_evid_final_t *this);
-
- /**
- * Set Optional TPM PCR Composite
- *
- * @param pcr_comp PCR Composite
- */
- void (*set_pcr_comp)(tcg_pts_attr_simple_evid_final_t *this,
- chunk_t pcr_comp);
-
- /**
- * Get Optional TPM Quote Signature Length
- *
- * @return TPM Quote Signature Length
- */
- u_int32_t (*get_tpm_quote_sign_len)(tcg_pts_attr_simple_evid_final_t *this);
-
- /**
- * Get Optional TPM Quote Signature
- *
- * @return TPM Quote Signature
- */
- chunk_t (*get_tpm_quote_sign)(tcg_pts_attr_simple_evid_final_t *this);
-
- /**
- * Set Optional TPM Quote Signature
- *
- * @param tpm_quote_sign TPM Quote Signature
- */
- void (*set_tpm_quote_sign)(tcg_pts_attr_simple_evid_final_t *this,
- chunk_t tpm_quote_sign);
+ u_int8_t (*get_quote_info)(tcg_pts_attr_simple_evid_final_t *this,
+ pts_meas_algorithms_t *comp_hash_algo,
+ chunk_t *pcr_comp, chunk_t *tpm_quote_sig);
/**
* Get Optional Evidence Signature
*
- * @return Optional Evidence Signature
+ * @evid_sig Optional Evidence Signature
+ * @return TRUE if Evidence Signature is available
*/
- chunk_t (*get_evid_sign)(tcg_pts_attr_simple_evid_final_t *this);
-
+ bool (*get_evid_sig)(tcg_pts_attr_simple_evid_final_t *this, chunk_t *evid_sig);
+
/**
* Set Optional Evidence Signature
*
- * @param signature Optional Evidence Signature
+ * @evid_sig Optional Evidence Signature
*/
- void (*set_evid_sign)(tcg_pts_attr_simple_evid_final_t *this,
- chunk_t signature);
+ void (*set_evid_sig)(tcg_pts_attr_simple_evid_final_t *this, chunk_t evid_sig);
};
/**
* Creates an tcg_pts_attr_simple_evid_final_t object
- *
+ *
* @param flags Set of flags
* @param comp_hash_algorithm Composite Hash Algorithm
* @param pcr_comp Optional TPM PCR Composite
* @param tpm_quote_sign Optional TPM Quote Signature
- * @param evid_sign Optional Evidence Signature
*/
-pa_tnc_attr_t* tcg_pts_attr_simple_evid_final_create(pts_simple_evid_final_flag_t flags,
+pa_tnc_attr_t* tcg_pts_attr_simple_evid_final_create(
+ u_int8_t flags,
pts_meas_algorithms_t comp_hash_algorithm,
chunk_t pcr_comp,
- chunk_t tpm_quote_sign,
- chunk_t evid_sign);
+ chunk_t tpm_quote_sign);
/**
* Creates an tcg_pts_attr_simple_evid_final_t object from received data
diff --git a/src/libpts/tcg/tcg_pts_attr_tpm_version_info.c b/src/libpts/tcg/tcg_pts_attr_tpm_version_info.c
index a1e91cccf..944a12cc9 100644
--- a/src/libpts/tcg/tcg_pts_attr_tpm_version_info.c
+++ b/src/libpts/tcg/tcg_pts_attr_tpm_version_info.c
@@ -72,6 +72,11 @@ struct private_tcg_pts_attr_tpm_version_info_t {
* TPM Version Information
*/
chunk_t tpm_version_info;
+
+ /**
+ * Reference count
+ */
+ refcount_t ref;
};
METHOD(pa_tnc_attr_t, get_vendor_id, pen_t,
@@ -135,12 +140,22 @@ METHOD(pa_tnc_attr_t, process, status_t,
return SUCCESS;
}
+METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*,
+ private_tcg_pts_attr_tpm_version_info_t *this)
+{
+ ref_get(&this->ref);
+ return &this->public.pa_tnc_attribute;
+}
+
METHOD(pa_tnc_attr_t, destroy, void,
private_tcg_pts_attr_tpm_version_info_t *this)
{
- free(this->value.ptr);
- free(this->tpm_version_info.ptr);
- free(this);
+ if (ref_put(&this->ref))
+ {
+ free(this->value.ptr);
+ free(this->tpm_version_info.ptr);
+ free(this);
+ }
}
METHOD(tcg_pts_attr_tpm_version_info_t, get_tpm_version_info, chunk_t,
@@ -173,6 +188,7 @@ pa_tnc_attr_t *tcg_pts_attr_tpm_version_info_create(chunk_t tpm_version_info)
.set_noskip_flag = _set_noskip_flag,
.build = _build,
.process = _process,
+ .get_ref = _get_ref,
.destroy = _destroy,
},
.get_tpm_version_info = _get_tpm_version_info,
@@ -180,7 +196,8 @@ pa_tnc_attr_t *tcg_pts_attr_tpm_version_info_create(chunk_t tpm_version_info)
},
.vendor_id = PEN_TCG,
.type = TCG_PTS_TPM_VERSION_INFO,
- .tpm_version_info = tpm_version_info,
+ .tpm_version_info = chunk_clone(tpm_version_info),
+ .ref = 1,
);
return &this->public.pa_tnc_attribute;
@@ -204,6 +221,7 @@ pa_tnc_attr_t *tcg_pts_attr_tpm_version_info_create_from_data(chunk_t data)
.set_noskip_flag = _set_noskip_flag,
.build = _build,
.process = _process,
+ .get_ref = _get_ref,
.destroy = _destroy,
},
.get_tpm_version_info = _get_tpm_version_info,
@@ -212,6 +230,7 @@ pa_tnc_attr_t *tcg_pts_attr_tpm_version_info_create_from_data(chunk_t data)
.vendor_id = PEN_TCG,
.type = TCG_PTS_TPM_VERSION_INFO,
.value = chunk_clone(data),
+ .ref = 1,
);
return &this->public.pa_tnc_attribute;
diff --git a/src/libpts/tcg/tcg_pts_attr_unix_file_meta.c b/src/libpts/tcg/tcg_pts_attr_unix_file_meta.c
index 0f644fdf9..a9f4a115d 100644
--- a/src/libpts/tcg/tcg_pts_attr_unix_file_meta.c
+++ b/src/libpts/tcg/tcg_pts_attr_unix_file_meta.c
@@ -67,6 +67,7 @@ typedef struct private_tcg_pts_attr_file_meta_t private_tcg_pts_attr_file_meta_t
#define PTS_FILE_META_SIZE 8
#define PTS_FILE_MEAS_RESERVED 0x00
+#define PTS_FILE_METADATA_SIZE 52
/**
* Private data of an tcg_pts_attr_file_meta_t object.
@@ -103,6 +104,10 @@ struct private_tcg_pts_attr_file_meta_t {
*/
pts_file_meta_t *metadata;
+ /**
+ * Reference count
+ */
+ refcount_t ref;
};
METHOD(pa_tnc_attr_t, get_vendor_id, pen_t,
@@ -140,52 +145,29 @@ METHOD(pa_tnc_attr_t, build, void,
{
bio_writer_t *writer;
enumerator_t *enumerator;
+ pts_file_metadata_t *entry;
u_int64_t number_of_files;
- char *filename;
- u_int16_t meta_length;
- pts_file_type_t type;
- u_int64_t filesize;
- time_t create_time;
- time_t last_modify_time;
- time_t last_access_time;
- u_int64_t owner_id;
- u_int64_t group_id;
number_of_files = this->metadata->get_file_count(this->metadata);
writer = bio_writer_create(PTS_FILE_META_SIZE);
- /* Write the 64 bit integer field - number of files as two 32 bit parts */
- writer->write_uint32(writer, number_of_files >> 32);
- writer->write_uint32(writer, number_of_files & 0xffffffff);
+ writer->write_uint64(writer, number_of_files);
enumerator = this->metadata->create_enumerator(this->metadata);
- while (enumerator->enumerate(enumerator, &filename, &meta_length, &type,
- &filesize, &filesize, &create_time, &last_modify_time, &last_access_time,
- &owner_id, &group_id))
+ while (enumerator->enumerate(enumerator, &entry))
{
- u_int64_t create_time64 = (u_int64_t)create_time;
- u_int64_t modify_time64 = (u_int64_t)last_modify_time;
- u_int64_t access_time64 = (u_int64_t)last_access_time;
-
- writer->write_uint16(writer, PTS_FILE_METADATA_SIZE + strlen(filename));
- writer->write_uint8 (writer, type);
+ writer->write_uint16(writer, PTS_FILE_METADATA_SIZE +
+ strlen(entry->filename));
+ writer->write_uint8 (writer, entry->type);
writer->write_uint8 (writer, PTS_FILE_MEAS_RESERVED);
-
- /* Write the 64 bit integer fields as two 32 bit parts */
- writer->write_uint32(writer, filesize >> 32);
- writer->write_uint32(writer, filesize & 0xffffffff);
- writer->write_uint32(writer, create_time64 >> 32);
- writer->write_uint32(writer, create_time64 & 0xffffffff);
- writer->write_uint32(writer, modify_time64 >> 32);
- writer->write_uint32(writer, modify_time64 & 0xffffffff);
- writer->write_uint32(writer, access_time64 >> 32);
- writer->write_uint32(writer, access_time64 & 0xffffffff);
- writer->write_uint32(writer, owner_id >> 32);
- writer->write_uint32(writer, owner_id & 0xffffffff);
- writer->write_uint32(writer, group_id >> 32);
- writer->write_uint32(writer, group_id & 0xffffffff);
-
- writer->write_data (writer, chunk_create(filename, strlen(filename)));
+ writer->write_uint64(writer, entry->filesize);
+ writer->write_uint64(writer, entry->created);
+ writer->write_uint64(writer, entry->modified);
+ writer->write_uint64(writer, entry->accessed);
+ writer->write_uint64(writer, entry->owner);
+ writer->write_uint64(writer, entry->group);
+ writer->write_data (writer, chunk_create(entry->filename,
+ strlen(entry->filename)));
}
enumerator->destroy(enumerator);
@@ -197,36 +179,12 @@ METHOD(pa_tnc_attr_t, process, status_t,
private_tcg_pts_attr_file_meta_t *this, u_int32_t *offset)
{
bio_reader_t *reader;
- int number_of_files;
- u_int32_t number_of_files32;
-
- u_int16_t meta_length;
- pts_file_type_t type;
- u_int8_t type8;
- u_int8_t reserved;
-
- int filesize;
- u_int32_t filesize32;
-
- int create_time;
- u_int32_t create_time32;
- time_t create_time_t;
- int modify_time;
- u_int32_t modify_time32;
- time_t modify_time_t;
- int access_time;
- u_int32_t access_time32;
- time_t access_time_t;
-
- int owner_id;
- u_int32_t owner_id32;
-
- int group_id;
- u_int32_t group_id32;
-
- size_t len;
+ pts_file_metadata_t *entry;
+ u_int8_t type, reserved;
+ u_int16_t len;
+ u_int64_t number_of_files, filesize, created, modified, accessed;
+ u_int64_t owner, group;
chunk_t filename;
- char buf[BUF_LEN];
status_t status = FAILED;
if (this->value.len < PTS_FILE_META_SIZE)
@@ -236,124 +194,76 @@ METHOD(pa_tnc_attr_t, process, status_t,
return FAILED;
}
reader = bio_reader_create(this->value);
+ reader->read_uint64(reader, &number_of_files);
- reader->read_uint32(reader, &number_of_files32);
- number_of_files = (sizeof(number_of_files) > 4) ? number_of_files32 << 32 : 0;
- reader->read_uint32(reader, &number_of_files32);
- number_of_files += number_of_files32;
-
this->metadata = pts_file_meta_create();
while (number_of_files--)
{
- if (!reader->read_uint16(reader, &meta_length))
+ if (!reader->read_uint16(reader, &len))
{
DBG1(DBG_TNC, "insufficient data for PTS file metadata length");
goto end;
}
- if (!reader->read_uint8 (reader, &type8))
+ if (!reader->read_uint8(reader, &type))
{
DBG1(DBG_TNC, "insufficient data for file type");
goto end;
}
- type = (pts_file_type_t)type8;
- if (!reader->read_uint8 (reader, &reserved))
+ if (!reader->read_uint8(reader, &reserved))
{
DBG1(DBG_TNC, "insufficient data for reserved field");
goto end;
}
- if (!reader->read_uint32(reader, &filesize32))
- {
- DBG1(DBG_TNC, "insufficient data for file size");
- goto end;
- }
- filesize = (sizeof(filesize) > 4) ? filesize32 << 32 : 0;
- if (!reader->read_uint32(reader, &filesize32))
- {
- DBG1(DBG_TNC, "insufficient data for file size");
- goto end;
- }
- filesize += filesize32;
-
- if (!reader->read_uint32(reader, &create_time32))
- {
- DBG1(DBG_TNC, "insufficient data for file size");
- goto end;
- }
- create_time = (sizeof(create_time) > 4) ? create_time32 << 32 : 0;
- if (!reader->read_uint32(reader, &create_time32))
- {
- DBG1(DBG_TNC, "insufficient data for file size");
- goto end;
- }
- create_time += create_time32;
- create_time_t = (time_t)create_time;
-
- if (!reader->read_uint32(reader, &modify_time32))
+ if (!reader->read_uint64(reader, &filesize))
{
DBG1(DBG_TNC, "insufficient data for file size");
goto end;
}
- modify_time = (sizeof(modify_time) > 4) ? modify_time32 << 32 : 0;
- if (!reader->read_uint32(reader, &modify_time32))
+ if (!reader->read_uint64(reader, &created))
{
- DBG1(DBG_TNC, "insufficient data for file size");
+ DBG1(DBG_TNC, "insufficient data for file create time");
goto end;
}
- modify_time += modify_time32;
- modify_time_t = (time_t)modify_time;
-
- if (!reader->read_uint32(reader, &access_time32))
+ if (!reader->read_uint64(reader, &modified))
{
- DBG1(DBG_TNC, "insufficient data for file size");
+ DBG1(DBG_TNC, "insufficient data for last modify time");
goto end;
}
- access_time = (sizeof(access_time) > 4) ? access_time32 << 32 : 0;
- if (!reader->read_uint32(reader, &access_time32))
+ if (!reader->read_uint64(reader, &accessed))
{
- DBG1(DBG_TNC, "insufficient data for file size");
+ DBG1(DBG_TNC, "insufficient data for last access time");
goto end;
}
- access_time += access_time32;
- access_time_t = (time_t)access_time;
-
- if (!reader->read_uint32(reader, &owner_id32))
+ if (!reader->read_uint64(reader, &owner))
{
- DBG1(DBG_TNC, "insufficient data for file size");
+ DBG1(DBG_TNC, "insufficient data for owner id");
goto end;
}
- owner_id = (sizeof(owner_id) > 4) ? owner_id32 << 32 : 0;
- if (!reader->read_uint32(reader, &owner_id32))
+ if (!reader->read_uint64(reader, &group))
{
- DBG1(DBG_TNC, "insufficient data for file size");
+ DBG1(DBG_TNC, "insufficient data for group id");
goto end;
}
- owner_id += owner_id32;
-
- if (!reader->read_uint32(reader, &group_id32))
- {
- DBG1(DBG_TNC, "insufficient data for file size");
- goto end;
- }
- group_id = (sizeof(group_id) > 4) ? group_id32 << 32 : 0;
- if (!reader->read_uint32(reader, &group_id32))
- {
- DBG1(DBG_TNC, "insufficient data for file size");
- goto end;
- }
- group_id += group_id32;
-
- if (!reader->read_data(reader, meta_length - PTS_FILE_METADATA_SIZE, &filename))
+ if (!reader->read_data(reader, len - PTS_FILE_METADATA_SIZE, &filename))
{
DBG1(DBG_TNC, "insufficient data for filename");
goto end;
}
- len = min(filename.len, BUF_LEN-1);
- memcpy(buf, filename.ptr, len);
- buf[len] = '\0';
- this->metadata->add(this->metadata, buf, type, filesize, create_time_t,
- modify_time_t, access_time_t, owner_id, group_id);
+ entry = malloc_thing(pts_file_metadata_t);
+ entry->type = type;
+ entry->filesize = filesize;
+ entry->created = created;
+ entry->modified = modified;
+ entry->accessed = accessed;
+ entry->owner = owner;
+ entry->group = group;
+ entry->filename = malloc(filename.len + 1);
+ entry->filename[filename.len] = '\0';
+ memcpy(entry->filename, filename.ptr, filename.len);
+
+ this->metadata->add(this->metadata, entry);
}
status = SUCCESS;
@@ -362,12 +272,22 @@ end:
return status;
}
+METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*,
+ private_tcg_pts_attr_file_meta_t *this)
+{
+ ref_get(&this->ref);
+ return &this->public.pa_tnc_attribute;
+}
+
METHOD(pa_tnc_attr_t, destroy, void,
private_tcg_pts_attr_file_meta_t *this)
{
- this->metadata->destroy(this->metadata);
- free(this->value.ptr);
- free(this);
+ if (ref_put(&this->ref))
+ {
+ this->metadata->destroy(this->metadata);
+ free(this->value.ptr);
+ free(this);
+ }
}
METHOD(tcg_pts_attr_file_meta_t, get_metadata, pts_file_meta_t*,
@@ -393,6 +313,7 @@ pa_tnc_attr_t *tcg_pts_attr_unix_file_meta_create(pts_file_meta_t *metadata)
.set_noskip_flag = _set_noskip_flag,
.build = _build,
.process = _process,
+ .get_ref = _get_ref,
.destroy = _destroy,
},
.get_metadata = _get_metadata,
@@ -400,6 +321,7 @@ pa_tnc_attr_t *tcg_pts_attr_unix_file_meta_create(pts_file_meta_t *metadata)
.vendor_id = PEN_TCG,
.type = TCG_PTS_UNIX_FILE_META,
.metadata = metadata,
+ .ref = 1,
);
return &this->public.pa_tnc_attribute;
@@ -423,6 +345,7 @@ pa_tnc_attr_t *tcg_pts_attr_unix_file_meta_create_from_data(chunk_t data)
.set_noskip_flag = _set_noskip_flag,
.build = _build,
.process = _process,
+ .get_ref = _get_ref,
.destroy = _destroy,
},
.get_metadata = _get_metadata,
@@ -430,6 +353,7 @@ pa_tnc_attr_t *tcg_pts_attr_unix_file_meta_create_from_data(chunk_t data)
.vendor_id = PEN_TCG,
.type = TCG_PTS_UNIX_FILE_META,
.value = chunk_clone(data),
+ .ref = 1,
);
return &this->public.pa_tnc_attribute;
diff --git a/src/libradius/Makefile.am b/src/libradius/Makefile.am
new file mode 100644
index 000000000..5672f7b84
--- /dev/null
+++ b/src/libradius/Makefile.am
@@ -0,0 +1,11 @@
+
+INCLUDES = -I$(top_srcdir)/src/libstrongswan
+
+ipseclib_LTLIBRARIES = libradius.la
+libradius_la_SOURCES = \
+ radius_message.h radius_message.c \
+ radius_socket.h radius_socket.c \
+ radius_client.h radius_client.c \
+ radius_config.h radius_config.c \
+ radius_mppe.h
+
diff --git a/src/libcharon/plugins/eap_radius/radius_client.c b/src/libradius/radius_client.c
index 245308e59..acdac78c9 100644
--- a/src/libcharon/plugins/eap_radius/radius_client.c
+++ b/src/libradius/radius_client.c
@@ -14,14 +14,12 @@
*/
#include "radius_client.h"
-
-#include "eap_radius_plugin.h"
-#include "radius_server.h"
+#include "radius_config.h"
#include <unistd.h>
#include <errno.h>
-#include <daemon.h>
+#include <debug.h>
#include <utils/host.h>
#include <utils/linked_list.h>
#include <threading/condvar.h>
@@ -40,9 +38,9 @@ struct private_radius_client_t {
radius_client_t public;
/**
- * Selected RADIUS server
+ * Selected RADIUS server configuration
*/
- radius_server_t *server;
+ radius_config_t *config;
/**
* RADIUS servers State attribute
@@ -86,37 +84,41 @@ METHOD(radius_client_t, request, radius_message_t*,
char virtual[] = {0x00,0x00,0x00,0x05};
radius_socket_t *socket;
radius_message_t *res;
+ chunk_t data;
/* we add the "Virtual" NAS-Port-Type, as we SHOULD include one */
req->add(req, RAT_NAS_PORT_TYPE, chunk_create(virtual, sizeof(virtual)));
/* add our NAS-Identifier */
req->add(req, RAT_NAS_IDENTIFIER,
- this->server->get_nas_identifier(this->server));
+ this->config->get_nas_identifier(this->config));
/* add State attribute, if server sent one */
if (this->state.ptr)
{
req->add(req, RAT_STATE, this->state);
}
- socket = this->server->get_socket(this->server);
+ socket = this->config->get_socket(this->config);
DBG1(DBG_CFG, "sending RADIUS %N to server '%s'", radius_message_code_names,
- req->get_code(req), this->server->get_name(this->server));
+ req->get_code(req), this->config->get_name(this->config));
+
res = socket->request(socket, req);
if (res)
{
DBG1(DBG_CFG, "received RADIUS %N from server '%s'",
radius_message_code_names, res->get_code(res),
- this->server->get_name(this->server));
+ this->config->get_name(this->config));
+ data = res->get_encoding(res);
+ DBG3(DBG_CFG, "%B", &data);
+
save_state(this, res);
if (res->get_code(res) == RMC_ACCESS_ACCEPT)
{
chunk_clear(&this->msk);
this->msk = socket->decrypt_msk(socket, req, res);
}
- this->server->put_socket(this->server, socket, TRUE);
+ this->config->put_socket(this->config, socket, TRUE);
return res;
}
- this->server->put_socket(this->server, socket, FALSE);
- charon->bus->alert(charon->bus, ALERT_RADIUS_NOT_RESPONDING);
+ this->config->put_socket(this->config, socket, FALSE);
return NULL;
}
@@ -129,7 +131,7 @@ METHOD(radius_client_t, get_msk, chunk_t,
METHOD(radius_client_t, destroy, void,
private_radius_client_t *this)
{
- this->server->destroy(this->server);
+ this->config->destroy(this->config);
chunk_clear(&this->msk);
free(this->state.ptr);
free(this);
@@ -138,12 +140,9 @@ METHOD(radius_client_t, destroy, void,
/**
* See header
*/
-radius_client_t *radius_client_create()
+radius_client_t *radius_client_create(radius_config_t *config)
{
private_radius_client_t *this;
- enumerator_t *enumerator;
- radius_server_t *server;
- int current, best = -1;
INIT(this,
.public = {
@@ -151,36 +150,8 @@ radius_client_t *radius_client_create()
.get_msk = _get_msk,
.destroy = _destroy,
},
+ .config = config,
);
- enumerator = eap_radius_create_server_enumerator();
- while (enumerator->enumerate(enumerator, &server))
- {
- current = server->get_preference(server);
- if (current > best ||
- /* for two with equal preference, 50-50 chance */
- (current == best && random() % 2 == 0))
- {
- DBG2(DBG_CFG, "RADIUS server '%s' is candidate: %d",
- server->get_name(server), current);
- best = current;
- DESTROY_IF(this->server);
- this->server = server->get_ref(server);
- }
- else
- {
- DBG2(DBG_CFG, "RADIUS server '%s' skipped: %d",
- server->get_name(server), current);
- }
- }
- enumerator->destroy(enumerator);
-
- if (!this->server)
- {
- free(this);
- return NULL;
- }
-
return &this->public;
}
-
diff --git a/src/libcharon/plugins/eap_radius/radius_client.h b/src/libradius/radius_client.h
index e4f3a7222..cf5f79b6c 100644
--- a/src/libcharon/plugins/eap_radius/radius_client.h
+++ b/src/libradius/radius_client.h
@@ -15,13 +15,14 @@
/**
* @defgroup radius_client radius_client
- * @{ @ingroup eap_radius
+ * @{ @ingroup libradius
*/
#ifndef RADIUS_CLIENT_H_
#define RADIUS_CLIENT_H_
#include "radius_message.h"
+#include "radius_config.h"
typedef struct radius_client_t radius_client_t;
@@ -59,8 +60,9 @@ struct radius_client_t {
/**
* Create a RADIUS client.
*
+ * @param config reference to a server configuration, gets owned
* @return radius_client_t object
*/
-radius_client_t *radius_client_create();
+radius_client_t *radius_client_create(radius_config_t *config);
#endif /** RADIUS_CLIENT_H_ @}*/
diff --git a/src/libcharon/plugins/eap_radius/radius_server.c b/src/libradius/radius_config.c
index 3baf39807..6e3394bb0 100644
--- a/src/libcharon/plugins/eap_radius/radius_server.c
+++ b/src/libradius/radius_config.c
@@ -13,23 +13,23 @@
* for more details.
*/
-#include "radius_server.h"
+#include "radius_config.h"
#include <threading/mutex.h>
#include <threading/condvar.h>
#include <utils/linked_list.h>
-typedef struct private_radius_server_t private_radius_server_t;
+typedef struct private_radius_config_t private_radius_config_t;
/**
- * Private data of an radius_server_t object.
+ * Private data of an radius_config_t object.
*/
-struct private_radius_server_t {
+struct private_radius_config_t {
/**
- * Public radius_server_t interface.
+ * Public radius_config_t interface.
*/
- radius_server_t public;
+ radius_config_t public;
/**
* list of radius sockets, as radius_socket_t
@@ -82,8 +82,8 @@ struct private_radius_server_t {
refcount_t ref;
};
-METHOD(radius_server_t, get_socket, radius_socket_t*,
- private_radius_server_t *this)
+METHOD(radius_config_t, get_socket, radius_socket_t*,
+ private_radius_config_t *this)
{
radius_socket_t *skt;
@@ -96,8 +96,8 @@ METHOD(radius_server_t, get_socket, radius_socket_t*,
return skt;
}
-METHOD(radius_server_t, put_socket, void,
- private_radius_server_t *this, radius_socket_t *skt, bool result)
+METHOD(radius_config_t, put_socket, void,
+ private_radius_config_t *this, radius_socket_t *skt, bool result)
{
this->mutex->lock(this->mutex);
this->sockets->insert_last(this->sockets, skt);
@@ -106,14 +106,14 @@ METHOD(radius_server_t, put_socket, void,
this->reachable = result;
}
-METHOD(radius_server_t, get_nas_identifier, chunk_t,
- private_radius_server_t *this)
+METHOD(radius_config_t, get_nas_identifier, chunk_t,
+ private_radius_config_t *this)
{
return this->nas_identifier;
}
-METHOD(radius_server_t, get_preference, int,
- private_radius_server_t *this)
+METHOD(radius_config_t, get_preference, int,
+ private_radius_config_t *this)
{
int pref;
@@ -147,22 +147,22 @@ METHOD(radius_server_t, get_preference, int,
return pref;
}
-METHOD(radius_server_t, get_name, char*,
- private_radius_server_t *this)
+METHOD(radius_config_t, get_name, char*,
+ private_radius_config_t *this)
{
return this->name;
}
-METHOD(radius_server_t, get_ref, radius_server_t*,
- private_radius_server_t *this)
+METHOD(radius_config_t, get_ref, radius_config_t*,
+ private_radius_config_t *this)
{
ref_get(&this->ref);
return &this->public;
}
-METHOD(radius_server_t, destroy, void,
- private_radius_server_t *this)
+METHOD(radius_config_t, destroy, void,
+ private_radius_config_t *this)
{
if (ref_put(&this->ref))
{
@@ -177,10 +177,12 @@ METHOD(radius_server_t, destroy, void,
/**
* See header
*/
-radius_server_t *radius_server_create(char *name, char *address, u_int16_t port,
- char *nas_identifier, char *secret, int sockets, int preference)
+radius_config_t *radius_config_create(char *name, char *address,
+ u_int16_t auth_port, u_int16_t acct_port,
+ char *nas_identifier, char *secret,
+ int sockets, int preference)
{
- private_radius_server_t *this;
+ private_radius_config_t *this;
radius_socket_t *socket;
INIT(this,
@@ -206,7 +208,7 @@ radius_server_t *radius_server_create(char *name, char *address, u_int16_t port,
while (sockets--)
{
- socket = radius_socket_create(address, port,
+ socket = radius_socket_create(address, auth_port, acct_port,
chunk_create(secret, strlen(secret)));
if (!socket)
{
diff --git a/src/libcharon/plugins/eap_radius/radius_server.h b/src/libradius/radius_config.h
index c59361c49..40ed6197a 100644
--- a/src/libcharon/plugins/eap_radius/radius_server.h
+++ b/src/libradius/radius_config.h
@@ -14,28 +14,28 @@
*/
/**
- * @defgroup radius_server radius_server
- * @{ @ingroup eap_radius
+ * @defgroup radius_config radius_config
+ * @{ @ingroup libradius
*/
-#ifndef RADIUS_SERVER_H_
-#define RADIUS_SERVER_H_
+#ifndef RADIUS_CONFIG_H_
+#define RADIUS_CONFIG_H_
-typedef struct radius_server_t radius_server_t;
+typedef struct radius_config_t radius_config_t;
#include "radius_socket.h"
/**
* RADIUS server configuration.
*/
-struct radius_server_t {
+struct radius_config_t {
/**
- * Get a RADIUS socket from the pool to communicate with this server.
+ * Get a RADIUS socket from the pool to communicate with this config.
*
* @return RADIUS socket
*/
- radius_socket_t* (*get_socket)(radius_server_t *this);
+ radius_socket_t* (*get_socket)(radius_config_t *this);
/**
* Release a socket to the pool after use.
@@ -43,14 +43,14 @@ struct radius_server_t {
* @param skt RADIUS socket to release
* @param result result of the socket use, TRUE for success
*/
- void (*put_socket)(radius_server_t *this, radius_socket_t *skt, bool result);
+ void (*put_socket)(radius_config_t *this, radius_socket_t *skt, bool result);
/**
* Get the NAS-Identifier to use with this server.
*
* @return NAS-Identifier, internal data
*/
- chunk_t (*get_nas_identifier)(radius_server_t *this);
+ chunk_t (*get_nas_identifier)(radius_config_t *this);
/**
* Get the preference of this server.
@@ -58,40 +58,43 @@ struct radius_server_t {
* Based on the available sockets and the server reachability a preference
* value is calculated: better servers return a higher value.
*/
- int (*get_preference)(radius_server_t *this);
+ int (*get_preference)(radius_config_t *this);
/**
* Get the name of the RADIUS server.
*
* @return server name
*/
- char* (*get_name)(radius_server_t *this);
+ char* (*get_name)(radius_config_t *this);
/**
- * Increase reference count of this server.
+ * Increase reference count of this server configuration.
*
* @return this
*/
- radius_server_t* (*get_ref)(radius_server_t *this);
+ radius_config_t* (*get_ref)(radius_config_t *this);
/**
- * Destroy a radius_server_t.
+ * Destroy a radius_config_t.
*/
- void (*destroy)(radius_server_t *this);
+ void (*destroy)(radius_config_t *this);
};
/**
- * Create a radius_server instance.
+ * Create a radius_config_t instance.
*
* @param name server name
* @param address server address
- * @param port server port
+ * @param auth_port server port for authentication
+ * @param acct_port server port for accounting
* @param nas_identifier NAS-Identifier to use with this server
* @param secret secret to use with this server
* @param sockets number of sockets to create in pool
* @param preference preference boost for this server
*/
-radius_server_t *radius_server_create(char *name, char *address, u_int16_t port,
- char *nas_identifier, char *secret, int sockets, int preference);
+radius_config_t *radius_config_create(char *name, char *address,
+ u_int16_t auth_port, u_int16_t acct_port,
+ char *nas_identifier, char *secret,
+ int sockets, int preference);
-#endif /** RADIUS_SERVER_H_ @}*/
+#endif /** RADIUS_CONFIG_H_ @}*/
diff --git a/src/libcharon/plugins/eap_radius/radius_message.c b/src/libradius/radius_message.c
index 23a29b772..ce8903cdb 100644
--- a/src/libcharon/plugins/eap_radius/radius_message.c
+++ b/src/libradius/radius_message.c
@@ -15,7 +15,7 @@
#include "radius_message.h"
-#include <daemon.h>
+#include <debug.h>
#include <crypto/hashers/hasher.h>
typedef struct private_radius_message_t private_radius_message_t;
@@ -74,7 +74,14 @@ ENUM_BEGIN(radius_message_code_names, RMC_ACCESS_REQUEST, RMC_ACCOUNTING_RESPONS
"Accounting-Response");
ENUM_NEXT(radius_message_code_names, RMC_ACCESS_CHALLENGE, RMC_ACCESS_CHALLENGE, RMC_ACCOUNTING_RESPONSE,
"Access-Challenge");
-ENUM_END(radius_message_code_names, RMC_ACCESS_CHALLENGE);
+ENUM_NEXT(radius_message_code_names, RMC_DISCONNECT_REQUEST, RMC_COA_NAK, RMC_ACCESS_CHALLENGE,
+ "Disconnect-Request",
+ "Disconnect-ACK",
+ "Disconnect-NAK",
+ "CoA-Request",
+ "CoA-ACK",
+ "CoA-NAK");
+ENUM_END(radius_message_code_names, RMC_COA_NAK);
ENUM(radius_attribute_type_names, RAT_USER_NAME, RAT_MIP6_HOME_LINK_PREFIX,
"User-Name",
@@ -261,7 +268,7 @@ METHOD(radius_message_t, add, void,
{
rattr_t *attribute;
- data.len = min(data.len, 253);
+ data.len = min(data.len, MAX_RADIUS_ATTRIBUTE_SIZE);
this->msg = realloc(this->msg,
ntohs(this->msg->length) + sizeof(rattr_t) + data.len);
attribute = ((void*)this->msg) + ntohs(this->msg->length);
@@ -272,19 +279,48 @@ METHOD(radius_message_t, add, void,
}
METHOD(radius_message_t, sign, void,
- private_radius_message_t *this, rng_t *rng, signer_t *signer)
+ private_radius_message_t *this, u_int8_t *req_auth, chunk_t secret,
+ hasher_t *hasher, signer_t *signer, rng_t *rng, bool msg_auth)
{
- char buf[HASH_SIZE_MD5];
+ if (rng)
+ {
+ /* build Request-Authenticator */
+ rng->get_bytes(rng, HASH_SIZE_MD5, this->msg->authenticator);
+ }
+ else
+ {
+ /* prepare build of Response-Authenticator */
+ if (req_auth)
+ {
+ memcpy(this->msg->authenticator, req_auth, HASH_SIZE_MD5);
+ }
+ else
+ {
+ memset(this->msg->authenticator, 0, sizeof(this->msg->authenticator));
+ }
+ }
- /* build Request-Authenticator */
- rng->get_bytes(rng, HASH_SIZE_MD5, this->msg->authenticator);
+ if (msg_auth)
+ {
+ char buf[HASH_SIZE_MD5];
- /* build Message-Authenticator attribute, using 16 null bytes */
- memset(buf, 0, sizeof(buf));
- add(this, RAT_MESSAGE_AUTHENTICATOR, chunk_create(buf, sizeof(buf)));
- signer->get_signature(signer,
+ /* build Message-Authenticator attribute, using 16 null bytes */
+ memset(buf, 0, sizeof(buf));
+ add(this, RAT_MESSAGE_AUTHENTICATOR, chunk_create(buf, sizeof(buf)));
+ signer->get_signature(signer,
chunk_create((u_char*)this->msg, ntohs(this->msg->length)),
((u_char*)this->msg) + ntohs(this->msg->length) - HASH_SIZE_MD5);
+ }
+
+ if (!rng)
+ {
+ chunk_t msg;
+
+ /* build Response-Authenticator */
+ msg = chunk_create((u_char*)this->msg, ntohs(this->msg->length));
+ hasher->get_hash(hasher, msg, NULL);
+ hasher->get_hash(hasher, secret, this->msg->authenticator);
+ }
}
METHOD(radius_message_t, verify, bool,
@@ -297,18 +333,29 @@ METHOD(radius_message_t, verify, bool,
chunk_t data, msg;
bool has_eap = FALSE, has_auth = FALSE;
- /* replace Response by Request Authenticator for verification */
- memcpy(res_auth, this->msg->authenticator, HASH_SIZE_MD5);
- memcpy(this->msg->authenticator, req_auth, HASH_SIZE_MD5);
msg = chunk_create((u_char*)this->msg, ntohs(this->msg->length));
- /* verify Response-Authenticator */
- hasher->get_hash(hasher, msg, NULL);
- hasher->get_hash(hasher, secret, buf);
- if (!memeq(buf, res_auth, HASH_SIZE_MD5))
+ if (this->msg->code != RMC_ACCESS_REQUEST)
{
- DBG1(DBG_CFG, "RADIUS Response-Authenticator verification failed");
- return FALSE;
+ /* replace Response by Request Authenticator for verification */
+ memcpy(res_auth, this->msg->authenticator, HASH_SIZE_MD5);
+ if (req_auth)
+ {
+ memcpy(this->msg->authenticator, req_auth, HASH_SIZE_MD5);
+ }
+ else
+ {
+ memset(this->msg->authenticator, 0, HASH_SIZE_MD5);
+ }
+
+ /* verify Response-Authenticator */
+ hasher->get_hash(hasher, msg, NULL);
+ hasher->get_hash(hasher, secret, buf);
+ if (!memeq(buf, res_auth, HASH_SIZE_MD5))
+ {
+ DBG1(DBG_CFG, "RADIUS Response-Authenticator verification failed");
+ return FALSE;
+ }
}
/* verify Message-Authenticator attribute */
@@ -346,8 +393,12 @@ METHOD(radius_message_t, verify, bool,
}
}
enumerator->destroy(enumerator);
- /* restore Response-Authenticator */
- memcpy(this->msg->authenticator, res_auth, HASH_SIZE_MD5);
+
+ if (this->msg->code != RMC_ACCESS_REQUEST)
+ {
+ /* restore Response-Authenticator */
+ memcpy(this->msg->authenticator, res_auth, HASH_SIZE_MD5);
+ }
if (has_eap && !has_auth)
{ /* Message-Authenticator is required if we have an EAP-Message */
@@ -398,7 +449,7 @@ METHOD(radius_message_t, destroy, void,
/**
* Generic constructor
*/
-static private_radius_message_t *radius_message_create()
+static private_radius_message_t *radius_message_create_empty()
{
private_radius_message_t *this;
@@ -423,12 +474,12 @@ static private_radius_message_t *radius_message_create()
/**
* See header
*/
-radius_message_t *radius_message_create_request()
+radius_message_t *radius_message_create(radius_message_code_t code)
{
- private_radius_message_t *this = radius_message_create();
+ private_radius_message_t *this = radius_message_create_empty();
INIT(this->msg,
- .code = RMC_ACCESS_REQUEST,
+ .code = code,
.identifier = 0,
.length = htons(sizeof(rmsg_t)),
);
@@ -439,9 +490,9 @@ radius_message_t *radius_message_create_request()
/**
* See header
*/
-radius_message_t *radius_message_parse_response(chunk_t data)
+radius_message_t *radius_message_parse(chunk_t data)
{
- private_radius_message_t *this = radius_message_create();
+ private_radius_message_t *this = radius_message_create_empty();
this->msg = malloc(data.len);
memcpy(this->msg, data.ptr, data.len);
@@ -454,4 +505,3 @@ radius_message_t *radius_message_parse_response(chunk_t data)
}
return &this->public;
}
-
diff --git a/src/libcharon/plugins/eap_radius/radius_message.h b/src/libradius/radius_message.h
index 266839d3b..90698ae7b 100644
--- a/src/libcharon/plugins/eap_radius/radius_message.h
+++ b/src/libradius/radius_message.h
@@ -14,8 +14,13 @@
*/
/**
+ * @defgroup libradius libradius
+ *
+ * @addtogroup libradius
+ * RADIUS protocol support library.
+ *
* @defgroup radius_message radius_message
- * @{ @ingroup eap_radius
+ * @{ @ingroup libradius
*/
#ifndef RADIUS_MESSAGE_H_
@@ -23,6 +28,10 @@
#include <library.h>
+#define MAX_RADIUS_ATTRIBUTE_SIZE 253
+
+#define RADIUS_TUNNEL_TYPE_ESP 9
+
typedef struct radius_message_t radius_message_t;
typedef enum radius_message_code_t radius_message_code_t;
typedef enum radius_attribute_type_t radius_attribute_type_t;
@@ -37,6 +46,12 @@ enum radius_message_code_t {
RMC_ACCOUNTING_REQUEST = 4,
RMC_ACCOUNTING_RESPONSE = 5,
RMC_ACCESS_CHALLENGE = 11,
+ RMC_DISCONNECT_REQUEST = 40,
+ RMC_DISCONNECT_ACK = 41,
+ RMC_DISCONNECT_NAK = 42,
+ RMC_COA_REQUEST = 43,
+ RMC_COA_ACK = 44,
+ RMC_COA_NAK = 45,
};
/**
@@ -236,18 +251,23 @@ struct radius_message_t {
/**
* Calculate and add the Message-Authenticator attribute to the message.
*
- * @param rng RNG to create Request-Authenticator
+ * @param req_auth 16 byte Authenticator of request, or NULL
+ * @param secret shared RADIUS secret
* @param signer HMAC-MD5 signer with secret set
+ * @param hasher MD5 hasher
+ * @param rng RNG to create Request-Authenticator, NULL to omit
+ * @param msg_auth calculate and add Message-Authenticator
*/
- void (*sign)(radius_message_t *this, rng_t *rng, signer_t *signer);
+ void (*sign)(radius_message_t *this, u_int8_t *req_auth, chunk_t secret,
+ hasher_t *hasher, signer_t *signer, rng_t *rng, bool msg_auth);
/**
- * Verify the integrity of a received RADIUS response.
+ * Verify the integrity of a received RADIUS message.
*
- * @param req_auth 16 byte Authenticator of the corresponding request
+ * @param req_auth 16 byte Authenticator of request, or NULL
* @param secret shared RADIUS secret
- * @param hasher hasher to verify Response-Authenticator
- * @param signer signer to verify Message-Authenticator attribute
+ * @param signer HMAC-MD5 signer with secret set
+ * @param hasher MD5 hasher
*/
bool (*verify)(radius_message_t *this, u_int8_t *req_auth, chunk_t secret,
hasher_t *hasher, signer_t *signer);
@@ -259,18 +279,19 @@ struct radius_message_t {
};
/**
- * Create an empty RADIUS request message (RMT_ACCESS_REQUEST).
+ * Create an empty RADIUS message.
*
+ * @param code request type
* @return radius_message_t object
*/
-radius_message_t *radius_message_create_request();
+radius_message_t *radius_message_create(radius_message_code_t code);
/**
- * Parse and verify a recevied RADIUS response.
+ * Parse and verify a recevied RADIUS message.
*
* @param data received message data
* @return radius_message_t object, NULL if length invalid
*/
-radius_message_t *radius_message_parse_response(chunk_t data);
+radius_message_t *radius_message_parse(chunk_t data);
#endif /** RADIUS_MESSAGE_H_ @}*/
diff --git a/src/libradius/radius_mppe.h b/src/libradius/radius_mppe.h
new file mode 100644
index 000000000..1b7a732ec
--- /dev/null
+++ b/src/libradius/radius_mppe.h
@@ -0,0 +1,40 @@
+/*
+ * 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 radius_mppe radius_mppe
+ * @{ @ingroup libradius
+ */
+
+#ifndef RADIUS_MPPE_H_
+#define RADIUS_MPPE_H_
+
+/**
+ * Microsoft specific vendor attributes
+ */
+#define MS_MPPE_SEND_KEY 16
+#define MS_MPPE_RECV_KEY 17
+
+typedef struct mppe_key_t mppe_key_t;
+
+struct mppe_key_t {
+ u_int32_t id;
+ u_int8_t type;
+ u_int8_t length;
+ u_int16_t salt;
+ u_int8_t key[];
+} __attribute__((packed));
+
+#endif /** RADIUS_MPPE_H_ @}*/
diff --git a/src/libcharon/plugins/eap_radius/radius_socket.c b/src/libradius/radius_socket.c
index b3229c288..048c8814e 100644
--- a/src/libcharon/plugins/eap_radius/radius_socket.c
+++ b/src/libradius/radius_socket.c
@@ -14,23 +14,14 @@
*/
#include "radius_socket.h"
+#include "radius_mppe.h"
#include <errno.h>
#include <unistd.h>
+#include <pen/pen.h>
#include <debug.h>
-/**
- * Vendor-Id of Microsoft specific attributes
- */
-#define VENDOR_ID_MICROSOFT 311
-
-/**
- * Microsoft specific vendor attributes
- */
-#define MS_MPPE_SEND_KEY 16
-#define MS_MPPE_RECV_KEY 17
-
typedef struct private_radius_socket_t private_radius_socket_t;
/**
@@ -44,19 +35,29 @@ struct private_radius_socket_t {
radius_socket_t public;
/**
- * socket file descriptor
+ * Server port for authentication
*/
- int fd;
+ u_int16_t auth_port;
/**
- * Server address
+ * socket file descriptor for authentication
*/
- char *address;
+ int auth_fd;
/**
- * Server port
+ * Server port for accounting
*/
- u_int16_t port;
+ u_int16_t acct_port;
+
+ /**
+ * socket file descriptor for accounting
+ */
+ int acct_fd;
+
+ /**
+ * Server address
+ */
+ char *address;
/**
* current RADIUS identifier
@@ -87,35 +88,36 @@ struct private_radius_socket_t {
/**
* Check or establish RADIUS connection
*/
-static bool check_connection(private_radius_socket_t *this)
+static bool check_connection(private_radius_socket_t *this,
+ int *fd, u_int16_t port)
{
- if (this->fd == -1)
+ if (*fd == -1)
{
host_t *server;
- server = host_create_from_dns(this->address, AF_UNSPEC, this->port);
+ server = host_create_from_dns(this->address, AF_UNSPEC, port);
if (!server)
{
DBG1(DBG_CFG, "resolving RADIUS server address '%s' failed",
this->address);
return FALSE;
}
- this->fd = socket(server->get_family(server), SOCK_DGRAM, IPPROTO_UDP);
- if (this->fd == -1)
+ *fd = socket(server->get_family(server), SOCK_DGRAM, IPPROTO_UDP);
+ if (*fd == -1)
{
DBG1(DBG_CFG, "opening RADIUS socket for %#H failed: %s",
server, strerror(errno));
server->destroy(server);
return FALSE;
}
- if (connect(this->fd, server->get_sockaddr(server),
+ if (connect(*fd, server->get_sockaddr(server),
*server->get_sockaddr_len(server)) < 0)
{
DBG1(DBG_CFG, "connecting RADIUS socket to %#H failed: %s",
server, strerror(errno));
server->destroy(server);
- close(this->fd);
- this->fd = -1;
+ close(*fd);
+ *fd = -1;
return FALSE;
}
server->destroy(server);
@@ -127,19 +129,36 @@ METHOD(radius_socket_t, request, radius_message_t*,
private_radius_socket_t *this, radius_message_t *request)
{
chunk_t data;
- int i;
+ int i, *fd;
+ u_int16_t port;
+ rng_t *rng = NULL;
+
+ if (request->get_code(request) == RMC_ACCOUNTING_REQUEST)
+ {
+ fd = &this->acct_fd;
+ port = this->acct_port;
+ }
+ else
+ {
+ fd = &this->auth_fd;
+ port = this->auth_port;
+ rng = this->rng;
+ }
/* set Message Identifier */
request->set_identifier(request, this->identifier++);
/* sign the request */
- request->sign(request, this->rng, this->signer);
+ request->sign(request, NULL, this->secret, this->hasher, this->signer,
+ rng, rng != NULL);
- if (!check_connection(this))
+ if (!check_connection(this, fd, port))
{
return NULL;
}
data = request->get_encoding(request);
+ DBG3(DBG_CFG, "%B", &data);
+
/* timeout after 2, 3, 4, 5 seconds */
for (i = 2; i <= 5; i++)
{
@@ -150,7 +169,7 @@ METHOD(radius_socket_t, request, radius_message_t*,
fd_set fds;
int res;
- if (send(this->fd, data.ptr, data.len, 0) != data.len)
+ if (send(*fd, data.ptr, data.len, 0) != data.len)
{
DBG1(DBG_CFG, "sending RADIUS message failed: %s", strerror(errno));
return NULL;
@@ -161,8 +180,8 @@ METHOD(radius_socket_t, request, radius_message_t*,
while (TRUE)
{
FD_ZERO(&fds);
- FD_SET(this->fd, &fds);
- res = select(this->fd + 1, &fds, NULL, NULL, &tv);
+ FD_SET(*fd, &fds);
+ res = select((*fd) + 1, &fds, NULL, NULL, &tv);
/* TODO: updated tv to time not waited. Linux does this for us. */
if (res < 0)
{ /* failed */
@@ -176,14 +195,14 @@ METHOD(radius_socket_t, request, radius_message_t*,
retransmit = TRUE;
break;
}
- res = recv(this->fd, buf, sizeof(buf), MSG_DONTWAIT);
+ res = recv(*fd, buf, sizeof(buf), MSG_DONTWAIT);
if (res <= 0)
{
DBG1(DBG_CFG, "receiving RADIUS message failed: %s",
strerror(errno));
break;
}
- response = radius_message_parse_response(chunk_create(buf, res));
+ response = radius_message_parse(chunk_create(buf, res));
if (response)
{
if (response->verify(response,
@@ -262,13 +281,7 @@ METHOD(radius_socket_t, decrypt_msk, chunk_t,
private_radius_socket_t *this, radius_message_t *request,
radius_message_t *response)
{
- struct {
- u_int32_t id;
- u_int8_t type;
- u_int8_t length;
- u_int16_t salt;
- u_int8_t key[];
- } __attribute__((packed)) *mppe_key;
+ mppe_key_t *mppe_key;
enumerator_t *enumerator;
chunk_t data, send = chunk_empty, recv = chunk_empty;
int type;
@@ -276,14 +289,13 @@ METHOD(radius_socket_t, decrypt_msk, chunk_t,
enumerator = response->create_enumerator(response);
while (enumerator->enumerate(enumerator, &type, &data))
{
- if (type == RAT_VENDOR_SPECIFIC &&
- data.len > sizeof(*mppe_key))
+ if (type == RAT_VENDOR_SPECIFIC && data.len > sizeof(mppe_key_t))
{
- mppe_key = (void*)data.ptr;
- if (ntohl(mppe_key->id) == VENDOR_ID_MICROSOFT &&
+ mppe_key = (mppe_key_t*)data.ptr;
+ if (ntohl(mppe_key->id) == PEN_MICROSOFT &&
mppe_key->length == data.len - sizeof(mppe_key->id))
{
- data = chunk_create(mppe_key->key, data.len - sizeof(*mppe_key));
+ data = chunk_create(mppe_key->key, data.len - sizeof(mppe_key_t));
if (mppe_key->type == MS_MPPE_SEND_KEY)
{
send = decrypt_mppe_key(this, mppe_key->salt, data, request);
@@ -311,9 +323,13 @@ METHOD(radius_socket_t, destroy, void,
DESTROY_IF(this->hasher);
DESTROY_IF(this->signer);
DESTROY_IF(this->rng);
- if (this->fd != -1)
+ if (this->auth_fd != -1)
+ {
+ close(this->auth_fd);
+ };
+ if (this->acct_fd != -1)
{
- close(this->fd);
+ close(this->acct_fd);
}
free(this);
}
@@ -321,8 +337,8 @@ METHOD(radius_socket_t, destroy, void,
/**
* See header
*/
-radius_socket_t *radius_socket_create(char *address, u_int16_t port,
- chunk_t secret)
+radius_socket_t *radius_socket_create(char *address, u_int16_t auth_port,
+ u_int16_t acct_port, chunk_t secret)
{
private_radius_socket_t *this;
@@ -333,13 +349,15 @@ radius_socket_t *radius_socket_create(char *address, u_int16_t port,
.destroy = _destroy,
},
.address = address,
- .port = port,
- .fd = -1,
+ .auth_port = auth_port,
+ .auth_fd = -1,
+ .acct_port = acct_port,
+ .acct_fd = -1,
+ .hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5),
+ .signer = lib->crypto->create_signer(lib->crypto, AUTH_HMAC_MD5_128),
+ .rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK),
);
- this->hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5);
- this->signer = lib->crypto->create_signer(lib->crypto, AUTH_HMAC_MD5_128);
- this->rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
if (!this->hasher || !this->signer || !this->rng)
{
DBG1(DBG_CFG, "RADIUS initialization failed, HMAC/MD5/RNG required");
diff --git a/src/libcharon/plugins/eap_radius/radius_socket.h b/src/libradius/radius_socket.h
index 2875008eb..07d642c08 100644
--- a/src/libcharon/plugins/eap_radius/radius_socket.h
+++ b/src/libradius/radius_socket.h
@@ -15,7 +15,7 @@
/**
* @defgroup radius_socket radius_socket
- * @{ @ingroup eap_radius
+ * @{ @ingroup libradius
*/
#ifndef RADIUS_SOCKET_H_
@@ -67,10 +67,11 @@ struct radius_socket_t {
* Create a radius_socket instance.
*
* @param address server name
- * @param port server port
+ * @param auth_port server port for authentication
+ * @param acct_port server port for accounting
* @param secret RADIUS secret
*/
-radius_socket_t *radius_socket_create(char *address, u_int16_t port,
- chunk_t secret);
+radius_socket_t *radius_socket_create(char *address, u_int16_t auth_port,
+ u_int16_t acct_port, chunk_t secret);
#endif /** RADIUS_SOCKET_H_ @}*/
diff --git a/src/libsimaka/simaka_manager.h b/src/libsimaka/simaka_manager.h
index a0edd60b9..64a67e56c 100644
--- a/src/libsimaka/simaka_manager.h
+++ b/src/libsimaka/simaka_manager.h
@@ -113,7 +113,7 @@ struct simaka_manager_t {
identification_t *pseudonym);
/**
- * Get a stored pseudonym from one of the registerd SIM cards.
+ * Get a stored pseudonym from one of the registered SIM cards.
*
* @param id permanent identity of the peer
* @return associated pseudonym identity, NULL if none found
@@ -134,7 +134,7 @@ struct simaka_manager_t {
u_int16_t counter);
/**
- * Retrieve fast reauthentication parameters from one of the registerd cards.
+ * Retrieve fast reauthentication parameters from one of the registered cards.
*
* @param id permanent identity of the peer
* @param mk buffer receiving master key MK
diff --git a/src/libsimaka/simaka_message.c b/src/libsimaka/simaka_message.c
index 969dc45ae..a5754b985 100644
--- a/src/libsimaka/simaka_message.c
+++ b/src/libsimaka/simaka_message.c
@@ -139,7 +139,7 @@ ENUM(simaka_client_error_names, SIM_UNABLE_TO_PROCESS, SIM_RANDS_NOT_FRESH,
*/
bool simaka_attribute_skippable(simaka_attribute_t attribute)
{
- bool skippable = !(attribute >= 0 && attribute <= 127);
+ bool skippable = !((int)attribute >= 0 && attribute <= 127);
DBG1(DBG_LIB, "%sskippable EAP-SIM/AKA attribute %N",
skippable ? "ignoring " : "found non-",
diff --git a/src/libstrongswan/Android.mk b/src/libstrongswan/Android.mk
index b6897c4c3..d33bee6c7 100644
--- a/src/libstrongswan/Android.mk
+++ b/src/libstrongswan/Android.mk
@@ -128,6 +128,8 @@ LOCAL_CFLAGS := $(strongswan_CFLAGS) \
LOCAL_MODULE := libstrongswan
+LOCAL_MODULE_TAGS := optional
+
LOCAL_ARM_MODE := arm
LOCAL_PRELINK_MODULE := false
diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am
index 284decbd9..d3c360b47 100644
--- a/src/libstrongswan/Makefile.am
+++ b/src/libstrongswan/Makefile.am
@@ -257,6 +257,13 @@ if MONOLITHIC
endif
endif
+if USE_PKCS8
+ SUBDIRS += plugins/pkcs8
+if MONOLITHIC
+ libstrongswan_la_LIBADD += plugins/pkcs8/libstrongswan-pkcs8.la
+endif
+endif
+
if USE_PGP
SUBDIRS += plugins/pgp
if MONOLITHIC
diff --git a/src/libstrongswan/asn1/asn1.c b/src/libstrongswan/asn1/asn1.c
index 4466b37a4..4cb38d126 100644
--- a/src/libstrongswan/asn1/asn1.c
+++ b/src/libstrongswan/asn1/asn1.c
@@ -222,7 +222,7 @@ size_t asn1_length(chunk_t *blob)
if (blob->len < 2)
{
- DBG2(DBG_LIB, "insufficient number of octets to parse ASN.1 length");
+ DBG2(DBG_ASN, "insufficient number of octets to parse ASN.1 length");
return ASN1_INVALID_LENGTH;
}
@@ -234,7 +234,7 @@ size_t asn1_length(chunk_t *blob)
{ /* single length octet */
if (n > blob->len)
{
- DBG2(DBG_LIB, "length is larger than remaining blob size");
+ DBG2(DBG_ASN, "length is larger than remaining blob size");
return ASN1_INVALID_LENGTH;
}
return n;
@@ -245,13 +245,13 @@ size_t asn1_length(chunk_t *blob)
if (n == 0 || n > blob->len)
{
- DBG2(DBG_LIB, "number of length octets invalid");
+ DBG2(DBG_ASN, "number of length octets invalid");
return ASN1_INVALID_LENGTH;
}
if (n > sizeof(len))
{
- DBG2(DBG_LIB, "number of length octets is larger than limit of"
+ DBG2(DBG_ASN, "number of length octets is larger than limit of"
" %d octets", (int)sizeof(len));
return ASN1_INVALID_LENGTH;
}
@@ -265,7 +265,7 @@ size_t asn1_length(chunk_t *blob)
}
if (len > blob->len)
{
- DBG2(DBG_LIB, "length is larger than remaining blob size");
+ DBG2(DBG_ASN, "length is larger than remaining blob size");
return ASN1_INVALID_LENGTH;
}
return len;
@@ -326,10 +326,10 @@ static const int tm_leap_1970 = 477;
*/
time_t asn1_to_time(const chunk_t *utctime, asn1_t type)
{
- int tm_year, tm_mon, tm_day, tm_days, tm_hour, tm_min, tm_sec;
+ int tm_year, tm_mon, tm_day, tm_hour, tm_min, tm_sec;
int tm_leap_4, tm_leap_100, tm_leap_400, tm_leap;
int tz_hour, tz_min, tz_offset;
- time_t tm_secs;
+ time_t tm_days, tm_secs;
u_char *eot = NULL;
if ((eot = memchr(utctime->ptr, 'Z', utctime->len)) != NULL)
@@ -435,6 +435,11 @@ chunk_t asn1_from_time(const time_t *time, asn1_t type)
struct tm t;
gmtime_r(time, &t);
+ /* RFC 5280 says that dates through the year 2049 MUST be encoded as UTCTIME
+ * and dates in 2050 or later MUST be encoded as GENERALIZEDTIME. We only
+ * enforce the latter to avoid overflows but allow callers to force the
+ * encoding to GENERALIZEDTIME */
+ type = (t.tm_year >= 150) ? ASN1_GENERALIZEDTIME : type;
if (type == ASN1_GENERALIZEDTIME)
{
format = "%04d%02d%02d%02d%02d%02dZ";
@@ -443,7 +448,7 @@ chunk_t asn1_from_time(const time_t *time, asn1_t type)
else /* ASN1_UTCTIME */
{
format = "%02d%02d%02d%02d%02d%02dZ";
- offset = (t.tm_year < 100)? 0 : -100;
+ offset = (t.tm_year < 100) ? 0 : -100;
}
snprintf(buf, BUF_LEN, format, t.tm_year + offset,
t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
@@ -471,12 +476,12 @@ void asn1_debug_simple_object(chunk_t object, asn1_t type, bool private)
{
break;
}
- DBG2(DBG_LIB, " %s", oid_str);
+ DBG2(DBG_ASN, " %s", oid_str);
free(oid_str);
}
else
{
- DBG2(DBG_LIB, " '%s'", oid_names[oid].name);
+ DBG2(DBG_ASN, " '%s'", oid_names[oid].name);
}
return;
case ASN1_UTF8STRING:
@@ -484,14 +489,14 @@ void asn1_debug_simple_object(chunk_t object, asn1_t type, bool private)
case ASN1_PRINTABLESTRING:
case ASN1_T61STRING:
case ASN1_VISIBLESTRING:
- DBG2(DBG_LIB, " '%.*s'", (int)object.len, object.ptr);
+ DBG2(DBG_ASN, " '%.*s'", (int)object.len, object.ptr);
return;
case ASN1_UTCTIME:
case ASN1_GENERALIZEDTIME:
{
time_t time = asn1_to_time(&object, type);
- DBG2(DBG_LIB, " '%T'", &time, TRUE);
+ DBG2(DBG_ASN, " '%T'", &time, TRUE);
}
return;
default:
@@ -499,11 +504,11 @@ void asn1_debug_simple_object(chunk_t object, asn1_t type, bool private)
}
if (private)
{
- DBG4(DBG_LIB, "%B", &object);
+ DBG4(DBG_ASN, "%B", &object);
}
else
{
- DBG3(DBG_LIB, "%B", &object);
+ DBG3(DBG_ASN, "%B", &object);
}
}
@@ -517,14 +522,14 @@ bool asn1_parse_simple_object(chunk_t *object, asn1_t type, u_int level, const c
/* an ASN.1 object must possess at least a tag and length field */
if (object->len < 2)
{
- DBG2(DBG_LIB, "L%d - %s: ASN.1 object smaller than 2 octets", level,
+ DBG2(DBG_ASN, "L%d - %s: ASN.1 object smaller than 2 octets", level,
name);
return FALSE;
}
if (*object->ptr != type)
{
- DBG2(DBG_LIB, "L%d - %s: ASN1 tag 0x%02x expected, but is 0x%02x",
+ DBG2(DBG_ASN, "L%d - %s: ASN1 tag 0x%02x expected, but is 0x%02x",
level, name, type, *object->ptr);
return FALSE;
}
@@ -533,12 +538,12 @@ bool asn1_parse_simple_object(chunk_t *object, asn1_t type, u_int level, const c
if (len == ASN1_INVALID_LENGTH || object->len < len)
{
- DBG2(DBG_LIB, "L%d - %s: length of ASN.1 object invalid or too large",
+ DBG2(DBG_ASN, "L%d - %s: length of ASN.1 object invalid or too large",
level, name);
return FALSE;
}
- DBG2(DBG_LIB, "L%d - %s:", level, name);
+ DBG2(DBG_ASN, "L%d - %s:", level, name);
asn1_debug_simple_object(*object, type, FALSE);
return TRUE;
}
@@ -547,14 +552,20 @@ bool asn1_parse_simple_object(chunk_t *object, asn1_t type, u_int level, const c
* ASN.1 definition of an algorithmIdentifier
*/
static const asn1Object_t algorithmIdentifierObjects[] = {
- { 0, "algorithmIdentifier", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
- { 1, "algorithm", ASN1_OID, ASN1_BODY }, /* 1 */
- { 1, "parameters", ASN1_EOC, ASN1_RAW|ASN1_OPT }, /* 2 */
- { 1, "end opt", ASN1_EOC, ASN1_END }, /* 3 */
- { 0, "exit", ASN1_EOC, ASN1_EXIT }
+ { 0, "algorithmIdentifier", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
+ { 1, "algorithm", ASN1_OID, ASN1_BODY }, /* 1 */
+ { 1, "parameters", ASN1_OID, ASN1_RAW|ASN1_OPT }, /* 2 */
+ { 1, "end opt", ASN1_EOC, ASN1_END }, /* 3 */
+ { 1, "parameters", ASN1_SEQUENCE, ASN1_RAW|ASN1_OPT }, /* 4 */
+ { 1, "end opt", ASN1_EOC, ASN1_END }, /* 5 */
+ { 1, "parameters", ASN1_OCTET_STRING, ASN1_RAW|ASN1_OPT }, /* 6 */
+ { 1, "end opt", ASN1_EOC, ASN1_END }, /* 7 */
+ { 0, "exit", ASN1_EOC, ASN1_EXIT }
};
-#define ALGORITHM_ID_ALG 1
-#define ALGORITHM_ID_PARAMETERS 2
+#define ALGORITHM_ID_ALG 1
+#define ALGORITHM_ID_PARAMETERS_OID 2
+#define ALGORITHM_ID_PARAMETERS_SEQ 4
+#define ALGORITHM_ID_PARAMETERS_OCT 6
/*
* Defined in header
@@ -576,7 +587,9 @@ int asn1_parse_algorithmIdentifier(chunk_t blob, int level0, chunk_t *parameters
case ALGORITHM_ID_ALG:
alg = asn1_known_oid(object);
break;
- case ALGORITHM_ID_PARAMETERS:
+ case ALGORITHM_ID_PARAMETERS_OID:
+ case ALGORITHM_ID_PARAMETERS_SEQ:
+ case ALGORITHM_ID_PARAMETERS_OCT:
if (parameters != NULL)
{
*parameters = object;
@@ -606,7 +619,7 @@ bool is_asn1(chunk_t blob)
tag = *blob.ptr;
if (tag != ASN1_SEQUENCE && tag != ASN1_SET && tag != ASN1_OCTET_STRING)
{
- DBG2(DBG_LIB, " file content is not binary ASN.1");
+ DBG2(DBG_ASN, " file content is not binary ASN.1");
return FALSE;
}
@@ -624,7 +637,7 @@ bool is_asn1(chunk_t blob)
return TRUE;
}
- DBG2(DBG_LIB, " file size does not match ASN.1 coded length");
+ DBG2(DBG_ASN, " file size does not match ASN.1 coded length");
return FALSE;
}
diff --git a/src/libstrongswan/asn1/asn1.h b/src/libstrongswan/asn1/asn1.h
index 05a060827..15ffff62e 100644
--- a/src/libstrongswan/asn1/asn1.h
+++ b/src/libstrongswan/asn1/asn1.h
@@ -35,8 +35,8 @@ typedef enum {
ASN1_BOOLEAN = 0x01,
ASN1_INTEGER = 0x02,
ASN1_BIT_STRING = 0x03,
- ASN1_OCTET_STRING = 0x04,
- ASN1_NULL = 0x05,
+ ASN1_OCTET_STRING = 0x04,
+ ASN1_NULL = 0x05,
ASN1_OID = 0x06,
ASN1_ENUMERATED = 0x0A,
ASN1_UTF8STRING = 0x0C,
@@ -48,7 +48,7 @@ typedef enum {
ASN1_UTCTIME = 0x17,
ASN1_GENERALIZEDTIME = 0x18,
ASN1_GRAPHICSTRING = 0x19,
- ASN1_VISIBLESTRING = 0x1A,
+ ASN1_VISIBLESTRING = 0x1A,
ASN1_GENERALSTRING = 0x1B,
ASN1_UNIVERSALSTRING = 0x1C,
ASN1_BMPSTRING = 0x1E,
@@ -75,7 +75,7 @@ typedef enum {
ASN1_CONTEXT_C_4 = 0xA4,
ASN1_CONTEXT_C_5 = 0xA5,
- ASN1_INVALID = 0x100,
+ ASN1_INVALID = 0x100,
} asn1_t;
#define ASN1_INVALID_LENGTH 0xffffffff
@@ -191,6 +191,8 @@ time_t asn1_to_time(const chunk_t *utctime, asn1_t type);
/**
* Converts time_t to an ASN.1 UTCTIME or GENERALIZEDTIME string
*
+ * @note The type is automatically changed to GENERALIZEDTIME if needed
+ *
* @param time time_t in UTC
* @param type ASN1_UTCTIME or ASN1_GENERALIZEDTIME
* @return body of an ASN.1 code time object
diff --git a/src/libstrongswan/asn1/asn1_parser.c b/src/libstrongswan/asn1/asn1_parser.c
index 2a7a38a52..40e11b321 100644
--- a/src/libstrongswan/asn1/asn1_parser.c
+++ b/src/libstrongswan/asn1/asn1_parser.c
@@ -120,7 +120,7 @@ METHOD(asn1_parser_t, iterate, bool,
if ((obj.flags & ASN1_DEF) && (blob->len == 0 || *start_ptr != obj.type) )
{
/* field is missing */
- DBG2(DBG_LIB, "L%d - %s:", level, obj.name);
+ DBG2(DBG_ASN, "L%d - %s:", level, obj.name);
if (obj.type & ASN1_CONSTRUCTED)
{
this->line++ ; /* skip context-specific tag */
@@ -147,7 +147,7 @@ METHOD(asn1_parser_t, iterate, bool,
if (blob->len < 2)
{
- DBG1(DBG_LIB, "L%d - %s: ASN.1 object smaller than 2 octets",
+ DBG1(DBG_ASN, "L%d - %s: ASN.1 object smaller than 2 octets",
level, obj.name);
this->success = FALSE;
goto end;
@@ -157,7 +157,7 @@ METHOD(asn1_parser_t, iterate, bool,
if (blob1->len == ASN1_INVALID_LENGTH)
{
- DBG1(DBG_LIB, "L%d - %s: length of ASN.1 object invalid or too large",
+ DBG1(DBG_ASN, "L%d - %s: length of ASN.1 object invalid or too large",
level, obj.name);
this->success = FALSE;
}
@@ -170,7 +170,7 @@ METHOD(asn1_parser_t, iterate, bool,
if (obj.flags & ASN1_RAW)
{
- DBG2(DBG_LIB, "L%d - %s:", level, obj.name);
+ DBG2(DBG_ASN, "L%d - %s:", level, obj.name);
object->ptr = start_ptr;
object->len = (size_t)(blob->ptr - start_ptr);
goto end;
@@ -178,14 +178,14 @@ METHOD(asn1_parser_t, iterate, bool,
if (*start_ptr != obj.type && !(this->implicit && this->line == 0))
{
- DBG1(DBG_LIB, "L%d - %s: ASN1 tag 0x%02x expected, but is 0x%02x",
+ DBG2(DBG_ASN, "L%d - %s: ASN1 tag 0x%02x expected, but is 0x%02x",
level, obj.name, obj.type, *start_ptr);
- DBG3(DBG_LIB, "%b", start_ptr, (u_int)(blob->ptr - start_ptr));
+ DBG3(DBG_ASN, "%b", start_ptr, (u_int)(blob->ptr - start_ptr));
this->success = FALSE;
goto end;
}
- DBG2(DBG_LIB, "L%d - %s:", level, obj.name);
+ DBG2(DBG_ASN, "L%d - %s:", level, obj.name);
/* In case of "SEQUENCE OF" or "SET OF" start a loop */
if (obj.flags & ASN1_LOOP)
@@ -214,11 +214,11 @@ METHOD(asn1_parser_t, iterate, bool,
object->len = (size_t)(blob->ptr - start_ptr);
if (this->private)
{
- DBG4(DBG_LIB, "%B", object);
+ DBG4(DBG_ASN, "%B", object);
}
else
{
- DBG3(DBG_LIB, "%B", object);
+ DBG3(DBG_ASN, "%B", object);
}
}
else if (obj.flags & ASN1_BODY)
diff --git a/src/libstrongswan/asn1/oid.txt b/src/libstrongswan/asn1/oid.txt
index 73c068851..5daa6dad6 100644
--- a/src/libstrongswan/asn1/oid.txt
+++ b/src/libstrongswan/asn1/oid.txt
@@ -97,6 +97,11 @@
0x0C "sha384WithRSAEncryption" OID_SHA384_WITH_RSA
0x0D "sha512WithRSAEncryption" OID_SHA512_WITH_RSA
0x0E "sha224WithRSAEncryption" OID_SHA224_WITH_RSA
+ 0x05 "PKCS-5"
+ 0x03 "pbeWithMD5AndDES-CBC" OID_PBE_MD5_DES_CBC
+ 0x0A "pbeWithSHA1AndDES-CBC" OID_PBE_SHA1_DES_CBC
+ 0x0C "id-PBKDF2" OID_PBKDF2
+ 0x0D "id-PBES2" OID_PBES2
0x07 "PKCS-7"
0x01 "data" OID_PKCS7_DATA
0x02 "signedData" OID_PKCS7_SIGNED_DATA
diff --git a/src/libstrongswan/credentials/auth_cfg.h b/src/libstrongswan/credentials/auth_cfg.h
index fbc4b6eda..31c7e7d90 100644
--- a/src/libstrongswan/credentials/auth_cfg.h
+++ b/src/libstrongswan/credentials/auth_cfg.h
@@ -65,7 +65,6 @@ extern enum_name_t *auth_class_names;
* to transport credentials during the authentication process.
*/
enum auth_rule_t {
-
/** identity to use for IKEv2 authentication exchange, identification_t* */
AUTH_RULE_IDENTITY,
/** authentication class, auth_class_t */
@@ -125,8 +124,8 @@ extern enum_name_t *auth_rule_names;
*
* RFC4739 defines multiple authentication rounds. This class defines such
* a round from a configuration perspective, either for the local or the remote
- * peer. Local config are called "rulesets", as they define how we authenticate.
- * Remote peer configs are called "constraits", they define what is needed to
+ * peer. Local configs are called "rulesets". They define how we authenticate.
+ * Remote peer configs are called "constraits". They define what is needed to
* complete the authentication round successfully.
*
* @verbatim
@@ -150,7 +149,7 @@ extern enum_name_t *auth_rule_names;
@endverbatim
*
- * Values for each items are either pointers (casted to void*) or short
+ * Values for each item are either pointers (casted to void*) or short
* integers (use uintptr_t cast).
*/
struct auth_cfg_t {
@@ -164,7 +163,7 @@ struct auth_cfg_t {
void (*add)(auth_cfg_t *this, auth_rule_t rule, ...);
/**
- * Get an rule value.
+ * Get a rule value.
*
* @param rule rule type
* @return bool if item has been found
@@ -179,9 +178,9 @@ struct auth_cfg_t {
enumerator_t* (*create_enumerator)(auth_cfg_t *this);
/**
- * Replace an rule at enumerator position.
+ * Replace a rule at enumerator position.
*
- * @param pos enumerator position position
+ * @param pos enumerator position
* @param rule rule type
* @param ... associated value to rule
*/
@@ -192,7 +191,7 @@ struct auth_cfg_t {
* Check if a used config fulfills a set of configured constraints.
*
* @param constraints required authorization rules
- * @param log_error wheter to log compliance errors
+ * @param log_error whether to log compliance errors
* @return TRUE if this complies with constraints
*/
bool (*complies)(auth_cfg_t *this, auth_cfg_t *constraints, bool log_error);
@@ -208,20 +207,20 @@ struct auth_cfg_t {
/**
* Purge all rules in a config.
*
- * @param keep_ca wheter to keep AUTH_RULE_CA_CERT entries
+ * @param keep_ca whether to keep AUTH_RULE_CA_CERT entries
*/
void (*purge)(auth_cfg_t *this, bool keep_ca);
/**
* Check two configs for equality.
*
- * @param other other config to compaire against this
+ * @param other other config to compare against this
* @return TRUE if auth infos identical
*/
bool (*equals)(auth_cfg_t *this, auth_cfg_t *other);
/**
- * Clone a authentication config, including all rules.
+ * Clone an authentication config, including all rules.
*
* @return cloned configuration
*/
diff --git a/src/libstrongswan/credentials/builder.c b/src/libstrongswan/credentials/builder.c
index 68c54fb45..d3157c80e 100644
--- a/src/libstrongswan/credentials/builder.c
+++ b/src/libstrongswan/credentials/builder.c
@@ -23,6 +23,7 @@ ENUM(builder_part_names, BUILD_FROM_FILE, BUILD_END,
"BUILD_BLOB_PEM",
"BUILD_BLOB_PGP",
"BUILD_BLOB_DNSKEY",
+ "BUILD_BLOB_ALGID_PARAMS",
"BUILD_KEY_SIZE",
"BUILD_SIGNING_KEY",
"BUILD_SIGNING_CERT",
diff --git a/src/libstrongswan/credentials/builder.h b/src/libstrongswan/credentials/builder.h
index 325b668cd..41250ccae 100644
--- a/src/libstrongswan/credentials/builder.h
+++ b/src/libstrongswan/credentials/builder.h
@@ -28,8 +28,8 @@ typedef enum builder_part_t builder_part_t;
/**
* Constructor function to build credentials.
*
- * Any added parts are cloned/refcounted by the builder implementation, a
- * caller may need to free the passed ressources themself.
+ * Any added parts are cloned/refcounted by the builder implementation.
+ * Callers may need to free the passed resources themselves.
*
* @param subtype constructor specific subtype, e.g. a certificate_type_t
* @param args list of builder part types, followed by parts, BUILD_END
@@ -53,10 +53,12 @@ enum builder_part_t {
BUILD_BLOB_ASN1_DER,
/** PEM encoded ASN.1/PGP blob, chunk_t */
BUILD_BLOB_PEM,
- /** OpenPGP key blob, chunk_t */
+ /** OpenPGP key blob, chunk_t */
BUILD_BLOB_PGP,
/** DNS public key blob (RFC 4034, RSA specifc RFC 3110), chunk_t */
BUILD_BLOB_DNSKEY,
+ /** parameters from algorithmIdentifier (ASN.1 blob), chunk_t */
+ BUILD_BLOB_ALGID_PARAMS,
/** key size in bits, as used for key generation, u_int */
BUILD_KEY_SIZE,
/** private key to use for signing, private_key_t* */
diff --git a/src/libstrongswan/credentials/cert_validator.h b/src/libstrongswan/credentials/cert_validator.h
index 733d9d612..00e30d7a0 100644
--- a/src/libstrongswan/credentials/cert_validator.h
+++ b/src/libstrongswan/credentials/cert_validator.h
@@ -39,7 +39,7 @@ struct cert_validator_t {
*
* @param subject subject certificate to check
* @param issuer issuer of subject
- * @param online wheter to do online revocation checking
+ * @param online whether to do online revocation checking
* @param pathlen the current length of the path bottom-up
* @param anchor is issuer trusted root anchor
* @param auth container for resulting authentication info
diff --git a/src/libstrongswan/credentials/certificates/x509.h b/src/libstrongswan/credentials/certificates/x509.h
index 8bd2a6a83..00171a718 100644
--- a/src/libstrongswan/credentials/certificates/x509.h
+++ b/src/libstrongswan/credentials/certificates/x509.h
@@ -78,12 +78,12 @@ enum x509_constraint_t {
* X.509 certPolicy extension.
*/
struct x509_cert_policy_t {
- /** OID of certPolicy */
- chunk_t oid;
/** Certification Practice Statement URI qualifier */
char *cps_uri;
/** UserNotice Text qualifier */
char *unotice_text;
+ /** OID of certPolicy */
+ chunk_t oid;
};
/**
diff --git a/src/libstrongswan/credentials/cred_encoding.c b/src/libstrongswan/credentials/cred_encoding.c
index a7637b598..4865984dd 100644
--- a/src/libstrongswan/credentials/cred_encoding.c
+++ b/src/libstrongswan/credentials/cred_encoding.c
@@ -116,7 +116,7 @@ METHOD(cred_encoding_t, get_cache, bool,
{
chunk_t *chunk;
- if (type >= CRED_ENCODING_MAX || type < 0)
+ if (type >= CRED_ENCODING_MAX || (int)type < 0)
{
return FALSE;
}
@@ -142,7 +142,7 @@ static bool encode(private_cred_encoding_t *this, cred_encoding_type_t type,
bool success = FALSE;
chunk_t *chunk;
- if (type >= CRED_ENCODING_MAX || type < 0)
+ if (type >= CRED_ENCODING_MAX || (int)type < 0)
{
return FALSE;
}
@@ -195,7 +195,7 @@ METHOD(cred_encoding_t, cache, void,
{
chunk_t *chunk;
- if (type >= CRED_ENCODING_MAX || type < 0)
+ if (type >= CRED_ENCODING_MAX || (int)type < 0)
{
return free(encoding.ptr);
}
diff --git a/src/libstrongswan/credentials/cred_encoding.h b/src/libstrongswan/credentials/cred_encoding.h
index e2d69691e..b029fe2ac 100644
--- a/src/libstrongswan/credentials/cred_encoding.h
+++ b/src/libstrongswan/credentials/cred_encoding.h
@@ -59,7 +59,7 @@ bool cred_encoding_args(va_list args, ...);
/**
* Encoding type of a fingerprint/credential.
*
- * Fingerprints have have the KEYID_*, public keys the PUBKEY_* and
+ * Fingerprints have the KEYID_*, public keys the PUBKEY_* and
* private keys the PRIVKEY_* prefix.
*/
enum cred_encoding_type_t {
diff --git a/src/libstrongswan/credentials/credential_factory.h b/src/libstrongswan/credentials/credential_factory.h
index 709dc916a..c31601245 100644
--- a/src/libstrongswan/credentials/credential_factory.h
+++ b/src/libstrongswan/credentials/credential_factory.h
@@ -54,7 +54,7 @@ struct credential_factory_t {
* The variable argument list takes builder_part_t types followed
* by the type specific value. The list must be terminated using BUILD_END.
* All passed parts get cloned/refcounted by the builder functions,
- * so free up allocated ressources after successful and unsuccessful
+ * so free up allocated resources after successful and unsuccessful
* invocations.
*
* @param type credential type to build
diff --git a/src/libstrongswan/credentials/credential_manager.c b/src/libstrongswan/credentials/credential_manager.c
index b8f8ae8e3..d54359ebf 100644
--- a/src/libstrongswan/credentials/credential_manager.c
+++ b/src/libstrongswan/credentials/credential_manager.c
@@ -921,7 +921,7 @@ METHOD(credential_manager_t, create_public_enumerator, enumerator_t*,
}
/**
- * Check if an helper contains a certificate as trust anchor
+ * Check if a helper contains a certificate as trust anchor
*/
static bool auth_contains_cacert(auth_cfg_t *auth, certificate_t *cert)
{
@@ -1004,7 +1004,7 @@ static auth_cfg_t *build_trustchain(private_credential_manager_t *this,
}
/**
- * find a private key of a give certificate
+ * find a private key of a given certificate
*/
static private_key_t *get_private_by_cert(private_credential_manager_t *this,
certificate_t *cert, key_type_t type)
diff --git a/src/libstrongswan/credentials/credential_manager.h b/src/libstrongswan/credentials/credential_manager.h
index 4b9f914c4..ad789c718 100644
--- a/src/libstrongswan/credentials/credential_manager.h
+++ b/src/libstrongswan/credentials/credential_manager.h
@@ -36,11 +36,11 @@ typedef struct credential_manager_t credential_manager_t;
* Manages credentials using credential_sets.
*
* The credential manager is the entry point of the credential framework. It
- * uses so called "sets" to access credentials in a modular fashion, these
+ * uses so called "sets" to access credentials in a modular fashion. These
* are implemented through the credential_set_t interface.
* The manager additionally does trust chain verification and trust status
- * chaching. A set may call the managers methods if it needs credentials itself,
- * the manager uses recursive locking.
+ * caching. A set may call the managers methods if it needs credentials itself.
+ * The manager uses recursive locking.
*
* @verbatim
@@ -62,8 +62,8 @@ typedef struct credential_manager_t credential_manager_t;
@endverbatim
*
- * The credential manager uses rwlocks for performance reasons, credential
- * sets must be fully thread save.
+ * The credential manager uses rwlocks for performance reasons. Credential
+ * sets must be fully thread-safe.
*/
struct credential_manager_t {
@@ -84,7 +84,7 @@ struct credential_manager_t {
*
* The enumerator enumerates over:
* shared_key_t*, id_match_t me, id_match_t other
- * But must accepts values for the id_matches.
+ * But must accept values for the id_matches.
*
* @param type kind of requested shared key
* @param first first subject between key is shared
@@ -120,7 +120,7 @@ struct credential_manager_t {
*
* @param type kind of requested shared key
* @param me own identity
- * @param other peers identity
+ * @param other peer identity
* @return shared_key_t, NULL if none found
*/
shared_key_t *(*get_shared)(credential_manager_t *this, shared_key_type_t type,
@@ -130,7 +130,7 @@ struct credential_manager_t {
*
* The get_private() method gets a secret private key identified by either
* the keyid itself or an id the key belongs to.
- * The auth parameter contains additional information, such as receipients
+ * The auth parameter contains additional information, such as recipients
* trusted CA certs. Auth gets filled with subject and CA certificates
* needed to validate a created signature.
*
@@ -163,7 +163,7 @@ struct credential_manager_t {
/**
* Create an enumerator over trusted public keys.
*
- * This method gets a an enumerator over trusted public keys to verify a
+ * This method creates an enumerator over trusted public keys to verify a
* signature created by id. The auth parameter contains additional
* authentication infos, e.g. peer and intermediate certificates.
* The resulting enumerator enumerates over public_key_t *, auth_cfg_t *,
@@ -180,7 +180,7 @@ struct credential_manager_t {
key_type_t type, identification_t *id, auth_cfg_t *auth);
/**
- * Cache a certificate by invoking cache_cert() on all registerd sets.
+ * Cache a certificate by invoking cache_cert() on all registered sets.
*
* @param cert certificate to cache
*/
@@ -199,8 +199,8 @@ struct credential_manager_t {
/**
* Check if a given subject certificate is issued by an issuer certificate.
*
- * This operation does signature verification, but uses the credential
- * managers cache for to speed up the operation.
+ * This operation does signature verification using the credential
+ * manager's cache to speed up the operation.
*
* @param subject subject certificate to check
* @param issuer issuer certificate that potentially has signed subject
@@ -228,7 +228,7 @@ struct credential_manager_t {
*
* To add a credential set for the current trustchain verification
* operation, sets may be added for the calling thread only. This
- * does not require a write lock and is therefore a much less expensive
+ * does not require a write lock and is therefore a much cheaper
* operation.
* The exclusive option allows to disable all other credential sets
* until the set is deregistered.
diff --git a/src/libstrongswan/credentials/credential_set.h b/src/libstrongswan/credentials/credential_set.h
index 0eee237cb..8673c484f 100644
--- a/src/libstrongswan/credentials/credential_set.h
+++ b/src/libstrongswan/credentials/credential_set.h
@@ -38,7 +38,7 @@ typedef struct credential_set_t credential_set_t;
* A credential set enumerator may not block the credential set, i.e. multiple
* threads must be able to hold multiple enumerators, as the credential manager
* is higly parallelized. The best way to achieve this is by using shared
- * read locks for the enumerators only. Otherwiese deadlocks will occur.
+ * read locks for the enumerators only. Otherwise deadlocks will occur.
* The writing cache_cert() routine is called by the manager only if no
* enumerator is alive, so it is save to use a write lock there.
*/
@@ -97,7 +97,7 @@ struct credential_set_t {
/**
* Cache a certificate in the credential set.
*
- * The caching policy is implementation dependent, the sets may cache the
+ * The caching policy is implementation dependent. The sets may cache the
* certificate in-memory, persistent on disk or not at all.
*
* @param cert certificate to cache
diff --git a/src/libstrongswan/crypto/crypto_tester.c b/src/libstrongswan/crypto/crypto_tester.c
index 4635dccea..8b1daa885 100644
--- a/src/libstrongswan/crypto/crypto_tester.c
+++ b/src/libstrongswan/crypto/crypto_tester.c
@@ -102,6 +102,8 @@ static const char* get_name(void *sym)
return "unknown";
}
+#ifdef CLOCK_THREAD_CPUTIME_ID
+
/**
* Start a benchmark timer
*/
@@ -122,6 +124,14 @@ static u_int end_timing(struct timespec *start)
(end.tv_sec - start->tv_sec) * 1000;
}
+#else /* CLOCK_THREAD_CPUTIME_ID */
+
+/* Make benchmarking a no-op if CLOCK_THREAD_CPUTIME_ID is not available */
+#define start_timing(start) ((start)->tv_sec = 0, (start)->tv_nsec = 0)
+#define end_timing(...) (this->bench_time)
+
+#endif /* CLOCK_THREAD_CPUTIME_ID */
+
/**
* Benchmark a crypter
*/
diff --git a/src/libstrongswan/crypto/diffie_hellman.c b/src/libstrongswan/crypto/diffie_hellman.c
index 5f7365321..1124ee6f7 100644
--- a/src/libstrongswan/crypto/diffie_hellman.c
+++ b/src/libstrongswan/crypto/diffie_hellman.c
@@ -64,7 +64,8 @@ static struct {
0x02,0x0B,0xBE,0xA6,0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD,
0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,0xF2,0x5F,0x14,0x37,
0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,
- 0xF4,0x4C,0x42,0xE9,0xA6,0x3A,0x36,0x20,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF)
+ 0xF4,0x4C,0x42,0xE9,0xA6,0x3A,0x36,0x20,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF),
+ .exp_len = 0,
},
},{
.group = MODP_1024_BIT, .opt_exp = 32, .public = {
@@ -77,7 +78,8 @@ static struct {
0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,
0xF4,0x4C,0x42,0xE9,0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED,
0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,0x7C,0x4B,0x1F,0xE6,
- 0x49,0x28,0x66,0x51,0xEC,0xE6,0x53,0x81,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF)
+ 0x49,0x28,0x66,0x51,0xEC,0xE6,0x53,0x81,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF),
+ .exp_len = 0,
},
},{
.group = MODP_1536_BIT, .opt_exp = 32, .public = {
@@ -94,7 +96,8 @@ static struct {
0x98,0xDA,0x48,0x36,0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F,
0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,0x20,0x85,0x52,0xBB,
0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,
- 0xF1,0x74,0x6C,0x08,0xCA,0x23,0x73,0x27,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF)
+ 0xF1,0x74,0x6C,0x08,0xCA,0x23,0x73,0x27,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF),
+ .exp_len = 0,
},
},{
.group = MODP_2048_BIT, .opt_exp = 48, .public = {
@@ -115,7 +118,8 @@ static struct {
0xE3,0x9E,0x77,0x2C,0x18,0x0E,0x86,0x03,0x9B,0x27,0x83,0xA2,0xEC,0x07,0xA2,0x8F,
0xB5,0xC5,0x5D,0xF0,0x6F,0x4C,0x52,0xC9,0xDE,0x2B,0xCB,0xF6,0x95,0x58,0x17,0x18,
0x39,0x95,0x49,0x7C,0xEA,0x95,0x6A,0xE5,0x15,0xD2,0x26,0x18,0x98,0xFA,0x05,0x10,
- 0x15,0x72,0x8E,0x5A,0x8A,0xAC,0xAA,0x68,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF)
+ 0x15,0x72,0x8E,0x5A,0x8A,0xAC,0xAA,0x68,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF),
+ .exp_len = 0,
},
},{
.group = MODP_3072_BIT, .opt_exp = 48, .public = {
@@ -144,7 +148,8 @@ static struct {
0xD8,0x76,0x02,0x73,0x3E,0xC8,0x6A,0x64,0x52,0x1F,0x2B,0x18,0x17,0x7B,0x20,0x0C,
0xBB,0xE1,0x17,0x57,0x7A,0x61,0x5D,0x6C,0x77,0x09,0x88,0xC0,0xBA,0xD9,0x46,0xE2,
0x08,0xE2,0x4F,0xA0,0x74,0xE5,0xAB,0x31,0x43,0xDB,0x5B,0xFC,0xE0,0xFD,0x10,0x8E,
- 0x4B,0x82,0xD1,0x20,0xA9,0x3A,0xD2,0xCA,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF)
+ 0x4B,0x82,0xD1,0x20,0xA9,0x3A,0xD2,0xCA,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF),
+ .exp_len = 0,
},
},{
.group = MODP_4096_BIT, .opt_exp = 64, .public = {
@@ -181,7 +186,8 @@ static struct {
0x23,0x3B,0xA1,0x86,0x51,0x5B,0xE7,0xED,0x1F,0x61,0x29,0x70,0xCE,0xE2,0xD7,0xAF,
0xB8,0x1B,0xDD,0x76,0x21,0x70,0x48,0x1C,0xD0,0x06,0x91,0x27,0xD5,0xB0,0x5A,0xA9,
0x93,0xB4,0xEA,0x98,0x8D,0x8F,0xDD,0xC1,0x86,0xFF,0xB7,0xDC,0x90,0xA6,0xC0,0x8F,
- 0x4D,0xF4,0x35,0xC9,0x34,0x06,0x31,0x99,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF)
+ 0x4D,0xF4,0x35,0xC9,0x34,0x06,0x31,0x99,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF),
+ .exp_len = 0,
},
},{
.group = MODP_6144_BIT, .opt_exp = 64, .public = {
@@ -234,7 +240,8 @@ static struct {
0xF5,0x50,0xAA,0x3D,0x8A,0x1F,0xBF,0xF0,0xEB,0x19,0xCC,0xB1,0xA3,0x13,0xD5,0x5C,
0xDA,0x56,0xC9,0xEC,0x2E,0xF2,0x96,0x32,0x38,0x7F,0xE8,0xD7,0x6E,0x3C,0x04,0x68,
0x04,0x3E,0x8F,0x66,0x3F,0x48,0x60,0xEE,0x12,0xBF,0x2D,0x5B,0x0B,0x74,0x74,0xD6,
- 0xE6,0x94,0xF9,0x1E,0x6D,0xCC,0x40,0x24,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF)
+ 0xE6,0x94,0xF9,0x1E,0x6D,0xCC,0x40,0x24,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF),
+ .exp_len = 0,
},
},{
.group = MODP_8192_BIT, .opt_exp = 64, .public = {
@@ -303,7 +310,8 @@ static struct {
0x40,0x09,0x43,0x8B,0x48,0x1C,0x6C,0xD7,0x88,0x9A,0x00,0x2E,0xD5,0xEE,0x38,0x2B,
0xC9,0x19,0x0D,0xA6,0xFC,0x02,0x6E,0x47,0x95,0x58,0xE4,0x47,0x56,0x77,0xE9,0xAA,
0x9E,0x30,0x50,0xE2,0x76,0x56,0x94,0xDF,0xC8,0x1F,0x56,0xE8,0x80,0xB9,0x6E,0x71,
- 0x60,0xC9,0x80,0xDD,0x98,0xED,0xD3,0xDF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF)
+ 0x60,0xC9,0x80,0xDD,0x98,0xED,0xD3,0xDF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF),
+ .exp_len = 0,
},
},{
.group = MODP_1024_160, .opt_exp = 20, .public = {
diff --git a/src/libstrongswan/crypto/diffie_hellman.h b/src/libstrongswan/crypto/diffie_hellman.h
index aca793b71..cab3b1ba7 100644
--- a/src/libstrongswan/crypto/diffie_hellman.h
+++ b/src/libstrongswan/crypto/diffie_hellman.h
@@ -74,8 +74,7 @@ struct diffie_hellman_t {
/**
* Returns the shared secret of this diffie hellman exchange.
*
- * Space for returned secret is allocated and must be
- * freed by the caller.
+ * Space for returned secret is allocated and must be freed by the caller.
*
* @param secret shared secret will be written into this chunk
* @return SUCCESS, FAILED if not both DH values are set
@@ -108,7 +107,7 @@ struct diffie_hellman_t {
diffie_hellman_group_t (*get_dh_group) (diffie_hellman_t *this);
/**
- * Destroys an diffie_hellman_t object.
+ * Destroys a diffie_hellman_t object.
*/
void (*destroy) (diffie_hellman_t *this);
};
diff --git a/src/libstrongswan/crypto/pkcs7.c b/src/libstrongswan/crypto/pkcs7.c
index 2593d8b79..a4d0e71fe 100644
--- a/src/libstrongswan/crypto/pkcs7.c
+++ b/src/libstrongswan/crypto/pkcs7.c
@@ -825,7 +825,7 @@ METHOD(pkcs7_t, build_signedData, bool,
/* take the current time as signingTime */
time_t now = time(NULL);
- chunk_t signingTime = asn1_from_time(&now, ASN1_UTCTIME);
+ chunk_t signingTime = asn1_from_time(&now, ASN1_UTCTIME);
chunk_t messageDigest, attributes;
diff --git a/src/libstrongswan/crypto/proposal/proposal_keywords.txt b/src/libstrongswan/crypto/proposal/proposal_keywords.txt
index 4ef664d8f..b16e2eccb 100644
--- a/src/libstrongswan/crypto/proposal/proposal_keywords.txt
+++ b/src/libstrongswan/crypto/proposal/proposal_keywords.txt
@@ -118,6 +118,7 @@ twofish192, ENCRYPTION_ALGORITHM, ENCR_TWOFISH_CBC, 192
twofish256, ENCRYPTION_ALGORITHM, ENCR_TWOFISH_CBC, 256
sha, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0
sha1, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0
+sha1_160, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_160, 0
sha256, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_256_128, 0
sha2_256, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_256_128, 0
sha256_96, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_256_96, 0
@@ -127,6 +128,7 @@ sha2_384, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_384_192, 0
sha512, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_512_256, 0
sha2_512, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_512_256, 0
md5, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0
+md5_128, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_128, 0
aesxcbc, INTEGRITY_ALGORITHM, AUTH_AES_XCBC_96, 0
camelliaxcbc, INTEGRITY_ALGORITHM, AUTH_CAMELLIA_XCBC_96, 0
modpnull, DIFFIE_HELLMAN_GROUP, MODP_NULL, 0
diff --git a/src/libstrongswan/debug.c b/src/libstrongswan/debug.c
index 608303445..d6c5b06b6 100644
--- a/src/libstrongswan/debug.c
+++ b/src/libstrongswan/debug.c
@@ -26,6 +26,7 @@ ENUM(debug_names, DBG_DMN, DBG_LIB,
"CFG",
"KNL",
"NET",
+ "ASN",
"ENC",
"TNC",
"IMC",
@@ -44,6 +45,7 @@ ENUM(debug_lower_names, DBG_DMN, DBG_LIB,
"cfg",
"knl",
"net",
+ "asn",
"enc",
"tnc",
"imc",
diff --git a/src/libstrongswan/debug.h b/src/libstrongswan/debug.h
index 849d28f9f..2a6ff98ad 100644
--- a/src/libstrongswan/debug.h
+++ b/src/libstrongswan/debug.h
@@ -48,6 +48,8 @@ enum debug_t {
DBG_KNL,
/** networking/sockets */
DBG_NET,
+ /** low-level encoding/decoding (ASN.1, X.509 etc.) */
+ DBG_ASN,
/** message encoding/decoding */
DBG_ENC,
/** trusted network connect */
diff --git a/src/libstrongswan/fetcher/fetcher_manager.h b/src/libstrongswan/fetcher/fetcher_manager.h
index 15250d531..449f284f7 100644
--- a/src/libstrongswan/fetcher/fetcher_manager.h
+++ b/src/libstrongswan/fetcher/fetcher_manager.h
@@ -26,7 +26,7 @@ typedef struct fetcher_manager_t fetcher_manager_t;
#include <fetcher/fetcher.h>
/**
- * Fetches from URIs using registerd fetcher_t instances.
+ * Fetches from URIs using registered fetcher_t instances.
*/
struct fetcher_manager_t {
diff --git a/src/libstrongswan/library.c b/src/libstrongswan/library.c
index 6ed4d1285..cd6a41f44 100644
--- a/src/libstrongswan/library.c
+++ b/src/libstrongswan/library.c
@@ -61,6 +61,9 @@ void library_deinit()
detailed = lib->settings->get_bool(lib->settings,
"libstrongswan.leak_detective.detailed", TRUE);
+ /* make sure the cache is clear before unloading plugins */
+ lib->credmgr->flush_cache(lib->credmgr, CERT_ANY);
+
this->public.scheduler->destroy(this->public.scheduler);
this->public.processor->destroy(this->public.processor);
this->public.plugins->destroy(this->public.plugins);
diff --git a/src/libstrongswan/plugins/openssl/openssl_ec_private_key.c b/src/libstrongswan/plugins/openssl/openssl_ec_private_key.c
index f4c4759bf..950504573 100644
--- a/src/libstrongswan/plugins/openssl/openssl_ec_private_key.c
+++ b/src/libstrongswan/plugins/openssl/openssl_ec_private_key.c
@@ -1,6 +1,6 @@
/*
+ * Copyright (C) 2008-2012 Tobias Brunner
* Copyright (C) 2009 Martin Willi
- * Copyright (C) 2008 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -371,14 +371,17 @@ openssl_ec_private_key_t *openssl_ec_private_key_load(key_type_t type,
va_list args)
{
private_openssl_ec_private_key_t *this;
- chunk_t blob = chunk_empty;
+ chunk_t par = chunk_empty, key = chunk_empty;
while (TRUE)
{
switch (va_arg(args, builder_part_t))
{
+ case BUILD_BLOB_ALGID_PARAMS:
+ par = va_arg(args, chunk_t);
+ continue;
case BUILD_BLOB_ASN1_DER:
- blob = va_arg(args, chunk_t);
+ key = va_arg(args, chunk_t);
continue;
case BUILD_END:
break;
@@ -389,18 +392,36 @@ openssl_ec_private_key_t *openssl_ec_private_key_load(key_type_t type,
}
this = create_empty();
- this->ec = d2i_ECPrivateKey(NULL, (const u_char**)&blob.ptr, blob.len);
- if (!this->ec)
+
+ if (par.ptr)
{
- destroy(this);
- return NULL;
+ this->ec = d2i_ECParameters(NULL, (const u_char**)&par.ptr, par.len);
+ if (!this->ec)
+ {
+ goto error;
+ }
+ if (!d2i_ECPrivateKey(&this->ec, (const u_char**)&key.ptr, key.len))
+ {
+ goto error;
+ }
+ }
+ else
+ {
+ this->ec = d2i_ECPrivateKey(NULL, (const u_char**)&key.ptr, key.len);
+ if (!this->ec)
+ {
+ goto error;
+ }
}
if (!EC_KEY_check_key(this->ec))
{
- destroy(this);
- return NULL;
+ goto error;
}
return &this->public;
+
+error:
+ destroy(this);
+ return NULL;
}
#endif /* OPENSSL_NO_EC */
diff --git a/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c b/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c
index 422e31521..a24bae5d6 100644
--- a/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c
+++ b/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c
@@ -44,6 +44,8 @@ struct private_openssl_rsa_public_key_t {
refcount_t ref;
};
+
+
/**
* Verification of an EMPSA PKCS1 signature described in PKCS#1
*/
@@ -386,4 +388,3 @@ openssl_rsa_public_key_t *openssl_rsa_public_key_load(key_type_t type,
destroy(this);
return NULL;
}
-
diff --git a/src/libstrongswan/plugins/pem/pem_builder.c b/src/libstrongswan/plugins/pem/pem_builder.c
index b760adda9..f05d348ee 100644
--- a/src/libstrongswan/plugins/pem/pem_builder.c
+++ b/src/libstrongswan/plugins/pem/pem_builder.c
@@ -73,7 +73,7 @@ static bool find_boundary(char* tag, chunk_t *line)
{
if (present("-----", line))
{
- DBG2(DBG_LIB, " -----%s %.*s-----", tag, (int)name.len, name.ptr);
+ DBG2(DBG_ASN, " -----%s %.*s-----", tag, (int)name.len, name.ptr);
return TRUE;
}
line->ptr++; line->len--; name.len++;
@@ -99,7 +99,7 @@ static status_t pem_decrypt(chunk_t *blob, encryption_algorithm_t alg,
hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5);
if (hasher == NULL)
{
- DBG1(DBG_LIB, " MD5 hash algorithm not available");
+ DBG1(DBG_ASN, " MD5 hash algorithm not available");
return NOT_SUPPORTED;
}
hash.len = hasher->get_hash_size(hasher);
@@ -121,7 +121,7 @@ static status_t pem_decrypt(chunk_t *blob, encryption_algorithm_t alg,
crypter = lib->crypto->create_crypter(lib->crypto, alg, key_size);
if (crypter == NULL)
{
- DBG1(DBG_LIB, " %N encryption algorithm not available",
+ DBG1(DBG_ASN, " %N encryption algorithm not available",
encryption_algorithm_names, alg);
return NOT_SUPPORTED;
}
@@ -131,7 +131,7 @@ static status_t pem_decrypt(chunk_t *blob, encryption_algorithm_t alg,
blob->len % crypter->get_block_size(crypter))
{
crypter->destroy(crypter);
- DBG1(DBG_LIB, " data size is not multiple of block size");
+ DBG1(DBG_ASN, " data size is not multiple of block size");
return PARSE_ERROR;
}
crypter->decrypt(crypter, *blob, iv, &decrypted);
@@ -155,7 +155,7 @@ static status_t pem_decrypt(chunk_t *blob, encryption_algorithm_t alg,
{
if (*last_padding_pos != padding)
{
- DBG1(DBG_LIB, " invalid passphrase");
+ DBG1(DBG_ASN, " invalid passphrase");
return INVALID_ARG;
}
}
@@ -234,7 +234,7 @@ static status_t pem_to_bin(chunk_t *blob, bool *pgp)
}
/* we are looking for a parameter: value pair */
- DBG2(DBG_LIB, " %.*s", (int)line.len, line.ptr);
+ DBG2(DBG_ASN, " %.*s", (int)line.len, line.ptr);
ugh = extract_parameter_value(&name, &value, &line);
if (ugh != NULL)
{
@@ -274,7 +274,7 @@ static status_t pem_to_bin(chunk_t *blob, bool *pgp)
}
else
{
- DBG1(DBG_LIB, " encryption algorithm '%.*s'"
+ DBG1(DBG_ASN, " encryption algorithm '%.*s'"
" not supported", dek.len, dek.ptr);
return NOT_SUPPORTED;
}
@@ -298,7 +298,7 @@ static status_t pem_to_bin(chunk_t *blob, bool *pgp)
*pgp = TRUE;
data.ptr++;
data.len--;
- DBG2(DBG_LIB, " armor checksum: %.*s", (int)data.len,
+ DBG2(DBG_ASN, " armor checksum: %.*s", (int)data.len,
data.ptr);
continue;
}
diff --git a/src/libstrongswan/plugins/pgp/pgp_cert.c b/src/libstrongswan/plugins/pgp/pgp_cert.c
index dea183ce2..5b2ec63fc 100644
--- a/src/libstrongswan/plugins/pgp/pgp_cert.c
+++ b/src/libstrongswan/plugins/pgp/pgp_cert.c
@@ -286,18 +286,18 @@ static bool parse_public_key(private_pgp_cert_t *this, chunk_t packet)
}
break;
default:
- DBG1(DBG_LIB, "PGP packet version V%d not supported",
+ DBG1(DBG_ASN, "PGP packet version V%d not supported",
this->version);
return FALSE;
}
if (this->valid)
{
- DBG2(DBG_LIB, "L2 - created %T, valid %d days", &this->created, FALSE,
+ DBG2(DBG_ASN, "L2 - created %T, valid %d days", &this->created, FALSE,
this->valid);
}
else
{
- DBG2(DBG_LIB, "L2 - created %T, never expires", &this->created, FALSE);
+ DBG2(DBG_ASN, "L2 - created %T, never expires", &this->created, FALSE);
}
DESTROY_IF(this->key);
this->key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ANY,
@@ -318,13 +318,13 @@ static bool parse_public_key(private_pgp_cert_t *this, chunk_t packet)
hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
if (hasher == NULL)
{
- DBG1(DBG_LIB, "no SHA-1 hasher available");
+ DBG1(DBG_ASN, "no SHA-1 hasher available");
return FALSE;
}
hasher->allocate_hash(hasher, pubkey_packet_header, NULL);
hasher->allocate_hash(hasher, pubkey_packet, &this->fingerprint);
hasher->destroy(hasher);
- DBG2(DBG_LIB, "L2 - v4 fingerprint %#B", &this->fingerprint);
+ DBG2(DBG_ASN, "L2 - v4 fingerprint %#B", &this->fingerprint);
}
else
{
@@ -335,7 +335,7 @@ static bool parse_public_key(private_pgp_cert_t *this, chunk_t packet)
return FALSE;
}
this->fingerprint = chunk_clone(this->fingerprint);
- DBG2(DBG_LIB, "L2 - v3 fingerprint %#B", &this->fingerprint);
+ DBG2(DBG_ASN, "L2 - v3 fingerprint %#B", &this->fingerprint);
}
return TRUE;
}
@@ -355,7 +355,7 @@ static bool parse_signature(private_pgp_cert_t *this, chunk_t packet)
/* we parse only v3 or v4 signature packets */
if (version != 3 && version != 4)
{
- DBG2(DBG_LIB, "L2 - v%d signature ignored", version);
+ DBG2(DBG_ASN, "L2 - v%d signature ignored", version);
return TRUE;
}
if (version == 4)
@@ -364,7 +364,7 @@ static bool parse_signature(private_pgp_cert_t *this, chunk_t packet)
{
return FALSE;
}
- DBG2(DBG_LIB, "L2 - v%d signature of type 0x%02x", version, type);
+ DBG2(DBG_ASN, "L2 - v%d signature of type 0x%02x", version, type);
}
else
{
@@ -377,7 +377,7 @@ static bool parse_signature(private_pgp_cert_t *this, chunk_t packet)
{
return FALSE;
}
- DBG2(DBG_LIB, "L2 - v3 signature of type 0x%02x, created %T", type,
+ DBG2(DBG_ASN, "L2 - v3 signature of type 0x%02x, created %T", type,
&created, FALSE);
}
/* TODO: parse and save signature to a list */
@@ -391,7 +391,7 @@ static bool parse_user_id(private_pgp_cert_t *this, chunk_t packet)
{
DESTROY_IF(this->user_id);
this->user_id = identification_create_from_encoding(ID_KEY_ID, packet);
- DBG2(DBG_LIB, "L2 - '%Y'", this->user_id);
+ DBG2(DBG_ASN, "L2 - '%Y'", this->user_id);
return TRUE;
}
diff --git a/src/libstrongswan/plugins/pgp/pgp_utils.c b/src/libstrongswan/plugins/pgp/pgp_utils.c
index 2d85cc0c8..7fd905ce4 100644
--- a/src/libstrongswan/plugins/pgp/pgp_utils.c
+++ b/src/libstrongswan/plugins/pgp/pgp_utils.c
@@ -79,7 +79,7 @@ bool pgp_read_scalar(chunk_t *blob, size_t bytes, u_int32_t *scalar)
if (bytes > blob->len)
{
- DBG1(DBG_LIB, "PGP data too short to read %d byte scalar", bytes);
+ DBG1(DBG_ASN, "PGP data too short to read %d byte scalar", bytes);
return FALSE;
}
while (bytes-- > 0)
@@ -100,13 +100,13 @@ bool pgp_read_mpi(chunk_t *blob, chunk_t *mpi)
if (!pgp_read_scalar(blob, 2, &bits))
{
- DBG1(DBG_LIB, "PGP data too short to read MPI length");
+ DBG1(DBG_ASN, "PGP data too short to read MPI length");
return FALSE;
}
bytes = (bits + 7) / 8;
if (bytes > blob->len)
{
- DBG1(DBG_LIB, "PGP data too short to read %d byte MPI", bytes);
+ DBG1(DBG_ASN, "PGP data too short to read %d byte MPI", bytes);
return FALSE;
}
*mpi = chunk_create(blob->ptr, bytes);
@@ -146,7 +146,7 @@ bool pgp_read_packet(chunk_t *blob, chunk_t *data, pgp_packet_tag_t *tag)
if (!blob->len)
{
- DBG1(DBG_LIB, "missing input");
+ DBG1(DBG_ASN, "missing input");
return FALSE;
}
t = blob->ptr[0];
@@ -154,27 +154,27 @@ bool pgp_read_packet(chunk_t *blob, chunk_t *data, pgp_packet_tag_t *tag)
/* bit 7 must be set */
if (!(t & 0x80))
{
- DBG1(DBG_LIB, "invalid packet tag");
+ DBG1(DBG_ASN, "invalid packet tag");
return FALSE;
}
/* bit 6 set defines new packet format */
if (t & 0x40)
{
- DBG1(DBG_LIB, "new PGP packet format not supported");
+ DBG1(DBG_ASN, "new PGP packet format not supported");
return FALSE;
}
t = (t & 0x3C) >> 2;
if (!pgp_old_packet_length(blob, &len) || len > blob->len)
{
- DBG1(DBG_LIB, "invalid packet length");
+ DBG1(DBG_ASN, "invalid packet length");
return FALSE;
}
*data = chunk_create(blob->ptr, len);
*blob = chunk_skip(*blob, len);
*tag = t;
- DBG2(DBG_LIB, "L1 - PGP %N (%u bytes)", pgp_packet_tag_names, t, len);
- DBG3(DBG_LIB, "%B", data);
+ DBG2(DBG_ASN, "L1 - PGP %N (%u bytes)", pgp_packet_tag_names, t, len);
+ DBG3(DBG_ASN, "%B", data);
return TRUE;
}
diff --git a/src/libstrongswan/plugins/pkcs1/pkcs1_builder.c b/src/libstrongswan/plugins/pkcs1/pkcs1_builder.c
index a605fabc7..6d022f362 100644
--- a/src/libstrongswan/plugins/pkcs1/pkcs1_builder.c
+++ b/src/libstrongswan/plugins/pkcs1/pkcs1_builder.c
@@ -81,10 +81,10 @@ static public_key_t *parse_public_key(chunk_t blob)
/* skip initial bit string octet defining 0 unused bits */
object = chunk_skip(object, 1);
}
- DBG2(DBG_LIB, "-- > --");
+ DBG2(DBG_ASN, "-- > --");
key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, type,
BUILD_BLOB_ASN1_DER, object, BUILD_END);
- DBG2(DBG_LIB, "-- < --");
+ DBG2(DBG_ASN, "-- < --");
break;
}
}
@@ -197,7 +197,7 @@ static private_key_t *parse_rsa_private_key(chunk_t blob)
case PRIV_KEY_VERSION:
if (object.len > 0 && *object.ptr != 0)
{
- DBG1(DBG_LIB, "PKCS#1 private key format is not version 1");
+ DBG1(DBG_ASN, "PKCS#1 private key format is not version 1");
goto end;
}
break;
diff --git a/src/libstrongswan/plugins/pkcs11/pkcs11_public_key.c b/src/libstrongswan/plugins/pkcs11/pkcs11_public_key.c
index d49a03856..d4ec9235d 100644
--- a/src/libstrongswan/plugins/pkcs11/pkcs11_public_key.c
+++ b/src/libstrongswan/plugins/pkcs11/pkcs11_public_key.c
@@ -726,7 +726,7 @@ pkcs11_public_key_t *pkcs11_public_key_load(key_type_t type, va_list args)
{
private_pkcs11_public_key_t *this;
chunk_t n, e, blob;
- size_t keylen;
+ size_t keylen = 0;
n = e = blob = chunk_empty;
while (TRUE)
@@ -810,7 +810,7 @@ static private_pkcs11_public_key_t *find_key_by_keyid(pkcs11_library_t *p11,
bool found = FALSE;
size_t keylen;
- switch (type)
+ switch (key_type)
{
case KEY_RSA:
type = CKK_RSA;
diff --git a/src/libstrongswan/plugins/pkcs8/Makefile.am b/src/libstrongswan/plugins/pkcs8/Makefile.am
new file mode 100644
index 000000000..bcaf2c6a5
--- /dev/null
+++ b/src/libstrongswan/plugins/pkcs8/Makefile.am
@@ -0,0 +1,16 @@
+
+INCLUDES = -I$(top_srcdir)/src/libstrongswan
+
+AM_CFLAGS = -rdynamic
+
+if MONOLITHIC
+noinst_LTLIBRARIES = libstrongswan-pkcs8.la
+else
+plugin_LTLIBRARIES = libstrongswan-pkcs8.la
+endif
+
+libstrongswan_pkcs8_la_SOURCES = \
+ pkcs8_plugin.h pkcs8_plugin.c \
+ pkcs8_builder.h pkcs8_builder.c
+
+libstrongswan_pkcs8_la_LDFLAGS = -module -avoid-version
diff --git a/src/libstrongswan/plugins/pkcs8/pkcs8_builder.c b/src/libstrongswan/plugins/pkcs8/pkcs8_builder.c
new file mode 100644
index 000000000..346240ae1
--- /dev/null
+++ b/src/libstrongswan/plugins/pkcs8/pkcs8_builder.c
@@ -0,0 +1,632 @@
+/*
+ * Copyright (C) 2012 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 "pkcs8_builder.h"
+
+#include <debug.h>
+#include <asn1/oid.h>
+#include <asn1/asn1.h>
+#include <asn1/asn1_parser.h>
+#include <credentials/keys/private_key.h>
+
+/**
+ * ASN.1 definition of a privateKeyInfo structure
+ */
+static const asn1Object_t pkinfoObjects[] = {
+ { 0, "privateKeyInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
+ { 1, "version", ASN1_INTEGER, ASN1_BODY }, /* 1 */
+ { 1, "privateKeyAlgorithm", ASN1_EOC, ASN1_RAW }, /* 2 */
+ { 1, "privateKey", ASN1_OCTET_STRING, ASN1_BODY }, /* 3 */
+ { 1, "attributes", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 4 */
+ { 1, "end opt", ASN1_EOC, ASN1_END }, /* 5 */
+ { 0, "exit", ASN1_EOC, ASN1_EXIT }
+};
+#define PKINFO_PRIVATE_KEY_ALGORITHM 2
+#define PKINFO_PRIVATE_KEY 3
+
+/**
+ * Load a generic private key from an ASN.1 encoded blob
+ */
+static private_key_t *parse_private_key(chunk_t blob)
+{
+ asn1_parser_t *parser;
+ chunk_t object, params = chunk_empty;
+ int objectID;
+ private_key_t *key = NULL;
+ key_type_t type = KEY_ANY;
+
+ parser = asn1_parser_create(pkinfoObjects, blob);
+ parser->set_flags(parser, FALSE, TRUE);
+
+ while (parser->iterate(parser, &objectID, &object))
+ {
+ switch (objectID)
+ {
+ case PKINFO_PRIVATE_KEY_ALGORITHM:
+ {
+ int oid = asn1_parse_algorithmIdentifier(object,
+ parser->get_level(parser) + 1, &params);
+
+ switch (oid)
+ {
+ case OID_RSA_ENCRYPTION:
+ type = KEY_RSA;
+ break;
+ case OID_EC_PUBLICKEY:
+ type = KEY_ECDSA;
+ break;
+ default:
+ /* key type not supported */
+ goto end;
+ }
+ break;
+ }
+ case PKINFO_PRIVATE_KEY:
+ {
+ DBG2(DBG_ASN, "-- > --");
+ if (params.ptr)
+ {
+ key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
+ type, BUILD_BLOB_ALGID_PARAMS,
+ params, BUILD_BLOB_ASN1_DER,
+ object, BUILD_END);
+ }
+ else
+ {
+ key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
+ type, BUILD_BLOB_ASN1_DER, object,
+ BUILD_END);
+ }
+ DBG2(DBG_ASN, "-- < --");
+ break;
+ }
+ }
+ }
+
+end:
+ parser->destroy(parser);
+ return key;
+}
+
+/**
+ * Verify padding of decrypted blob.
+ * Length of blob is adjusted accordingly.
+ */
+static bool verify_padding(chunk_t *blob)
+{
+ u_int8_t padding, count;
+
+ padding = count = blob->ptr[blob->len - 1];
+ if (padding > 8)
+ {
+ return FALSE;
+ }
+ for (; blob->len && count; --blob->len, --count)
+ {
+ if (blob->ptr[blob->len - 1] != padding)
+ {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+/**
+ * Prototype for key derivation functions.
+ */
+typedef void (*kdf_t)(void *generator, chunk_t password, chunk_t salt,
+ u_int64_t iterations, chunk_t key);
+
+/**
+ * Try to decrypt the given blob with multiple passwords using the given
+ * key derivation function. keymat is where the kdf function writes the key
+ * to, key and iv point to the actual keys and initialization vectors resp.
+ */
+static private_key_t *decrypt_private_key(chunk_t blob,
+ encryption_algorithm_t encr, size_t key_len, kdf_t kdf,
+ void *generator, chunk_t salt, u_int64_t iterations,
+ chunk_t keymat, chunk_t key, chunk_t iv)
+{
+ enumerator_t *enumerator;
+ shared_key_t *shared;
+ crypter_t *crypter;
+ private_key_t *private_key = NULL;
+
+ crypter = lib->crypto->create_crypter(lib->crypto, encr, key_len);
+ if (!crypter)
+ {
+ DBG1(DBG_ASN, " %N encryption algorithm not available",
+ encryption_algorithm_names, encr);
+ return NULL;
+ }
+ if (blob.len % crypter->get_block_size(crypter))
+ {
+ DBG1(DBG_ASN, " data size is not a multiple of block size");
+ crypter->destroy(crypter);
+ return NULL;
+ }
+
+ enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr,
+ SHARED_PRIVATE_KEY_PASS, NULL, NULL);
+ while (enumerator->enumerate(enumerator, &shared, NULL, NULL))
+ {
+ chunk_t decrypted;
+
+ kdf(generator, shared->get_key(shared), salt, iterations, keymat);
+
+ crypter->set_key(crypter, key);
+ crypter->decrypt(crypter, blob, iv, &decrypted);
+ if (verify_padding(&decrypted))
+ {
+ private_key = parse_private_key(decrypted);
+ if (private_key)
+ {
+ chunk_clear(&decrypted);
+ break;
+ }
+ }
+ chunk_free(&decrypted);
+ }
+ enumerator->destroy(enumerator);
+ crypter->destroy(crypter);
+
+ return private_key;
+}
+
+/**
+ * Function F of PBKDF2
+ */
+static void pbkdf2_f(chunk_t block, prf_t *prf, chunk_t seed,
+ u_int64_t iterations)
+{
+ chunk_t u;
+ u_int64_t i;
+
+ u = chunk_alloca(prf->get_block_size(prf));
+ prf->get_bytes(prf, seed, u.ptr);
+ memcpy(block.ptr, u.ptr, block.len);
+
+ for (i = 1; i < iterations; i++)
+ {
+ prf->get_bytes(prf, u, u.ptr);
+ memxor(block.ptr, u.ptr, block.len);
+ }
+}
+
+/**
+ * PBKDF2 key derivation function
+ */
+static void pbkdf2(prf_t *prf, chunk_t password, chunk_t salt,
+ u_int64_t iterations, chunk_t key)
+{
+ chunk_t keymat, block, seed;
+ size_t blocks;
+ u_int32_t i = 0, *ni;
+
+ prf->set_key(prf, password);
+
+ block.len = prf->get_block_size(prf);
+ blocks = (key.len - 1) / block.len + 1;
+ keymat = chunk_alloca(blocks * block.len);
+
+ seed = chunk_cata("cc", salt, chunk_from_thing(i));
+ ni = (u_int32_t*)(seed.ptr + salt.len);
+
+ for (; i < blocks; i++)
+ {
+ *ni = htonl(i + 1);
+ block.ptr = keymat.ptr + (i * block.len);
+ pbkdf2_f(block, prf, seed, iterations);
+ }
+
+ memcpy(key.ptr, keymat.ptr, key.len);
+}
+
+/**
+ * Decrypt an encrypted PKCS#8 encoded private key according to PBES2
+ */
+static private_key_t *decrypt_private_key_pbes2(chunk_t blob,
+ encryption_algorithm_t encr, size_t key_len,
+ chunk_t iv, pseudo_random_function_t prf_func,
+ chunk_t salt, u_int64_t iterations)
+{
+ private_key_t *private_key;
+ prf_t *prf;
+ chunk_t key;
+
+ prf = lib->crypto->create_prf(lib->crypto, prf_func);
+ if (!prf)
+ {
+ DBG1(DBG_ASN, " %N prf algorithm not available",
+ pseudo_random_function_names, prf_func);
+ return NULL;
+ }
+
+ key = chunk_alloca(key_len);
+
+ private_key = decrypt_private_key(blob, encr, key_len, (kdf_t)pbkdf2, prf,
+ salt, iterations, key, key, iv);
+
+ prf->destroy(prf);
+ return private_key;
+}
+
+/**
+ * PBKDF1 key derivation function
+ */
+static void pbkdf1(hasher_t *hasher, chunk_t password, chunk_t salt,
+ u_int64_t iterations, chunk_t key)
+{
+ chunk_t hash;
+ u_int64_t i;
+
+ hash = chunk_alloca(hasher->get_hash_size(hasher));
+ hasher->get_hash(hasher, password, NULL);
+ hasher->get_hash(hasher, salt, hash.ptr);
+
+ for (i = 1; i < iterations; i++)
+ {
+ hasher->get_hash(hasher, hash, hash.ptr);
+ }
+
+ memcpy(key.ptr, hash.ptr, key.len);
+}
+
+/**
+ * Decrypt an encrypted PKCS#8 encoded private key according to PBES1
+ */
+static private_key_t *decrypt_private_key_pbes1(chunk_t blob,
+ encryption_algorithm_t encr, size_t key_len,
+ hash_algorithm_t hash, chunk_t salt,
+ u_int64_t iterations)
+{
+ private_key_t *private_key = NULL;
+ hasher_t *hasher = NULL;
+ chunk_t keymat, key, iv;
+
+ hasher = lib->crypto->create_hasher(lib->crypto, hash);
+ if (!hasher)
+ {
+ DBG1(DBG_ASN, " %N hash algorithm not available",
+ hash_algorithm_names, hash);
+ goto end;
+ }
+ if (hasher->get_hash_size(hasher) < key_len)
+ {
+ goto end;
+ }
+
+ keymat = chunk_alloca(key_len * 2);
+ key.len = key_len;
+ key.ptr = keymat.ptr;
+ iv.len = key_len;
+ iv.ptr = keymat.ptr + key_len;
+
+ private_key = decrypt_private_key(blob, encr, key_len, (kdf_t)pbkdf1,
+ hasher, salt, iterations, keymat,
+ key, iv);
+
+end:
+ DESTROY_IF(hasher);
+ return private_key;
+}
+
+/**
+ * Parse an ASN1_INTEGER to a u_int64_t.
+ */
+static u_int64_t parse_asn1_integer_uint64(chunk_t blob)
+{
+ u_int64_t val = 0;
+ int i;
+
+ for (i = 0; i < blob.len; i++)
+ { /* if it is longer than 8 bytes, we just use the 8 LSBs */
+ val <<= 8;
+ val |= (u_int64_t)blob.ptr[i];
+ }
+ return val;
+}
+
+/**
+ * ASN.1 definition of a PBKDF2-params structure
+ * The salt is actually a CHOICE and could be an AlgorithmIdentifier from
+ * PBKDF2-SaltSources (but as per RFC 2898 that's for future versions).
+ */
+static const asn1Object_t pbkdf2ParamsObjects[] = {
+ { 0, "PBKDF2-params", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
+ { 1, "salt", ASN1_OCTET_STRING, ASN1_BODY }, /* 1 */
+ { 1, "iterationCount",ASN1_INTEGER, ASN1_BODY }, /* 2 */
+ { 1, "keyLength", ASN1_INTEGER, ASN1_OPT|ASN1_BODY }, /* 3 */
+ { 1, "end opt", ASN1_EOC, ASN1_END }, /* 4 */
+ { 1, "prf", ASN1_EOC, ASN1_DEF|ASN1_RAW }, /* 5 */
+ { 0, "exit", ASN1_EOC, ASN1_EXIT }
+};
+#define PBKDF2_SALT 1
+#define PBKDF2_ITERATION_COUNT 2
+#define PBKDF2_KEY_LENGTH 3
+#define PBKDF2_PRF 5
+
+/**
+ * Parse a PBKDF2-params structure
+ */
+static void parse_pbkdf2_params(chunk_t blob, chunk_t *salt,
+ u_int64_t *iterations, size_t *key_len,
+ pseudo_random_function_t *prf)
+{
+ asn1_parser_t *parser;
+ chunk_t object;
+ int objectID;
+
+ parser = asn1_parser_create(pbkdf2ParamsObjects, blob);
+
+ *key_len = 0; /* key_len is optional */
+
+ while (parser->iterate(parser, &objectID, &object))
+ {
+ switch (objectID)
+ {
+ case PBKDF2_SALT:
+ {
+ *salt = object;
+ break;
+ }
+ case PBKDF2_ITERATION_COUNT:
+ {
+ *iterations = parse_asn1_integer_uint64(object);
+ break;
+ }
+ case PBKDF2_KEY_LENGTH:
+ {
+ *key_len = (size_t)parse_asn1_integer_uint64(object);
+ break;
+ }
+ case PBKDF2_PRF:
+ { /* defaults to id-hmacWithSHA1 */
+ *prf = PRF_HMAC_SHA1;
+ break;
+ }
+ }
+ }
+
+ parser->destroy(parser);
+}
+
+/**
+ * ASN.1 definition of a PBES2-params structure
+ */
+static const asn1Object_t pbes2ParamsObjects[] = {
+ { 0, "PBES2-params", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
+ { 1, "keyDerivationFunc", ASN1_EOC, ASN1_RAW }, /* 1 */
+ { 1, "encryptionScheme", ASN1_EOC, ASN1_RAW }, /* 2 */
+ { 0, "exit", ASN1_EOC, ASN1_EXIT }
+};
+#define PBES2PARAMS_KEY_DERIVATION_FUNC 1
+#define PBES2PARAMS_ENCRYPTION_SCHEME 2
+
+/**
+ * Parse a PBES2-params structure
+ */
+static void parse_pbes2_params(chunk_t blob, chunk_t *salt,
+ u_int64_t *iterations, size_t *key_len,
+ pseudo_random_function_t *prf,
+ encryption_algorithm_t *encr, chunk_t *iv)
+{
+ asn1_parser_t *parser;
+ chunk_t object, params;
+ int objectID;
+
+ parser = asn1_parser_create(pbes2ParamsObjects, blob);
+
+ while (parser->iterate(parser, &objectID, &object))
+ {
+ switch (objectID)
+ {
+ case PBES2PARAMS_KEY_DERIVATION_FUNC:
+ {
+ int oid = asn1_parse_algorithmIdentifier(object,
+ parser->get_level(parser) + 1, &params);
+ if (oid != OID_PBKDF2)
+ { /* unsupported key derivation function */
+ goto end;
+ }
+ parse_pbkdf2_params(params, salt, iterations, key_len, prf);
+ break;
+ }
+ case PBES2PARAMS_ENCRYPTION_SCHEME:
+ {
+ int oid = asn1_parse_algorithmIdentifier(object,
+ parser->get_level(parser) + 1, &params);
+ if (oid != OID_3DES_EDE_CBC)
+ { /* unsupported encryption scheme */
+ goto end;
+ }
+ if (*key_len <= 0)
+ { /* default key len for DES-EDE3-CBC-Pad */
+ *key_len = 24;
+ }
+ if (!asn1_parse_simple_object(&params, ASN1_OCTET_STRING,
+ parser->get_level(parser) + 1, "IV"))
+ {
+ goto end;
+ }
+ *encr = ENCR_3DES;
+ *iv = params;
+ break;
+ }
+ }
+ }
+
+end:
+ parser->destroy(parser);
+}
+
+/**
+ * ASN.1 definition of a PBEParameter structure
+ */
+static const asn1Object_t pbeParameterObjects[] = {
+ { 0, "PBEParameter", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
+ { 1, "salt", ASN1_OCTET_STRING, ASN1_BODY }, /* 1 */
+ { 1, "iterationCount", ASN1_INTEGER, ASN1_BODY }, /* 2 */
+ { 0, "exit", ASN1_EOC, ASN1_EXIT }
+};
+#define PBEPARAM_SALT 1
+#define PBEPARAM_ITERATION_COUNT 2
+
+/**
+ * Parse a PBEParameter structure
+ */
+static void parse_pbe_parameters(chunk_t blob, chunk_t *salt,
+ u_int64_t *iterations)
+{
+ asn1_parser_t *parser;
+ chunk_t object;
+ int objectID;
+
+ parser = asn1_parser_create(pbeParameterObjects, blob);
+
+ while (parser->iterate(parser, &objectID, &object))
+ {
+ switch (objectID)
+ {
+ case PBEPARAM_SALT:
+ {
+ *salt = object;
+ break;
+ }
+ case PBEPARAM_ITERATION_COUNT:
+ {
+ *iterations = parse_asn1_integer_uint64(object);
+ break;
+ }
+ }
+ }
+
+ parser->destroy(parser);
+}
+
+/**
+ * ASN.1 definition of an encryptedPrivateKeyInfo structure
+ */
+static const asn1Object_t encryptedPKIObjects[] = {
+ { 0, "encryptedPrivateKeyInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
+ { 1, "encryptionAlgorithm", ASN1_EOC, ASN1_RAW }, /* 1 */
+ { 1, "encryptedData", ASN1_OCTET_STRING, ASN1_BODY }, /* 2 */
+ { 0, "exit", ASN1_EOC, ASN1_EXIT }
+};
+#define EPKINFO_ENCRYPTION_ALGORITHM 1
+#define EPKINFO_ENCRYPTED_DATA 2
+
+/**
+ * Load an encrypted private key from an ASN.1 encoded blob
+ * Schemes per PKCS#5 (RFC 2898)
+ */
+static private_key_t *parse_encrypted_private_key(chunk_t blob)
+{
+ asn1_parser_t *parser;
+ chunk_t object, params, salt, iv;
+ u_int64_t iterations = 0;
+ int objectID;
+ encryption_algorithm_t encr = ENCR_UNDEFINED;
+ hash_algorithm_t hash = HASH_UNKNOWN;
+ pseudo_random_function_t prf = PRF_UNDEFINED;
+ private_key_t *key = NULL;
+ size_t key_len = 8;
+
+ parser = asn1_parser_create(encryptedPKIObjects, blob);
+
+ while (parser->iterate(parser, &objectID, &object))
+ {
+ switch (objectID)
+ {
+ case EPKINFO_ENCRYPTION_ALGORITHM:
+ {
+ int oid = asn1_parse_algorithmIdentifier(object,
+ parser->get_level(parser) + 1, &params);
+
+ switch (oid)
+ {
+ case OID_PBE_MD5_DES_CBC:
+ encr = ENCR_DES;
+ hash = HASH_MD5;
+ parse_pbe_parameters(params, &salt, &iterations);
+ break;
+ case OID_PBE_SHA1_DES_CBC:
+ encr = ENCR_DES;
+ hash = HASH_SHA1;
+ parse_pbe_parameters(params, &salt, &iterations);
+ break;
+ case OID_PBES2:
+ parse_pbes2_params(params, &salt, &iterations,
+ &key_len, &prf, &encr, &iv);
+ break;
+ default:
+ /* encryption scheme not supported */
+ goto end;
+ }
+ break;
+ }
+ case EPKINFO_ENCRYPTED_DATA:
+ {
+ if (prf != PRF_UNDEFINED)
+ {
+ key = decrypt_private_key_pbes2(object, encr, key_len, iv,
+ prf, salt, iterations);
+ }
+ else
+ {
+ key = decrypt_private_key_pbes1(object, encr, key_len, hash,
+ salt, iterations);
+ }
+ break;
+ }
+ }
+ }
+
+end:
+ parser->destroy(parser);
+ return key;
+}
+
+/**
+ * See header.
+ */
+private_key_t *pkcs8_private_key_load(key_type_t type, va_list args)
+{
+ chunk_t blob = chunk_empty;
+ private_key_t *key;
+
+ while (TRUE)
+ {
+ switch (va_arg(args, builder_part_t))
+ {
+ case BUILD_BLOB_ASN1_DER:
+ blob = va_arg(args, chunk_t);
+ continue;
+ case BUILD_END:
+ break;
+ default:
+ return NULL;
+ }
+ break;
+ }
+ /* we don't know whether it is encrypted or not, try both ways */
+ key = parse_encrypted_private_key(blob);
+ if (!key)
+ {
+ key = parse_private_key(blob);
+ }
+ return key;
+}
+
diff --git a/src/libstrongswan/plugins/pkcs8/pkcs8_builder.h b/src/libstrongswan/plugins/pkcs8/pkcs8_builder.h
new file mode 100644
index 000000000..b07f2d927
--- /dev/null
+++ b/src/libstrongswan/plugins/pkcs8/pkcs8_builder.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2012 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup pkcs8_builder pkcs8_builder
+ * @{ @ingroup pkcs8
+ */
+
+#ifndef PKCS8_BUILDER_H_
+#define PKCS8_BUILDER_H_
+
+#include <credentials/builder.h>
+#include <credentials/keys/private_key.h>
+
+/**
+ * Load an RSA or ECDSA private key from PKCS#8 data.
+ *
+ * @param type type of the key, KEY_RSA or KEY_ECDSA
+ * @param args builder_part_t argument list
+ * @return private key, NULL on failure
+ */
+private_key_t *pkcs8_private_key_load(key_type_t type, va_list args);
+
+#endif /** PKCS8_BUILDER_H_ @}*/
diff --git a/src/libstrongswan/plugins/pkcs8/pkcs8_plugin.c b/src/libstrongswan/plugins/pkcs8/pkcs8_plugin.c
new file mode 100644
index 000000000..f78c83054
--- /dev/null
+++ b/src/libstrongswan/plugins/pkcs8/pkcs8_plugin.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2012 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 "pkcs8_plugin.h"
+
+#include <library.h>
+
+#include "pkcs8_builder.h"
+
+typedef struct private_pkcs8_plugin_t private_pkcs8_plugin_t;
+
+/**
+ * private data of pkcs8_plugin
+ */
+struct private_pkcs8_plugin_t {
+
+ /**
+ * public functions
+ */
+ pkcs8_plugin_t public;
+};
+
+METHOD(plugin_t, get_name, char*,
+ private_pkcs8_plugin_t *this)
+{
+ return "pkcs8";
+}
+
+METHOD(plugin_t, get_features, int,
+ private_pkcs8_plugin_t *this, plugin_feature_t *features[])
+{
+ static plugin_feature_t f[] = {
+ PLUGIN_REGISTER(PRIVKEY, pkcs8_private_key_load, FALSE),
+ PLUGIN_PROVIDE(PRIVKEY, KEY_RSA),
+ PLUGIN_PROVIDE(PRIVKEY, KEY_ECDSA),
+ };
+ *features = f;
+ return countof(f);
+}
+
+METHOD(plugin_t, destroy, void,
+ private_pkcs8_plugin_t *this)
+{
+ free(this);
+}
+
+/*
+ * see header file
+ */
+plugin_t *pkcs8_plugin_create()
+{
+ private_pkcs8_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/plugins/pkcs8/pkcs8_plugin.h b/src/libstrongswan/plugins/pkcs8/pkcs8_plugin.h
new file mode 100644
index 000000000..03ca950a3
--- /dev/null
+++ b/src/libstrongswan/plugins/pkcs8/pkcs8_plugin.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2012 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 PURPSE. See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup pkcs8 pkcs8
+ * @ingroup plugins
+ *
+ * @defgroup pkcs8_plugin pkcs8_plugin
+ * @{ @ingroup pkcs8
+ */
+
+#ifndef PKCS8_PLUGIN_H_
+#define PKCS8_PLUGIN_H_
+
+#include <plugins/plugin.h>
+
+typedef struct pkcs8_plugin_t pkcs8_plugin_t;
+
+/**
+ * Plugin providing PKCS#8 private key decoding functions
+ */
+struct pkcs8_plugin_t {
+
+ /**
+ * implements plugin interface
+ */
+ plugin_t plugin;
+};
+
+#endif /** PKCS8_PLUGIN_H_ @}*/
diff --git a/src/libstrongswan/plugins/plugin_loader.c b/src/libstrongswan/plugins/plugin_loader.c
index 4d26a77f8..164b68e60 100644
--- a/src/libstrongswan/plugins/plugin_loader.c
+++ b/src/libstrongswan/plugins/plugin_loader.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 Tobias Brunner
+ * Copyright (C) 2010-2012 Tobias Brunner
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -45,6 +45,11 @@ struct private_plugin_loader_t {
* List of plugins, as plugin_entry_t
*/
linked_list_t *plugins;
+
+ /**
+ * List of names of loaded plugins
+ */
+ char *loaded_plugins;
};
/**
@@ -204,6 +209,38 @@ METHOD(plugin_loader_t, create_plugin_enumerator, enumerator_t*,
}
/**
+ * Create a list of the names of all loaded plugins
+ */
+static char* loaded_plugins_list(private_plugin_loader_t *this)
+{
+ int buf_len = 128, len = 0;
+ char *buf, *name;
+ enumerator_t *enumerator;
+ plugin_t *plugin;
+
+ buf = malloc(buf_len);
+ buf[0] = '\0';
+ enumerator = create_plugin_enumerator(this);
+ while (enumerator->enumerate(enumerator, &plugin, NULL))
+ {
+ name = plugin->get_name(plugin);
+ if (len + (strlen(name) + 1) >= buf_len)
+ {
+ buf_len <<= 1;
+ buf = realloc(buf, buf_len);
+ }
+ len += snprintf(&buf[len], buf_len - len, "%s ", name);
+ }
+ enumerator->destroy(enumerator);
+ if (len > 0 && buf[len - 1] == ' ')
+ {
+ buf[len - 1] = '\0';
+ }
+ return buf;
+}
+
+
+/**
* Check if a plugin is already loaded
*/
static bool plugin_loaded(private_plugin_loader_t *this, char *name)
@@ -516,6 +553,11 @@ METHOD(plugin_loader_t, load_plugins, bool,
/* unload plugins that we were not able to load any features for */
purge_plugins(this);
}
+ if (!critical_failed)
+ {
+ free(this->loaded_plugins);
+ this->loaded_plugins = loaded_plugins_list(this);
+ }
return !critical_failed;
}
@@ -558,6 +600,8 @@ METHOD(plugin_loader_t, unload, void,
}
enumerator->destroy(enumerator);
}
+ free(this->loaded_plugins);
+ this->loaded_plugins = NULL;
}
/**
@@ -606,11 +650,18 @@ METHOD(plugin_loader_t, reload, u_int,
return reloaded;
}
+METHOD(plugin_loader_t, loaded_plugins, char*,
+ private_plugin_loader_t *this)
+{
+ return this->loaded_plugins ?: "";
+}
+
METHOD(plugin_loader_t, destroy, void,
private_plugin_loader_t *this)
{
unload(this);
this->plugins->destroy(this->plugins);
+ free(this->loaded_plugins);
free(this);
}
@@ -627,6 +678,7 @@ plugin_loader_t *plugin_loader_create()
.reload = _reload,
.unload = _unload,
.create_plugin_enumerator = _create_plugin_enumerator,
+ .loaded_plugins = _loaded_plugins,
.destroy = _destroy,
},
.plugins = linked_list_create(),
diff --git a/src/libstrongswan/plugins/plugin_loader.h b/src/libstrongswan/plugins/plugin_loader.h
index b3ad7a35f..7fd07044d 100644
--- a/src/libstrongswan/plugins/plugin_loader.h
+++ b/src/libstrongswan/plugins/plugin_loader.h
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2012 Tobias Brunner
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -68,6 +69,15 @@ struct plugin_loader_t {
enumerator_t* (*create_plugin_enumerator)(plugin_loader_t *this);
/**
+ * Get a simple list the names of all loaded plugins.
+ *
+ * The function returns internal data, do not free.
+ *
+ * @return list of the names of all loaded plugins
+ */
+ char* (*loaded_plugins)(plugin_loader_t *this);
+
+ /**
* Unload loaded plugins, destroy plugin_loader instance.
*/
void (*destroy)(plugin_loader_t *this);
diff --git a/src/libstrongswan/plugins/x509/x509_ac.c b/src/libstrongswan/plugins/x509/x509_ac.c
index 16522bf62..a2cb589e0 100644
--- a/src/libstrongswan/plugins/x509/x509_ac.c
+++ b/src/libstrongswan/plugins/x509/x509_ac.c
@@ -192,7 +192,7 @@ static bool parse_directoryName(chunk_t blob, int level, bool implicit, identifi
}
else
{
- DBG1(DBG_LIB, "more than one directory name - first selected");
+ DBG1(DBG_ASN, "more than one directory name - first selected");
directoryName->destroy(directoryName);
}
}
@@ -200,7 +200,7 @@ static bool parse_directoryName(chunk_t blob, int level, bool implicit, identifi
}
else
{
- DBG1(DBG_LIB, "no directoryName found");
+ DBG1(DBG_ASN, "no directoryName found");
}
list->destroy(list);
@@ -359,10 +359,10 @@ static bool parse_certificate(private_x509_ac_t *this)
break;
case AC_OBJ_VERSION:
this->version = (object.len) ? (1 + (u_int)*object.ptr) : 1;
- DBG2(DBG_LIB, " v%d", this->version);
+ DBG2(DBG_ASN, " v%d", this->version);
if (this->version != 2)
{
- DBG1(DBG_LIB, "v%d attribute certificates are not "
+ DBG1(DBG_ASN, "v%d attribute certificates are not "
"supported", this->version);
goto end;
}
@@ -408,20 +408,20 @@ static bool parse_certificate(private_x509_ac_t *this)
switch (type)
{
case OID_AUTHENTICATION_INFO:
- DBG2(DBG_LIB, " need to parse authenticationInfo");
+ DBG2(DBG_ASN, " need to parse authenticationInfo");
break;
case OID_ACCESS_IDENTITY:
- DBG2(DBG_LIB, " need to parse accessIdentity");
+ DBG2(DBG_ASN, " need to parse accessIdentity");
break;
case OID_CHARGING_IDENTITY:
- DBG2(DBG_LIB, "-- > --");
+ DBG2(DBG_ASN, "-- > --");
this->charging = ietf_attributes_create_from_encoding(object);
- DBG2(DBG_LIB, "-- < --");
+ DBG2(DBG_ASN, "-- < --");
break;
case OID_GROUP:
- DBG2(DBG_LIB, "-- > --");
+ DBG2(DBG_ASN, "-- > --");
this->groups = ietf_attributes_create_from_encoding(object);
- DBG2(DBG_LIB, "-- < --");
+ DBG2(DBG_ASN, "-- < --");
break;
case OID_ROLE:
parse_roleSyntax(object, level);
@@ -436,21 +436,21 @@ static bool parse_certificate(private_x509_ac_t *this)
break;
case AC_OBJ_CRITICAL:
critical = object.len && *object.ptr;
- DBG2(DBG_LIB, " %s",(critical)?"TRUE":"FALSE");
+ DBG2(DBG_ASN, " %s",(critical)?"TRUE":"FALSE");
break;
case AC_OBJ_EXTN_VALUE:
{
switch (extn_oid)
{
case OID_CRL_DISTRIBUTION_POINTS:
- DBG2(DBG_LIB, " need to parse crlDistributionPoints");
+ DBG2(DBG_ASN, " need to parse crlDistributionPoints");
break;
case OID_AUTHORITY_KEY_ID:
this->authKeyIdentifier = x509_parse_authorityKeyIdentifier(object,
level, &this->authKeySerialNumber);
break;
case OID_TARGET_INFORMATION:
- DBG2(DBG_LIB, " need to parse targetInformation");
+ DBG2(DBG_ASN, " need to parse targetInformation");
break;
case OID_NO_REV_AVAIL:
this->noRevAvail = TRUE;
@@ -465,7 +465,7 @@ static bool parse_certificate(private_x509_ac_t *this)
NULL);
if (this->algorithm != sig_alg)
{
- DBG1(DBG_LIB, " signature algorithms do not agree");
+ DBG1(DBG_ASN, " signature algorithms do not agree");
success = FALSE;
goto end;
}
@@ -528,7 +528,7 @@ static chunk_t build_attr_cert_validity(private_x509_ac_t *this)
{
return asn1_wrap(ASN1_SEQUENCE, "mm",
asn1_from_time(&this->notBefore, ASN1_GENERALIZEDTIME),
- asn1_from_time(&this->notAfter, ASN1_GENERALIZEDTIME));
+ asn1_from_time(&this->notAfter, ASN1_GENERALIZEDTIME));
}
diff --git a/src/libstrongswan/plugins/x509/x509_cert.c b/src/libstrongswan/plugins/x509/x509_cert.c
index cba1a4610..59f490025 100644
--- a/src/libstrongswan/plugins/x509/x509_cert.c
+++ b/src/libstrongswan/plugins/x509/x509_cert.c
@@ -301,7 +301,7 @@ static void parse_basicConstraints(chunk_t blob, int level0,
{
case BASIC_CONSTRAINTS_CA:
isCA = object.len && *object.ptr;
- DBG2(DBG_LIB, " %s", isCA ? "TRUE" : "FALSE");
+ DBG2(DBG_ASN, " %s", isCA ? "TRUE" : "FALSE");
if (isCA)
{
this->flags |= X509_CA;
@@ -482,7 +482,7 @@ static identification_t *parse_generalName(chunk_t blob, int level0)
if (id_type != ID_ANY)
{
gn = identification_create_from_encoding(id_type, object);
- DBG2(DBG_LIB, " '%Y'", gn);
+ DBG2(DBG_ASN, " '%Y'", gn);
goto end;
}
}
@@ -638,7 +638,7 @@ static void parse_authorityInfoAccess(chunk_t blob, int level0,
/* parsing went wrong - abort */
goto end;
}
- DBG2(DBG_LIB, " '%Y'", id);
+ DBG2(DBG_ASN, " '%Y'", id);
if (accessMethod == OID_OCSP &&
asprintf(&uri, "%Y", id) > 0)
{
@@ -1137,36 +1137,36 @@ static bool check_address_object(ts_type_t ts_type, chunk_t object)
case TS_IPV4_ADDR_RANGE:
if (object.len > 5)
{
- DBG1(DBG_LIB, "IPv4 address object is larger than 5 octets");
+ DBG1(DBG_ASN, "IPv4 address object is larger than 5 octets");
return FALSE;
}
break;
case TS_IPV6_ADDR_RANGE:
if (object.len > 17)
{
- DBG1(DBG_LIB, "IPv6 address object is larger than 17 octets");
+ DBG1(DBG_ASN, "IPv6 address object is larger than 17 octets");
return FALSE;
}
break;
default:
- DBG1(DBG_LIB, "unknown address family");
+ DBG1(DBG_ASN, "unknown address family");
return FALSE;
}
if (object.len == 0)
{
- DBG1(DBG_LIB, "An ASN.1 bit string must contain at least the "
+ DBG1(DBG_ASN, "An ASN.1 bit string must contain at least the "
"initial octet");
return FALSE;
}
if (object.len == 1 && object.ptr[0] != 0)
{
- DBG1(DBG_LIB, "An empty ASN.1 bit string must contain a zero "
+ DBG1(DBG_ASN, "An empty ASN.1 bit string must contain a zero "
"initial octet");
return FALSE;
}
if (object.ptr[0] > 7)
{
- DBG1(DBG_LIB, "number of unused bits is too large");
+ DBG1(DBG_ASN, "number of unused bits is too large");
return FALSE;
}
return TRUE;
@@ -1204,11 +1204,11 @@ static void parse_ipAddrBlocks(chunk_t blob, int level0,
{
break;
}
- DBG2(DBG_LIB, " %N", ts_type_name, ts_type);
+ DBG2(DBG_ASN, " %N", ts_type_name, ts_type);
}
break;
case IP_ADDR_BLOCKS_INHERIT:
- DBG1(DBG_LIB, "inherit choice is not supported");
+ DBG1(DBG_ASN, "inherit choice is not supported");
break;
case IP_ADDR_BLOCKS_PREFIX:
if (!check_address_object(ts_type, object))
@@ -1217,7 +1217,7 @@ static void parse_ipAddrBlocks(chunk_t blob, int level0,
}
ts = traffic_selector_create_from_rfc3779_format(ts_type,
object, object);
- DBG2(DBG_LIB, " %R", ts);
+ DBG2(DBG_ASN, " %R", ts);
this->ipAddrBlocks->insert_last(this->ipAddrBlocks, ts);
break;
case IP_ADDR_BLOCKS_MIN:
@@ -1234,7 +1234,7 @@ static void parse_ipAddrBlocks(chunk_t blob, int level0,
}
ts = traffic_selector_create_from_rfc3779_format(ts_type,
min_object, object);
- DBG2(DBG_LIB, " %R", ts);
+ DBG2(DBG_ASN, " %R", ts);
this->ipAddrBlocks->insert_last(this->ipAddrBlocks, ts);
break;
default:
@@ -1323,12 +1323,12 @@ static bool parse_certificate(private_x509_cert_t *this)
this->version = (object.len) ? (1+(u_int)*object.ptr) : 1;
if (this->version < 1 || this->version > 3)
{
- DBG1(DBG_LIB, "X.509v%d not supported", this->version);
+ DBG1(DBG_ASN, "X.509v%d not supported", this->version);
goto end;
}
else
{
- DBG2(DBG_LIB, " X.509v%d", this->version);
+ DBG2(DBG_ASN, " X.509v%d", this->version);
}
break;
case X509_OBJ_SERIAL_NUMBER:
@@ -1339,7 +1339,7 @@ static bool parse_certificate(private_x509_cert_t *this)
break;
case X509_OBJ_ISSUER:
this->issuer = identification_create_from_encoding(ID_DER_ASN1_DN, object);
- DBG2(DBG_LIB, " '%Y'", this->issuer);
+ DBG2(DBG_ASN, " '%Y'", this->issuer);
break;
case X509_OBJ_NOT_BEFORE:
this->notBefore = asn1_parse_time(object, level);
@@ -1349,13 +1349,13 @@ static bool parse_certificate(private_x509_cert_t *this)
break;
case X509_OBJ_SUBJECT:
this->subject = identification_create_from_encoding(ID_DER_ASN1_DN, object);
- DBG2(DBG_LIB, " '%Y'", this->subject);
+ DBG2(DBG_ASN, " '%Y'", this->subject);
break;
case X509_OBJ_SUBJECT_PUBLIC_KEY_INFO:
- DBG2(DBG_LIB, "-- > --");
+ DBG2(DBG_ASN, "-- > --");
this->public_key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY,
KEY_ANY, BUILD_BLOB_ASN1_DER, object, BUILD_END);
- DBG2(DBG_LIB, "-- < --");
+ DBG2(DBG_ASN, "-- < --");
if (this->public_key == NULL)
{
goto end;
@@ -1364,7 +1364,7 @@ static bool parse_certificate(private_x509_cert_t *this)
case X509_OBJ_OPTIONAL_EXTENSIONS:
if (this->version != 3)
{
- DBG1(DBG_LIB, "Only X.509v3 certificates have extensions");
+ DBG1(DBG_ASN, "Only X.509v3 certificates have extensions");
goto end;
}
break;
@@ -1373,7 +1373,7 @@ static bool parse_certificate(private_x509_cert_t *this)
break;
case X509_OBJ_CRITICAL:
critical = object.len && *object.ptr;
- DBG2(DBG_LIB, " %s", critical ? "TRUE" : "FALSE");
+ DBG2(DBG_ASN, " %s", critical ? "TRUE" : "FALSE");
break;
case X509_OBJ_EXTN_VALUE:
{
@@ -1448,7 +1448,7 @@ static bool parse_certificate(private_x509_cert_t *this)
if (critical && lib->settings->get_bool(lib->settings,
"libstrongswan.x509.enforce_critical", TRUE))
{
- DBG1(DBG_LIB, "critical '%s' extension not supported",
+ DBG1(DBG_ASN, "critical '%s' extension not supported",
(extn_oid == OID_UNKNOWN) ? "unknown" :
(char*)oid_names[extn_oid].name);
goto end;
@@ -1461,7 +1461,7 @@ static bool parse_certificate(private_x509_cert_t *this)
this->algorithm = asn1_parse_algorithmIdentifier(object, level, NULL);
if (this->algorithm != sig_alg)
{
- DBG1(DBG_LIB, " signature algorithms do not agree");
+ DBG1(DBG_ASN, " signature algorithms do not agree");
goto end;
}
break;
@@ -1491,7 +1491,7 @@ end:
hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
if (hasher == NULL)
{
- DBG1(DBG_LIB, " unable to create hash of certificate, SHA1 not supported");
+ DBG1(DBG_ASN, " unable to create hash of certificate, SHA1 not supported");
return NULL;
}
hasher->allocate_hash(hasher, this->encoding, &this->encoding_hash);
@@ -1904,7 +1904,7 @@ chunk_t build_generalName(identification_t *id)
context = ASN1_CONTEXT_S_7;
break;
default:
- DBG1(DBG_LIB, "encoding %N as generalName not supported",
+ DBG1(DBG_ASN, "encoding %N as generalName not supported",
id_type_names, id->get_type(id));
return chunk_empty;
}
diff --git a/src/libstrongswan/plugins/x509/x509_crl.c b/src/libstrongswan/plugins/x509/x509_crl.c
index 758505ab5..7bcca16a3 100644
--- a/src/libstrongswan/plugins/x509/x509_crl.c
+++ b/src/libstrongswan/plugins/x509/x509_crl.c
@@ -242,14 +242,14 @@ static bool parse(private_x509_crl_t *this)
break;
case CRL_OBJ_VERSION:
this->version = (object.len) ? (1+(u_int)*object.ptr) : 1;
- DBG2(DBG_LIB, " v%d", this->version);
+ DBG2(DBG_ASN, " v%d", this->version);
break;
case CRL_OBJ_SIG_ALG:
sig_alg = asn1_parse_algorithmIdentifier(object, level, NULL);
break;
case CRL_OBJ_ISSUER:
this->issuer = identification_create_from_encoding(ID_DER_ASN1_DN, object);
- DBG2(DBG_LIB, " '%Y'", this->issuer);
+ DBG2(DBG_ASN, " '%Y'", this->issuer);
break;
case CRL_OBJ_THIS_UPDATE:
this->thisUpdate = asn1_parse_time(object, level);
@@ -274,7 +274,7 @@ static bool parse(private_x509_crl_t *this)
case CRL_OBJ_CRL_ENTRY_CRITICAL:
case CRL_OBJ_CRITICAL:
critical = object.len && *object.ptr;
- DBG2(DBG_LIB, " %s", critical ? "TRUE" : "FALSE");
+ DBG2(DBG_ASN, " %s", critical ? "TRUE" : "FALSE");
break;
case CRL_OBJ_CRL_ENTRY_EXTN_VALUE:
case CRL_OBJ_EXTN_VALUE:
@@ -291,7 +291,7 @@ static bool parse(private_x509_crl_t *this)
{
revoked->reason = *object.ptr;
}
- DBG2(DBG_LIB, " '%N'", crl_reason_names,
+ DBG2(DBG_ASN, " '%N'", crl_reason_names,
revoked->reason);
}
break;
@@ -324,7 +324,7 @@ static bool parse(private_x509_crl_t *this)
if (critical && lib->settings->get_bool(lib->settings,
"libstrongswan.x509.enforce_critical", TRUE))
{
- DBG1(DBG_LIB, "critical '%s' extension not supported",
+ DBG1(DBG_ASN, "critical '%s' extension not supported",
(extn_oid == OID_UNKNOWN) ? "unknown" :
(char*)oid_names[extn_oid].name);
goto end;
@@ -338,7 +338,7 @@ static bool parse(private_x509_crl_t *this)
this->algorithm = asn1_parse_algorithmIdentifier(object, level, NULL);
if (this->algorithm != sig_alg)
{
- DBG1(DBG_LIB, " signature algorithms do not agree");
+ DBG1(DBG_ASN, " signature algorithms do not agree");
goto end;
}
break;
diff --git a/src/libstrongswan/plugins/x509/x509_ocsp_response.c b/src/libstrongswan/plugins/x509/x509_ocsp_response.c
index 23b206fb1..7dfef3993 100644
--- a/src/libstrongswan/plugins/x509/x509_ocsp_response.c
+++ b/src/libstrongswan/plugins/x509/x509_ocsp_response.c
@@ -507,7 +507,7 @@ static bool parse_basicOCSPResponse(private_x509_ocsp_response_t *this,
if (version != OCSP_BASIC_RESPONSE_VERSION)
{
- DBG1(DBG_LIB, " ocsp ResponseData version %d not "
+ DBG1(DBG_ASN, " ocsp ResponseData version %d not "
"supported", version);
goto end;
}
@@ -516,12 +516,12 @@ static bool parse_basicOCSPResponse(private_x509_ocsp_response_t *this,
case BASIC_RESPONSE_ID_BY_NAME:
this->responderId = identification_create_from_encoding(
ID_DER_ASN1_DN, object);
- DBG2(DBG_LIB, " '%Y'", this->responderId);
+ DBG2(DBG_ASN, " '%Y'", this->responderId);
break;
case BASIC_RESPONSE_ID_BY_KEY:
this->responderId = identification_create_from_encoding(
ID_KEY_ID, object);
- DBG2(DBG_LIB, " '%Y'", this->responderId);
+ DBG2(DBG_ASN, " '%Y'", this->responderId);
break;
case BASIC_RESPONSE_PRODUCED_AT:
this->producedAt = asn1_to_time(&object, ASN1_GENERALIZEDTIME);
@@ -535,7 +535,7 @@ static bool parse_basicOCSPResponse(private_x509_ocsp_response_t *this,
break;
case BASIC_RESPONSE_CRITICAL:
critical = object.len && *object.ptr;
- DBG2(DBG_LIB, " %s", critical ? "TRUE" : "FALSE");
+ DBG2(DBG_ASN, " %s", critical ? "TRUE" : "FALSE");
break;
case BASIC_RESPONSE_EXT_VALUE:
if (extn_oid == OID_NONCE)
diff --git a/src/libstrongswan/plugins/x509/x509_pkcs10.c b/src/libstrongswan/plugins/x509/x509_pkcs10.c
index a19a3998a..ca08db2c6 100644
--- a/src/libstrongswan/plugins/x509/x509_pkcs10.c
+++ b/src/libstrongswan/plugins/x509/x509_pkcs10.c
@@ -276,7 +276,7 @@ static bool parse_extension_request(private_x509_pkcs10_t *this, chunk_t blob, i
break;
case PKCS10_EXTN_CRITICAL:
critical = object.len && *object.ptr;
- DBG2(DBG_LIB, " %s", critical ? "TRUE" : "FALSE");
+ DBG2(DBG_ASN, " %s", critical ? "TRUE" : "FALSE");
break;
case PKCS10_EXTN_VALUE:
{
@@ -309,25 +309,25 @@ static bool parse_challengePassword(private_x509_pkcs10_t *this, chunk_t blob, i
if (blob.len < 2)
{
- DBG1(DBG_LIB, "L%d - challengePassword: ASN.1 object smaller "
+ DBG1(DBG_ASN, "L%d - challengePassword: ASN.1 object smaller "
"than 2 octets", level);
return FALSE;
}
tag = *blob.ptr;
if (tag < ASN1_UTF8STRING || tag > ASN1_IA5STRING)
{
- DBG1(DBG_LIB, "L%d - challengePassword: ASN.1 object is not "
+ DBG1(DBG_ASN, "L%d - challengePassword: ASN.1 object is not "
"a character string", level);
return FALSE;
}
if (asn1_length(&blob) == ASN1_INVALID_LENGTH)
{
- DBG1(DBG_LIB, "L%d - challengePassword: ASN.1 object has an "
+ DBG1(DBG_ASN, "L%d - challengePassword: ASN.1 object has an "
"invalid length", level);
return FALSE;
}
- DBG2(DBG_LIB, "L%d - challengePassword:", level);
- DBG4(DBG_LIB, " '%.*s'", blob.len, blob.ptr);
+ DBG2(DBG_ASN, "L%d - challengePassword:", level);
+ DBG4(DBG_ASN, " '%.*s'", blob.len, blob.ptr);
return TRUE;
}
@@ -385,14 +385,14 @@ static bool parse_certificate_request(private_x509_pkcs10_t *this)
case PKCS10_VERSION:
if (object.len > 0 && *object.ptr != 0)
{
- DBG1(DBG_LIB, "PKCS#10 certificate request format is "
+ DBG1(DBG_ASN, "PKCS#10 certificate request format is "
"not version 1");
goto end;
}
break;
case PKCS10_SUBJECT:
this->subject = identification_create_from_encoding(ID_DER_ASN1_DN, object);
- DBG2(DBG_LIB, " '%Y'", this->subject);
+ DBG2(DBG_ASN, " '%Y'", this->subject);
break;
case PKCS10_SUBJECT_PUBLIC_KEY_INFO:
this->public_key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY,
diff --git a/src/libstrongswan/processing/processor.c b/src/libstrongswan/processing/processor.c
index be33fcd84..222f1a535 100644
--- a/src/libstrongswan/processing/processor.c
+++ b/src/libstrongswan/processing/processor.c
@@ -102,7 +102,7 @@ static void restart(private_processor_t *this)
{
thread_t *thread;
- DBG2(DBG_JOB, "terminated worker thread, ID: %u", thread_current_id());
+ DBG2(DBG_JOB, "terminated worker thread %.2u", thread_current_id());
/* respawn thread if required */
this->mutex->lock(this->mutex);
@@ -152,7 +152,7 @@ static void process_jobs(private_processor_t *this)
/* worker threads are not cancellable by default */
thread_cancelability(FALSE);
- DBG2(DBG_JOB, "started worker thread, ID: %u", thread_current_id());
+ DBG2(DBG_JOB, "started worker thread %.2u", thread_current_id());
this->mutex->lock(this->mutex);
while (this->desired_threads >= this->total_threads)
@@ -230,7 +230,7 @@ METHOD(processor_t, get_idle_threads, u_int,
*/
static job_priority_t sane_prio(job_priority_t prio)
{
- if (prio < 0 || prio >= JOB_PRIO_MAX)
+ if ((int)prio < 0 || prio >= JOB_PRIO_MAX)
{
return JOB_PRIO_MAX - 1;
}
diff --git a/src/libstrongswan/threading/thread.c b/src/libstrongswan/threading/thread.c
index 5b6f0d2ce..49a1b8430 100644
--- a/src/libstrongswan/threading/thread.c
+++ b/src/libstrongswan/threading/thread.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 Tobias Brunner
+ * Copyright (C) 2009-2012 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -18,6 +18,19 @@
#include <signal.h>
#include <semaphore.h>
+#ifdef HAVE_GETTID
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_SYS_GETTID
+#include <sys/syscall.h>
+static inline pid_t gettid()
+{
+ return syscall(SYS_gettid);
+}
+#endif
+
#include <library.h>
#include <debug.h>
@@ -278,6 +291,17 @@ static void *thread_main(private_thread_t *this)
sem_wait(&this->created);
current_thread->set(current_thread, this);
pthread_cleanup_push((thread_cleanup_t)thread_cleanup, this);
+
+ /* TODO: this is not 100% portable as pthread_t is an opaque type (i.e.
+ * could be of any size, or even a struct) */
+#ifdef HAVE_GETTID
+ DBG2(DBG_LIB, "created thread %.2d [%u]",
+ this->id, gettid());
+#else
+ DBG2(DBG_LIB, "created thread %.2d [%lx]",
+ this->id, (u_long)this->thread_id);
+#endif
+
res = this->main(this->arg);
pthread_cleanup_pop(TRUE);
@@ -414,12 +438,20 @@ void thread_exit(void *val)
}
/**
+ * A dummy thread value that reserved pthread_key_t value "0". A buggy PKCS#11
+ * library mangles this key, without owning it, so we allocate it for them.
+ */
+static thread_value_t *dummy1;
+
+/**
* Described in header.
*/
void threads_init()
{
private_thread_t *main_thread = thread_create_internal();
+ dummy1 = thread_value_create(NULL);
+
main_thread->id = 0;
main_thread->thread_id = pthread_self();
current_thread = thread_value_create(NULL);
@@ -443,6 +475,8 @@ void threads_deinit()
{
private_thread_t *main_thread = (private_thread_t*)thread_current();
+ dummy1->destroy(dummy1);
+
main_thread->mutex->lock(main_thread->mutex);
thread_destroy(main_thread);
current_thread->destroy(current_thread);
diff --git a/src/libstrongswan/utils.c b/src/libstrongswan/utils.c
index 2fe7f653c..5a104de7f 100644
--- a/src/libstrongswan/utils.c
+++ b/src/libstrongswan/utils.c
@@ -344,6 +344,28 @@ bool ref_put(refcount_t *ref)
pthread_mutex_unlock(&ref_mutex);
return !more_refs;
}
+
+/**
+ * Single mutex for all compare and swap operations.
+ */
+static pthread_mutex_t cas_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/**
+ * Compare and swap if equal to old value
+ */
+#define _cas_impl(name, type) \
+bool cas_##name(type *ptr, type oldval, type newval) \
+{ \
+ bool swapped; \
+ pthread_mutex_lock(&cas_mutex); \
+ if ((swapped = (*ptr == oldval))) { *ptr = newval; } \
+ pthread_mutex_unlock(&cas_mutex); \
+ return swapped; \
+}
+
+_cas_impl(bool, bool)
+_cas_impl(ptr, void*)
+
#endif /* HAVE_GCC_ATOMIC_OPERATIONS */
/**
diff --git a/src/libstrongswan/utils.h b/src/libstrongswan/utils.h
index e5e4a10c0..367b3e37c 100644
--- a/src/libstrongswan/utils.h
+++ b/src/libstrongswan/utils.h
@@ -579,6 +579,11 @@ typedef volatile u_int refcount_t;
#define ref_get(ref) {__sync_fetch_and_add(ref, 1); }
#define ref_put(ref) (!__sync_sub_and_fetch(ref, 1))
+#define cas_bool(ptr, oldval, newval) \
+ (__sync_bool_compare_and_swap(ptr, oldval, newval))
+#define cas_ptr(ptr, oldval, newval) \
+ (__sync_bool_compare_and_swap(ptr, oldval, newval))
+
#else /* !HAVE_GCC_ATOMIC_OPERATIONS */
/**
@@ -601,6 +606,27 @@ void ref_get(refcount_t *ref);
*/
bool ref_put(refcount_t *ref);
+/**
+ * Atomically replace value of ptr with newval if it currently equals oldval.
+ *
+ * @param ptr pointer to variable
+ * @param oldval old value of the variable
+ * @param newval new value set if possible
+ * @return TRUE if value equaled oldval and newval was written
+ */
+bool cas_bool(bool *ptr, bool oldval, bool newval);
+
+/**
+ * Atomically replace value of ptr with newval if it currently equals oldval.
+ *
+ * @param ptr pointer to variable
+ * @param oldval old value of the variable
+ * @param newval new value set if possible
+ * @return TRUE if value equaled oldval and newval was written
+ */
+bool cas_ptr(void **ptr, void *oldval, void *newval);
+
+
#endif /* HAVE_GCC_ATOMIC_OPERATIONS */
/**
diff --git a/src/libstrongswan/utils/leak_detective.c b/src/libstrongswan/utils/leak_detective.c
index 93cc027de..0a8789335 100644
--- a/src/libstrongswan/utils/leak_detective.c
+++ b/src/libstrongswan/utils/leak_detective.c
@@ -194,6 +194,7 @@ char *whitelist[] = {
"__pthread_setspecific",
/* glibc functions */
"mktime",
+ "ctime",
"__gmtime_r",
"localtime_r",
"tzset",
diff --git a/src/libtls/Makefile.am b/src/libtls/Makefile.am
index 36335e84b..4cc1a1bdb 100644
--- a/src/libtls/Makefile.am
+++ b/src/libtls/Makefile.am
@@ -11,6 +11,7 @@ libtls_la_SOURCES = \
tls_prf.h tls_prf.c \
tls_socket.h tls_socket.c \
tls_eap.h tls_eap.c \
+ tls_cache.h tls_cache.c \
tls_peer.h tls_peer.c \
tls_server.h tls_server.c \
tls_handshake.h tls_application.h tls.h tls.c
diff --git a/src/libtls/tls.c b/src/libtls/tls.c
index 3941bea26..2bcaffbc8 100644
--- a/src/libtls/tls.c
+++ b/src/libtls/tls.c
@@ -437,7 +437,7 @@ METHOD(tls_t, destroy, void,
*/
tls_t *tls_create(bool is_server, identification_t *server,
identification_t *peer, tls_purpose_t purpose,
- tls_application_t *application)
+ tls_application_t *application, tls_cache_t *cache)
{
private_tls_t *this;
@@ -472,7 +472,7 @@ tls_t *tls_create(bool is_server, identification_t *server,
.purpose = purpose,
);
- this->crypto = tls_crypto_create(&this->public);
+ this->crypto = tls_crypto_create(&this->public, cache);
this->alert = tls_alert_create();
if (is_server)
{
diff --git a/src/libtls/tls.h b/src/libtls/tls.h
index 068ba542c..e22b0facc 100644
--- a/src/libtls/tls.h
+++ b/src/libtls/tls.h
@@ -35,6 +35,7 @@ typedef struct tls_t tls_t;
#include <library.h>
#include "tls_application.h"
+#include "tls_cache.h"
/**
* TLS/SSL version numbers
@@ -240,10 +241,11 @@ void libtls_init(void);
* @param peer peer identity, NULL for no client authentication
* @param purpose purpose this TLS stack instance is used for
* @param application higher layer application or NULL if none
+ * @param cache session cache to use, or NULL
* @return TLS stack
*/
tls_t *tls_create(bool is_server, identification_t *server,
identification_t *peer, tls_purpose_t purpose,
- tls_application_t *application);
+ tls_application_t *application, tls_cache_t *cache);
#endif /** TLS_H_ @}*/
diff --git a/src/libtls/tls_cache.c b/src/libtls/tls_cache.c
new file mode 100644
index 000000000..a89201ad7
--- /dev/null
+++ b/src/libtls/tls_cache.c
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2011 Martin Willi
+ * Copyright (C) 2011 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 "tls_cache.h"
+
+#include <debug.h>
+#include <utils/linked_list.h>
+#include <utils/hashtable.h>
+#include <threading/rwlock.h>
+
+typedef struct private_tls_cache_t private_tls_cache_t;
+
+/**
+ * Private data of an tls_cache_t object.
+ */
+struct private_tls_cache_t {
+
+ /**
+ * Public tls_cache_t interface.
+ */
+ tls_cache_t public;
+
+ /**
+ * Mapping session => entry_t, fast lookup by session
+ */
+ hashtable_t *table;
+
+ /**
+ * List containing all entries
+ */
+ linked_list_t *list;
+
+ /**
+ * Lock to list and table
+ */
+ rwlock_t *lock;
+
+ /**
+ * Session limit
+ */
+ u_int max_sessions;
+
+ /**
+ * maximum age of a session, in seconds
+ */
+ u_int max_age;
+};
+
+/**
+ * Hashtable entry
+ */
+typedef struct {
+ /** session identifier */
+ chunk_t session;
+ /** master secret */
+ chunk_t master;
+ /** TLS cipher suite */
+ tls_cipher_suite_t suite;
+ /** optional identity this entry is bound to */
+ identification_t *id;
+ /** time of add */
+ time_t t;
+} entry_t;
+
+/**
+ * Destroy an entry
+ */
+static void entry_destroy(entry_t *entry)
+{
+ chunk_clear(&entry->session);
+ chunk_clear(&entry->master);
+ DESTROY_IF(entry->id);
+ free(entry);
+}
+
+/**
+ * Hashtable hash function
+ */
+static u_int hash(chunk_t *key)
+{
+ return chunk_hash(*key);
+}
+
+/**
+ * Hashtable equals function
+ */
+static bool equals(chunk_t *a, chunk_t *b)
+{
+ return chunk_equals(*a, *b);
+}
+
+METHOD(tls_cache_t, create_, void,
+ private_tls_cache_t *this, chunk_t session, identification_t *id,
+ chunk_t master, tls_cipher_suite_t suite)
+{
+ entry_t *entry;
+
+ INIT(entry,
+ .session = chunk_clone(session),
+ .master = chunk_clone(master),
+ .suite = suite,
+ .id = id ? id->clone(id) : NULL,
+ .t = time_monotonic(NULL),
+ );
+
+ this->lock->write_lock(this->lock);
+ this->list->insert_first(this->list, entry);
+ this->table->put(this->table, &entry->session, entry);
+ if (this->list->get_count(this->list) > this->max_sessions &&
+ this->list->remove_last(this->list, (void**)&entry) == SUCCESS)
+ {
+ DBG2(DBG_TLS, "session limit of %u reached, deleting %#B",
+ this->max_sessions, &entry->session);
+ this->table->remove(this->table, &entry->session);
+ entry_destroy(entry);
+ }
+ this->lock->unlock(this->lock);
+
+ DBG2(DBG_TLS, "created TLS session %#B, %d sessions",
+ &session, this->list->get_count(this->list));
+}
+
+METHOD(tls_cache_t, lookup, tls_cipher_suite_t,
+ private_tls_cache_t *this, chunk_t session, identification_t *id,
+ chunk_t* master)
+{
+ tls_cipher_suite_t suite = 0;
+ entry_t *entry;
+ time_t now;
+ u_int age;
+
+ now = time_monotonic(NULL);
+
+ this->lock->write_lock(this->lock);
+ entry = this->table->get(this->table, &session);
+ if (entry)
+ {
+ age = now - entry->t;
+ if (age <= this->max_age)
+ {
+ if (!id || !entry->id || id->equals(id, entry->id))
+ {
+ *master = chunk_clone(entry->master);
+ suite = entry->suite;
+ }
+ }
+ else
+ {
+ DBG2(DBG_TLS, "TLS session %#B expired: %u seconds", &session, age);
+ }
+ }
+ this->lock->unlock(this->lock);
+
+ if (suite)
+ {
+ DBG2(DBG_TLS, "resuming TLS session %#B, age %u seconds", &session, age);
+ }
+ return suite;
+}
+
+METHOD(tls_cache_t, check, chunk_t,
+ private_tls_cache_t *this, identification_t *id)
+{
+ chunk_t session = chunk_empty;
+ enumerator_t *enumerator;
+ entry_t *entry;
+ time_t now;
+
+ now = time_monotonic(NULL);
+ this->lock->read_lock(this->lock);
+ enumerator = this->list->create_enumerator(this->list);
+ while (enumerator->enumerate(enumerator, &entry))
+ {
+ if (entry->t + this->max_age >= now &&
+ entry->id && id->equals(id, entry->id))
+ {
+ session = chunk_clone(entry->session);
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+
+ return session;
+}
+
+METHOD(tls_cache_t, destroy, void,
+ private_tls_cache_t *this)
+{
+ entry_t *entry;
+
+ while (this->list->remove_last(this->list, (void**)&entry) == SUCCESS)
+ {
+ entry_destroy(entry);
+ }
+ this->list->destroy(this->list);
+ this->table->destroy(this->table);
+ this->lock->destroy(this->lock);
+ free(this);
+}
+
+/**
+ * See header
+ */
+tls_cache_t *tls_cache_create(u_int max_sessions, u_int max_age)
+{
+ private_tls_cache_t *this;
+
+ INIT(this,
+ .public = {
+ .create = _create_,
+ .lookup = _lookup,
+ .check = _check,
+ .destroy = _destroy,
+ },
+ .table = hashtable_create((hashtable_hash_t)hash,
+ (hashtable_equals_t)equals, 8),
+ .list = linked_list_create(),
+ .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
+ .max_sessions = max_sessions,
+ .max_age = max_age,
+ );
+
+ return &this->public;
+}
diff --git a/src/libtls/tls_cache.h b/src/libtls/tls_cache.h
new file mode 100644
index 000000000..ea4e2013e
--- /dev/null
+++ b/src/libtls/tls_cache.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2011 Martin Willi
+ * Copyright (C) 2011 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 tls_cache tls_cache
+ * @{ @ingroup libtls
+ */
+
+#ifndef TLS_CACHE_H_
+#define TLS_CACHE_H_
+
+typedef struct tls_cache_t tls_cache_t;
+
+#include "tls_crypto.h"
+
+/**
+ * TLS session cache facility.
+ */
+struct tls_cache_t {
+
+ /**
+ * Create a new TLS session entry.
+ *
+ * @param session session identifier
+ * @param id identity the session is bound to
+ * @param master TLS master secret
+ * @param suite TLS cipher suite of the session
+ */
+ void (*create)(tls_cache_t *this, chunk_t session, identification_t *id,
+ chunk_t master, tls_cipher_suite_t suite);
+
+ /**
+ * Look up a TLS session entry.
+ *
+ * @param session session ID to find
+ * @param id identity the session is bound to
+ * @param master gets allocated master secret, if session found
+ * @return TLS suite of session, 0 if none found
+ */
+ tls_cipher_suite_t (*lookup)(tls_cache_t *this, chunk_t session,
+ identification_t *id, chunk_t* master);
+
+ /**
+ * Check if we have a session for a given identity.
+ *
+ * @param id identity to check
+ * @return allocated session ID, or chunk_empty
+ */
+ chunk_t (*check)(tls_cache_t *this, identification_t *id);
+
+ /**
+ * Destroy a tls_cache_t.
+ */
+ void (*destroy)(tls_cache_t *this);
+};
+
+/**
+ * Create a tls_cache instance.
+ *
+ * @param max_sessions maximum number of sessions to store
+ * @param max_age maximum age of a session, in seconds
+ * @return tls cache
+ */
+tls_cache_t *tls_cache_create(u_int max_sessions, u_int max_age);
+
+#endif /** TLS_CACHE_H_ @}*/
diff --git a/src/libtls/tls_compression.h b/src/libtls/tls_compression.h
index b4832ab06..b2c60d5d6 100644
--- a/src/libtls/tls_compression.h
+++ b/src/libtls/tls_compression.h
@@ -23,12 +23,12 @@
#include <library.h>
+typedef struct tls_compression_t tls_compression_t;
+
#include "tls.h"
#include "tls_alert.h"
#include "tls_fragmentation.h"
-typedef struct tls_compression_t tls_compression_t;
-
/**
* TLS record protocol compression layer.
*/
diff --git a/src/libtls/tls_crypto.c b/src/libtls/tls_crypto.c
index b9a5d6627..4d84876d0 100644
--- a/src/libtls/tls_crypto.c
+++ b/src/libtls/tls_crypto.c
@@ -370,6 +370,11 @@ struct private_tls_crypto_t {
tls_t *tls;
/**
+ * TLS session cache
+ */
+ tls_cache_t *cache;
+
+ /**
* All handshake data concatentated
*/
chunk_t handshake;
@@ -437,7 +442,7 @@ typedef struct {
static suite_algs_t suite_algs[] = {
{ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
KEY_ECDSA, ECP_256_BIT,
- HASH_SHA1, PRF_HMAC_SHA1,
+ HASH_SHA256, PRF_HMAC_SHA2_256,
AUTH_HMAC_SHA1_160, ENCR_AES_CBC, 16
},
{ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
@@ -447,7 +452,7 @@ static suite_algs_t suite_algs[] = {
},
{ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
KEY_ECDSA, ECP_384_BIT,
- HASH_SHA1, PRF_HMAC_SHA1,
+ HASH_SHA256, PRF_HMAC_SHA2_256,
AUTH_HMAC_SHA1_160, ENCR_AES_CBC, 32
},
{ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
@@ -457,7 +462,7 @@ static suite_algs_t suite_algs[] = {
},
{ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
KEY_RSA, ECP_256_BIT,
- HASH_SHA1, PRF_HMAC_SHA1,
+ HASH_SHA256, PRF_HMAC_SHA2_256,
AUTH_HMAC_SHA1_160, ENCR_AES_CBC, 16
},
{ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
@@ -467,7 +472,7 @@ static suite_algs_t suite_algs[] = {
},
{ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
KEY_RSA, ECP_384_BIT,
- HASH_SHA1, PRF_HMAC_SHA1,
+ HASH_SHA256, PRF_HMAC_SHA2_256,
AUTH_HMAC_SHA1_160, ENCR_AES_CBC, 32
},
{ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
@@ -477,7 +482,7 @@ static suite_algs_t suite_algs[] = {
},
{ TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
KEY_RSA, MODP_2048_BIT,
- HASH_SHA1, PRF_HMAC_SHA1,
+ HASH_SHA256,PRF_HMAC_SHA2_256,
AUTH_HMAC_SHA1_160, ENCR_AES_CBC, 16
},
{ TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
@@ -487,7 +492,7 @@ static suite_algs_t suite_algs[] = {
},
{ TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
KEY_RSA, MODP_3072_BIT,
- HASH_SHA1, PRF_HMAC_SHA1,
+ HASH_SHA256, PRF_HMAC_SHA2_256,
AUTH_HMAC_SHA1_160, ENCR_AES_CBC, 32
},
{ TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
@@ -497,7 +502,7 @@ static suite_algs_t suite_algs[] = {
},
{ TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA,
KEY_RSA, MODP_2048_BIT,
- HASH_SHA1, PRF_HMAC_SHA1,
+ HASH_SHA256, PRF_HMAC_SHA2_256,
AUTH_HMAC_SHA1_160, ENCR_CAMELLIA_CBC, 16
},
{ TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256,
@@ -507,7 +512,7 @@ static suite_algs_t suite_algs[] = {
},
{ TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA,
KEY_RSA, MODP_3072_BIT,
- HASH_SHA1, PRF_HMAC_SHA1,
+ HASH_SHA256, PRF_HMAC_SHA2_256,
AUTH_HMAC_SHA1_160, ENCR_CAMELLIA_CBC, 32
},
{ TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256,
@@ -517,12 +522,12 @@ static suite_algs_t suite_algs[] = {
},
{ TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
KEY_RSA, MODP_2048_BIT,
- HASH_SHA1, PRF_HMAC_SHA1,
+ HASH_SHA256, PRF_HMAC_SHA2_256,
AUTH_HMAC_SHA1_160, ENCR_3DES, 0
},
{ TLS_RSA_WITH_AES_128_CBC_SHA,
KEY_RSA, MODP_NONE,
- HASH_SHA1, PRF_HMAC_SHA1,
+ HASH_SHA256, PRF_HMAC_SHA2_256,
AUTH_HMAC_SHA1_160, ENCR_AES_CBC, 16
},
{ TLS_RSA_WITH_AES_128_CBC_SHA256,
@@ -532,7 +537,7 @@ static suite_algs_t suite_algs[] = {
},
{ TLS_RSA_WITH_AES_256_CBC_SHA,
KEY_RSA, MODP_NONE,
- HASH_SHA1, PRF_HMAC_SHA1,
+ HASH_SHA256, PRF_HMAC_SHA2_256,
AUTH_HMAC_SHA1_160, ENCR_AES_CBC, 32
},
{ TLS_RSA_WITH_AES_256_CBC_SHA256,
@@ -542,7 +547,7 @@ static suite_algs_t suite_algs[] = {
},
{ TLS_RSA_WITH_CAMELLIA_128_CBC_SHA,
KEY_RSA, MODP_NONE,
- HASH_SHA1, PRF_HMAC_SHA1,
+ HASH_SHA256, PRF_HMAC_SHA2_256,
AUTH_HMAC_SHA1_160, ENCR_CAMELLIA_CBC, 16
},
{ TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256,
@@ -552,7 +557,7 @@ static suite_algs_t suite_algs[] = {
},
{ TLS_RSA_WITH_CAMELLIA_256_CBC_SHA,
KEY_RSA, MODP_NONE,
- HASH_SHA1, PRF_HMAC_SHA1,
+ HASH_SHA256, PRF_HMAC_SHA2_256,
AUTH_HMAC_SHA1_160, ENCR_CAMELLIA_CBC, 32
},
{ TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256,
@@ -562,32 +567,32 @@ static suite_algs_t suite_algs[] = {
},
{ TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
KEY_ECDSA, ECP_256_BIT,
- HASH_SHA1, PRF_HMAC_SHA1,
+ HASH_SHA256, PRF_HMAC_SHA2_256,
AUTH_HMAC_SHA1_160, ENCR_3DES, 0
},
{ TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
KEY_RSA, ECP_256_BIT,
- HASH_SHA1, PRF_HMAC_SHA1,
+ HASH_SHA256, PRF_HMAC_SHA2_256,
AUTH_HMAC_SHA1_160, ENCR_3DES, 0
},
{ TLS_RSA_WITH_3DES_EDE_CBC_SHA,
KEY_RSA, MODP_NONE,
- HASH_SHA1, PRF_HMAC_SHA1,
+ HASH_SHA256, PRF_HMAC_SHA2_256,
AUTH_HMAC_SHA1_160, ENCR_3DES, 0
},
{ TLS_ECDHE_ECDSA_WITH_NULL_SHA,
KEY_ECDSA, ECP_256_BIT,
- HASH_SHA1, PRF_HMAC_SHA1,
+ HASH_SHA256, PRF_HMAC_SHA2_256,
AUTH_HMAC_SHA1_160, ENCR_NULL, 0
},
{ TLS_ECDHE_RSA_WITH_NULL_SHA,
KEY_ECDSA, ECP_256_BIT,
- HASH_SHA1, PRF_HMAC_SHA1,
+ HASH_SHA256, PRF_HMAC_SHA2_256,
AUTH_HMAC_SHA1_160, ENCR_NULL, 0
},
{ TLS_RSA_WITH_NULL_SHA,
KEY_RSA, MODP_NONE,
- HASH_SHA1, PRF_HMAC_SHA1,
+ HASH_SHA256, PRF_HMAC_SHA2_256,
AUTH_HMAC_SHA1_160, ENCR_NULL, 0
},
{ TLS_RSA_WITH_NULL_SHA256,
@@ -597,7 +602,7 @@ static suite_algs_t suite_algs[] = {
},
{ TLS_RSA_WITH_NULL_MD5,
KEY_RSA, MODP_NONE,
- HASH_MD5, PRF_HMAC_MD5,
+ HASH_SHA256, PRF_HMAC_SHA2_256,
AUTH_HMAC_MD5_128, ENCR_NULL, 0
},
};
@@ -834,25 +839,25 @@ static void filter_mac_config_suites(private_tls_crypto_t *this,
while (enumerator->enumerate(enumerator, &token))
{
if (strcaseeq(token, "md5") &&
- suites[i].hash == HASH_MD5)
+ suites[i].mac == AUTH_HMAC_MD5_128)
{
suites[remaining++] = suites[i];
break;
}
if (strcaseeq(token, "sha1") &&
- suites[i].hash == HASH_SHA1)
+ suites[i].mac == AUTH_HMAC_SHA1_160)
{
suites[remaining++] = suites[i];
break;
}
if (strcaseeq(token, "sha256") &&
- suites[i].hash == HASH_SHA256)
+ suites[i].mac == AUTH_HMAC_SHA2_256_256)
{
suites[remaining++] = suites[i];
break;
}
if (strcaseeq(token, "sha384") &&
- suites[i].hash == HASH_SHA384)
+ suites[i].mac == AUTH_HMAC_SHA2_384_384)
{
suites[remaining++] = suites[i];
break;
@@ -1462,13 +1467,15 @@ METHOD(tls_crypto_t, calculate_finished, bool,
return TRUE;
}
-METHOD(tls_crypto_t, derive_secrets, void,
- private_tls_crypto_t *this, chunk_t premaster,
- chunk_t client_random, chunk_t server_random)
+/**
+ * Derive master secret from premaster, optionally save session
+ */
+static void derive_master(private_tls_crypto_t *this, chunk_t premaster,
+ chunk_t session, identification_t *id,
+ chunk_t client_random, chunk_t server_random)
{
char master[48];
- chunk_t seed, block, client_write, server_write;
- int mks, eks = 0, ivs = 0;
+ chunk_t seed;
/* derive master secret */
seed = chunk_cata("cc", client_random, server_random);
@@ -1477,7 +1484,22 @@ METHOD(tls_crypto_t, derive_secrets, void,
sizeof(master), master);
this->prf->set_key(this->prf, chunk_from_thing(master));
- memset(master, 0, sizeof(master));
+ if (this->cache && session.len)
+ {
+ this->cache->create(this->cache, session, id, chunk_from_thing(master),
+ this->suite);
+ }
+ memwipe(master, sizeof(master));
+}
+
+/**
+ * Expand key material from master secret
+ */
+static void expand_keys(private_tls_crypto_t *this,
+ chunk_t client_random, chunk_t server_random)
+{
+ chunk_t seed, block, client_write, server_write;
+ int mks, eks = 0, ivs = 0;
/* derive key block for key expansion */
mks = this->signer_out->get_key_size(this->signer_out);
@@ -1546,6 +1568,57 @@ METHOD(tls_crypto_t, derive_secrets, void,
}
}
}
+
+ /* EAP-MSK */
+ if (this->msk_label)
+ {
+ seed = chunk_cata("cc", client_random, server_random);
+ this->msk = chunk_alloc(64);
+ this->prf->get_bytes(this->prf, this->msk_label, seed,
+ this->msk.len, this->msk.ptr);
+ }
+}
+
+METHOD(tls_crypto_t, derive_secrets, void,
+ private_tls_crypto_t *this, chunk_t premaster, chunk_t session,
+ identification_t *id, chunk_t client_random, chunk_t server_random)
+{
+ derive_master(this, premaster, session, id, client_random, server_random);
+ expand_keys(this, client_random, server_random);
+}
+
+METHOD(tls_crypto_t, resume_session, tls_cipher_suite_t,
+ private_tls_crypto_t *this, chunk_t session, identification_t *id,
+ chunk_t client_random, chunk_t server_random)
+{
+ chunk_t master;
+
+ if (this->cache && session.len)
+ {
+ this->suite = this->cache->lookup(this->cache, session, id, &master);
+ if (this->suite)
+ {
+ this->suite = select_cipher_suite(this, &this->suite, 1, KEY_ANY);
+ if (this->suite)
+ {
+ this->prf->set_key(this->prf, master);
+ expand_keys(this, client_random, server_random);
+ }
+ chunk_clear(&master);
+ }
+ return this->suite;
+ }
+ return 0;
+}
+
+METHOD(tls_crypto_t, get_session, chunk_t,
+ private_tls_crypto_t *this, identification_t *server)
+{
+ if (this->cache)
+ {
+ return this->cache->check(this->cache, server);
+ }
+ return chunk_empty;
}
METHOD(tls_crypto_t, change_cipher, void,
@@ -1566,21 +1639,6 @@ METHOD(tls_crypto_t, change_cipher, void,
}
}
-METHOD(tls_crypto_t, derive_eap_msk, void,
- private_tls_crypto_t *this, chunk_t client_random, chunk_t server_random)
-{
- if (this->msk_label)
- {
- chunk_t seed;
-
- seed = chunk_cata("cc", client_random, server_random);
- free(this->msk.ptr);
- this->msk = chunk_alloc(64);
- this->prf->get_bytes(this->prf, this->msk_label, seed,
- this->msk.len, this->msk.ptr);
- }
-}
-
METHOD(tls_crypto_t, get_eap_msk, chunk_t,
private_tls_crypto_t *this)
{
@@ -1606,7 +1664,7 @@ METHOD(tls_crypto_t, destroy, void,
/**
* See header
*/
-tls_crypto_t *tls_crypto_create(tls_t *tls)
+tls_crypto_t *tls_crypto_create(tls_t *tls, tls_cache_t *cache)
{
private_tls_crypto_t *this;
enumerator_t *enumerator;
@@ -1628,12 +1686,14 @@ tls_crypto_t *tls_crypto_create(tls_t *tls)
.verify_handshake = _verify_handshake,
.calculate_finished = _calculate_finished,
.derive_secrets = _derive_secrets,
+ .resume_session = _resume_session,
+ .get_session = _get_session,
.change_cipher = _change_cipher,
- .derive_eap_msk = _derive_eap_msk,
.get_eap_msk = _get_eap_msk,
.destroy = _destroy,
},
.tls = tls,
+ .cache = cache,
);
enumerator = lib->creds->create_builder_enumerator(lib->creds);
diff --git a/src/libtls/tls_crypto.h b/src/libtls/tls_crypto.h
index 35c9b6e05..7430aea66 100644
--- a/src/libtls/tls_crypto.h
+++ b/src/libtls/tls_crypto.h
@@ -54,13 +54,13 @@ enum tls_cipher_suite_t {
TLS_RSA_EXPORT_WITH_DES40_CBC_SHA = 0x0008,
TLS_RSA_WITH_DES_CBC_SHA = 0x0009,
TLS_RSA_WITH_3DES_EDE_CBC_SHA = 0x000A,
- TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA = 0x000B,
+ TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA = 0x000B,
TLS_DH_DSS_WITH_DES_CBC_SHA = 0x000C,
TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA = 0x000D,
TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA = 0x000E,
- TLS_DH_RSA_WITH_DES_CBC_SHA = 0x000F,
+ TLS_DH_RSA_WITH_DES_CBC_SHA = 0x000F,
TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA = 0x0010,
- TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = 0x0011,
+ TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = 0x0011,
TLS_DHE_DSS_WITH_DES_CBC_SHA = 0x0012,
TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA = 0x0013,
TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA = 0x0014,
@@ -110,7 +110,7 @@ enum tls_cipher_suite_t {
TLS_RSA_WITH_CAMELLIA_128_CBC_SHA = 0x0041,
TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA = 0x0042,
TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA = 0x0043,
- TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA = 0x0044,
+ TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA = 0x0044,
TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA = 0x0045,
TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA = 0x0046,
@@ -126,8 +126,8 @@ enum tls_cipher_suite_t {
TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA = 0x0085,
TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA = 0x0086,
TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA = 0x0087,
- TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA = 0x0088,
- TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA = 0x0089,
+ TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA = 0x0088,
+ TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA = 0x0089,
TLS_PSK_WITH_RC4_128_SHA = 0x008A,
TLS_PSK_WITH_3DES_EDE_CBC_SHA = 0x008B,
TLS_PSK_WITH_AES_128_CBC_SHA = 0x008C,
@@ -511,27 +511,43 @@ struct tls_crypto_t {
* Derive the master secret, MAC and encryption keys.
*
* @param premaster premaster secret
+ * @param session session identifier to cache master secret
+ * @param id identity the session is bound to
* @param client_random random data from client hello
* @param server_random random data from server hello
*/
void (*derive_secrets)(tls_crypto_t *this, chunk_t premaster,
+ chunk_t session, identification_t *id,
chunk_t client_random, chunk_t server_random);
/**
- * Change the cipher used at protection layer.
+ * Try to resume a TLS session, derive key material.
*
- * @param inbound TRUE to change inbound cipher, FALSE for outbound
+ * @param session session identifier
+ * @param id identity the session is bound to
+ * @param client_random random data from client hello
+ * @param server_random random data from server hello
+ * @return selected suite
*/
- void (*change_cipher)(tls_crypto_t *this, bool inbound);
+ tls_cipher_suite_t (*resume_session)(tls_crypto_t *this, chunk_t session,
+ identification_t *id,
+ chunk_t client_random,
+ chunk_t server_random);
/**
- * Derive the EAP-TLS MSK.
+ * Check if we have a session to resume as a client.
*
- * @param client_random random data from client hello
- * @param server_random random data from server hello
+ * @param id server identity to get a session for
+ * @return allocated session identifier, or chunk_empty
*/
- void (*derive_eap_msk)(tls_crypto_t *this,
- chunk_t client_random, chunk_t server_random);
+ chunk_t (*get_session)(tls_crypto_t *this, identification_t *id);
+
+ /**
+ * Change the cipher used at protection layer.
+ *
+ * @param inbound TRUE to change inbound cipher, FALSE for outbound
+ */
+ void (*change_cipher)(tls_crypto_t *this, bool inbound);
/**
* Get the MSK to use in EAP-TLS.
@@ -548,7 +564,11 @@ struct tls_crypto_t {
/**
* Create a tls_crypto instance.
+ *
+ * @param tls TLS stack
+ * @param cache TLS session cache
+ * @return TLS crypto helper
*/
-tls_crypto_t *tls_crypto_create(tls_t *tls);
+tls_crypto_t *tls_crypto_create(tls_t *tls, tls_cache_t *cache);
#endif /** TLS_CRYPTO_H_ @}*/
diff --git a/src/libtls/tls_fragmentation.c b/src/libtls/tls_fragmentation.c
index c42c16fb8..62e36aaec 100644
--- a/src/libtls/tls_fragmentation.c
+++ b/src/libtls/tls_fragmentation.c
@@ -251,8 +251,9 @@ METHOD(tls_fragmentation_t, process, status_t,
switch (type)
{
case TLS_CHANGE_CIPHER_SPEC:
- if (this->handshake->change_cipherspec(this->handshake))
+ if (this->handshake->cipherspec_changed(this->handshake, TRUE))
{
+ this->handshake->change_cipherspec(this->handshake, TRUE);
status = NEED_MORE;
break;
}
@@ -324,8 +325,12 @@ static status_t build_handshake(private_tls_fragmentation_t *this)
msg->write_data24(msg, hs->get_buf(hs));
DBG2(DBG_TLS, "sending TLS %N handshake (%u bytes)",
tls_handshake_type_names, type, hs->get_buf(hs).len);
- hs->destroy(hs);
- continue;
+ if (!this->handshake->cipherspec_changed(this->handshake, FALSE))
+ {
+ hs->destroy(hs);
+ continue;
+ }
+ /* FALL */
case INVALID_STATE:
this->output_type = TLS_HANDSHAKE;
this->output = chunk_clone(msg->get_buf(msg));
@@ -397,8 +402,9 @@ METHOD(tls_fragmentation_t, build, status_t,
}
if (!this->output.len)
{
- if (this->handshake->cipherspec_changed(this->handshake))
+ if (this->handshake->cipherspec_changed(this->handshake, FALSE))
{
+ this->handshake->change_cipherspec(this->handshake, FALSE);
*type = TLS_CHANGE_CIPHER_SPEC;
*data = chunk_clone(chunk_from_chars(0x01));
return NEED_MORE;
diff --git a/src/libtls/tls_fragmentation.h b/src/libtls/tls_fragmentation.h
index d80278916..f650e7be8 100644
--- a/src/libtls/tls_fragmentation.h
+++ b/src/libtls/tls_fragmentation.h
@@ -23,12 +23,12 @@
#include <library.h>
+typedef struct tls_fragmentation_t tls_fragmentation_t;
+
#include "tls.h"
#include "tls_alert.h"
#include "tls_handshake.h"
-typedef struct tls_fragmentation_t tls_fragmentation_t;
-
/**
* TLS record protocol fragmentation layer.
*/
diff --git a/src/libtls/tls_handshake.h b/src/libtls/tls_handshake.h
index 4f6af2a54..bea0024eb 100644
--- a/src/libtls/tls_handshake.h
+++ b/src/libtls/tls_handshake.h
@@ -62,18 +62,19 @@ struct tls_handshake_t {
tls_handshake_type_t *type, bio_writer_t *writer);
/**
- * Check if the cipher spec for outgoing messages has changed.
+ * Check if the cipher spec should be changed for outgoing messages.
*
- * @return TRUE if cipher spec changed
+ * @param inbound TRUE to check for inbound cipherspec change
+ * @return TRUE if cipher spec should be changed
*/
- bool (*cipherspec_changed)(tls_handshake_t *this);
+ bool (*cipherspec_changed)(tls_handshake_t *this, bool inbound);
/**
- * Change the cipher spec for incoming messages.
+ * Change the cipher for a direction.
*
- * @return TRUE if cipher spec changed
+ * @param inbound TRUE to change inbound cipherspec, FALSE for outbound
*/
- bool (*change_cipherspec)(tls_handshake_t *this);
+ void (*change_cipherspec)(tls_handshake_t *this, bool inbound);
/**
* Check if the finished message was decoded successfully.
diff --git a/src/libtls/tls_peer.c b/src/libtls/tls_peer.c
index d3b5ff0aa..6091702cf 100644
--- a/src/libtls/tls_peer.c
+++ b/src/libtls/tls_peer.c
@@ -36,7 +36,7 @@ typedef enum {
STATE_CIPHERSPEC_CHANGED_OUT,
STATE_FINISHED_SENT,
STATE_CIPHERSPEC_CHANGED_IN,
- STATE_COMPLETE,
+ STATE_FINISHED_RECEIVED,
} peer_state_t;
/**
@@ -110,6 +110,16 @@ struct private_tls_peer_t {
diffie_hellman_t *dh;
/**
+ * Resuming a session?
+ */
+ bool resume;
+
+ /**
+ * TLS session identifier
+ */
+ chunk_t session;
+
+ /**
* List of server-supported hashsig algorithms
*/
chunk_t hashsig;
@@ -129,7 +139,7 @@ static status_t process_server_hello(private_tls_peer_t *this,
u_int8_t compression;
u_int16_t version, cipher;
chunk_t random, session, ext = chunk_empty;
- tls_cipher_suite_t suite;
+ tls_cipher_suite_t suite = 0;
this->crypto->append_handshake(this->crypto,
TLS_SERVER_HELLO, reader->peek(reader));
@@ -155,16 +165,34 @@ static status_t process_server_hello(private_tls_peer_t *this,
this->alert->add(this->alert, TLS_FATAL, TLS_PROTOCOL_VERSION);
return NEED_MORE;
}
- suite = cipher;
- if (!this->crypto->select_cipher_suite(this->crypto, &suite, 1, KEY_ANY))
+
+ if (chunk_equals(this->session, session))
{
- DBG1(DBG_TLS, "received TLS cipher suite %N inacceptable",
- tls_cipher_suite_names, suite);
- this->alert->add(this->alert, TLS_FATAL, TLS_HANDSHAKE_FAILURE);
- return NEED_MORE;
+ suite = this->crypto->resume_session(this->crypto, session, this->server,
+ chunk_from_thing(this->client_random),
+ chunk_from_thing(this->server_random));
+ if (suite)
+ {
+ DBG1(DBG_TLS, "resumed %N using suite %N",
+ tls_version_names, version, tls_cipher_suite_names, suite);
+ this->resume = TRUE;
+ }
+ }
+ if (!suite)
+ {
+ suite = cipher;
+ if (!this->crypto->select_cipher_suite(this->crypto, &suite, 1, KEY_ANY))
+ {
+ DBG1(DBG_TLS, "received TLS cipher suite %N inacceptable",
+ tls_cipher_suite_names, suite);
+ this->alert->add(this->alert, TLS_FATAL, TLS_HANDSHAKE_FAILURE);
+ return NEED_MORE;
+ }
+ DBG1(DBG_TLS, "negotiated %N using suite %N",
+ tls_version_names, version, tls_cipher_suite_names, suite);
+ free(this->session.ptr);
+ this->session = chunk_clone(session);
}
- DBG1(DBG_TLS, "negotiated TLS version %N with suite %N",
- tls_version_names, version, tls_cipher_suite_names, suite);
this->state = STATE_HELLO_RECEIVED;
return NEED_MORE;
}
@@ -599,10 +627,9 @@ static status_t process_finished(private_tls_peer_t *this, bio_reader_t *reader)
this->alert->add(this->alert, TLS_FATAL, TLS_DECRYPT_ERROR);
return NEED_MORE;
}
- this->state = STATE_COMPLETE;
- this->crypto->derive_eap_msk(this->crypto,
- chunk_from_thing(this->client_random),
- chunk_from_thing(this->server_random));
+ this->state = STATE_FINISHED_RECEIVED;
+ this->crypto->append_handshake(this->crypto, TLS_FINISHED, received);
+
return NEED_MORE;
}
@@ -696,8 +723,9 @@ static status_t send_client_hello(private_tls_peer_t *this,
writer->write_uint16(writer, version);
writer->write_data(writer, chunk_from_thing(this->client_random));
- /* session identifier => none */
- writer->write_data8(writer, chunk_empty);
+ /* session identifier */
+ this->session = this->crypto->get_session(this->crypto, this->server);
+ writer->write_data8(writer, this->session);
/* add TLS cipher suites */
count = this->crypto->get_cipher_suites(this->crypto, &suites);
@@ -886,6 +914,7 @@ static status_t send_key_exchange_encrypt(private_tls_peer_t *this,
htoun16(premaster, TLS_1_2);
this->crypto->derive_secrets(this->crypto, chunk_from_thing(premaster),
+ this->session, this->server,
chunk_from_thing(this->client_random),
chunk_from_thing(this->server_random));
@@ -930,6 +959,7 @@ static status_t send_key_exchange_dhe(private_tls_peer_t *this,
return NEED_MORE;
}
this->crypto->derive_secrets(this->crypto, premaster,
+ this->session, this->server,
chunk_from_thing(this->client_random),
chunk_from_thing(this->server_random));
chunk_clear(&premaster);
@@ -1042,34 +1072,52 @@ METHOD(tls_handshake_t, build, status_t,
}
METHOD(tls_handshake_t, cipherspec_changed, bool,
- private_tls_peer_t *this)
+ private_tls_peer_t *this, bool inbound)
{
- if ((this->peer && this->state == STATE_VERIFY_SENT) ||
- (!this->peer && this->state == STATE_KEY_EXCHANGE_SENT))
+ if (inbound)
{
- this->crypto->change_cipher(this->crypto, FALSE);
- this->state = STATE_CIPHERSPEC_CHANGED_OUT;
- return TRUE;
+ if (this->resume)
+ {
+ return this->state == STATE_HELLO_RECEIVED;
+ }
+ return this->state == STATE_FINISHED_SENT;
+ }
+ else
+ {
+ if (this->resume)
+ {
+ return this->state == STATE_FINISHED_RECEIVED;
+ }
+ if (this->peer)
+ {
+ return this->state == STATE_VERIFY_SENT;
+ }
+ return this->state == STATE_KEY_EXCHANGE_SENT;
}
- return FALSE;
}
-METHOD(tls_handshake_t, change_cipherspec, bool,
- private_tls_peer_t *this)
+METHOD(tls_handshake_t, change_cipherspec, void,
+ private_tls_peer_t *this, bool inbound)
{
- if (this->state == STATE_FINISHED_SENT)
+ this->crypto->change_cipher(this->crypto, inbound);
+ if (inbound)
{
- this->crypto->change_cipher(this->crypto, TRUE);
this->state = STATE_CIPHERSPEC_CHANGED_IN;
- return TRUE;
}
- return FALSE;
+ else
+ {
+ this->state = STATE_CIPHERSPEC_CHANGED_OUT;
+ }
}
METHOD(tls_handshake_t, finished, bool,
private_tls_peer_t *this)
{
- return this->state == STATE_COMPLETE;
+ if (this->resume)
+ {
+ return this->state == STATE_FINISHED_SENT;
+ }
+ return this->state == STATE_FINISHED_RECEIVED;
}
METHOD(tls_handshake_t, destroy, void,
@@ -1081,6 +1129,7 @@ METHOD(tls_handshake_t, destroy, void,
this->server_auth->destroy(this->server_auth);
free(this->hashsig.ptr);
free(this->cert_types.ptr);
+ free(this->session.ptr);
free(this);
}
diff --git a/src/libtls/tls_protection.h b/src/libtls/tls_protection.h
index 99c94e935..05cf3df45 100644
--- a/src/libtls/tls_protection.h
+++ b/src/libtls/tls_protection.h
@@ -23,12 +23,12 @@
#include <library.h>
+typedef struct tls_protection_t tls_protection_t;
+
#include "tls.h"
#include "tls_alert.h"
#include "tls_compression.h"
-typedef struct tls_protection_t tls_protection_t;
-
/**
* TLS record protocol protection layer.
*/
diff --git a/src/libtls/tls_server.c b/src/libtls/tls_server.c
index b8b67adf4..e3617dc9a 100644
--- a/src/libtls/tls_server.c
+++ b/src/libtls/tls_server.c
@@ -22,6 +22,10 @@
typedef struct private_tls_server_t private_tls_server_t;
+/**
+ * Size of a session ID
+ */
+#define SESSION_ID_SIZE 16
typedef enum {
STATE_INIT,
@@ -121,6 +125,16 @@ struct private_tls_server_t {
tls_version_t client_version;
/**
+ * TLS session identifier
+ */
+ chunk_t session;
+
+ /**
+ * Do we resume a session?
+ */
+ bool resume;
+
+ /**
* Hash and signature algorithms supported by peer
*/
chunk_t hashsig;
@@ -199,6 +213,7 @@ static status_t process_client_hello(private_tls_server_t *this,
bio_reader_t *extensions;
tls_cipher_suite_t *suites;
int count, i;
+ rng_t *rng;
this->crypto->append_handshake(this->crypto,
TLS_CLIENT_HELLO, reader->peek(reader));
@@ -228,7 +243,7 @@ static status_t process_client_hello(private_tls_server_t *this,
extensions->destroy(extensions);
return NEED_MORE;
}
- DBG1(DBG_TLS, "received TLS '%N' extension",
+ DBG2(DBG_TLS, "received TLS '%N' extension",
tls_extension_names, extension);
DBG3(DBG_TLS, "%B", &ext);
switch (extension)
@@ -249,6 +264,17 @@ static status_t process_client_hello(private_tls_server_t *this,
memcpy(this->client_random, random.ptr, sizeof(this->client_random));
+ htoun32(&this->server_random, time(NULL));
+ rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
+ if (!rng)
+ {
+ DBG1(DBG_TLS, "no suitable RNG found to generate server random");
+ this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
+ return NEED_MORE;
+ }
+ rng->get_bytes(rng, sizeof(this->server_random) - 4, this->server_random + 4);
+ rng->destroy(rng);
+
if (!this->tls->set_version(this->tls, version))
{
DBG1(DBG_TLS, "negotiated version %N not supported",
@@ -256,24 +282,44 @@ static status_t process_client_hello(private_tls_server_t *this,
this->alert->add(this->alert, TLS_FATAL, TLS_PROTOCOL_VERSION);
return NEED_MORE;
}
- count = ciphers.len / sizeof(u_int16_t);
- suites = alloca(count * sizeof(tls_cipher_suite_t));
- DBG2(DBG_TLS, "received %d TLS cipher suites:", count);
- for (i = 0; i < count; i++)
+
+ this->client_version = version;
+ this->suite = this->crypto->resume_session(this->crypto, session, this->peer,
+ chunk_from_thing(this->client_random),
+ chunk_from_thing(this->server_random));
+ if (this->suite)
{
- suites[i] = untoh16(&ciphers.ptr[i * sizeof(u_int16_t)]);
- DBG2(DBG_TLS, " %N", tls_cipher_suite_names, suites[i]);
+ this->session = chunk_clone(session);
+ this->resume = TRUE;
+ DBG1(DBG_TLS, "resumed %N using suite %N",
+ tls_version_names, this->tls->get_version(this->tls),
+ tls_cipher_suite_names, this->suite);
}
-
- if (!select_suite_and_key(this, suites, count))
+ else
{
- this->alert->add(this->alert, TLS_FATAL, TLS_HANDSHAKE_FAILURE);
- return NEED_MORE;
+ count = ciphers.len / sizeof(u_int16_t);
+ suites = alloca(count * sizeof(tls_cipher_suite_t));
+ DBG2(DBG_TLS, "received %d TLS cipher suites:", count);
+ for (i = 0; i < count; i++)
+ {
+ suites[i] = untoh16(&ciphers.ptr[i * sizeof(u_int16_t)]);
+ DBG2(DBG_TLS, " %N", tls_cipher_suite_names, suites[i]);
+ }
+ if (!select_suite_and_key(this, suites, count))
+ {
+ this->alert->add(this->alert, TLS_FATAL, TLS_HANDSHAKE_FAILURE);
+ return NEED_MORE;
+ }
+ rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG);
+ if (rng)
+ {
+ rng->allocate_bytes(rng, SESSION_ID_SIZE, &this->session);
+ rng->destroy(rng);
+ }
+ DBG1(DBG_TLS, "negotiated %N using suite %N",
+ tls_version_names, this->tls->get_version(this->tls),
+ tls_cipher_suite_names, this->suite);
}
- DBG1(DBG_TLS, "negotiated TLS version %N with suite %N",
- tls_version_names, this->tls->get_version(this->tls),
- tls_cipher_suite_names, this->suite);
- this->client_version = version;
this->state = STATE_HELLO_RECEIVED;
return NEED_MORE;
}
@@ -391,6 +437,7 @@ static status_t process_key_exchange_encrypted(private_tls_server_t *this,
}
this->crypto->derive_secrets(this->crypto, chunk_from_thing(premaster),
+ this->session, this->peer,
chunk_from_thing(this->client_random),
chunk_from_thing(this->server_random));
@@ -439,6 +486,7 @@ static status_t process_key_exchange_dhe(private_tls_server_t *this,
}
this->crypto->derive_secrets(this->crypto, premaster,
+ this->session, this->peer,
chunk_from_thing(this->client_random),
chunk_from_thing(this->server_random));
chunk_clear(&premaster);
@@ -576,10 +624,7 @@ METHOD(tls_handshake_t, process, status_t,
expected = TLS_CERTIFICATE_VERIFY;
break;
}
- else
- {
- return INVALID_STATE;
- }
+ return INVALID_STATE;
case STATE_CIPHERSPEC_CHANGED_IN:
if (type == TLS_FINISHED)
{
@@ -605,27 +650,12 @@ METHOD(tls_handshake_t, process, status_t,
static status_t send_server_hello(private_tls_server_t *this,
tls_handshake_type_t *type, bio_writer_t *writer)
{
- tls_version_t version;
- rng_t *rng;
-
- htoun32(&this->server_random, time(NULL));
- rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
- if (!rng)
- {
- DBG1(DBG_TLS, "no suitable RNG found to generate server random");
- this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
- return FAILED;
- }
- rng->get_bytes(rng, sizeof(this->server_random) - 4, this->server_random + 4);
- rng->destroy(rng);
-
/* TLS version */
- version = this->tls->get_version(this->tls);
- writer->write_uint16(writer, version);
+ writer->write_uint16(writer, this->tls->get_version(this->tls));
writer->write_data(writer, chunk_from_thing(this->server_random));
- /* session identifier => none, we don't support session resumption */
- writer->write_data8(writer, chunk_empty);
+ /* session identifier if we have one */
+ writer->write_data8(writer, this->session);
/* add selected TLS cipher suite */
writer->write_uint16(writer, this->suite);
@@ -914,9 +944,8 @@ static status_t send_finished(private_tls_server_t *this,
*type = TLS_FINISHED;
this->state = STATE_FINISHED_SENT;
- this->crypto->derive_eap_msk(this->crypto,
- chunk_from_thing(this->client_random),
- chunk_from_thing(this->server_random));
+ this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer));
+
return NEED_MORE;
}
@@ -956,33 +985,52 @@ METHOD(tls_handshake_t, build, status_t,
}
METHOD(tls_handshake_t, cipherspec_changed, bool,
- private_tls_server_t *this)
+ private_tls_server_t *this, bool inbound)
{
- if (this->state == STATE_FINISHED_RECEIVED)
+ if (inbound)
{
- this->crypto->change_cipher(this->crypto, FALSE);
- this->state = STATE_CIPHERSPEC_CHANGED_OUT;
- return TRUE;
+ if (this->resume)
+ {
+ return this->state == STATE_FINISHED_SENT;
+ }
+ if (this->peer)
+ {
+ return this->state == STATE_CERT_VERIFY_RECEIVED;
+ }
+ return this->state == STATE_KEY_EXCHANGE_RECEIVED;
+ }
+ else
+ {
+ if (this->resume)
+ {
+ return this->state == STATE_HELLO_SENT;
+ }
+ return this->state == STATE_FINISHED_RECEIVED;
}
return FALSE;
}
-METHOD(tls_handshake_t, change_cipherspec, bool,
- private_tls_server_t *this)
+METHOD(tls_handshake_t, change_cipherspec, void,
+ private_tls_server_t *this, bool inbound)
{
- if ((this->peer && this->state == STATE_CERT_VERIFY_RECEIVED) ||
- (!this->peer && this->state == STATE_KEY_EXCHANGE_RECEIVED))
+ this->crypto->change_cipher(this->crypto, inbound);
+ if (inbound)
{
- this->crypto->change_cipher(this->crypto, TRUE);
this->state = STATE_CIPHERSPEC_CHANGED_IN;
- return TRUE;
}
- return FALSE;
+ else
+ {
+ this->state = STATE_CIPHERSPEC_CHANGED_OUT;
+ }
}
METHOD(tls_handshake_t, finished, bool,
private_tls_server_t *this)
{
+ if (this->resume)
+ {
+ return this->state == STATE_FINISHED_RECEIVED;
+ }
return this->state == STATE_FINISHED_SENT;
}
@@ -995,6 +1043,7 @@ METHOD(tls_handshake_t, destroy, void,
this->server_auth->destroy(this->server_auth);
free(this->hashsig.ptr);
free(this->curves.ptr);
+ free(this->session.ptr);
free(this);
}
diff --git a/src/libtls/tls_socket.c b/src/libtls/tls_socket.c
index 691a8e79f..3abff596d 100644
--- a/src/libtls/tls_socket.c
+++ b/src/libtls/tls_socket.c
@@ -16,8 +16,20 @@
#include "tls_socket.h"
#include <unistd.h>
+#include <errno.h>
#include <debug.h>
+#include <threading/thread.h>
+
+/**
+ * Buffer size for plain side I/O
+ */
+#define PLAIN_BUF_SIZE 4096
+
+/**
+ * Buffer size for encrypted side I/O
+ */
+#define CRYPTO_BUF_SIZE 4096
typedef struct private_tls_socket_t private_tls_socket_t;
typedef struct private_tls_application_t private_tls_application_t;
@@ -96,8 +108,8 @@ METHOD(tls_application_t, build, status_t,
*/
static bool exchange(private_tls_socket_t *this, bool wr)
{
- char buf[1024];
- ssize_t len;
+ char buf[CRYPTO_BUF_SIZE], *pos;
+ ssize_t len, out;
int round = 0;
for (round = 0; TRUE; round++)
@@ -109,10 +121,18 @@ static bool exchange(private_tls_socket_t *this, bool wr)
{
case NEED_MORE:
case ALREADY_DONE:
- len = write(this->fd, buf, len);
- if (len == -1)
+ pos = buf;
+ while (len)
{
- return FALSE;
+ out = write(this->fd, pos, len);
+ if (out == -1)
+ {
+ DBG1(DBG_TLS, "TLS crypto write error: %s",
+ strerror(errno));
+ return FALSE;
+ }
+ len -= out;
+ pos += out;
}
continue;
case INVALID_STATE:
@@ -175,6 +195,81 @@ METHOD(tls_socket_t, write_, bool,
return FALSE;
}
+METHOD(tls_socket_t, splice, bool,
+ private_tls_socket_t *this, int rfd, int wfd)
+{
+ char buf[PLAIN_BUF_SIZE], *pos;
+ fd_set set;
+ chunk_t data;
+ ssize_t len;
+ bool old;
+
+ while (TRUE)
+ {
+ FD_ZERO(&set);
+ FD_SET(rfd, &set);
+ FD_SET(this->fd, &set);
+
+ old = thread_cancelability(TRUE);
+ len = select(max(rfd, this->fd) + 1, &set, NULL, NULL, NULL);
+ thread_cancelability(old);
+ if (len == -1)
+ {
+ DBG1(DBG_TLS, "TLS select error: %s", strerror(errno));
+ return FALSE;
+ }
+ if (FD_ISSET(this->fd, &set))
+ {
+ if (!read_(this, &data))
+ {
+ DBG2(DBG_TLS, "TLS read error/disconnect");
+ return TRUE;
+ }
+ pos = data.ptr;
+ while (data.len)
+ {
+ len = write(wfd, pos, data.len);
+ if (len == -1)
+ {
+ free(data.ptr);
+ DBG1(DBG_TLS, "TLS plain write error: %s", strerror(errno));
+ return FALSE;
+ }
+ data.len -= len;
+ pos += len;
+ }
+ free(data.ptr);
+ }
+ if (FD_ISSET(rfd, &set))
+ {
+ len = read(rfd, buf, sizeof(buf));
+ if (len > 0)
+ {
+ if (!write_(this, chunk_create(buf, len)))
+ {
+ DBG1(DBG_TLS, "TLS write error");
+ return FALSE;
+ }
+ }
+ else
+ {
+ if (len < 0)
+ {
+ DBG1(DBG_TLS, "TLS plain read error: %s", strerror(errno));
+ return FALSE;
+ }
+ return TRUE;
+ }
+ }
+ }
+}
+
+METHOD(tls_socket_t, get_fd, int,
+ private_tls_socket_t *this)
+{
+ return this->fd;
+}
+
METHOD(tls_socket_t, destroy, void,
private_tls_socket_t *this)
{
@@ -187,7 +282,7 @@ METHOD(tls_socket_t, destroy, void,
* See header
*/
tls_socket_t *tls_socket_create(bool is_server, identification_t *server,
- identification_t *peer, int fd)
+ identification_t *peer, int fd, tls_cache_t *cache)
{
private_tls_socket_t *this;
@@ -195,6 +290,8 @@ tls_socket_t *tls_socket_create(bool is_server, identification_t *server,
.public = {
.read = _read_,
.write = _write_,
+ .splice = _splice,
+ .get_fd = _get_fd,
.destroy = _destroy,
},
.app = {
@@ -208,7 +305,7 @@ tls_socket_t *tls_socket_create(bool is_server, identification_t *server,
);
this->tls = tls_create(is_server, server, peer, TLS_PURPOSE_GENERIC,
- &this->app.application);
+ &this->app.application, cache);
if (!this->tls)
{
free(this);
diff --git a/src/libtls/tls_socket.h b/src/libtls/tls_socket.h
index ac714a385..edd05fd29 100644
--- a/src/libtls/tls_socket.h
+++ b/src/libtls/tls_socket.h
@@ -55,6 +55,25 @@ struct tls_socket_t {
bool (*write)(tls_socket_t *this, chunk_t data);
/**
+ * Read/write plain data from file descriptor.
+ *
+ * This call is blocking, but a thread cancellation point. Data is
+ * exchanged until one of the sockets gets closed or an error occurs.
+ *
+ * @param rfd file descriptor to read plain data from
+ * @param wfd file descriptor to write plain data to
+ * @return TRUE if data exchanged successfully
+ */
+ bool (*splice)(tls_socket_t *this, int rfd, int wfd);
+
+ /**
+ * Get the underlying file descriptor passed to the constructor.
+ *
+ * @return file descriptor
+ */
+ int (*get_fd)(tls_socket_t *this);
+
+ /**
* Destroy a tls_socket_t.
*/
void (*destroy)(tls_socket_t *this);
@@ -67,9 +86,10 @@ struct tls_socket_t {
* @param server server identity
* @param peer client identity, NULL for no client authentication
* @param fd socket to read/write from
+ * @param cache session cache to use, or NULL
* @return TLS socket wrapper
*/
tls_socket_t *tls_socket_create(bool is_server, identification_t *server,
- identification_t *peer, int fd);
+ identification_t *peer, int fd, tls_cache_t *cache);
#endif /** TLS_SOCKET_H_ @}*/
diff --git a/src/libtnccs/Android.mk b/src/libtnccs/Android.mk
index 0055fce34..a4bbc13f5 100644
--- a/src/libtnccs/Android.mk
+++ b/src/libtnccs/Android.mk
@@ -21,6 +21,8 @@ LOCAL_CFLAGS := $(strongswan_CFLAGS)
LOCAL_MODULE := libtnccs
+LOCAL_MODULE_TAGS := optional
+
LOCAL_ARM_MODE := arm
LOCAL_PRELINK_MODULE := false
diff --git a/src/libtnccs/Makefile.am b/src/libtnccs/Makefile.am
index 4f331c46b..449d32d92 100644
--- a/src/libtnccs/Makefile.am
+++ b/src/libtnccs/Makefile.am
@@ -13,4 +13,4 @@ tnc/imv/imv_recommendations.h tnc/imv/imv_recommendations.c \
tnc/tnccs/tnccs.h tnc/tnccs/tnccs.c \
tnc/tnccs/tnccs_manager.h tnc/tnccs/tnccs_manager.c
-
+EXTRA_DIST = Android.mk
diff --git a/src/libtnccs/tnc/imc/imc.h b/src/libtnccs/tnc/imc/imc.h
index ddedf714c..3ff7d5194 100644
--- a/src/libtnccs/tnc/imc/imc.h
+++ b/src/libtnccs/tnc/imc/imc.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 Andreas Steffen
+ * Copyright (C) 2010-2011 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -40,11 +40,11 @@ struct imc_t {
* the API version number to be used. It also supplies the IMC ID, an IMC
* identifier that the IMC must use when calling TNC Client callback functions.
*
- * @param imcID IMC ID assigned by TNCC
- * @param minVersion minimum API version supported by TNCC
- * @param maxVersion maximum API version supported by TNCC
- * @param OutActualVersion mutually supported API version number
- * @return TNC result code
+ * @param imcID IMC ID assigned by TNCC
+ * @param minVersion minimum API version supported by TNCC
+ * @param maxVersion maximum API version supported by TNCC
+ * @param OutActualVersion mutually supported API version number
+ * @return TNC result code
*/
TNC_Result (*initialize)(TNC_IMCID imcID,
TNC_Version minVersion,
@@ -55,10 +55,10 @@ struct imc_t {
* The TNC Client calls this function to inform the IMC that the state of
* the network connection identified by connectionID has changed to newState.
*
- * @param imcID IMC ID assigned by TNCC
- * @param connectionID network connection ID assigned by TNCC
- * @param newState new network connection state
- * @return TNC result code
+ * @param imcID IMC ID assigned by TNCC
+ * @param connectionID network connection ID assigned by TNCC
+ * @param newState new network connection state
+ * @return TNC result code
*/
TNC_Result (*notify_connection_change)(TNC_IMCID imcID,
TNC_ConnectionID connectionID,
@@ -68,9 +68,9 @@ struct imc_t {
* The TNC Client calls this function to indicate that an Integrity Check
* Handshake is beginning and solicit messages from IMCs for the first batch.
*
- * @param imcID IMC ID assigned by TNCC
- * @param connectionID network connection ID assigned by TNCC
- * @return TNC result code
+ * @param imcID IMC ID assigned by TNCC
+ * @param connectionID network connection ID assigned by TNCC
+ * @return TNC result code
*/
TNC_Result (*begin_handshake)(TNC_IMCID imcID,
TNC_ConnectionID connectionID);
@@ -81,12 +81,12 @@ struct imc_t {
* the number of octets indicated by messageLength. The type of the message
* is indicated by messageType.
*
- * @param imcID IMC ID assigned by TNCS
- * @param connectionID network connection ID assigned by TNCC
- * @param message reference to buffer containing message
- * @param messageLength number of octets in message
- * @param messageType message type of message
- * @return TNC result code
+ * @param imcID IMC ID assigned by TNCS
+ * @param connectionID network connection ID assigned by TNCC
+ * @param message reference to buffer containing message
+ * @param messageLength number of octets in message
+ * @param messageType message type of message
+ * @return TNC result code
*/
TNC_Result (*receive_message)(TNC_IMCID imcID,
TNC_ConnectionID connectionID,
@@ -95,13 +95,40 @@ struct imc_t {
TNC_MessageType messageType);
/**
+ * The TNC Client calls this function to deliver a message to the IMC.
+ * The message is contained in the buffer referenced by message and contains
+ * the number of octets indicated by messageLength. The type of the message
+ * is indicated by the message Vendor ID and message subtype.
+ *
+ * @param imcID IMC ID assigned by TNCS
+ * @param connectionID network connection ID assigned by TNCC
+ * @param messageFlags message flags
+ * @param message reference to buffer containing message
+ * @param messageLength number of octets in message
+ * @param messageVendorID message Vendor ID
+ * @param messageSubtype message subtype
+ * @param sourceIMVID source IMV ID
+ * @param destinationIMCID destination IMC ID
+ * @return TNC result code
+ */
+ TNC_Result (*receive_message_long)(TNC_IMCID imcID,
+ TNC_ConnectionID connectionID,
+ TNC_UInt32 messageFlags,
+ TNC_BufferReference message,
+ TNC_UInt32 messageLength,
+ TNC_VendorID messageVendorID,
+ TNC_MessageSubtype messageSubtype,
+ TNC_UInt32 sourceIMVID,
+ TNC_UInt32 destinationIMCID);
+
+ /**
* The TNC Client calls this function to notify IMCs that all IMV messages
* received in a batch have been delivered and this is the IMC’s last chance
* to send a message in the batch of IMC messages currently being collected.
*
- * @param imcID IMC ID assigned by TNCC
- * @param connectionID network connection ID assigned by TNCC
- * @return TNC result code
+ * @param imcID IMC ID assigned by TNCC
+ * @param connectionID network connection ID assigned by TNCC
+ * @return TNC result code
*/
TNC_Result (*batch_ending)(TNC_IMCID imcID,
TNC_ConnectionID connectionID);
@@ -110,8 +137,8 @@ struct imc_t {
* The TNC Client calls this function to close down the IMC when all work is
* complete or the IMC reports TNC_RESULT_FATAL.
*
- * @param imcID IMC ID assigned by TNCC
- * @return TNC result code
+ * @param imcID IMC ID assigned by TNCC
+ * @return TNC result code
*/
TNC_Result (*terminate)(TNC_IMCID imcID);
@@ -122,9 +149,9 @@ struct imc_t {
* TNCS bind function. The IMV can then use the TNCS bind function to obtain
* pointers to any other TNCS functions.
*
- * @param imcID IMC ID assigned by TNCC
- * @param bindFunction pointer to TNC_TNCC_BindFunction
- * @return TNC result code
+ * @param imcID IMC ID assigned by TNCC
+ * @param bindFunction pointer to TNC_TNCC_BindFunction
+ * @return TNC result code
*/
TNC_Result (*provide_bind_function)(TNC_IMCID imcID,
TNC_TNCC_BindFunctionPointer bindFunction);
@@ -132,40 +159,67 @@ struct imc_t {
/**
* Sets the ID of an imc_t object.
*
- * @param id IMC ID to be assigned
+ * @param id IMC ID to be assigned
*/
void (*set_id)(imc_t *this, TNC_IMCID id);
/**
* Returns the ID of an imc_t object.
*
- * @return assigned IMC ID
+ * @return assigned IMC ID
*/
TNC_IMCID (*get_id)(imc_t *this);
/**
+ * Assign an additional ID to an imc_t object.
+ *
+ * @param id additional IMC ID to be assigned
+ */
+ void (*add_id)(imc_t *this, TNC_IMCID id);
+
+ /**
+ * Checks if the ID is assigned to the imc_t object.
+ *
+ * @return TRUE if IMC ID is assigned to imc_t object
+ */
+ bool (*has_id)(imc_t *this, TNC_IMCID id);
+
+ /**
* Returns the name of an imc_t object.
*
- * @return name of IMC
+ * @return name of IMC
*/
char* (*get_name)(imc_t *this);
/**
* Sets the supported message types of an imc_t object.
*
- * @param supported_types list of messages type supported by IMC
- * @param type_count number of supported message types
+ * @param supported_types list of messages type supported by IMC
+ * @param type_count number of supported message types
*/
void (*set_message_types)(imc_t *this, TNC_MessageTypeList supported_types,
TNC_UInt32 type_count);
/**
+ * Sets the supported long message types of an imc_t object.
+ *
+ * @param supported_vids list of vendor IDs supported by IMC
+ * @param supported_subtypes list of messages type supported by IMC
+ * @param type_count number of supported message types
+ */
+ void (*set_message_types_long)(imc_t *this, TNC_VendorIDList supported_vids,
+ TNC_MessageSubtypeList supported_subtypes,
+ TNC_UInt32 type_count);
+
+ /**
* Check if the IMC supports a given message type.
*
- * @param message_type message type
- * @return TRUE if supported
+ * @param msg_vid message vendor ID
+ * @param msg_subtype message subtype
+ * @return TRUE if supported
*/
- bool (*type_supported)(imc_t *this, TNC_MessageType message_type);
+ bool (*type_supported)(imc_t *this, TNC_VendorID msg_vid,
+ TNC_MessageSubtype msg_subtype);
/**
* Destroys an imc_t object.
diff --git a/src/libtnccs/tnc/imc/imc_manager.h b/src/libtnccs/tnc/imc/imc_manager.h
index 396964100..25e0efe9d 100644
--- a/src/libtnccs/tnc/imc/imc_manager.h
+++ b/src/libtnccs/tnc/imc/imc_manager.h
@@ -66,6 +66,15 @@ struct imc_manager_t {
bool (*is_registered)(imc_manager_t *this, TNC_IMCID id);
/**
+ * Reserve an additional ID for an IMC
+ *
+ * @param id ID of IMC instance
+ * @param new_id reserved ID assigned to IMC
+ * @return TRUE if primary IMC ID was used
+ */
+ bool (*reserve_id)(imc_manager_t *this, TNC_IMCID id, TNC_UInt32 *new_id);
+
+ /**
* Return the preferred language for recommendations
*
* @return preferred language string
@@ -84,17 +93,17 @@ struct imc_manager_t {
/**
* Begin a handshake between the IMCs and a connection
*
- * @param id connection ID
+ * @param id connection ID
*/
void (*begin_handshake)(imc_manager_t *this, TNC_ConnectionID id);
/**
* Sets the supported message types reported by a given IMC
*
- * @param id ID of reporting IMC
- * @param supported_types list of messages type supported by IMC
- * @param type_count number of supported message types
- * @return TNC result code
+ * @param id ID of reporting IMC
+ * @param supported_types list of messages type supported by IMC
+ * @param type_count number of supported message types
+ * @return TNC result code
*/
TNC_Result (*set_message_types)(imc_manager_t *this,
TNC_IMCID id,
@@ -102,18 +111,41 @@ struct imc_manager_t {
TNC_UInt32 type_count);
/**
+ * Sets the supported long message types reported by a given IMC
+ *
+ * @param id ID of reporting IMC
+ * @param supported_vids list of vendor IDs supported by IMC
+ * @param supported_subtypes list of messages type supported by IMC
+ * @param type_count number of supported message types
+ * @return TNC result code
+ */
+ TNC_Result (*set_message_types_long)(imc_manager_t *this,
+ TNC_IMCID id,
+ TNC_VendorIDList supported_vids,
+ TNC_MessageSubtypeList supported_subtypes,
+ TNC_UInt32 type_count);
+
+ /**
* Delivers a message to interested IMCs.
*
- * @param connection_id ID of connection over which message was received
- * @param message message
- * @param message_len message length
- * @param message_type message type
+ * @param connection_id connection ID
+ * @param excl exclusive message flag
+ * @param msg message
+ * @param msg_len message length
+ * @param msg_vid message Vendor ID
+ * @param msg_subtype message subtype
+ * @param src_imv_id source IMV ID
+ * @param dst_imc_id destination IMC ID
*/
void (*receive_message)(imc_manager_t *this,
TNC_ConnectionID connection_id,
- TNC_BufferReference message,
- TNC_UInt32 message_len,
- TNC_MessageType message_type);
+ bool excl,
+ 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);
/**
* Notify all IMCs that all IMV messages received in a batch have been
diff --git a/src/libtnccs/tnc/imv/imv.h b/src/libtnccs/tnc/imv/imv.h
index df338d40a..3716532d6 100644
--- a/src/libtnccs/tnc/imv/imv.h
+++ b/src/libtnccs/tnc/imv/imv.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 Andreas Steffen
+ * Copyright (C) 2010-2011 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -40,11 +40,11 @@ struct imv_t {
* the API version number to be used. It also supplies the IMV ID, an IMV
* identifier that the IMV must use when calling TNC Server callback functions.
*
- * @param imvID IMV ID assigned by TNCS
- * @param minVersion minimum API version supported
- * @param maxVersion maximum API version supported by TNCS
- * @param OutActualVersion mutually supported API version number
- * @return TNC result code
+ * @param imvID IMV ID assigned by TNCS
+ * @param minVersion minimum API version supported
+ * @param maxVersion maximum API version supported by TNCS
+ * @param OutActualVersion mutually supported API version number
+ * @return TNC result code
*/
TNC_Result (*initialize)(TNC_IMVID imvID,
TNC_Version minVersion,
@@ -55,10 +55,10 @@ struct imv_t {
* The TNC Server calls this function to inform the IMV that the state of
* the network connection identified by connectionID has changed to newState.
*
- * @param imvID IMV ID assigned by TNCS
- * @param connectionID network connection ID assigned by TNCS
- * @param newState new network connection state
- * @return TNC result code
+ * @param imvID IMV ID assigned by TNCS
+ * @param connectionID network connection ID assigned by TNCS
+ * @param newState new network connection state
+ * @return TNC result code
*/
TNC_Result (*notify_connection_change)(TNC_IMVID imvID,
TNC_ConnectionID connectionID,
@@ -69,9 +69,9 @@ struct imv_t {
* Handshake (after all IMC-IMV messages have been delivered) to solicit
* recommendations from IMVs that have not yet provided a recommendation.
*
- * @param imvID IMV ID assigned by TNCS
- * @param connectionID network connection ID assigned by TNCS
- * @return TNC result code
+ * @param imvID IMV ID assigned by TNCS
+ * @param connectionID network connection ID assigned by TNCS
+ * @return TNC result code
*/
TNC_Result (*solicit_recommendation)(TNC_IMVID imvID,
TNC_ConnectionID connectionID);
@@ -82,12 +82,12 @@ struct imv_t {
* the number of octets indicated by messageLength. The type of the message
* is indicated by messageType.
*
- * @param imvID IMV ID assigned by TNCS
- * @param connectionID network connection ID assigned by TNCS
- * @param message reference to buffer containing message
- * @param messageLength number of octets in message
- * @param messageType message type of message
- * @return TNC result code
+ * @param imvID IMV ID assigned by TNCS
+ * @param connectionID network connection ID assigned by TNCS
+ * @param message reference to buffer containing message
+ * @param messageLength number of octets in message
+ * @param messageType message type of message
+ * @return TNC result code
*/
TNC_Result (*receive_message)(TNC_IMVID imvID,
TNC_ConnectionID connectionID,
@@ -96,13 +96,40 @@ struct imv_t {
TNC_MessageType messageType);
/**
+ * The TNC Server calls this function to deliver a message to the IMV.
+ * The message is contained in the buffer referenced by message and contains
+ * the number of octets indicated by messageLength. The type of the message
+ * is indicated by the message Vendor ID and message subtype.
+ *
+ * @param imvID IMV ID assigned by TNCS
+ * @param connectionID network connection ID assigned by TNCS
+ * @param messageFlags message flags
+ * @param message reference to buffer containing message
+ * @param messageLength number of octets in message
+ * @param messageVendorID message Vendor ID
+ * @param messageSubtype message subtype
+ * @param sourceIMCID source IMC ID
+ * @param destinationIMVID destination IMV ID
+ * @return TNC result code
+ */
+ TNC_Result (*receive_message_long)(TNC_IMVID imvID,
+ TNC_ConnectionID connectionID,
+ TNC_UInt32 messageFlags,
+ TNC_BufferReference message,
+ TNC_UInt32 messageLength,
+ TNC_VendorID messageVendorID,
+ TNC_MessageSubtype messageSubtype,
+ TNC_UInt32 sourceIMCID,
+ TNC_UInt32 destinationIMVID);
+
+ /**
* The TNC Server calls this function to notify IMVs that all IMC messages
* received in a batch have been delivered and this is the IMV’s last chance
* to send a message in the batch of IMV messages currently being collected.
*
- * @param imvID IMV ID assigned by TNCS
- * @param connectionID network connection ID assigned by TNCS
- * @return TNC result code
+ * @param imvID IMV ID assigned by TNCS
+ * @param connectionID network connection ID assigned by TNCS
+ * @return TNC result code
*/
TNC_Result (*batch_ending)(TNC_IMVID imvID,
TNC_ConnectionID connectionID);
@@ -110,8 +137,8 @@ struct imv_t {
/**
* The TNC Server calls this function to close down the IMV.
*
- * @param imvID IMV ID assigned by TNCS
- * @return TNC result code
+ * @param imvID IMV ID assigned by TNCS
+ * @return TNC result code
*/
TNC_Result (*terminate)(TNC_IMVID imvID);
@@ -122,9 +149,9 @@ struct imv_t {
* TNCS bind function. The IMV can then use the TNCS bind function to obtain
* pointers to any other TNCS functions.
*
- * @param imvID IMV ID assigned by TNCS
- * @param bindFunction pointer to TNC_TNCS_BindFunction
- * @return TNC result code
+ * @param imvID IMV ID assigned by TNCS
+ * @param bindFunction pointer to TNC_TNCS_BindFunction
+ * @return TNC result code
*/
TNC_Result (*provide_bind_function)(TNC_IMVID imvID,
TNC_TNCS_BindFunctionPointer bindFunction);
@@ -132,40 +159,67 @@ struct imv_t {
/**
* Sets the ID of an imv_t object.
*
- * @param id IMV ID to be assigned
+ * @param id IMV ID to be assigned
*/
void (*set_id)(imv_t *this, TNC_IMVID id);
/**
* Returns the ID of an imv_t object.
*
- * @return IMV ID assigned by TNCS
+ * @return IMV ID assigned by TNCS
*/
TNC_IMVID (*get_id)(imv_t *this);
/**
+ * Assign an additional ID to an imv_t object.
+ *
+ * @param id additional IMV ID to be assigned
+ */
+ void (*add_id)(imv_t *this, TNC_IMVID id);
+
+ /**
+ * Checks if the ID is assigned to the imv_t object.
+ *
+ * @return TRUE if IMV ID is assigned to imv_t object
+ */
+ bool (*has_id)(imv_t *this, TNC_IMVID id);
+
+ /**
* Returns the name of an imv_t object.
*
- * @return name of IMV
+ * @return name of IMV
*/
char* (*get_name)(imv_t *this);
/**
* Sets the supported message types of an imv_t object.
*
- * @param supported_types list of messages type supported by IMV
- * @param type_count number of supported message types
+ * @param supported_types list of messages type supported by IMV
+ * @param type_count number of supported message types
*/
void (*set_message_types)(imv_t *this, TNC_MessageTypeList supported_types,
TNC_UInt32 type_count);
/**
+ * Sets the supported long message types of an imv_t object.
+ *
+ * @param supported_vids list of vendor IDs supported by IMC
+ * @param supported_subtypes list of messages type supported by IMC
+ * @param type_count number of supported message types
+ */
+ void (*set_message_types_long)(imv_t *this, TNC_VendorIDList supported_vids,
+ TNC_MessageSubtypeList supported_subtypes,
+ TNC_UInt32 type_count);
+
+ /**
* Check if the IMV supports a given message type.
*
- * @param message_type message type
- * @return TRUE if supported
+ * @param msg_vid message vendor ID
+ * @param msg_subtype message subtype
+ * @return TRUE if supported
*/
- bool (*type_supported)(imv_t *this, TNC_MessageType message_type);
+ bool (*type_supported)(imv_t *this, TNC_VendorID msg_vid,
+ TNC_MessageSubtype msg_subtype);
/**
* Destroys an imv_t object.
diff --git a/src/libtnccs/tnc/imv/imv_manager.h b/src/libtnccs/tnc/imv/imv_manager.h
index caa25e857..43f40973c 100644
--- a/src/libtnccs/tnc/imv/imv_manager.h
+++ b/src/libtnccs/tnc/imv/imv_manager.h
@@ -67,6 +67,14 @@ struct imv_manager_t {
*/
bool (*is_registered)(imv_manager_t *this, TNC_IMVID id);
+ /**
+ * Reserve an additional ID for an IMV
+ *
+ * @param id ID of IMV instance
+ * @param new_id reserved ID assigned to IMV
+ * @return TRUE if primary IMV ID was used
+ */
+ bool (*reserve_id)(imv_manager_t *this, TNC_IMVID id, TNC_UInt32 *new_id);
/**
* Get the configured recommendation policy
@@ -106,10 +114,10 @@ struct imv_manager_t {
/**
* Sets the supported message types reported by a given IMV
*
- * @param id ID of reporting IMV
- * @param supported_types list of messages type supported by IMV
- * @param type_count number of supported message types
- * @return TNC result code
+ * @param id ID of reporting IMV
+ * @param supported_types list of messages type supported by IMV
+ * @param type_count number of supported message types
+ * @return TNC result code
*/
TNC_Result (*set_message_types)(imv_manager_t *this,
TNC_IMVID id,
@@ -117,25 +125,48 @@ struct imv_manager_t {
TNC_UInt32 type_count);
/**
+ * Sets the supported long message types reported by a given IMV
+ *
+ * @param id ID of reporting IMV
+ * @param supported_vids list of vendor IDs supported by IMV
+ * @param supported_subtypes list of messages type supported by IMV
+ * @param type_count number of supported message types
+ * @return TNC result code
+ */
+ TNC_Result (*set_message_types_long)(imv_manager_t *this,
+ TNC_IMVID id,
+ TNC_VendorIDList supported_vids,
+ TNC_MessageSubtypeList supported_subtypes,
+ TNC_UInt32 type_count);
+
+ /**
* Solicit recommendations from IMVs that have not yet provided one
*
- * @param id connection ID
+ * @param id connection ID
*/
void (*solicit_recommendation)(imv_manager_t *this, TNC_ConnectionID id);
/**
* Delivers a message to interested IMVs.
*
- * @param connection_id ID of connection over which message was received
- * @param message message
- * @param message_len message length
- * @param message_type message type
+ * @param connection_id connection ID
+ * @param excl exclusive message flag
+ * @param msg message
+ * @param msg_len message length
+ * @param msg_vid message Vendor ID
+ * @param msg_subtype message subtype
+ * @param src_imc_id source IMC ID
+ * @param dst_imv_id destination IMV ID
*/
void (*receive_message)(imv_manager_t *this,
TNC_ConnectionID connection_id,
- TNC_BufferReference message,
- TNC_UInt32 message_len,
- TNC_MessageType message_type);
+ bool excl,
+ TNC_BufferReference msg,
+ TNC_UInt32 msg_len,
+ TNC_VendorID msg_vid,
+ TNC_MessageSubtype msg_subtype,
+ TNC_UInt32 src_imc_id,
+ TNC_UInt32 dst_imv_id);
/**
* Notify all IMVs that all IMC messages received in a batch have been
diff --git a/src/libtnccs/tnc/tnccs/tnccs.h b/src/libtnccs/tnc/tnccs/tnccs.h
index 4bbab5bd3..c3020d7c3 100644
--- a/src/libtnccs/tnc/tnccs/tnccs.h
+++ b/src/libtnccs/tnc/tnccs/tnccs.h
@@ -63,15 +63,20 @@ typedef tnccs_t *(*tnccs_constructor_t)(bool is_server);
*
* @param imc_id ID of IMC or TNC_IMCID_ANY
* @param imc_id ID of IMV or TNC_IMVID_ANY
+ * @param msg_flags message flags
* @param msg message to be added
* @param msg_len message length
- * @param msg_type message type
- * @return result code
+ * @param msg_vid message vendor ID
+ * @param msg_subtype message subtype
+ * @return return code
*/
-typedef TNC_Result (*tnccs_send_message_t)(tnccs_t* tncss, TNC_IMCID imc_id,
- TNC_IMVID imv_id,
- TNC_BufferReference msg,
- TNC_UInt32 msg_len,
- TNC_MessageType msg_type);
+typedef TNC_Result (*tnccs_send_message_t)(tnccs_t* tncss,
+ TNC_IMCID imc_id,
+ TNC_IMVID imv_id,
+ TNC_UInt32 msg_flags,
+ TNC_BufferReference msg,
+ TNC_UInt32 msg_len,
+ TNC_VendorID msg_vid,
+ TNC_MessageSubtype msg_subtype);
#endif /** TNCCS_H_ @}*/
diff --git a/src/libtnccs/tnc/tnccs/tnccs_manager.h b/src/libtnccs/tnc/tnccs/tnccs_manager.h
index 26b0fa17c..9ca450468 100644
--- a/src/libtnccs/tnc/tnccs/tnccs_manager.h
+++ b/src/libtnccs/tnc/tnccs/tnccs_manager.h
@@ -66,13 +66,15 @@ struct tnccs_manager_t {
* callback function for adding a message to a TNCCS batch and create
* an empty set for collecting IMV recommendations
*
+ * @param type TNCCS protocol type
* @param tnccs TNCCS connection instance
* @param send_message TNCCS callback function
* @param request_handshake_retry pointer to boolean variable
* @param recs pointer to IMV recommendation set
* @return assigned connection ID
*/
- TNC_ConnectionID (*create_connection)(tnccs_manager_t *this, tnccs_t *tnccs,
+ TNC_ConnectionID (*create_connection)(tnccs_manager_t *this,
+ tnccs_type_t type, tnccs_t *tnccs,
tnccs_send_message_t send_message,
bool *request_handshake_retry,
recommendations_t **recs);
@@ -106,17 +108,22 @@ struct tnccs_manager_t {
* @param imc_id ID of IMC or TNC_IMCID_ANY
* @param imv_id ID of IMV or TNC_IMVID_ANY
* @param id ID of target connection
+ * @param msg_flags message flags
* @param msg message to be added
* @param msg_len message length
- * @param msg_type message type
+ * @param msg_vid message vendor ID
+ * @param msg_subtype message subtype
* @return return code
*/
- TNC_Result (*send_message)(tnccs_manager_t *this, TNC_IMCID imc_id,
- TNC_IMVID imv_id,
- TNC_ConnectionID id,
- TNC_BufferReference msg,
- TNC_UInt32 msg_len,
- TNC_MessageType msg_type);
+ TNC_Result (*send_message)(tnccs_manager_t *this,
+ TNC_IMCID imc_id,
+ TNC_IMVID imv_id,
+ TNC_ConnectionID id,
+ TNC_UInt32 msg_flags,
+ TNC_BufferReference msg,
+ TNC_UInt32 msg_len,
+ TNC_VendorID msg_vid,
+ TNC_MessageSubtype msg_subtype);
/**
* Deliver an IMV Action Recommendation and IMV Evaluation Result to the TNCS
@@ -137,35 +144,37 @@ struct tnccs_manager_t {
* Get the value of an attribute associated with a connection or with the
* TNCS as a whole.
*
- * @param imv_id ID of the IMV requesting the attribute
+ * @param is_imc TRUE if IMC, FALSE if IMV
+ * @param imcv_id ID of the IMC/IMV requesting the attribute
* @param id ID of target connection
* @param attribute_id ID of the requested attribute
* @param buffer_len length of the buffer in bytes
* @param buffer pointer to the buffer
- * @param out_value_len actual length of the returned attribute
+ * @param value_len actual length of the returned attribute
* @return return code
*/
- TNC_Result (*get_attribute)(tnccs_manager_t *this,
- TNC_IMVID imv_id,
+ TNC_Result (*get_attribute)(tnccs_manager_t *this, bool is_imc,
+ TNC_UInt32 imcv_id,
TNC_ConnectionID id,
TNC_AttributeID attribute_id,
TNC_UInt32 buffer_len,
TNC_BufferReference buffer,
- TNC_UInt32 *out_value_len);
+ TNC_UInt32 *value_len);
/**
* Set the value of an attribute associated with a connection or with the
* TNCS as a whole.
*
- * @param imv_id ID of the IMV setting the attribute
+ * @param is_imc TRUE if IMC, FALSE if IMV
+ * @param imcv_id ID of the IMC/IMV setting the attribute
* @param id ID of target connection
* @param attribute_id ID of the attribute to be set
* @param buffer_len length of the buffer in bytes
* @param buffer pointer to the buffer
* @return return code
*/
- TNC_Result (*set_attribute)(tnccs_manager_t *this,
- TNC_IMVID imv_id,
+ TNC_Result (*set_attribute)(tnccs_manager_t *this, bool is_imc,
+ TNC_UInt32 imcv_id,
TNC_ConnectionID id,
TNC_AttributeID attribute_id,
TNC_UInt32 buffer_len,
diff --git a/src/libtncif/Android.mk b/src/libtncif/Android.mk
index 91cfa8354..ef406dd59 100644
--- a/src/libtncif/Android.mk
+++ b/src/libtncif/Android.mk
@@ -16,6 +16,8 @@ LOCAL_CFLAGS := $(strongswan_CFLAGS)
LOCAL_MODULE := libtncif
+LOCAL_MODULE_TAGS := optional
+
LOCAL_ARM_MODE := arm
LOCAL_PRELINK_MODULE := false
diff --git a/src/libtncif/Makefile.am b/src/libtncif/Makefile.am
index cfaba912a..cc262ffca 100644
--- a/src/libtncif/Makefile.am
+++ b/src/libtncif/Makefile.am
@@ -5,3 +5,5 @@ noinst_LTLIBRARIES = libtncif.la
libtncif_la_SOURCES = \
tncif.h tncifimc.h tncifimv.h tncif_names.h tncif_names.c \
tncif_pa_subtypes.h tncif_pa_subtypes.c
+
+EXTRA_DIST = Android.mk
diff --git a/src/libtncif/tncif.h b/src/libtncif/tncif.h
index 3a889962e..f904bc600 100644
--- a/src/libtncif/tncif.h
+++ b/src/libtncif/tncif.h
@@ -1,22 +1,25 @@
/* tncif.h
*
- * Trusted Network Connect IF-IMV API version 1.20
+ * Trusted Network Connect IF-IMC/IMV API version 1.30
* Microsoft Windows DLL Platform Binding C Header
- * February 5, 2007
+ * October 14, 2011
*
- * Copyright(c) 2005-2007, Trusted Computing Group, Inc. All rights
+ * Common definitions for IF-IMC and IF-IMV
+ * extracted from tncifimc.h and tncifimv.h
+ *
+ * Copyright(c) 2005-2011, Trusted Computing Group, Inc. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
- * - Redistributions of source code must retain the above copyright
+ * o Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
+ * o Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
- * - Neither the name of the Trusted Computing Group nor the names of
+ * o Neither the name of the Trusted Computing Group nor the names of
* its contributors may be used to endorse or promote products
* derived from this software without specific prior written
* permission.
@@ -41,32 +44,38 @@
* Any marks and brands contained herein are the property of their
* respective owners.
*
- * Trusted Network Connect IF-IMC/IF-IMV API version 1.00 Revision 3
- * Microsoft Windows DLL Platform Binding C Header
- * Common definitions for IF-IMC and IF-IMV
- * extracted from tncifimc.h and tncifimv.h
- * Feb 12, 2007
+ */
+
+/**
+ * @defgroup tncif tncif
+ * @{ @ingroup libtncif
*/
#ifndef TNCIF_H_
#define TNCIF_H_
/* Basic Types */
+
typedef unsigned long TNC_UInt32;
typedef unsigned char *TNC_BufferReference;
/* Derived Types */
+
typedef TNC_UInt32 TNC_ConnectionID;
typedef TNC_UInt32 TNC_ConnectionState;
typedef TNC_UInt32 TNC_RetryReason;
typedef TNC_UInt32 TNC_MessageType;
typedef TNC_MessageType *TNC_MessageTypeList;
typedef TNC_UInt32 TNC_VendorID;
+typedef TNC_VendorID *TNC_VendorIDList;
typedef TNC_UInt32 TNC_MessageSubtype;
+typedef TNC_MessageSubtype *TNC_MessageSubtypeList;
typedef TNC_UInt32 TNC_Version;
typedef TNC_UInt32 TNC_Result;
+typedef TNC_UInt32 TNC_AttributeID;
/* Result Codes */
+
#define TNC_RESULT_SUCCESS 0
#define TNC_RESULT_NOT_INITIALIZED 1
#define TNC_RESULT_ALREADY_INITIALIZED 2
@@ -78,11 +87,17 @@ typedef TNC_UInt32 TNC_Result;
#define TNC_RESULT_ILLEGAL_OPERATION 8
#define TNC_RESULT_OTHER 9
#define TNC_RESULT_FATAL 10
+#define TNC_RESULT_EXCEEDED_MAX_ROUND_TRIPS 0x00559700
+#define TNC_RESULT_EXCEEDED_MAX_MESSAGE_SIZE 0x00559701
+#define TNC_RESULT_NO_LONG_MESSAGE_TYPES 0x00559702
+#define TNC_RESULT_NO_SOH_SUPPORT 0x00559703
/* Network Connection ID Values */
+
#define TNC_CONNECTIONID_ANY 0xFFFFFFFF
/* Network Connection State Values */
+
#define TNC_CONNECTION_STATE_CREATE 0
#define TNC_CONNECTION_STATE_HANDSHAKE 1
#define TNC_CONNECTION_STATE_ACCESS_ALLOWED 2
@@ -90,10 +105,38 @@ typedef TNC_UInt32 TNC_Result;
#define TNC_CONNECTION_STATE_ACCESS_NONE 4
#define TNC_CONNECTION_STATE_DELETE 5
+/* IMC/IMV ID Values */
+
+#define TNC_IMVID_ANY ((TNC_UInt32) 0xffff)
+#define TNC_IMCID_ANY ((TNC_UInt32) 0xffff)
+
/* Vendor ID Values */
+
#define TNC_VENDORID_TCG 0
+#define TNC_VENDORID_TCG_NEW 0x005597
#define TNC_VENDORID_ANY ((TNC_VendorID) 0xffffff)
+
/* Message Subtype Values */
+
#define TNC_SUBTYPE_ANY ((TNC_MessageSubtype) 0xff)
+/* Message Flags Values */
+
+#define TNC_MESSAGE_FLAGS_EXCLUSIVE ((TNC_UInt32) 0x80000000)
+
+/* Message Attribute ID Values */
+
+#define TNC_ATTRIBUTEID_PREFERRED_LANGUAGE ((TNC_AttributeID) 0x00000001)
+#define TNC_ATTRIBUTEID_MAX_ROUND_TRIPS ((TNC_AttributeID) 0x00559700)
+#define TNC_ATTRIBUTEID_MAX_MESSAGE_SIZE ((TNC_AttributeID) 0x00559701)
+#define TNC_ATTRIBUTEID_DHPN ((TNC_AttributeID) 0x00559702)
+#define TNC_ATTRIBUTEID_HAS_LONG_TYPES ((TNC_AttributeID) 0x00559703)
+#define TNC_ATTRIBUTEID_HAS_EXCLUSIVE ((TNC_AttributeID) 0x00559704)
+#define TNC_ATTRIBUTEID_HAS_SOH ((TNC_AttributeID) 0x00559705)
+#define TNC_ATTRIBUTEID_IFTNCCS_PROTOCOL ((TNC_AttributeID) 0x0055970A)
+#define TNC_ATTRIBUTEID_IFTNCCS_VERSION ((TNC_AttributeID) 0x0055970B)
+#define TNC_ATTRIBUTEID_IFT_PROTOCOL ((TNC_AttributeID) 0x0055970C)
+#define TNC_ATTRIBUTEID_IFT_VERSION ((TNC_AttributeID) 0x0055970D)
+#define TNC_ATTRIBUTEID_TLS_UNIQUE ((TNC_AttributeID) 0x0055970E)
+
#endif /** TNCIF_H_ @}*/
diff --git a/src/libtncif/tncif_names.h b/src/libtncif/tncif_names.h
index a7c9e7be3..9b50a34e9 100644
--- a/src/libtncif/tncif_names.h
+++ b/src/libtncif/tncif_names.h
@@ -12,6 +12,16 @@
* for more details.
*/
+/**
+ * @defgroup libtncif libtncif
+ *
+ * @addtogroup libtncif
+ * TNC interface definitions
+ *
+ * @defgroup tncif_names tncif_names
+ * @{ @ingroup libtncif
+ */
+
#ifndef TNCIF_NAMES_H_
#define TNCIF_NAMES_H_
diff --git a/src/libtncif/tncif_pa_subtypes.c b/src/libtncif/tncif_pa_subtypes.c
index de857e1ce..d15a1c864 100644
--- a/src/libtncif/tncif_pa_subtypes.c
+++ b/src/libtncif/tncif_pa_subtypes.c
@@ -16,7 +16,7 @@
#include "tncif_pa_subtypes.h"
-ENUM(pa_subtype_ietf_names, PA_SUBTYPE_IETF_TESTING, PA_SUBTYPE_IETF_NEA_CLIENT,
+ENUM_BEGIN(pa_subtype_ietf_names, PA_SUBTYPE_IETF_TESTING, PA_SUBTYPE_IETF_NEA_CLIENT,
"Testing",
"Operating System",
"Anti-Virus",
@@ -27,10 +27,20 @@ ENUM(pa_subtype_ietf_names, PA_SUBTYPE_IETF_TESTING, PA_SUBTYPE_IETF_NEA_CLIENT,
"VPN",
"NEA Client"
);
+ENUM_NEXT(pa_subtype_ietf_names, PA_SUBTYPE_IETF_ANY, PA_SUBTYPE_IETF_ANY,
+ PA_SUBTYPE_IETF_NEA_CLIENT,
+ "ANY"
+);
+ENUM_END(pa_subtype_ietf_names, PA_SUBTYPE_IETF_ANY);
-ENUM(pa_subtype_tcg_names, PA_SUBTYPE_TCG_PTS, PA_SUBTYPE_TCG_PTS,
+ENUM_BEGIN(pa_subtype_tcg_names, PA_SUBTYPE_TCG_PTS, PA_SUBTYPE_TCG_PTS,
"PTS"
);
+ENUM_NEXT(pa_subtype_tcg_names, PA_SUBTYPE_TCG_ANY, PA_SUBTYPE_TCG_ANY,
+ PA_SUBTYPE_TCG_PTS,
+ "ANY"
+);
+ENUM_END(pa_subtype_tcg_names, PA_SUBTYPE_TCG_ANY);
ENUM_BEGIN(pa_subtype_fhh_names, PA_SUBTYPE_FHH_HOSTSCANNER, PA_SUBTYPE_FHH_DUMMY,
"HostScanner",
@@ -45,12 +55,21 @@ ENUM_NEXT(pa_subtype_fhh_names, PA_SUBTYPE_FHH_CLAMAV, PA_SUBTYPE_FHH_CLAMAV,
PA_SUBTYPE_FHH_ATTESTATION,
"ClamAV"
);
-ENUM_END(pa_subtype_fhh_names, PA_SUBTYPE_FHH_CLAMAV);
+ENUM_NEXT(pa_subtype_fhh_names, PA_SUBTYPE_FHH_ANY, PA_SUBTYPE_FHH_ANY,
+ PA_SUBTYPE_FHH_CLAMAV,
+ "ANY"
+);
+ENUM_END(pa_subtype_fhh_names, PA_SUBTYPE_FHH_ANY);
-ENUM(pa_subtype_ita_names, PA_SUBTYPE_ITA_TEST, PA_SUBTYPE_ITA_SCANNER,
+ENUM_BEGIN(pa_subtype_ita_names, PA_SUBTYPE_ITA_TEST, PA_SUBTYPE_ITA_SCANNER,
"Test",
"Scanner"
);
+ENUM_NEXT(pa_subtype_ita_names, PA_SUBTYPE_ITA_ANY, PA_SUBTYPE_ITA_ANY,
+ PA_SUBTYPE_ITA_SCANNER,
+ "ANY"
+);
+ENUM_END(pa_subtype_ita_names, PA_SUBTYPE_ITA_ANY);
/**
* See header
diff --git a/src/libtncif/tncif_pa_subtypes.h b/src/libtncif/tncif_pa_subtypes.h
index 771971338..0be495bfc 100644
--- a/src/libtncif/tncif_pa_subtypes.h
+++ b/src/libtncif/tncif_pa_subtypes.h
@@ -12,6 +12,11 @@
* for more details.
*/
+/**
+ * @defgroup tncif_pa_subtypes tncif_pa_subtypes
+ * @{ @ingroup libtncif
+ */
+
#ifndef TNCIF_PA_SUBTYPES_H_
#define TNCIF_PA_SUBTYPES_H_
@@ -27,15 +32,16 @@ typedef enum pa_subtype_ita_t pa_subtype_ita_t;
* PA-TNC IETF Standard Subtypes as defined in section 3.5 of RFC 5792
*/
enum pa_subtype_ietf_t {
- PA_SUBTYPE_IETF_TESTING = 0,
- PA_SUBTYPE_IETF_OPERATING_SYSTEM = 1,
- PA_SUBTYPE_IETF_ANTI_VIRUS = 2,
- PA_SUBTYPE_IETF_ANTI_SPYWARE = 3,
- PA_SUBTYPE_IETF_ANTI_MALWARE = 4,
- PA_SUBTYPE_IETF_FIREWALL = 5,
- PA_SUBTYPE_IETF_IDPS = 6,
- PA_SUBTYPE_IETF_VPN = 7,
- PA_SUBTYPE_IETF_NEA_CLIENT = 8
+ PA_SUBTYPE_IETF_TESTING = 0x00,
+ PA_SUBTYPE_IETF_OPERATING_SYSTEM = 0x01,
+ PA_SUBTYPE_IETF_ANTI_VIRUS = 0x02,
+ PA_SUBTYPE_IETF_ANTI_SPYWARE = 0x03,
+ PA_SUBTYPE_IETF_ANTI_MALWARE = 0x04,
+ PA_SUBTYPE_IETF_FIREWALL = 0x05,
+ PA_SUBTYPE_IETF_IDPS = 0x06,
+ PA_SUBTYPE_IETF_VPN = 0x07,
+ PA_SUBTYPE_IETF_NEA_CLIENT = 0x08,
+ PA_SUBTYPE_IETF_ANY = 0xff
};
/**
@@ -47,7 +53,8 @@ extern enum_name_t *pa_subtype_ietf_names;
* PA-TNC TCG Subtypes
*/
enum pa_subtype_tcg_t {
- PA_SUBTYPE_TCG_PTS = 1
+ PA_SUBTYPE_TCG_PTS = 0x01,
+ PA_SUBTYPE_TCG_ANY = 0xff
};
/**
@@ -59,11 +66,12 @@ extern enum_name_t *pa_subtype_tcg_names;
* PA-TNC FHH Subtypes
*/
enum pa_subtype_fhh_t {
- PA_SUBTYPE_FHH_HOSTSCANNER = 0x30,
- PA_SUBTYPE_FHH_DUMMY = 0x31,
- PA_SUBTYPE_FHH_PLATID = 0x33,
- PA_SUBTYPE_FHH_ATTESTATION = 0x34,
- PA_SUBTYPE_FHH_CLAMAV = 0x41
+ PA_SUBTYPE_FHH_HOSTSCANNER = 0x30,
+ PA_SUBTYPE_FHH_DUMMY = 0x31,
+ PA_SUBTYPE_FHH_PLATID = 0x33,
+ PA_SUBTYPE_FHH_ATTESTATION = 0x34,
+ PA_SUBTYPE_FHH_CLAMAV = 0x41,
+ PA_SUBTYPE_FHH_ANY = 0xff
};
/**
@@ -75,8 +83,9 @@ extern enum_name_t *pa_subtype_fhh_names;
* PA-TNC ITA-HSR Subtypes
*/
enum pa_subtype_ita_t {
- PA_SUBTYPE_ITA_TEST = 1,
- PA_SUBTYPE_ITA_SCANNER = 2
+ PA_SUBTYPE_ITA_TEST = 0x01,
+ PA_SUBTYPE_ITA_SCANNER = 0x02,
+ PA_SUBTYPE_ITA_ANY = 0xff
};
/**
diff --git a/src/libtncif/tncifimc.h b/src/libtncif/tncifimc.h
index c6ddabd45..45af913df 100644
--- a/src/libtncif/tncifimc.h
+++ b/src/libtncif/tncifimc.h
@@ -1,22 +1,22 @@
/* tncifimc.h
*
- * Trusted Network Connect IF-IMC API version 1.20 Revision 8
+ * Trusted Network Connect IF-IMC API version 1.30
* Microsoft Windows DLL Platform Binding C Header
- * February 5, 2007
+ * October 14, 2011
*
- * Copyright(c) 2005-2007, Trusted Computing Group, Inc. All rights
+ * Copyright(c) 2005-2011, Trusted Computing Group, Inc. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
- * - Redistributions of source code must retain the above copyright
+ * o Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
+ * o Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
- * - Neither the name of the Trusted Computing Group nor the names of
+ * o Neither the name of the Trusted Computing Group nor the names of
* its contributors may be used to endorse or promote products
* derived from this software without specific prior written
* permission.
@@ -45,7 +45,7 @@
/**
* @defgroup tncifimc tncifimc
- * @{ @ingroup tnc
+ * @{ @ingroup libtncif
*/
#ifndef TNCIFIMC_H_
@@ -53,6 +53,16 @@
#include "tncif.h"
+#ifdef WIN32
+#ifdef TNC_IMC_EXPORTS
+#define TNC_IMC_API __declspec(dllexport)
+#else
+#define TNC_IMC_API __declspec(dllimport)
+#endif
+#else
+#define TNC_IMC_API
+#endif
+
/* Derived Types */
typedef TNC_UInt32 TNC_IMCID;
@@ -77,6 +87,22 @@ typedef TNC_Result (*TNC_IMC_ReceiveMessagePointer)(
TNC_BufferReference message,
TNC_UInt32 messageLength,
TNC_MessageType messageType);
+typedef TNC_Result (*TNC_IMC_ReceiveMessageSOHPointer)(
+ TNC_IMCID imcID,
+ TNC_ConnectionID connectionID,
+ TNC_BufferReference sohrReportEntry,
+ TNC_UInt32 sohrRELength,
+ TNC_MessageType systemHealthID);
+typedef TNC_Result (*TNC_IMC_ReceiveMessageLongPointer)(
+ TNC_IMCID imcID,
+ TNC_ConnectionID connectionID,
+ TNC_UInt32 messageFlags,
+ TNC_BufferReference message,
+ TNC_UInt32 messageLength,
+ TNC_VendorID messageVendorID,
+ TNC_MessageSubtype messageSubtype,
+ TNC_UInt32 sourceIMVID,
+ TNC_UInt32 destinationIMCID);
typedef TNC_Result (*TNC_IMC_BatchEndingPointer)(
TNC_IMCID imcID,
TNC_ConnectionID connectionID);
@@ -86,16 +112,51 @@ typedef TNC_Result (*TNC_TNCC_ReportMessageTypesPointer)(
TNC_IMCID imcID,
TNC_MessageTypeList supportedTypes,
TNC_UInt32 typeCount);
+typedef TNC_Result (*TNC_TNCC_ReportMessageTypesLongPointer)(
+ TNC_IMCID imcID,
+ TNC_VendorIDList supportedVendorIDs,
+ TNC_MessageSubtypeList supportedSubtypes,
+ TNC_UInt32 typeCount);
typedef TNC_Result (*TNC_TNCC_SendMessagePointer)(
TNC_IMCID imcID,
TNC_ConnectionID connectionID,
TNC_BufferReference message,
TNC_UInt32 messageLength,
TNC_MessageType messageType);
+typedef TNC_Result (*TNC_TNCC_SendMessageSOHPointer)(
+ TNC_IMCID imcID,
+ TNC_ConnectionID connectionID,
+ TNC_BufferReference sohReportEntry,
+ TNC_UInt32 sohRELength);
+typedef TNC_Result (*TNC_TNCC_SendMessageLongPointer)(
+ TNC_IMCID imcID,
+ TNC_ConnectionID connectionID,
+ TNC_UInt32 messageFlags,
+ TNC_BufferReference message,
+ TNC_UInt32 messageLength,
+ TNC_VendorID messageVendorID,
+ TNC_MessageSubtype messageSubtype,
+ TNC_UInt32 destinationIMVID);
typedef TNC_Result (*TNC_TNCC_RequestHandshakeRetryPointer)(
TNC_IMCID imcID,
TNC_ConnectionID connectionID,
TNC_RetryReason reason);
+typedef TNC_Result (*TNC_TNCC_GetAttributePointer)(
+ TNC_IMCID imcID,
+ TNC_ConnectionID connectionID,
+ TNC_AttributeID attributeID,
+ TNC_UInt32 bufferLength,
+ TNC_BufferReference buffer,
+ TNC_UInt32 *pOutValueLength);
+typedef TNC_Result (*TNC_TNCC_SetAttributePointer)(
+ TNC_IMCID imcID,
+ TNC_ConnectionID connectionID,
+ TNC_AttributeID attributeID,
+ TNC_UInt32 bufferLength,
+ TNC_BufferReference buffer);
+typedef TNC_Result (*TNC_TNCC_ReserveAdditionalIMCIDPointer)(
+ TNC_IMCID imcID,
+ TNC_UInt32 *pOutIMCID);
typedef TNC_Result (*TNC_TNCC_BindFunctionPointer)(
TNC_IMCID imcID,
char *functionName,
@@ -104,6 +165,8 @@ typedef TNC_Result (*TNC_IMC_ProvideBindFunctionPointer)(
TNC_IMCID imcID,
TNC_TNCC_BindFunctionPointer bindFunction);
+/* Version Numbers */
+
#define TNC_IFIMC_VERSION_1 1
/* Handshake Retry Reason Values */
@@ -118,38 +181,62 @@ typedef TNC_Result (*TNC_IMC_ProvideBindFunctionPointer)(
/* reserved for TNC_RETRY_REASON_IMV_MINOR_EVENT: 7 */
/* reserved for TNC_RETRY_REASON_IMV_PERIODIC: 8 */
+/* Message Attribute ID Values */
+
+#define TNC_ATTRIBUTEID_SOHR ((TNC_AttributeID) 0x00559708)
+#define TNC_ATTRIBUTEID_SSOHR ((TNC_AttributeID) 0x00559709)
+#define TNC_ATTRIBUTEID_PRIMARY_IMC_ID ((TNC_AttributeID) 0x00559711)
+
/* IMC Functions */
-TNC_Result TNC_IMC_Initialize(
+TNC_IMC_API TNC_Result TNC_IMC_Initialize(
/*in*/ TNC_IMCID imcID,
/*in*/ TNC_Version minVersion,
/*in*/ TNC_Version maxVersion,
/*out*/ TNC_Version *pOutActualVersion);
-TNC_Result TNC_IMC_NotifyConnectionChange(
+TNC_IMC_API TNC_Result TNC_IMC_NotifyConnectionChange(
/*in*/ TNC_IMCID imcID,
/*in*/ TNC_ConnectionID connectionID,
/*in*/ TNC_ConnectionState newState);
-TNC_Result TNC_IMC_BeginHandshake(
+TNC_IMC_API TNC_Result TNC_IMC_BeginHandshake(
/*in*/ TNC_IMCID imcID,
/*in*/ TNC_ConnectionID connectionID);
-TNC_Result TNC_IMC_ReceiveMessage(
+TNC_IMC_API TNC_Result TNC_IMC_ReceiveMessage(
/*in*/ TNC_IMCID imcID,
/*in*/ TNC_ConnectionID connectionID,
/*in*/ TNC_BufferReference messageBuffer,
/*in*/ TNC_UInt32 messageLength,
/*in*/ TNC_MessageType messageType);
-TNC_Result TNC_IMC_BatchEnding(
+TNC_IMC_API TNC_Result TNC_IMC_ReceiveMessageSOH(
+/*in*/ TNC_IMCID imcID,
+/*in*/ TNC_ConnectionID connectionID,
+/*in*/ TNC_BufferReference sohrReportEntry,
+/*in*/ TNC_UInt32 sohrRELength,
+/*in*/ TNC_MessageType systemHealthID);
+
+TNC_IMC_API TNC_Result TNC_IMC_ReceiveMessageLong(
+/*in*/ TNC_IMCID imcID,
+/*in*/ TNC_ConnectionID connectionID,
+/*in*/ TNC_UInt32 messageFlags,
+/*in*/ TNC_BufferReference message,
+/*in*/ TNC_UInt32 messageLength,
+/*in*/ TNC_VendorID messageVendorID,
+/*in*/ TNC_MessageSubtype messageSubtype,
+/*in*/ TNC_UInt32 sourceIMVID,
+/*in*/ TNC_UInt32 destinationIMCID);
+
+TNC_IMC_API TNC_Result TNC_IMC_BatchEnding(
/*in*/ TNC_IMCID imcID,
/*in*/ TNC_ConnectionID connectionID);
-TNC_Result TNC_IMC_Terminate(
+TNC_IMC_API TNC_Result TNC_IMC_Terminate(
/*in*/ TNC_IMCID imcID);
-TNC_Result TNC_IMC_ProvideBindFunction(
+TNC_IMC_API TNC_Result TNC_IMC_ProvideBindFunction(
/*in*/ TNC_IMCID imcID,
/*in*/ TNC_TNCC_BindFunctionPointer bindFunction);
@@ -160,6 +247,12 @@ TNC_Result TNC_TNCC_ReportMessageTypes(
/*in*/ TNC_MessageTypeList supportedTypes,
/*in*/ TNC_UInt32 typeCount);
+TNC_Result TNC_TNCC_ReportMessageTypesLong(
+/*in*/ TNC_IMCID imcID,
+/*in*/ TNC_VendorIDList supportedVendorIDs,
+/*in*/ TNC_MessageSubtypeList supportedSubtypes,
+/*in*/ TNC_UInt32 typeCount);
+
TNC_Result TNC_TNCC_SendMessage(
/*in*/ TNC_IMCID imcID,
/*in*/ TNC_ConnectionID connectionID,
@@ -167,11 +260,45 @@ TNC_Result TNC_TNCC_SendMessage(
/*in*/ TNC_UInt32 messageLength,
/*in*/ TNC_MessageType messageType);
+TNC_Result TNC_TNCC_SendMessageSOH(
+/*in*/ TNC_IMCID imcID,
+/*in*/ TNC_ConnectionID connectionID,
+/*in*/ TNC_BufferReference sohReportEntry,
+/*in*/ TNC_UInt32 sohRELength);
+
+TNC_Result TNC_TNCC_SendMessageLong(
+/*in*/ TNC_IMCID imcID,
+/*in*/ TNC_ConnectionID connectionID,
+/*in*/ TNC_UInt32 messageFlags,
+/*in*/ TNC_BufferReference message,
+/*in*/ TNC_UInt32 messageLength,
+/*in*/ TNC_VendorID messageVendorID,
+/*in*/ TNC_MessageSubtype messageSubtype,
+/*in*/ TNC_UInt32 destinationIMVID);
TNC_Result TNC_TNCC_RequestHandshakeRetry(
/*in*/ TNC_IMCID imcID,
/*in*/ TNC_ConnectionID connectionID,
/*in*/ TNC_RetryReason reason);
+TNC_Result TNC_TNCC_GetAttribute(
+/*in*/ TNC_IMCID imcID,
+/*in*/ TNC_ConnectionID connectionID,
+/*in*/ TNC_AttributeID attributeID,
+/*in*/ TNC_UInt32 bufferLength,
+/*out*/ TNC_BufferReference buffer,
+/*out*/ TNC_UInt32 *pOutValueLength);
+
+TNC_Result TNC_TNCC_SetAttribute(
+/*in*/ TNC_IMCID imcID,
+/*in*/ TNC_ConnectionID connectionID,
+/*in*/ TNC_AttributeID attributeID,
+/*in*/ TNC_UInt32 bufferLength,
+/*in*/ TNC_BufferReference buffer);
+
+TNC_Result TNC_TNCS_ReserveAdditionalIMCID(
+/*in*/ TNC_IMCID imcID,
+/*out*/ TNC_UInt32 *pOutIMCID);
+
TNC_Result TNC_TNCC_BindFunction(
/*in*/ TNC_IMCID imcID,
/*in*/ char *functionName,
diff --git a/src/libtncif/tncifimv.h b/src/libtncif/tncifimv.h
index 7a2394c06..3c9db0055 100644
--- a/src/libtncif/tncifimv.h
+++ b/src/libtncif/tncifimv.h
@@ -1,22 +1,22 @@
/* tncifimv.h
*
- * Trusted Network Connect IF-IMV API version 1.20
+ * Trusted Network Connect IF-IMV API version 1.30
* Microsoft Windows DLL Platform Binding C Header
- * February 5, 2007
+ * October 14, 2011
*
- * Copyright(c) 2005-2007, Trusted Computing Group, Inc. All rights
+ * Copyright(c) 2005-2011, Trusted Computing Group, Inc. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
- * - Redistributions of source code must retain the above copyright
+ * o Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
+ * o Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
- * - Neither the name of the Trusted Computing Group nor the names of
+ * o Neither the name of the Trusted Computing Group nor the names of
* its contributors may be used to endorse or promote products
* derived from this software without specific prior written
* permission.
@@ -42,80 +42,134 @@
* respective owners.
*/
+/**
+ * @defgroup tncifimv tncifimv
+ * @{ @ingroup libtncif
+ */
+
#ifndef TNCIFIMV_H_
#define TNCIFIMV_H_
#include "tncif.h"
+#ifdef WIN32
+#ifdef TNC_IMV_EXPORTS
+#define TNC_IMV_API __declspec(dllexport)
+#else
+#define TNC_IMV_API __declspec(dllimport)
+#endif
+#else
+#define TNC_IMV_API
+#endif
+
+/* Derived Types */
+
typedef TNC_UInt32 TNC_IMVID;
typedef TNC_UInt32 TNC_IMV_Action_Recommendation;
typedef TNC_UInt32 TNC_IMV_Evaluation_Result;
-typedef TNC_UInt32 TNC_AttributeID;
/* Function pointers */
typedef TNC_Result (*TNC_IMV_InitializePointer)(
- TNC_IMVID imvID,
- TNC_Version minVersion,
- TNC_Version maxVersion,
- TNC_Version *pOutActualVersion);
+ TNC_IMVID imvID,
+ TNC_Version minVersion,
+ TNC_Version maxVersion,
+ TNC_Version *pOutActualVersion);
typedef TNC_Result (*TNC_IMV_NotifyConnectionChangePointer)(
- TNC_IMVID imvID,
- TNC_ConnectionID connectionID,
- TNC_ConnectionState newState);
+ TNC_IMVID imvID,
+ TNC_ConnectionID connectionID,
+ TNC_ConnectionState newState);
typedef TNC_Result (*TNC_IMV_ReceiveMessagePointer)(
- TNC_IMVID imvID,
- TNC_ConnectionID connectionID,
- TNC_BufferReference message,
- TNC_UInt32 messageLength,
- TNC_MessageType messageType);
+ TNC_IMVID imvID,
+ TNC_ConnectionID connectionID,
+ TNC_BufferReference message,
+ TNC_UInt32 messageLength,
+ TNC_MessageType messageType);
+typedef TNC_Result (*TNC_IMV_ReceiveMessageSOHPointer)(
+ TNC_IMVID imvID,
+ TNC_ConnectionID connectionID,
+ TNC_BufferReference sohReportEntry,
+ TNC_UInt32 sohRELength,
+ TNC_MessageType systemHealthID);
+typedef TNC_Result (*TNC_IMV_ReceiveMessageLongPointer)(
+ TNC_IMVID imvID,
+ TNC_ConnectionID connectionID,
+ TNC_UInt32 messageFlags,
+ TNC_BufferReference message,
+ TNC_UInt32 messageLength,
+ TNC_VendorID messageVendorID,
+ TNC_MessageSubtype messageSubtype,
+ TNC_UInt32 sourceIMCID,
+ TNC_UInt32 destinationIMVID);
typedef TNC_Result (*TNC_IMV_SolicitRecommendationPointer)(
- TNC_IMVID imvID,
- TNC_ConnectionID connectionID);
+ TNC_IMVID imvID,
+ TNC_ConnectionID connectionID);
typedef TNC_Result (*TNC_IMV_BatchEndingPointer)(
- TNC_IMVID imvID,
- TNC_ConnectionID connectionID);
+ TNC_IMVID imvID,
+ TNC_ConnectionID connectionID);
typedef TNC_Result (*TNC_IMV_TerminatePointer)(
- TNC_IMVID imvID);
+ TNC_IMVID imvID);
typedef TNC_Result (*TNC_TNCS_ReportMessageTypesPointer)(
- TNC_IMVID imvID,
- TNC_MessageTypeList supportedTypes,
- TNC_UInt32 typeCount);
+ TNC_IMVID imvID,
+ TNC_MessageTypeList supportedTypes,
+ TNC_UInt32 typeCount);
+typedef TNC_Result (*TNC_TNCS_ReportMessageTypesLongPointer)(
+ TNC_IMVID imvID,
+ TNC_VendorIDList supportedVendorIDs,
+ TNC_MessageSubtypeList supportedSubtypes,
+ TNC_UInt32 typeCount);
typedef TNC_Result (*TNC_TNCS_SendMessagePointer)(
- TNC_IMVID imvID,
- TNC_ConnectionID connectionID,
- TNC_BufferReference message,
- TNC_UInt32 messageLength,
- TNC_MessageType messageType);
+ TNC_IMVID imvID,
+ TNC_ConnectionID connectionID,
+ TNC_BufferReference message,
+ TNC_UInt32 messageLength,
+ TNC_MessageType messageType);
+typedef TNC_Result (*TNC_TNCS_SendMessageSOHPointer)(
+ TNC_IMVID imvID,
+ TNC_ConnectionID connectionID,
+ TNC_BufferReference sohrReportEntry,
+ TNC_UInt32 sohrRELength);
+typedef TNC_Result (*TNC_TNCS_SendMessageLongPointer)(
+ TNC_IMVID imvID,
+ TNC_ConnectionID connectionID,
+ TNC_UInt32 messageFlags,
+ TNC_BufferReference message,
+ TNC_UInt32 messageLength,
+ TNC_VendorID messageVendorID,
+ TNC_MessageSubtype messageSubtype,
+ TNC_UInt32 destinationIMCID);
typedef TNC_Result (*TNC_TNCS_RequestHandshakeRetryPointer)(
- TNC_IMVID imvID,
- TNC_ConnectionID connectionID,
- TNC_RetryReason reason);
+ TNC_IMVID imvID,
+ TNC_ConnectionID connectionID,
+ TNC_RetryReason reason);
typedef TNC_Result (*TNC_TNCS_ProvideRecommendationPointer)(
- TNC_IMVID imvID,
- TNC_ConnectionID connectionID,
- TNC_IMV_Action_Recommendation recommendation,
- TNC_IMV_Evaluation_Result evaluation);
+ TNC_IMVID imvID,
+ TNC_ConnectionID connectionID,
+ TNC_IMV_Action_Recommendation recommendation,
+ TNC_IMV_Evaluation_Result evaluation);
typedef TNC_Result (*TNC_TNCS_GetAttributePointer)(
- TNC_IMVID imvID,
-TNC_ConnectionID connectionID,
-TNC_AttributeID attributeID,
- TNC_UInt32 bufferLength,
- TNC_BufferReference buffer,
- TNC_UInt32 *pOutValueLength);
-typedef TNC_Result (*TNC_TNCS_SetAttributePointer)(
- TNC_IMVID imvID,
+ TNC_IMVID imvID,
TNC_ConnectionID connectionID,
-TNC_AttributeID attributeID,
- TNC_UInt32 bufferLength,
- TNC_BufferReference buffer);
+ TNC_AttributeID attributeID,
+ TNC_UInt32 bufferLength,
+ TNC_BufferReference buffer,
+ TNC_UInt32 *pOutValueLength);
+typedef TNC_Result (*TNC_TNCS_SetAttributePointer)(
+ TNC_IMVID imvID,
+ TNC_ConnectionID connectionID,
+ TNC_AttributeID attributeID,
+ TNC_UInt32 bufferLength,
+ TNC_BufferReference buffer);
+typedef TNC_Result (*TNC_TNCS_ReserveAdditionalIMVIDPointer)(
+ TNC_IMVID imvID,
+ TNC_UInt32 *pOutIMVID);
typedef TNC_Result (*TNC_TNCS_BindFunctionPointer)(
- TNC_IMVID imvID,
- char *functionName,
- void **pOutfunctionPointer);
+ TNC_IMVID imvID,
+ char *functionName,
+ void **pOutfunctionPointer);
typedef TNC_Result (*TNC_IMV_ProvideBindFunctionPointer)(
- TNC_IMVID imvID,
- TNC_TNCS_BindFunctionPointer bindFunction);
+ TNC_IMVID imvID,
+ TNC_TNCS_BindFunctionPointer bindFunction);
/* Version Numbers */
@@ -150,42 +204,62 @@ typedef TNC_Result (*TNC_IMV_ProvideBindFunctionPointer)(
/* Message Attribute ID Values */
-#define TNC_ATTRIBUTEID_PREFERRED_LANGUAGE ((TNC_AttributeID) 0x00000001)
#define TNC_ATTRIBUTEID_REASON_STRING ((TNC_AttributeID) 0x00000002)
#define TNC_ATTRIBUTEID_REASON_LANGUAGE ((TNC_AttributeID) 0x00000003)
+#define TNC_ATTRIBUTEID_SOH ((TNC_AttributeID) 0x00559706)
+#define TNC_ATTRIBUTEID_SSOH ((TNC_AttributeID) 0x00559707)
+#define TNC_ATTRIBUTEID_PRIMARY_IMV_ID ((TNC_AttributeID) 0x00559710)
/* IMV Functions */
-TNC_Result TNC_IMV_Initialize(
+TNC_IMV_API TNC_Result TNC_IMV_Initialize(
/*in*/ TNC_IMVID imvID,
/*in*/ TNC_Version minVersion,
/*in*/ TNC_Version maxVersion,
/*in*/ TNC_Version *pOutActualVersion);
-TNC_Result TNC_IMV_NotifyConnectionChange(
+TNC_IMV_API TNC_Result TNC_IMV_NotifyConnectionChange(
/*in*/ TNC_IMVID imvID,
/*in*/ TNC_ConnectionID connectionID,
/*in*/ TNC_ConnectionState newState);
-TNC_Result TNC_IMV_ReceiveMessage(
+TNC_IMV_API TNC_Result TNC_IMV_ReceiveMessage(
/*in*/ TNC_IMVID imvID,
/*in*/ TNC_ConnectionID connectionID,
/*in*/ TNC_BufferReference messageBuffer,
/*in*/ TNC_UInt32 messageLength,
/*in*/ TNC_MessageType messageType);
-TNC_Result TNC_IMV_SolicitRecommendation(
+TNC_IMV_API TNC_Result TNC_IMV_ReceiveMessageSOH(
+/*in*/ TNC_IMVID imvID,
+/*in*/ TNC_ConnectionID connectionID,
+/*in*/ TNC_BufferReference sohReportEntry,
+/*in*/ TNC_UInt32 sohRELength,
+/*in*/ TNC_MessageType systemHealthID);
+
+TNC_IMV_API TNC_Result TNC_IMV_ReceiveMessageLong(
+/*in*/ TNC_IMVID imvID,
+/*in*/ TNC_ConnectionID connectionID,
+/*in*/ TNC_UInt32 messageFlags,
+/*in*/ TNC_BufferReference message,
+/*in*/ TNC_UInt32 messageLength,
+/*in*/ TNC_VendorID messageVendorID,
+/*in*/ TNC_MessageSubtype messageSubtype,
+/*in*/ TNC_UInt32 sourceIMCID,
+/*in*/ TNC_UInt32 destinationIMVID);
+
+TNC_IMV_API TNC_Result TNC_IMV_SolicitRecommendation(
/*in*/ TNC_IMVID imvID,
/*in*/ TNC_ConnectionID connectionID);
-TNC_Result TNC_IMV_BatchEnding(
+TNC_IMV_API TNC_Result TNC_IMV_BatchEnding(
/*in*/ TNC_IMVID imvID,
/*in*/ TNC_ConnectionID connectionID);
-TNC_Result TNC_IMV_Terminate(
+TNC_IMV_API TNC_Result TNC_IMV_Terminate(
/*in*/ TNC_IMVID imvID);
-TNC_Result TNC_IMV_ProvideBindFunction(
+TNC_IMV_API TNC_Result TNC_IMV_ProvideBindFunction(
/*in*/ TNC_IMVID imvID,
/*in*/ TNC_TNCS_BindFunctionPointer bindFunction);
@@ -196,6 +270,12 @@ TNC_Result TNC_TNCS_ReportMessageTypes(
/*in*/ TNC_MessageTypeList supportedTypes,
/*in*/ TNC_UInt32 typeCount);
+TNC_Result TNC_TNCS_ReportMessageTypesLong(
+/*in*/ TNC_IMVID imvID,
+/*in*/ TNC_VendorIDList supportedVendorIDs,
+/*in*/ TNC_MessageSubtypeList supportedSubtypes,
+/*in*/ TNC_UInt32 typeCount);
+
TNC_Result TNC_TNCS_SendMessage(
/*in*/ TNC_IMVID imvID,
/*in*/ TNC_ConnectionID connectionID,
@@ -203,6 +283,22 @@ TNC_Result TNC_TNCS_SendMessage(
/*in*/ TNC_UInt32 messageLength,
/*in*/ TNC_MessageType messageType);
+TNC_Result TNC_TNCS_SendMessageSOH(
+/*in*/ TNC_IMVID imvID,
+/*in*/ TNC_ConnectionID connectionID,
+/*in*/ TNC_BufferReference sohrReportEntry,
+/*in*/ TNC_UInt32 sohrRELength);
+
+TNC_Result TNC_TNCS_SendMessageLong(
+/*in*/ TNC_IMVID imvID,
+/*in*/ TNC_ConnectionID connectionID,
+/*in*/ TNC_UInt32 messageFlags,
+/*in*/ TNC_BufferReference message,
+/*in*/ TNC_UInt32 messageLength,
+/*in*/ TNC_VendorID messageVendorID,
+/*in*/ TNC_MessageSubtype messageSubtype,
+/*in*/ TNC_UInt32 destinationIMCID);
+
TNC_Result TNC_TNCS_RequestHandshakeRetry(
/*in*/ TNC_IMVID imvID,
/*in*/ TNC_ConnectionID connectionID,
@@ -222,13 +318,16 @@ TNC_Result TNC_TNCS_GetAttribute(
/*out*/ TNC_BufferReference buffer,
/*out*/ TNC_UInt32 *pOutValueLength);
-TNC_Result TNC_TNCS_SetAttribute(
+TNC_Result TNC_TNCS_ReserveAdditionalIMVID(
/*in*/ TNC_IMVID imvID,
-/*in*/ TNC_ConnectionID connectionID,
-/*in*/ TNC_AttributeID attributeID,
-/*in*/ TNC_UInt32 bufferLength,
-/*in*/ TNC_BufferReference buffer);
+/*out*/ TNC_UInt32 *pOutIMVID);
+TNC_Result TNC_TNCS_SetAttribute(
+/*in*/ TNC_IMVID imvID,
+/*in*/ TNC_ConnectionID connectionID,
+/*in*/ TNC_AttributeID attributeID,
+/*in*/ TNC_UInt32 bufferLength,
+/*in*/ TNC_BufferReference buffer);
TNC_Result TNC_TNCS_BindFunction(
/*in*/ TNC_IMVID imvID,
/*in*/ char *functionName,
diff --git a/src/pki/command.c b/src/pki/command.c
index 0142b4ab7..07ba5bb1d 100644
--- a/src/pki/command.c
+++ b/src/pki/command.c
@@ -176,6 +176,13 @@ int command_usage(char *error)
fprintf(out, "Error: %s\n", error);
}
fprintf(out, "strongSwan %s PKI tool\n", VERSION);
+
+ if (active == help_idx)
+ {
+ fprintf(out, "loaded plugins: %s\n",
+ lib->plugins->loaded_plugins(lib->plugins));
+ }
+
fprintf(out, "usage:\n");
if (active == help_idx)
{
diff --git a/src/pki/commands/issue.c b/src/pki/commands/issue.c
index 97769fca6..0398c9dc9 100644
--- a/src/pki/commands/issue.c
+++ b/src/pki/commands/issue.c
@@ -67,11 +67,11 @@ static int issue()
char *error = NULL, *keyid = NULL;
identification_t *id = NULL;
linked_list_t *san, *cdps, *ocsp, *permitted, *excluded, *policies, *mappings;
- int lifetime = 1095;
int pathlen = X509_NO_CONSTRAINT, inhibit_any = X509_NO_CONSTRAINT;
int inhibit_mapping = X509_NO_CONSTRAINT, require_explicit = X509_NO_CONSTRAINT;
chunk_t serial = chunk_empty;
chunk_t encoding = chunk_empty;
+ time_t lifetime = 1095;
time_t not_before, not_after;
x509_flag_t flags = 0;
x509_t *x509;
diff --git a/src/pki/commands/self.c b/src/pki/commands/self.c
index 7852d8594..6813c98f7 100644
--- a/src/pki/commands/self.c
+++ b/src/pki/commands/self.c
@@ -55,11 +55,11 @@ static int self()
char *file = NULL, *dn = NULL, *hex = NULL, *error = NULL, *keyid = NULL;
identification_t *id = NULL;
linked_list_t *san, *ocsp, *permitted, *excluded, *policies, *mappings;
- int lifetime = 1095;
int pathlen = X509_NO_CONSTRAINT, inhibit_any = X509_NO_CONSTRAINT;
int inhibit_mapping = X509_NO_CONSTRAINT, require_explicit = X509_NO_CONSTRAINT;
chunk_t serial = chunk_empty;
chunk_t encoding = chunk_empty;
+ time_t lifetime = 1095;
time_t not_before, not_after;
x509_flag_t flags = 0;
x509_cert_policy_t *policy = NULL;
diff --git a/src/pki/commands/signcrl.c b/src/pki/commands/signcrl.c
index 9a21bd99c..827fd7318 100644
--- a/src/pki/commands/signcrl.c
+++ b/src/pki/commands/signcrl.c
@@ -124,7 +124,7 @@ static int sign_crl()
int serial_len = 0;
crl_reason_t reason = CRL_REASON_UNSPECIFIED;
time_t thisUpdate, nextUpdate, date = time(NULL);
- int lifetime = 15;
+ time_t lifetime = 15;
linked_list_t *list, *cdps;
enumerator_t *enumerator, *lastenum = NULL;
x509_cdp_t *cdp;
diff --git a/src/pluto/Android.mk b/src/pluto/Android.mk
index 4c4bdca92..618f79c42 100644
--- a/src/pluto/Android.mk
+++ b/src/pluto/Android.mk
@@ -69,6 +69,8 @@ LOCAL_CFLAGS := $(strongswan_CFLAGS) \
LOCAL_MODULE := pluto
+LOCAL_MODULE_TAGS := optional
+
LOCAL_ARM_MODE := arm
LOCAL_PRELINK_MODULE := false
diff --git a/src/pluto/Makefile.am b/src/pluto/Makefile.am
index 68ba16346..3fd0e039c 100644
--- a/src/pluto/Makefile.am
+++ b/src/pluto/Makefile.am
@@ -102,6 +102,8 @@ endif
dist_man_MANS = pluto.8
+EXTRA_DIST = Android.mk
+
# compile options
#################
diff --git a/src/pluto/ca.c b/src/pluto/ca.c
index 175c0b022..827b98121 100644
--- a/src/pluto/ca.c
+++ b/src/pluto/ca.c
@@ -219,7 +219,8 @@ cert_t* get_authcert(identification_t *subject, chunk_t keyid,
}
/* compare the subjectDistinguishedNames */
- if (!certificate->has_subject(certificate, subject))
+ if (!(subject && certificate->has_subject(certificate, subject)) &&
+ (subject || !keyid.ptr))
{
continue;
}
diff --git a/src/pluto/defs.c b/src/pluto/defs.c
index f83318e12..7f3a819de 100644
--- a/src/pluto/defs.c
+++ b/src/pluto/defs.c
@@ -16,6 +16,7 @@
#include <string.h>
#include <stdio.h>
#include <dirent.h>
+#include <inttypes.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -91,8 +92,7 @@ mv_chunk(u_char **pos, chunk_t content)
const char*
check_expiry(time_t expiration_date, int warning_interval, bool strict)
{
- time_t now;
- int time_left;
+ time_t now, time_left;
if (expiration_date == UNDEFINED_TIME)
return "ok (expires never)";
@@ -125,8 +125,8 @@ check_expiry(time_t expiration_date, int warning_interval, bool strict)
time_left /= 60;
unit = "minute";
}
- snprintf(buf, 35, "warning (expires in %d %s%s)", time_left,
- unit, (time_left == 1)?"":"s");
+ snprintf(buf, 35, "warning (expires in %" PRIu64 " %s%s)",
+ (u_int64_t)time_left, unit, (time_left == 1) ? "" : "s");
return buf;
}
}
diff --git a/src/pluto/keys.c b/src/pluto/keys.c
index 9031fcda5..fb61bef5c 100644
--- a/src/pluto/keys.c
+++ b/src/pluto/keys.c
@@ -835,14 +835,7 @@ static void process_secret(secret_t *s, int whackfd)
err_t ugh = NULL;
s->kind = SECRET_PSK; /* default */
- if (*tok == '"' || *tok == '\'')
- {
- log_psk("PSK", s);
-
- /* old PSK format: just a string */
- ugh = process_psk_secret(&s->u.preshared_secret);
- }
- else if (tokeqword("psk"))
+ if (tokeqword("psk"))
{
log_psk("PSK", s);
@@ -989,13 +982,7 @@ static void process_secret_records(int whackfd)
for (;;)
{
- if (tok[0] == '"' || tok[0] == '\'')
- {
- /* found key part */
- process_secret(s, whackfd);
- break;
- }
- else if (tokeq(":"))
+ if (tokeq(":"))
{
/* found key part */
shift(); /* discard explicit separator */
diff --git a/src/pluto/log.c b/src/pluto/log.c
index 0bfc8fa9e..f6fa226d5 100644
--- a/src/pluto/log.c
+++ b/src/pluto/log.c
@@ -868,19 +868,8 @@ DBG_dump(const char *label, const void *p, size_t len)
static void show_loaded_plugins()
{
- char buf[BUF_LEN];
- plugin_t *plugin;
- int len = 0;
- enumerator_t *enumerator;
-
- buf[0] = '\0';
- enumerator = lib->plugins->create_plugin_enumerator(lib->plugins);
- while (len < BUF_LEN && enumerator->enumerate(enumerator, &plugin, NULL))
- {
- len += snprintf(&buf[len], BUF_LEN-len, "%s ", plugin->get_name(plugin));
- }
- enumerator->destroy(enumerator);
- whack_log(RC_COMMENT, "loaded plugins: %s", buf);
+ whack_log(RC_COMMENT, "loaded plugins: %s",
+ lib->plugins->loaded_plugins(lib->plugins));
}
void show_status(bool all, const char *name)
diff --git a/src/pluto/plutomain.c b/src/pluto/plutomain.c
index db5f2d941..dbc857ce2 100644
--- a/src/pluto/plutomain.c
+++ b/src/pluto/plutomain.c
@@ -264,26 +264,6 @@ static const char *pkcs11_init_args = NULL;
/* options read by optionsfrom */
options_t *options;
-/**
- * Log loaded plugins
- */
-static void print_plugins()
-{
- char buf[BUF_LEN];
- plugin_t *plugin;
- int len = 0;
- enumerator_t *enumerator;
-
- buf[0] = '\0';
- enumerator = lib->plugins->create_plugin_enumerator(lib->plugins);
- while (len < BUF_LEN && enumerator->enumerate(enumerator, &plugin, NULL))
- {
- len += snprintf(&buf[len], BUF_LEN-len, "%s ", plugin->get_name(plugin));
- }
- enumerator->destroy(enumerator);
- DBG1(DBG_DMN, "loaded plugins: %s", buf);
-}
-
int main(int argc, char **argv)
{
bool fork_desired = TRUE;
@@ -675,6 +655,9 @@ int main(int argc, char **argv)
close(fd);
}
+ /* for uncritical pseudo random numbers */
+ srand(time(NULL) + getpid());
+
init_constants();
init_log("pluto");
@@ -698,7 +681,8 @@ int main(int argc, char **argv)
{
exit(SS_RC_INITIALIZATION_FAILED);
}
- print_plugins();
+ DBG1(DBG_DMN, "loaded plugins: %s",
+ lib->plugins->loaded_plugins(lib->plugins));
init_builder();
if (!init_secret() || !init_crypto())
@@ -852,6 +836,7 @@ void exit_pluto(int status)
delete_lock();
options->destroy(options);
pluto_deinit();
+ lib->credmgr->flush_cache(lib->credmgr, CERT_ANY);
lib->plugins->unload(lib->plugins);
libhydra_deinit();
library_deinit();
diff --git a/src/scepclient/scepclient.c b/src/scepclient/scepclient.c
index 2d364d654..0b54eeee3 100644
--- a/src/scepclient/scepclient.c
+++ b/src/scepclient/scepclient.c
@@ -276,25 +276,6 @@ usage(const char *message)
}
/**
- * Log loaded plugins
- */
-static void print_plugins()
-{
- char buf[BUF_LEN];
- plugin_t *plugin;
- int len = 0;
- enumerator_t *enumerator;
-
- enumerator = lib->plugins->create_plugin_enumerator(lib->plugins);
- while (len < BUF_LEN && enumerator->enumerate(enumerator, &plugin, NULL))
- {
- len += snprintf(&buf[len], BUF_LEN-len, "%s ", plugin->get_name(plugin));
- }
- enumerator->destroy(enumerator);
- DBG1(DBG_LIB, " loaded plugins: %s", buf);
-}
-
-/**
* @brief main of scepclient
*
* @param argc number of arguments
@@ -704,10 +685,6 @@ int main(int argc, char **argv)
case 'x': /* --maxpolltime */
max_poll_time = atoi(optarg);
- if (max_poll_time < 0)
- {
- usage("invalid maxpolltime specified");
- }
continue;
case 'a': /*--algorithm */
@@ -763,7 +740,8 @@ int main(int argc, char **argv)
{
exit_scepclient("plugin loading failed");
}
- print_plugins();
+ DBG1(DBG_LIB, " loaded plugins: %s",
+ lib->plugins->loaded_plugins(lib->plugins));
if ((filetype_out == 0) && (!request_ca_certificate))
{
diff --git a/src/starter/Android.mk b/src/starter/Android.mk
index 48e4b0b27..a82fe9385 100644
--- a/src/starter/Android.mk
+++ b/src/starter/Android.mk
@@ -30,10 +30,17 @@ endif
LOCAL_MODULE := starter
+LOCAL_MODULE_TAGS := optional
+
LOCAL_ARM_MODE := arm
LOCAL_PRELINK_MODULE := false
+LOCAL_REQUIRED_MODULES := stroke
+ifneq ($(strongswan_BUILD_PLUTO),)
+LOCAL_REQUIRED_MODULES += whack
+endif
+
LOCAL_SHARED_LIBRARIES += libstrongswan libhydra libfreeswan
include $(BUILD_EXECUTABLE)
diff --git a/src/starter/Makefile.am b/src/starter/Makefile.am
index ba97c060f..94ddf5aba 100644
--- a/src/starter/Makefile.am
+++ b/src/starter/Makefile.am
@@ -28,7 +28,7 @@ AM_CFLAGS = \
AM_YFLAGS = -v -d
starter_LDADD = defs.o $(top_builddir)/src/libfreeswan/libfreeswan.a $(top_builddir)/src/libstrongswan/libstrongswan.la $(top_builddir)/src/libhydra/libhydra.la $(SOCKLIB)
-EXTRA_DIST = keywords.txt ipsec.conf
+EXTRA_DIST = keywords.txt ipsec.conf Android.mk
MAINTAINERCLEANFILES = keywords.c
BUILT_SOURCES = parser.h
diff --git a/src/starter/confread.c b/src/starter/confread.c
index ce69fd724..2fb329c85 100644
--- a/src/starter/confread.c
+++ b/src/starter/confread.c
@@ -135,7 +135,7 @@ static void load_setup(starter_config_t *cfg, config_parsed_t *cfgp)
kw_token_t token = kw->entry->token;
- if (token < KW_SETUP_FIRST || token > KW_SETUP_LAST)
+ if ((int)token < KW_SETUP_FIRST || token > KW_SETUP_LAST)
{
plog("# unsupported keyword '%s' in config setup", kw->entry->name);
cfg->err++;
diff --git a/src/starter/confread.h b/src/starter/confread.h
index 19c404e2e..655c97084 100644
--- a/src/starter/confread.h
+++ b/src/starter/confread.h
@@ -198,12 +198,12 @@ struct starter_config {
char *plutostderrlog;
bool uniqueids;
u_int overridemtu;
- u_int crlcheckinterval;
+ time_t crlcheckinterval;
bool cachecrls;
strict_t strictcrlpolicy;
bool nocrsend;
bool nat_traversal;
- u_int keep_alive;
+ time_t keep_alive;
u_int force_keepalive;
char *virtual_private;
char *pkcs11module;
diff --git a/src/starter/invokepluto.c b/src/starter/invokepluto.c
index 11c13abe2..70c0692ea 100644
--- a/src/starter/invokepluto.c
+++ b/src/starter/invokepluto.c
@@ -184,7 +184,7 @@ starter_start_pluto (starter_config_t *cfg, bool no_fork, bool attach_gdb)
static char buf1[15];
arg[argc++] = "--crlcheckinterval";
- snprintf(buf1, sizeof(buf1), "%u", cfg->setup.crlcheckinterval);
+ snprintf(buf1, sizeof(buf1), "%d", (int)cfg->setup.crlcheckinterval);
arg[argc++] = buf1;
}
if (cfg->setup.cachecrls)
@@ -212,7 +212,7 @@ starter_start_pluto (starter_config_t *cfg, bool no_fork, bool attach_gdb)
static char buf2[15];
arg[argc++] = "--keep_alive";
- snprintf(buf2, sizeof(buf2), "%u", cfg->setup.keep_alive);
+ snprintf(buf2, sizeof(buf2), "%d", (int)cfg->setup.keep_alive);
arg[argc++] = buf2;
}
if (cfg->setup.virtual_private)
diff --git a/src/starter/y.output b/src/starter/y.output
new file mode 100644
index 000000000..702cb1f9c
--- /dev/null
+++ b/src/starter/y.output
@@ -0,0 +1,351 @@
+Grammar
+
+ 0 $accept: config_file $end
+
+ 1 config_file: config_file section_or_include
+ 2 | /* empty */
+
+ 3 section_or_include: FILE_VERSION STRING EOL
+
+ 4 $@1: /* empty */
+
+ 5 section_or_include: CONFIG SETUP EOL $@1 kw_section
+
+ 6 $@2: /* empty */
+
+ 7 section_or_include: CONN STRING EOL $@2 kw_section
+
+ 8 $@3: /* empty */
+
+ 9 section_or_include: CA STRING EOL $@3 kw_section
+
+ 10 $@4: /* empty */
+
+ 11 section_or_include: INCLUDE STRING $@4 EOL
+ 12 | EOL
+
+ 13 kw_section: FIRST_SPACES statement_kw EOL kw_section
+ 14 | /* empty */
+
+ 15 statement_kw: STRING EQUAL STRING
+ 16 | STRING EQUAL
+ 17 | /* empty */
+
+
+Terminals, with rules where they appear
+
+$end (0) 0
+error (256)
+EQUAL (258) 15 16
+FIRST_SPACES (259) 13
+EOL (260) 3 5 7 9 11 12 13
+CONFIG (261) 5
+SETUP (262) 5
+CONN (263) 7
+CA (264) 9
+INCLUDE (265) 11
+FILE_VERSION (266) 3
+STRING (267) 3 7 9 11 15 16
+
+
+Nonterminals, with rules where they appear
+
+$accept (13)
+ on left: 0
+config_file (14)
+ on left: 1 2, on right: 0 1
+section_or_include (15)
+ on left: 3 5 7 9 11 12, on right: 1
+$@1 (16)
+ on left: 4, on right: 5
+$@2 (17)
+ on left: 6, on right: 7
+$@3 (18)
+ on left: 8, on right: 9
+$@4 (19)
+ on left: 10, on right: 11
+kw_section (20)
+ on left: 13 14, on right: 5 7 9 13
+statement_kw (21)
+ on left: 15 16 17, on right: 13
+
+
+state 0
+
+ 0 $accept: . config_file $end
+
+ $default reduce using rule 2 (config_file)
+
+ config_file go to state 1
+
+
+state 1
+
+ 0 $accept: config_file . $end
+ 1 config_file: config_file . section_or_include
+
+ $end shift, and go to state 2
+ EOL shift, and go to state 3
+ CONFIG shift, and go to state 4
+ CONN shift, and go to state 5
+ CA shift, and go to state 6
+ INCLUDE shift, and go to state 7
+ FILE_VERSION shift, and go to state 8
+
+ section_or_include go to state 9
+
+
+state 2
+
+ 0 $accept: config_file $end .
+
+ $default accept
+
+
+state 3
+
+ 12 section_or_include: EOL .
+
+ $default reduce using rule 12 (section_or_include)
+
+
+state 4
+
+ 5 section_or_include: CONFIG . SETUP EOL $@1 kw_section
+
+ SETUP shift, and go to state 10
+
+
+state 5
+
+ 7 section_or_include: CONN . STRING EOL $@2 kw_section
+
+ STRING shift, and go to state 11
+
+
+state 6
+
+ 9 section_or_include: CA . STRING EOL $@3 kw_section
+
+ STRING shift, and go to state 12
+
+
+state 7
+
+ 11 section_or_include: INCLUDE . STRING $@4 EOL
+
+ STRING shift, and go to state 13
+
+
+state 8
+
+ 3 section_or_include: FILE_VERSION . STRING EOL
+
+ STRING shift, and go to state 14
+
+
+state 9
+
+ 1 config_file: config_file section_or_include .
+
+ $default reduce using rule 1 (config_file)
+
+
+state 10
+
+ 5 section_or_include: CONFIG SETUP . EOL $@1 kw_section
+
+ EOL shift, and go to state 15
+
+
+state 11
+
+ 7 section_or_include: CONN STRING . EOL $@2 kw_section
+
+ EOL shift, and go to state 16
+
+
+state 12
+
+ 9 section_or_include: CA STRING . EOL $@3 kw_section
+
+ EOL shift, and go to state 17
+
+
+state 13
+
+ 11 section_or_include: INCLUDE STRING . $@4 EOL
+
+ $default reduce using rule 10 ($@4)
+
+ $@4 go to state 18
+
+
+state 14
+
+ 3 section_or_include: FILE_VERSION STRING . EOL
+
+ EOL shift, and go to state 19
+
+
+state 15
+
+ 5 section_or_include: CONFIG SETUP EOL . $@1 kw_section
+
+ $default reduce using rule 4 ($@1)
+
+ $@1 go to state 20
+
+
+state 16
+
+ 7 section_or_include: CONN STRING EOL . $@2 kw_section
+
+ $default reduce using rule 6 ($@2)
+
+ $@2 go to state 21
+
+
+state 17
+
+ 9 section_or_include: CA STRING EOL . $@3 kw_section
+
+ $default reduce using rule 8 ($@3)
+
+ $@3 go to state 22
+
+
+state 18
+
+ 11 section_or_include: INCLUDE STRING $@4 . EOL
+
+ EOL shift, and go to state 23
+
+
+state 19
+
+ 3 section_or_include: FILE_VERSION STRING EOL .
+
+ $default reduce using rule 3 (section_or_include)
+
+
+state 20
+
+ 5 section_or_include: CONFIG SETUP EOL $@1 . kw_section
+
+ FIRST_SPACES shift, and go to state 24
+
+ $default reduce using rule 14 (kw_section)
+
+ kw_section go to state 25
+
+
+state 21
+
+ 7 section_or_include: CONN STRING EOL $@2 . kw_section
+
+ FIRST_SPACES shift, and go to state 24
+
+ $default reduce using rule 14 (kw_section)
+
+ kw_section go to state 26
+
+
+state 22
+
+ 9 section_or_include: CA STRING EOL $@3 . kw_section
+
+ FIRST_SPACES shift, and go to state 24
+
+ $default reduce using rule 14 (kw_section)
+
+ kw_section go to state 27
+
+
+state 23
+
+ 11 section_or_include: INCLUDE STRING $@4 EOL .
+
+ $default reduce using rule 11 (section_or_include)
+
+
+state 24
+
+ 13 kw_section: FIRST_SPACES . statement_kw EOL kw_section
+
+ STRING shift, and go to state 28
+
+ $default reduce using rule 17 (statement_kw)
+
+ statement_kw go to state 29
+
+
+state 25
+
+ 5 section_or_include: CONFIG SETUP EOL $@1 kw_section .
+
+ $default reduce using rule 5 (section_or_include)
+
+
+state 26
+
+ 7 section_or_include: CONN STRING EOL $@2 kw_section .
+
+ $default reduce using rule 7 (section_or_include)
+
+
+state 27
+
+ 9 section_or_include: CA STRING EOL $@3 kw_section .
+
+ $default reduce using rule 9 (section_or_include)
+
+
+state 28
+
+ 15 statement_kw: STRING . EQUAL STRING
+ 16 | STRING . EQUAL
+
+ EQUAL shift, and go to state 30
+
+
+state 29
+
+ 13 kw_section: FIRST_SPACES statement_kw . EOL kw_section
+
+ EOL shift, and go to state 31
+
+
+state 30
+
+ 15 statement_kw: STRING EQUAL . STRING
+ 16 | STRING EQUAL .
+
+ STRING shift, and go to state 32
+
+ $default reduce using rule 16 (statement_kw)
+
+
+state 31
+
+ 13 kw_section: FIRST_SPACES statement_kw EOL . kw_section
+
+ FIRST_SPACES shift, and go to state 24
+
+ $default reduce using rule 14 (kw_section)
+
+ kw_section go to state 33
+
+
+state 32
+
+ 15 statement_kw: STRING EQUAL STRING .
+
+ $default reduce using rule 15 (statement_kw)
+
+
+state 33
+
+ 13 kw_section: FIRST_SPACES statement_kw EOL kw_section .
+
+ $default reduce using rule 13 (kw_section)
diff --git a/src/stroke/Android.mk b/src/stroke/Android.mk
index 833130e25..69b3e54ca 100644
--- a/src/stroke/Android.mk
+++ b/src/stroke/Android.mk
@@ -15,6 +15,8 @@ LOCAL_CFLAGS := $(strongswan_CFLAGS)
LOCAL_MODULE := stroke
+LOCAL_MODULE_TAGS := optional
+
LOCAL_ARM_MODE := arm
LOCAL_PRELINK_MODULE := false
diff --git a/src/stroke/Makefile.am b/src/stroke/Makefile.am
index 6eee8cd6c..f93680b64 100644
--- a/src/stroke/Makefile.am
+++ b/src/stroke/Makefile.am
@@ -5,7 +5,7 @@ stroke.c stroke_msg.h stroke_keywords.c stroke_keywords.h
stroke_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la $(SOCKLIB)
INCLUDES = -I$(top_srcdir)/src/libstrongswan
-EXTRA_DIST = stroke_keywords.txt
+EXTRA_DIST = stroke_keywords.txt Android.mk
BUILT_SOURCES = stroke_keywords.c
MAINTAINERCLEANFILES = stroke_keywords.c
AM_CFLAGS = -DIPSEC_PIDDIR=\"${piddir}\"
diff --git a/src/stroke/stroke.c b/src/stroke/stroke.c
index e70245362..6aadd3ec9 100644
--- a/src/stroke/stroke.c
+++ b/src/stroke/stroke.c
@@ -392,7 +392,7 @@ static void exit_usage(char *error)
printf(" where: START and optional END define the clients source IP\n");
printf(" Set loglevel for a logging type:\n");
printf(" stroke loglevel TYPE LEVEL\n");
- printf(" where: TYPE is any|dmn|mgr|ike|chd|job|cfg|knl|net|enc|tnc|imc|imv|pts|tls|lib\n");
+ printf(" where: TYPE is any|dmn|mgr|ike|chd|job|cfg|knl|net|asn|enc|tnc|imc|imv|pts|tls|lib\n");
printf(" LEVEL is -1|0|1|2|3|4\n");
printf(" Show connection status:\n");
printf(" stroke status\n");
diff --git a/src/whack/Android.mk b/src/whack/Android.mk
index 08d96a071..bf5ec0e98 100644
--- a/src/whack/Android.mk
+++ b/src/whack/Android.mk
@@ -18,6 +18,8 @@ LOCAL_CFLAGS := $(strongswan_CFLAGS)
LOCAL_MODULE := whack
+LOCAL_MODULE_TAGS := optional
+
LOCAL_ARM_MODE := arm
LOCAL_PRELINK_MODULE := false
diff --git a/src/whack/Makefile.am b/src/whack/Makefile.am
index fa4c9959c..23374475e 100644
--- a/src/whack/Makefile.am
+++ b/src/whack/Makefile.am
@@ -15,3 +15,4 @@ $(top_builddir)/src/libfreeswan/libfreeswan.a
AM_CFLAGS = -DDEBUG -DIPSEC_PIDDIR=\"${piddir}\"
+EXTRA_DIST = Android.mk