From 552cc11b1f017ce4962fca741f567d098f768574 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 13 Mar 2008 14:14:44 +0000 Subject: merged the modularization branch (credentials) back to trunk --- src/Makefile.am | 4 + src/charon/Makefile.am | 108 +- src/charon/bus/bus.c | 61 +- src/charon/bus/bus.h | 66 +- src/charon/bus/listeners/file_logger.c | 9 +- src/charon/bus/listeners/file_logger.h | 35 +- src/charon/bus/listeners/sys_logger.c | 9 +- src/charon/bus/listeners/sys_logger.h | 35 +- src/charon/config/backend.h | 75 + src/charon/config/backend_manager.c | 351 +- src/charon/config/backend_manager.h | 75 +- src/charon/config/backends/backend.h | 105 - src/charon/config/backends/local_backend.c | 322 -- src/charon/config/backends/local_backend.h | 60 - src/charon/config/backends/sqlite_backend.c | 309 -- src/charon/config/backends/sqlite_backend.h | 58 - src/charon/config/backends/writeable_backend.h | 64 - src/charon/config/child_cfg.c | 10 +- src/charon/config/child_cfg.h | 74 +- .../config/credentials/local_credential_store.c | 1620 ---------- .../config/credentials/local_credential_store.h | 63 - src/charon/config/ike_cfg.c | 9 +- src/charon/config/ike_cfg.h | 59 +- src/charon/config/peer_cfg.c | 113 +- src/charon/config/peer_cfg.h | 175 +- src/charon/config/proposal.c | 9 +- src/charon/config/proposal.h | 114 +- src/charon/config/traffic_selector.c | 29 +- src/charon/config/traffic_selector.h | 101 +- src/charon/control/controller.c | 574 ++++ src/charon/control/controller.h | 174 + src/charon/control/interface_manager.c | 665 ---- src/charon/control/interface_manager.h | 206 -- src/charon/control/interfaces/dbus_interface.c | 427 --- src/charon/control/interfaces/dbus_interface.h | 57 - src/charon/control/interfaces/interface.h | 59 - src/charon/control/interfaces/stroke_interface.c | 1818 ----------- src/charon/control/interfaces/stroke_interface.h | 60 - src/charon/control/interfaces/xml_interface.c | 754 ----- src/charon/control/interfaces/xml_interface.h | 57 - src/charon/control/interfaces/xml_interface.xml | 400 --- src/charon/credentials/auth_info.c | 356 +++ src/charon/credentials/auth_info.h | 158 + src/charon/credentials/credential_manager.c | 1385 ++++++++ src/charon/credentials/credential_manager.h | 187 ++ src/charon/credentials/credential_set.h | 93 + src/charon/daemon.c | 97 +- src/charon/daemon.h | 418 +-- src/charon/encoding/generator.c | 9 +- src/charon/encoding/generator.h | 45 +- src/charon/encoding/message.c | 511 ++- src/charon/encoding/message.h | 129 +- src/charon/encoding/parser.c | 29 +- src/charon/encoding/parser.h | 52 +- src/charon/encoding/payloads/auth_payload.c | 9 +- src/charon/encoding/payloads/auth_payload.h | 51 +- src/charon/encoding/payloads/cert_payload.c | 179 +- src/charon/encoding/payloads/cert_payload.h | 134 +- src/charon/encoding/payloads/certreq_payload.c | 201 +- src/charon/encoding/payloads/certreq_payload.h | 104 +- .../encoding/payloads/configuration_attribute.c | 9 +- .../encoding/payloads/configuration_attribute.h | 54 +- src/charon/encoding/payloads/cp_payload.c | 9 +- src/charon/encoding/payloads/cp_payload.h | 49 +- src/charon/encoding/payloads/delete_payload.c | 9 +- src/charon/encoding/payloads/delete_payload.h | 44 +- src/charon/encoding/payloads/eap_payload.c | 9 +- src/charon/encoding/payloads/eap_payload.h | 60 +- src/charon/encoding/payloads/encodings.c | 9 +- src/charon/encoding/payloads/encodings.h | 33 +- src/charon/encoding/payloads/encryption_payload.c | 9 +- src/charon/encoding/payloads/encryption_payload.h | 70 +- src/charon/encoding/payloads/endpoint_notify.c | 9 +- src/charon/encoding/payloads/endpoint_notify.h | 77 +- src/charon/encoding/payloads/id_payload.c | 9 +- src/charon/encoding/payloads/id_payload.h | 58 +- src/charon/encoding/payloads/ike_header.c | 9 +- src/charon/encoding/payloads/ike_header.h | 95 +- src/charon/encoding/payloads/ke_payload.c | 9 +- src/charon/encoding/payloads/ke_payload.h | 61 +- src/charon/encoding/payloads/nonce_payload.c | 9 +- src/charon/encoding/payloads/nonce_payload.h | 43 +- src/charon/encoding/payloads/notify_payload.c | 9 +- src/charon/encoding/payloads/notify_payload.h | 80 +- src/charon/encoding/payloads/payload.c | 10 +- src/charon/encoding/payloads/payload.h | 67 +- .../encoding/payloads/proposal_substructure.c | 9 +- .../encoding/payloads/proposal_substructure.h | 113 +- src/charon/encoding/payloads/sa_payload.c | 9 +- src/charon/encoding/payloads/sa_payload.h | 76 +- .../payloads/traffic_selector_substructure.c | 9 +- .../payloads/traffic_selector_substructure.h | 83 +- src/charon/encoding/payloads/transform_attribute.c | 9 +- src/charon/encoding/payloads/transform_attribute.h | 64 +- .../encoding/payloads/transform_substructure.c | 9 +- .../encoding/payloads/transform_substructure.h | 100 +- src/charon/encoding/payloads/ts_payload.c | 9 +- src/charon/encoding/payloads/ts_payload.h | 78 +- src/charon/encoding/payloads/unknown_payload.c | 9 +- src/charon/encoding/payloads/unknown_payload.h | 40 +- src/charon/encoding/payloads/vendor_id_payload.c | 9 +- src/charon/encoding/payloads/vendor_id_payload.h | 43 +- src/charon/kernel/kernel_interface.c | 9 +- src/charon/kernel/kernel_interface.h | 116 +- src/charon/network/packet.c | 11 +- src/charon/network/packet.h | 55 +- src/charon/network/receiver.c | 31 +- src/charon/network/receiver.h | 33 +- src/charon/network/sender.c | 9 +- src/charon/network/sender.h | 34 +- src/charon/network/socket-raw.c | 9 +- src/charon/network/socket.c | 9 +- src/charon/network/socket.h | 66 +- src/charon/plugins/dbus/Makefile.am | 11 + src/charon/plugins/dbus/dbus.c | 422 +++ src/charon/plugins/dbus/dbus.h | 50 + src/charon/plugins/eap_aka/Makefile.am | 11 + src/charon/plugins/eap_aka/eap_aka.c | 1557 +++++++++ src/charon/plugins/eap_aka/eap_aka.h | 83 + src/charon/plugins/eap_aka/eap_aka_plugin.c | 52 + src/charon/plugins/eap_aka/eap_aka_plugin.h | 49 + src/charon/plugins/eap_identity/Makefile.am | 10 + src/charon/plugins/eap_identity/eap_identity.c | 125 + src/charon/plugins/eap_identity/eap_identity.h | 51 + .../plugins/eap_identity/eap_identity_plugin.c | 48 + .../plugins/eap_identity/eap_identity_plugin.h | 49 + src/charon/plugins/eap_md5/Makefile.am | 10 + src/charon/plugins/eap_md5/eap_md5.c | 300 ++ src/charon/plugins/eap_md5/eap_md5.h | 59 + src/charon/plugins/eap_md5/eap_md5_plugin.c | 52 + src/charon/plugins/eap_md5/eap_md5_plugin.h | 49 + src/charon/plugins/eap_sim/Makefile.am | 13 + src/charon/plugins/eap_sim/eap_sim.c | 1150 +++++++ src/charon/plugins/eap_sim/eap_sim.h | 111 + src/charon/plugins/eap_sim/eap_sim_file.c | 283 ++ src/charon/plugins/eap_sim/eap_sim_plugin.c | 52 + src/charon/plugins/eap_sim/eap_sim_plugin.h | 49 + src/charon/plugins/med_db/Makefile.am | 10 + src/charon/plugins/med_db/med_db_creds.c | 211 ++ src/charon/plugins/med_db/med_db_creds.h | 55 + src/charon/plugins/med_db/med_db_plugin.c | 88 + src/charon/plugins/med_db/med_db_plugin.h | 49 + src/charon/plugins/sql/Makefile.am | 10 + src/charon/plugins/sql/config.sql | 73 + src/charon/plugins/sql/cred.sql | 24 + src/charon/plugins/sql/sql_config.c | 538 ++++ src/charon/plugins/sql/sql_config.h | 55 + src/charon/plugins/sql/sql_plugin.c | 89 + src/charon/plugins/sql/sql_plugin.h | 49 + src/charon/plugins/sql/test.sql | 47 + src/charon/plugins/stroke/Makefile.am | 10 + src/charon/plugins/stroke/stroke.c | 3335 ++++++++++++++++++++ src/charon/plugins/stroke/stroke.h | 52 + src/charon/plugins/unit_tester/Makefile.am | 17 + src/charon/plugins/unit_tester/tests.h | 33 + .../plugins/unit_tester/tests/test_auth_info.c | 142 + src/charon/plugins/unit_tester/tests/test_curl.c | 44 + .../plugins/unit_tester/tests/test_enumerator.c | 214 ++ .../plugins/unit_tester/tests/test_fips_prf.c | 61 + src/charon/plugins/unit_tester/tests/test_mutex.c | 100 + src/charon/plugins/unit_tester/tests/test_mysql.c | 90 + src/charon/plugins/unit_tester/tests/test_sqlite.c | 94 + src/charon/plugins/unit_tester/unit_tester.c | 118 + src/charon/plugins/unit_tester/unit_tester.h | 51 + src/charon/plugins/xml/Makefile.am | 10 + src/charon/plugins/xml/schema.xml | 400 +++ src/charon/plugins/xml/xml.c | 749 +++++ src/charon/plugins/xml/xml.h | 52 + src/charon/processing/jobs/acquire_job.c | 9 +- src/charon/processing/jobs/acquire_job.h | 27 +- src/charon/processing/jobs/callback_job.c | 9 +- src/charon/processing/jobs/callback_job.h | 44 +- src/charon/processing/jobs/delete_child_sa_job.c | 9 +- src/charon/processing/jobs/delete_child_sa_job.h | 27 +- src/charon/processing/jobs/delete_ike_sa_job.c | 9 +- src/charon/processing/jobs/delete_ike_sa_job.h | 27 +- .../processing/jobs/initiate_mediation_job.c | 10 +- .../processing/jobs/initiate_mediation_job.h | 30 +- src/charon/processing/jobs/job.h | 33 +- src/charon/processing/jobs/mediation_job.c | 10 +- src/charon/processing/jobs/mediation_job.h | 30 +- src/charon/processing/jobs/process_message_job.c | 10 +- src/charon/processing/jobs/process_message_job.h | 27 +- src/charon/processing/jobs/rekey_child_sa_job.c | 9 +- src/charon/processing/jobs/rekey_child_sa_job.h | 32 +- src/charon/processing/jobs/rekey_ike_sa_job.c | 12 +- src/charon/processing/jobs/rekey_ike_sa_job.h | 27 +- src/charon/processing/jobs/retransmit_job.c | 9 +- src/charon/processing/jobs/retransmit_job.h | 27 +- src/charon/processing/jobs/roam_job.c | 10 +- src/charon/processing/jobs/roam_job.h | 27 +- src/charon/processing/jobs/send_dpd_job.c | 10 +- src/charon/processing/jobs/send_dpd_job.h | 26 +- src/charon/processing/jobs/send_keepalive_job.c | 10 +- src/charon/processing/jobs/send_keepalive_job.h | 26 +- src/charon/processing/processor.c | 11 +- src/charon/processing/processor.h | 51 +- src/charon/processing/scheduler.c | 9 +- src/charon/processing/scheduler.h | 38 +- src/charon/sa/authenticators/authenticator.c | 9 +- src/charon/sa/authenticators/authenticator.h | 41 +- src/charon/sa/authenticators/eap/eap_aka.c | 1440 --------- src/charon/sa/authenticators/eap/eap_aka.h | 141 - src/charon/sa/authenticators/eap/eap_identity.c | 135 - src/charon/sa/authenticators/eap/eap_identity.h | 59 - src/charon/sa/authenticators/eap/eap_manager.c | 172 + src/charon/sa/authenticators/eap/eap_manager.h | 84 + src/charon/sa/authenticators/eap/eap_md5.c | 282 -- src/charon/sa/authenticators/eap/eap_md5.h | 59 - src/charon/sa/authenticators/eap/eap_method.c | 189 +- src/charon/sa/authenticators/eap/eap_method.h | 107 +- src/charon/sa/authenticators/eap/eap_sim.c | 1125 ------- src/charon/sa/authenticators/eap/eap_sim.h | 114 - .../sa/authenticators/eap/sim/eap_sim_file.c | 288 -- src/charon/sa/authenticators/eap_authenticator.c | 30 +- src/charon/sa/authenticators/eap_authenticator.h | 36 +- src/charon/sa/authenticators/psk_authenticator.c | 85 +- src/charon/sa/authenticators/psk_authenticator.h | 28 +- src/charon/sa/authenticators/rsa_authenticator.c | 90 +- src/charon/sa/authenticators/rsa_authenticator.h | 28 +- src/charon/sa/child_sa.c | 9 +- src/charon/sa/child_sa.h | 84 +- src/charon/sa/connect_manager.c | 18 +- src/charon/sa/connect_manager.h | 49 +- src/charon/sa/ike_sa.c | 122 +- src/charon/sa/ike_sa.h | 303 +- src/charon/sa/ike_sa_id.c | 10 +- src/charon/sa/ike_sa_id.h | 61 +- src/charon/sa/ike_sa_manager.c | 24 +- src/charon/sa/ike_sa_manager.h | 63 +- src/charon/sa/mediation_manager.c | 9 +- src/charon/sa/mediation_manager.h | 43 +- src/charon/sa/task_manager.c | 19 +- src/charon/sa/task_manager.h | 63 +- src/charon/sa/tasks/child_create.c | 13 +- src/charon/sa/tasks/child_create.h | 34 +- src/charon/sa/tasks/child_delete.c | 9 +- src/charon/sa/tasks/child_delete.h | 28 +- src/charon/sa/tasks/child_rekey.c | 9 +- src/charon/sa/tasks/child_rekey.h | 28 +- src/charon/sa/tasks/ike_auth.c | 43 +- src/charon/sa/tasks/ike_auth.h | 25 +- src/charon/sa/tasks/ike_auth_lifetime.c | 9 +- src/charon/sa/tasks/ike_auth_lifetime.h | 26 +- src/charon/sa/tasks/ike_cert.c | 366 --- src/charon/sa/tasks/ike_cert.h | 61 - src/charon/sa/tasks/ike_cert_post.c | 210 ++ src/charon/sa/tasks/ike_cert_post.h | 55 + src/charon/sa/tasks/ike_cert_pre.c | 346 ++ src/charon/sa/tasks/ike_cert_pre.h | 55 + src/charon/sa/tasks/ike_config.c | 9 +- src/charon/sa/tasks/ike_config.h | 25 +- src/charon/sa/tasks/ike_delete.c | 9 +- src/charon/sa/tasks/ike_delete.h | 25 +- src/charon/sa/tasks/ike_dpd.c | 9 +- src/charon/sa/tasks/ike_dpd.h | 25 +- src/charon/sa/tasks/ike_init.c | 15 +- src/charon/sa/tasks/ike_init.h | 28 +- src/charon/sa/tasks/ike_mobike.c | 9 +- src/charon/sa/tasks/ike_mobike.h | 35 +- src/charon/sa/tasks/ike_natd.c | 25 +- src/charon/sa/tasks/ike_natd.h | 25 +- src/charon/sa/tasks/ike_p2p.c | 11 +- src/charon/sa/tasks/ike_p2p.h | 38 +- src/charon/sa/tasks/ike_reauth.c | 9 +- src/charon/sa/tasks/ike_reauth.h | 26 +- src/charon/sa/tasks/ike_rekey.c | 9 +- src/charon/sa/tasks/ike_rekey.h | 28 +- src/charon/sa/tasks/task.c | 12 +- src/charon/sa/tasks/task.h | 50 +- src/libfast/Makefile.am | 8 + src/libfast/context.h | 44 + src/libfast/controller.h | 79 + src/libfast/dispatcher.c | 383 +++ src/libfast/dispatcher.h | 139 + src/libfast/filter.h | 60 + src/libfast/request.c | 447 +++ src/libfast/request.h | 186 ++ src/libfast/session.c | 211 ++ src/libfast/session.h | 80 + src/libstrongswan/Makefile.am | 115 +- src/libstrongswan/asn1/asn1.c | 24 +- src/libstrongswan/asn1/asn1.h | 27 +- src/libstrongswan/asn1/pem.c | 20 +- src/libstrongswan/asn1/pem.h | 6 +- src/libstrongswan/asn1/ttodata.c | 18 +- src/libstrongswan/asn1/ttodata.h | 2 +- src/libstrongswan/chunk.c | 97 +- src/libstrongswan/chunk.h | 31 +- src/libstrongswan/credential_store.h | 330 -- src/libstrongswan/credentials/builder.c | 31 + src/libstrongswan/credentials/builder.h | 101 + .../credentials/certificates/certificate.c | 40 + .../credentials/certificates/certificate.h | 190 ++ src/libstrongswan/credentials/certificates/crl.c | 32 + src/libstrongswan/credentials/certificates/crl.h | 93 + .../credentials/certificates/ocsp_request.c | 19 + .../credentials/certificates/ocsp_request.h | 41 + .../credentials/certificates/ocsp_response.c | 29 + .../credentials/certificates/ocsp_response.h | 84 + src/libstrongswan/credentials/certificates/x509.c | 25 + src/libstrongswan/credentials/certificates/x509.h | 114 + src/libstrongswan/credentials/credential_factory.c | 263 ++ src/libstrongswan/credentials/credential_factory.h | 100 + src/libstrongswan/credentials/keys/private_key.c | 19 + src/libstrongswan/credentials/keys/private_key.h | 143 + src/libstrongswan/credentials/keys/public_key.c | 32 + src/libstrongswan/credentials/keys/public_key.h | 163 + src/libstrongswan/credentials/keys/shared_key.c | 27 + src/libstrongswan/credentials/keys/shared_key.h | 86 + src/libstrongswan/crypto/ac.c | 636 ---- src/libstrongswan/crypto/ac.h | 110 - src/libstrongswan/crypto/ca.c | 813 ----- src/libstrongswan/crypto/ca.h | 243 -- src/libstrongswan/crypto/certinfo.c | 257 -- src/libstrongswan/crypto/certinfo.h | 203 -- src/libstrongswan/crypto/crl.c | 536 ---- src/libstrongswan/crypto/crl.h | 158 - .../crypto/crypters/aes_cbc_crypter.c | 1620 ---------- .../crypto/crypters/aes_cbc_crypter.h | 61 - src/libstrongswan/crypto/crypters/crypter.c | 34 +- src/libstrongswan/crypto/crypters/crypter.h | 102 +- src/libstrongswan/crypto/crypters/des_crypter.c | 1536 --------- src/libstrongswan/crypto/crypters/des_crypter.h | 58 - src/libstrongswan/crypto/crypto_factory.c | 483 +++ src/libstrongswan/crypto/crypto_factory.h | 206 ++ src/libstrongswan/crypto/diffie_hellman.c | 561 +--- src/libstrongswan/crypto/diffie_hellman.h | 68 +- src/libstrongswan/crypto/hashers/hasher.c | 65 +- src/libstrongswan/crypto/hashers/hasher.h | 142 +- src/libstrongswan/crypto/hashers/md5_hasher.c | 405 --- src/libstrongswan/crypto/hashers/md5_hasher.h | 60 - src/libstrongswan/crypto/hashers/sha1_hasher.c | 280 -- src/libstrongswan/crypto/hashers/sha1_hasher.h | 60 - src/libstrongswan/crypto/hashers/sha2_hasher.c | 672 ---- src/libstrongswan/crypto/hashers/sha2_hasher.h | 62 - src/libstrongswan/crypto/hmac.c | 215 -- src/libstrongswan/crypto/hmac.h | 117 - src/libstrongswan/crypto/ietf_attr_list.c | 405 --- src/libstrongswan/crypto/ietf_attr_list.h | 89 - src/libstrongswan/crypto/ocsp.c | 934 ------ src/libstrongswan/crypto/ocsp.h | 34 +- src/libstrongswan/crypto/pkcs7.c | 34 +- src/libstrongswan/crypto/pkcs7.h | 93 +- src/libstrongswan/crypto/pkcs9.c | 10 +- src/libstrongswan/crypto/pkcs9.h | 63 +- src/libstrongswan/crypto/prf_plus.c | 9 +- src/libstrongswan/crypto/prf_plus.h | 46 +- src/libstrongswan/crypto/prfs/fips_prf.c | 258 -- src/libstrongswan/crypto/prfs/fips_prf.h | 80 - src/libstrongswan/crypto/prfs/hmac_prf.c | 118 - src/libstrongswan/crypto/prfs/hmac_prf.h | 65 - src/libstrongswan/crypto/prfs/prf.c | 40 +- src/libstrongswan/crypto/prfs/prf.h | 75 +- src/libstrongswan/crypto/rsa/rsa_private_key.c | 722 ----- src/libstrongswan/crypto/rsa/rsa_private_key.h | 163 - src/libstrongswan/crypto/rsa/rsa_public_key.c | 516 --- src/libstrongswan/crypto/rsa/rsa_public_key.h | 173 - src/libstrongswan/crypto/signers/hmac_signer.c | 185 -- src/libstrongswan/crypto/signers/hmac_signer.h | 68 - src/libstrongswan/crypto/signers/signer.c | 34 +- src/libstrongswan/crypto/signers/signer.h | 84 +- src/libstrongswan/crypto/x509.c | 1562 --------- src/libstrongswan/crypto/x509.h | 406 --- src/libstrongswan/database/database.h | 103 + src/libstrongswan/database/database_factory.c | 119 + src/libstrongswan/database/database_factory.h | 73 + src/libstrongswan/debug.c | 9 +- src/libstrongswan/debug.h | 16 +- src/libstrongswan/enum.c | 33 +- src/libstrongswan/enum.h | 55 +- src/libstrongswan/fetcher/fetcher.h | 105 + src/libstrongswan/fetcher/fetcher_manager.c | 206 ++ src/libstrongswan/fetcher/fetcher_manager.h | 74 + src/libstrongswan/fips/fips.c | 9 +- src/libstrongswan/fips/fips.h | 33 +- src/libstrongswan/fips/fips_canister_end.c | 9 +- src/libstrongswan/fips/fips_canister_start.c | 9 +- src/libstrongswan/fips/fips_signer.c | 11 +- src/libstrongswan/library.c | 220 +- src/libstrongswan/library.h | 324 +- src/libstrongswan/plugins/aes/Makefile.am | 10 + src/libstrongswan/plugins/aes/aes_crypter.c | 1621 ++++++++++ src/libstrongswan/plugins/aes/aes_crypter.h | 50 + src/libstrongswan/plugins/aes/aes_plugin.c | 60 + src/libstrongswan/plugins/aes/aes_plugin.h | 47 + src/libstrongswan/plugins/curl/Makefile.am | 11 + src/libstrongswan/plugins/curl/curl_fetcher.c | 176 ++ src/libstrongswan/plugins/curl/curl_fetcher.h | 47 + src/libstrongswan/plugins/curl/curl_plugin.c | 79 + src/libstrongswan/plugins/curl/curl_plugin.h | 47 + src/libstrongswan/plugins/des/Makefile.am | 10 + src/libstrongswan/plugins/des/des_crypter.c | 1531 +++++++++ src/libstrongswan/plugins/des/des_crypter.h | 49 + src/libstrongswan/plugins/des/des_plugin.c | 62 + src/libstrongswan/plugins/des/des_plugin.h | 47 + src/libstrongswan/plugins/fips_prf/Makefile.am | 10 + src/libstrongswan/plugins/fips_prf/fips_prf.c | 261 ++ src/libstrongswan/plugins/fips_prf/fips_prf.h | 59 + .../plugins/fips_prf/fips_prf_plugin.c | 59 + .../plugins/fips_prf/fips_prf_plugin.h | 47 + src/libstrongswan/plugins/gmp/Makefile.am | 14 + src/libstrongswan/plugins/gmp/gmp_diffie_hellman.c | 569 ++++ src/libstrongswan/plugins/gmp/gmp_diffie_hellman.h | 49 + src/libstrongswan/plugins/gmp/gmp_plugin.c | 85 + src/libstrongswan/plugins/gmp/gmp_plugin.h | 47 + .../plugins/gmp/gmp_rsa_private_key.c | 844 +++++ .../plugins/gmp/gmp_rsa_private_key.h | 48 + src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c | 574 ++++ src/libstrongswan/plugins/gmp/gmp_rsa_public_key.h | 48 + src/libstrongswan/plugins/hmac/Makefile.am | 11 + src/libstrongswan/plugins/hmac/hmac.c | 214 ++ src/libstrongswan/plugins/hmac/hmac.h | 93 + src/libstrongswan/plugins/hmac/hmac_plugin.c | 84 + src/libstrongswan/plugins/hmac/hmac_plugin.h | 47 + src/libstrongswan/plugins/hmac/hmac_prf.c | 137 + src/libstrongswan/plugins/hmac/hmac_prf.h | 51 + src/libstrongswan/plugins/hmac/hmac_signer.c | 199 ++ src/libstrongswan/plugins/hmac/hmac_signer.h | 55 + src/libstrongswan/plugins/ldap/Makefile.am | 11 + src/libstrongswan/plugins/ldap/ldap_fetcher.c | 213 ++ src/libstrongswan/plugins/ldap/ldap_fetcher.h | 42 + src/libstrongswan/plugins/ldap/ldap_plugin.c | 62 + src/libstrongswan/plugins/ldap/ldap_plugin.h | 47 + src/libstrongswan/plugins/md5/Makefile.am | 10 + src/libstrongswan/plugins/md5/md5_hasher.c | 392 +++ src/libstrongswan/plugins/md5/md5_hasher.h | 48 + src/libstrongswan/plugins/md5/md5_plugin.c | 60 + src/libstrongswan/plugins/md5/md5_plugin.h | 47 + src/libstrongswan/plugins/mysql/Makefile.am | 12 + src/libstrongswan/plugins/mysql/mysql_database.c | 686 ++++ src/libstrongswan/plugins/mysql/mysql_database.h | 58 + src/libstrongswan/plugins/mysql/mysql_plugin.c | 69 + src/libstrongswan/plugins/mysql/mysql_plugin.h | 47 + src/libstrongswan/plugins/plugin.h | 49 + src/libstrongswan/plugins/plugin_loader.c | 129 + src/libstrongswan/plugins/plugin_loader.h | 53 + src/libstrongswan/plugins/sha1/Makefile.am | 10 + src/libstrongswan/plugins/sha1/sha1_hasher.c | 294 ++ src/libstrongswan/plugins/sha1/sha1_hasher.h | 50 + src/libstrongswan/plugins/sha1/sha1_plugin.c | 62 + src/libstrongswan/plugins/sha1/sha1_plugin.h | 47 + src/libstrongswan/plugins/sha2/Makefile.am | 10 + src/libstrongswan/plugins/sha2/sha2_hasher.c | 632 ++++ src/libstrongswan/plugins/sha2/sha2_hasher.h | 50 + src/libstrongswan/plugins/sha2/sha2_plugin.c | 64 + src/libstrongswan/plugins/sha2/sha2_plugin.h | 47 + src/libstrongswan/plugins/sqlite/Makefile.am | 12 + src/libstrongswan/plugins/sqlite/sqlite_database.c | 296 ++ src/libstrongswan/plugins/sqlite/sqlite_database.h | 46 + src/libstrongswan/plugins/sqlite/sqlite_plugin.c | 60 + src/libstrongswan/plugins/sqlite/sqlite_plugin.h | 47 + src/libstrongswan/plugins/x509/Makefile.am | 13 + src/libstrongswan/plugins/x509/x509_cert.c | 1273 ++++++++ src/libstrongswan/plugins/x509/x509_cert.h | 47 + src/libstrongswan/plugins/x509/x509_crl.c | 717 +++++ src/libstrongswan/plugins/x509/x509_crl.h | 48 + src/libstrongswan/plugins/x509/x509_ocsp_request.c | 603 ++++ src/libstrongswan/plugins/x509/x509_ocsp_request.h | 54 + .../plugins/x509/x509_ocsp_response.c | 928 ++++++ .../plugins/x509/x509_ocsp_response.h | 47 + src/libstrongswan/plugins/x509/x509_plugin.c | 75 + src/libstrongswan/plugins/x509/x509_plugin.h | 47 + src/libstrongswan/printf_hook.c | 132 +- src/libstrongswan/printf_hook.h | 86 +- src/libstrongswan/settings.c | 408 +++ src/libstrongswan/settings.h | 96 + src/libstrongswan/utils.c | 327 ++ src/libstrongswan/utils.h | 265 ++ src/libstrongswan/utils/enumerator.c | 364 ++- src/libstrongswan/utils/enumerator.h | 118 +- src/libstrongswan/utils/fetcher.c | 424 --- src/libstrongswan/utils/fetcher.h | 95 - src/libstrongswan/utils/host.c | 32 +- src/libstrongswan/utils/host.h | 140 +- src/libstrongswan/utils/identification.c | 292 +- src/libstrongswan/utils/identification.h | 137 +- src/libstrongswan/utils/iterator.h | 95 +- src/libstrongswan/utils/leak_detective.c | 220 +- src/libstrongswan/utils/leak_detective.h | 42 +- src/libstrongswan/utils/lexparser.c | 11 +- src/libstrongswan/utils/lexparser.h | 35 +- src/libstrongswan/utils/linked_list.c | 209 +- src/libstrongswan/utils/linked_list.h | 183 +- src/libstrongswan/utils/mutex.c | 267 ++ src/libstrongswan/utils/mutex.h | 123 + src/libstrongswan/utils/optionsfrom.c | 10 +- src/libstrongswan/utils/optionsfrom.h | 38 +- src/libstrongswan/utils/randomizer.c | 53 +- src/libstrongswan/utils/randomizer.h | 79 +- src/manager/Makefile.am | 17 +- src/manager/controller/auth_controller.c | 9 +- src/manager/controller/auth_controller.h | 20 +- src/manager/controller/config_controller.c | 9 +- src/manager/controller/config_controller.h | 20 +- src/manager/controller/control_controller.c | 9 +- src/manager/controller/control_controller.h | 18 +- src/manager/controller/gateway_controller.c | 9 +- src/manager/controller/gateway_controller.h | 20 +- src/manager/controller/ikesa_controller.c | 9 +- src/manager/controller/ikesa_controller.h | 20 +- src/manager/database.c | 183 -- src/manager/database.h | 69 - src/manager/gateway.c | 11 +- src/manager/gateway.h | 34 +- src/manager/lib/context.h | 47 - src/manager/lib/controller.h | 84 - src/manager/lib/dispatcher.c | 401 --- src/manager/lib/dispatcher.h | 95 - src/manager/lib/request.c | 341 -- src/manager/lib/request.h | 135 - src/manager/lib/session.c | 175 - src/manager/lib/session.h | 73 - src/manager/lib/xml.c | 169 - src/manager/lib/xml.h | 63 - src/manager/main.c | 31 +- src/manager/manager.c | 23 +- src/manager/manager.h | 39 +- src/manager/storage.c | 130 + src/manager/storage.h | 69 + src/manager/xml.c | 164 + src/manager/xml.h | 63 + src/pluto/Makefile.am | 6 +- src/scepclient/Makefile.am | 5 - src/starter/args.c | 1 - src/starter/confread.h | 1 - src/starter/invokecharon.c | 10 - src/starter/keywords.h | 1 - src/starter/keywords.txt | 1 - src/starter/starter.c | 2 +- src/starter/starterstroke.c | 5 +- src/starter/starterstroke.h | 2 +- src/stroke/Makefile.am | 3 +- src/stroke/stroke.c | 2 +- src/stroke/stroke.h | 249 -- src/stroke/stroke_msg.h | 260 ++ 536 files changed, 42502 insertions(+), 36127 deletions(-) create mode 100644 src/charon/config/backend.h delete mode 100644 src/charon/config/backends/backend.h delete mode 100644 src/charon/config/backends/local_backend.c delete mode 100644 src/charon/config/backends/local_backend.h delete mode 100644 src/charon/config/backends/sqlite_backend.c delete mode 100644 src/charon/config/backends/sqlite_backend.h delete mode 100644 src/charon/config/backends/writeable_backend.h delete mode 100644 src/charon/config/credentials/local_credential_store.c delete mode 100644 src/charon/config/credentials/local_credential_store.h create mode 100644 src/charon/control/controller.c create mode 100644 src/charon/control/controller.h delete mode 100644 src/charon/control/interface_manager.c delete mode 100644 src/charon/control/interface_manager.h delete mode 100644 src/charon/control/interfaces/dbus_interface.c delete mode 100644 src/charon/control/interfaces/dbus_interface.h delete mode 100644 src/charon/control/interfaces/interface.h delete mode 100755 src/charon/control/interfaces/stroke_interface.c delete mode 100644 src/charon/control/interfaces/stroke_interface.h delete mode 100644 src/charon/control/interfaces/xml_interface.c delete mode 100644 src/charon/control/interfaces/xml_interface.h delete mode 100644 src/charon/control/interfaces/xml_interface.xml create mode 100644 src/charon/credentials/auth_info.c create mode 100644 src/charon/credentials/auth_info.h create mode 100644 src/charon/credentials/credential_manager.c create mode 100644 src/charon/credentials/credential_manager.h create mode 100644 src/charon/credentials/credential_set.h create mode 100644 src/charon/plugins/dbus/Makefile.am create mode 100644 src/charon/plugins/dbus/dbus.c create mode 100644 src/charon/plugins/dbus/dbus.h create mode 100644 src/charon/plugins/eap_aka/Makefile.am create mode 100644 src/charon/plugins/eap_aka/eap_aka.c create mode 100644 src/charon/plugins/eap_aka/eap_aka.h create mode 100644 src/charon/plugins/eap_aka/eap_aka_plugin.c create mode 100644 src/charon/plugins/eap_aka/eap_aka_plugin.h create mode 100644 src/charon/plugins/eap_identity/Makefile.am create mode 100644 src/charon/plugins/eap_identity/eap_identity.c create mode 100644 src/charon/plugins/eap_identity/eap_identity.h create mode 100644 src/charon/plugins/eap_identity/eap_identity_plugin.c create mode 100644 src/charon/plugins/eap_identity/eap_identity_plugin.h create mode 100644 src/charon/plugins/eap_md5/Makefile.am create mode 100644 src/charon/plugins/eap_md5/eap_md5.c create mode 100644 src/charon/plugins/eap_md5/eap_md5.h create mode 100644 src/charon/plugins/eap_md5/eap_md5_plugin.c create mode 100644 src/charon/plugins/eap_md5/eap_md5_plugin.h create mode 100644 src/charon/plugins/eap_sim/Makefile.am create mode 100644 src/charon/plugins/eap_sim/eap_sim.c create mode 100644 src/charon/plugins/eap_sim/eap_sim.h create mode 100644 src/charon/plugins/eap_sim/eap_sim_file.c create mode 100644 src/charon/plugins/eap_sim/eap_sim_plugin.c create mode 100644 src/charon/plugins/eap_sim/eap_sim_plugin.h create mode 100644 src/charon/plugins/med_db/Makefile.am create mode 100644 src/charon/plugins/med_db/med_db_creds.c create mode 100644 src/charon/plugins/med_db/med_db_creds.h create mode 100644 src/charon/plugins/med_db/med_db_plugin.c create mode 100644 src/charon/plugins/med_db/med_db_plugin.h create mode 100644 src/charon/plugins/sql/Makefile.am create mode 100644 src/charon/plugins/sql/config.sql create mode 100644 src/charon/plugins/sql/cred.sql create mode 100644 src/charon/plugins/sql/sql_config.c create mode 100644 src/charon/plugins/sql/sql_config.h create mode 100644 src/charon/plugins/sql/sql_plugin.c create mode 100644 src/charon/plugins/sql/sql_plugin.h create mode 100644 src/charon/plugins/sql/test.sql create mode 100644 src/charon/plugins/stroke/Makefile.am create mode 100755 src/charon/plugins/stroke/stroke.c create mode 100644 src/charon/plugins/stroke/stroke.h create mode 100644 src/charon/plugins/unit_tester/Makefile.am create mode 100644 src/charon/plugins/unit_tester/tests.h create mode 100644 src/charon/plugins/unit_tester/tests/test_auth_info.c create mode 100644 src/charon/plugins/unit_tester/tests/test_curl.c create mode 100644 src/charon/plugins/unit_tester/tests/test_enumerator.c create mode 100644 src/charon/plugins/unit_tester/tests/test_fips_prf.c create mode 100644 src/charon/plugins/unit_tester/tests/test_mutex.c create mode 100644 src/charon/plugins/unit_tester/tests/test_mysql.c create mode 100644 src/charon/plugins/unit_tester/tests/test_sqlite.c create mode 100644 src/charon/plugins/unit_tester/unit_tester.c create mode 100644 src/charon/plugins/unit_tester/unit_tester.h create mode 100644 src/charon/plugins/xml/Makefile.am create mode 100644 src/charon/plugins/xml/schema.xml create mode 100644 src/charon/plugins/xml/xml.c create mode 100644 src/charon/plugins/xml/xml.h delete mode 100644 src/charon/sa/authenticators/eap/eap_aka.c delete mode 100644 src/charon/sa/authenticators/eap/eap_aka.h delete mode 100644 src/charon/sa/authenticators/eap/eap_identity.c delete mode 100644 src/charon/sa/authenticators/eap/eap_identity.h create mode 100644 src/charon/sa/authenticators/eap/eap_manager.c create mode 100644 src/charon/sa/authenticators/eap/eap_manager.h delete mode 100644 src/charon/sa/authenticators/eap/eap_md5.c delete mode 100644 src/charon/sa/authenticators/eap/eap_md5.h delete mode 100644 src/charon/sa/authenticators/eap/eap_sim.c delete mode 100644 src/charon/sa/authenticators/eap/eap_sim.h delete mode 100644 src/charon/sa/authenticators/eap/sim/eap_sim_file.c delete mode 100644 src/charon/sa/tasks/ike_cert.c delete mode 100644 src/charon/sa/tasks/ike_cert.h create mode 100644 src/charon/sa/tasks/ike_cert_post.c create mode 100644 src/charon/sa/tasks/ike_cert_post.h create mode 100644 src/charon/sa/tasks/ike_cert_pre.c create mode 100644 src/charon/sa/tasks/ike_cert_pre.h create mode 100644 src/libfast/Makefile.am create mode 100644 src/libfast/context.h create mode 100644 src/libfast/controller.h create mode 100644 src/libfast/dispatcher.c create mode 100644 src/libfast/dispatcher.h create mode 100644 src/libfast/filter.h create mode 100644 src/libfast/request.c create mode 100644 src/libfast/request.h create mode 100644 src/libfast/session.c create mode 100644 src/libfast/session.h delete mode 100755 src/libstrongswan/credential_store.h create mode 100644 src/libstrongswan/credentials/builder.c create mode 100644 src/libstrongswan/credentials/builder.h create mode 100644 src/libstrongswan/credentials/certificates/certificate.c create mode 100644 src/libstrongswan/credentials/certificates/certificate.h create mode 100644 src/libstrongswan/credentials/certificates/crl.c create mode 100644 src/libstrongswan/credentials/certificates/crl.h create mode 100644 src/libstrongswan/credentials/certificates/ocsp_request.c create mode 100644 src/libstrongswan/credentials/certificates/ocsp_request.h create mode 100644 src/libstrongswan/credentials/certificates/ocsp_response.c create mode 100644 src/libstrongswan/credentials/certificates/ocsp_response.h create mode 100644 src/libstrongswan/credentials/certificates/x509.c create mode 100644 src/libstrongswan/credentials/certificates/x509.h create mode 100644 src/libstrongswan/credentials/credential_factory.c create mode 100644 src/libstrongswan/credentials/credential_factory.h create mode 100644 src/libstrongswan/credentials/keys/private_key.c create mode 100644 src/libstrongswan/credentials/keys/private_key.h create mode 100644 src/libstrongswan/credentials/keys/public_key.c create mode 100644 src/libstrongswan/credentials/keys/public_key.h create mode 100644 src/libstrongswan/credentials/keys/shared_key.c create mode 100644 src/libstrongswan/credentials/keys/shared_key.h delete mode 100644 src/libstrongswan/crypto/ac.c delete mode 100644 src/libstrongswan/crypto/ac.h delete mode 100644 src/libstrongswan/crypto/ca.c delete mode 100644 src/libstrongswan/crypto/ca.h delete mode 100644 src/libstrongswan/crypto/certinfo.c delete mode 100644 src/libstrongswan/crypto/certinfo.h delete mode 100755 src/libstrongswan/crypto/crl.c delete mode 100755 src/libstrongswan/crypto/crl.h delete mode 100644 src/libstrongswan/crypto/crypters/aes_cbc_crypter.c delete mode 100644 src/libstrongswan/crypto/crypters/aes_cbc_crypter.h delete mode 100644 src/libstrongswan/crypto/crypters/des_crypter.c delete mode 100644 src/libstrongswan/crypto/crypters/des_crypter.h create mode 100644 src/libstrongswan/crypto/crypto_factory.c create mode 100644 src/libstrongswan/crypto/crypto_factory.h delete mode 100644 src/libstrongswan/crypto/hashers/md5_hasher.c delete mode 100644 src/libstrongswan/crypto/hashers/md5_hasher.h delete mode 100644 src/libstrongswan/crypto/hashers/sha1_hasher.c delete mode 100644 src/libstrongswan/crypto/hashers/sha1_hasher.h delete mode 100644 src/libstrongswan/crypto/hashers/sha2_hasher.c delete mode 100644 src/libstrongswan/crypto/hashers/sha2_hasher.h delete mode 100644 src/libstrongswan/crypto/hmac.c delete mode 100644 src/libstrongswan/crypto/hmac.h delete mode 100644 src/libstrongswan/crypto/ietf_attr_list.c delete mode 100644 src/libstrongswan/crypto/ietf_attr_list.h delete mode 100644 src/libstrongswan/crypto/ocsp.c delete mode 100644 src/libstrongswan/crypto/prfs/fips_prf.c delete mode 100644 src/libstrongswan/crypto/prfs/fips_prf.h delete mode 100644 src/libstrongswan/crypto/prfs/hmac_prf.c delete mode 100644 src/libstrongswan/crypto/prfs/hmac_prf.h delete mode 100644 src/libstrongswan/crypto/rsa/rsa_private_key.c delete mode 100644 src/libstrongswan/crypto/rsa/rsa_private_key.h delete mode 100644 src/libstrongswan/crypto/rsa/rsa_public_key.c delete mode 100644 src/libstrongswan/crypto/rsa/rsa_public_key.h delete mode 100644 src/libstrongswan/crypto/signers/hmac_signer.c delete mode 100644 src/libstrongswan/crypto/signers/hmac_signer.h delete mode 100755 src/libstrongswan/crypto/x509.c delete mode 100755 src/libstrongswan/crypto/x509.h create mode 100644 src/libstrongswan/database/database.h create mode 100644 src/libstrongswan/database/database_factory.c create mode 100644 src/libstrongswan/database/database_factory.h create mode 100644 src/libstrongswan/fetcher/fetcher.h create mode 100644 src/libstrongswan/fetcher/fetcher_manager.c create mode 100644 src/libstrongswan/fetcher/fetcher_manager.h create mode 100644 src/libstrongswan/plugins/aes/Makefile.am create mode 100644 src/libstrongswan/plugins/aes/aes_crypter.c create mode 100644 src/libstrongswan/plugins/aes/aes_crypter.h create mode 100644 src/libstrongswan/plugins/aes/aes_plugin.c create mode 100644 src/libstrongswan/plugins/aes/aes_plugin.h create mode 100644 src/libstrongswan/plugins/curl/Makefile.am create mode 100644 src/libstrongswan/plugins/curl/curl_fetcher.c create mode 100644 src/libstrongswan/plugins/curl/curl_fetcher.h create mode 100644 src/libstrongswan/plugins/curl/curl_plugin.c create mode 100644 src/libstrongswan/plugins/curl/curl_plugin.h create mode 100644 src/libstrongswan/plugins/des/Makefile.am create mode 100644 src/libstrongswan/plugins/des/des_crypter.c create mode 100644 src/libstrongswan/plugins/des/des_crypter.h create mode 100644 src/libstrongswan/plugins/des/des_plugin.c create mode 100644 src/libstrongswan/plugins/des/des_plugin.h create mode 100644 src/libstrongswan/plugins/fips_prf/Makefile.am create mode 100644 src/libstrongswan/plugins/fips_prf/fips_prf.c create mode 100644 src/libstrongswan/plugins/fips_prf/fips_prf.h create mode 100644 src/libstrongswan/plugins/fips_prf/fips_prf_plugin.c create mode 100644 src/libstrongswan/plugins/fips_prf/fips_prf_plugin.h create mode 100644 src/libstrongswan/plugins/gmp/Makefile.am create mode 100644 src/libstrongswan/plugins/gmp/gmp_diffie_hellman.c create mode 100644 src/libstrongswan/plugins/gmp/gmp_diffie_hellman.h create mode 100644 src/libstrongswan/plugins/gmp/gmp_plugin.c create mode 100644 src/libstrongswan/plugins/gmp/gmp_plugin.h create mode 100644 src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c create mode 100644 src/libstrongswan/plugins/gmp/gmp_rsa_private_key.h create mode 100644 src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c create mode 100644 src/libstrongswan/plugins/gmp/gmp_rsa_public_key.h create mode 100644 src/libstrongswan/plugins/hmac/Makefile.am create mode 100644 src/libstrongswan/plugins/hmac/hmac.c create mode 100644 src/libstrongswan/plugins/hmac/hmac.h create mode 100644 src/libstrongswan/plugins/hmac/hmac_plugin.c create mode 100644 src/libstrongswan/plugins/hmac/hmac_plugin.h create mode 100644 src/libstrongswan/plugins/hmac/hmac_prf.c create mode 100644 src/libstrongswan/plugins/hmac/hmac_prf.h create mode 100644 src/libstrongswan/plugins/hmac/hmac_signer.c create mode 100644 src/libstrongswan/plugins/hmac/hmac_signer.h create mode 100644 src/libstrongswan/plugins/ldap/Makefile.am create mode 100644 src/libstrongswan/plugins/ldap/ldap_fetcher.c create mode 100644 src/libstrongswan/plugins/ldap/ldap_fetcher.h create mode 100644 src/libstrongswan/plugins/ldap/ldap_plugin.c create mode 100644 src/libstrongswan/plugins/ldap/ldap_plugin.h create mode 100644 src/libstrongswan/plugins/md5/Makefile.am create mode 100644 src/libstrongswan/plugins/md5/md5_hasher.c create mode 100644 src/libstrongswan/plugins/md5/md5_hasher.h create mode 100644 src/libstrongswan/plugins/md5/md5_plugin.c create mode 100644 src/libstrongswan/plugins/md5/md5_plugin.h create mode 100644 src/libstrongswan/plugins/mysql/Makefile.am create mode 100644 src/libstrongswan/plugins/mysql/mysql_database.c create mode 100644 src/libstrongswan/plugins/mysql/mysql_database.h create mode 100644 src/libstrongswan/plugins/mysql/mysql_plugin.c create mode 100644 src/libstrongswan/plugins/mysql/mysql_plugin.h create mode 100644 src/libstrongswan/plugins/plugin.h create mode 100644 src/libstrongswan/plugins/plugin_loader.c create mode 100644 src/libstrongswan/plugins/plugin_loader.h create mode 100644 src/libstrongswan/plugins/sha1/Makefile.am create mode 100644 src/libstrongswan/plugins/sha1/sha1_hasher.c create mode 100644 src/libstrongswan/plugins/sha1/sha1_hasher.h create mode 100644 src/libstrongswan/plugins/sha1/sha1_plugin.c create mode 100644 src/libstrongswan/plugins/sha1/sha1_plugin.h create mode 100644 src/libstrongswan/plugins/sha2/Makefile.am create mode 100644 src/libstrongswan/plugins/sha2/sha2_hasher.c create mode 100644 src/libstrongswan/plugins/sha2/sha2_hasher.h create mode 100644 src/libstrongswan/plugins/sha2/sha2_plugin.c create mode 100644 src/libstrongswan/plugins/sha2/sha2_plugin.h create mode 100644 src/libstrongswan/plugins/sqlite/Makefile.am create mode 100644 src/libstrongswan/plugins/sqlite/sqlite_database.c create mode 100644 src/libstrongswan/plugins/sqlite/sqlite_database.h create mode 100644 src/libstrongswan/plugins/sqlite/sqlite_plugin.c create mode 100644 src/libstrongswan/plugins/sqlite/sqlite_plugin.h create mode 100644 src/libstrongswan/plugins/x509/Makefile.am create mode 100644 src/libstrongswan/plugins/x509/x509_cert.c create mode 100644 src/libstrongswan/plugins/x509/x509_cert.h create mode 100644 src/libstrongswan/plugins/x509/x509_crl.c create mode 100644 src/libstrongswan/plugins/x509/x509_crl.h create mode 100644 src/libstrongswan/plugins/x509/x509_ocsp_request.c create mode 100644 src/libstrongswan/plugins/x509/x509_ocsp_request.h create mode 100644 src/libstrongswan/plugins/x509/x509_ocsp_response.c create mode 100644 src/libstrongswan/plugins/x509/x509_ocsp_response.h create mode 100644 src/libstrongswan/plugins/x509/x509_plugin.c create mode 100644 src/libstrongswan/plugins/x509/x509_plugin.h create mode 100644 src/libstrongswan/settings.c create mode 100644 src/libstrongswan/settings.h create mode 100644 src/libstrongswan/utils.c create mode 100644 src/libstrongswan/utils.h delete mode 100644 src/libstrongswan/utils/fetcher.c delete mode 100644 src/libstrongswan/utils/fetcher.h create mode 100644 src/libstrongswan/utils/mutex.c create mode 100644 src/libstrongswan/utils/mutex.h delete mode 100644 src/manager/database.c delete mode 100644 src/manager/database.h delete mode 100644 src/manager/lib/context.h delete mode 100644 src/manager/lib/controller.h delete mode 100644 src/manager/lib/dispatcher.c delete mode 100644 src/manager/lib/dispatcher.h delete mode 100644 src/manager/lib/request.c delete mode 100644 src/manager/lib/request.h delete mode 100644 src/manager/lib/session.c delete mode 100644 src/manager/lib/session.h delete mode 100644 src/manager/lib/xml.c delete mode 100644 src/manager/lib/xml.h create mode 100644 src/manager/storage.c create mode 100644 src/manager/storage.h create mode 100644 src/manager/xml.c create mode 100644 src/manager/xml.h delete mode 100644 src/stroke/stroke.h create mode 100644 src/stroke/stroke_msg.h (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 4c8ed7d7e..504401230 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -31,6 +31,10 @@ if USE_UML SUBDIRS += dumm endif +if USE_FAST + SUBDIRS += libfast +endif + if USE_MANAGER SUBDIRS += manager endif diff --git a/src/charon/Makefile.am b/src/charon/Makefile.am index 1d7022336..0ee61cd08 100644 --- a/src/charon/Makefile.am +++ b/src/charon/Makefile.am @@ -4,16 +4,13 @@ charon_SOURCES = \ bus/bus.c bus/bus.h \ bus/listeners/file_logger.c bus/listeners/file_logger.h \ bus/listeners/sys_logger.c bus/listeners/sys_logger.h \ -config/backends/backend.h config/backends/writeable_backend.h \ -config/backend_manager.c config/backend_manager.h \ +config/backend_manager.c config/backend_manager.h config/backend.h \ config/child_cfg.c config/child_cfg.h \ -config/credentials/local_credential_store.c config/credentials/local_credential_store.h \ config/ike_cfg.c config/ike_cfg.h \ config/peer_cfg.c config/peer_cfg.h \ config/proposal.c config/proposal.h \ config/traffic_selector.c config/traffic_selector.h \ -control/interfaces/interface.h \ -control/interface_manager.c control/interface_manager.h \ +control/controller.c control/controller.h \ daemon.c daemon.h \ encoding/generator.c encoding/generator.h \ encoding/message.c encoding/message.h \ @@ -63,6 +60,7 @@ processing/processor.c processing/processor.h \ sa/authenticators/authenticator.c sa/authenticators/authenticator.h \ sa/authenticators/eap_authenticator.c sa/authenticators/eap_authenticator.h \ sa/authenticators/eap/eap_method.c sa/authenticators/eap/eap_method.h \ +sa/authenticators/eap/eap_manager.c sa/authenticators/eap/eap_manager.h \ sa/authenticators/psk_authenticator.c sa/authenticators/psk_authenticator.h \ sa/authenticators/rsa_authenticator.c sa/authenticators/rsa_authenticator.h \ sa/child_sa.c sa/child_sa.h \ @@ -74,7 +72,8 @@ sa/tasks/child_create.c sa/tasks/child_create.h \ sa/tasks/child_delete.c sa/tasks/child_delete.h \ sa/tasks/child_rekey.c sa/tasks/child_rekey.h \ sa/tasks/ike_auth.c sa/tasks/ike_auth.h \ -sa/tasks/ike_cert.c sa/tasks/ike_cert.h \ +sa/tasks/ike_cert_pre.c sa/tasks/ike_cert_pre.h \ +sa/tasks/ike_cert_post.c sa/tasks/ike_cert_post.h \ sa/tasks/ike_config.c sa/tasks/ike_config.h \ sa/tasks/ike_delete.c sa/tasks/ike_delete.h \ sa/tasks/ike_dpd.c sa/tasks/ike_dpd.h \ @@ -84,7 +83,10 @@ sa/tasks/ike_mobike.c sa/tasks/ike_mobike.h \ sa/tasks/ike_rekey.c sa/tasks/ike_rekey.h \ sa/tasks/ike_reauth.c sa/tasks/ike_reauth.h \ sa/tasks/ike_auth_lifetime.c sa/tasks/ike_auth_lifetime.h \ -sa/tasks/task.c sa/tasks/task.h +sa/tasks/task.c sa/tasks/task.h \ +credentials/credential_manager.c credentials/credential_manager.h \ +credentials/auth_info.c credentials/auth_info.h \ +credentials/credential_set.h # Use RAW socket if pluto gets built if USE_PLUTO @@ -102,89 +104,53 @@ if USE_P2P sa/tasks/ike_p2p.c sa/tasks/ike_p2p.h endif -INCLUDES = -I${linuxdir} -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon -I$(top_srcdir)/src/stroke -AM_CFLAGS = -rdynamic -DIPSEC_CONFDIR=\"${confdir}\" -DIPSEC_DIR=\"${ipsecdir}\" -DIPSEC_PIDDIR=\"${piddir}\" \ - -DIPSEC_EAPDIR=\"${eapdir}\" -DIPSEC_BACKENDDIR=\"${backenddir}\" -DIPSEC_INTERFACEDIR=\"${interfacedir}\" \ - -DSIM_READER_LIB=\"${simreader}\" -charon_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la -lgmp -lpthread -lm -ldl - -if USE_LIBCURL - charon_LDADD += -lcurl -endif +INCLUDES = -I${linuxdir} -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon +AM_CFLAGS = -rdynamic -DIPSEC_DIR=\"${ipsecdir}\" \ + -DIPSEC_PIDDIR=\"${piddir}\" -DIPSEC_PLUGINDIR=\"${plugindir}\" +charon_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la -lpthread -lm -ldl +# build optional plugins +######################## -# build EAP plugins -################### -eap_LTLIBRARIES = +SUBDIRS = -if USE_EAP_IDENTITY - eap_LTLIBRARIES += libcharon-eapidentity.la - libcharon_eapidentity_la_SOURCES = sa/authenticators/eap/eap_identity.h sa/authenticators/eap/eap_identity.c - libcharon_eapidentity_la_LDFLAGS = -module +if USE_UNIT_TESTS + SUBDIRS += plugins/unit_tester endif -if USE_EAP_SIM - eap_LTLIBRARIES += libcharon-eapsim.la - libcharon_eapsim_la_SOURCES = sa/authenticators/eap/eap_sim.h sa/authenticators/eap/eap_sim.c - libcharon_eapsim_la_LDFLAGS = -module - - plugin_LTLIBRARIES = libcharon-eapsim-file.la - libcharon_eapsim_file_la_SOURCES = sa/authenticators/eap/sim/eap_sim_file.c - libcharon_eapsim_file_la_LDFLAGS = -module +if USE_STROKE + SUBDIRS += plugins/stroke endif -if USE_EAP_MD5 - eap_LTLIBRARIES += libcharon-eapmd5.la - libcharon_eapmd5_la_SOURCES = sa/authenticators/eap/eap_md5.h sa/authenticators/eap/eap_md5.c - libcharon_eapmd5_la_LDFLAGS = -module +if USE_LIBDBUS + SUBDIRS += plugins/dbus endif -if USE_EAP_AKA - eap_LTLIBRARIES += libcharon-eapaka.la - libcharon_eapaka_la_SOURCES = sa/authenticators/eap/eap_aka.h sa/authenticators/eap/eap_aka.c - libcharon_eapaka_la_LDFLAGS = -module +if USE_LIBXML + SUBDIRS += plugins/xml endif -# build backends -################ -backend_LTLIBRARIES = - -if USE_STROKE - backend_LTLIBRARIES += libcharon-local.la - libcharon_local_la_SOURCES = config/backends/local_backend.h config/backends/local_backend.c - libcharon_local_la_LDFLAGS = -module +if USE_SQL + SUBDIRS += plugins/sql endif -if USE_LIBSQLITE - backend_LTLIBRARIES += libcharon-sqlite.la - libcharon_sqlite_la_SOURCES = config/backends/sqlite_backend.h config/backends/sqlite_backend.c - libcharon_sqlite_la_LIBADD = -lsqlite3 - libcharon_sqlite_la_LDFLAGS = -module +if USE_EAP_IDENTITY + SUBDIRS += plugins/eap_identity endif -# build control interfaces -########################## -interface_LTLIBRARIES = +if USE_EAP_SIM + SUBDIRS += plugins/eap_sim +endif -if USE_STROKE - interface_LTLIBRARIES += libcharon-stroke.la - libcharon_stroke_la_SOURCES = control/interfaces/stroke_interface.h control/interfaces/stroke_interface.c - libcharon_stroke_la_LDFLAGS = -module +if USE_EAP_MD5 + SUBDIRS += plugins/eap_md5 endif -if USE_LIBDBUS - interface_LTLIBRARIES += libcharon-dbus.la - libcharon_dbus_la_SOURCES = control/interfaces/dbus_interface.h control/interfaces/dbus_interface.c - libcharon_dbus_la_LDFLAGS = -module - libcharon_dbus_la_LIBADD = ${dbus_LIBS} - INCLUDES += ${dbus_CFLAGS} +if USE_EAP_AKA + SUBDIRS += plugins/eap_aka endif -if USE_LIBXML - interface_LTLIBRARIES += libcharon-xml.la - libcharon_xml_la_SOURCES = control/interfaces/xml_interface.h control/interfaces/xml_interface.c - libcharon_xml_la_LDFLAGS = -module - libcharon_xml_la_LIBADD = ${xml_LIBS} - INCLUDES += ${xml_CFLAGS} +if USE_MED_DB + SUBDIRS += plugins/med_db endif diff --git a/src/charon/bus/bus.c b/src/charon/bus/bus.c index e53ac43ce..5f813e781 100644 --- a/src/charon/bus/bus.c +++ b/src/charon/bus/bus.c @@ -1,10 +1,3 @@ -/** - * @file bus.c - * - * @brief Implementation of bus_t. - * - */ - /* * Copyright (C) 2006 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,8 @@ * 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. + * + * $Id$ */ #include "bus.h" @@ -25,6 +20,7 @@ #include #include +#include ENUM(signal_names, SIG_ANY, SIG_MAX, /** should not get printed */ @@ -72,9 +68,9 @@ struct private_bus_t { linked_list_t *listeners; /** - * mutex to synchronize active listeners + * mutex to synchronize active listeners, recursively */ - pthread_mutex_t mutex; + mutex_t *mutex; /** * Thread local storage for a unique, simple thread ID @@ -107,7 +103,7 @@ struct entry_t { /** * condvar where active listeners wait */ - pthread_cond_t cond; + condvar_t *condvar; }; /** @@ -119,11 +115,20 @@ static entry_t *entry_create(bus_listener_t *listener, bool blocker) this->listener = listener; this->blocker = blocker; - pthread_cond_init(&this->cond, NULL); + this->condvar = condvar_create(CONDVAR_DEFAULT); return this; } +/** + * destroy an entry_t + */ +static void entry_destroy(entry_t *entry) +{ + entry->condvar->destroy(entry->condvar); + free(entry); +} + /** * Get a unique thread number for a calling thread. Since * pthread_self returns large and ugly numbers, use this function @@ -151,9 +156,9 @@ static int get_thread_number(private_bus_t *this) */ static void add_listener(private_bus_t *this, bus_listener_t *listener) { - pthread_mutex_lock(&this->mutex); + this->mutex->lock(this->mutex); this->listeners->insert_last(this->listeners, entry_create(listener, FALSE)); - pthread_mutex_unlock(&this->mutex); + this->mutex->unlock(this->mutex); } /** @@ -164,19 +169,19 @@ static void remove_listener(private_bus_t *this, bus_listener_t *listener) iterator_t *iterator; entry_t *entry; - pthread_mutex_lock(&this->mutex); + this->mutex->lock(this->mutex); iterator = this->listeners->create_iterator(this->listeners, TRUE); while (iterator->iterate(iterator, (void**)&entry)) { if (entry->listener == listener) { iterator->remove(iterator); - free(entry); + entry_destroy(entry); break; } } iterator->destroy(iterator); - pthread_mutex_unlock(&this->mutex); + this->mutex->unlock(this->mutex); } typedef struct cleanup_data_t cleanup_data_t; @@ -205,7 +210,7 @@ static void listener_cleanup(cleanup_data_t *data) if (entry == data->entry) { iterator->remove(iterator); - free(entry); + entry_destroy(entry); break; } } @@ -223,21 +228,21 @@ static void listen_(private_bus_t *this, bus_listener_t *listener, job_t *job) data.this = this; data.entry = entry_create(listener, TRUE); - pthread_mutex_lock(&this->mutex); + this->mutex->lock(this->mutex); this->listeners->insert_last(this->listeners, data.entry); charon->processor->queue_job(charon->processor, job); - pthread_cleanup_push((void*)pthread_mutex_unlock, &this->mutex); + pthread_cleanup_push((void*)this->mutex->unlock, this->mutex); pthread_cleanup_push((void*)listener_cleanup, &data); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old); while (data.entry->blocker) { - pthread_cond_wait(&data.entry->cond, &this->mutex); + data.entry->condvar->wait(data.entry->condvar, this->mutex); } pthread_setcancelstate(old, NULL); pthread_cleanup_pop(FALSE); /* unlock mutex */ pthread_cleanup_pop(TRUE); - free(data.entry); + entry_destroy(data.entry); } /** @@ -248,6 +253,7 @@ static void set_sa(private_bus_t *this, ike_sa_t *ike_sa) pthread_setspecific(this->thread_sa, ike_sa); } + /** * Implementation of bus_t.vsignal. */ @@ -259,7 +265,7 @@ static void vsignal(private_bus_t *this, signal_t signal, level_t level, ike_sa_t *ike_sa; long thread; - pthread_mutex_lock(&this->mutex); + this->mutex->lock(this->mutex); ike_sa = pthread_getspecific(this->thread_sa); thread = get_thread_number(this); @@ -275,18 +281,18 @@ static void vsignal(private_bus_t *this, signal_t signal, level_t level, if (entry->blocker) { entry->blocker = FALSE; - pthread_cond_signal(&entry->cond); + entry->condvar->signal(entry->condvar); } else { - free(entry); + entry_destroy(entry); } } va_end(args_copy); } iterator->destroy(iterator); - pthread_mutex_unlock(&this->mutex); + this->mutex->unlock(this->mutex); } /** @@ -307,7 +313,8 @@ static void signal_(private_bus_t *this, signal_t signal, level_t level, */ static void destroy(private_bus_t *this) { - this->listeners->destroy_function(this->listeners, free); + this->mutex->destroy(this->mutex); + this->listeners->destroy_function(this->listeners, (void*)entry_destroy); free(this); } @@ -327,7 +334,7 @@ bus_t *bus_create() this->public.destroy = (void(*)(bus_t*)) destroy; this->listeners = linked_list_create(); - pthread_mutex_init(&this->mutex, NULL); + this->mutex = mutex_create(MUTEX_DEFAULT); pthread_key_create(&this->thread_id, NULL); pthread_key_create(&this->thread_sa, NULL); diff --git a/src/charon/bus/bus.h b/src/charon/bus/bus.h index f71018444..678bf37d4 100644 --- a/src/charon/bus/bus.h +++ b/src/charon/bus/bus.h @@ -1,10 +1,3 @@ -/** - * @file bus.h - * - * @brief Interface of bus_t. - * - */ - /* * Copyright (C) 2006 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup bus bus + * @{ @ingroup charon */ #ifndef BUS_H_ @@ -36,7 +36,7 @@ typedef struct bus_t bus_t; /** - * @brief signals emitted by the daemon. + * signals emitted by the daemon. * * Signaling is for different purporses. First, it allows debugging via * "debugging signal messages", sencondly, it allows to follow certain @@ -52,8 +52,6 @@ typedef struct bus_t bus_t; * Debug signal betwee a START and a SUCCESS/FAILED belongs to that operation * if the IKE_SA is the same. The thread may change, as multiple threads * may be involved in a complex scenario. - * - * @ingroup bus */ enum signal_t { /** pseudo signal, representing any other signal */ @@ -157,7 +155,7 @@ enum level_t { #if DEBUG_LEVEL >= 1 /** - * @brief Log a debug message via the signal bus. + * Log a debug message via the signal bus. * * @param signal signal_t signal description * @param format printf() style format string @@ -189,7 +187,7 @@ enum level_t { #endif /* DBG4 */ /** - * @brief Raise a signal for an occured event. + * Raise a signal for an occured event. * * @param sig signal_t signal description * @param format printf() style format string @@ -198,7 +196,7 @@ enum level_t { #define SIG(sig, format, ...) charon->bus->signal(charon->bus, sig, LEVEL_0, format, ##__VA_ARGS__) /** - * @brief Get the type of a signal. + * Get the type of a signal. * * A signal may be a debugging signal with a specific context. They have * a level specific for their context > 0. All audit signals use the @@ -211,17 +209,15 @@ enum level_t { /** - * @brief Interface for registering at the signal bus. + * Interface for registering at the signal bus. * * To receive signals from the bus, the client implementing the * bus_listener_t interface registers itself at the signal bus. - * - * @ingroup bus */ struct bus_listener_t { /** - * @brief Send a signal to a bus listener. + * Send a signal to a bus listener. * * A numerical identification for the thread is included, as the * associated IKE_SA, if any. Signal specifies the type of @@ -231,8 +227,10 @@ struct bus_listener_t { * a "..." parameters to functions is not (cleanly) possible. * The implementing signal function returns TRUE to stay registered * to the bus, or FALSE to unregister itself. + * You should not call bus_t.signal() inside of a registered listener, + * as it WILL call itself recursively. If you do so, make shure to + * avoid infinite recursion. Watch your stack! * - * @param this listener * @param singal kind of the signal (up, down, rekeyed, ...) * @param level verbosity level of the signal * @param thread ID of the thread raised this signal @@ -246,40 +244,36 @@ struct bus_listener_t { }; /** - * @brief Signal bus which sends signals to registered listeners. + * Signal bus which sends signals to registered listeners. * * The signal bus is not much more than a multiplexer. A listener interested * in receiving event signals registers at the bus. Any signals sent to * are delivered to all registered listeners. * To deliver signals to threads, the blocking listen() call may be used * to wait for a signal. - * - * @ingroup bus */ struct bus_t { /** - * @brief Register a listener to the bus. + * Register a listener to the bus. * * A registered listener receives all signals which are sent to the bus. * The listener is passive; the thread which emitted the signal * processes the listener routine. * - * @param this bus * @param listener listener to register. */ void (*add_listener) (bus_t *this, bus_listener_t *listener); /** - * @brief Unregister a listener from the bus. + * Unregister a listener from the bus. * - * @param this bus * @param listener listener to unregister. */ void (*remove_listener) (bus_t *this, bus_listener_t *listener); /** - * @brief Register a listener and block the calling thread. + * Register a listener and block the calling thread. * * This call registers a listener and blocks the calling thread until * its listeners function returns FALSE. This allows to wait for certain @@ -287,14 +281,13 @@ struct bus_t { * registered, this allows to listen on events we initiate with the job * without missing any signals. * - * @param this bus * @param listener listener to register * @param job job to execute asynchronously when registered, or NULL */ void (*listen)(bus_t *this, bus_listener_t *listener, job_t *job); /** - * @brief Set the IKE_SA the calling thread is using. + * Set the IKE_SA the calling thread is using. * * To associate an received signal to an IKE_SA without passing it as * parameter each time, the thread registers it's used IKE_SA each @@ -302,13 +295,12 @@ struct bus_t { * the IKE_SA (by passing NULL). This IKE_SA is stored per-thread, so each * thread has one IKE_SA registered (or not). * - * @param this bus * @param ike_sa ike_sa to register, or NULL to unregister */ void (*set_sa) (bus_t *this, ike_sa_t *ike_sa); /** - * @brief Send a signal to the bus. + * Send a signal to the bus. * * The signal specifies the type of the event occured. The format string * specifies an additional informational or error message with a @@ -316,7 +308,6 @@ struct bus_t { * Some useful macros are available to shorten this call. * @see SIG(), DBG1() * - * @param this bus * @param singal kind of the signal (up, down, rekeyed, ...) * @param level verbosity level of the signal * @param format printf() style format string @@ -325,7 +316,7 @@ struct bus_t { void (*signal) (bus_t *this, signal_t signal, level_t level, char* format, ...); /** - * @brief Send a signal to the bus using va_list arguments. + * Send a signal to the bus using va_list arguments. * * Same as bus_t.signal(), but uses va_list argument list. * @@ -333,7 +324,6 @@ struct bus_t { * called extensively and therefore shouldn't allocate heap memory or * do other expensive tasks! * - * @param this bus * @param singal kind of the signal (up, down, rekeyed, ...) * @param level verbosity level of the signal * @param format printf() style format string @@ -342,20 +332,16 @@ struct bus_t { void (*vsignal) (bus_t *this, signal_t signal, level_t level, char* format, va_list args); /** - * @brief Destroy the signal bus. - * - * @param this bus to destroy + * Destroy the signal bus. */ void (*destroy) (bus_t *this); }; /** - * @brief Create the signal bus which multiplexes signals to its listeners. + * Create the signal bus which multiplexes signals to its listeners. * * @return signal bus instance - * - * @ingroup bus */ bus_t *bus_create(); -#endif /* BUS_H_ */ +#endif /* BUS_H_ @} */ diff --git a/src/charon/bus/listeners/file_logger.c b/src/charon/bus/listeners/file_logger.c index 14f9f72cf..1a31e316e 100644 --- a/src/charon/bus/listeners/file_logger.c +++ b/src/charon/bus/listeners/file_logger.c @@ -1,10 +1,3 @@ -/** - * @file file_logger.c - * - * @brief Implementation of file_logger_t. - * - */ - /* * Copyright (C) 2006 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,8 @@ * 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. + * + * $Id$ */ #include diff --git a/src/charon/bus/listeners/file_logger.h b/src/charon/bus/listeners/file_logger.h index d67daba25..6b716c6a7 100644 --- a/src/charon/bus/listeners/file_logger.h +++ b/src/charon/bus/listeners/file_logger.h @@ -1,10 +1,3 @@ -/** - * @file file_logger.h - * - * @brief Interface of file_logger_t. - * - */ - /* * Copyright (C) 2006 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup file_logger file_logger + * @{ @ingroup listeners */ #ifndef FILE_LOGGER_H_ @@ -28,12 +28,7 @@ typedef struct file_logger_t file_logger_t; #include /** - * @brief Logger to files which implements bus_listener_t. - * - * @b Constructors: - * - file_logger_create() - * - * @ingroup listeners + * Logger to files which implements bus_listener_t. */ struct file_logger_t { @@ -43,31 +38,25 @@ struct file_logger_t { bus_listener_t listener; /** - * @brief Set the loglevel for a signal type. + * Set the loglevel for a signal type. * - * @param this stream_logger_t object * @param singal type of signal * @param level max level to log (0..4) */ void (*set_level) (file_logger_t *this, signal_t signal, level_t level); /** - * @brief Destroys a file_logger_t object. - * - * @param this file_logger_t object + * Destroys a file_logger_t object. */ void (*destroy) (file_logger_t *this); }; /** - * @brief Constructor to create a file_logger_t object. + * Constructor to create a file_logger_t object. * * @param out FILE to write to * @return file_logger_t object - * - * @ingroup listeners */ file_logger_t *file_logger_create(FILE *out); - -#endif /* FILE_LOGGER_H_ */ +#endif /* FILE_LOGGER_H_ @} */ diff --git a/src/charon/bus/listeners/sys_logger.c b/src/charon/bus/listeners/sys_logger.c index d26d14dc0..876fab8fd 100644 --- a/src/charon/bus/listeners/sys_logger.c +++ b/src/charon/bus/listeners/sys_logger.c @@ -1,10 +1,3 @@ -/** - * @file sys_logger.c - * - * @brief Implementation of sys_logger_t. - * - */ - /* * Copyright (C) 2006 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,8 @@ * 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. + * + * $Id$ */ #include diff --git a/src/charon/bus/listeners/sys_logger.h b/src/charon/bus/listeners/sys_logger.h index 091217313..1a04c2ad9 100644 --- a/src/charon/bus/listeners/sys_logger.h +++ b/src/charon/bus/listeners/sys_logger.h @@ -1,10 +1,3 @@ -/** - * @file sys_logger.h - * - * @brief Interface of sys_logger_t. - * - */ - /* * Copyright (C) 2006 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup sys_logger sys_logger + * @{ @ingroup listeners */ #ifndef SYS_LOGGER_H_ @@ -30,12 +30,7 @@ typedef struct sys_logger_t sys_logger_t; #include /** - * @brief Logger for syslog which implements bus_listener_t. - * - * @b Constructors: - * - sys_logger_create() - * - * @ingroup listeners + * Logger for syslog which implements bus_listener_t. */ struct sys_logger_t { @@ -45,31 +40,25 @@ struct sys_logger_t { bus_listener_t listener; /** - * @brief Set the loglevel for a signal type. + * Set the loglevel for a signal type. * - * @param this stream_logger_t object * @param singal type of signal * @param level max level to log */ void (*set_level) (sys_logger_t *this, signal_t signal, level_t level); /** - * @brief Destroys a sys_logger_t object. - * - * @param this sys_logger_t object + * Destroys a sys_logger_t object. */ void (*destroy) (sys_logger_t *this); }; /** - * @brief Constructor to create a sys_logger_t object. + * Constructor to create a sys_logger_t object. * * @param facility syslog facility to use * @return sys_logger_t object - * - * @ingroup listeners */ sys_logger_t *sys_logger_create(int facility); - -#endif /* SYS_LOGGER_H_ */ +#endif /* SYS_LOGGER_H_ @} */ diff --git a/src/charon/config/backend.h b/src/charon/config/backend.h new file mode 100644 index 000000000..96e76e05f --- /dev/null +++ b/src/charon/config/backend.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2007-2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +/** + * @defgroup backend backend + * @{ @ingroup config + */ + +#ifndef BACKEND_H_ +#define BACKEND_H_ + +typedef struct backend_t backend_t; + +#include +#include +#include +#include +#include + +/** + * The interface for a configuration backend. + * + * A configuration backend is loaded into the backend_manager. It does the actual + * configuration lookup for the method it implements. See backend_manager_t for + * more information. + */ +struct backend_t { + + /** + * Create an enumerator over all IKE configs matching two hosts. + * + * Hosts may be NULL to get all. + * + * @param me address of local host + * @param other address of remote host + * @return enumerator over ike_cfg_t's + */ + enumerator_t* (*create_ike_cfg_enumerator)(backend_t *this, + host_t *me, host_t *other); + /** + * Create an enumerator over all Peer configs matching two IDs. + * + * IDs may be NULL to get all. + * + * @param me identity of ourself + * @param other identity of remote host + * @return enumerator over peer_cfg_t + */ + enumerator_t* (*create_peer_cfg_enumerator)(backend_t *this, + identification_t *me, + identification_t *other); + /** + * Get a peer_cfg identified by it's name, or a name of its child. + * + * @param name name of peer/child cfg + * @return matching peer_config, or NULL if none found + */ + peer_cfg_t *(*get_peer_cfg_by_name)(backend_t *this, char *name); +}; + +#endif /* BACKEND_H_ @} */ diff --git a/src/charon/config/backend_manager.c b/src/charon/config/backend_manager.c index b2104acea..075ab2417 100644 --- a/src/charon/config/backend_manager.c +++ b/src/charon/config/backend_manager.c @@ -1,10 +1,3 @@ -/** - * @file backend_manager.c - * - * @brief Implementation of backend_manager_t. - * - */ - /* * Copyright (C) 2007 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,18 +11,18 @@ * 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. + * + * $Id$ */ #include "backend_manager.h" #include -#include -#include -#include +#include #include #include -#include +#include typedef struct private_backend_manager_t private_backend_manager_t; @@ -50,164 +43,249 @@ struct private_backend_manager_t { linked_list_t *backends; /** - * Additional list of writable backends. - */ - linked_list_t *writeable; - - /** - * List of dlopen() handles we used to open backends + * locking mutex */ - linked_list_t *handles; + mutex_t *mutex; }; /** - * implements backend_manager_t.get_ike_cfg. + * data to pass nested IKE enumerator */ -static ike_cfg_t *get_ike_cfg(private_backend_manager_t *this, - host_t *my_host, host_t *other_host) +typedef struct { + private_backend_manager_t *this; + host_t *me; + host_t *other; +} ike_data_t; + +/** + * data to pass nested peer enumerator + */ +typedef struct { + private_backend_manager_t *this; + identification_t *me; + identification_t *other; +} peer_data_t; + +/** + * destroy IKE enumerator data and unlock list + */ +static void ike_enum_destroy(ike_data_t *data) { - backend_t *backend; - ike_cfg_t *config = NULL; - iterator_t *iterator = this->backends->create_iterator(this->backends, TRUE); - while (config == NULL && iterator->iterate(iterator, (void**)&backend)) - { - config = backend->get_ike_cfg(backend, my_host, other_host); - } - iterator->destroy(iterator); - return config; + data->this->mutex->unlock(data->this->mutex); + free(data); } /** - * implements backend_manager_t.get_peer_cfg. - */ -static peer_cfg_t *get_peer_cfg(private_backend_manager_t *this, - identification_t *my_id, identification_t *other_id, - ca_info_t *other_ca_info) + * destroy PEER enumerator data and unlock list + */ +static void peer_enum_destroy(peer_data_t *data) { - backend_t *backend; - peer_cfg_t *config = NULL; - iterator_t *iterator = this->backends->create_iterator(this->backends, TRUE); - while (config == NULL && iterator->iterate(iterator, (void**)&backend)) - { - config = backend->get_peer_cfg(backend, my_id, other_id, other_ca_info); - } - iterator->destroy(iterator); - return config; + data->this->mutex->unlock(data->this->mutex); + free(data); } /** - * implements backend_manager_t.get_peer_cfg_by_name. - */ -static peer_cfg_t *get_peer_cfg_by_name(private_backend_manager_t *this, char *name) + * inner enumerator constructor for IKE cfgs + */ +static enumerator_t *ike_enum_create(backend_t *backend, ike_data_t *data) { - backend_t *backend; - peer_cfg_t *config = NULL; - iterator_t *iterator = this->backends->create_iterator(this->backends, TRUE); - while (config == NULL && iterator->iterate(iterator, (void**)&backend)) - { - config = backend->get_peer_cfg_by_name(backend, name); - } - iterator->destroy(iterator); - return config; + return backend->create_ike_cfg_enumerator(backend, data->me, data->other); } /** - * implements backend_manager_t.add_peer_cfg. - */ -static void add_peer_cfg(private_backend_manager_t *this, peer_cfg_t *config) + * inner enumerator constructor for Peer cfgs + */ +static enumerator_t *peer_enum_create(backend_t *backend, peer_data_t *data) { - writeable_backend_t *backend; - - if (this->writeable->get_first(this->writeable, (void**)&backend) == SUCCESS) - { - backend->add_cfg(backend, config); - } + return backend->create_peer_cfg_enumerator(backend, data->me, data->other); } - /** - * implements backend_manager_t.create_iterator. - */ -static iterator_t* create_iterator(private_backend_manager_t *this) + * inner enumerator constructor for all Peer cfgs + */ +static enumerator_t *peer_enum_create_all(backend_t *backend) { - writeable_backend_t *backend; - - if (this->writeable->get_first(this->writeable, (void**)&backend) == SUCCESS) - { - return backend->create_iterator(backend); - } - /* give out an empty iterator if we have no writable backend*/ - return this->writeable->create_iterator(this->writeable, TRUE); + return backend->create_peer_cfg_enumerator(backend, NULL, NULL); } /** - * load the configuration backend modules + * implements backend_manager_t.get_ike_cfg. */ -static void load_backends(private_backend_manager_t *this) +static ike_cfg_t *get_ike_cfg(private_backend_manager_t *this, + host_t *me, host_t *other) { - struct dirent* entry; - DIR* dir; - - dir = opendir(IPSEC_BACKENDDIR); - if (dir == NULL) - { - DBG1(DBG_CFG, "error opening backend modules directory "IPSEC_BACKENDDIR); - return; - } + ike_cfg_t *current, *found = NULL; + enumerator_t *enumerator; + host_t *my_candidate, *other_candidate; + ike_data_t *data; + enum { + MATCH_NONE = 0x00, + MATCH_ANY = 0x01, + MATCH_ME = 0x04, + MATCH_OTHER = 0x08, + } prio, best = MATCH_ANY; - DBG1(DBG_CFG, "loading backend modules from '"IPSEC_BACKENDDIR"'"); - - while ((entry = readdir(dir)) != NULL) + data = malloc_thing(ike_data_t); + data->this = this; + data->me = me; + data->other = other; + + DBG2(DBG_CFG, "looking for a config for %H...%H", me, other); + + this->mutex->lock(this->mutex); + enumerator = enumerator_create_nested( + this->backends->create_enumerator(this->backends), + (void*)ike_enum_create, data, (void*)ike_enum_destroy); + while (enumerator->enumerate(enumerator, (void**)¤t)) { - char file[256]; - backend_t *backend; - backend_constructor_t constructor; - void *handle; - char *ending; + prio = MATCH_NONE; + my_candidate = current->get_my_host(current); + other_candidate = current->get_other_host(current); - snprintf(file, sizeof(file), IPSEC_BACKENDDIR"/%s", entry->d_name); - - ending = entry->d_name + strlen(entry->d_name) - 3; - if (ending <= entry->d_name || !streq(ending, ".so")) + if (my_candidate->ip_equals(my_candidate, me)) { - /* skip anything which does not look like a library */ - DBG2(DBG_CFG, " skipping %s, doesn't look like a library", - entry->d_name); - continue; + prio += MATCH_ME; } - /* try to load the library */ - handle = dlopen(file, RTLD_LAZY); - if (handle == NULL) + else if (my_candidate->is_anyaddr(my_candidate)) { - DBG1(DBG_CFG, " opening backend module %s failed: %s", - entry->d_name, dlerror()); - continue; + prio += MATCH_ANY; } - constructor = dlsym(handle, "backend_create"); - if (constructor == NULL) + if (other_candidate->ip_equals(other_candidate, other)) { - DBG1(DBG_CFG, " backend module %s has no backend_create() " - "function, skipped", entry->d_name); - dlclose(handle); - continue; + prio += MATCH_OTHER; } + else if (other_candidate->is_anyaddr(other_candidate)) + { + prio += MATCH_ANY; + } + + DBG2(DBG_CFG, " candidate: %H...%H, prio %d", + my_candidate, other_candidate, prio); - backend = constructor(); - if (backend == NULL) + /* we require at least two MATCH_ANY */ + if (prio > best) { - DBG1(DBG_CFG, " unable to create instance of backend " - "module %s, skipped", entry->d_name); - dlclose(handle); - continue; + best = prio; + DESTROY_IF(found); + found = current; + found->get_ref(found); } - DBG1(DBG_CFG, " loaded backend module successfully from %s", entry->d_name); - this->backends->insert_last(this->backends, backend); - if (backend->is_writeable(backend)) + } + enumerator->destroy(enumerator); + this->mutex->unlock(this->mutex); + return found; +} + + +static enumerator_t *create_peer_cfg_enumerator(private_backend_manager_t *this) +{ + this->mutex->lock(this->mutex); + return enumerator_create_nested( + this->backends->create_enumerator(this->backends), + (void*)peer_enum_create_all, this->mutex, + (void*)this->mutex->unlock); +} + +/** + * implements backend_manager_t.get_peer_cfg. + */ +static peer_cfg_t *get_peer_cfg(private_backend_manager_t *this, + identification_t *me, identification_t *other, + auth_info_t *auth) +{ + peer_cfg_t *current, *found = NULL; + enumerator_t *enumerator; + identification_t *my_candidate, *other_candidate; + id_match_t best = ID_MATCH_NONE; + peer_data_t *data; + + DBG2(DBG_CFG, "looking for a config for %D...%D", me, other); + + data = malloc_thing(peer_data_t); + data->this = this; + data->me = me; + data->other = other; + + this->mutex->lock(this->mutex); + enumerator = enumerator_create_nested( + this->backends->create_enumerator(this->backends), + (void*)peer_enum_create, data, (void*)peer_enum_destroy); + while (enumerator->enumerate(enumerator, ¤t)) + { + id_match_t m1, m2, sum; + + my_candidate = current->get_my_id(current); + other_candidate = current->get_other_id(current); + + m1 = my_candidate->matches(my_candidate, me); + m2 = other->matches(other, other_candidate); + sum = m1 + m2; + + if (m1 && m2) { - this->writeable->insert_last(this->writeable, backend); + if (auth->complies(auth, current->get_auth(current))) + { + DBG2(DBG_CFG, " candidate '%s': %D...%D, prio %d", + current->get_name(current), my_candidate, + other_candidate, sum); + if (sum > best) + { + DESTROY_IF(found); + found = current; + found->get_ref(found); + best = sum; + } + } } - this->handles->insert_last(this->handles, handle); } - closedir(dir); + if (found) + { + DBG1(DBG_CFG, "found matching config \"%s\": %D...%D, prio %d", + found->get_name(found), found->get_my_id(found), + found->get_other_id(found), best); + } + enumerator->destroy(enumerator); + this->mutex->unlock(this->mutex); + return found; +} + +/** + * implements backend_manager_t.get_peer_cfg_by_name. + */ +static peer_cfg_t *get_peer_cfg_by_name(private_backend_manager_t *this, char *name) +{ + backend_t *backend; + peer_cfg_t *config = NULL; + enumerator_t *enumerator; + + this->mutex->lock(this->mutex); + enumerator = this->backends->create_enumerator(this->backends); + while (config == NULL && enumerator->enumerate(enumerator, (void**)&backend)) + { + config = backend->get_peer_cfg_by_name(backend, name); + } + enumerator->destroy(enumerator); + this->mutex->unlock(this->mutex); + return config; +} + +/** + * Implementation of backend_manager_t.remove_backend. + */ +static void remove_backend(private_backend_manager_t *this, backend_t *backend) +{ + this->mutex->lock(this->mutex); + this->backends->remove(this->backends, backend, NULL); + this->mutex->unlock(this->mutex); +} + +/** + * Implementation of backend_manager_t.add_backend. + */ +static void add_backend(private_backend_manager_t *this, backend_t *backend) +{ + this->mutex->lock(this->mutex); + this->backends->insert_last(this->backends, backend); + this->mutex->unlock(this->mutex); } /** @@ -215,9 +293,8 @@ static void load_backends(private_backend_manager_t *this) */ static void destroy(private_backend_manager_t *this) { - this->backends->destroy_offset(this->backends, offsetof(backend_t, destroy)); - this->writeable->destroy(this->writeable); - this->handles->destroy_function(this->handles, (void*)dlclose); + this->backends->destroy(this->backends); + this->mutex->destroy(this->mutex); free(this); } @@ -229,17 +306,15 @@ backend_manager_t *backend_manager_create() private_backend_manager_t *this = malloc_thing(private_backend_manager_t); this->public.get_ike_cfg = (ike_cfg_t* (*)(backend_manager_t*, host_t*, host_t*))get_ike_cfg; - this->public.get_peer_cfg = (peer_cfg_t* (*)(backend_manager_t*,identification_t*,identification_t*,ca_info_t*))get_peer_cfg; + this->public.get_peer_cfg = (peer_cfg_t* (*)(backend_manager_t*,identification_t*,identification_t*,auth_info_t*))get_peer_cfg; this->public.get_peer_cfg_by_name = (peer_cfg_t* (*)(backend_manager_t*,char*))get_peer_cfg_by_name; - this->public.add_peer_cfg = (void (*)(backend_manager_t*,peer_cfg_t*))add_peer_cfg; - this->public.create_iterator = (iterator_t* (*)(backend_manager_t*))create_iterator; + this->public.create_peer_cfg_enumerator = (enumerator_t* (*)(backend_manager_t*))create_peer_cfg_enumerator; + this->public.add_backend = (void(*)(backend_manager_t*, backend_t *backend))add_backend; + this->public.remove_backend = (void(*)(backend_manager_t*, backend_t *backend))remove_backend; this->public.destroy = (void (*)(backend_manager_t*))destroy; this->backends = linked_list_create(); - this->writeable = linked_list_create(); - this->handles = linked_list_create(); - - load_backends(this); + this->mutex = mutex_create(MUTEX_RECURSIVE); return &this->public; } diff --git a/src/charon/config/backend_manager.h b/src/charon/config/backend_manager.h index 7ca6d660e..a626d928f 100644 --- a/src/charon/config/backend_manager.h +++ b/src/charon/config/backend_manager.h @@ -1,10 +1,3 @@ -/** - * @file backend_manager.h - * - * @brief Interface backend_manager_t. - * - */ - /* * Copyright (C) 2007 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup backend_manager backend_manager + * @{ @ingroup config */ #ifndef BACKEND_MANAGER_H_ @@ -30,20 +30,15 @@ typedef struct backend_manager_t backend_manager_t; #include #include #include -#include +#include /** - * @brief A loader and multiplexer to use multiple backends. + * A loader and multiplexer to use multiple backends. * * Charon allows the use of multiple configuration backends simultaneously. To * access all this backends by a single call, this class wraps multiple - * backends behind a single object. It is also responsible for loading - * the backend modules and cleaning them up. - * A backend may be writeable or not. All backends implement the backend_t - * interface, those who are writeable additionally implement the - * writeable_backend_t interface. Adding configs to the backend_manager will - * be redirected to the first writeable backend. + * backends behind a single object. * @verbatim +---------+ +-----------+ +--------------+ | @@ -55,18 +50,12 @@ typedef struct backend_manager_t backend_manager_t; +---------+ +-----------+ | @endverbatim - * - * @b Constructors: - * - backend_manager_create() - * - * @ingroup config */ struct backend_manager_t { /** - * @brief Get an ike_config identified by two hosts. + * Get an ike_config identified by two hosts. * - * @param this calling object * @param my_host address of own host * @param other_host address of remote host * @return matching ike_config, or NULL if none found @@ -75,59 +64,57 @@ struct backend_manager_t { host_t *my_host, host_t *other_host); /** - * @brief Get a peer_config identified by two IDs and the peer's certificate issuer + * Get a peer_config identified by two IDs and authorization info. * - * @param this calling object * @param my_id own ID * @param other_id peer ID - * @param other_ca_info info record on issuer of peer certificate + * @param auth_info authorization info * @return matching peer_config, or NULL if none found */ - peer_cfg_t* (*get_peer_cfg)(backend_manager_t *this, - identification_t *my_id, identification_t *other_id, - ca_info_t *other_ca_info); + peer_cfg_t* (*get_peer_cfg)(backend_manager_t *this, identification_t *my_id, + identification_t *other_id, auth_info_t *auth); /** - * @brief Get a peer_config identified by it's name. + * Get a peer_config identified by it's name. * - * @param this calling object * @param name name of the peer_config * @return matching peer_config, or NULL if none found */ peer_cfg_t* (*get_peer_cfg_by_name)(backend_manager_t *this, char *name); /** - * @brief Add a peer_config to the first found writable backend. + * Create an enumerator over all peer configs. * - * @param this calling object - * @param config peer_config to add to the backend + * @return enumerator over peer configs */ - void (*add_peer_cfg)(backend_manager_t *this, peer_cfg_t *config); + enumerator_t* (*create_peer_cfg_enumerator)(backend_manager_t *this); /** - * @brief Create an iterator over all peer configs of the writable backend. + * Register a backend on the manager. * - * @param this calling object - * @return iterator over peer configs + * @param backend backend to register */ - iterator_t* (*create_iterator)(backend_manager_t *this); + void (*add_backend)(backend_manager_t *this, backend_t *backend); /** - * @brief Destroys a backend_manager_t object. + * Unregister a backend. * - * @param this calling object + * @param backend backend to unregister + */ + void (*remove_backend)(backend_manager_t *this, backend_t *backend); + + /** + * Destroys a backend_manager_t object. */ void (*destroy) (backend_manager_t *this); }; /** - * @brief Creates a new instance of the manager and loads all backends. + * Create an instance of the backend manager * * @return backend_manager instance - * - * @ingroup config */ backend_manager_t* backend_manager_create(void); -#endif /*BACKEND_MANAGER_H_*/ +#endif /*BACKEND_MANAGER_H_ @} */ diff --git a/src/charon/config/backends/backend.h b/src/charon/config/backends/backend.h deleted file mode 100644 index 592d1dd4c..000000000 --- a/src/charon/config/backends/backend.h +++ /dev/null @@ -1,105 +0,0 @@ -/** - * @file backend.h - * - * @brief Interface backend_t. - * - */ - -/* - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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 BACKEND_H_ -#define BACKEND_H_ - -typedef struct backend_t backend_t; - -#include -#include -#include -#include - -/** - * @brief The interface for a configuration backend. - * - * A configuration backend is loaded by the backend_manager. It does the actual - * configuration lookup for the method it implements. See backend_manager_t for - * more information. - * - * @b Constructors: - * - implementations constructors - * - * @ingroup backends - */ -struct backend_t { - - /** - * @brief Get an ike_cfg identified by two hosts. - * - * @param this calling object - * @param my_host address of own host - * @param other_host address of remote host - * @return matching ike_config, or NULL if none found - */ - ike_cfg_t *(*get_ike_cfg)(backend_t *this, - host_t *my_host, host_t *other_host); - - /** - * @brief Get a peer_cfg identified by two IDs. - * - * Select a config based on the two IDs and the other's certificate issuer - * - * @param this calling object - * @param my_id own ID - * @param other_id peer ID - * @param other_ca_info info record on issuer of peer certificate - * @return matching peer_config, or NULL if none found - */ - peer_cfg_t *(*get_peer_cfg)(backend_t *this, - identification_t *my_id, identification_t *other_id, - ca_info_t *other_ca_info); - - /** - * @brief Get a peer_cfg identified by it's name, or a name of its child. - * - * @param this calling object - * @param name - * @return matching peer_config, or NULL if none found - */ - peer_cfg_t *(*get_peer_cfg_by_name)(backend_t *this, char *name); - - /** - * @brief Check if a backend is writable and implements writable_backend_t. - * - * @param this calling object - * @return TRUE if backend implements writable_backend_t. - */ - bool (*is_writeable)(backend_t *this); - - /** - * @brief Destroy a backend. - * - * @param this calling object - */ - void (*destroy)(backend_t *this); -}; - - -/** - * Construction to create a backend. - */ -typedef backend_t*(*backend_constructor_t)(void); - -#endif /* BACKEND_H_ */ - diff --git a/src/charon/config/backends/local_backend.c b/src/charon/config/backends/local_backend.c deleted file mode 100644 index e04c72ac1..000000000 --- a/src/charon/config/backends/local_backend.c +++ /dev/null @@ -1,322 +0,0 @@ -/** - * @file local_backend.c - * - * @brief Implementation of local_backend_t. - * - */ - -/* - * Copyright (C) 2006 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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 - -#include "local_backend.h" - -#include -#include -#include - - -typedef struct private_local_backend_t private_local_backend_t; - -/** - * Private data of an local_backend_t object - */ -struct private_local_backend_t { - - /** - * Public part - */ - local_backend_t public; - - /** - * list of configs - */ - linked_list_t *cfgs; - - /** - * Mutex to exclusivly access list - */ - pthread_mutex_t mutex; -}; - -/** - * implements backen_t.get_ike_cfg. - */ -static ike_cfg_t *get_ike_cfg(private_local_backend_t *this, - host_t *my_host, host_t *other_host) -{ - peer_cfg_t *peer; - ike_cfg_t *current, *found = NULL; - iterator_t *iterator; - host_t *my_candidate, *other_candidate; - enum { - MATCH_NONE = 0x00, - MATCH_ANY = 0x01, - MATCH_ME = 0x04, - MATCH_OTHER = 0x08, - } prio, best = MATCH_ANY; - - DBG2(DBG_CFG, "looking for a config for %H...%H", - my_host, other_host); - - iterator = this->cfgs->create_iterator_locked(this->cfgs, &this->mutex); - while (iterator->iterate(iterator, (void**)&peer)) - { - prio = MATCH_NONE; - current = peer->get_ike_cfg(peer); - my_candidate = current->get_my_host(current); - other_candidate = current->get_other_host(current); - - if (my_candidate->ip_equals(my_candidate, my_host)) - { - prio += MATCH_ME; - } - else if (my_candidate->is_anyaddr(my_candidate)) - { - prio += MATCH_ANY; - } - - if (other_candidate->ip_equals(other_candidate, other_host)) - { - prio += MATCH_OTHER; - } - else if (other_candidate->is_anyaddr(other_candidate)) - { - prio += MATCH_ANY; - } - - DBG2(DBG_CFG, " candidate '%s': %H...%H, prio %d", - peer->get_name(peer), my_candidate, other_candidate, prio); - - /* we require at least two MATCH_ANY */ - if (prio > best) - { - best = prio; - found = current; - } - } - if (found) - { - found->get_ref(found); - } - iterator->destroy(iterator); - return found; -} - -#define PRIO_NO_MATCH_FOUND 256 - -/** - * implements backend_t.get_peer. - */ -static peer_cfg_t *get_peer_cfg(private_local_backend_t *this, - identification_t *my_id, identification_t *other_id, - ca_info_t *other_ca_info) -{ - peer_cfg_t *current, *found = NULL; - iterator_t *iterator; - identification_t *my_candidate, *other_candidate; - int best = PRIO_NO_MATCH_FOUND; - - DBG2(DBG_CFG, "looking for a config for %D...%D", my_id, other_id); - - iterator = this->cfgs->create_iterator_locked(this->cfgs, &this->mutex); - while (iterator->iterate(iterator, (void**)¤t)) - { - int wc1, wc2; - - my_candidate = current->get_my_id(current); - other_candidate = current->get_other_id(current); - - if (my_candidate->matches(my_candidate, my_id, &wc1) - && other_id->matches(other_id, other_candidate, &wc2)) - { - int prio = (wc1 + wc2) * (MAX_CA_PATH_LEN + 1); - int pathlen = 0; - identification_t *other_candidate_ca = current->get_other_ca(current); - linked_list_t *groups = current->get_groups(current); - - /* is a group membership required? */ - if (groups->get_count(groups) > 0) - { - DBG1(DBG_CFG, " group membership required"); - } - - /* are there any ca constraints? */ - if (other_candidate_ca->get_type(other_candidate_ca) != ID_ANY) - { - ca_info_t *ca_info = other_ca_info; - - for (pathlen = 0; pathlen < MAX_CA_PATH_LEN; pathlen++) - { - if (ca_info == NULL) - { - prio = PRIO_NO_MATCH_FOUND; - break; - } - else - { - x509_t *cacert = ca_info->get_certificate(ca_info); - identification_t *other_ca = cacert->get_subject(cacert); - - if (other_candidate_ca->equals(other_candidate_ca, other_ca)) - { - /* found a ca match */ - break; - } - if (cacert->is_self_signed(cacert)) - { - /* reached the root ca without a match */ - prio = PRIO_NO_MATCH_FOUND; - break; - } - /* move a level upward in the trust path hierarchy */ - ca_info = charon->credentials->get_issuer(charon->credentials, cacert); - } - } - if (pathlen == MAX_CA_PATH_LEN) - { - DBG1(DBG_CFG, "maximum ca path length of %d levels reached", MAX_CA_PATH_LEN); - prio = PRIO_NO_MATCH_FOUND; - } - } - if (prio == PRIO_NO_MATCH_FOUND) - { - DBG2(DBG_CFG, " candidate '%s': %D...%D, no ca match", - current->get_name(current), my_candidate, other_candidate); - } - else - { - prio += pathlen; - DBG2(DBG_CFG, " candidate '%s': %D...%D, prio %d", - current->get_name(current), my_candidate, other_candidate, prio); - - if (prio < best) - { - found = current; - best = prio; - } - } - } - } - if (found) - { - DBG1(DBG_CFG, "found matching config \"%s\": %D...%D, prio %d", - found->get_name(found), - found->get_my_id(found), - found->get_other_id(found), - best); - found->get_ref(found); - } - iterator->destroy(iterator); - return found; -} - -/** - * implements backend_t.get_peer_cfg_by_name. - */ -static peer_cfg_t *get_peer_cfg_by_name(private_local_backend_t *this, char *name) -{ - iterator_t *i1, *i2; - peer_cfg_t *current, *found = NULL; - child_cfg_t *child; - - i1 = this->cfgs->create_iterator(this->cfgs, TRUE); - while (i1->iterate(i1, (void**)¤t)) - { - /* compare peer_cfgs name first */ - if (streq(current->get_name(current), name)) - { - found = current; - found->get_ref(found); - break; - } - /* compare all child_cfg names otherwise */ - i2 = current->create_child_cfg_iterator(current); - while (i2->iterate(i2, (void**)&child)) - { - if (streq(child->get_name(child), name)) - { - found = current; - found->get_ref(found); - break; - } - } - i2->destroy(i2); - if (found) - { - break; - } - } - i1->destroy(i1); - return found; -} - -/** - * Implementation of backend_t.is_writable. - */ -static bool is_writeable(private_local_backend_t *this) -{ - return TRUE; -} - -/** - * Implementation of writable_backend_t.create_iterator. - */ -static iterator_t* create_iterator(private_local_backend_t *this) -{ - return this->cfgs->create_iterator_locked(this->cfgs, &this->mutex); -} - -/** - * Implementation of writable_backend_t.add_peer_cfg. - */ -static void add_cfg(private_local_backend_t *this, peer_cfg_t *config) -{ - pthread_mutex_lock(&this->mutex); - this->cfgs->insert_last(this->cfgs, config); - pthread_mutex_unlock(&this->mutex); -} - -/** - * Implementation of backend_t.destroy. - */ -static void destroy(private_local_backend_t *this) -{ - this->cfgs->destroy_offset(this->cfgs, offsetof(peer_cfg_t, destroy)); - free(this); -} - -/** - * Described in header. - */ -backend_t *backend_create(void) -{ - private_local_backend_t *this = malloc_thing(private_local_backend_t); - - this->public.backend.backend.get_ike_cfg = (ike_cfg_t* (*)(backend_t*, host_t*, host_t*))get_ike_cfg; - this->public.backend.backend.get_peer_cfg = (peer_cfg_t* (*)(backend_t*,identification_t*,identification_t*,ca_info_t*))get_peer_cfg; - this->public.backend.backend.get_peer_cfg_by_name = (peer_cfg_t* (*)(backend_t*,char*))get_peer_cfg_by_name; - this->public.backend.backend.is_writeable = (bool(*) (backend_t*))is_writeable; - this->public.backend.backend.destroy = (void (*)(backend_t*))destroy; - this->public.backend.create_iterator = (iterator_t* (*)(writeable_backend_t*))create_iterator; - this->public.backend.add_cfg = (void (*)(writeable_backend_t*,peer_cfg_t*))add_cfg; - - /* private variables */ - this->cfgs = linked_list_create(); - pthread_mutex_init(&this->mutex, NULL); - - return &this->public.backend.backend; -} diff --git a/src/charon/config/backends/local_backend.h b/src/charon/config/backends/local_backend.h deleted file mode 100644 index b33c6443b..000000000 --- a/src/charon/config/backends/local_backend.h +++ /dev/null @@ -1,60 +0,0 @@ -/** - * @file local_backend.h - * - * @brief Interface of local_backend_t. - * - */ - -/* - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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 LOCAL_BACKEND_H_ -#define LOCAL_BACKEND_H_ - -typedef struct local_backend_t local_backend_t; - -#include -#include - -/** - * @brief An in-memory backend to store configurations. - * - * The local_backend_t stores the configuration in a simple list. It - * implements both, backend_t and writeable_backend_t. - * - * @b Constructors: - * - local_backend_create() - * - * @ingroup backends - */ -struct local_backend_t { - - /** - * Implements writable_backend_t interface - */ - writeable_backend_t backend; -}; - -/** - * @brief Create a backend_t instance implemented as local backend. - * - * @return backend instance - * - * @ingroup backends - */ -backend_t *backend_create(void); - -#endif /* LOCAL_BACKEND_H_ */ - diff --git a/src/charon/config/backends/sqlite_backend.c b/src/charon/config/backends/sqlite_backend.c deleted file mode 100644 index e1c96c870..000000000 --- a/src/charon/config/backends/sqlite_backend.c +++ /dev/null @@ -1,309 +0,0 @@ -/** - * @file sqlite_backend.c - * - * @brief Implementation of sqlite_backend_t. - * - */ - -/* - * Copyright (C) 2006 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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 -#include - -#include "sqlite_backend.h" - -#include - - -typedef struct private_sqlite_backend_t private_sqlite_backend_t; - -/** - * Private data of an sqlite_backend_t object - */ -struct private_sqlite_backend_t { - - /** - * Public part - */ - sqlite_backend_t public; - - /** - * SQLite database handle - */ - sqlite3 *db; -}; - -/** - * implements backen_t.get_ike_cfg. - */ -static ike_cfg_t *get_ike_cfg(private_sqlite_backend_t *this, - host_t *my_host, host_t *other_host) -{ - return NULL; -} - -/** - * add TS with child "id" to "child_cfg" - */ -static void add_ts(private_sqlite_backend_t *this, child_cfg_t *child_cfg, int id) -{ - sqlite3_stmt *stmt; - - if (sqlite3_prepare_v2(this->db, - "SELECT type, protocol, start_addr, end_addr, start_port, end_port, kind " - "FROM traffic_selectors, child_config_traffic_selector " - "ON traffic_selectors.oid = child_config_traffic_selector.traffic_selector " - "WHERE child_config_traffic_selector.child_cfg = ?;", - -1, &stmt, NULL) == SQLITE_OK && - sqlite3_bind_int(stmt, 1, id) == SQLITE_OK) - { - while (sqlite3_step(stmt) == SQLITE_ROW) - { - traffic_selector_t *ts; - bool local = FALSE; - enum { - TS_LOCAL = 0, - TS_REMOTE = 1, - TS_LOCAL_DYNAMIC = 2, - TS_REMOTE_DYNAMIC = 3, - } kind; - - kind = sqlite3_column_int(stmt, 6); - switch (kind) - { - case TS_LOCAL: - local = TRUE; - /* FALL */ - case TS_REMOTE: - ts = traffic_selector_create_from_string( - sqlite3_column_int(stmt, 1), /* protocol */ - sqlite3_column_int(stmt, 0), /* type */ - (char*)sqlite3_column_text(stmt, 2), /* from addr */ - sqlite3_column_int(stmt, 4), /* from port */ - (char*)sqlite3_column_text(stmt, 3), /* to addr */ - sqlite3_column_int(stmt, 5)); /* to port */ - break; - case TS_LOCAL_DYNAMIC: - local = TRUE; - /* FALL */ - case TS_REMOTE_DYNAMIC: - ts = traffic_selector_create_dynamic( - sqlite3_column_int(stmt, 1), /* protocol */ - sqlite3_column_int(stmt, 0), /* type */ - sqlite3_column_int(stmt, 4), /* from port */ - sqlite3_column_int(stmt, 5)); /* to port */ - break; - default: - continue; - } - if (ts) - { - child_cfg->add_traffic_selector(child_cfg, local, ts); - } - } - } - sqlite3_finalize(stmt); -} - -/** - * add childrens belonging to config with "id" to "peer_cfg" - */ -static void add_children(private_sqlite_backend_t *this, peer_cfg_t *peer_cfg, int id) -{ - sqlite3_stmt *stmt; - child_cfg_t *child_cfg; - - if (sqlite3_prepare_v2(this->db, - "SELECT child_configs.oid, name, updown, hostaccess, mode, " - "lifetime, rekeytime, jitter " - "FROM child_configs, peer_config_child_config " - "ON child_configs.oid = peer_config_child_config.child_cfg " - "WHERE peer_config_child_config.peer_cfg = ?;", - -1, &stmt, NULL) == SQLITE_OK && - sqlite3_bind_int(stmt, 1, id) == SQLITE_OK) - { - while (sqlite3_step(stmt) == SQLITE_ROW) - { - child_cfg = child_cfg_create( - (char*)sqlite3_column_text(stmt, 1), /* name */ - sqlite3_column_int(stmt, 5), /* lifetime */ - sqlite3_column_int(stmt, 6), /* rekeytime */ - sqlite3_column_int(stmt, 7), /* jitter */ - (char*)sqlite3_column_text(stmt, 2), /* updown */ - sqlite3_column_int(stmt, 3), /* hostaccess */ - sqlite3_column_int(stmt, 4)); /* mode */ - add_ts(this, child_cfg, sqlite3_column_int(stmt, 0)); - child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP)); - peer_cfg->add_child_cfg(peer_cfg, child_cfg); - } - } - sqlite3_finalize(stmt); -} - -/** - * processing function for get_peer_cfg and get_peer_cfg_by_name - */ -static peer_cfg_t *process_peer_cfg_row(private_sqlite_backend_t *this, - sqlite3_stmt *stmt) -{ - host_t *local_host, *remote_host, *local_vip = NULL, *remote_vip = NULL; - identification_t *local_id, *remote_id; - peer_cfg_t *peer_cfg; - ike_cfg_t *ike_cfg; - - local_host = host_create_from_string((char*)sqlite3_column_text(stmt, 17), IKEV2_UDP_PORT); - remote_host = host_create_from_string((char*)sqlite3_column_text(stmt, 18), IKEV2_UDP_PORT); - if (sqlite3_column_text(stmt, 15)) - { - local_vip = host_create_from_string((char*)sqlite3_column_text(stmt, 15), 0); - } - if (sqlite3_column_text(stmt, 16)) - { - remote_vip = host_create_from_string((char*)sqlite3_column_text(stmt, 16), 0); - } - local_id = identification_create_from_string((char*)sqlite3_column_text(stmt, 2)); - remote_id = identification_create_from_string((char*)sqlite3_column_text(stmt, 3)); - if (local_host && remote_host && local_id && remote_id) - { - ike_cfg = ike_cfg_create(sqlite3_column_int(stmt, 19), FALSE, - local_host, remote_host); - ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE)); - peer_cfg = peer_cfg_create( - (char*)sqlite3_column_text(stmt, 1), /* name */ - 2, ike_cfg, local_id, remote_id, NULL, NULL, linked_list_create(), - sqlite3_column_int(stmt, 4), /* cert_policy */ - sqlite3_column_int(stmt, 5), /* auth_method */ - sqlite3_column_int(stmt, 6), 0 /* eap_type, vendor */ - sqlite3_column_int(stmt, 7), /* keyingtries */ - sqlite3_column_int(stmt, 8), /* rekey_time */ - sqlite3_column_int(stmt, 9), /* reauth_time */ - sqlite3_column_int(stmt, 10), /* jitter_time */ - sqlite3_column_int(stmt, 11), /* over_time */ - sqlite3_column_int(stmt, 14), /* mobike */ - sqlite3_column_int(stmt, 12), /* dpd_delay */ - sqlite3_column_int(stmt, 13), /* dpd_action */ - local_vip, remote_vip, FALSE, NULL, NULL); - add_children(this, peer_cfg, sqlite3_column_int(stmt, 0)); - return peer_cfg; - } - - DESTROY_IF(local_host); - DESTROY_IF(remote_host); - DESTROY_IF(local_id); - DESTROY_IF(remote_id); - DESTROY_IF(local_vip); - DESTROY_IF(remote_vip); - return NULL; -} - -/** - * implements backend_t.get_peer_cfg. - */ -static peer_cfg_t *get_peer_cfg(private_sqlite_backend_t *this, - identification_t *my_id, identification_t *other_id, - ca_info_t *other_ca_info) -{ - sqlite3_stmt *stmt; - char local[256], remote[256]; - peer_cfg_t *peer_cfg = NULL; - - snprintf(local, sizeof(local), "%D", my_id); - snprintf(remote, sizeof(remote), "%D", other_id); - - if (sqlite3_prepare_v2(this->db, - "SELECT peer_configs.oid, name, local_id, remote_id, cert_policy, " - "auth_method, eap_type, keyingtries, " - "rekey_time, reauth_time, jitter_time, over_time, " - "dpd_delay, dpd_action, mobike, local_vip, remote_vip, " - "local, remote, certreq " - "FROM peer_configs, ike_configs " - "ON peer_configs.ike_cfg = ike_configs.oid " - "WHERE local_id = ? and remote_id = ?;", -1, &stmt, NULL) == SQLITE_OK && - sqlite3_bind_text(stmt, 1, local, -1, SQLITE_STATIC) == SQLITE_OK && - sqlite3_bind_text(stmt, 2, remote, -1, SQLITE_STATIC) == SQLITE_OK && - sqlite3_step(stmt) == SQLITE_ROW) - { - peer_cfg = process_peer_cfg_row(this, stmt); - } - sqlite3_finalize(stmt); - return peer_cfg; -} - -/** - * implements backend_t.get_peer_cfg_by_name. - */ -static peer_cfg_t *get_peer_cfg_by_name(private_sqlite_backend_t *this, char *name) -{ - sqlite3_stmt *stmt; - peer_cfg_t *peer_cfg = NULL; - - if (sqlite3_prepare_v2(this->db, - "SELECT peer_configs.oid, name, local_id, remote_id, cert_policy, " - "auth_method, eap_type, keyingtries, lifetime, rekeytime, jitter, " - "dpd_delay, dpd_action, reauth, mobike, local_vip, remote_vip, " - "local, remote, certreq " - "FROM peer_configs, ike_configs " - "ON peer_configs.ike_cfg = ike_configs.oid " - "WHERE name = ? ;", -1, &stmt, NULL) == SQLITE_OK && - sqlite3_bind_text(stmt, 1, name, -1, SQLITE_STATIC) == SQLITE_OK && - sqlite3_step(stmt) == SQLITE_ROW) - { - peer_cfg = process_peer_cfg_row(this, stmt); - } - sqlite3_finalize(stmt); - return peer_cfg; -} - -/** - * Implementation of backend_t.is_writable. - */ -static bool is_writeable(private_sqlite_backend_t *this) -{ - return FALSE; -} - -/** - * Implementation of backend_t.destroy. - */ -static void destroy(private_sqlite_backend_t *this) -{ - sqlite3_close(this->db); - free(this); -} - -/** - * Described in header. - */ -backend_t *backend_create(void) -{ - private_sqlite_backend_t *this = malloc_thing(private_sqlite_backend_t); - - this->public.backend.get_ike_cfg = (ike_cfg_t* (*)(backend_t*, host_t*, host_t*))get_ike_cfg; - this->public.backend.get_peer_cfg = (peer_cfg_t* (*)(backend_t*,identification_t*,identification_t*,ca_info_t*))get_peer_cfg; - this->public.backend.get_peer_cfg_by_name = (peer_cfg_t* (*)(backend_t*,char*))get_peer_cfg_by_name; - this->public.backend.is_writeable = (bool(*) (backend_t*))is_writeable; - this->public.backend.destroy = (void (*)(backend_t*))destroy; - - if (sqlite3_open(IPSEC_DIR "/manager.db", &this->db) != SQLITE_OK) - { - DBG1(DBG_CFG, "opening SQLite database '" IPSEC_DIR "/manager.db' failed."); - destroy(this); - return NULL; - } - - return &this->public.backend; -} - diff --git a/src/charon/config/backends/sqlite_backend.h b/src/charon/config/backends/sqlite_backend.h deleted file mode 100644 index 4bc146583..000000000 --- a/src/charon/config/backends/sqlite_backend.h +++ /dev/null @@ -1,58 +0,0 @@ -/** - * @file sqlite_backend.h - * - * @brief Interface of sqlite_backend_t. - * - */ - -/* - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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 SQLITE_BACKEND_H_ -#define SQLITE_BACKEND_H_ - -typedef struct sqlite_backend_t sqlite_backend_t; - -#include - -#include "backend.h" - -/** - * @brief An SQLite based configuration backend. - * - * @b Constructors: - * - sqlite_backend_create() - * - * @ingroup backends - */ -struct sqlite_backend_t { - - /** - * Implements backend_t interface - */ - backend_t backend; -}; - -/** - * @brief Create a backend_t instance implemented as sqlite backend. - * - * @return backend instance - * - * @ingroup backends - */ -backend_t *backend_create(void); - -#endif /* SQLITE_BACKEND_H_ */ - diff --git a/src/charon/config/backends/writeable_backend.h b/src/charon/config/backends/writeable_backend.h deleted file mode 100644 index ea62f62c9..000000000 --- a/src/charon/config/backends/writeable_backend.h +++ /dev/null @@ -1,64 +0,0 @@ -/** - * @file writeable_backend.h - * - * @brief Interface of writeable_backend_t. - * - */ - -/* - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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 WRITEABLE_BACKEND_H_ -#define WRITEABLE_BACKEND_H_ - -typedef struct writeable_backend_t writeable_backend_t; - -#include -#include - -/** - * @brief A writeable backend extends backend_t by modification functions. - * - * @b Constructors: - * - writeable_backend_create() - * - * @ingroup backends - */ -struct writeable_backend_t { - - /** - * Implements backend_t interface - */ - backend_t backend; - - /** - * @brief Add a peer_config to the backend. - * - * @param this calling object - * @param config peer_config to add to the backend - */ - void (*add_cfg)(writeable_backend_t *this, peer_cfg_t *config); - - /** - * @brief Create an iterator over all peer configs. - * - * @param this calling object - * @return iterator over peer configs - */ - iterator_t* (*create_iterator)(writeable_backend_t *this); -}; - -#endif /* WRITEABLE_BACKEND_H_ */ - diff --git a/src/charon/config/child_cfg.c b/src/charon/config/child_cfg.c index 5827b4f61..b4bc95707 100644 --- a/src/charon/config/child_cfg.c +++ b/src/charon/config/child_cfg.c @@ -1,10 +1,3 @@ -/** - * @file child_cfg.c - * - * @brief Implementation of child_cfg_t. - * - */ - /* * Copyright (C) 2005-2007 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,9 +12,10 @@ * 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. + * + * $Id$ */ - #include "child_cfg.h" #include diff --git a/src/charon/config/child_cfg.h b/src/charon/config/child_cfg.h index e1a6553b4..c7401d623 100644 --- a/src/charon/config/child_cfg.h +++ b/src/charon/config/child_cfg.h @@ -1,10 +1,3 @@ -/** - * @file child_cfg.h - * - * @brief Interface of child_cfg_t. - * - */ - /* * Copyright (C) 2005-2007 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup child_cfg child_cfg + * @{ @ingroup config */ #ifndef CHILD_CFG_H_ @@ -32,11 +32,9 @@ typedef struct child_cfg_t child_cfg_t; #include /** - * @brief Mode of an CHILD_SA. + * Mode of an CHILD_SA. * * These are equal to those defined in XFRM, so don't change. - * - * @ingroup config */ enum mode_t { /** transport mode, no inner address */ @@ -53,7 +51,7 @@ enum mode_t { extern enum_name_t *mode_names; /** - * @brief A child_cfg_t defines the config template for a CHILD_SA. + * A child_cfg_t defines the config template for a CHILD_SA. * * After creation, proposals and traffic selectors may be added to the config. * A child_cfg object is referenced multiple times, and is not thread save. @@ -62,51 +60,42 @@ extern enum_name_t *mode_names; * A reference counter handles the number of references hold to this config. * * @see peer_cfg_t to get an overview over the configurations. - * - * @b Constructors: - * - child_cfg_create() - * - * @ingroup config */ struct child_cfg_t { /** - * @brief Get the name of the child_cfg. + * Get the name of the child_cfg. * - * @param this calling object * @return child_cfg's name */ char *(*get_name) (child_cfg_t *this); /** - * @brief Add a proposal to the list. + * Add a proposal to the list. * * The proposals are stored by priority, first added * is the most prefered. * After add, proposal is owned by child_cfg. * - * @param this calling object * @param proposal proposal to add */ void (*add_proposal) (child_cfg_t *this, proposal_t *proposal); /** - * @brief Get the list of proposals for the CHILD_SA. + * Get the list of proposals for the CHILD_SA. * * Resulting list and all of its proposals must be freed after use. * - * @param this calling object * @param strip_dh TRUE strip out diffie hellman groups * @return list of proposals */ linked_list_t* (*get_proposals)(child_cfg_t *this, bool strip_dh); /** - * @brief Select a proposal from a supplied list. + * Select a proposal from a supplied list. * * Returned propsal is newly created and must be destroyed after usage. * - * @param this calling object * @param proposals list from from wich proposals are selected * @param strip_dh TRUE strip out diffie hellman groups * @return selected proposal, or NULL if nothing matches @@ -115,12 +104,11 @@ struct child_cfg_t { bool strip_dh); /** - * @brief Add a traffic selector to the config. + * Add a traffic selector to the config. * * Use the "local" parameter to add it for the local or the remote side. * After add, traffic selector is owned by child_cfg. * - * @param this calling object * @param local TRUE for local side, FALSE for remote * @param ts traffic_selector to add */ @@ -128,7 +116,7 @@ struct child_cfg_t { traffic_selector_t *ts); /** - * @brief Get a list of traffic selectors to use for the CHILD_SA. + * Get a list of traffic selectors to use for the CHILD_SA. * * The config contains two set of traffic selectors, one for the local * side, one for the remote side. @@ -139,7 +127,6 @@ struct child_cfg_t { * the "host" parameter to narrow such traffic selectors to that address. * Resulted list and its traffic selectors must be destroyed after use. * - * @param this calling object * @param local TRUE for TS on local side, FALSE for remote * @param supplied list with TS to select from, or NULL * @param host address to use for narrowing "dynamic" TS', or NULL @@ -150,23 +137,21 @@ struct child_cfg_t { host_t *host); /** - * @brief Get the updown script to run for the CHILD_SA. + * Get the updown script to run for the CHILD_SA. * - * @param this calling object * @return path to updown script */ char* (*get_updown)(child_cfg_t *this); /** - * @brief Should we allow access to the local host (gateway)? + * Should we allow access to the local host (gateway)? * - * @param this calling object * @return value of hostaccess flag */ bool (*get_hostaccess) (child_cfg_t *this); /** - * @brief Get the lifetime of a CHILD_SA. + * Get the lifetime of a CHILD_SA. * * If "rekey" is set to TRUE, a lifetime is returned before the first * rekeying should be started. If it is FALSE, the actual lifetime is @@ -174,57 +159,50 @@ struct child_cfg_t { * The rekey time automatically contains a jitter to avoid simlutaneous * rekeying. * - * @param this child_cfg * @param rekey TRUE to get rekey time * @return lifetime in seconds */ u_int32_t (*get_lifetime) (child_cfg_t *this, bool rekey); /** - * @brief Get the mode to use for the CHILD_SA. + * Get the mode to use for the CHILD_SA. * * The mode is either tunnel, transport or BEET. The peer must agree * on the method, fallback is tunnel mode. * - * @param this child_cfg * @return lifetime in seconds */ mode_t (*get_mode) (child_cfg_t *this); /** - * @brief Get the DH group to use for CHILD_SA setup. + * Get the DH group to use for CHILD_SA setup. * - * @param this calling object - * @return dh group to use + * @return dh group to use */ diffie_hellman_group_t (*get_dh_group)(child_cfg_t *this); /** - * @brief Get a new reference. + * Get a new reference. * * Get a new reference to this child_cfg by increasing * it's internal reference counter. * Do not call get_ref or any other function until you * already have a reference. Otherwise the object may get * destroyed while calling get_ref(), - * - * @param this calling object */ void (*get_ref) (child_cfg_t *this); /** - * @brief Destroys the child_cfg object. + * Destroys the child_cfg object. * * Decrements the internal reference counter and * destroys the child_cfg when it reaches zero. - * - * @param this calling object */ void (*destroy) (child_cfg_t *this); }; /** - * @brief Create a configuration template for CHILD_SA setup. + * Create a configuration template for CHILD_SA setup. * * The "name" string gets cloned. * Lifetimes are in seconds. To prevent to peers to start rekeying at the @@ -241,11 +219,9 @@ struct child_cfg_t { * @param hostaccess TRUE to allow access to the local host * @param mode mode to propose for CHILD_SA, transport, tunnel or BEET * @return child_cfg_t object - * - * @ingroup config */ child_cfg_t *child_cfg_create(char *name, u_int32_t lifetime, u_int32_t rekeytime, u_int32_t jitter, char *updown, bool hostaccess, mode_t mode); -#endif /* CHILD_CFG_H_ */ +#endif /* CHILD_CFG_H_ @} */ diff --git a/src/charon/config/credentials/local_credential_store.c b/src/charon/config/credentials/local_credential_store.c deleted file mode 100644 index 4067261c1..000000000 --- a/src/charon/config/credentials/local_credential_store.c +++ /dev/null @@ -1,1620 +0,0 @@ -/** - * @file local_credential_store.c - * - * @brief Implementation of local_credential_store_t. - * - */ - -/* - * Copyright (C) 2006 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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. - * - * RCSID $Id$ - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "local_credential_store.h" - -#define PATH_BUF 256 - -typedef struct shared_key_t shared_key_t; - -/** - * Private date of a shared_key_t object - */ -struct shared_key_t { - - /** - * shared secret - */ - chunk_t secret; - - /** - * list of peer IDs - */ - linked_list_t *peers; -}; - - -/** - * Implementation of shared_key_t.destroy. - */ -static void shared_key_destroy(shared_key_t *this) -{ - this->peers->destroy_offset(this->peers, offsetof(identification_t, destroy)); - chunk_free_randomized(&this->secret); - free(this); -} - -/** - * @brief Creates a shared_key_t object. - * - * @param shared_key shared key value - * @return shared_key_t object - * - * @ingroup config - */ -static shared_key_t *shared_key_create(chunk_t secret) -{ - shared_key_t *this = malloc_thing(shared_key_t); - - /* private data */ - this->secret = secret; - this->peers = linked_list_create(); - - return (this); -} - -/* ------------------------------------------------------------------------ * - * the ca_info_t object as a central control element - -+--------------------------------------------------------+ -| local_credential_store_t | -+--------------------------------------------------------+ - | | -+---------------------------+ +-------------------------+ -| linked_list_t *auth_certs | | linked_list_t *ca_infos | -+---------------------------+ +-------------------------+ - | | - | +------------------------- + - | | ca_info_t | - | +--------------------------+ -+---------------+ | char *name | -| x509_t |<--| x509_t *cacert | -+---------------+ | linked_list_t *attrcerts | +----------------------+ -| chunk_t keyid | | linked_list_t *certinfos |-->| certinfo_t | -+---------------+ | linked_list_t *ocspuris | +----------------------+ - | | crl_t *crl | | chunk_t serialNumber | - | | linked_list_t *crluris | | cert_status_t status | -+---------------+ | pthread_mutex_t mutex | | time_t thisUpdate | -| x509_t | +--------------------------+ | time_t nextUpdate | -+---------------+ | | bool once | -| chunk_t keyid | | +----------------------+ -+---------------+ +------------------------- + | - | | ca_info_t | +----------------------+ - | +--------------------------+ | certinfo_t | -+---------------+ | char *name | +----------------------+ -| x509_t |<--| x509_t *cacert | | chunk_t serialNumber | -+---------------+ | linked_list_t *attrcerts | | cert_status_t status | -| chunk_t keyid | | linked_list_t *certinfos | | time_t thisUpdate | -+---------------+ | linked_list_t *ocspuris | | time_t nextUpdate | - | | crl_t *crl | | bool once | - | | linked_list_t *crluris | +----------------------+ - | | pthread_mutex_t mutex; | | - | +--------------------------+ - | | - - * ------------------------------------------------------------------------ */ - -typedef struct private_local_credential_store_t private_local_credential_store_t; - -/** - * Private data of an local_credential_store_t object - */ -struct private_local_credential_store_t { - - /** - * Public part - */ - local_credential_store_t public; - - /** - * list of shared keys - */ - linked_list_t *shared_keys; - - /** - * list of EAP keys - */ - linked_list_t *eap_keys; - - /** - * list of key_entry_t's with private keys - */ - linked_list_t *private_keys; - - /** - * mutex controls access to the linked lists of secret keys - */ - pthread_mutex_t keys_mutex; - - /** - * list of X.509 certificates with public keys - */ - linked_list_t *certs; - - /** - * list of X.509 authority certificates with public keys - */ - linked_list_t *auth_certs; - - /** - * list of X.509 CA information records - */ - linked_list_t *ca_infos; - - /** - * list of X.509 attribute certificates - */ - linked_list_t *acerts; - - /** - * mutex controls access to the linked list of attribute certificates - */ - pthread_mutex_t acerts_mutex; -}; - - -/** - * Get a key from a list with shared_key_t's - */ -static status_t get_key(linked_list_t *keys, - identification_t *my_id, - identification_t *other_id, chunk_t *secret) -{ - typedef enum { - PRIO_UNDEFINED= 0x00, - PRIO_ANY_MATCH= 0x01, - PRIO_MY_MATCH= 0x02, - PRIO_OTHER_MATCH= 0x04, - } prio_t; - - prio_t best_prio = PRIO_UNDEFINED; - chunk_t found = chunk_empty; - shared_key_t *shared_key; - iterator_t *iterator; - - iterator = keys->create_iterator(keys, TRUE); - - while (iterator->iterate(iterator, (void**)&shared_key)) - { - iterator_t *peer_iterator; - identification_t *peer_id; - prio_t prio = PRIO_UNDEFINED; - - peer_iterator = shared_key->peers->create_iterator(shared_key->peers, TRUE); - - if (peer_iterator->get_count(peer_iterator) == 0) - { - /* this is a wildcard shared key */ - prio = PRIO_ANY_MATCH; - } - else - { - while (peer_iterator->iterate(peer_iterator, (void**)&peer_id)) - { - if (my_id->equals(my_id, peer_id)) - { - prio |= PRIO_MY_MATCH; - } - if (other_id->equals(other_id, peer_id)) - { - prio |= PRIO_OTHER_MATCH; - } - } - } - peer_iterator->destroy(peer_iterator); - - if (prio > best_prio) - { - best_prio = prio; - found = shared_key->secret; - } - } - iterator->destroy(iterator); - - if (best_prio == PRIO_UNDEFINED) - { - return NOT_FOUND; - } - else - { - *secret = chunk_clone(found); - return SUCCESS; - } -} - -/** - * Implementation of local_credential_store_t.get_shared_key. - */ -static status_t get_shared_key(private_local_credential_store_t *this, - identification_t *my_id, - identification_t *other_id, chunk_t *secret) -{ - status_t status; - - pthread_mutex_lock(&(this->keys_mutex)); - status = get_key(this->shared_keys, my_id, other_id, secret); - pthread_mutex_unlock(&(this->keys_mutex)); - return status; -} - -/** - * Implementation of local_credential_store_t.get_eap_key. - */ -static status_t get_eap_key(private_local_credential_store_t *this, - identification_t *my_id, - identification_t *other_id, chunk_t *secret) -{ - status_t status; - - pthread_mutex_lock(&(this->keys_mutex)); - status = get_key(this->eap_keys, my_id, other_id, secret); - pthread_mutex_unlock(&(this->keys_mutex)); - return status; -} - -/** - * Implementation of credential_store_t.get_certificate. - */ -static x509_t* get_certificate(private_local_credential_store_t *this, - identification_t *id) -{ - x509_t *found = NULL; - x509_t *current_cert; - - iterator_t *iterator = this->certs->create_iterator(this->certs, TRUE); - - while (iterator->iterate(iterator, (void**)¤t_cert)) - { - if (id->equals(id, current_cert->get_subject(current_cert)) || - current_cert->equals_subjectAltName(current_cert, id)) - { - found = current_cert; - break; - } - } - iterator->destroy(iterator); - return found; -} - -/** - * Implementation of local_credential_store_t.get_rsa_public_key. - */ -static rsa_public_key_t *get_rsa_public_key(private_local_credential_store_t *this, - identification_t *id) -{ - x509_t *cert = get_certificate(this, id); - - return (cert == NULL)? NULL:cert->get_public_key(cert); -} - -/** - * Implementation of credential_store_t.get_issuer. - */ -static ca_info_t* get_issuer(private_local_credential_store_t *this, x509_t *cert) -{ - ca_info_t *found = cert->get_ca_info(cert); - - if (found == NULL) - { - iterator_t *iterator = this->ca_infos->create_iterator(this->ca_infos, TRUE); - ca_info_t *ca_info; - - while (iterator->iterate(iterator, (void**)&ca_info)) - { - if (ca_info->is_cert_issuer(ca_info, cert)) - { - found = ca_info; - cert->set_ca_info(cert, found); - break; - } - } - iterator->destroy(iterator); - } - return found; -} - -/** - * Implementation of local_credential_store_t.has_rsa_private_key. - */ -static bool has_rsa_private_key(private_local_credential_store_t *this, rsa_public_key_t *pubkey) -{ - bool found = FALSE; - rsa_private_key_t *current; - iterator_t *iterator; - - pthread_mutex_lock(&(this->keys_mutex)); - iterator = this->private_keys->create_iterator(this->private_keys, TRUE); - - while (iterator->iterate(iterator, (void**)¤t)) - { - if (current->belongs_to(current, pubkey)) - { - found = TRUE; - break; - } - } - iterator->destroy(iterator); - pthread_mutex_unlock(&(this->keys_mutex)); - return found; -} - -/** - * Implementation of credential_store_t.get_auth_certificate. - */ -static x509_t* get_auth_certificate(private_local_credential_store_t *this, - u_int auth_flags, - identification_t *id) -{ - x509_t *found = NULL; - x509_t *current_cert; - - iterator_t *iterator = this->auth_certs->create_iterator(this->auth_certs, TRUE); - - while (iterator->iterate(iterator, (void**)¤t_cert)) - { - if (current_cert->has_authority_flag(current_cert, auth_flags) - && id->equals(id, current_cert->get_subject(current_cert))) - { - found = current_cert; - break; - } - } - iterator->destroy(iterator); - - return found; -} - -/** - * Implementation of credential_store_t.get_ca_certificate_by_keyid. - */ -static x509_t* get_ca_certificate_by_keyid(private_local_credential_store_t *this, - chunk_t keyid) -{ - x509_t *found = NULL; - x509_t *current_cert; - - iterator_t *iterator = this->auth_certs->create_iterator(this->auth_certs, TRUE); - - while (iterator->iterate(iterator, (void**)¤t_cert)) - { - rsa_public_key_t *pubkey = current_cert->get_public_key(current_cert); - - if (current_cert->has_authority_flag(current_cert, AUTH_CA) - && chunk_equals(keyid, pubkey->get_keyid(pubkey))) - { - found = current_cert; - break; - } - } - iterator->destroy(iterator); - - return found; -} - -/** - * Find an exact copy of a certificate in a linked list - */ -static x509_t* find_certificate(linked_list_t *certs, x509_t *cert) -{ - x509_t *found_cert = NULL, *current_cert; - - iterator_t *iterator = certs->create_iterator(certs, TRUE); - - while (iterator->iterate(iterator, (void**)¤t_cert)) - { - if (cert->equals(cert, current_cert)) - { - found_cert = current_cert; - break; - } - } - iterator->destroy(iterator); - - return found_cert; -} - -/** - * Adds crl and ocsp uris to the corresponding issuer info record - */ -static void add_uris(ca_info_t *issuer, x509_t *cert) -{ - iterator_t *iterator; - identification_t *uri; - - /* add any crl distribution points to the issuer ca info record */ - iterator = cert->create_crluri_iterator(cert); - - while (iterator->iterate(iterator, (void**)&uri)) - { - if (uri->get_type(uri) == ID_DER_ASN1_GN_URI) - { - issuer->add_crluri(issuer, uri->get_encoding(uri)); - } - } - iterator->destroy(iterator); - - /* add any ocsp access points to the issuer ca info record */ - iterator = cert->create_ocspuri_iterator(cert); - - while (iterator->iterate(iterator, (void**)&uri)) - { - if (uri->get_type(uri) == ID_DER_ASN1_GN_URI) - { - issuer->add_ocspuri(issuer, uri->get_encoding(uri)); - } - } - iterator->destroy(iterator); -} - -/** - * Implementation of credential_store_t.is_trusted - */ -static bool is_trusted(private_local_credential_store_t *this, const char *label, x509_t *cert) -{ - int pathlen; - time_t until = UNDEFINED_TIME; - x509_t *cert_to_be_trusted = cert; - - DBG1(DBG_CFG, "establishing trust in %s certificate:", label); - - for (pathlen = 0; pathlen < MAX_CA_PATH_LEN; pathlen++) - { - err_t ugh = NULL; - ca_info_t *issuer; - x509_t *issuer_cert; - rsa_public_key_t *issuer_public_key; - bool valid_signature; - - DBG1(DBG_CFG, "subject: '%D'", cert->get_subject(cert)); - DBG1(DBG_CFG, "issuer: '%D'", cert->get_issuer(cert)); - - ugh = cert->is_valid(cert, &until); - if (ugh != NULL) - { - DBG1(DBG_CFG, "certificate %s", ugh); - return FALSE; - } - DBG2(DBG_CFG, "certificate is valid"); - - issuer = get_issuer(this, cert); - if (issuer == NULL) - { - DBG1(DBG_CFG, "issuer not found"); - return FALSE; - } - DBG2(DBG_CFG, "issuer found"); - - issuer_cert = issuer->get_certificate(issuer); - issuer_public_key = issuer_cert->get_public_key(issuer_cert); - valid_signature = cert->verify(cert, issuer_public_key); - - if (!valid_signature) - { - DBG1(DBG_CFG, "certificate signature is invalid"); - return FALSE; - } - DBG2(DBG_CFG, "certificate signature is valid"); - - /* check if cert is a self-signed root ca */ - if (pathlen > 0 && cert->is_self_signed(cert)) - { - DBG1(DBG_CFG, "reached self-signed root ca"); - cert_to_be_trusted->set_until(cert_to_be_trusted, until); - cert_to_be_trusted->set_status(cert_to_be_trusted, CERT_GOOD); - return TRUE; - } - else - { - DBG1(DBG_CFG, "going up one step in the certificate trust chain (%d)", - pathlen + 1); - cert = issuer_cert; - } - } - DBG1(DBG_CFG, "maximum ca path length of %d levels reached", MAX_CA_PATH_LEN); - return FALSE; -} - -/** - * Implementation of credential_store_t.verify. - */ -static bool verify(private_local_credential_store_t *this, x509_t *cert, bool *found) -{ - int pathlen; - time_t until = UNDEFINED_TIME; - - x509_t *end_cert = cert; - x509_t *cert_copy = find_certificate(this->certs, end_cert); - - DBG1(DBG_CFG, "verifying end entity certificate up to trust anchor:"); - - *found = (cert_copy != NULL); - if (*found) - { - DBG2(DBG_CFG, - "end entitity certificate is already in credential store"); - } - - for (pathlen = 0; pathlen < MAX_CA_PATH_LEN; pathlen++) - { - bool valid_signature; - err_t ugh = NULL; - ca_info_t *issuer; - x509_t *issuer_cert; - rsa_public_key_t *issuer_public_key; - chunk_t keyid = cert->get_keyid(cert); - - DBG1(DBG_CFG, "subject: '%D'", cert->get_subject(cert)); - DBG1(DBG_CFG, "issuer: '%D'", cert->get_issuer(cert)); - DBG1(DBG_CFG, "keyid: %#B", &keyid); - - ugh = cert->is_valid(cert, &until); - if (ugh != NULL) - { - DBG1(DBG_CFG, "certificate %s", ugh); - return FALSE; - } - DBG2(DBG_CFG, "certificate is valid"); - - issuer = get_issuer(this, cert); - if (issuer == NULL) - { - DBG1(DBG_CFG, "issuer not found"); - return FALSE; - } - DBG2(DBG_CFG, "issuer found"); - - issuer_cert = issuer->get_certificate(issuer); - issuer_public_key = issuer_cert->get_public_key(issuer_cert); - valid_signature = cert->verify(cert, issuer_public_key); - - if (!valid_signature) - { - DBG1(DBG_CFG, "certificate signature is invalid"); - return FALSE; - } - DBG2(DBG_CFG, "certificate signature is valid"); - - /* check if cert is a self-signed root ca */ - if (pathlen > 0 && cert->is_self_signed(cert)) - { - DBG1(DBG_CFG, "reached self-signed root ca"); - - /* set the definite status and trust interval of the end entity certificate */ - end_cert->set_until(end_cert, until); - if (cert_copy) - { - cert_copy->set_status(cert_copy, end_cert->get_status(end_cert)); - cert_copy->set_until(cert_copy, until); - } - return TRUE; - } - else - { - bool strict; - time_t nextUpdate; - cert_status_t status; - certinfo_t *certinfo = certinfo_create(cert->get_serialNumber(cert)); - - if (pathlen == 0) - { - /* add any crl and ocsp uris contained in the certificate under test */ - add_uris(issuer, cert); - } - - strict = issuer->is_strict(issuer); - DBG1(DBG_CFG, "issuer %s a strict crl policy", - strict ? "enforces":"does not enforce"); - - /* first check certificate revocation using ocsp */ - status = issuer->verify_by_ocsp(issuer, certinfo, &this->public.credential_store); - - /* if ocsp service is not available then fall back to crl */ - if ((status == CERT_UNDEFINED) || (status == CERT_UNKNOWN && strict)) - { - - certinfo->set_status(certinfo, CERT_UNKNOWN); - status = issuer->verify_by_crl(issuer, certinfo, CRL_DIR); - } - - nextUpdate = certinfo->get_nextUpdate(certinfo); - cert->set_status(cert, status); - - switch (status) - { - case CERT_GOOD: - /* with strict crl policy the public key must have the same - * lifetime as the validity of the ocsp status or crl lifetime - */ - if (strict) - { - cert->set_until(cert, nextUpdate); - until = (nextUpdate < until)? nextUpdate : until; - } - - /* if status information is stale */ - if (strict && nextUpdate < time(NULL)) - { - DBG2(DBG_CFG, "certificate is good but status is stale"); - certinfo->destroy(certinfo); - return FALSE; - } - DBG1(DBG_CFG, "certificate is good"); - break; - case CERT_REVOKED: - { - time_t revocationTime = certinfo->get_revocationTime(certinfo); - DBG1(DBG_CFG, - "certificate was revoked on %T, reason: %N", - &revocationTime, crl_reason_names, - certinfo->get_revocationReason(certinfo)); - - /* set revocationTime */ - cert->set_until(cert, revocationTime); - - /* update status of end certificate in the credential store */ - if (cert_copy) - { - if (pathlen > 0) - { - cert_copy->set_status(cert_copy, CERT_UNTRUSTED); - } - else - { - cert_copy->set_status(cert_copy, CERT_REVOKED); - cert_copy->set_until(cert_copy, - certinfo->get_revocationTime(certinfo)); - } - } - certinfo->destroy(certinfo); - return FALSE; - } - case CERT_UNKNOWN: - case CERT_UNDEFINED: - default: - DBG1(DBG_CFG, "certificate status unknown"); - if (strict) - { - /* update status of end certificate in the credential store */ - if (cert_copy) - { - cert_copy->set_status(cert_copy, CERT_UNTRUSTED); - } - certinfo->destroy(certinfo); - return FALSE; - } - break; - } - certinfo->destroy(certinfo); - } - DBG1(DBG_CFG, "going up one step in the certificate trust chain (%d)", - pathlen + 1); - cert = issuer_cert; - } - DBG1(DBG_CFG, "maximum ca path length of %d levels reached", MAX_CA_PATH_LEN); - return FALSE; -} - -/** - * Implementation of local_credential_store_t.rsa_signature. - */ -static status_t rsa_signature(private_local_credential_store_t *this, - rsa_public_key_t *pubkey, - hash_algorithm_t hash_algorithm, - chunk_t data, chunk_t *signature) -{ - rsa_private_key_t *current, *key = NULL; - iterator_t *iterator; - status_t status; - chunk_t keyid = pubkey->get_keyid(pubkey); - - DBG2(DBG_IKE, "looking for RSA private key with keyid %#B...", &keyid); - pthread_mutex_lock(&(this->keys_mutex)); - - iterator = this->private_keys->create_iterator(this->private_keys, TRUE); - while (iterator->iterate(iterator, (void**)¤t)) - { - if (current->belongs_to(current, pubkey)) - { - key = current; - break; - } - } - iterator->destroy(iterator); - - if (key) - { - DBG2(DBG_IKE, " matching RSA private key found"); - status = key->build_emsa_pkcs1_signature(key, hash_algorithm, data, signature); - } - else - { - DBG1(DBG_IKE, "no RSA private key found with keyid %#B", &keyid); - status = NOT_FOUND; - } - pthread_mutex_unlock(&(this->keys_mutex)); - return status; -} - -/** - * Implementation of local_credential_store_t.verify_signature. - */ -static status_t verify_signature(private_local_credential_store_t *this, - chunk_t hash, chunk_t signature, - identification_t *id, ca_info_t **issuer_p) -{ - iterator_t *iterator = this->certs->create_iterator(this->certs, TRUE); - status_t sig_status; - x509_t *cert; - - /* default return values in case of failure */ - sig_status = NOT_FOUND; - *issuer_p = NULL; - - while (iterator->iterate(iterator, (void**)&cert)) - { - if (id->equals(id, cert->get_subject(cert)) - || cert->equals_subjectAltName(cert, id)) - { - rsa_public_key_t *public_key = cert->get_public_key(cert); - cert_status_t cert_status = cert->get_status(cert); - - DBG2(DBG_CFG, "found candidate peer certificate"); - - if (cert_status == CERT_UNDEFINED || cert->get_until(cert) < time(NULL)) - { - bool found; - - if (!verify(this, cert, &found)) - { - sig_status = VERIFY_ERROR; - DBG1(DBG_CFG, "candidate peer certificate was not successfully verified"); - continue; - } - *issuer_p = get_issuer(this, cert); - } - else - { - ca_info_t *issuer = get_issuer(this, cert); - chunk_t keyid = public_key->get_keyid(public_key); - - DBG2(DBG_CFG, "subject: '%D'", cert->get_subject(cert)); - DBG2(DBG_CFG, "issuer: '%D'", cert->get_issuer(cert)); - DBG2(DBG_CFG, "keyid: %#B", &keyid); - - if (issuer == NULL) - { - DBG1(DBG_CFG, "candidate peer certificate has no retrievable issuer"); - sig_status = NOT_FOUND; - continue; - } - if (cert_status == CERT_REVOKED || cert_status == CERT_UNTRUSTED - || ((issuer)->is_strict(issuer) && cert_status != CERT_GOOD)) - { - DBG1(DBG_CFG, "candidate peer certificate has an inacceptable status: %N", cert_status_names, cert_status); - sig_status = VERIFY_ERROR; - continue; - } - *issuer_p = issuer; - } - sig_status = public_key->verify_emsa_pkcs1_signature(public_key, HASH_UNKNOWN, hash, signature); - if (sig_status == SUCCESS) - { - DBG2(DBG_CFG, "candidate peer certificate has a matching RSA public key"); - break; - } - else - { - DBG1(DBG_CFG, "candidate peer certificate has a non-matching RSA public key"); - *issuer_p = NULL; - } - } - } - iterator->destroy(iterator); - if (sig_status == NOT_FOUND) - { - DBG1(DBG_CFG, "no candidate peer certificate found"); - } - return sig_status; -} - -/** - * Add a unique certificate to a linked list - */ -static x509_t* add_certificate(linked_list_t *certs, x509_t *cert) -{ - x509_t *found_cert = find_certificate(certs, cert); - - if (found_cert) - { - /* add the authority flags */ - found_cert->add_authority_flags(found_cert, cert->get_authority_flags(cert)); - - cert->destroy(cert); - return found_cert; - } - else - { - certs->insert_last(certs, (void*)cert); - return cert; - } -} - -/** - * Add a unique ca info record to a linked list - */ -static ca_info_t* add_ca_info(private_local_credential_store_t *this, ca_info_t *ca_info) -{ - ca_info_t *current_ca_info; - ca_info_t *found_ca_info = NULL; - - iterator_t *iterator = this->ca_infos->create_iterator(this->ca_infos, TRUE); - - while (iterator->iterate(iterator, (void**)¤t_ca_info)) - { - if (current_ca_info->equals(current_ca_info, ca_info)) - { - found_ca_info = current_ca_info; - break; - } - } - iterator->destroy(iterator); - - if (found_ca_info) - { - current_ca_info->add_info(current_ca_info, ca_info); - ca_info->destroy(ca_info); - ca_info = found_ca_info; - } - else - { - this->ca_infos->insert_last(this->ca_infos, (void*)ca_info); - } - return ca_info; -} - -/** - * Release ca info record of a given name - */ -static status_t release_ca_info(private_local_credential_store_t *this, const char *name) -{ - status_t status = NOT_FOUND; - ca_info_t *ca_info; - - iterator_t *iterator = this->ca_infos->create_iterator(this->ca_infos, TRUE); - - while (iterator->iterate(iterator, (void**)&ca_info)) - { - if (ca_info->equals_name_release_info(ca_info, name)) - { - status = SUCCESS; - break; - } - } - iterator->destroy(iterator); - - return status; -} - -/** - * Implements local_credential_store_t.add_end_certificate - */ -static x509_t* add_end_certificate(private_local_credential_store_t *this, x509_t *cert) -{ - x509_t *ret_cert = add_certificate(this->certs, cert); - - /* add crl and ocsp uris the first time the certificate is added */ - if (ret_cert == cert) - { - ca_info_t *issuer = get_issuer(this, cert); - - if (issuer) - { - add_uris(issuer, cert); - } - } - return ret_cert; -} - -/** - * Implements local_credential_store_t.add_auth_certificate - */ -static x509_t* add_auth_certificate(private_local_credential_store_t *this, x509_t *cert, u_int auth_flags) -{ - cert->add_authority_flags(cert, auth_flags); - return add_certificate(this->auth_certs, cert); -} - -/** - * Implements local_credential_store_t.create_cert_iterator - */ -static iterator_t* create_cert_iterator(private_local_credential_store_t *this) -{ - return this->certs->create_iterator(this->certs, TRUE); -} - -/** - * Implements local_credential_store_t.create_cacert_iterator - */ -static iterator_t* create_auth_cert_iterator(private_local_credential_store_t *this) -{ - return this->auth_certs->create_iterator(this->auth_certs, TRUE); -} - -/** - * Implements local_credential_store_t.create_cainfo_iterator - */ -static iterator_t* create_cainfo_iterator(private_local_credential_store_t *this) -{ - return this->ca_infos->create_iterator(this->ca_infos, TRUE); -} - -/** - * Implements local_credential_store_t.create_acert_iterator - */ -static iterator_t* create_acert_iterator(private_local_credential_store_t *this) -{ - return this->acerts->create_iterator_locked(this->acerts, &this->acerts_mutex); -} - -/** - * Implements local_credential_store_t.load_auth_certificates - */ -static void load_auth_certificates(private_local_credential_store_t *this, - u_int auth_flag, - const char* label, - const char* path) -{ - struct dirent* entry; - struct stat stb; - DIR* dir; - - DBG1(DBG_CFG, "loading %s certificates from '%s'", label, path); - - dir = opendir(path); - if (dir == NULL) - { - DBG1(DBG_CFG, "error opening %s certs directory '%s'", label, path); - return; - } - - while ((entry = readdir(dir)) != NULL) - { - char file[PATH_BUF]; - - snprintf(file, sizeof(file), "%s/%s", path, entry->d_name); - - if (stat(file, &stb) == -1) - { - continue; - } - /* try to parse all regular files */ - if (stb.st_mode & S_IFREG) - { - x509_t *cert = x509_create_from_file(file, label); - - if (cert) - { - err_t ugh = cert->is_valid(cert, NULL); - - if (ugh != NULL) - { - DBG1(DBG_CFG, "warning: %s certificate %s", label, ugh); - } - - if (auth_flag == AUTH_CA && !cert->is_ca(cert)) - { - DBG1(DBG_CFG, " CA basic constraints flag not set, cert discarded"); - cert->destroy(cert); - } - else - { - x509_t *ret_cert; - - cert->add_authority_flags(cert, auth_flag); - - ret_cert = add_certificate(this->auth_certs, cert); - - if (auth_flag == AUTH_CA && ret_cert == cert) - { - ca_info_t *ca_info = ca_info_create(NULL, cert); - - add_ca_info(this, ca_info); - } - } - } - } - } - closedir(dir); -} - -/** - * Implements local_credential_store_t.load_ca_certificates - */ -static void load_ca_certificates(private_local_credential_store_t *this) -{ - load_auth_certificates(this, AUTH_CA, "ca", CA_CERTIFICATE_DIR); - - /* add any crl and ocsp uris found in the ca certificates to the - * corresponding issuer info record. We can do this only after all - * ca certificates have been loaded and the ca hierarchy is known. - */ - { - iterator_t *iterator = this->ca_infos->create_iterator(this->ca_infos, TRUE); - ca_info_t *ca_info; - - while (iterator->iterate(iterator, (void **)&ca_info)) - { - if (ca_info->is_ca(ca_info)) - { - x509_t *cacert = ca_info->get_certificate(ca_info); - ca_info_t *issuer = get_issuer(this, cacert); - - if (issuer) - { - add_uris(issuer, cacert); - } - } - } - iterator->destroy(iterator); - } -} - -/** - * Implements local_credential_store_t.load_aa_certificates - */ -static void load_aa_certificates(private_local_credential_store_t *this) -{ - load_auth_certificates(this, AUTH_AA, "aa", AA_CERTIFICATE_DIR); -} - -/** - * Add a unique attribute certificate to a linked list - */ -static void add_attr_certificate(private_local_credential_store_t *this, x509ac_t *cert) -{ - iterator_t *iterator; - x509ac_t *current_cert; - bool found = FALSE; - - pthread_mutex_lock(&(this->acerts_mutex)); - iterator = this->acerts->create_iterator(this->acerts, TRUE); - - while (iterator->iterate(iterator, (void **)¤t_cert)) - { - if (cert->equals_holder(cert, current_cert)) - { - if (cert->is_newer(cert, current_cert)) - { - iterator->replace(iterator, NULL, (void *)cert); - current_cert->destroy(current_cert); - DBG1(DBG_CFG, " this attr cert is newer - existing attr cert replaced"); - } - else - { - cert->destroy(cert); - DBG1(DBG_CFG, " this attr cert is not newer - existing attr cert retained"); - } - found = TRUE; - break; - } - } - iterator->destroy(iterator); - - if (!found) - { - this->acerts->insert_last(this->acerts, (void *)cert); - } - pthread_mutex_unlock(&(this->acerts_mutex)); -} - -/** - * Implements local_credential_store_t.load_attr_certificates - */ -static void load_attr_certificates(private_local_credential_store_t *this) -{ - struct dirent* entry; - struct stat stb; - DIR* dir; - - const char *path = ATTR_CERTIFICATE_DIR; - - DBG1(DBG_CFG, "loading attribute certificates from '%s'", path); - - dir = opendir(ATTR_CERTIFICATE_DIR); - if (dir == NULL) - { - DBG1(DBG_CFG, "error opening attribute certs directory '%s'", path); - return; - } - - while ((entry = readdir(dir)) != NULL) - { - char file[PATH_BUF]; - - snprintf(file, sizeof(file), "%s/%s", path, entry->d_name); - - if (stat(file, &stb) == -1) - { - continue; - } - /* try to parse all regular files */ - if (stb.st_mode & S_IFREG) - { - x509ac_t *cert = x509ac_create_from_file(file); - - if (cert) - { - err_t ugh = cert->is_valid(cert, NULL); - - if (ugh != NULL) - { - DBG1(DBG_CFG, "warning: attribute certificate %s", ugh); - } - add_attr_certificate(this, cert); - } - } - } - closedir(dir); - - -} - -/** - * Implements local_credential_store_t.load_ocsp_certificates - */ -static void load_ocsp_certificates(private_local_credential_store_t *this) -{ - load_auth_certificates(this, AUTH_OCSP, "ocsp", OCSP_CERTIFICATE_DIR); -} - -/** - * Add the latest crl to the issuing ca - */ -static void add_crl(private_local_credential_store_t *this, crl_t *crl, const char *path) -{ - iterator_t *iterator = this->ca_infos->create_iterator(this->ca_infos, TRUE); - ca_info_t *ca_info; - bool found = FALSE; - - while (iterator->iterate(iterator, (void**)&ca_info)) - { - if (ca_info->is_ca(ca_info) && ca_info->is_crl_issuer(ca_info, crl)) - { - char buffer[BUF_LEN]; - chunk_t uri = { buffer, 7 + strlen(path) }; - - ca_info->add_crl(ca_info, crl); - if (uri.len < BUF_LEN) - { - snprintf(buffer, BUF_LEN, "file://%s", path); - ca_info->add_crluri(ca_info, uri); - } - found = TRUE; - break; - } - } - iterator->destroy(iterator); - - if (!found) - { - crl->destroy(crl); - DBG2(DBG_CFG, " no issuing ca found for this crl - discarded"); - } -} - -/** - * Implements local_credential_store_t.load_crls - */ -static void load_crls(private_local_credential_store_t *this) -{ - struct dirent* entry; - struct stat stb; - DIR* dir; - crl_t *crl; - - DBG1(DBG_CFG, "loading crls from '%s'", CRL_DIR); - - dir = opendir(CRL_DIR); - if (dir == NULL) - { - DBG1(DBG_CFG, "error opening crl directory '%s'", CRL_DIR); - return; - } - - while ((entry = readdir(dir)) != NULL) - { - char file[PATH_BUF]; - - snprintf(file, sizeof(file), "%s/%s", CRL_DIR, entry->d_name); - - if (stat(file, &stb) == -1) - { - continue; - } - /* try to parse all regular files */ - if (stb.st_mode & S_IFREG) - { - crl = crl_create_from_file(file); - if (crl) - { - DBG1(DBG_CFG, " crl is %s", crl->is_valid(crl)? "valid":"stale"); - add_crl(this, crl, file); - } - } - } - closedir(dir); -} - -/** - * Convert a string of characters into a binary secret - * A string between single or double quotes is treated as ASCII characters - * A string prepended by 0x is treated as HEX and prepended by 0s as Base64 - */ -static err_t extract_secret(chunk_t *secret, chunk_t *line) -{ - chunk_t raw_secret; - char delimiter = ' '; - bool quotes = FALSE; - - if (!eat_whitespace(line)) - { - return "missing secret"; - } - - if (*line->ptr == '\'' || *line->ptr == '"') - { - quotes = TRUE; - delimiter = *line->ptr; - line->ptr++; line->len--; - } - - if (!extract_token(&raw_secret, delimiter, line)) - { - if (delimiter == ' ') - { - raw_secret = *line; - } - else - { - return "missing second delimiter"; - } - } - - if (quotes) - { - /* treat as an ASCII string */ - *secret = chunk_clone(raw_secret); - } - else - { - size_t len; - err_t ugh; - - /* secret converted to binary form doesn't use more space than the raw_secret */ - *secret = chunk_alloc(raw_secret.len); - - /* convert from HEX or Base64 to binary */ - ugh = ttodata(raw_secret.ptr, raw_secret.len, 0, secret->ptr, secret->len, &len); - - if (ugh != NULL) - { - chunk_free_randomized(secret); - return ugh; - } - secret->len = len; - } - return NULL; -} - -/** - * Implements local_credential_store_t.load_secrets - */ -static void load_secrets(private_local_credential_store_t *this, bool reload) -{ - FILE *fd = fopen(SECRETS_FILE, "r"); - - if (fd) - { - size_t bytes; - int line_nr = 0; - chunk_t chunk, src, line; - - DBG1(DBG_CFG, "%sloading secrets from \"%s\"", - reload? "re":"", SECRETS_FILE); - - fseek(fd, 0, SEEK_END); - chunk.len = ftell(fd); - rewind(fd); - chunk.ptr = malloc(chunk.len); - bytes = fread(chunk.ptr, 1, chunk.len, fd); - fclose(fd); - src = chunk; - - pthread_mutex_lock(&(this->keys_mutex)); - if (reload) - { - DBG1(DBG_CFG, " forgetting old secrets"); - this->private_keys->destroy_offset(this->private_keys, - offsetof(rsa_private_key_t, destroy)); - this->private_keys = linked_list_create(); - - this->shared_keys->destroy_function(this->shared_keys, - (void*)shared_key_destroy); - this->shared_keys = linked_list_create(); - - this->eap_keys->destroy_function(this->eap_keys, - (void*)shared_key_destroy); - this->eap_keys = linked_list_create(); - } - - while (fetchline(&src, &line)) - { - chunk_t ids, token; - bool is_eap = FALSE; - - line_nr++; - - if (!eat_whitespace(&line)) - { - continue; - } - if (!extract_last_token(&ids, ':', &line)) - { - DBG1(DBG_CFG, "line %d: missing ':' separator", line_nr); - goto error; - } - /* NULL terminate the ids string by replacing the : separator */ - *(ids.ptr + ids.len) = '\0'; - - if (!eat_whitespace(&line) || !extract_token(&token, ' ', &line)) - { - DBG1(DBG_CFG, "line %d: missing token", line_nr); - goto error; - } - if (match("RSA", &token)) - { - char path[PATH_BUF]; - chunk_t filename; - chunk_t secret = chunk_empty; - chunk_t *passphrase = NULL; - - rsa_private_key_t *key; - - err_t ugh = extract_value(&filename, &line); - - if (ugh != NULL) - { - DBG1(DBG_CFG, "line %d: %s", line_nr, ugh); - goto error; - } - if (filename.len == 0) - { - DBG1(DBG_CFG, "line %d: empty filename", line_nr); - goto error; - } - if (*filename.ptr == '/') - { - /* absolute path name */ - snprintf(path, sizeof(path), "%.*s", filename.len, filename.ptr); - } - else - { - /* relative path name */ - snprintf(path, sizeof(path), "%s/%.*s", PRIVATE_KEY_DIR, - filename.len, filename.ptr); - } - - /* check for optional passphrase */ - if (eat_whitespace(&line)) - { - ugh = extract_secret(&secret, &line); - if (ugh != NULL) - { - DBG1(DBG_CFG, "line %d: malformed passphrase: %s", line_nr, ugh); - goto error; - } - if (secret.len > 0) - passphrase = &secret; - } - key = rsa_private_key_create_from_file(path, passphrase); - if (key) - { - this->private_keys->insert_last(this->private_keys, (void*)key); - } - chunk_free_randomized(&secret); - } - else if ( match("PSK", &token) || - ((match("EAP", &token) || match("XAUTH", &token)) && (is_eap = TRUE))) - { - shared_key_t *shared_key; - chunk_t secret = chunk_empty; - - err_t ugh = extract_secret(&secret, &line); - if (ugh != NULL) - { - DBG1(DBG_CFG, "line %d: malformed secret: %s", line_nr, ugh); - goto error; - } - - DBG1(DBG_CFG, " loading %s key for %s", - is_eap ? "EAP" : "shared", - ids.len > 0 ? (char*)ids.ptr : "%any"); - - DBG4(DBG_CFG, " secret:", secret); - - shared_key = shared_key_create(secret); - if (is_eap) - { - this->eap_keys->insert_last(this->eap_keys, (void*)shared_key); - } - else - { - this->shared_keys->insert_last(this->shared_keys, (void*)shared_key); - } - while (ids.len > 0) - { - chunk_t id; - identification_t *peer_id; - - ugh = extract_value(&id, &ids); - if (ugh != NULL) - { - DBG1(DBG_CFG, "line %d: %s", line_nr, ugh); - goto error; - } - if (id.len == 0) - { - continue; - } - - /* NULL terminate the ID string */ - *(id.ptr + id.len) = '\0'; - - peer_id = identification_create_from_string(id.ptr); - if (peer_id == NULL) - { - DBG1(DBG_CFG, "line %d: malformed ID: %s", line_nr, id.ptr); - goto error; - } - - if (peer_id->get_type(peer_id) == ID_ANY) - { - peer_id->destroy(peer_id); - continue; - } - shared_key->peers->insert_last(shared_key->peers, (void*)peer_id); - } - } - else if (match("PIN", &token)) - { - - } - else - { - DBG1(DBG_CFG, "line %d: token must be either " - "RSA, PSK, EAP, or PIN", line_nr, token.len); - goto error; - } - } -error: - chunk_free_randomized(&chunk); - pthread_mutex_unlock(&(this->keys_mutex)); - } - else - { - DBG1(DBG_CFG, "could not open file '%s': %s", SECRETS_FILE, - strerror(errno)); - } -} - -/** - * Implementation of local_credential_store_t.destroy. - */ -static void destroy(private_local_credential_store_t *this) -{ - this->certs->destroy_offset(this->certs, offsetof(x509_t, destroy)); - this->auth_certs->destroy_offset(this->auth_certs, offsetof(x509_t, destroy)); - this->ca_infos->destroy_offset(this->ca_infos, offsetof(ca_info_t, destroy)); - - pthread_mutex_lock(&(this->acerts_mutex)); - this->acerts->destroy_offset(this->acerts, offsetof(x509ac_t, destroy)); - pthread_mutex_unlock(&(this->acerts_mutex)); - - pthread_mutex_lock(&(this->keys_mutex)); - this->private_keys->destroy_offset(this->private_keys, offsetof(rsa_private_key_t, destroy)); - this->shared_keys->destroy_function(this->shared_keys, (void*)shared_key_destroy); - this->eap_keys->destroy_function(this->eap_keys, (void*)shared_key_destroy); - pthread_mutex_unlock(&(this->keys_mutex)); - - free(this); -} - -/** - * Described in header. - */ -local_credential_store_t * local_credential_store_create(void) -{ - private_local_credential_store_t *this = malloc_thing(private_local_credential_store_t); - - /* public functions */ - this->public.credential_store.get_shared_key = (status_t (*) (credential_store_t*,identification_t*,identification_t*,chunk_t*))get_shared_key; - this->public.credential_store.get_eap_key = (status_t (*) (credential_store_t*,identification_t*,identification_t*,chunk_t*))get_eap_key; - this->public.credential_store.get_rsa_public_key = (rsa_public_key_t*(*)(credential_store_t*,identification_t*))get_rsa_public_key; - this->public.credential_store.has_rsa_private_key = (bool (*) (credential_store_t*,rsa_public_key_t*))has_rsa_private_key; - this->public.credential_store.get_certificate = (x509_t* (*) (credential_store_t*,identification_t*))get_certificate; - this->public.credential_store.get_auth_certificate = (x509_t* (*) (credential_store_t*,u_int,identification_t*))get_auth_certificate; - this->public.credential_store.get_ca_certificate_by_keyid = (x509_t* (*) (credential_store_t*,chunk_t))get_ca_certificate_by_keyid; - this->public.credential_store.get_issuer = (ca_info_t* (*) (credential_store_t*,x509_t*))get_issuer; - this->public.credential_store.is_trusted = (bool (*) (credential_store_t*,const char*,x509_t*))is_trusted; - this->public.credential_store.rsa_signature = (status_t (*) (credential_store_t*,rsa_public_key_t*,hash_algorithm_t,chunk_t,chunk_t*))rsa_signature; - this->public.credential_store.verify_signature = (status_t (*) (credential_store_t*,chunk_t,chunk_t,identification_t*,ca_info_t**))verify_signature; - this->public.credential_store.verify = (bool (*) (credential_store_t*,x509_t*,bool*))verify; - this->public.credential_store.add_end_certificate = (x509_t* (*) (credential_store_t*,x509_t*))add_end_certificate; - this->public.credential_store.add_auth_certificate = (x509_t* (*) (credential_store_t*,x509_t*,u_int))add_auth_certificate; - this->public.credential_store.add_ca_info = (ca_info_t* (*) (credential_store_t*,ca_info_t*))add_ca_info; - this->public.credential_store.release_ca_info = (status_t (*) (credential_store_t*,const char*))release_ca_info; - this->public.credential_store.create_cert_iterator = (iterator_t* (*) (credential_store_t*))create_cert_iterator; - this->public.credential_store.create_auth_cert_iterator = (iterator_t* (*) (credential_store_t*))create_auth_cert_iterator; - this->public.credential_store.create_cainfo_iterator = (iterator_t* (*) (credential_store_t*))create_cainfo_iterator; - this->public.credential_store.create_acert_iterator = (iterator_t* (*) (credential_store_t*))create_acert_iterator; - this->public.credential_store.load_ca_certificates = (void (*) (credential_store_t*))load_ca_certificates; - this->public.credential_store.load_aa_certificates = (void (*) (credential_store_t*))load_aa_certificates; - this->public.credential_store.load_attr_certificates = (void (*) (credential_store_t*))load_attr_certificates; - this->public.credential_store.load_ocsp_certificates = (void (*) (credential_store_t*))load_ocsp_certificates; - this->public.credential_store.load_crls = (void (*) (credential_store_t*))load_crls; - this->public.credential_store.load_secrets = (void (*) (credential_store_t*,bool))load_secrets; - this->public.credential_store.destroy = (void (*) (credential_store_t*))destroy; - - /* initialize the mutexes */ - pthread_mutex_init(&(this->keys_mutex), NULL); - pthread_mutex_init(&(this->acerts_mutex), NULL); - - /* private variables */ - this->shared_keys = linked_list_create(); - this->eap_keys = linked_list_create(); - this->private_keys = linked_list_create(); - this->certs = linked_list_create(); - this->auth_certs = linked_list_create(); - this->ca_infos = linked_list_create(); - this->acerts = linked_list_create(); - - return (&this->public); -} diff --git a/src/charon/config/credentials/local_credential_store.h b/src/charon/config/credentials/local_credential_store.h deleted file mode 100644 index 87a12663a..000000000 --- a/src/charon/config/credentials/local_credential_store.h +++ /dev/null @@ -1,63 +0,0 @@ -/** - * @file local_credential_store.h - * - * @brief Interface of local_credential_store_t. - * - */ - -/* - * Copyright (C) 2006 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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 LOCAL_CREDENTIAL_H_ -#define LOCAL_CREDENTIAL_H_ - -typedef struct local_credential_store_t local_credential_store_t; - -#include -#include -#include - - -/** - * @brief A credential_store_t implementation using simple credentail lists. - * - * The local_credential_store_t class implements the credential_store_t interface - * as simple as possible. The credentials are stored in lists, and are loaded from - * files on the disk. - * Shared secret are not handled yet, so get_shared_secret always returns NOT_FOUND. - * - * @b Constructors: - * - local_credential_store_create(bool strict) - * - * @ingroup config - */ -struct local_credential_store_t { - - /** - * Implements credential_store_t interface - */ - credential_store_t credential_store; -}; - -/** - * @brief Creates a local_credential_store_t instance. - * - * @return credential store instance. - * - * @ingroup config - */ -local_credential_store_t *local_credential_store_create(void); - -#endif /* LOCAL_CREDENTIAL_H_ */ diff --git a/src/charon/config/ike_cfg.c b/src/charon/config/ike_cfg.c index abb300aab..5c994ae3c 100644 --- a/src/charon/config/ike_cfg.c +++ b/src/charon/config/ike_cfg.c @@ -1,10 +1,3 @@ -/** - * @file ike_cfg.c - * - * @brief Implementation of ike_cfg_t. - * - */ - /* * Copyright (C) 2005-2007 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,8 @@ * 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. + * + * $Id$ */ #include "ike_cfg.h" diff --git a/src/charon/config/ike_cfg.h b/src/charon/config/ike_cfg.h index 5165d12a6..d28da9b8d 100644 --- a/src/charon/config/ike_cfg.h +++ b/src/charon/config/ike_cfg.h @@ -1,10 +1,3 @@ -/** - * @file ike_cfg.h - * - * @brief Interface of ike_cfg_t. - * - */ - /* * Copyright (C) 2005-2007 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup ike_cfg ike_cfg + * @{ @ingroup config */ #ifndef IKE_CFG_H_ @@ -34,115 +34,98 @@ typedef struct ike_cfg_t ike_cfg_t; #include /** - * @brief An ike_cfg_t defines the rules to set up an IKE_SA. + * An ike_cfg_t defines the rules to set up an IKE_SA. * * @see peer_cfg_t to get an overview over the configurations. - * - * @b Constructors: - * - ike_cfg_create() - * - * @ingroup config */ struct ike_cfg_t { /** - * @brief Get own address. + * Get own address. * - * @param this calling object * @return host information as host_t object */ host_t* (*get_my_host) (ike_cfg_t *this); /** - * @brief Get peers address. + * Get peers address. * - * @param this calling object * @return host information as host_t object */ host_t* (*get_other_host) (ike_cfg_t *this); /** - * @brief Adds a proposal to the list. + * Adds a proposal to the list. * * The first added proposal has the highest priority, the last * added the lowest. * - * @param this calling object * @param proposal proposal to add */ void (*add_proposal) (ike_cfg_t *this, proposal_t *proposal); /** - * @brief Returns a list of all supported proposals. + * Returns a list of all supported proposals. * * Returned list and its proposals must be destroyed after use. * - * @param this calling object * @return list containing all the proposals */ linked_list_t* (*get_proposals) (ike_cfg_t *this); /** - * @brief Select a proposed from suggested proposals. + * Select a proposed from suggested proposals. * * Returned proposal must be destroyed after use. * - * @param this calling object * @param proposals list of proposals to select from * @return selected proposal, or NULL if none matches. */ proposal_t *(*select_proposal) (ike_cfg_t *this, linked_list_t *proposals); /** - * @brief Should we send a certificate request in IKE_SA_INIT? + * Should we send a certificate request in IKE_SA_INIT? * - * @param this calling object * @return certificate request sending policy */ bool (*send_certreq) (ike_cfg_t *this); /** - * @brief Enforce UDP encapsulation by faking NATD notifies? + * Enforce UDP encapsulation by faking NATD notifies? * - * @param this calling object * @return TRUE to enfoce UDP encapsulation */ bool (*force_encap) (ike_cfg_t *this); /** - * @brief Get the DH group to use for IKE_SA setup. + * Get the DH group to use for IKE_SA setup. * - * @param this calling object * @return dh group to use for initialization */ diffie_hellman_group_t (*get_dh_group)(ike_cfg_t *this); /** - * @brief Get a new reference to this ike_cfg. + * Get a new reference to this ike_cfg. * * Get a new reference to this ike_cfg by increasing * it's internal reference counter. * Do not call get_ref or any other function until you * already have a reference. Otherwise the object may get * destroyed while calling get_ref(), - * - * @param this calling object */ void (*get_ref) (ike_cfg_t *this); /** - * @brief Destroys a ike_cfg_t object. + * Destroys a ike_cfg_t object. * * Decrements the internal reference counter and * destroys the ike_cfg when it reaches zero. - * - * @param this calling object */ void (*destroy) (ike_cfg_t *this); }; /** - * @brief Creates a ike_cfg_t object. + * Creates a ike_cfg_t object. * * Supplied hosts become owned by ike_cfg, the name gets cloned. * @@ -152,10 +135,8 @@ struct ike_cfg_t { * @param my_host host_t representing local address * @param other_host host_t representing remote address * @return ike_cfg_t object. - * - * @ingroup config */ ike_cfg_t *ike_cfg_create(bool certreq, bool force_encap, host_t *my_host, host_t *other_host); -#endif /* IKE_CFG_H_ */ +#endif /* IKE_CFG_H_ @} */ diff --git a/src/charon/config/peer_cfg.c b/src/charon/config/peer_cfg.c index 0b5d391c4..1547f53aa 100644 --- a/src/charon/config/peer_cfg.c +++ b/src/charon/config/peer_cfg.c @@ -1,10 +1,3 @@ -/** - * @file peer_cfg.c - * - * @brief Implementation of peer_cfg_t. - * - */ - /* * Copyright (C) 2007 Tobias Brunner * Copyright (C) 2005-2007 Martin Willi @@ -20,6 +13,8 @@ * 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. + * + * $Id$ */ #include @@ -29,7 +24,6 @@ #include #include -#include ENUM(cert_policy_names, CERT_ALWAYS_SEND, CERT_NEVER_SEND, "CERT_ALWAYS_SEND", @@ -96,21 +90,6 @@ struct private_peer_cfg_t { */ identification_t *other_id; - /** - * we have a cert issued by this CA - */ - identification_t *my_ca; - - /** - * we require the other end to have a cert issued by this CA - */ - identification_t *other_ca; - - /** - * we require the other end to belong to at least one group - */ - linked_list_t *groups; - /** * should we send a certificate */ @@ -180,6 +159,11 @@ struct private_peer_cfg_t { * virtual IP to use remotly */ host_t *other_virtual_ip; + + /** + * required authorization constraints + */ + auth_info_t *auth; #ifdef P2P /** @@ -235,12 +219,26 @@ static void add_child_cfg(private_peer_cfg_t *this, child_cfg_t *child_cfg) } /** - * Implementation of peer_cfg_t.create_child_cfg_iterator. + * Implementation of peer_cfg_t.remove_child_cfg. */ -static iterator_t* create_child_cfg_iterator(private_peer_cfg_t *this) +static void remove_child_cfg(private_peer_cfg_t *this, enumerator_t *enumerator) { - return this->child_cfgs->create_iterator_locked(this->child_cfgs, - &this->mutex); + pthread_mutex_lock(&this->mutex); + this->child_cfgs->remove_at(this->child_cfgs, enumerator); + pthread_mutex_unlock(&this->mutex); +} + +/** + * Implementation of peer_cfg_t.create_child_cfg_enumerator. + */ +static enumerator_t* create_child_cfg_enumerator(private_peer_cfg_t *this) +{ + enumerator_t *enumerator; + + pthread_mutex_lock(&this->mutex); + enumerator = this->child_cfgs->create_enumerator(this->child_cfgs); + return enumerator_create_cleaner(enumerator, + (void*)pthread_mutex_unlock, &this->mutex); } /** @@ -267,10 +265,10 @@ static child_cfg_t* select_child_cfg(private_peer_cfg_t *this, host_t *my_host, host_t *other_host) { child_cfg_t *current, *found = NULL; - iterator_t *iterator; + enumerator_t *enumerator; - iterator = create_child_cfg_iterator(this); - while (iterator->iterate(iterator, (void**)¤t)) + enumerator = create_child_cfg_enumerator(this); + while (enumerator->enumerate(enumerator, ¤t)) { if (contains_ts(current, TRUE, my_ts, my_host) && contains_ts(current, FALSE, other_ts, other_host)) @@ -280,7 +278,7 @@ static child_cfg_t* select_child_cfg(private_peer_cfg_t *this, break; } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); return found; } @@ -300,30 +298,6 @@ static identification_t *get_other_id(private_peer_cfg_t *this) return this->other_id; } -/** - * Implementation of peer_cfg_t.get_my_ca - */ -static identification_t *get_my_ca(private_peer_cfg_t *this) -{ - return this->my_ca; -} - -/** - * Implementation of peer_cfg_t.get_other_ca - */ -static identification_t *get_other_ca(private_peer_cfg_t *this) -{ - return this->other_ca; -} - -/** - * Implementation of peer_cfg_t.get_groups - */ -static linked_list_t *get_groups(private_peer_cfg_t *this) -{ - return this->groups; -} - /** * Implementation of peer_cfg_t.get_cert_policy. */ @@ -452,6 +426,14 @@ static host_t* get_other_virtual_ip(private_peer_cfg_t *this, host_t *suggestion } return suggestion->clone(suggestion); } + +/** + * Implementation of peer_cfg_t.get_auth. + */ +static auth_info_t* get_auth(private_peer_cfg_t *this) +{ + return this->auth; +} #ifdef P2P /** @@ -502,15 +484,13 @@ static void destroy(private_peer_cfg_t *this) this->child_cfgs->destroy_offset(this->child_cfgs, offsetof(child_cfg_t, destroy)); this->my_id->destroy(this->my_id); this->other_id->destroy(this->other_id); - DESTROY_IF(this->my_ca); - DESTROY_IF(this->other_ca); DESTROY_IF(this->my_virtual_ip); DESTROY_IF(this->other_virtual_ip); + this->auth->destroy(this->auth); #ifdef P2P DESTROY_IF(this->p2p_mediated_by); DESTROY_IF(this->peer_id); #endif /* P2P */ - ietfAttr_list_destroy(this->groups); free(this->name); free(this); } @@ -521,8 +501,7 @@ static void destroy(private_peer_cfg_t *this) */ peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg, identification_t *my_id, identification_t *other_id, - identification_t *my_ca, identification_t *other_ca, - linked_list_t *groups, cert_policy_t cert_policy, + cert_policy_t cert_policy, auth_method_t auth_method, eap_type_t eap_type, u_int32_t eap_vendor, u_int32_t keyingtries, u_int32_t rekey_time, @@ -540,13 +519,11 @@ peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg, this->public.get_ike_version = (u_int(*) (peer_cfg_t *))get_ike_version; this->public.get_ike_cfg = (ike_cfg_t* (*) (peer_cfg_t *))get_ike_cfg; this->public.add_child_cfg = (void (*) (peer_cfg_t *, child_cfg_t*))add_child_cfg; - this->public.create_child_cfg_iterator = (iterator_t* (*) (peer_cfg_t *))create_child_cfg_iterator; + this->public.remove_child_cfg = (void(*)(peer_cfg_t*, enumerator_t*))remove_child_cfg; + this->public.create_child_cfg_enumerator = (enumerator_t* (*) (peer_cfg_t *))create_child_cfg_enumerator; this->public.select_child_cfg = (child_cfg_t* (*) (peer_cfg_t *,linked_list_t*,linked_list_t*,host_t*,host_t*))select_child_cfg; this->public.get_my_id = (identification_t* (*)(peer_cfg_t*))get_my_id; this->public.get_other_id = (identification_t* (*)(peer_cfg_t *))get_other_id; - this->public.get_my_ca = (identification_t* (*)(peer_cfg_t *))get_my_ca; - this->public.get_other_ca = (identification_t* (*)(peer_cfg_t *))get_other_ca; - this->public.get_groups = (linked_list_t* (*)(peer_cfg_t *))get_groups; this->public.get_cert_policy = (cert_policy_t (*) (peer_cfg_t *))get_cert_policy; this->public.get_auth_method = (auth_method_t (*) (peer_cfg_t *))get_auth_method; this->public.get_eap_type = (eap_type_t (*) (peer_cfg_t *,u_int32_t*))get_eap_type; @@ -559,6 +536,7 @@ peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg, this->public.get_dpd_action = (dpd_action_t (*) (peer_cfg_t *))get_dpd_action; this->public.get_my_virtual_ip = (host_t* (*) (peer_cfg_t *))get_my_virtual_ip; this->public.get_other_virtual_ip = (host_t* (*) (peer_cfg_t *, host_t *))get_other_virtual_ip; + this->public.get_auth = (auth_info_t*(*)(peer_cfg_t*))get_auth; this->public.get_ref = (void(*)(peer_cfg_t *))get_ref; this->public.destroy = (void(*)(peer_cfg_t *))destroy; #ifdef P2P @@ -575,9 +553,6 @@ peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg, pthread_mutex_init(&this->mutex, NULL); this->my_id = my_id; this->other_id = other_id; - this->my_ca = my_ca; - this->other_ca = other_ca; - this->groups = groups; this->cert_policy = cert_policy; this->auth_method = auth_method; this->eap_type = eap_type; @@ -600,11 +575,15 @@ peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg, this->dpd_action = dpd_action; this->my_virtual_ip = my_virtual_ip; this->other_virtual_ip = other_virtual_ip; + this->auth = auth_info_create(); this->refcount = 1; #ifdef P2P this->p2p_mediation = p2p_mediation; this->p2p_mediated_by = p2p_mediated_by; this->peer_id = peer_id; +#else /* P2P */ + DESTROY_IF(p2p_mediated_by); + DESTROY_IF(peer_id); #endif /* P2P */ return &this->public; diff --git a/src/charon/config/peer_cfg.h b/src/charon/config/peer_cfg.h index 7f1dbcab6..6c0601ff6 100644 --- a/src/charon/config/peer_cfg.h +++ b/src/charon/config/peer_cfg.h @@ -1,10 +1,3 @@ -/** - * @file peer_cfg.h - * - * @brief Interface of peer_cfg_t. - * - */ - /* * Copyright (C) 2007 Tobias Brunner * Copyright (C) 2005-2007 Martin Willi @@ -20,6 +13,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup peer_cfg peer_cfg + * @{ @ingroup config */ #ifndef PEER_CFG_H_ @@ -31,21 +31,20 @@ typedef struct peer_cfg_t peer_cfg_t; #include #include -#include +#include #include #include #include #include #include #include +#include /** * Certificate sending policy. This is also used for certificate * requests when using this definition for the other peer. If * it is CERT_NEVER_SEND, a certreq is omitted, otherwise its * included. - * - * @ingroup config * * @warning These definitions must be the same as in pluto/starter, * as they are sent over the stroke socket. @@ -61,17 +60,13 @@ enum cert_policy_t { /** * enum strings for cert_policy_t - * - * @ingroup config */ extern enum_name_t *cert_policy_names; /** - * @brief Actions to take when a peer does not respond (dead peer detected). + * Actions to take when a peer does not respond (dead peer detected). * * These values are the same as in pluto/starter, so do not modify them! - * - * @ingroup config */ enum dpd_action_t { /** DPD disabled */ @@ -90,7 +85,7 @@ enum dpd_action_t { extern enum_name_t *dpd_action_names; /** - * @brief Configuration of a peer, specified by IDs. + * Configuration of a peer, specified by IDs. * * The peer config defines a connection between two given IDs. It contains * exactly one ike_cfg_t, which is use for initiation. Additionally, it contains @@ -106,61 +101,67 @@ extern enum_name_t *dpd_action_names; | - ... | | - dpd config | | - ... |-+ +---------------+ | - ... | +---------------+ +-------------------+ + ^ + | + +-------------------+ + | auth_info | + +-------------------+ + | auth_items | + +-------------------+ @endverbatim - * - * @b Constructors: - * - peer_cfg_create() - * - * @ingroup config + * The auth_info_t object associated to the peer_cfg holds additional + * authorization constraints. A peer who wants to use a config needs to fullfil + * the requirements defined in auth_info. */ struct peer_cfg_t { /** - * @brief Get the name of the peer_cfg. + * Get the name of the peer_cfg. * * Returned object is not getting cloned. * - * @param this calling object * @return peer_cfg's name */ char* (*get_name) (peer_cfg_t *this); /** - * @brief Get the IKE version to use for initiating. + * Get the IKE version to use for initiating. * - * @param this calling object * @return IKE major version */ u_int (*get_ike_version)(peer_cfg_t *this); /** - * @brief Get the IKE config to use for initiaton. + * Get the IKE config to use for initiaton. * - * @param this calling object * @return the IKE config to use */ ike_cfg_t* (*get_ike_cfg) (peer_cfg_t *this); /** - * @brief Attach a CHILD config. + * Attach a CHILD config. * - * @param this calling object * @param child_cfg CHILD config to add */ void (*add_child_cfg) (peer_cfg_t *this, child_cfg_t *child_cfg); /** - * @brief Create an iterator for all attached CHILD configs. + * Detach a CHILD config, pointed to by an enumerator. + * + * @param enumerator enumerator indicating element position + */ + void (*remove_child_cfg)(peer_cfg_t *this, enumerator_t *enumerator); + + /** + * Create an enumerator for all attached CHILD configs. * - * @param this calling object - * @return an iterator over all CHILD configs. + * @return an enumerator over all CHILD configs. */ - iterator_t* (*create_child_cfg_iterator) (peer_cfg_t *this); + enumerator_t* (*create_child_cfg_enumerator) (peer_cfg_t *this); /** - * @brief Select a CHILD config from traffic selectors. + * Select a CHILD config from traffic selectors. * - * @param this calling object * @param my_ts TS for local side * @param other_ts TS for remote side * @param my_host host to narrow down dynamic TS for local side @@ -172,213 +173,175 @@ struct peer_cfg_t { host_t *other_host); /** - * @brief Get own ID. + * Get the authentication constraint items. + * + * @return auth_info object to manipulate requirements + */ + auth_info_t* (*get_auth)(peer_cfg_t *this); + + /** + * Get own ID. * - * @param this calling object * @return own id */ identification_t* (*get_my_id)(peer_cfg_t *this); /** - * @brief Get peers ID. + * Get peers ID. * - * @param this calling object * @return other id */ identification_t* (*get_other_id)(peer_cfg_t *this); - - /** - * @brief Get own CA. - * - * @param this calling object - * @return own ca - */ - identification_t* (*get_my_ca)(peer_cfg_t *this); - - /** - * @brief Get peer CA. - * - * @param this calling object - * @return other ca - */ - identification_t* (*get_other_ca)(peer_cfg_t *this); - - /** - * @brief Get list of group attributes. - * - * @param this calling object - * @return linked list of group attributes - */ - linked_list_t* (*get_groups)(peer_cfg_t *this); /** - * @brief Should be sent a certificate for this connection? + * Should be sent a certificate for this connection? * - * @param this calling object * @return certificate sending policy */ cert_policy_t (*get_cert_policy) (peer_cfg_t *this); /** - * @brief Get the authentication method to use to authenticate us. + * Get the authentication method to use to authenticate us. * - * @param this calling object * @return authentication method */ auth_method_t (*get_auth_method) (peer_cfg_t *this); /** - * @brief Get the EAP type to use for peer authentication. + * Get the EAP type to use for peer authentication. * * If vendor specific types are used, a vendor ID != 0 is returned to * to vendor argument. Then the returned type is specific for that * vendor ID. * - * @param this calling object * @param vendor receives vendor specifier, 0 for predefined EAP types * @return authentication method */ eap_type_t (*get_eap_type) (peer_cfg_t *this, u_int32_t *vendor); /** - * @brief Get the max number of retries after timeout. + * Get the max number of retries after timeout. * - * @param this calling object * @return max number retries */ u_int32_t (*get_keyingtries) (peer_cfg_t *this); /** - * @brief Get a time to start rekeying (is randomized with jitter). + * Get a time to start rekeying (is randomized with jitter). * - * @param this calling object * @return time in s when to start rekeying, 0 disables rekeying */ u_int32_t (*get_rekey_time)(peer_cfg_t *this); /** - * @brief Get a time to start reauthentication (is randomized with jitter). + * Get a time to start reauthentication (is randomized with jitter). * - * @param this calling object * @return time in s when to start reauthentication, 0 disables it */ u_int32_t (*get_reauth_time)(peer_cfg_t *this); /** - * @brief Get the timeout of a rekeying/reauthenticating SA. + * Get the timeout of a rekeying/reauthenticating SA. * - * @param thsi calling object * @return timeout in s */ u_int32_t (*get_over_time)(peer_cfg_t *this); /** - * @brief Use MOBIKE (RFC4555) if peer supports it? + * Use MOBIKE (RFC4555) if peer supports it? * - * @param this calling object * @return TRUE to enable MOBIKE support */ bool (*use_mobike) (peer_cfg_t *this); /** - * @brief Get the DPD check interval. + * Get the DPD check interval. * - * @param this calling object * @return dpd_delay in seconds */ u_int32_t (*get_dpd_delay) (peer_cfg_t *this); /** - * @brief What should be done with a CHILD_SA, when other peer does not respond. + * What should be done with a CHILD_SA, when other peer does not respond. * - * @param this calling object * @return dpd action */ dpd_action_t (*get_dpd_action) (peer_cfg_t *this); /** - * @brief Get a virtual IP for the local peer. + * Get a virtual IP for the local peer. * * If no virtual IP should be used, NULL is returned. %any means to request * a virtual IP using configuration payloads. A specific address is also * used for a request and may be changed by the server. * - * @param this peer_cfg * @param suggestion NULL, %any or specific * @return clone of an IP, %any or NULL */ host_t* (*get_my_virtual_ip) (peer_cfg_t *this); /** - * @brief Get a virtual IP for the remote peer. + * Get a virtual IP for the remote peer. * * An IP may be supplied, if one was requested by the initiator. However, * the suggestion is not more as it says, any address may be returned, even * NULL to not use virtual IPs. * - * @param this peer_cfg * @param suggestion NULL, %any or specific * @return clone of an IP to use */ host_t* (*get_other_virtual_ip) (peer_cfg_t *this, host_t *suggestion); - + #ifdef P2P /** - * @brief Is this a mediation connection? + * Is this a mediation connection? * - * @param this peer_cfg * @return TRUE, if this is a mediation connection */ bool (*is_mediation) (peer_cfg_t *this); /** - * @brief Get peer_cfg of the connection this one is mediated through. + * Get peer_cfg of the connection this one is mediated through. * - * @param this peer_cfg * @return reference to peer_cfg of the mediation connection */ peer_cfg_t* (*get_mediated_by) (peer_cfg_t *this); /** - * @brief Get the id of the other peer at the mediation server. + * Get the id of the other peer at the mediation server. * * This is the leftid of the peer's connection with the mediation server. * * If it is not configured, it is assumed to be the same as the right id * of this connection. * - * @param this peer_cfg * @return the id of the other peer */ identification_t* (*get_peer_id) (peer_cfg_t *this); #endif /* P2P */ /** - * @brief Get a new reference. + * Get a new reference. * * Get a new reference to this peer_cfg by increasing * it's internal reference counter. * Do not call get_ref or any other function until you * already have a reference. Otherwise the object may get * destroyed while calling get_ref(), - * - * @param this calling object */ void (*get_ref) (peer_cfg_t *this); /** - * @brief Destroys the peer_cfg object. + * Destroys the peer_cfg object. * * Decrements the internal reference counter and * destroys the peer_cfg when it reaches zero. - * - * @param this calling object */ void (*destroy) (peer_cfg_t *this); }; /** - * @brief Create a configuration object for IKE_AUTH and later. + * Create a configuration object for IKE_AUTH and later. * * name-string gets cloned, ID's not. * Virtual IPs are used if they are != NULL. A %any host means the virtual @@ -392,9 +355,6 @@ struct peer_cfg_t { * @param ike_cfg IKE config to use when acting as initiator * @param my_id identification_t for ourselves * @param other_id identification_t for the remote guy - * @param my_ca CA to use for us - * @param other_ca CA to use for other - * @param groups list of group memberships * @param cert_policy should we send a certificate payload? * @param auth_method auth method to use to authenticate us * @param eap_type EAP type to use for peer authentication @@ -414,13 +374,10 @@ struct peer_cfg_t { * @param p2p_mediated_by name of the mediation connection to mediate through * @param peer_id ID that identifies our peer at the mediation server * @return peer_cfg_t object - * - * @ingroup config */ peer_cfg_t *peer_cfg_create(char *name, u_int ikev_version, ike_cfg_t *ike_cfg, identification_t *my_id, identification_t *other_id, - identification_t *my_ca, identification_t *other_ca, - linked_list_t *groups, cert_policy_t cert_policy, + cert_policy_t cert_policy, auth_method_t auth_method, eap_type_t eap_type, u_int32_t eap_vendor, u_int32_t keyingtries, u_int32_t rekey_time, @@ -431,4 +388,4 @@ peer_cfg_t *peer_cfg_create(char *name, u_int ikev_version, ike_cfg_t *ike_cfg, bool p2p_mediation, peer_cfg_t *p2p_mediated_by, identification_t *peer_id); -#endif /* PEER_CFG_H_ */ +#endif /* PEER_CFG_H_ @} */ diff --git a/src/charon/config/proposal.c b/src/charon/config/proposal.c index cff9859c1..04ec28a61 100644 --- a/src/charon/config/proposal.c +++ b/src/charon/config/proposal.c @@ -1,10 +1,3 @@ -/** - * @file proposal.c - * - * @brief Implementation of proposal_t. - * - */ - /* * Copyright (C) 2006 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,8 @@ * 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. + * + * $Id$ */ #include diff --git a/src/charon/config/proposal.h b/src/charon/config/proposal.h index 379550f44..0f3559012 100644 --- a/src/charon/config/proposal.h +++ b/src/charon/config/proposal.h @@ -1,10 +1,3 @@ -/** - * @file proposal.h - * - * @brief Interface of proposal_t. - * - */ - /* * Copyright (C) 2006 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup proposal proposal + * @{ @ingroup config */ #ifndef PROPOSAL_H_ @@ -40,8 +40,6 @@ typedef struct proposal_t proposal_t; /** * Protocol ID of a proposal. - * - * @ingroup config */ enum protocol_id_t { PROTO_NONE = 0, @@ -52,16 +50,12 @@ enum protocol_id_t { /** * enum names for protocol_id_t - * - * @ingroup config */ extern enum_name_t *protocol_id_names; /** * Type of a transform, as in IKEv2 RFC 3.3.2. - * - * @ingroup config */ enum transform_type_t { UNDEFINED_TRANSFORM_TYPE = 241, @@ -74,16 +68,12 @@ enum transform_type_t { /** * enum names for transform_type_t. - * - * @ingroup config */ extern enum_name_t *transform_type_names; /** * Extended sequence numbers, as in IKEv2 RFC 3.3.2. - * - * @ingroup config */ enum extended_sequence_numbers_t { NO_EXT_SEQ_NUMBERS = 0, @@ -92,8 +82,6 @@ enum extended_sequence_numbers_t { /** * enum strings for extended_sequence_numbers_t. - * - * @ingroup config */ extern enum_name_t *extended_sequence_numbers_names; @@ -102,8 +90,6 @@ extern enum_name_t *extended_sequence_numbers_names; /** * Struct used to store different kinds of algorithms. The internal * lists of algorithms contain such structures. - * - * @ingroup config */ struct algorithm_t { /** @@ -118,22 +104,17 @@ struct algorithm_t { }; /** - * @brief Stores a set of algorithms used for an SA. + * Stores a set of algorithms used for an SA. * * A proposal stores algorithms for a specific * protocol. It can store algorithms for one protocol. * Proposals with multiple protocols are not supported, * as it's not specified in RFC4301 anymore. - * - * @b Constructors: - * - proposal_create() - * - * @ingroup config */ struct proposal_t { /** - * @brief Add an algorithm to the proposal. + * Add an algorithm to the proposal. * * The algorithms are stored by priority, first added * is the most preferred. @@ -144,120 +125,103 @@ struct proposal_t { * integrity_algorithm_t, dh_group_number_t and * extended_sequence_numbers_t. * - * @param this calling object - * @param type kind of algorithm - * @param alg identifier for algorithm - * @param key_size key size to use + * @param type kind of algorithm + * @param alg identifier for algorithm + * @param key_size key size to use */ void (*add_algorithm) (proposal_t *this, transform_type_t type, u_int16_t alg, size_t key_size); /** - * @brief Get an iterator over algorithms for a specifc algo type. + * Get an iterator over algorithms for a specifc algo type. * - * @param this calling object - * @param type kind of algorithm - * @return iterator over algorithm_t's + * @param type kind of algorithm + * @return iterator over algorithm_t's */ iterator_t *(*create_algorithm_iterator) (proposal_t *this, transform_type_t type); /** - * @brief Get the algorithm for a type to use. + * Get the algorithm for a type to use. * * If there are multiple algorithms, only the first is returned. * - * @param this calling object - * @param type kind of algorithm - * @param[out] algo pointer which receives algorithm and key size - * @return TRUE if algorithm of this kind available + * @param type kind of algorithm + * @param algo pointer which receives algorithm and key size + * @return TRUE if algorithm of this kind available */ bool (*get_algorithm) (proposal_t *this, transform_type_t type, algorithm_t** algo); /** - * @brief Check if the proposal has a specific DH group. + * Check if the proposal has a specific DH group. * - * @param this calling object - * @param group group to check for - * @return TRUE if algorithm included + * @param group group to check for + * @return TRUE if algorithm included */ bool (*has_dh_group) (proposal_t *this, diffie_hellman_group_t group); /** - * @brief Compare two proposal, and select a matching subset. + * Compare two proposal, and select a matching subset. * * If the proposals are for the same protocols (AH/ESP), they are * compared. If they have at least one algorithm of each type * in common, a resulting proposal of this kind is created. * - * @param this calling object - * @param other proposal to compair agains - * @return - * - selected proposal, if possible - * - NULL, if proposals don't match + * @param other proposal to compair agains + * @return selected proposal, NULL if proposals don't match */ proposal_t *(*select) (proposal_t *this, proposal_t *other); /** - * @brief Get the protocol ID of the proposal. + * Get the protocol ID of the proposal. * - * @param this calling object - * @return protocol of the proposal + * @return protocol of the proposal */ protocol_id_t (*get_protocol) (proposal_t *this); /** - * @brief Get the SPI of the proposal. + * Get the SPI of the proposal. * - * @param this calling object - * @return spi for proto + * @return spi for proto */ u_int64_t (*get_spi) (proposal_t *this); /** - * @brief Set the SPI of the proposal. + * Set the SPI of the proposal. * - * @param this calling object - * @param spi spi to set for proto + * @param spi spi to set for proto */ void (*set_spi) (proposal_t *this, u_int64_t spi); /** - * @brief Clone a proposal. + * Clone a proposal. * - * @param this proposal to clone - * @return clone of it + * @return clone of proposal */ proposal_t *(*clone) (proposal_t *this); /** - * @brief Destroys the proposal object. - * - * @param this calling object + * Destroys the proposal object. */ void (*destroy) (proposal_t *this); }; /** - * @brief Create a child proposal for AH, ESP or IKE. + * Create a child proposal for AH, ESP or IKE. * * @param protocol protocol, such as PROTO_ESP * @return proposal_t object - * - * @ingroup config */ proposal_t *proposal_create(protocol_id_t protocol); /** - * @brief Create a default proposal if nothing further specified. + * Create a default proposal if nothing further specified. * * @param protocol protocol, such as PROTO_ESP * @return proposal_t object - * - * @ingroup config */ proposal_t *proposal_create_default(protocol_id_t protocol); /** - * @brief Create a proposal from a string identifying the algorithms. + * Create a proposal from a string identifying the algorithms. * * The string is in the same form as a in the ipsec.conf file. * E.g.: aes128-sha2_256-modp2048 @@ -268,9 +232,7 @@ proposal_t *proposal_create_default(protocol_id_t protocol); * @param protocol protocol, such as PROTO_ESP * @param algs algorithms as string * @return proposal_t object - * - * @ingroup config */ proposal_t *proposal_create_from_string(protocol_id_t protocol, const char *algs); -#endif /* PROPOSAL_H_ */ +#endif /* PROPOSAL_H_ @} */ diff --git a/src/charon/config/traffic_selector.c b/src/charon/config/traffic_selector.c index da39c434d..02a74a1b7 100644 --- a/src/charon/config/traffic_selector.c +++ b/src/charon/config/traffic_selector.c @@ -1,10 +1,3 @@ -/** - * @file traffic_selector.c - * - * @brief Implementation of traffic_selector_t. - * - */ - /* * Copyright (C) 2007 Tobias Brunner * Copyright (C) 2005-2007 Martin Willi @@ -20,6 +13,8 @@ * 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. + * + * $Id$ */ #include @@ -276,11 +271,25 @@ static int print(FILE *stream, const struct printf_info *info, } /** - * register printf() handlers + * arginfo handler for printf() traffic selector + */ +static int arginfo(const struct printf_info *info, size_t n, int *argtypes) +{ + if (n > 0) + { + argtypes[0] = PA_POINTER; + } + return 1; +} + +/** + * return printf hook functions for a chunk */ -static void __attribute__ ((constructor))print_register() +printf_hook_functions_t traffic_selector_get_printf_hooks() { - register_printf_function(PRINTF_TRAFFIC_SELECTOR, print, arginfo_ptr); + printf_hook_functions_t hooks = {print, arginfo}; + + return hooks; } /** diff --git a/src/charon/config/traffic_selector.h b/src/charon/config/traffic_selector.h index 0e798fc6a..4b8b91ac7 100644 --- a/src/charon/config/traffic_selector.h +++ b/src/charon/config/traffic_selector.h @@ -1,10 +1,3 @@ -/** - * @file traffic_selector.h - * - * @brief Interface of traffic_selector_t. - * - */ - /* * Copyright (C) 2007 Tobias Brunner * Copyright (C) 2005-2006 Martin Willi @@ -20,6 +13,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup traffic_selector traffic_selector + * @{ @ingroup config */ #ifndef TRAFFIC_SELECTOR_H_ @@ -33,8 +33,6 @@ typedef struct traffic_selector_t traffic_selector_t; /** * Traffic selector types. - * - * @ingroup config */ enum ts_type_t { @@ -63,29 +61,20 @@ enum ts_type_t { extern enum_name_t *ts_type_name; /** - * @brief Object representing a traffic selector entry. + * Object representing a traffic selector entry. * * A traffic selector defines an range of addresses * and a range of ports. IPv6 is not fully supported yet. - * - * @b Constructors: - * - traffic_selector_create_from_bytes() - * - traffic_selector_create_from_string() - * - * @todo Add IPv6 support - * - * @ingroup config */ struct traffic_selector_t { /** - * @brief Compare two traffic selectors, and create a new one + * Compare two traffic selectors, and create a new one * which is the largest subset of both (subnet & port). * * Resulting traffic_selector is newly created and must be destroyed. * - * @param this first to compare - * @param other second to compare + * @param other traffic selector to compare * @return * - created subset of them * - or NULL if no match between this and other @@ -94,73 +83,66 @@ struct traffic_selector_t { traffic_selector_t *other); /** - * @brief Clone a traffic selector. + * Clone a traffic selector. * - * @param this traffic selector to clone * @return clone of it */ traffic_selector_t *(*clone) (traffic_selector_t *this); /** - * @brief Get starting address of this ts as a chunk. + * Get starting address of this ts as a chunk. * * Chunk is in network order gets allocated. * - * @param this called object * @return chunk containing the address */ chunk_t (*get_from_address) (traffic_selector_t *this); /** - * @brief Get ending address of this ts as a chunk. + * Get ending address of this ts as a chunk. * * Chunk is in network order gets allocated. * - * @param this called object * @return chunk containing the address */ chunk_t (*get_to_address) (traffic_selector_t *this); /** - * @brief Get starting port of this ts. + * Get starting port of this ts. * * Port is in host order, since the parser converts it. * Size depends on protocol. * - * @param this called object * @return port */ u_int16_t (*get_from_port) (traffic_selector_t *this); /** - * @brief Get ending port of this ts. + * Get ending port of this ts. * * Port is in host order, since the parser converts it. * Size depends on protocol. * - * @param this called object * @return port */ u_int16_t (*get_to_port) (traffic_selector_t *this); /** - * @brief Get the type of the traffic selector. + * Get the type of the traffic selector. * - * @param this called object * @return ts_type_t specifying the type */ ts_type_t (*get_type) (traffic_selector_t *this); /** - * @brief Get the protocol id of this ts. + * Get the protocol id of this ts. * - * @param this called object * @return protocol id */ u_int8_t (*get_protocol) (traffic_selector_t *this); /** - * @brief Check if the traffic selector is for a single host. + * Check if the traffic selector is for a single host. * * Traffic selector may describe the end of *-to-host tunnel. In this * case, the address range is a single address equal to the hosts @@ -168,61 +150,54 @@ struct traffic_selector_t { * If host is NULL, the traffic selector is checked if it is a single host, * but not a specific one. * - * @param this called object * @param host host_t specifying the address range */ bool (*is_host) (traffic_selector_t *this, host_t* host); /** - * @brief Update the address of a traffic selector. + * Update the address of a traffic selector. * * Update the address range of a traffic selector, if it is * constructed with the traffic_selector_create_dynamic(). * - * @param this called object * @param host host_t specifying the address */ void (*set_address) (traffic_selector_t *this, host_t* host); /** - * @brief Compare two traffic selectors for equality. + * Compare two traffic selectors for equality. * - * @param this first to compare - * @param other second to compare with first + * @param other ts to compare with this * @return pointer to a string. */ bool (*equals) (traffic_selector_t *this, traffic_selector_t *other); /** - * @brief Check if a traffic selector is contained completly in another. + * Check if a traffic selector is contained completly in another. * * contains() allows to check if multiple traffic selectors are redundant. * - * @param this ts that is contained in another * @param other ts that contains this * @return TRUE if other contains this completly, FALSE otherwise */ bool (*is_contained_in) (traffic_selector_t *this, traffic_selector_t *other); /** - * @brief Check if a specific host is included in the address range of + * Check if a specific host is included in the address range of * this traffic selector. * - * @param this called object * @param host the host to check */ bool (*includes) (traffic_selector_t *this, host_t *host); /** - * @brief Destroys the ts object - * - * @param this called object + * Destroys the ts object */ void (*destroy) (traffic_selector_t *this); }; /** - * @brief Create a new traffic selector using human readable params. + * Create a new traffic selector using human readable params. * * @param protocol protocol for this ts, such as TCP or UDP * @param type type of following addresses, such as TS_IPV4_ADDR_RANGE @@ -233,8 +208,6 @@ struct traffic_selector_t { * @return * - traffic_selector_t object * - NULL if invalid address strings/protocol - * - * @ingroup config */ traffic_selector_t *traffic_selector_create_from_string( u_int8_t protocol, ts_type_t type, @@ -242,7 +215,7 @@ traffic_selector_t *traffic_selector_create_from_string( char *to_addr, u_int16_t to_port); /** - * @brief Create a new traffic selector using data read from the net. + * Create a new traffic selector using data read from the net. * * There exists a mix of network and host order in the params. * But the parser gives us this data in this format, so we @@ -255,8 +228,6 @@ traffic_selector_t *traffic_selector_create_from_string( * @param to_address end of address range as string, network * @param to_port port number, host order * @return traffic_selector_t object - * - * @ingroup config */ traffic_selector_t *traffic_selector_create_from_bytes( u_int8_t protocol, ts_type_t type, @@ -264,7 +235,7 @@ traffic_selector_t *traffic_selector_create_from_bytes( chunk_t to_address, u_int16_t to_port); /** - * @brief Create a new traffic selector defining a whole subnet. + * Create a new traffic selector defining a whole subnet. * * In most cases, definition of a traffic selector for full subnets * is sufficient. This constructor creates a traffic selector for @@ -278,15 +249,13 @@ traffic_selector_t *traffic_selector_create_from_bytes( * @return * - traffic_selector_t object * - NULL if address family of net not supported - * - * @ingroup config */ traffic_selector_t *traffic_selector_create_from_subnet( host_t *net, u_int8_t netbits, u_int8_t protocol, u_int16_t port); /** - * @brief Create a traffic selector for host-to-host cases. + * Create a traffic selector for host-to-host cases. * * For host2host or virtual IP setups, the traffic selectors gets * created at runtime using the external/virtual IP. Using this constructor, @@ -300,13 +269,19 @@ traffic_selector_t *traffic_selector_create_from_subnet( * @return * - traffic_selector_t object * - NULL if type not supported - * - * @ingroup config */ traffic_selector_t *traffic_selector_create_dynamic( u_int8_t protocol, ts_type_t type, u_int16_t from_port, u_int16_t to_port); -#endif /* TRAFFIC_SELECTOR_H_ */ +/** + * Get printf hooks for a traffic selector. + * + * Arguments are: + * traffic_selector_t *ts + * With the #-specifier, arguments are: + * linked_list_t *list containing traffic_selector_t* + */ +printf_hook_functions_t traffic_selector_get_printf_hooks(); -/* vim: set ts=4 sw=4 noet: */ +#endif /* TRAFFIC_SELECTOR_H_ @} */ diff --git a/src/charon/control/controller.c b/src/charon/control/controller.c new file mode 100644 index 000000000..353b35780 --- /dev/null +++ b/src/charon/control/controller.c @@ -0,0 +1,574 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "controller.h" + +#include +#include +#include +#include + +#include +#include + + +typedef struct private_controller_t private_controller_t; +typedef struct interface_bus_listener_t interface_bus_listener_t; + +/** + * Private data of an stroke_t object. + */ +struct private_controller_t { + + /** + * Public part of stroke_t object. + */ + controller_t public; +}; + + +/** + * helper struct to map bus listener callbacks to interface callbacks + */ +struct interface_bus_listener_t { + + /** + * public bus listener interface + */ + bus_listener_t public; + + /** + * status of the operation, return to method callers + */ + status_t status; + + /** + * IKE SA to filter log output + */ + ike_sa_t *ike_sa; + + /** + * interface callback (listener gets redirected to here) + */ + controller_cb_t callback; + + /** + * user parameter to pass to callback + */ + void *param; + + /** + * child configuration, used for initiate + */ + child_cfg_t *child_cfg; + + /** + * peer configuration, used for initiate + */ + peer_cfg_t *peer_cfg; + + /** + * unique ID, used for various methods + */ + u_int32_t id; +}; + + +typedef struct interface_job_t interface_job_t; + +/** + * job for asynchronous listen operations + */ +struct interface_job_t { + /** + * job interface + */ + job_t public; + + /** + * associated listener + */ + interface_bus_listener_t listener; +}; + +/** + * Implements the famous nop operation + */ +static void nop(job_t *job) +{ + /* NOP */ +} + +/** + * Implementation of controller_t.create_ike_sa_iterator. + */ +static iterator_t* create_ike_sa_iterator(controller_t *this) +{ + return charon->ike_sa_manager->create_iterator(charon->ike_sa_manager); +} + +/** + * listener function for initiate + */ +static bool initiate_listener(interface_bus_listener_t *this, signal_t signal, + level_t level, int thread, ike_sa_t *ike_sa, + char* format, va_list args) +{ + if (this->ike_sa == ike_sa) + { + if (!this->callback(this->param, signal, level, ike_sa, format, args)) + { + return FALSE; + } + switch (signal) + { + case CHILD_UP_SUCCESS: + this->status = SUCCESS; + return FALSE; + case IKE_UP_FAILED: + case CHILD_UP_FAILED: + return FALSE; + default: + break; + } + } + return TRUE; +} + +/** + * execute function for initiate + */ +static status_t initiate_execute(interface_job_t *job) +{ + ike_sa_t *ike_sa; + interface_bus_listener_t *listener = &job->listener; + peer_cfg_t *peer_cfg = listener->peer_cfg; + + ike_sa = charon->ike_sa_manager->checkout_by_config(charon->ike_sa_manager, + peer_cfg); + listener->ike_sa = ike_sa; + + if (ike_sa->get_peer_cfg(ike_sa) == NULL) + { + ike_sa->set_peer_cfg(ike_sa, peer_cfg); + } + peer_cfg->destroy(peer_cfg); + + if (ike_sa->initiate(ike_sa, listener->child_cfg) != SUCCESS) + { + return charon->ike_sa_manager->checkin_and_destroy( + charon->ike_sa_manager, ike_sa); + } + return charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); +} + +/** + * Implementation of controller_t.initiate. + */ +static status_t initiate(private_controller_t *this, + peer_cfg_t *peer_cfg, child_cfg_t *child_cfg, + controller_cb_t callback, void *param) +{ + interface_job_t job; + + job.listener.public.signal = (void*)initiate_listener; + job.listener.ike_sa = NULL; + job.listener.callback = callback; + job.listener.param = param; + job.listener.status = FAILED; + job.listener.child_cfg = child_cfg; + job.listener.peer_cfg = peer_cfg; + job.public.execute = (void*)initiate_execute; + job.public.destroy = nop; + + if (callback == NULL) + { + return initiate_execute(&job); + } + charon->bus->listen(charon->bus, (bus_listener_t*)&job.listener, (job_t*)&job); + return job.listener.status; +} + +/** + * listener function for terminate_ike + */ +static bool terminate_ike_listener(interface_bus_listener_t *this, signal_t signal, + level_t level, int thread, ike_sa_t *ike_sa, + char* format, va_list args) +{ + if (this->ike_sa == ike_sa) + { + if (!this->callback(this->param, signal, level, ike_sa, format, args)) + { + return FALSE; + } + switch (signal) + { + case IKE_DOWN_SUCCESS: + this->status = SUCCESS; + return FALSE; + case IKE_DOWN_FAILED: + return FALSE; + default: + break; + } + } + return TRUE; +} + +/** + * execute function for terminate_ike + */ +static status_t terminate_ike_execute(interface_job_t *job) +{ + ike_sa_t *ike_sa; + interface_bus_listener_t *listener = &job->listener; + + ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager, + listener->id, FALSE); + if (ike_sa == NULL) + { + SIG(IKE_DOWN_FAILED, "unable to terminate, IKE_SA with " + "ID %d not found", listener->id); + return NOT_FOUND; + } + listener->ike_sa = ike_sa; + + if (ike_sa->delete(ike_sa) == DESTROY_ME) + { + return charon->ike_sa_manager->checkin_and_destroy( + charon->ike_sa_manager, ike_sa); + } + return charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); +} + +/** + * Implementation of controller_t.terminate_ike. + */ +static status_t terminate_ike(controller_t *this, u_int32_t unique_id, + controller_cb_t callback, void *param) +{ + interface_job_t job; + + job.listener.public.signal = (void*)terminate_ike_listener; + job.listener.ike_sa = NULL; + job.listener.callback = callback; + job.listener.param = param; + job.listener.status = FAILED; + job.listener.id = unique_id; + job.public.execute = (void*)terminate_ike_execute; + job.public.destroy = nop; + + if (callback == NULL) + { + return terminate_ike_execute(&job); + } + charon->bus->listen(charon->bus, (bus_listener_t*)&job.listener, (job_t*)&job); + return job.listener.status; +} +/** + * listener function for terminate_child + */ +static bool terminate_child_listener(interface_bus_listener_t *this, signal_t signal, + level_t level, int thread, ike_sa_t *ike_sa, + char* format, va_list args) +{ + if (this->ike_sa == ike_sa) + { + if (!this->callback(this->param, signal, level, ike_sa, format, args)) + { + return FALSE; + } + switch (signal) + { + case CHILD_DOWN_SUCCESS: + case IKE_DOWN_SUCCESS: + this->status = SUCCESS; + return FALSE; + case IKE_DOWN_FAILED: + case CHILD_DOWN_FAILED: + return FALSE; + default: + break; + } + } + return TRUE; +} + +/** + * execute function for terminate_child + */ +static status_t terminate_child_execute(interface_job_t *job) +{ + ike_sa_t *ike_sa; + child_sa_t *child_sa; + iterator_t *iterator; + interface_bus_listener_t *listener = &job->listener; + + ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager, + listener->id, TRUE); + if (ike_sa == NULL) + { + SIG(CHILD_DOWN_FAILED, "unable to terminate, CHILD_SA with " + "ID %d not found", listener->id); + return NOT_FOUND; + } + listener->ike_sa = ike_sa; + + iterator = ike_sa->create_child_sa_iterator(ike_sa); + while (iterator->iterate(iterator, (void**)&child_sa)) + { + if (child_sa->get_state(child_sa) != CHILD_ROUTED && + child_sa->get_reqid(child_sa) == listener->id) + { + break; + } + child_sa = NULL; + } + iterator->destroy(iterator); + + if (child_sa == NULL) + { + SIG(CHILD_DOWN_FAILED, "unable to terminate, established CHILD_SA with " + "ID %d not found", listener->id); + charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + return NOT_FOUND; + } + + if (ike_sa->delete_child_sa(ike_sa, child_sa->get_protocol(child_sa), + child_sa->get_spi(child_sa, TRUE)) == DESTROY_ME) + { + return charon->ike_sa_manager->checkin_and_destroy( + charon->ike_sa_manager, ike_sa); + } + return charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); +} + +/** + * Implementation of controller_t.terminate_child. + */ +static status_t terminate_child(controller_t *this, u_int32_t reqid, + controller_cb_t callback, void *param) +{ + interface_job_t job; + + job.listener.public.signal = (void*)terminate_child_listener; + job.listener.ike_sa = NULL; + job.listener.callback = callback; + job.listener.param = param; + job.listener.status = FAILED; + job.listener.id = reqid; + job.public.execute = (void*)terminate_child_execute; + job.public.destroy = nop; + + if (callback == NULL) + { + return terminate_child_execute(&job); + } + charon->bus->listen(charon->bus, (bus_listener_t*)&job.listener, (job_t*)&job); + return job.listener.status; +} + +/** + * listener function for route + */ +static bool route_listener(interface_bus_listener_t *this, signal_t signal, + level_t level, int thread, ike_sa_t *ike_sa, + char* format, va_list args) +{ + if (this->ike_sa == ike_sa) + { + if (!this->callback(this->param, signal, level, ike_sa, format, args)) + { + return FALSE; + } + switch (signal) + { + case CHILD_ROUTE_SUCCESS: + this->status = SUCCESS; + return FALSE; + case CHILD_ROUTE_FAILED: + return FALSE; + default: + break; + } + } + return TRUE; +} + +/** + * execute function for route + */ +static status_t route_execute(interface_job_t *job) +{ + ike_sa_t *ike_sa; + interface_bus_listener_t *listener = &job->listener; + peer_cfg_t *peer_cfg = listener->peer_cfg; + ike_sa = charon->ike_sa_manager->checkout_by_config(charon->ike_sa_manager, + peer_cfg); + listener->ike_sa = ike_sa; + + if (ike_sa->get_peer_cfg(ike_sa) == NULL) + { + ike_sa->set_peer_cfg(ike_sa, peer_cfg); + } + if (ike_sa->route(ike_sa, listener->child_cfg) == DESTROY_ME) + { + return charon->ike_sa_manager->checkin_and_destroy( + charon->ike_sa_manager, ike_sa); + } + return charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); +} + +/** + * Implementation of controller_t.route. + */ +static status_t route(controller_t *this, + peer_cfg_t *peer_cfg, child_cfg_t *child_cfg, + controller_cb_t callback, void *param) +{ + interface_job_t job; + + job.listener.public.signal = (void*)route_listener; + job.listener.ike_sa = NULL; + job.listener.callback = callback; + job.listener.param = param; + job.listener.status = FAILED; + job.listener.peer_cfg = peer_cfg; + job.listener.child_cfg = child_cfg; + job.public.execute = (void*)route_execute; + job.public.destroy = nop; + + if (callback == NULL) + { + return route_execute(&job); + } + charon->bus->listen(charon->bus, (bus_listener_t*)&job.listener, (job_t*)&job); + return job.listener.status; +} + +/** + * listener function for unroute + */ +static bool unroute_listener(interface_bus_listener_t *this, signal_t signal, + level_t level, int thread, ike_sa_t *ike_sa, + char* format, va_list args) +{ + if (this->ike_sa == ike_sa) + { + if (!this->callback(this->param, signal, level, ike_sa, format, args)) + { + return FALSE; + } + switch (signal) + { + case CHILD_UNROUTE_SUCCESS: + this->status = SUCCESS; + return FALSE; + case CHILD_UNROUTE_FAILED: + return FALSE; + default: + break; + } + } + return TRUE; +} +/** + * execute function for unroute + */ +static status_t unroute_execute(interface_job_t *job) +{ + ike_sa_t *ike_sa; + interface_bus_listener_t *listener = &job->listener; + + ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager, + listener->id, TRUE); + if (ike_sa == NULL) + { + SIG(CHILD_DOWN_FAILED, "unable to unroute, CHILD_SA with " + "ID %d not found", listener->id); + return NOT_FOUND; + } + listener->ike_sa = ike_sa; + if (ike_sa->unroute(ike_sa, listener->id) == DESTROY_ME) + { + return charon->ike_sa_manager->checkin_and_destroy( + charon->ike_sa_manager, ike_sa); + } + return charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); +} + +/** + * Implementation of controller_t.unroute. + */ +static status_t unroute(controller_t *this, u_int32_t reqid, + controller_cb_t callback, void *param) +{ + interface_job_t job; + + job.listener.public.signal = (void*)unroute_listener; + job.listener.ike_sa = NULL; + job.listener.callback = callback; + job.listener.param = param; + job.listener.status = FAILED; + job.listener.id = reqid; + job.public.execute = (void*)unroute_execute; + job.public.destroy = nop; + + if (callback == NULL) + { + return unroute_execute(&job); + } + charon->bus->listen(charon->bus, (bus_listener_t*)&job.listener, (job_t*)&job); + return job.listener.status; +} + +/** + * See header + */ +bool controller_cb_empty(void *param, signal_t signal, level_t level, + ike_sa_t *ike_sa, char *format, va_list args) +{ + return TRUE; +} + +/** + * Implementation of stroke_t.destroy. + */ +static void destroy(private_controller_t *this) +{ + free(this); +} + +/* + * Described in header-file + */ +controller_t *controller_create(void) +{ + private_controller_t *this = malloc_thing(private_controller_t); + + this->public.create_ike_sa_iterator = (iterator_t*(*)(controller_t*))create_ike_sa_iterator; + this->public.initiate = (status_t(*)(controller_t*,peer_cfg_t*,child_cfg_t*,bool(*)(void*,signal_t,level_t,ike_sa_t*,char*,va_list),void*))initiate; + this->public.terminate_ike = (status_t(*)(controller_t*,u_int32_t,controller_cb_t, void*))terminate_ike; + this->public.terminate_child = (status_t(*)(controller_t*,u_int32_t,controller_cb_t, void *param))terminate_child; + this->public.route = (status_t(*)(controller_t*,peer_cfg_t*, child_cfg_t*,controller_cb_t,void*))route; + this->public.unroute = (status_t(*)(controller_t*,u_int32_t,controller_cb_t,void*))unroute; + this->public.destroy = (void (*)(controller_t*))destroy; + + return &this->public; +} + diff --git a/src/charon/control/controller.h b/src/charon/control/controller.h new file mode 100644 index 000000000..460c04e0d --- /dev/null +++ b/src/charon/control/controller.h @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +/** + * @defgroup controller_i controller + * @{ @ingroup control + */ + +#ifndef CONTROLLER_H_ +#define CONTROLLER_H_ + +#include + +/** + * callback to log things triggered by controller. + * + * @param param echoed parameter supplied when function invoked + * @param signal type of signal + * @param level verbosity level if log + * @param ike_sa associated IKE_SA, if any + * @param format printf like format string + * @param args list of arguments to use for format + * @return FALSE to return from invoked function + */ +typedef bool(*controller_cb_t)(void* param, signal_t signal, level_t level, + ike_sa_t* ike_sa, char* format, va_list args); + +/** + * Empty callback function for controller_t functions. + * + * If you wan't to do a syncrhonous call, but don't need a callback, pass + * this function to the controllers methods. + */ +bool controller_cb_empty(void *param, signal_t signal, level_t level, + ike_sa_t *ike_sa, char *format, va_list args); + +typedef struct controller_t controller_t; + +/** + * The controller provides a simple interface to run actions. + * + * The controller starts actions by creating jobs. It then tries to + * evaluate the result of the operation by listening on the bus. + * + * Passing NULL as callback to the managers function calls them asynchronously. + * If a callback is specified, they are called synchronoulsy. There is a default + * callback "controller_cb_empty" if you wan't to call a function + * synchronously, but don't need a callback. + */ +struct controller_t { + + /** + * Create an iterator for all IKE_SAs. + * + * The iterator blocks the IKE_SA manager until it gets destroyed. Do + * not call another interface/manager method while the iterator is alive. + * + * @return iterator, locks IKE_SA manager until destroyed + */ + iterator_t* (*create_ike_sa_iterator)(controller_t *this); + + /** + * Initiate a CHILD_SA, and if required, an IKE_SA. + * + * The inititate() function is synchronous and thus blocks until the + * IKE_SA is established or failed. Because of this, the initiate() function + * contains a thread cancellation point. + * + * @param peer_cfg peer_cfg to use for IKE_SA setup + * @param child_cfg child_cfg to set up CHILD_SA from + * @param cb logging callback + * @param param parameter to include in each call of cb + * @return + * - SUCCESS, if CHILD_SA established + * - FAILED, if setup failed + * - NEED_MORE, if callback returned FALSE + */ + status_t (*initiate)(controller_t *this, + peer_cfg_t *peer_cfg, child_cfg_t *child_cfg, + controller_cb_t callback, void *param); + + /** + * Terminate an IKE_SA and all of its CHILD_SAs. + * + * The terminate() function is synchronous and thus blocks until the + * IKE_SA is properly deleted, or the delete timed out. + * The terminate() function contains a thread cancellation point. + * + * @param unique_id unique id of the IKE_SA to terminate. + * @param cb logging callback + * @param param parameter to include in each call of cb + * @return + * - SUCCESS, if CHILD_SA terminated + * - NOT_FOUND, if no such CHILD_SA found + * - NEED_MORE, if callback returned FALSE + */ + status_t (*terminate_ike)(controller_t *this, u_int32_t unique_id, + controller_cb_t callback, void *param); + + /** + * Terminate a CHILD_SA. + * + * @param reqid reqid of the CHILD_SA to terminate + * @param cb logging callback + * @param param parameter to include in each call of cb + * @return + * - SUCCESS, if CHILD_SA terminated + * - NOT_FOUND, if no such CHILD_SA found + * - NEED_MORE, if callback returned FALSE + */ + status_t (*terminate_child)(controller_t *this, u_int32_t reqid, + controller_cb_t callback, void *param); + + /** + * Route a CHILD_SA (install triggering policies). + * + * @param peer_cfg peer_cfg to use for IKE_SA setup, if triggered + * @param child_cfg child_cfg to route + * @param cb logging callback + * @param param parameter to include in each call of cb + * @return + * - SUCCESS, if CHILD_SA routed + * - FAILED, if routing failed + * - NEED_MORE, if callback returned FALSE + */ + status_t (*route)(controller_t *this, + peer_cfg_t *peer_cfg, child_cfg_t *child_cfg, + controller_cb_t callback, void *param); + + /** + * Unroute a routed CHILD_SA (uninstall triggering policies). + * + * Only the route is removed, not the CHILD_SAs the route triggered. + * + * @param reqid reqid of the CHILD_SA to unroute + * @param cb logging callback + * @param param parameter to include in each call of cb + * @return + * - SUCCESS, if CHILD_SA terminated + * - NOT_FOUND, if no such CHILD_SA routed + * - NEED_MORE, if callback returned FALSE + */ + status_t (*unroute)(controller_t *this, u_int32_t reqid, + controller_cb_t callback, void *param); + + /** + * Destroy a controller_t instance. + */ + void (*destroy) (controller_t *this); +}; + + +/** + * Creates a controller instance. + * + * @return controller_t object + */ +controller_t *controller_create(void); + +#endif /* CONTROLLER_H_ @} */ diff --git a/src/charon/control/interface_manager.c b/src/charon/control/interface_manager.c deleted file mode 100644 index 4d5aa2ea6..000000000 --- a/src/charon/control/interface_manager.c +++ /dev/null @@ -1,665 +0,0 @@ -/** - * @file interface_manager.c - * - * @brief Implementation of interface_manager_t. - * - */ - -/* - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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 "interface_manager.h" - -#include -#include -#include -#include - -#include -#include -#include - - -typedef struct private_interface_manager_t private_interface_manager_t; -typedef struct interface_bus_listener_t interface_bus_listener_t; - -/** - * Private data of an stroke_t object. - */ -struct private_interface_manager_t { - - /** - * Public part of stroke_t object. - */ - interface_manager_t public; - - /** - * a list of all loaded interfaces - */ - linked_list_t *interfaces; - - /** - * dlopen() handles of interfaces - */ - linked_list_t *handles; -}; - - -/** - * helper struct to map bus listener callbacks to interface callbacks - */ -struct interface_bus_listener_t { - - /** - * public bus listener interface - */ - bus_listener_t public; - - /** - * status of the operation, return to method callers - */ - status_t status; - - /** - * IKE SA to filter log output - */ - ike_sa_t *ike_sa; - - /** - * interface callback (listener gets redirected to here) - */ - interface_manager_cb_t callback; - - /** - * user parameter to pass to callback - */ - void *param; - - /** - * child configuration, used for initiate - */ - child_cfg_t *child_cfg; - - /** - * peer configuration, used for initiate - */ - peer_cfg_t *peer_cfg; - - /** - * unique ID, used for various methods - */ - u_int32_t id; -}; - - -typedef struct interface_job_t interface_job_t; - -/** - * job for asynchronous listen operations - */ -struct interface_job_t { - /** - * job interface - */ - job_t public; - - /** - * associated listener - */ - interface_bus_listener_t listener; -}; - -/** - * Implements the famous nop operation - */ -static void nop(job_t *job) -{ - /* NOP */ -} - -/** - * Implementation of interface_manager_t.create_ike_sa_iterator. - */ -static iterator_t* create_ike_sa_iterator(interface_manager_t *this) -{ - return charon->ike_sa_manager->create_iterator(charon->ike_sa_manager); -} - -/** - * listener function for initiate - */ -static bool initiate_listener(interface_bus_listener_t *this, signal_t signal, - level_t level, int thread, ike_sa_t *ike_sa, - char* format, va_list args) -{ - if (this->ike_sa == ike_sa) - { - if (!this->callback(this->param, signal, level, ike_sa, format, args)) - { - return FALSE; - } - switch (signal) - { - case CHILD_UP_SUCCESS: - this->status = SUCCESS; - return FALSE; - case IKE_UP_FAILED: - case CHILD_UP_FAILED: - return FALSE; - default: - break; - } - } - return TRUE; -} - -/** - * execute function for initiate - */ -static status_t initiate_execute(interface_job_t *job) -{ - ike_sa_t *ike_sa; - interface_bus_listener_t *listener = &job->listener; - peer_cfg_t *peer_cfg = listener->peer_cfg; - - ike_sa = charon->ike_sa_manager->checkout_by_config(charon->ike_sa_manager, - peer_cfg); - listener->ike_sa = ike_sa; - - if (ike_sa->get_peer_cfg(ike_sa) == NULL) - { - ike_sa->set_peer_cfg(ike_sa, peer_cfg); - } - peer_cfg->destroy(peer_cfg); - - if (ike_sa->initiate(ike_sa, listener->child_cfg) != SUCCESS) - { - return charon->ike_sa_manager->checkin_and_destroy( - charon->ike_sa_manager, ike_sa); - } - return charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); -} - -/** - * Implementation of interface_manager_t.initiate. - */ -static status_t initiate(private_interface_manager_t *this, - peer_cfg_t *peer_cfg, child_cfg_t *child_cfg, - interface_manager_cb_t callback, void *param) -{ - interface_job_t job; - - job.listener.public.signal = (void*)initiate_listener; - job.listener.ike_sa = NULL; - job.listener.callback = callback; - job.listener.param = param; - job.listener.status = FAILED; - job.listener.child_cfg = child_cfg; - job.listener.peer_cfg = peer_cfg; - job.public.execute = (void*)initiate_execute; - job.public.destroy = nop; - - if (callback == NULL) - { - return initiate_execute(&job); - } - charon->bus->listen(charon->bus, (bus_listener_t*)&job.listener, (job_t*)&job); - return job.listener.status; -} - -/** - * listener function for terminate_ike - */ -static bool terminate_ike_listener(interface_bus_listener_t *this, signal_t signal, - level_t level, int thread, ike_sa_t *ike_sa, - char* format, va_list args) -{ - if (this->ike_sa == ike_sa) - { - if (!this->callback(this->param, signal, level, ike_sa, format, args)) - { - return FALSE; - } - switch (signal) - { - case IKE_DOWN_SUCCESS: - this->status = SUCCESS; - return FALSE; - case IKE_DOWN_FAILED: - return FALSE; - default: - break; - } - } - return TRUE; -} - -/** - * execute function for terminate_ike - */ -static status_t terminate_ike_execute(interface_job_t *job) -{ - ike_sa_t *ike_sa; - interface_bus_listener_t *listener = &job->listener; - - ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager, - listener->id, FALSE); - if (ike_sa == NULL) - { - SIG(IKE_DOWN_FAILED, "unable to terminate, IKE_SA with " - "ID %d not found", listener->id); - return NOT_FOUND; - } - listener->ike_sa = ike_sa; - - if (ike_sa->delete(ike_sa) == DESTROY_ME) - { - return charon->ike_sa_manager->checkin_and_destroy( - charon->ike_sa_manager, ike_sa); - } - return charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); -} - -/** - * Implementation of interface_manager_t.terminate_ike. - */ -static status_t terminate_ike(interface_manager_t *this, u_int32_t unique_id, - interface_manager_cb_t callback, void *param) -{ - interface_job_t job; - - job.listener.public.signal = (void*)terminate_ike_listener; - job.listener.ike_sa = NULL; - job.listener.callback = callback; - job.listener.param = param; - job.listener.status = FAILED; - job.listener.id = unique_id; - job.public.execute = (void*)terminate_ike_execute; - job.public.destroy = nop; - - if (callback == NULL) - { - return terminate_ike_execute(&job); - } - charon->bus->listen(charon->bus, (bus_listener_t*)&job.listener, (job_t*)&job); - return job.listener.status; -} -/** - * listener function for terminate_child - */ -static bool terminate_child_listener(interface_bus_listener_t *this, signal_t signal, - level_t level, int thread, ike_sa_t *ike_sa, - char* format, va_list args) -{ - if (this->ike_sa == ike_sa) - { - if (!this->callback(this->param, signal, level, ike_sa, format, args)) - { - return FALSE; - } - switch (signal) - { - case CHILD_DOWN_SUCCESS: - case IKE_DOWN_SUCCESS: - this->status = SUCCESS; - return FALSE; - case IKE_DOWN_FAILED: - case CHILD_DOWN_FAILED: - return FALSE; - default: - break; - } - } - return TRUE; -} - -/** - * execute function for terminate_child - */ -static status_t terminate_child_execute(interface_job_t *job) -{ - ike_sa_t *ike_sa; - child_sa_t *child_sa; - iterator_t *iterator; - interface_bus_listener_t *listener = &job->listener; - - ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager, - listener->id, TRUE); - if (ike_sa == NULL) - { - SIG(CHILD_DOWN_FAILED, "unable to terminate, CHILD_SA with " - "ID %d not found", listener->id); - return NOT_FOUND; - } - listener->ike_sa = ike_sa; - - iterator = ike_sa->create_child_sa_iterator(ike_sa); - while (iterator->iterate(iterator, (void**)&child_sa)) - { - if (child_sa->get_state(child_sa) != CHILD_ROUTED && - child_sa->get_reqid(child_sa) == listener->id) - { - break; - } - child_sa = NULL; - } - iterator->destroy(iterator); - - if (child_sa == NULL) - { - SIG(CHILD_DOWN_FAILED, "unable to terminate, established CHILD_SA with " - "ID %d not found", listener->id); - charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); - return NOT_FOUND; - } - - if (ike_sa->delete_child_sa(ike_sa, child_sa->get_protocol(child_sa), - child_sa->get_spi(child_sa, TRUE)) == DESTROY_ME) - { - return charon->ike_sa_manager->checkin_and_destroy( - charon->ike_sa_manager, ike_sa); - } - return charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); -} - -/** - * Implementation of interface_manager_t.terminate_child. - */ -static status_t terminate_child(interface_manager_t *this, u_int32_t reqid, - interface_manager_cb_t callback, void *param) -{ - interface_job_t job; - - job.listener.public.signal = (void*)terminate_child_listener; - job.listener.ike_sa = NULL; - job.listener.callback = callback; - job.listener.param = param; - job.listener.status = FAILED; - job.listener.id = reqid; - job.public.execute = (void*)terminate_child_execute; - job.public.destroy = nop; - - if (callback == NULL) - { - return terminate_child_execute(&job); - } - charon->bus->listen(charon->bus, (bus_listener_t*)&job.listener, (job_t*)&job); - return job.listener.status; -} - -/** - * listener function for route - */ -static bool route_listener(interface_bus_listener_t *this, signal_t signal, - level_t level, int thread, ike_sa_t *ike_sa, - char* format, va_list args) -{ - if (this->ike_sa == ike_sa) - { - if (!this->callback(this->param, signal, level, ike_sa, format, args)) - { - return FALSE; - } - switch (signal) - { - case CHILD_ROUTE_SUCCESS: - this->status = SUCCESS; - return FALSE; - case CHILD_ROUTE_FAILED: - return FALSE; - default: - break; - } - } - return TRUE; -} - -/** - * execute function for route - */ -static status_t route_execute(interface_job_t *job) -{ - ike_sa_t *ike_sa; - interface_bus_listener_t *listener = &job->listener; - peer_cfg_t *peer_cfg = listener->peer_cfg; - - ike_sa = charon->ike_sa_manager->checkout_by_config(charon->ike_sa_manager, - peer_cfg); - listener->ike_sa = ike_sa; - - if (ike_sa->get_peer_cfg(ike_sa) == NULL) - { - ike_sa->set_peer_cfg(ike_sa, peer_cfg); - } - if (ike_sa->route(ike_sa, listener->child_cfg) == DESTROY_ME) - { - return charon->ike_sa_manager->checkin_and_destroy( - charon->ike_sa_manager, ike_sa); - } - return charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); -} - -/** - * Implementation of interface_manager_t.route. - */ -static status_t route(interface_manager_t *this, - peer_cfg_t *peer_cfg, child_cfg_t *child_cfg, - interface_manager_cb_t callback, void *param) -{ - interface_job_t job; - - job.listener.public.signal = (void*)route_listener; - job.listener.ike_sa = NULL; - job.listener.callback = callback; - job.listener.param = param; - job.listener.status = FAILED; - job.listener.peer_cfg = peer_cfg; - job.listener.child_cfg = child_cfg; - job.public.execute = (void*)route_execute; - job.public.destroy = nop; - - if (callback == NULL) - { - return route_execute(&job); - } - charon->bus->listen(charon->bus, (bus_listener_t*)&job.listener, (job_t*)&job); - return job.listener.status; -} - -/** - * listener function for unroute - */ -static bool unroute_listener(interface_bus_listener_t *this, signal_t signal, - level_t level, int thread, ike_sa_t *ike_sa, - char* format, va_list args) -{ - if (this->ike_sa == ike_sa) - { - if (!this->callback(this->param, signal, level, ike_sa, format, args)) - { - return FALSE; - } - switch (signal) - { - case CHILD_UNROUTE_SUCCESS: - this->status = SUCCESS; - return FALSE; - case CHILD_UNROUTE_FAILED: - return FALSE; - default: - break; - } - } - return TRUE; -} -/** - * execute function for unroute - */ -static status_t unroute_execute(interface_job_t *job) -{ - ike_sa_t *ike_sa; - interface_bus_listener_t *listener = &job->listener; - - ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager, - listener->id, TRUE); - if (ike_sa == NULL) - { - SIG(CHILD_DOWN_FAILED, "unable to unroute, CHILD_SA with " - "ID %d not found", listener->id); - return NOT_FOUND; - } - listener->ike_sa = ike_sa; - if (ike_sa->unroute(ike_sa, listener->id) == DESTROY_ME) - { - return charon->ike_sa_manager->checkin_and_destroy( - charon->ike_sa_manager, ike_sa); - } - return charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); -} - -/** - * Implementation of interface_manager_t.unroute. - */ -static status_t unroute(interface_manager_t *this, u_int32_t reqid, - interface_manager_cb_t callback, void *param) -{ - interface_job_t job; - - job.listener.public.signal = (void*)unroute_listener; - job.listener.ike_sa = NULL; - job.listener.callback = callback; - job.listener.param = param; - job.listener.status = FAILED; - job.listener.id = reqid; - job.public.execute = (void*)unroute_execute; - job.public.destroy = nop; - - if (callback == NULL) - { - return unroute_execute(&job); - } - charon->bus->listen(charon->bus, (bus_listener_t*)&job.listener, (job_t*)&job); - return job.listener.status; -} - -/** - * load the control interface modules - */ -static void load_interfaces(private_interface_manager_t *this) -{ - struct dirent* entry; - DIR* dir; - - dir = opendir(IPSEC_INTERFACEDIR); - if (dir == NULL) - { - DBG1(DBG_CFG, "error opening interface modules directory "IPSEC_INTERFACEDIR); - return; - } - - DBG1(DBG_CFG, "loading control interface modules from '"IPSEC_INTERFACEDIR"'"); - - while ((entry = readdir(dir)) != NULL) - { - char file[256]; - interface_t *interface; - interface_constructor_t constructor; - void *handle; - char *ending; - - snprintf(file, sizeof(file), IPSEC_INTERFACEDIR"/%s", entry->d_name); - - ending = entry->d_name + strlen(entry->d_name) - 3; - if (ending <= entry->d_name || !streq(ending, ".so")) - { - /* skip anything which does not look like a library */ - DBG2(DBG_CFG, " skipping %s, doesn't look like a library", - entry->d_name); - continue; - } - /* try to load the library */ - handle = dlopen(file, RTLD_LAZY); - if (handle == NULL) - { - DBG1(DBG_CFG, " opening control interface module %s failed: %s", - entry->d_name, dlerror()); - continue; - } - constructor = dlsym(handle, "interface_create"); - if (constructor == NULL) - { - DBG1(DBG_CFG, " interface module %s has no interface_create() " - "function, skipped", entry->d_name); - dlclose(handle); - continue; - } - - interface = constructor(); - if (interface == NULL) - { - DBG1(DBG_CFG, " unable to create instance of interface " - "module %s, skipped", entry->d_name); - dlclose(handle); - continue; - } - DBG1(DBG_CFG, " loaded control interface module successfully from %s", entry->d_name); - this->interfaces->insert_last(this->interfaces, interface); - this->handles->insert_last(this->handles, handle); - } - closedir(dir); -} - -/** - * See header - */ -bool interface_manager_cb_empty(void *param, signal_t signal, level_t level, - ike_sa_t *ike_sa, char *format, va_list args) -{ - return TRUE; -} - -/** - * Implementation of stroke_t.destroy. - */ -static void destroy(private_interface_manager_t *this) -{ - this->interfaces->destroy_offset(this->interfaces, offsetof(interface_t, destroy)); - this->handles->destroy_function(this->handles, (void*)dlclose); - free(this); -} - -/* - * Described in header-file - */ -interface_manager_t *interface_manager_create(void) -{ - private_interface_manager_t *this = malloc_thing(private_interface_manager_t); - - this->public.create_ike_sa_iterator = (iterator_t*(*)(interface_manager_t*))create_ike_sa_iterator; - this->public.initiate = (status_t(*)(interface_manager_t*,peer_cfg_t*,child_cfg_t*,bool(*)(void*,signal_t,level_t,ike_sa_t*,char*,va_list),void*))initiate; - this->public.terminate_ike = (status_t(*)(interface_manager_t*,u_int32_t,interface_manager_cb_t, void*))terminate_ike; - this->public.terminate_child = (status_t(*)(interface_manager_t*,u_int32_t,interface_manager_cb_t, void *param))terminate_child; - this->public.route = (status_t(*)(interface_manager_t*,peer_cfg_t*, child_cfg_t*,interface_manager_cb_t,void*))route; - this->public.unroute = (status_t(*)(interface_manager_t*,u_int32_t,interface_manager_cb_t,void*))unroute; - this->public.destroy = (void (*)(interface_manager_t*))destroy; - - this->interfaces = linked_list_create(); - this->handles = linked_list_create(); - - load_interfaces(this); - - return &this->public; -} - diff --git a/src/charon/control/interface_manager.h b/src/charon/control/interface_manager.h deleted file mode 100644 index 3ee1f0e39..000000000 --- a/src/charon/control/interface_manager.h +++ /dev/null @@ -1,206 +0,0 @@ -/** - * @file interface_manager.h - * - * @brief Interface of interface_manager_t. - * - */ - -/* - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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 INTERFACE_MANAGER_H_ -#define INTERFACE_MANAGER_H_ - -#include - -/** - * callback to log things triggered by interface_manager. - * - * @param param echoed parameter supplied when function invoked - * @param signal type of signal - * @param level verbosity level if log - * @param ike_sa associated IKE_SA, if any - * @param format printf like format string - * @param args list of arguments to use for format - * @return FALSE to return from invoked function - * @ingroup control - */ -typedef bool(*interface_manager_cb_t)(void* param, signal_t signal, level_t level, - ike_sa_t* ike_sa, char* format, va_list args); - -/** - * @brief Empty callback function for interface_manager_t functions. - * - * If you wan't to do a syncrhonous call, but don't need a callback, pass - * this function to the interface_managers methods. - */ -bool interface_manager_cb_empty(void *param, signal_t signal, level_t level, - ike_sa_t *ike_sa, char *format, va_list args); - -typedef struct interface_manager_t interface_manager_t; - -/** - * @brief The interface_manager loads control interfaces and has helper methods. - * - * One job of the interface manager is to load pluggable control interface - * modules, implemented as interface_t. - * @verbatim - - +---------+ +------------+ +--------------+ | - | | | |<----- +--------------+ | | - | daemon |<-----| interface- | +--------------+ |-+ <==|==> IPC - | core | | manager |<----| interfaces |-+ | - | |<-----| | +--------------+ | - | | | | | - +---------+ +------------+ | - - @endverbatim - * The manager does not really use the interfaces, instead, the interface - * use the manager to fullfill their tasks (initiating, terminating, ...). - * The interface_manager starts actions by creating jobs. It then tries to - * evaluate the result of the operation by listening on the bus. - * - * Passing NULL as callback to the managers function calls them asynchronously. - * If a callback is specified, they are called synchronoulsy. There is a default - * callback "interface_manager_cb_empty" if you wan't to call a function - * synchronously, but don't need a callback. - * - * @b Constructors: - * - interface_manager_create() - * - * @ingroup control - */ -struct interface_manager_t { - - /** - * @brief Create an iterator for all IKE_SAs. - * - * The iterator blocks the IKE_SA manager until it gets destroyed. Do - * not call another interface/manager method while the iterator is alive. - * - * @param this calling object - * @return iterator, locks IKE_SA manager until destroyed - */ - iterator_t* (*create_ike_sa_iterator)(interface_manager_t *this); - - /** - * @brief Initiate a CHILD_SA, and if required, an IKE_SA. - * - * The inititate() function is synchronous and thus blocks until the - * IKE_SA is established or failed. Because of this, the initiate() function - * contains a thread cancellation point. - * - * @param this calling object - * @param peer_cfg peer_cfg to use for IKE_SA setup - * @param child_cfg child_cfg to set up CHILD_SA from - * @param cb logging callback - * @param param parameter to include in each call of cb - * @return - * - SUCCESS, if CHILD_SA established - * - FAILED, if setup failed - * - NEED_MORE, if callback returned FALSE - */ - status_t (*initiate)(interface_manager_t *this, - peer_cfg_t *peer_cfg, child_cfg_t *child_cfg, - interface_manager_cb_t callback, void *param); - - /** - * @brief Terminate an IKE_SA and all of its CHILD_SAs. - * - * The terminate() function is synchronous and thus blocks until the - * IKE_SA is properly deleted, or the delete timed out. - * The terminate() function contains a thread cancellation point. - * - * @param this calling object - * @param unique_id unique id of the IKE_SA to terminate. - * @param cb logging callback - * @param param parameter to include in each call of cb - * @return - * - SUCCESS, if CHILD_SA terminated - * - NOT_FOUND, if no such CHILD_SA found - * - NEED_MORE, if callback returned FALSE - */ - status_t (*terminate_ike)(interface_manager_t *this, u_int32_t unique_id, - interface_manager_cb_t callback, void *param); - - /** - * @brief Terminate a CHILD_SA. - * - * @param this calling object - * @param reqid reqid of the CHILD_SA to terminate - * @param cb logging callback - * @param param parameter to include in each call of cb - * @return - * - SUCCESS, if CHILD_SA terminated - * - NOT_FOUND, if no such CHILD_SA found - * - NEED_MORE, if callback returned FALSE - */ - status_t (*terminate_child)(interface_manager_t *this, u_int32_t reqid, - interface_manager_cb_t callback, void *param); - - /** - * @brief Route a CHILD_SA (install triggering policies). - * - * @param this calling object - * @param peer_cfg peer_cfg to use for IKE_SA setup, if triggered - * @param child_cfg child_cfg to route - * @param cb logging callback - * @param param parameter to include in each call of cb - * @return - * - SUCCESS, if CHILD_SA routed - * - FAILED, if routing failed - * - NEED_MORE, if callback returned FALSE - */ - status_t (*route)(interface_manager_t *this, - peer_cfg_t *peer_cfg, child_cfg_t *child_cfg, - interface_manager_cb_t callback, void *param); - - /** - * @brief Unroute a routed CHILD_SA (uninstall triggering policies). - * - * Only the route is removed, not the CHILD_SAs the route triggered. - * - * @param this calling object - * @param reqid reqid of the CHILD_SA to unroute - * @param cb logging callback - * @param param parameter to include in each call of cb - * @return - * - SUCCESS, if CHILD_SA terminated - * - NOT_FOUND, if no such CHILD_SA routed - * - NEED_MORE, if callback returned FALSE - */ - status_t (*unroute)(interface_manager_t *this, u_int32_t reqid, - interface_manager_cb_t callback, void *param); - - /** - * @brief Destroy a interface_manager_t instance. - * - * @param this interface_manager_t objec to destroy - */ - void (*destroy) (interface_manager_t *this); -}; - - -/** - * @brief Creates a interface_manager instance and loads all interface modules. - * - * @return interface_manager_t object - * - * @ingroup control - */ -interface_manager_t *interface_manager_create(void); - -#endif /* INTERFACE_MANAGER_H_ */ - diff --git a/src/charon/control/interfaces/dbus_interface.c b/src/charon/control/interfaces/dbus_interface.c deleted file mode 100644 index 39226aaef..000000000 --- a/src/charon/control/interfaces/dbus_interface.c +++ /dev/null @@ -1,427 +0,0 @@ -/** - * @file dbus_interface.c - * - * @brief Implementation of dbus_interface_t. - * - */ - -/* - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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 DBUS_API_SUBJECT_TO_CHANGE -#include -#include -#include -#include - -#include "dbus_interface.h" - -#include -#include -#include - - -#define NM_DBUS_SERVICE_STRONG "org.freedesktop.NetworkManager.strongswan" -#define NM_DBUS_INTERFACE_STRONG "org.freedesktop.NetworkManager.strongswan" -#define NM_DBUS_PATH_STRONG "/org/freedesktop/NetworkManager/strongswan" - -typedef struct private_dbus_interface_t private_dbus_interface_t; - -/** - * Private data of an dbus_interface_t object. - */ -struct private_dbus_interface_t { - - /** - * Public part of dbus_t object. - */ - dbus_interface_t public; - - /** - * DBUS connection - */ - DBusConnection* conn; - - /** - * error value used here and there - */ - DBusError err; - - /** - * state of the daemon - */ - NMVPNState state; - - /** - * job accepting stroke messages - */ - callback_job_t *job; - - /** - * name of the currently active connection - */ - char *name; -}; - -/** - * set daemon state and send StateChange signal to the bus - */ -static void set_state(private_dbus_interface_t *this, NMVPNState state) -{ - DBusMessage* msg; - - msg = dbus_message_new_signal(NM_DBUS_PATH_STRONG, NM_DBUS_INTERFACE_STRONG, NM_DBUS_VPN_SIGNAL_STATE_CHANGE); - - if (!dbus_message_append_args(msg, DBUS_TYPE_UINT32, &this->state, - DBUS_TYPE_UINT32, &state, DBUS_TYPE_INVALID) || - !dbus_connection_send(this->conn, msg, NULL)) - { - DBG1(DBG_CFG, "unable to send DBUS StateChange signal"); - } - dbus_connection_flush(this->conn); - dbus_message_unref(msg); - this->state = state; -} - - -/** - * get the child_cfg with the same name as the peer cfg - */ -static child_cfg_t* get_child_from_peer(peer_cfg_t *peer_cfg, char *name) -{ - child_cfg_t *current, *found = NULL; - iterator_t *iterator; - - iterator = peer_cfg->create_child_cfg_iterator(peer_cfg); - while (iterator->iterate(iterator, (void**)¤t)) - { - if (streq(current->get_name(current), name)) - { - found = current; - found->get_ref(found); - break; - } - } - iterator->destroy(iterator); - return found; -} - - -/** - * process NetworkManagers startConnection method call - */ -static bool start_connection(private_dbus_interface_t *this, DBusMessage* msg) -{ - DBusMessage *reply, *signal; - char *name, *user, **data, **passwords, **routes; - int data_count, passwords_count, routes_count; - u_int32_t me, other, p2p, netmask, mss; - char *dev, *domain, *banner; - const dbus_int32_t array[] = {}; - const dbus_int32_t *varray = array; - peer_cfg_t *peer_cfg; - child_cfg_t *child_cfg; - status_t status = FAILED; - - dbus_error_free(&this->err); - - if (!dbus_message_get_args(msg, &this->err, - DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &user, - DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &passwords, &passwords_count, - DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &data, &data_count, - DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &routes, &routes_count, - DBUS_TYPE_INVALID)) - { - return FALSE; - } - set_state(this, NM_VPN_STATE_STARTING); - - peer_cfg = charon->backends->get_peer_cfg_by_name(charon->backends, name); - if (peer_cfg) - { - free(this->name); - this->name = strdup(peer_cfg->get_name(peer_cfg)); - child_cfg = get_child_from_peer(peer_cfg, name); - if (child_cfg) - { - status = charon->interfaces->initiate(charon->interfaces, - peer_cfg, child_cfg, interface_manager_cb_empty, NULL); - } - else - { - peer_cfg->destroy(peer_cfg); - } - } - reply = dbus_message_new_method_return(msg); - dbus_connection_send(this->conn, reply, NULL); - dbus_message_unref(reply); - - if (status == SUCCESS) - { - - set_state(this, NM_VPN_STATE_STARTED); - signal = dbus_message_new_signal(NM_DBUS_PATH_STRONG, - NM_DBUS_INTERFACE_STRONG, - NM_DBUS_VPN_SIGNAL_IP4_CONFIG); - me = other = p2p = mss = netmask = 0; - dev = domain = banner = ""; - if (dbus_message_append_args(signal, - DBUS_TYPE_UINT32, &other, - DBUS_TYPE_STRING, &dev, - DBUS_TYPE_UINT32, &me, - DBUS_TYPE_UINT32, &p2p, - DBUS_TYPE_UINT32, &netmask, - DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &varray, 0, - DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &varray, 0, - DBUS_TYPE_UINT32, &mss, - DBUS_TYPE_STRING, &domain, - DBUS_TYPE_STRING, &banner, DBUS_TYPE_INVALID)) - { - dbus_connection_send(this->conn, signal, NULL); - } - dbus_message_unref(signal); - } - else - { - set_state(this, NM_VPN_STATE_STOPPED); - } - - dbus_connection_flush(this->conn); - return TRUE; -} - -/** - * process NetworkManagers stopConnection method call - */ -static bool stop_connection(private_dbus_interface_t *this, DBusMessage* msg) -{ - u_int32_t id; - iterator_t *iterator; - ike_sa_t *ike_sa; - - if (this->name == NULL) - { - return FALSE; - } - - dbus_error_free(&this->err); - - set_state(this, NM_VPN_STATE_STOPPING); - - iterator = charon->interfaces->create_ike_sa_iterator(charon->interfaces); - while (iterator->iterate(iterator, (void**)&ike_sa)) - { - child_sa_t *child_sa; - iterator_t *children; - - if (this->name && streq(this->name, ike_sa->get_name(ike_sa))) - { - id = ike_sa->get_unique_id(ike_sa); - iterator->destroy(iterator); - charon->interfaces->terminate_ike(charon->interfaces, id, NULL, NULL); - set_state(this, NM_VPN_STATE_STOPPED); - return TRUE;; - } - children = ike_sa->create_child_sa_iterator(ike_sa); - while (children->iterate(children, (void**)&child_sa)) - { - if (this->name && streq(this->name, child_sa->get_name(child_sa))) - { - id = child_sa->get_reqid(child_sa); - children->destroy(children); - iterator->destroy(iterator); - charon->interfaces->terminate_child(charon->interfaces, id, NULL, NULL); - set_state(this, NM_VPN_STATE_STOPPED); - return TRUE; - } - } - children->destroy(children); - } - iterator->destroy(iterator); - set_state(this, NM_VPN_STATE_STOPPED); - return TRUE; -} - -/** - * process NetworkManagers getState method call - */ -static bool get_state(private_dbus_interface_t *this, DBusMessage* msg) -{ - DBusMessage* reply; - reply = dbus_message_new_method_return(msg); - if (!reply || !dbus_message_append_args(reply, - DBUS_TYPE_UINT32, &this->state, - DBUS_TYPE_INVALID)) - { - return FALSE; - } - dbus_connection_send(this->conn, reply, NULL); - return TRUE; -} - -/** - * Handle incoming messages - */ -static DBusHandlerResult message_handler(DBusConnection *con, DBusMessage *msg, - private_dbus_interface_t *this) -{ - bool handled; - - if (dbus_message_is_method_call(msg, NM_DBUS_INTERFACE_STRONG, - "startConnection")) - { - handled = start_connection(this, msg); - } - else if (dbus_message_is_method_call(msg, NM_DBUS_INTERFACE_STRONG, - "stopConnection")) - { - handled = stop_connection(this, msg); - } - else if (dbus_message_is_method_call(msg, NM_DBUS_INTERFACE_STRONG, - "getState")) - { - handled = get_state(this, msg); - } - else - { - DBG1(DBG_CFG, "ignoring DBUS message %s.%s", - dbus_message_get_interface(msg), dbus_message_get_member(msg)); - handled = FALSE; - } - - if (handled) - { - return DBUS_HANDLER_RESULT_HANDLED; - } - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; -} - -/** - * Handle received signals - -static DBusHandlerResult signal_handler(DBusConnection *con, DBusMessage *msg, - private_dbus_interface_t *this) -{ - bool handled; - - if (dbus_message_is_signal(msg, NM_DBUS_INTERFACE, "VPNConnectionStateChange")) - { - NMVPNState state; - char *name; - - if (dbus_message_get_args(msg, &this->err, DBUS_TYPE_STRING, &name, - DBUS_TYPE_UINT32, &state, DBUS_TYPE_INVALID)) - { - DBG1(DBG_CFG, "got state %d for %s", state, name); - } - handled = TRUE; - } - else - { - DBG1(DBG_CFG, "ignoring DBUS signal %s.%s", - dbus_message_get_interface(msg), dbus_message_get_member(msg)); - handled = FALSE; - } - if (handled) - { - return DBUS_HANDLER_RESULT_HANDLED; - } - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; -} */ - -/** - * dispatcher function processed by a seperate thread - */ -static job_requeue_t dispatch(private_dbus_interface_t *this) -{ - if (dbus_connection_read_write_dispatch(this->conn, -1)) - { - return JOB_REQUEUE_DIRECT; - } - return JOB_REQUEUE_NONE; -} - -/** - * Implementation of interface_t.destroy. - */ -static void destroy(private_dbus_interface_t *this) -{ - this->job->cancel(this->job); - dbus_connection_close(this->conn); - dbus_error_free(&this->err); - dbus_shutdown(); - free(this->name); - free(this); -} - -/* - * Described in header file - */ -interface_t *interface_create() -{ - int ret; - DBusObjectPathVTable v = {NULL, (void*)&message_handler, NULL, NULL, NULL, NULL}; - private_dbus_interface_t *this = malloc_thing(private_dbus_interface_t); - - this->public.interface.destroy = (void (*)(interface_t*))destroy; - - dbus_error_init(&this->err); - this->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &this->err); - if (dbus_error_is_set(&this->err)) - { - DBG1(DBG_CFG, "unable to open DBUS connection: %s", this->err.message); - charon->kill(charon, "DBUS initialization failed"); - } - dbus_connection_set_exit_on_disconnect(this->conn, FALSE); - - ret = dbus_bus_request_name(this->conn, NM_DBUS_SERVICE_STRONG, - DBUS_NAME_FLAG_REPLACE_EXISTING , &this->err); - if (dbus_error_is_set(&this->err)) - { - DBG1(DBG_CFG, "unable to set DBUS name: %s", this->err.message); - charon->kill(charon, "unable to set DBUS name"); - } - if (ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) - { - charon->kill(charon, "DBUS name already owned"); - } - if (!dbus_connection_register_object_path(this->conn, NM_DBUS_PATH_STRONG, &v, this)) - { - charon->kill(charon, "unable to register DBUS message handler"); - } - /* - if (!dbus_connection_add_filter(this->conn, (void*)signal_handler, this, NULL)) - { - charon->kill(charon, "unable to register DBUS signal handler"); - } - - dbus_bus_add_match(this->conn, "type='signal', " - "interface='" NM_DBUS_INTERFACE_VPN "'," - "path='" NM_DBUS_PATH_VPN "'", &this->err); - if (dbus_error_is_set (&this->err)) - { - charon->kill(charon, "unable to add DBUS signal match"); - }*/ - - this->name = NULL; - this->state = NM_VPN_STATE_INIT; - set_state(this, NM_VPN_STATE_STOPPED); - - this->job = callback_job_create((callback_job_cb_t)dispatch, this, NULL, NULL); - charon->processor->queue_job(charon->processor, (job_t*)this->job); - - return &this->public.interface; -} - diff --git a/src/charon/control/interfaces/dbus_interface.h b/src/charon/control/interfaces/dbus_interface.h deleted file mode 100644 index 0ce57bbbc..000000000 --- a/src/charon/control/interfaces/dbus_interface.h +++ /dev/null @@ -1,57 +0,0 @@ -/** - * @file dbus_interface.h - * - * @brief Interface of dbus_interface_t. - * - */ - -/* - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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 DBUS_INTERFACE_H_ -#define DBUS_INTERFACE_H_ - -typedef struct dbus_interface_t dbus_interface_t; - -#include - -/** - * @brief The DBUS interface uses the DBUS system bus to communicate. - * - * @b Constructors: - * - dbus_interface_create() - * - * @ingroup interfaces - */ -struct dbus_interface_t { - - /** - * implements interface_t. - */ - interface_t interface; -}; - - -/** - * @brief Create the DBUS interface. - * - * @return stroke_t object - * - * @ingroup interfaces - */ -interface_t *interface_create(); - -#endif /* DBUS_INTERFACE_H_ */ - diff --git a/src/charon/control/interfaces/interface.h b/src/charon/control/interfaces/interface.h deleted file mode 100644 index 955f4a4eb..000000000 --- a/src/charon/control/interfaces/interface.h +++ /dev/null @@ -1,59 +0,0 @@ -/** - * @file interface.h - * - * @brief Interface of interface_t. - * - */ - -/* - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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 INTERFACE_H_ -#define INTERFACE_H_ - -typedef struct interface_t interface_t; - -/** - * @brief Interface for a controller. - * - * An interface controls the daemon by calling functions on the - * interface_manager. All interfaces are manager by the interface_manager - * in a generic way, so they need their own class. - * - * @b Constructors: - * - interface_create() of one of the modules - * - * @ingroup interfaces - */ -struct interface_t { - - /** - * @brief Destroy all interfaces - * - * @param this stroke_t objec to destroy - */ - void (*destroy) (interface_t *this); -}; - - -/** - * Constructor in a control interface module to create the interface. - * - * @ingroup interfaces - */ -typedef interface_t*(*interface_constructor_t)(void); - -#endif /* INTERFACE_H_ */ - diff --git a/src/charon/control/interfaces/stroke_interface.c b/src/charon/control/interfaces/stroke_interface.c deleted file mode 100755 index 3b4b246bd..000000000 --- a/src/charon/control/interfaces/stroke_interface.c +++ /dev/null @@ -1,1818 +0,0 @@ -/** - * @file stroke_interface.c - * - * @brief Implementation of stroke_interface_t. - * - */ - -/* - * Copyright (C) 2007 Tobias Brunner - * Copyright (C) 2006-2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "stroke_interface.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define IKE_PORT 500 -#define PATH_BUF 256 -#define STROKE_THREADS 3 - -typedef struct private_stroke_interface_t private_stroke_interface_t; - -/** - * Private data of an stroke_interfacet object. - */ -struct private_stroke_interface_t { - - /** - * Public part of stroke_interfacet object. - */ - stroke_interface_t public; - - /** - * Unix socket to listen for strokes - */ - int socket; - - /** - * job accepting stroke messages - */ - callback_job_t *job; -}; - -typedef struct stroke_log_info_t stroke_log_info_t; - -/** - * helper struct to say what and where to log when using controller callback - */ -struct stroke_log_info_t { - - /** - * level to log up to - */ - level_t level; - - /** - * where to write log - */ - FILE* out; -}; - -/** - * Helper function which corrects the string pointers - * in a stroke_msg_t. Strings in a stroke_msg sent over "wire" - * contains RELATIVE addresses (relative to the beginning of the - * stroke_msg). They must be corrected if they reach our address - * space... - */ -static void pop_string(stroke_msg_t *msg, char **string) -{ - if (*string == NULL) - return; - - /* check for sanity of string pointer and string */ - if (string < (char**)msg - || string > (char**)msg + sizeof(stroke_msg_t) - || (unsigned long)*string < (unsigned long)((char*)msg->buffer - (char*)msg) - || (unsigned long)*string > msg->length) - { - *string = "(invalid pointer in stroke msg)"; - } - else - { - *string = (char*)msg + (unsigned long)*string; - } -} - -/** - * Load end entitity certificate - */ -static x509_t* load_end_certificate(const char *filename, identification_t **idp) -{ - char path[PATH_BUF]; - x509_t *cert; - - if (*filename == '/') - { - /* absolute path name */ - snprintf(path, sizeof(path), "%s", filename); - } - else - { - /* relative path name */ - snprintf(path, sizeof(path), "%s/%s", CERTIFICATE_DIR, filename); - } - - cert = x509_create_from_file(path, "end entity"); - - if (cert) - { - identification_t *id = *idp; - identification_t *subject = cert->get_subject(cert); - - err_t ugh = cert->is_valid(cert, NULL); - - if (ugh != NULL) - { - DBG1(DBG_CFG, "warning: certificate %s", ugh); - } - if (!id->equals(id, subject) && !cert->equals_subjectAltName(cert, id)) - { - id->destroy(id); - id = subject; - *idp = id->clone(id); - } - return charon->credentials->add_end_certificate(charon->credentials, cert); - } - return NULL; -} - -/** - * Load ca certificate - */ -static x509_t* load_ca_certificate(const char *filename) -{ - char path[PATH_BUF]; - x509_t *cert; - - if (*filename == '/') - { - /* absolute path name */ - snprintf(path, sizeof(path), "%s", filename); - } - else - { - /* relative path name */ - snprintf(path, sizeof(path), "%s/%s", CA_CERTIFICATE_DIR, filename); - } - - cert = x509_create_from_file(path, "ca"); - - if (cert) - { - if (cert->is_ca(cert)) - { - return charon->credentials->add_auth_certificate(charon->credentials, cert, AUTH_CA); - } - else - { - DBG1(DBG_CFG, " CA basic constraints flag not set, cert discarded"); - cert->destroy(cert); - } - } - return NULL; -} - -/** - * Pop the strings of a stroke_end_t struct and log them for debugging purposes - */ -static void pop_end(stroke_msg_t *msg, const char* label, stroke_end_t *end) -{ - pop_string(msg, &end->address); - pop_string(msg, &end->subnet); - pop_string(msg, &end->sourceip); - pop_string(msg, &end->id); - pop_string(msg, &end->cert); - pop_string(msg, &end->ca); - pop_string(msg, &end->groups); - pop_string(msg, &end->updown); - - DBG2(DBG_CFG, " %s=%s", label, end->address); - DBG2(DBG_CFG, " %ssubnet=%s", label, end->subnet); - DBG2(DBG_CFG, " %ssourceip=%s", label, end->sourceip); - DBG2(DBG_CFG, " %sid=%s", label, end->id); - DBG2(DBG_CFG, " %scert=%s", label, end->cert); - DBG2(DBG_CFG, " %sca=%s", label, end->ca); - DBG2(DBG_CFG, " %sgroups=%s", label, end->groups); - DBG2(DBG_CFG, " %supdown=%s", label, end->updown); -} - -/** - * Add a connection to the configuration list - */ -static void stroke_add_conn(stroke_msg_t *msg, FILE *out) -{ - ike_cfg_t *ike_cfg; - peer_cfg_t *peer_cfg; - peer_cfg_t *mediated_by_cfg = NULL; - child_cfg_t *child_cfg; - identification_t *my_id, *other_id; - identification_t *my_ca = NULL; - identification_t *other_ca = NULL; - identification_t *peer_id = NULL; - bool my_ca_same = FALSE; - bool other_ca_same =FALSE; - host_t *my_host, *other_host, *my_subnet, *other_subnet; - host_t *my_vip = NULL, *other_vip = NULL; - linked_list_t *other_groups = linked_list_create(); - proposal_t *proposal; - traffic_selector_t *my_ts, *other_ts; - char *interface; - bool use_existing = FALSE; - iterator_t *iterator; - u_int32_t vendor; - - pop_string(msg, &msg->add_conn.name); - DBG1(DBG_CFG, "received stroke: add connection '%s'", msg->add_conn.name); - DBG2(DBG_CFG, "conn %s", msg->add_conn.name); - pop_end(msg, "left", &msg->add_conn.me); - pop_end(msg, "right", &msg->add_conn.other); - pop_string(msg, &msg->add_conn.algorithms.ike); - pop_string(msg, &msg->add_conn.algorithms.esp); - DBG2(DBG_CFG, " ike=%s", msg->add_conn.algorithms.ike); - DBG2(DBG_CFG, " esp=%s", msg->add_conn.algorithms.esp); - pop_string(msg, &msg->add_conn.p2p.mediated_by); - pop_string(msg, &msg->add_conn.p2p.peerid); - DBG2(DBG_CFG, " p2p_mediation=%s", msg->add_conn.p2p.mediation ? "yes" : "no"); - DBG2(DBG_CFG, " p2p_mediated_by=%s", msg->add_conn.p2p.mediated_by); - DBG2(DBG_CFG, " p2p_peerid=%s", msg->add_conn.p2p.peerid); - - my_host = msg->add_conn.me.address ? - host_create_from_string(msg->add_conn.me.address, IKE_PORT) : NULL; - if (my_host == NULL) - { - DBG1(DBG_CFG, "invalid host: %s\n", msg->add_conn.me.address); - return; - } - - other_host = msg->add_conn.other.address ? - host_create_from_string(msg->add_conn.other.address, IKE_PORT) : NULL; - if (other_host == NULL) - { - DBG1(DBG_CFG, "invalid host: %s\n", msg->add_conn.other.address); - my_host->destroy(my_host); - return; - } - - interface = charon->kernel_interface->get_interface(charon->kernel_interface, - other_host); - if (interface) - { - stroke_end_t tmp_end; - host_t *tmp_host; - - DBG2(DBG_CFG, "left is other host, swapping ends\n"); - - tmp_host = my_host; - my_host = other_host; - other_host = tmp_host; - - tmp_end = msg->add_conn.me; - msg->add_conn.me = msg->add_conn.other; - msg->add_conn.other = tmp_end; - free(interface); - } - else - { - interface = charon->kernel_interface->get_interface( - charon->kernel_interface, my_host); - if (!interface) - { - DBG1(DBG_CFG, "left nor right host is our side, assuming left=local"); - } - else - { - free(interface); - } - } - - my_id = identification_create_from_string(msg->add_conn.me.id ? - msg->add_conn.me.id : msg->add_conn.me.address); - if (my_id == NULL) - { - DBG1(DBG_CFG, "invalid ID: %s\n", msg->add_conn.me.id); - goto destroy_hosts; - } - - other_id = identification_create_from_string(msg->add_conn.other.id ? - msg->add_conn.other.id : msg->add_conn.other.address); - if (other_id == NULL) - { - DBG1(DBG_CFG, "invalid ID: %s\n", msg->add_conn.other.id); - my_id->destroy(my_id); - goto destroy_hosts; - } - -#ifdef P2P - if (msg->add_conn.p2p.mediation && msg->add_conn.p2p.mediated_by) - { - DBG1(DBG_CFG, "a mediation connection cannot be a" - " mediated connection at the same time, aborting"); - goto destroy_ids; - } - - if (msg->add_conn.p2p.mediated_by) - { - mediated_by_cfg = charon->backends->get_peer_cfg_by_name(charon->backends, msg->add_conn.p2p.mediated_by); - if (!mediated_by_cfg) - { - DBG1(DBG_CFG, "mediation connection '%s' not found, aborting", - msg->add_conn.p2p.mediated_by); - goto destroy_ids; - } - - if (!mediated_by_cfg->is_mediation(mediated_by_cfg)) - { - DBG1(DBG_CFG, "connection '%s' as referred to by '%s' is" - "no mediation connection, aborting", - msg->add_conn.p2p.mediated_by, msg->add_conn.name); - goto destroy_ids; - } - } - - if (msg->add_conn.p2p.peerid) - { - peer_id = identification_create_from_string(msg->add_conn.p2p.peerid); - if (!peer_id) - { - DBG1(DBG_CFG, "invalid peer ID: %s\n", msg->add_conn.p2p.peerid); - goto destroy_ids; - } - } - else - { - /* no peer ID supplied, assume right ID */ - peer_id = other_id->clone(other_id); - } -#endif /* P2P */ - - my_subnet = host_create_from_string(msg->add_conn.me.subnet ? - msg->add_conn.me.subnet : msg->add_conn.me.address, IKE_PORT); - if (my_subnet == NULL) - { - DBG1(DBG_CFG, "invalid subnet: %s\n", msg->add_conn.me.subnet); - goto destroy_ids; - } - - other_subnet = host_create_from_string(msg->add_conn.other.subnet ? - msg->add_conn.other.subnet : msg->add_conn.other.address, IKE_PORT); - if (other_subnet == NULL) - { - DBG1(DBG_CFG, "invalid subnet: %s\n", msg->add_conn.me.subnet); - my_subnet->destroy(my_subnet); - goto destroy_ids; - } - - if (msg->add_conn.me.virtual_ip && msg->add_conn.me.sourceip) - { - my_vip = host_create_from_string(msg->add_conn.me.sourceip, 0); - } - if (msg->add_conn.other.virtual_ip && msg->add_conn.other.sourceip) - { - other_vip = host_create_from_string(msg->add_conn.other.sourceip, 0); - } - - if (msg->add_conn.me.tohost) - { - my_ts = traffic_selector_create_dynamic(msg->add_conn.me.protocol, - my_host->get_family(my_host) == AF_INET ? - TS_IPV4_ADDR_RANGE : TS_IPV6_ADDR_RANGE, - msg->add_conn.me.port ? msg->add_conn.me.port : 0, - msg->add_conn.me.port ? msg->add_conn.me.port : 65535); - } - else - { - my_ts = traffic_selector_create_from_subnet(my_subnet, - msg->add_conn.me.subnet ? msg->add_conn.me.subnet_mask : 0, - msg->add_conn.me.protocol, msg->add_conn.me.port); - } - my_subnet->destroy(my_subnet); - - if (msg->add_conn.other.tohost) - { - other_ts = traffic_selector_create_dynamic(msg->add_conn.other.protocol, - other_host->get_family(other_host) == AF_INET ? - TS_IPV4_ADDR_RANGE : TS_IPV6_ADDR_RANGE, - msg->add_conn.other.port ? msg->add_conn.other.port : 0, - msg->add_conn.other.port ? msg->add_conn.other.port : 65535); - } - else - { - other_ts = traffic_selector_create_from_subnet(other_subnet, - msg->add_conn.other.subnet ? msg->add_conn.other.subnet_mask : 0, - msg->add_conn.other.protocol, msg->add_conn.other.port); - } - other_subnet->destroy(other_subnet); - - if (msg->add_conn.me.ca) - { - if (streq(msg->add_conn.me.ca, "%same")) - { - my_ca_same = TRUE; - } - else - { - my_ca = identification_create_from_string(msg->add_conn.me.ca); - } - } - if (msg->add_conn.other.ca) - { - if (streq(msg->add_conn.other.ca, "%same")) - { - other_ca_same = TRUE; - } - else - { - other_ca = identification_create_from_string(msg->add_conn.other.ca); - } - } - if (msg->add_conn.me.cert) - { - x509_t *cert = load_end_certificate(msg->add_conn.me.cert, &my_id); - - if (cert) - { - ca_info_t *ca_info; - - if (cert->is_self_signed(cert)) - { - /* a self-signed certificate is its own ca */ - ca_info = ca_info_create(NULL, cert); - ca_info = charon->credentials->add_ca_info(charon->credentials, ca_info); - cert->set_ca_info(cert, ca_info); - } - else - { - /* get_issuer() automatically sets cert->ca_info */ - ca_info = charon->credentials->get_issuer(charon->credentials, cert); - } - if (my_ca == NULL && !my_ca_same) - { - identification_t *issuer = cert->get_issuer(cert); - - my_ca = issuer->clone(issuer); - } - } - } - if (msg->add_conn.other.cert) - { - x509_t *cert = load_end_certificate(msg->add_conn.other.cert, &other_id); - - if (cert) - { - ca_info_t *ca_info; - - if (cert->is_self_signed(cert)) - { - /* a self-signed certificate is its own ca */ - ca_info = ca_info_create(NULL, cert); - ca_info = charon->credentials->add_ca_info(charon->credentials, ca_info); - cert->set_ca_info(cert, ca_info); - } - else - { - /* get_issuer() automatically sets cert->ca_info */ - ca_info = charon->credentials->get_issuer(charon->credentials, cert); - } - if (other_ca == NULL && !other_ca_same) - { - identification_t *issuer = cert->get_issuer(cert); - - other_ca = issuer->clone(issuer); - } - } - } - if (other_ca_same && my_ca) - { - other_ca = my_ca->clone(my_ca); - } - else if (my_ca_same && other_ca) - { - my_ca = other_ca->clone(other_ca); - } - if (my_ca == NULL) - { - my_ca = identification_create_from_string("%any"); - } - if (other_ca == NULL) - { - other_ca = identification_create_from_string("%any"); - } - DBG2(DBG_CFG, " my ca: '%D'", my_ca); - DBG2(DBG_CFG, " other ca:'%D'", other_ca); - - if (msg->add_conn.other.groups) - { - ietfAttr_list_create_from_string(msg->add_conn.other.groups, other_groups); - } - - /* have a look for an (almost) identical peer config to reuse */ - iterator = charon->backends->create_iterator(charon->backends); - while (iterator->iterate(iterator, (void**)&peer_cfg)) - { - host_t *my_vip_conf, *other_vip_conf; - bool my_vip_equals = FALSE, other_vip_equals = FALSE; - - my_vip_conf = peer_cfg->get_my_virtual_ip(peer_cfg); - if ((my_vip && my_vip_conf && my_vip->equals(my_vip, my_vip_conf)) || - (!my_vip_conf && !my_vip)) - { - my_vip_equals = TRUE; - } - DESTROY_IF(my_vip_conf); - other_vip_conf = peer_cfg->get_other_virtual_ip(peer_cfg, NULL); - if ((other_vip && other_vip_conf && other_vip->equals(other_vip, other_vip_conf)) || - (!other_vip_conf && !other_vip)) - { - other_vip_equals = TRUE; - } - DESTROY_IF(other_vip_conf); - - ike_cfg = peer_cfg->get_ike_cfg(peer_cfg); - if (my_id->equals(my_id, peer_cfg->get_my_id(peer_cfg)) - && other_id->equals(other_id, peer_cfg->get_other_id(peer_cfg)) - && my_host->equals(my_host, ike_cfg->get_my_host(ike_cfg)) - && other_host->equals(other_host, ike_cfg->get_other_host(ike_cfg)) - && other_ca->equals(other_ca, peer_cfg->get_other_ca(peer_cfg)) - && ietfAttr_list_equals(other_groups, peer_cfg->get_groups(peer_cfg)) - && peer_cfg->get_ike_version(peer_cfg) == (msg->add_conn.ikev2 ? 2 : 1) - && peer_cfg->get_auth_method(peer_cfg) == msg->add_conn.auth_method - && peer_cfg->get_eap_type(peer_cfg, &vendor) == msg->add_conn.eap_type - && vendor == msg->add_conn.eap_vendor - && my_vip_equals && other_vip_equals) - { - DBG1(DBG_CFG, "reusing existing configuration '%s'", - peer_cfg->get_name(peer_cfg)); - use_existing = TRUE; - break; - } - } - iterator->destroy(iterator); - - if (use_existing) - { - DESTROY_IF(my_vip); - DESTROY_IF(other_vip); - my_host->destroy(my_host); - my_id->destroy(my_id); - my_ca->destroy(my_ca); - other_host->destroy(other_host); - other_id->destroy(other_id); - other_ca->destroy(other_ca); - DESTROY_IF(peer_id); - DESTROY_IF(mediated_by_cfg); - ietfAttr_list_destroy(other_groups); - } - else - { - ike_cfg = ike_cfg_create(msg->add_conn.other.sendcert != CERT_NEVER_SEND, - msg->add_conn.force_encap, my_host, other_host); - - if (msg->add_conn.algorithms.ike) - { - char *proposal_string; - char *strict = msg->add_conn.algorithms.ike + strlen(msg->add_conn.algorithms.ike) - 1; - - if (*strict == '!') - *strict = '\0'; - else - strict = NULL; - - while ((proposal_string = strsep(&msg->add_conn.algorithms.ike, ","))) - { - proposal = proposal_create_from_string(PROTO_IKE, proposal_string); - if (proposal == NULL) - { - DBG1(DBG_CFG, "invalid IKE proposal string: %s", proposal_string); - my_id->destroy(my_id); - other_id->destroy(other_id); - my_ts->destroy(my_ts); - other_ts->destroy(other_ts); - my_ca->destroy(my_ca); - other_ca->destroy(other_ca); - ike_cfg->destroy(ike_cfg); - return; - } - ike_cfg->add_proposal(ike_cfg, proposal); - } - if (!strict) - { - proposal = proposal_create_default(PROTO_IKE); - ike_cfg->add_proposal(ike_cfg, proposal); - } - } - else - { - proposal = proposal_create_default(PROTO_IKE); - ike_cfg->add_proposal(ike_cfg, proposal); - } - - u_int32_t rekey = 0, reauth = 0, over, jitter; - - jitter = msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100; - over = msg->add_conn.rekey.margin; - if (msg->add_conn.rekey.reauth) - { - reauth = msg->add_conn.rekey.ike_lifetime - over; - } - else - { - rekey = msg->add_conn.rekey.ike_lifetime - over; - } - - peer_cfg = peer_cfg_create(msg->add_conn.name, msg->add_conn.ikev2 ? 2 : 1, - ike_cfg, my_id, other_id, my_ca, other_ca, other_groups, - msg->add_conn.me.sendcert, msg->add_conn.auth_method, - msg->add_conn.eap_type, msg->add_conn.eap_vendor, - msg->add_conn.rekey.tries, rekey, reauth, jitter, over, - msg->add_conn.mobike, - msg->add_conn.dpd.delay, msg->add_conn.dpd.action, my_vip, other_vip, - msg->add_conn.p2p.mediation, mediated_by_cfg, peer_id); - } - - child_cfg = child_cfg_create( - msg->add_conn.name, msg->add_conn.rekey.ipsec_lifetime, - msg->add_conn.rekey.ipsec_lifetime - msg->add_conn.rekey.margin, - msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100, - msg->add_conn.me.updown, msg->add_conn.me.hostaccess, - msg->add_conn.mode); - - peer_cfg->add_child_cfg(peer_cfg, child_cfg); - - child_cfg->add_traffic_selector(child_cfg, TRUE, my_ts); - child_cfg->add_traffic_selector(child_cfg, FALSE, other_ts); - - if (msg->add_conn.algorithms.esp) - { - char *proposal_string; - char *strict = msg->add_conn.algorithms.esp + strlen(msg->add_conn.algorithms.esp) - 1; - - if (*strict == '!') - *strict = '\0'; - else - strict = NULL; - - while ((proposal_string = strsep(&msg->add_conn.algorithms.esp, ","))) - { - proposal = proposal_create_from_string(PROTO_ESP, proposal_string); - if (proposal == NULL) - { - DBG1(DBG_CFG, "invalid ESP proposal string: %s", proposal_string); - peer_cfg->destroy(peer_cfg); - return; - } - child_cfg->add_proposal(child_cfg, proposal); - } - if (!strict) - { - proposal = proposal_create_default(PROTO_ESP); - child_cfg->add_proposal(child_cfg, proposal); - } - } - else - { - proposal = proposal_create_default(PROTO_ESP); - child_cfg->add_proposal(child_cfg, proposal); - } - - if (!use_existing) - { - /* add config to backend */ - charon->backends->add_peer_cfg(charon->backends, peer_cfg); - DBG1(DBG_CFG, "added configuration '%s': %H[%D]...%H[%D]", - msg->add_conn.name, my_host, my_id, other_host, other_id); - } - return; - - /* mopping up after parsing errors */ - -destroy_ids: - my_id->destroy(my_id); - other_id->destroy(other_id); - DESTROY_IF(mediated_by_cfg); - DESTROY_IF(peer_id); - -destroy_hosts: - my_host->destroy(my_host); - other_host->destroy(other_host); -} - -/** - * Delete a connection from the list - */ -static void stroke_del_conn(stroke_msg_t *msg, FILE *out) -{ - iterator_t *peer_iter, *child_iter; - peer_cfg_t *peer; - child_cfg_t *child; - - pop_string(msg, &(msg->del_conn.name)); - DBG1(DBG_CFG, "received stroke: delete connection '%s'", msg->del_conn.name); - - peer_iter = charon->backends->create_iterator(charon->backends); - while (peer_iter->iterate(peer_iter, (void**)&peer)) - { - /* remove peer config with such a name */ - if (streq(peer->get_name(peer), msg->del_conn.name)) - { - peer_iter->remove(peer_iter); - peer->destroy(peer); - continue; - } - /* remove any child with such a name */ - child_iter = peer->create_child_cfg_iterator(peer); - while (child_iter->iterate(child_iter, (void**)&child)) - { - if (streq(child->get_name(child), msg->del_conn.name)) - { - child_iter->remove(child_iter); - child->destroy(child); - } - } - child_iter->destroy(child_iter); - } - peer_iter->destroy(peer_iter); - - fprintf(out, "deleted connection '%s'\n", msg->del_conn.name); -} - -/** - * get the child_cfg with the same name as the peer cfg - */ -static child_cfg_t* get_child_from_peer(peer_cfg_t *peer_cfg, char *name) -{ - child_cfg_t *current, *found = NULL; - iterator_t *iterator; - - iterator = peer_cfg->create_child_cfg_iterator(peer_cfg); - while (iterator->iterate(iterator, (void**)¤t)) - { - if (streq(current->get_name(current), name)) - { - found = current; - found->get_ref(found); - break; - } - } - iterator->destroy(iterator); - return found; -} - -/** - * logging to the stroke interface - */ -static bool stroke_log(stroke_log_info_t *info, signal_t signal, level_t level, - ike_sa_t *ike_sa, char *format, va_list args) -{ - if (level <= info->level) - { - if (vfprintf(info->out, format, args) < 0 || - fprintf(info->out, "\n") < 0 || - fflush(info->out) != 0) - { - return FALSE; - } - } - return TRUE; -} - -/** - * initiate a connection by name - */ -static void stroke_initiate(stroke_msg_t *msg, FILE *out) -{ - peer_cfg_t *peer_cfg; - child_cfg_t *child_cfg; - stroke_log_info_t info; - - pop_string(msg, &(msg->initiate.name)); - DBG1(DBG_CFG, "received stroke: initiate '%s'", msg->initiate.name); - - peer_cfg = charon->backends->get_peer_cfg_by_name(charon->backends, - msg->initiate.name); - if (peer_cfg == NULL) - { - fprintf(out, "no config named '%s'\n", msg->initiate.name); - return; - } - if (peer_cfg->get_ike_version(peer_cfg) != 2) - { - DBG1(DBG_CFG, "ignoring initiation request for IKEv%d config", - peer_cfg->get_ike_version(peer_cfg)); - peer_cfg->destroy(peer_cfg); - return; - } - - child_cfg = get_child_from_peer(peer_cfg, msg->initiate.name); - if (child_cfg == NULL) - { - fprintf(out, "no child config named '%s'\n", msg->initiate.name); - peer_cfg->destroy(peer_cfg); - return; - } - - if (msg->output_verbosity < 0) - { - charon->interfaces->initiate(charon->interfaces, peer_cfg, child_cfg, - NULL, NULL); - } - else - { - info.out = out; - info.level = msg->output_verbosity; - charon->interfaces->initiate(charon->interfaces, peer_cfg, child_cfg, - (interface_manager_cb_t)stroke_log, &info); - } -} - -/** - * route a policy (install SPD entries) - */ -static void stroke_route(stroke_msg_t *msg, FILE *out) -{ - peer_cfg_t *peer_cfg; - child_cfg_t *child_cfg; - stroke_log_info_t info; - - pop_string(msg, &(msg->route.name)); - DBG1(DBG_CFG, "received stroke: route '%s'", msg->route.name); - - peer_cfg = charon->backends->get_peer_cfg_by_name(charon->backends, - msg->route.name); - if (peer_cfg == NULL) - { - fprintf(out, "no config named '%s'\n", msg->route.name); - return; - } - if (peer_cfg->get_ike_version(peer_cfg) != 2) - { - peer_cfg->destroy(peer_cfg); - return; - } - - child_cfg = get_child_from_peer(peer_cfg, msg->route.name); - if (child_cfg == NULL) - { - fprintf(out, "no child config named '%s'\n", msg->route.name); - peer_cfg->destroy(peer_cfg); - return; - } - - info.out = out; - info.level = msg->output_verbosity; - charon->interfaces->route(charon->interfaces, peer_cfg, child_cfg, - (interface_manager_cb_t)stroke_log, &info); - peer_cfg->destroy(peer_cfg); - child_cfg->destroy(child_cfg); -} - -/** - * unroute a policy - */ -static void stroke_unroute(stroke_msg_t *msg, FILE *out) -{ - char *name; - ike_sa_t *ike_sa; - iterator_t *iterator; - stroke_log_info_t info; - - pop_string(msg, &(msg->terminate.name)); - name = msg->terminate.name; - - info.out = out; - info.level = msg->output_verbosity; - - iterator = charon->interfaces->create_ike_sa_iterator(charon->interfaces); - while (iterator->iterate(iterator, (void**)&ike_sa)) - { - child_sa_t *child_sa; - iterator_t *children; - u_int32_t id; - - children = ike_sa->create_child_sa_iterator(ike_sa); - while (children->iterate(children, (void**)&child_sa)) - { - if (child_sa->get_state(child_sa) == CHILD_ROUTED && - streq(name, child_sa->get_name(child_sa))) - { - id = child_sa->get_reqid(child_sa); - children->destroy(children); - iterator->destroy(iterator); - charon->interfaces->unroute(charon->interfaces, id, - (interface_manager_cb_t)stroke_log, &info); - return; - } - } - children->destroy(children); - } - iterator->destroy(iterator); - DBG1(DBG_CFG, "no such SA found"); -} - -/** - * terminate a connection by name - */ -static void stroke_terminate(stroke_msg_t *msg, FILE *out) -{ - char *string, *pos = NULL, *name = NULL; - u_int32_t id = 0; - bool child; - int len; - ike_sa_t *ike_sa; - iterator_t *iterator; - stroke_log_info_t info; - - pop_string(msg, &(msg->terminate.name)); - string = msg->terminate.name; - DBG1(DBG_CFG, "received stroke: terminate '%s'", string); - - len = strlen(string); - if (len < 1) - { - DBG1(DBG_CFG, "error parsing string"); - return; - } - switch (string[len-1]) - { - case '}': - child = TRUE; - pos = strchr(string, '{'); - break; - case ']': - child = FALSE; - pos = strchr(string, '['); - break; - default: - name = string; - child = FALSE; - break; - } - - if (name) - { - /* is a single name */ - } - else if (pos == string + len - 2) - { /* is name[] or name{} */ - string[len-2] = '\0'; - name = string; - } - else - { /* is name[123] or name{23} */ - string[len-1] = '\0'; - id = atoi(pos + 1); - if (id == 0) - { - DBG1(DBG_CFG, "error parsing string"); - return; - } - } - - info.out = out; - info.level = msg->output_verbosity; - - iterator = charon->interfaces->create_ike_sa_iterator(charon->interfaces); - while (iterator->iterate(iterator, (void**)&ike_sa)) - { - child_sa_t *child_sa; - iterator_t *children; - - if (child) - { - children = ike_sa->create_child_sa_iterator(ike_sa); - while (children->iterate(children, (void**)&child_sa)) - { - if ((name && streq(name, child_sa->get_name(child_sa))) || - (id && id == child_sa->get_reqid(child_sa))) - { - id = child_sa->get_reqid(child_sa); - children->destroy(children); - iterator->destroy(iterator); - - charon->interfaces->terminate_child(charon->interfaces, id, - (interface_manager_cb_t)stroke_log, &info); - return; - } - } - children->destroy(children); - } - else if ((name && streq(name, ike_sa->get_name(ike_sa))) || - (id && id == ike_sa->get_unique_id(ike_sa))) - { - id = ike_sa->get_unique_id(ike_sa); - /* unlock manager first */ - iterator->destroy(iterator); - - charon->interfaces->terminate_ike(charon->interfaces, id, - (interface_manager_cb_t)stroke_log, &info); - return; - } - - } - iterator->destroy(iterator); - DBG1(DBG_CFG, "no such SA found"); -} - -/** - * Add a ca information record to the cainfo list - */ -static void stroke_add_ca(stroke_msg_t *msg, FILE *out) -{ - x509_t *cacert; - ca_info_t *ca_info; - - pop_string(msg, &msg->add_ca.name); - pop_string(msg, &msg->add_ca.cacert); - pop_string(msg, &msg->add_ca.crluri); - pop_string(msg, &msg->add_ca.crluri2); - pop_string(msg, &msg->add_ca.ocspuri); - pop_string(msg, &msg->add_ca.ocspuri2); - - DBG1(DBG_CFG, "received stroke: add ca '%s'", msg->add_ca.name); - - DBG2(DBG_CFG, "ca %s", msg->add_ca.name); - DBG2(DBG_CFG, " cacert=%s", msg->add_ca.cacert); - DBG2(DBG_CFG, " crluri=%s", msg->add_ca.crluri); - DBG2(DBG_CFG, " crluri2=%s", msg->add_ca.crluri2); - DBG2(DBG_CFG, " ocspuri=%s", msg->add_ca.ocspuri); - DBG2(DBG_CFG, " ocspuri2=%s", msg->add_ca.ocspuri2); - - if (msg->add_ca.cacert == NULL) - { - DBG1(DBG_CFG, "missing cacert parameter\n"); - return; - } - - cacert = load_ca_certificate(msg->add_ca.cacert); - - if (cacert == NULL) - { - return; - } - ca_info = ca_info_create(msg->add_ca.name, cacert); - - if (msg->add_ca.crluri) - { - chunk_t uri = { msg->add_ca.crluri, strlen(msg->add_ca.crluri) }; - - ca_info->add_crluri(ca_info, uri); - } - if (msg->add_ca.crluri2) - { - chunk_t uri = { msg->add_ca.crluri2, strlen(msg->add_ca.crluri2) }; - - ca_info->add_crluri(ca_info, uri); - } - if (msg->add_ca.ocspuri) - { - chunk_t uri = { msg->add_ca.ocspuri, strlen(msg->add_ca.ocspuri) }; - - ca_info->add_ocspuri(ca_info, uri); - } - if (msg->add_ca.ocspuri2) - { - chunk_t uri = { msg->add_ca.ocspuri2, strlen(msg->add_ca.ocspuri2) }; - - ca_info->add_ocspuri(ca_info, uri); - } - charon->credentials->add_ca_info(charon->credentials, ca_info); - DBG1(DBG_CFG, "added ca '%s'", msg->add_ca.name); - -} - -/** - * Delete a ca information record from the cainfo list - */ -static void stroke_del_ca(stroke_msg_t *msg, FILE *out) -{ - status_t status; - - pop_string(msg, &(msg->del_ca.name)); - DBG1(DBG_CFG, "received stroke: delete ca '%s'", msg->del_ca.name); - - status = charon->credentials->release_ca_info(charon->credentials, - msg->del_ca.name); - - if (status == SUCCESS) - { - fprintf(out, "deleted ca '%s'\n", msg->del_ca.name); - } - else - { - fprintf(out, "no ca named '%s'\n", msg->del_ca.name); - } -} - -/** - * log an IKE_SA to out - */ -static void log_ike_sa(FILE *out, ike_sa_t *ike_sa, bool all) -{ - ike_sa_id_t *id = ike_sa->get_id(ike_sa); - u_int32_t rekey, reauth; - - fprintf(out, "%12s[%d]: %N, %H[%D]...%H[%D]\n", - ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa), - ike_sa_state_names, ike_sa->get_state(ike_sa), - ike_sa->get_my_host(ike_sa), ike_sa->get_my_id(ike_sa), - ike_sa->get_other_host(ike_sa), ike_sa->get_other_id(ike_sa)); - - if (all) - { - fprintf(out, "%12s[%d]: IKE SPIs: %.16llx_i%s %.16llx_r%s", - ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa), - id->get_initiator_spi(id), id->is_initiator(id) ? "*" : "", - id->get_responder_spi(id), id->is_initiator(id) ? "" : "*"); - - rekey = ike_sa->get_statistic(ike_sa, STAT_REKEY_TIME); - reauth = ike_sa->get_statistic(ike_sa, STAT_REAUTH_TIME); - if (rekey) - { - fprintf(out, ", rekeying in %V", &rekey); - } - if (reauth) - { - fprintf(out, ", reauthentication in %V", &reauth); - } - if (!rekey && !reauth) - { - fprintf(out, ", rekeying disabled"); - } - fprintf(out, "\n"); - } -} - -/** - * log an CHILD_SA to out - */ -static void log_child_sa(FILE *out, child_sa_t *child_sa, bool all) -{ - u_int32_t rekey, now = time(NULL); - u_int32_t use_in, use_out, use_fwd; - encryption_algorithm_t encr_alg; - integrity_algorithm_t int_alg; - size_t encr_len, int_len; - mode_t mode; - - child_sa->get_stats(child_sa, &mode, &encr_alg, &encr_len, - &int_alg, &int_len, &rekey, &use_in, &use_out, - &use_fwd); - - fprintf(out, "%12s{%d}: %N, %N", - child_sa->get_name(child_sa), child_sa->get_reqid(child_sa), - child_sa_state_names, child_sa->get_state(child_sa), - mode_names, mode); - - if (child_sa->get_state(child_sa) == CHILD_INSTALLED) - { - fprintf(out, ", %N SPIs: %.8x_i %.8x_o", - protocol_id_names, child_sa->get_protocol(child_sa), - htonl(child_sa->get_spi(child_sa, TRUE)), - htonl(child_sa->get_spi(child_sa, FALSE))); - - if (all) - { - fprintf(out, "\n%12s{%d}: ", child_sa->get_name(child_sa), - child_sa->get_reqid(child_sa)); - - - if (child_sa->get_protocol(child_sa) == PROTO_ESP) - { - fprintf(out, "%N", encryption_algorithm_names, encr_alg); - - if (encr_len) - { - fprintf(out, "-%d", encr_len); - } - fprintf(out, "/"); - } - - fprintf(out, "%N", integrity_algorithm_names, int_alg); - if (int_len) - { - fprintf(out, "-%d", int_len); - } - fprintf(out, ", rekeying "); - - if (rekey) - { - fprintf(out, "in %#V", &now, &rekey); - } - else - { - fprintf(out, "disabled"); - } - - fprintf(out, ", last use: "); - use_in = max(use_in, use_fwd); - if (use_in) - { - fprintf(out, "%ds_i ", now - use_in); - } - else - { - fprintf(out, "no_i "); - } - if (use_out) - { - fprintf(out, "%ds_o ", now - use_out); - } - else - { - fprintf(out, "no_o "); - } - } - } - - fprintf(out, "\n%12s{%d}: %#R=== %#R\n", - child_sa->get_name(child_sa), child_sa->get_reqid(child_sa), - child_sa->get_traffic_selectors(child_sa, TRUE), - child_sa->get_traffic_selectors(child_sa, FALSE)); -} - -/** - * show status of daemon - */ -static void stroke_status(stroke_msg_t *msg, FILE *out, bool all) -{ - iterator_t *iterator, *children; - host_t *host; - peer_cfg_t *peer_cfg; - ike_cfg_t *ike_cfg; - child_cfg_t *child_cfg; - ike_sa_t *ike_sa; - char *name = NULL; - - if (msg->status.name) - { - pop_string(msg, &(msg->status.name)); - name = msg->status.name; - } - - if (all) - { - leak_detective_status(out); - - fprintf(out, "Performance:\n"); - fprintf(out, " worker threads: %d idle of %d,", - charon->processor->get_idle_threads(charon->processor), - charon->processor->get_total_threads(charon->processor)); - fprintf(out, " job queue load: %d,", - charon->processor->get_job_load(charon->processor)); - fprintf(out, " scheduled events: %d\n", - charon->scheduler->get_job_load(charon->scheduler)); - iterator = charon->kernel_interface->create_address_iterator( - charon->kernel_interface); - fprintf(out, "Listening IP addresses:\n"); - while (iterator->iterate(iterator, (void**)&host)) - { - fprintf(out, " %H\n", host); - } - iterator->destroy(iterator); - - fprintf(out, "Connections:\n"); - iterator = charon->backends->create_iterator(charon->backends); - while (iterator->iterate(iterator, (void**)&peer_cfg)) - { - if (peer_cfg->get_ike_version(peer_cfg) != 2 || - (name && !streq(name, peer_cfg->get_name(peer_cfg)))) - { - continue; - } - - ike_cfg = peer_cfg->get_ike_cfg(peer_cfg); - fprintf(out, "%12s: %H[%D]...%H[%D]\n", peer_cfg->get_name(peer_cfg), - ike_cfg->get_my_host(ike_cfg), peer_cfg->get_my_id(peer_cfg), - ike_cfg->get_other_host(ike_cfg), peer_cfg->get_other_id(peer_cfg)); - { - identification_t *my_ca = peer_cfg->get_my_ca(peer_cfg); - identification_t *other_ca = peer_cfg->get_other_ca(peer_cfg); - linked_list_t *groups = peer_cfg->get_groups(peer_cfg); - - if (my_ca->get_type(my_ca) != ID_ANY - || other_ca->get_type(other_ca) != ID_ANY) - { - fprintf(out, "%12s: CAs: '%D'...'%D'\n", peer_cfg->get_name(peer_cfg), - my_ca, other_ca); - } - if (groups->get_count(groups) > 0) - { - fprintf(out, "%12s: groups: ", peer_cfg->get_name(peer_cfg)); - ietfAttr_list_list(groups, out); - fprintf(out, "\n"); - } - - } - children = peer_cfg->create_child_cfg_iterator(peer_cfg); - while (children->iterate(children, (void**)&child_cfg)) - { - linked_list_t *my_ts, *other_ts; - my_ts = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, NULL); - other_ts = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL, NULL); - fprintf(out, "%12s: %#R=== %#R\n", child_cfg->get_name(child_cfg), - my_ts, other_ts); - my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy)); - other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy)); - } - children->destroy(children); - } - iterator->destroy(iterator); - } - - iterator = charon->ike_sa_manager->create_iterator(charon->ike_sa_manager); - if (all && iterator->get_count(iterator) > 0) - { - fprintf(out, "Security Associations:\n"); - } - while (iterator->iterate(iterator, (void**)&ike_sa)) - { - bool ike_printed = FALSE; - child_sa_t *child_sa; - iterator_t *children = ike_sa->create_child_sa_iterator(ike_sa); - - if (name == NULL || streq(name, ike_sa->get_name(ike_sa))) - { - log_ike_sa(out, ike_sa, all); - ike_printed = TRUE; - } - - while (children->iterate(children, (void**)&child_sa)) - { - if (name == NULL || streq(name, child_sa->get_name(child_sa))) - { - if (!ike_printed) - { - log_ike_sa(out, ike_sa, all); - ike_printed = TRUE; - } - log_child_sa(out, child_sa, all); - } - } - children->destroy(children); - } - iterator->destroy(iterator); -} - -/** - * list all authority certificates matching a specified flag - */ -static void list_auth_certificates(u_int flag, const char *label, - bool utc, FILE *out) -{ - bool first = TRUE; - x509_t *cert; - - iterator_t *iterator = charon->credentials->create_auth_cert_iterator(charon->credentials); - - while (iterator->iterate(iterator, (void**)&cert)) - { - if (cert->has_authority_flag(cert, flag)) - { - if (first) - { - fprintf(out, "\n"); - fprintf(out, "List of X.509 %s Certificates:\n", label); - fprintf(out, "\n"); - first = FALSE; - } - cert->list(cert, out, utc); - fprintf(out, "\n"); - } - } - iterator->destroy(iterator); -} - -/** - * list various information - */ -static void stroke_list(stroke_msg_t *msg, FILE *out) -{ - iterator_t *iterator; - - if (msg->list.flags & LIST_CERTS) - { - x509_t *cert; - - iterator = charon->credentials->create_cert_iterator(charon->credentials); - if (iterator->get_count(iterator)) - { - fprintf(out, "\n"); - fprintf(out, "List of X.509 End Entity Certificates:\n"); - fprintf(out, "\n"); - } - while (iterator->iterate(iterator, (void**)&cert)) - { - cert->list(cert, out, msg->list.utc); - if (charon->credentials->has_rsa_private_key( - charon->credentials, cert->get_public_key(cert))) - { - fprintf(out, ", has private key"); - } - fprintf(out, "\n"); - - } - iterator->destroy(iterator); - } - if (msg->list.flags & LIST_CACERTS) - { - list_auth_certificates(AUTH_CA, "CA", msg->list.utc, out); - } - if (msg->list.flags & LIST_OCSPCERTS) - { - list_auth_certificates(AUTH_OCSP, "OCSP", msg->list.utc, out); - } - if (msg->list.flags & LIST_AACERTS) - { - list_auth_certificates(AUTH_AA, "AA", msg->list.utc, out); - } - if (msg->list.flags & LIST_ACERTS) - { - x509ac_t *cert; - - iterator = charon->credentials->create_acert_iterator(charon->credentials); - if (iterator->get_count(iterator)) - { - fprintf(out, "\n"); - fprintf(out, "List of X.509 Attribute Certificates:\n"); - fprintf(out, "\n"); - } - while (iterator->iterate(iterator, (void**)&cert)) - { - cert->list(cert, out, msg->list.utc); - } - iterator->destroy(iterator); - } - if (msg->list.flags & LIST_CAINFOS) - { - ca_info_t *ca_info; - bool first = TRUE; - - iterator = charon->credentials->create_cainfo_iterator(charon->credentials); - while (iterator->iterate(iterator, (void**)&ca_info)) - { - if (ca_info->is_ca(ca_info)) - { - if (first) - { - fprintf(out, "\n"); - fprintf(out, "List of X.509 CA Information Records:\n"); - fprintf(out, "\n"); - first = FALSE; - } - ca_info->list(ca_info, out, msg->list.utc); - } - } - iterator->destroy(iterator); - } - if (msg->list.flags & LIST_CRLS) - { - ca_info_t *ca_info; - bool first = TRUE; - - iterator = charon->credentials->create_cainfo_iterator(charon->credentials); - while (iterator->iterate(iterator, (void **)&ca_info)) - { - if (ca_info->is_ca(ca_info) && ca_info->has_crl(ca_info)) - { - if (first) - { - fprintf(out, "\n"); - fprintf(out, "List of X.509 CRLs:\n"); - fprintf(out, "\n"); - first = FALSE; - } - ca_info->list_crl(ca_info, out, msg->list.utc); - } - } - iterator->destroy(iterator); - } - if (msg->list.flags & LIST_OCSP) - { - ca_info_t *ca_info; - bool first = TRUE; - - iterator = charon->credentials->create_cainfo_iterator(charon->credentials); - while (iterator->iterate(iterator, (void **)&ca_info)) - { - if (ca_info->is_ca(ca_info) && ca_info->has_certinfos(ca_info)) - { - if (first) - { - fprintf(out, "\n"); - fprintf(out, "List of OCSP responses:\n"); - first = FALSE; - } - fprintf(out, "\n"); - ca_info->list_certinfos(ca_info, out, msg->list.utc); - } - } - iterator->destroy(iterator); - } -} - -/** - * reread various information - */ -static void stroke_reread(stroke_msg_t *msg, FILE *out) -{ - if (msg->reread.flags & REREAD_SECRETS) - { - charon->credentials->load_secrets(charon->credentials, TRUE); - } - if (msg->reread.flags & REREAD_CACERTS) - { - charon->credentials->load_ca_certificates(charon->credentials); - } - if (msg->reread.flags & REREAD_OCSPCERTS) - { - charon->credentials->load_ocsp_certificates(charon->credentials); - } - if (msg->reread.flags & REREAD_AACERTS) - { - charon->credentials->load_aa_certificates(charon->credentials); - } - if (msg->reread.flags & REREAD_ACERTS) - { - charon->credentials->load_attr_certificates(charon->credentials); - } - if (msg->reread.flags & REREAD_CRLS) - { - charon->credentials->load_crls(charon->credentials); - } -} - -/** - * purge various information - */ -static void stroke_purge(stroke_msg_t *msg, FILE *out) -{ - if (msg->purge.flags & PURGE_OCSP) - { - iterator_t *iterator = charon->credentials->create_cainfo_iterator(charon->credentials); - ca_info_t *ca_info; - - while (iterator->iterate(iterator, (void**)&ca_info)) - { - if (ca_info->is_ca(ca_info)) - { - ca_info->purge_ocsp(ca_info); - } - } - iterator->destroy(iterator); - } -} - -signal_t get_signal_from_logtype(char *type) -{ - if (strcasecmp(type, "any") == 0) return SIG_ANY; - else if (strcasecmp(type, "mgr") == 0) return DBG_MGR; - else if (strcasecmp(type, "ike") == 0) return DBG_IKE; - else if (strcasecmp(type, "chd") == 0) return DBG_CHD; - else if (strcasecmp(type, "job") == 0) return DBG_JOB; - else if (strcasecmp(type, "cfg") == 0) return DBG_CFG; - else if (strcasecmp(type, "knl") == 0) return DBG_KNL; - else if (strcasecmp(type, "net") == 0) return DBG_NET; - else if (strcasecmp(type, "enc") == 0) return DBG_ENC; - else if (strcasecmp(type, "lib") == 0) return DBG_LIB; - else return -1; -} - -/** - * set the verbosity debug output - */ -static void stroke_loglevel(stroke_msg_t *msg, FILE *out) -{ - signal_t signal; - - pop_string(msg, &(msg->loglevel.type)); - DBG1(DBG_CFG, "received stroke: loglevel %d for %s", - msg->loglevel.level, msg->loglevel.type); - - signal = get_signal_from_logtype(msg->loglevel.type); - if (signal < 0) - { - fprintf(out, "invalid type (%s)!\n", msg->loglevel.type); - return; - } - - charon->outlog->set_level(charon->outlog, signal, msg->loglevel.level); - charon->syslog->set_level(charon->syslog, signal, msg->loglevel.level); -} - -/** - * process a stroke request from the socket pointed by "fd" - */ -static job_requeue_t stroke_process(int *fdp) -{ - stroke_msg_t *msg; - u_int16_t msg_length; - ssize_t bytes_read; - FILE *out; - int strokefd = *fdp; - - /* peek the length */ - bytes_read = recv(strokefd, &msg_length, sizeof(msg_length), MSG_PEEK); - if (bytes_read != sizeof(msg_length)) - { - DBG1(DBG_CFG, "reading length of stroke message failed: %s", - strerror(errno)); - close(strokefd); - return JOB_REQUEUE_NONE; - } - - /* read message */ - msg = malloc(msg_length); - bytes_read = recv(strokefd, msg, msg_length, 0); - if (bytes_read != msg_length) - { - DBG1(DBG_CFG, "reading stroke message failed: %s", strerror(errno)); - close(strokefd); - return JOB_REQUEUE_NONE; - } - - out = fdopen(strokefd, "w"); - if (out == NULL) - { - DBG1(DBG_CFG, "opening stroke output channel failed: %s", strerror(errno)); - close(strokefd); - free(msg); - return JOB_REQUEUE_NONE; - } - - DBG3(DBG_CFG, "stroke message %b", (void*)msg, msg_length); - - /* the stroke_* functions are blocking, as they listen on the bus. Add - * cancellation handlers. */ - pthread_cleanup_push((void*)fclose, out); - pthread_cleanup_push(free, msg); - - switch (msg->type) - { - case STR_INITIATE: - stroke_initiate(msg, out); - break; - case STR_ROUTE: - stroke_route(msg, out); - break; - case STR_UNROUTE: - stroke_unroute(msg, out); - break; - case STR_TERMINATE: - stroke_terminate(msg, out); - break; - case STR_STATUS: - stroke_status(msg, out, FALSE); - break; - case STR_STATUS_ALL: - stroke_status(msg, out, TRUE); - break; - case STR_ADD_CONN: - stroke_add_conn(msg, out); - break; - case STR_DEL_CONN: - stroke_del_conn(msg, out); - break; - case STR_ADD_CA: - stroke_add_ca(msg, out); - break; - case STR_DEL_CA: - stroke_del_ca(msg, out); - break; - case STR_LOGLEVEL: - stroke_loglevel(msg, out); - break; - case STR_LIST: - stroke_list(msg, out); - break; - case STR_REREAD: - stroke_reread(msg, out); - break; - case STR_PURGE: - stroke_purge(msg, out); - break; - default: - DBG1(DBG_CFG, "received unknown stroke"); - } - /* remove and execute cancellation handlers */ - pthread_cleanup_pop(1); - pthread_cleanup_pop(1); - - return JOB_REQUEUE_NONE; -} - -/** - * Implementation of private_stroke_interface_t.stroke_receive. - */ -static job_requeue_t stroke_receive(private_stroke_interface_t *this) -{ - struct sockaddr_un strokeaddr; - int strokeaddrlen = sizeof(strokeaddr); - int strokefd, *fdp; - int oldstate; - callback_job_t *job; - - pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); - strokefd = accept(this->socket, (struct sockaddr *)&strokeaddr, &strokeaddrlen); - pthread_setcancelstate(oldstate, NULL); - - if (strokefd < 0) - { - DBG1(DBG_CFG, "accepting stroke connection failed: %s", strerror(errno)); - return JOB_REQUEUE_FAIR; - } - - fdp = malloc_thing(int); - *fdp = strokefd; - job = callback_job_create((callback_job_cb_t)stroke_process, fdp, free, this->job); - charon->processor->queue_job(charon->processor, (job_t*)job); - - return JOB_REQUEUE_FAIR; -} - -/** - * Implementation of interface_t.destroy. - */ -static void destroy(private_stroke_interface_t *this) -{ - this->job->cancel(this->job); - free(this); -} - -/* - * Described in header-file - */ -interface_t *interface_create() -{ - struct sockaddr_un socket_addr = { AF_UNIX, STROKE_SOCKET}; - private_stroke_interface_t *this = malloc_thing(private_stroke_interface_t); - mode_t old; - - /* public functions */ - this->public.interface.destroy = (void (*)(interface_t*))destroy; - - /* set up unix socket */ - this->socket = socket(AF_UNIX, SOCK_STREAM, 0); - if (this->socket == -1) - { - DBG1(DBG_CFG, "could not create stroke socket"); - free(this); - return NULL; - } - - unlink(socket_addr.sun_path); - old = umask(~(S_IRWXU | S_IRWXG)); - if (bind(this->socket, (struct sockaddr *)&socket_addr, sizeof(socket_addr)) < 0) - { - DBG1(DBG_CFG, "could not bind stroke socket: %s", strerror(errno)); - close(this->socket); - free(this); - return NULL; - } - umask(old); - if (chown(socket_addr.sun_path, IPSEC_UID, IPSEC_GID) != 0) - { - DBG1(DBG_CFG, "changing stroke socket permissions failed: %s", - strerror(errno)); - } - - if (listen(this->socket, 0) < 0) - { - DBG1(DBG_CFG, "could not listen on stroke socket: %s", strerror(errno)); - close(this->socket); - unlink(socket_addr.sun_path); - free(this); - return NULL; - } - - this->job = callback_job_create((callback_job_cb_t)stroke_receive, - this, NULL, NULL); - charon->processor->queue_job(charon->processor, (job_t*)this->job); - - return &this->public.interface; -} - diff --git a/src/charon/control/interfaces/stroke_interface.h b/src/charon/control/interfaces/stroke_interface.h deleted file mode 100644 index f1b68023a..000000000 --- a/src/charon/control/interfaces/stroke_interface.h +++ /dev/null @@ -1,60 +0,0 @@ -/** - * @file stroke_interface.h - * - * @brief Interface of stroke_t. - * - */ - -/* - * Copyright (C) 2006 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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 STROKE_INTERFACE_H_ -#define STROKE_INTERFACE_H_ - -typedef struct stroke_interface_t stroke_interface_t; - -#include - -/** - * @brief Simple configuration interface using unix-sockets. - * - * Stroke is a home-brewed communication interface inspired by whack. It - * uses a unix socket (/var/run/charon.ctl). - * - * @b Constructors: - * - stroke_create() - * - * @ingroup interfaces - */ -struct stroke_interface_t { - - /** - * implements interface_t. - */ - interface_t interface; -}; - - -/** - * @brief Create the stroke interface and listen on the socket. - * - * @return interface_t for the stroke interface - * - * @ingroup interfaces - */ -interface_t *interface_create(void); - -#endif /* STROKE_INTERFACE_H_ */ - diff --git a/src/charon/control/interfaces/xml_interface.c b/src/charon/control/interfaces/xml_interface.c deleted file mode 100644 index aa2a554a0..000000000 --- a/src/charon/control/interfaces/xml_interface.c +++ /dev/null @@ -1,754 +0,0 @@ -/** - * @file xml_interface.c - * - * @brief Implementation of xml_interface_t. - * - */ - -/* - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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 - -#include "xml_interface.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - - -typedef struct private_xml_interface_t private_xml_interface_t; - -/** - * Private data of an xml_interface_t object. - */ -struct private_xml_interface_t { - - /** - * Public part of xml_t object. - */ - xml_interface_t public; - - /** - * XML unix socket fd - */ - int socket; - - /** - * job accepting stroke messages - */ - callback_job_t *job; -}; - -ENUM(ike_sa_state_lower_names, IKE_CREATED, IKE_DELETING, - "created", - "connecting", - "established", - "rekeying", - "deleting", -); - -/** - * write a bool into element - */ -static void write_bool(xmlTextWriterPtr writer, char *element, bool val) -{ - xmlTextWriterWriteElement(writer, element, val ? "true" : "false"); -} - -/** - * write a identification_t into element - */ -static void write_id(xmlTextWriterPtr writer, char *element, identification_t *id) -{ - xmlTextWriterStartElement(writer, element); - switch (id->get_type(id)) - { - { - char *type = ""; - while (TRUE) - { - case ID_ANY: - type = "any"; - break; - case ID_IPV4_ADDR: - type = "ipv4"; - break; - case ID_IPV6_ADDR: - type = "ipv6"; - break; - case ID_FQDN: - type = "fqdn"; - break; - case ID_RFC822_ADDR: - type = "email"; - break; - case ID_DER_ASN1_DN: - type = "asn1dn"; - break; - case ID_DER_ASN1_GN: - type = "asn1gn"; - break; - } - xmlTextWriterWriteAttribute(writer, "type", type); - xmlTextWriterWriteFormatString(writer, "%D", id); - break; - } - default: - /* TODO: base64 keyid */ - xmlTextWriterWriteAttribute(writer, "type", "keyid"); - break; - } - xmlTextWriterEndElement(writer); -} - -/** - * write a host_t address into an element - */ -static void write_address(xmlTextWriterPtr writer, char *element, host_t *host) -{ - xmlTextWriterStartElement(writer, element); - xmlTextWriterWriteAttribute(writer, "type", - host->get_family(host) == AF_INET ? "ipv4" : "ipv6"); - if (host->is_anyaddr(host)) - { /* do not use %any for XML */ - xmlTextWriterWriteFormatString(writer, "%s", - host->get_family(host) == AF_INET ? "0.0.0.0" : "::"); - } - else - { - xmlTextWriterWriteFormatString(writer, "%H", host); - } - xmlTextWriterEndElement(writer); -} - -/** - * write networks element - */ -static void write_networks(xmlTextWriterPtr writer, char *element, - linked_list_t *list) -{ - iterator_t *iterator; - traffic_selector_t *ts; - - xmlTextWriterStartElement(writer, element); - iterator = list->create_iterator(list, TRUE); - while (iterator->iterate(iterator, (void**)&ts)) - { - xmlTextWriterStartElement(writer, "network"); - xmlTextWriterWriteAttribute(writer, "type", - ts->get_type(ts) == TS_IPV4_ADDR_RANGE ? "ipv4" : "ipv6"); - xmlTextWriterWriteFormatString(writer, "%R", ts); - xmlTextWriterEndElement(writer); - } - iterator->destroy(iterator); - xmlTextWriterEndElement(writer); -} - -/** - * write a childEnd - */ -static void write_childend(xmlTextWriterPtr writer, child_sa_t *child, bool local) -{ - linked_list_t *list; - - xmlTextWriterWriteFormatElement(writer, "spi", "%lx", - htonl(child->get_spi(child, local))); - list = child->get_traffic_selectors(child, local); - write_networks(writer, "networks", list); -} - -/** - * write a child_sa_t - */ -static void write_child(xmlTextWriterPtr writer, child_sa_t *child) -{ - mode_t mode; - encryption_algorithm_t encr; - integrity_algorithm_t int_algo; - size_t encr_len, int_len; - u_int32_t rekey, use_in, use_out, use_fwd; - child_cfg_t *config; - - config = child->get_config(child); - child->get_stats(child, &mode, &encr, &encr_len, &int_algo, &int_len, - &rekey, &use_in, &use_out, &use_fwd); - - xmlTextWriterStartElement(writer, "childsa"); - xmlTextWriterWriteFormatElement(writer, "reqid", "%d", child->get_reqid(child)); - xmlTextWriterWriteFormatElement(writer, "childconfig", "%s", - config->get_name(config)); - xmlTextWriterStartElement(writer, "local"); - write_childend(writer, child, TRUE); - xmlTextWriterEndElement(writer); - xmlTextWriterStartElement(writer, "remote"); - write_childend(writer, child, FALSE); - xmlTextWriterEndElement(writer); - xmlTextWriterEndElement(writer); -} - -/** - * process a ikesalist query request message - */ -static void request_query_ikesa(xmlTextReaderPtr reader, xmlTextWriterPtr writer) -{ - iterator_t *iterator; - ike_sa_t *ike_sa; - - /* */ - xmlTextWriterStartElement(writer, "ikesalist"); - - iterator = charon->ike_sa_manager->create_iterator(charon->ike_sa_manager); - while (iterator->iterate(iterator, (void**)&ike_sa)) - { - ike_sa_id_t *id; - host_t *local, *remote; - iterator_t *children; - child_sa_t *child_sa; - - id = ike_sa->get_id(ike_sa); - - xmlTextWriterStartElement(writer, "ikesa"); - xmlTextWriterWriteFormatElement(writer, "id", "%d", - ike_sa->get_unique_id(ike_sa)); - xmlTextWriterWriteFormatElement(writer, "status", "%N", - ike_sa_state_lower_names, ike_sa->get_state(ike_sa)); - xmlTextWriterWriteElement(writer, "role", - id->is_initiator(id) ? "initiator" : "responder"); - xmlTextWriterWriteElement(writer, "peerconfig", ike_sa->get_name(ike_sa)); - - /* */ - local = ike_sa->get_my_host(ike_sa); - xmlTextWriterStartElement(writer, "local"); - xmlTextWriterWriteFormatElement(writer, "spi", "%.16llx", - id->is_initiator(id) ? id->get_initiator_spi(id) - : id->get_responder_spi(id)); - write_id(writer, "identification", ike_sa->get_my_id(ike_sa)); - write_address(writer, "address", local); - xmlTextWriterWriteFormatElement(writer, "port", "%d", - local->get_port(local)); - if (ike_sa->supports_extension(ike_sa, EXT_NATT)) - { - write_bool(writer, "nat", ike_sa->has_condition(ike_sa, COND_NAT_HERE)); - } - xmlTextWriterEndElement(writer); - /* */ - - /* */ - remote = ike_sa->get_other_host(ike_sa); - xmlTextWriterStartElement(writer, "remote"); - xmlTextWriterWriteFormatElement(writer, "spi", "%.16llx", - id->is_initiator(id) ? id->get_responder_spi(id) - : id->get_initiator_spi(id)); - write_id(writer, "identification", ike_sa->get_other_id(ike_sa)); - write_address(writer, "address", remote); - xmlTextWriterWriteFormatElement(writer, "port", "%d", - remote->get_port(remote)); - if (ike_sa->supports_extension(ike_sa, EXT_NATT)) - { - write_bool(writer, "nat", ike_sa->has_condition(ike_sa, COND_NAT_THERE)); - } - xmlTextWriterEndElement(writer); - /* */ - - /* */ - xmlTextWriterStartElement(writer, "childsalist"); - children = ike_sa->create_child_sa_iterator(ike_sa); - while (children->iterate(children, (void**)&child_sa)) - { - write_child(writer, child_sa); - } - children->destroy(children); - /* */ - xmlTextWriterEndElement(writer); - - /* */ - xmlTextWriterEndElement(writer); - } - iterator->destroy(iterator); - - /* */ - xmlTextWriterEndElement(writer); -} - -/** - * process a configlist query request message - */ -static void request_query_config(xmlTextReaderPtr reader, xmlTextWriterPtr writer) -{ - iterator_t *iterator; - peer_cfg_t *peer_cfg; - - /* */ - xmlTextWriterStartElement(writer, "configlist"); - - iterator = charon->backends->create_iterator(charon->backends); - while (iterator->iterate(iterator, (void**)&peer_cfg)) - { - iterator_t *children; - child_cfg_t *child_cfg; - ike_cfg_t *ike_cfg; - linked_list_t *list; - - if (peer_cfg->get_ike_version(peer_cfg) != 2) - { /* only IKEv2 connections yet */ - continue; - } - - /* */ - xmlTextWriterStartElement(writer, "peerconfig"); - xmlTextWriterWriteElement(writer, "name", peer_cfg->get_name(peer_cfg)); - write_id(writer, "local", peer_cfg->get_my_id(peer_cfg)); - write_id(writer, "remote", peer_cfg->get_other_id(peer_cfg)); - - /* */ - ike_cfg = peer_cfg->get_ike_cfg(peer_cfg); - xmlTextWriterStartElement(writer, "ikeconfig"); - write_address(writer, "local", ike_cfg->get_my_host(ike_cfg)); - write_address(writer, "remote", ike_cfg->get_other_host(ike_cfg)); - xmlTextWriterEndElement(writer); - /* */ - - /* */ - xmlTextWriterStartElement(writer, "childconfiglist"); - children = peer_cfg->create_child_cfg_iterator(peer_cfg); - while (children->iterate(children, (void**)&child_cfg)) - { - /* */ - xmlTextWriterStartElement(writer, "childconfig"); - xmlTextWriterWriteElement(writer, "name", - child_cfg->get_name(child_cfg)); - list = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, NULL); - write_networks(writer, "local", list); - list->destroy_offset(list, offsetof(traffic_selector_t, destroy)); - list = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL, NULL); - write_networks(writer, "remote", list); - list->destroy_offset(list, offsetof(traffic_selector_t, destroy)); - xmlTextWriterEndElement(writer); - /* */ - } - children->destroy(children); - /* */ - xmlTextWriterEndElement(writer); - /* */ - xmlTextWriterEndElement(writer); - } - iterator->destroy(iterator); - /* */ - xmlTextWriterEndElement(writer); -} - -/** - * callback which logs to a XML writer - */ -static bool xml_callback(xmlTextWriterPtr writer, signal_t signal, level_t level, - ike_sa_t* ike_sa, char* format, va_list args) -{ - if (level <= 1) - { - /* */ - xmlTextWriterStartElement(writer, "item"); - xmlTextWriterWriteFormatAttribute(writer, "level", "%d", level); - xmlTextWriterWriteFormatAttribute(writer, "source", "%N", signal_names, signal); - xmlTextWriterWriteFormatAttribute(writer, "thread", "%u", pthread_self()); - xmlTextWriterWriteVFormatString(writer, format, args); - xmlTextWriterEndElement(writer); - /* */ - } - return TRUE; -} - -/** - * process a *terminate control request message - */ -static void request_control_terminate(xmlTextReaderPtr reader, - xmlTextWriterPtr writer, bool ike) -{ - if (xmlTextReaderRead(reader) && - xmlTextReaderNodeType(reader) == XML_READER_TYPE_TEXT) - { - const char *str; - u_int32_t id; - status_t status; - - str = xmlTextReaderConstValue(reader); - if (str == NULL || !(id = atoi(str))) - { - DBG1(DBG_CFG, "error parsing XML id string"); - return; - } - DBG1(DBG_CFG, "terminating %s_SA %d", ike ? "IKE" : "CHILD", id); - - /* */ - xmlTextWriterStartElement(writer, "log"); - if (ike) - { - status = charon->interfaces->terminate_ike( - charon->interfaces, id, - (interface_manager_cb_t)xml_callback, writer); - } - else - { - status = charon->interfaces->terminate_child( - charon->interfaces, id, - (interface_manager_cb_t)xml_callback, writer); - } - /* */ - xmlTextWriterEndElement(writer); - xmlTextWriterWriteFormatElement(writer, "status", "%d", status); - } -} - -/** - * process a *initiate control request message - */ -static void request_control_initiate(xmlTextReaderPtr reader, - xmlTextWriterPtr writer, bool ike) -{ - if (xmlTextReaderRead(reader) && - xmlTextReaderNodeType(reader) == XML_READER_TYPE_TEXT) - { - const char *str; - status_t status = FAILED; - peer_cfg_t *peer; - child_cfg_t *child = NULL; - iterator_t *iterator; - - str = xmlTextReaderConstValue(reader); - if (str == NULL) - { - DBG1(DBG_CFG, "error parsing XML config name string"); - return; - } - DBG1(DBG_CFG, "initiating %s_SA %s", ike ? "IKE" : "CHILD", str); - - /* */ - xmlTextWriterStartElement(writer, "log"); - peer = charon->backends->get_peer_cfg_by_name(charon->backends, (char*)str); - if (peer) - { - iterator = peer->create_child_cfg_iterator(peer); - if (ike) - { - if (!iterator->iterate(iterator, (void**)&child)) - { - child = NULL; - } - child->get_ref(child); - } - else - { - while (iterator->iterate(iterator, (void**)&child)) - { - if (streq(child->get_name(child), str)) - { - child->get_ref(child); - break; - } - child = NULL; - } - } - iterator->destroy(iterator); - if (child) - { - status = charon->interfaces->initiate(charon->interfaces, - peer, child, (interface_manager_cb_t)xml_callback, - writer); - } - else - { - peer->destroy(peer); - } - } - /* */ - xmlTextWriterEndElement(writer); - xmlTextWriterWriteFormatElement(writer, "status", "%d", status); - } -} - -/** - * process a query request - */ -static void request_query(xmlTextReaderPtr reader, xmlTextWriterPtr writer) -{ - /* */ - xmlTextWriterStartElement(writer, "query"); - while (xmlTextReaderRead(reader)) - { - if (xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) - { - if (streq(xmlTextReaderConstName(reader), "ikesalist")) - { - request_query_ikesa(reader, writer); - break; - } - if (streq(xmlTextReaderConstName(reader), "configlist")) - { - request_query_config(reader, writer); - break; - } - } - } - /* */ - xmlTextWriterEndElement(writer); -} - -/** - * process a control request - */ -static void request_control(xmlTextReaderPtr reader, xmlTextWriterPtr writer) -{ - /* */ - xmlTextWriterStartElement(writer, "control"); - while (xmlTextReaderRead(reader)) - { - if (xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) - { - if (streq(xmlTextReaderConstName(reader), "ikesaterminate")) - { - request_control_terminate(reader, writer, TRUE); - break; - } - if (streq(xmlTextReaderConstName(reader), "childsaterminate")) - { - request_control_terminate(reader, writer, FALSE); - break; - } - if (streq(xmlTextReaderConstName(reader), "ikesainitiate")) - { - request_control_initiate(reader, writer, TRUE); - break; - } - if (streq(xmlTextReaderConstName(reader), "childsainitiate")) - { - request_control_initiate(reader, writer, FALSE); - break; - } - } - } - /* */ - xmlTextWriterEndElement(writer); -} - -/** - * process a request message - */ -static void request(xmlTextReaderPtr reader, char *id, int fd) -{ - xmlTextWriterPtr writer; - - writer = xmlNewTextWriter(xmlOutputBufferCreateFd(fd, NULL)); - if (writer == NULL) - { - DBG1(DBG_CFG, "opening SMP XML writer failed"); - return; - } - - xmlTextWriterStartDocument(writer, NULL, NULL, NULL); - /* */ - xmlTextWriterStartElement(writer, "message"); - xmlTextWriterWriteAttribute(writer, "xmlns", - "http://www.strongswan.org/smp/1.0"); - xmlTextWriterWriteAttribute(writer, "id", id); - xmlTextWriterWriteAttribute(writer, "type", "response"); - - while (xmlTextReaderRead(reader)) - { - if (xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) - { - if (streq(xmlTextReaderConstName(reader), "query")) - { - request_query(reader, writer); - break; - } - if (streq(xmlTextReaderConstName(reader), "control")) - { - request_control(reader, writer); - break; - } - } - } - /* and close document */ - xmlTextWriterEndDocument(writer); - xmlFreeTextWriter(writer); -} - -/** - * cleanup helper function for open file descriptors - */ -static void closefdp(int *fd) -{ - close(*fd); -} - -/** - * read from a opened connection and process it - */ -static job_requeue_t process(int *fdp) -{ - int oldstate, fd = *fdp; - char buffer[4096]; - size_t len; - xmlTextReaderPtr reader; - char *id = NULL, *type = NULL; - - pthread_cleanup_push((void*)closefdp, (void*)&fd); - pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); - len = read(fd, buffer, sizeof(buffer)); - pthread_setcancelstate(oldstate, NULL); - pthread_cleanup_pop(0); - if (len <= 0) - { - close(fd); - DBG2(DBG_CFG, "SMP XML connection closed"); - return JOB_REQUEUE_NONE; - } - DBG3(DBG_CFG, "got XML request: %b", buffer, len); - - reader = xmlReaderForMemory(buffer, len, NULL, NULL, 0); - if (reader == NULL) - { - DBG1(DBG_CFG, "opening SMP XML reader failed"); - return JOB_REQUEUE_FAIR;; - } - - /* read message type and id */ - while (xmlTextReaderRead(reader)) - { - if (xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT && - streq(xmlTextReaderConstName(reader), "message")) - { - id = xmlTextReaderGetAttribute(reader, "id"); - type = xmlTextReaderGetAttribute(reader, "type"); - break; - } - } - - /* process message */ - if (id && type) - { - if (streq(type, "request")) - { - request(reader, id, fd); - } - else - { - /* response(reader, id) */ - } - } - xmlFreeTextReader(reader); - return JOB_REQUEUE_FAIR;; -} - -/** - * accept from XML socket and create jobs to process connections - */ -static job_requeue_t dispatch(private_xml_interface_t *this) -{ - struct sockaddr_un strokeaddr; - int oldstate, fd, *fdp, strokeaddrlen = sizeof(strokeaddr); - callback_job_t *job; - - /* wait for connections, but allow thread to terminate */ - pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); - fd = accept(this->socket, (struct sockaddr *)&strokeaddr, &strokeaddrlen); - pthread_setcancelstate(oldstate, NULL); - - if (fd < 0) - { - DBG1(DBG_CFG, "accepting SMP XML socket failed: %s", strerror(errno)); - sleep(1); - return JOB_REQUEUE_FAIR;; - } - - fdp = malloc_thing(int); - *fdp = fd; - job = callback_job_create((callback_job_cb_t)process, fdp, free, this->job); - charon->processor->queue_job(charon->processor, (job_t*)job); - - return JOB_REQUEUE_DIRECT; -} - -/** - * Implementation of itnerface_t.destroy. - */ -static void destroy(private_xml_interface_t *this) -{ - this->job->cancel(this->job); - close(this->socket); - free(this); -} - -/* - * Described in header file - */ -interface_t *interface_create() -{ - struct sockaddr_un unix_addr = { AF_UNIX, IPSEC_PIDDIR "/charon.xml"}; - private_xml_interface_t *this = malloc_thing(private_xml_interface_t); - mode_t old; - - this->public.interface.destroy = (void (*)(interface_t*))destroy; - - /* set up unix socket */ - this->socket = socket(AF_UNIX, SOCK_STREAM, 0); - if (this->socket == -1) - { - DBG1(DBG_CFG, "could not create XML socket"); - free(this); - return NULL; - } - - unlink(unix_addr.sun_path); - old = umask(~(S_IRWXU | S_IRWXG)); - if (bind(this->socket, (struct sockaddr *)&unix_addr, sizeof(unix_addr)) < 0) - { - DBG1(DBG_CFG, "could not bind XML socket: %s", strerror(errno)); - close(this->socket); - free(this); - return NULL; - } - umask(old); - if (chown(unix_addr.sun_path, IPSEC_UID, IPSEC_GID) != 0) - { - DBG1(DBG_CFG, "changing XML socket permissions failed: %s", strerror(errno)); - } - - if (listen(this->socket, 5) < 0) - { - DBG1(DBG_CFG, "could not listen on XML socket: %s", strerror(errno)); - close(this->socket); - free(this); - return NULL; - } - - this->job = callback_job_create((callback_job_cb_t)dispatch, this, NULL, NULL); - charon->processor->queue_job(charon->processor, (job_t*)this->job); - - return &this->public.interface; -} - diff --git a/src/charon/control/interfaces/xml_interface.h b/src/charon/control/interfaces/xml_interface.h deleted file mode 100644 index 6d88c3842..000000000 --- a/src/charon/control/interfaces/xml_interface.h +++ /dev/null @@ -1,57 +0,0 @@ -/** - * @file xml_interface.h - * - * @brief Interface of xml_interface_t. - * - */ - -/* - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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 XML_INTERFACE_H_ -#define XML_INTERFACE_H_ - -typedef struct xml_interface_t xml_interface_t; - -#include - -/** - * @brief The XML interface uses a socket to communicate using XML. - * - * @b Constructors: - * - xml_interface_create() - * - * @ingroup interfaces - */ -struct xml_interface_t { - - /** - * implements interface_t. - */ - interface_t interface; -}; - - -/** - * @brief Create the XML interface. - * - * @return stroke_t object - * - * @ingroup interfaces - */ -interface_t *interface_create(void); - -#endif /* XML_INTERFACE_H_ */ - diff --git a/src/charon/control/interfaces/xml_interface.xml b/src/charon/control/interfaces/xml_interface.xml deleted file mode 100644 index 66a51117e..000000000 --- a/src/charon/control/interfaces/xml_interface.xml +++ /dev/null @@ -1,400 +0,0 @@ - - - - - - - - - - - - - - - - request - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - response - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - created - connecting - established - rekeying - deleting - - - - - initiator - responder - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 65535 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - any - - - - - - ipv4 - - - - - - ipv6 - - - - - - fqdn - - - - - - email - - - - - - asn1gn - - - - - - asn1dn - - - - - - keyid - - - - - - - - - - ipv4 - - - - - - ipv6 - - - - - - - - (([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(/([0-9]|[1-2][0-9]|3[0-2]))? - - - - - ([0-9a-fA-F]{1,4}:|:){1,7}([0-9a-fA-F]{1,4}|:)(/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8]))? - - - - - [a-z0-9\-](\.[a-z0-9\-]+)* - - - - - [a-zA-Z0-9_\-\.]+@(([a-z0-9\-](\.[a-z0-9\-]+)*)|(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])) - - - - - - - - - - - - - - - diff --git a/src/charon/credentials/auth_info.c b/src/charon/credentials/auth_info.c new file mode 100644 index 000000000..a0fc4c00f --- /dev/null +++ b/src/charon/credentials/auth_info.c @@ -0,0 +1,356 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + + +#include "auth_info.h" + +#include +#include +#include +#include + +ENUM(auth_item_names, AUTHN_CA_CERT, AUTHZ_AC_GROUP, + "AUTHN_CA_CERT", + "AUTHN_IM_CERT", + "AUTHN_SUBJECT_CERT", + "AUTHZ_PUBKEY", + "AUTHZ_PSK", + "AUTHZ_EAP", + "AUTHZ_CA_CERT", + "AUTHZ_IM_CERT", + "AUTHZ_SUBJECT_CERT", + "AUTHZ_CRL_VALIDATION", + "AUTHZ_OCSP_VALIDATION", + "AUTHZ_AC_GROUP", +); + +typedef struct private_auth_info_t private_auth_info_t; + +/** + * private data of item_set + */ +struct private_auth_info_t { + + /** + * public functions + */ + auth_info_t public; + + /** + * list of item_t's + */ + linked_list_t *items; +}; + +typedef struct item_t item_t; + +struct item_t { + /** type of this item */ + auth_item_t type; + /** associated privlege value, if any */ + void *value; +}; + +/** + * implements item_enumerator_t.enumerate + */ +static bool item_filter(void *data, item_t **item, auth_item_t *type, + void *unused, void **value) +{ + *type = (*item)->type; + *value = (*item)->value; + return TRUE; +} + +/** + * Implementation of auth_info_t.create_item_enumerator. + */ +static enumerator_t* create_item_enumerator(private_auth_info_t *this) +{ + return enumerator_create_filter(this->items->create_enumerator(this->items), + (void*)item_filter, NULL, NULL); +} + +/** + * Implementation of auth_info_t.get_item. + */ +static bool get_item(private_auth_info_t *this, auth_item_t type, void** value) +{ + enumerator_t *enumerator; + void *current_value; + auth_item_t current_type; + bool found = FALSE; + + enumerator = create_item_enumerator(this); + while (enumerator->enumerate(enumerator, ¤t_type, ¤t_value)) + { + if (type == current_type) + { + *value = current_value; + found = TRUE; + break; + } + } + enumerator->destroy(enumerator); + return found; +} + +/** + * Implementation of auth_info_t.add_item. + */ +static void add_item(private_auth_info_t *this, auth_item_t type, void *value) +{ + item_t *item = malloc_thing(item_t); + + item->type = type; + switch (type) + { + case AUTHZ_PUBKEY: + { + public_key_t *key = (public_key_t*)value; + + item->value = key->get_ref(key); + break; + } + case AUTHZ_PSK: + { + shared_key_t *key = (shared_key_t*)value; + + item->value = key->get_ref(key); + break; + } + case AUTHN_CA_CERT: + case AUTHN_IM_CERT: + case AUTHN_SUBJECT_CERT: + case AUTHZ_CA_CERT: + case AUTHZ_IM_CERT: + case AUTHZ_SUBJECT_CERT: + { + certificate_t *cert = (certificate_t*)value; + + item->value = cert->get_ref(cert); + break; + } + case AUTHZ_CRL_VALIDATION: + case AUTHZ_OCSP_VALIDATION: + { + cert_validation_t *validation = malloc_thing(cert_validation_t); + + *validation = *(cert_validation_t*)value; + item->value = validation; + break; + } + case AUTHZ_EAP: + { + eap_method_t *method = malloc_thing(eap_method_t); + + *method = *(eap_method_t*)value; + item->value = method; + break; + } + case AUTHZ_AC_GROUP: + { + identification_t *id = (identification_t*)value; + + item->value = id->clone(id); + break; + } + } + this->items->insert_last(this->items, item); +} + + +/** + * Implementation of auth_info_t.complies. + */ +static bool complies(private_auth_info_t *this, auth_info_t *constraints) +{ + enumerator_t *enumerator; + bool success = TRUE; + auth_item_t type; + void *value; + + enumerator = constraints->create_item_enumerator(constraints); + while (enumerator->enumerate(enumerator, &type, &value)) + { + switch (type) + { + case AUTHN_CA_CERT: + case AUTHN_IM_CERT: + case AUTHN_SUBJECT_CERT: + { /* skip non-authorization tokens */ + continue; + } + case AUTHZ_CRL_VALIDATION: + case AUTHZ_OCSP_VALIDATION: + { + cert_validation_t *valid; + + /* OCSP validation is also sufficient for CRL constraint, but + * not vice-versa */ + if (!get_item(this, type, (void**)&valid) && + type == AUTHZ_CRL_VALIDATION && + !get_item(this, AUTHZ_OCSP_VALIDATION, (void**)&valid)) + { + DBG1(DBG_CFG, "constraint check failed: %N requires at " + "least %N, but no check done", auth_item_names, type, + cert_validation_names, *(cert_validation_t*)value); + success = FALSE; + break; + } + switch (*(cert_validation_t*)value) + { + case VALIDATION_SKIPPED: + if (*valid == VALIDATION_SKIPPED) + { + break; + } /* FALL */ + case VALIDATION_GOOD: + if (*valid == VALIDATION_GOOD) + { + break; + } /* FALL */ + default: + DBG1(DBG_CFG, "constraint check failed: %N is %N, but " + "requires at least %N", auth_item_names, type, + cert_validation_names, *valid, + cert_validation_names, *(cert_validation_t*)value); + success = FALSE; + break; + } + break; + } + case AUTHZ_PUBKEY: + case AUTHZ_PSK: + case AUTHZ_IM_CERT: + case AUTHZ_SUBJECT_CERT: + case AUTHZ_EAP: + case AUTHZ_AC_GROUP: + DBG1(DBG_CFG, "constraint check %N not implemented!", + auth_item_names, type); + success = FALSE; + break; + case AUTHZ_CA_CERT: + { + certificate_t *cert; + + if (!get_item(this, AUTHZ_CA_CERT, (void**)&cert) || + !cert->equals(cert, (certificate_t*)value)) + { + cert = (certificate_t*)value; + DBG1(DBG_CFG, "constraint check failed: peer not " + "authenticated by CA '%D'.", cert->get_issuer(cert)); + success = FALSE; + } + break; + } + } + if (!success) + { + break; + } + } + enumerator->destroy(enumerator); + return success; +} + +/** + * Implementation of auth_info_t.merge. + */ +static void merge(private_auth_info_t *this, private_auth_info_t *other) +{ + item_t *item; + + while (other->items->remove_first(other->items, (void**)&item) == SUCCESS) + { + this->items->insert_last(this->items, item); + } +} + +/** + * Implementation of auth_info_t.destroy + */ +static void destroy(private_auth_info_t *this) +{ + item_t *item; + + while (this->items->remove_last(this->items, (void**)&item) == SUCCESS) + { + switch (item->type) + { + case AUTHZ_PUBKEY: + { + public_key_t *key = (public_key_t*)item->value; + key->destroy(key); + break; + } + case AUTHZ_PSK: + { + shared_key_t *key = (shared_key_t*)item->value; + key->destroy(key); + break; + } + case AUTHN_CA_CERT: + case AUTHN_IM_CERT: + case AUTHN_SUBJECT_CERT: + case AUTHZ_CA_CERT: + case AUTHZ_IM_CERT: + case AUTHZ_SUBJECT_CERT: + { + certificate_t *cert = (certificate_t*)item->value; + cert->destroy(cert); + break; + } + case AUTHZ_CRL_VALIDATION: + case AUTHZ_OCSP_VALIDATION: + case AUTHZ_EAP: + { + free(item->value); + break; + } + case AUTHZ_AC_GROUP: + { + identification_t *id = (identification_t*)item->value; + id->destroy(id); + break; + } + } + free(item); + } + this->items->destroy(this->items); + free(this); +} + +/* + * see header file + */ +auth_info_t *auth_info_create() +{ + private_auth_info_t *this = malloc_thing(private_auth_info_t); + + this->public.add_item = (void(*)(auth_info_t*, auth_item_t type, void *value))add_item; + this->public.get_item = (bool(*)(auth_info_t*, auth_item_t type, void **value))get_item; + this->public.create_item_enumerator = (enumerator_t*(*)(auth_info_t*))create_item_enumerator; + this->public.complies = (bool(*)(auth_info_t*, auth_info_t *))complies; + this->public.merge = (void(*)(auth_info_t*, auth_info_t *other))merge; + this->public.destroy = (void(*)(auth_info_t*))destroy; + + this->items = linked_list_create(); + + return &this->public; +} + diff --git a/src/charon/credentials/auth_info.h b/src/charon/credentials/auth_info.h new file mode 100644 index 000000000..f8ba29df0 --- /dev/null +++ b/src/charon/credentials/auth_info.h @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup auth_info auth_info + * @{ @ingroup ccredentials + */ + +#ifndef AUTH_INFO_H_ +#define AUTH_INFO_H_ + +#include + +typedef struct auth_info_t auth_info_t; +typedef enum auth_item_t auth_item_t; + +/** + * Authentication/Authorization process helper item. + * + * For the authentication process, further information may be needed. These + * items are defined as auth_item_t and have a AUTHN prefix. + * The authentication process returns important data for the authorization + * process, these items are defined with a AUTHZ prefix. + * Authentication uses AUTHN items and creates AUTHZ items during authentication, + * authorization reads AUTHZ values to give out privileges. + * + * +---+ +---------------------+ + * | A | | A | + * | u | | u +-----------+ | + * | t | | t | Required | | + * | h | | h | auth_info | | + * | e | | o +-----------+ | + * | n | | r | | + * +-----------+ | t | | i | | + * | Provided | | i | | z V | + * | auth_info |--| c |-------------| a ----> match? ----|-------> + * +-----------+ | a | | t | + * | t | | i | + * | i | | o | + * | o | | n | + * | n | | | + * +---+ +---------------------+ + */ +enum auth_item_t { + + /* + * items provided to authentication process + */ + + /** CA certificate to use for authentication, value is certificate_t* */ + AUTHN_CA_CERT, + /** intermediate certificate, value is certificate_t* */ + AUTHN_IM_CERT, + /** certificate for trustchain verification, value is certificate_t* */ + AUTHN_SUBJECT_CERT, + + /* + * item provided to authorization process + */ + + /** subject has been authenticated by public key, value is public_key_t* */ + AUTHZ_PUBKEY, + /** subject has ben authenticated using preshared secrets, value is shared_key_t* */ + AUTHZ_PSK, + /** subject has been authenticated using EAP, value is eap_method_t */ + AUTHZ_EAP, + /** certificate authority, value is certificate_t* */ + AUTHZ_CA_CERT, + /** intermediate certificate in trustchain, value is certificate_t* */ + AUTHZ_IM_CERT, + /** subject certificate, value is certificate_t* */ + AUTHZ_SUBJECT_CERT, + /** result of a CRL validation, value is cert_validation_t */ + AUTHZ_CRL_VALIDATION, + /** result of a OCSP validation, value is cert_validation_t */ + AUTHZ_OCSP_VALIDATION, + /** subject is in attribute certificate group, value is identification_t* */ + AUTHZ_AC_GROUP, +}; + + +/** + * enum name for auth_item_t. + */ +extern enum_name_t *auth_item_names; + +/** + * The auth_info class contains auth_item_t's used for AA. + * + * A auth_info allows the separation of authentication and authorization. + */ +struct auth_info_t { + + /** + * Add an item to the set. + * + * @param type auth_info type + * @param value associated value to auth_info type, if any + */ + void (*add_item)(auth_info_t *this, auth_item_t type, void *value); + + /** + * Get an item. + * + * @param type auth_info type to get + * @param value pointer to a pointer receiving item + * @return bool if item has been found + */ + bool (*get_item)(auth_info_t *this, auth_item_t type, void **value); + + /** + * Create an enumerator over all items. + * + * @return enumerator over (auth_item_t type, void *value) + */ + enumerator_t* (*create_item_enumerator)(auth_info_t *this); + + /** + * Check if this fulfills a set of required constraints. + * + * @param constraints required authorization infos + * @return TRUE if this complies with constraints + */ + bool (*complies)(auth_info_t *this, auth_info_t *constraints); + + /** + * Merge items from other into this. + * + * Items do not get cloned, but moved from other to this. + * + * @param other items to read for merge + */ + void (*merge)(auth_info_t *this, auth_info_t *other); + + /** + * Destroy a auth_info instance with all associated values. + */ + void (*destroy)(auth_info_t *this); +}; + +/** + * Create a auth_info instance. + */ +auth_info_t *auth_info_create(); + +#endif /* AUTH_INFO_H_ @}*/ diff --git a/src/charon/credentials/credential_manager.c b/src/charon/credentials/credential_manager.c new file mode 100644 index 000000000..e5db23524 --- /dev/null +++ b/src/charon/credentials/credential_manager.c @@ -0,0 +1,1385 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "credential_manager.h" + +#include +#include +#include +#include +#include +#include +#include + +#define MAX_CA_LEVELS 6 + +typedef struct private_credential_manager_t private_credential_manager_t; + +/** + * private data of credential_manager + */ +struct private_credential_manager_t { + + /** + * public functions + */ + credential_manager_t public; + + /** + * list of credential sets + */ + linked_list_t *sets; + + /** + * mutex to gain exclusive access + */ + mutex_t *mutex; +}; + +/** data to pass to create_private_enumerator */ +typedef struct { + private_credential_manager_t *this; + key_type_t type; + identification_t* keyid; +} private_data_t; + +/** data to pass to create_cert_enumerator */ +typedef struct { + private_credential_manager_t *this; + certificate_type_t cert; + key_type_t key; + identification_t *id; + bool trusted; +} cert_data_t; + +/** data to pass to create_cdp_enumerator */ +typedef struct { + private_credential_manager_t *this; + certificate_type_t type; + identification_t *id; +} cdp_data_t; + +/** data to pass to create_shared_enumerator */ +typedef struct { + private_credential_manager_t *this; + shared_key_type_t type; + identification_t *me; + identification_t *other; +} shared_data_t; + +/** + * cleanup function for cert data + */ +static void destroy_cert_data(cert_data_t *data) +{ + data->this->mutex->unlock(data->this->mutex); + free(data); +} + +/** + * enumerator constructor for certificates + */ +static enumerator_t *create_cert(credential_set_t *set, cert_data_t *data) +{ + return set->create_cert_enumerator(set, data->cert, data->key, + data->id, data->trusted); +} + +/** + * Implementation of credential_manager_t.create_cert_enumerator. + */ +static enumerator_t *create_cert_enumerator(private_credential_manager_t *this, + certificate_type_t certificate, key_type_t key, + identification_t *id, bool trusted) +{ + cert_data_t *data = malloc_thing(cert_data_t); + data->this = this; + data->cert = certificate; + data->key = key; + data->id = id; + data->trusted = trusted; + + this->mutex->lock(this->mutex); + return enumerator_create_nested(this->sets->create_enumerator(this->sets), + (void*)create_cert, data, + (void*)destroy_cert_data); +} + +/** + * Implementation of credential_manager_t.get_cert. + */ +static certificate_t *get_cert(private_credential_manager_t *this, + certificate_type_t cert, key_type_t key, + identification_t *id, bool trusted) +{ + certificate_t *current, *found = NULL; + enumerator_t *enumerator; + + this->mutex->lock(this->mutex); + enumerator = create_cert_enumerator(this, cert, key, id, trusted); + if (enumerator->enumerate(enumerator, ¤t)) + { + /* TODO: best match? order by keyid, subject, sualtname */ + found = current->get_ref(current); + } + enumerator->destroy(enumerator); + this->mutex->unlock(this->mutex); + return found; +} + + +/** + * cleanup function for cdp data + */ +static void destroy_cdp_data(cdp_data_t *data) +{ + data->this->mutex->unlock(data->this->mutex); + free(data); +} + +/** + * enumerator constructor for CDPs + */ +static enumerator_t *create_cdp(credential_set_t *set, cdp_data_t *data) +{ + return set->create_cdp_enumerator(set, data->type, data->id); +} +/** + * Implementation of credential_manager_t.create_cdp_enumerator. + */ +static enumerator_t * create_cdp_enumerator(private_credential_manager_t *this, + credential_type_t type, identification_t *id) +{ + cdp_data_t *data = malloc_thing(cdp_data_t); + data->this = this; + data->type = type; + data->id = id; + + this->mutex->lock(this->mutex); + return enumerator_create_nested(this->sets->create_enumerator(this->sets), + (void*)create_cdp, data, + (void*)destroy_cdp_data); +} + +/** + * cleanup function for private data + */ +static void destroy_private_data(private_data_t *data) +{ + data->this->mutex->unlock(data->this->mutex); + free(data); +} + +/** + * enumerator constructor for private keys + */ +static enumerator_t *create_private(credential_set_t *set, private_data_t *data) +{ + return set->create_private_enumerator(set, data->type, data->keyid); +} + +/** + * Implementation of credential_manager_t.get_private_by_keyid. + */ +static enumerator_t* create_private_enumerator( + private_credential_manager_t *this, + key_type_t key, identification_t *keyid) +{ + private_data_t *data; + + data = malloc_thing(private_data_t); + data->this = this; + data->type = key; + data->keyid = keyid; + this->mutex->lock(this->mutex); + return enumerator_create_nested(this->sets->create_enumerator(this->sets), + (void*)create_private, data, (void*)destroy_private_data); +} + +/** + * Implementation of credential_manager_t.get_private_by_keyid. + */ +static private_key_t *get_private_by_keyid(private_credential_manager_t *this, + key_type_t key, identification_t *keyid) +{ + private_key_t *found = NULL; + enumerator_t *enumerator; + + enumerator = create_private_enumerator(this, key, keyid); + if (enumerator->enumerate(enumerator, &found)) + { + found->get_ref(found); + } + enumerator->destroy(enumerator); + return found; +} + +/** + * cleanup function for shared data + */ +static void destroy_shared_data(shared_data_t *data) +{ + data->this->mutex->unlock(data->this->mutex); + free(data); +} + +/** + * enumerator constructor for shared keys + */ +static enumerator_t *create_shared(credential_set_t *set, shared_data_t *data) +{ + return set->create_shared_enumerator(set, data->type, data->me, data->other); +} + +/** + * Implementation of credential_manager_t.create_shared_enumerator. + */ +static enumerator_t *create_shared_enumerator(private_credential_manager_t *this, + shared_key_type_t type, + identification_t *me, identification_t *other) +{ + shared_data_t *data = malloc_thing(shared_data_t); + data->this = this; + data->type = type; + data->me = me; + data->other = other; + + this->mutex->lock(this->mutex); + return enumerator_create_nested(this->sets->create_enumerator(this->sets), + (void*)create_shared, data, + (void*)destroy_shared_data); +} + +/** + * Implementation of credential_manager_t.get_shared. + */ +static shared_key_t *get_shared(private_credential_manager_t *this, + shared_key_type_t type, identification_t *me, + identification_t *other) +{ + shared_key_t *current, *found = NULL; + id_match_t *best_me = ID_MATCH_NONE, *best_other = ID_MATCH_NONE; + id_match_t *match_me, *match_other; + enumerator_t *enumerator; + + enumerator = create_shared_enumerator(this, type, me, other); + while (enumerator->enumerate(enumerator, ¤t, &match_me, &match_other)) + { + if (match_other > best_other || + (match_other == best_other && match_me > best_me)) + { + DESTROY_IF(found); + found = current->get_ref(current); + best_me = match_me; + best_other = match_other; + } + } + enumerator->destroy(enumerator); + return found; +} + +/** + * forward declaration + */ +static certificate_t *get_trusted_cert(private_credential_manager_t *this, + key_type_t type, identification_t *id, + auth_info_t *auth, bool crl, bool ocsp); +/** + * return null ;-) + */ +static void *return_null() +{ + return NULL; +} + +/** + * credential_set_t implementation around an OCSP response + */ +typedef struct ocsp_wrapper_t { + credential_set_t set; + ocsp_response_t *response; +} ocsp_wrapper_t; + +/** + * enumerator for ocsp_wrapper_t.create_cert_enumerator() + */ +typedef struct { + enumerator_t public; + enumerator_t *inner; + certificate_type_t cert; + key_type_t key; + identification_t *id; +} ocsp_wrapper_enumerator_t; + +/** + * enumerate function for ocsp_wrapper_enumerator_t + */ +static bool ocsp_wrapper_enum_enumerate(ocsp_wrapper_enumerator_t *this, + certificate_t **cert) +{ + certificate_t *current; + public_key_t *public; + + while (this->inner->enumerate(this->inner, ¤t)) + { + if (this->cert != CERT_ANY && this->cert != current->get_type(current)) + { /* CERT type requested, but does not match */ + continue; + } + public = current->get_public_key(current); + if (this->key != KEY_ANY && !public) + { /* key type requested, but no public key */ + DESTROY_IF(public); + continue; + } + if (this->key != KEY_ANY && public && this->key != public->get_type(public)) + { /* key type requested, but public key has another type */ + DESTROY_IF(public); + continue; + } + DESTROY_IF(public); + if (this->id && !current->has_subject(current, this->id)) + { /* subject requested, but does not match */ + continue; + } + *cert = current; + return TRUE; + } + return FALSE; +} + +/** + * destroy function for ocsp_wrapper_enumerator_t + */ +static void ocsp_wrapper_enum_destroy(ocsp_wrapper_enumerator_t *this) +{ + this->inner->destroy(this->inner); + free(this); +} + +/** + * implementation of ocsp_wrapper_t.set.create_cert_enumerator + */ +static enumerator_t *ocsp_wrapper_create_enumerator(ocsp_wrapper_t *this, + certificate_type_t cert, key_type_t key, + identification_t *id, bool trusted) +{ + ocsp_wrapper_enumerator_t *enumerator; + + if (trusted) + { + return NULL; + } + + enumerator = malloc_thing(ocsp_wrapper_enumerator_t); + enumerator->cert = cert; + enumerator->key = key; + enumerator->id = id; + enumerator->inner = this->response->create_cert_enumerator(this->response); + enumerator->public.enumerate = (void*)ocsp_wrapper_enum_enumerate; + enumerator->public.destroy = (void*)ocsp_wrapper_enum_destroy; + return &enumerator->public; +} + +/** + * create credential_set wrapper around an OCSP response + */ +static ocsp_wrapper_t *ocsp_wrapper_create(ocsp_response_t *response) +{ + ocsp_wrapper_t *this = malloc_thing(ocsp_wrapper_t); + + this->response = response; + this->set.create_private_enumerator = (void*)return_null; + this->set.create_cert_enumerator = (void*)ocsp_wrapper_create_enumerator; + this->set.create_shared_enumerator = (void*)return_null; + this->set.create_cdp_enumerator = (void*)return_null; + + return this; +} + +/** + * Do an OCSP request + */ +static ocsp_response_t *fetch_ocsp(private_credential_manager_t *this, char *url, + certificate_t *subject, certificate_t *issuer) +{ + certificate_t *request, *response, *issuer_cert; + chunk_t send, receive; + identification_t *responder; + auth_info_t *auth; + ocsp_wrapper_t *wrapper; + + /* TODO: requestor name, signature */ + request = lib->creds->create(lib->creds, + CRED_CERTIFICATE, CERT_X509_OCSP_REQUEST, + BUILD_CA_CERT, issuer->get_ref(issuer), + BUILD_CERT, subject->get_ref(subject), BUILD_END); + if (!request) + { + DBG1(DBG_CFG, "generating OCSP request failed"); + return NULL; + } + + send = request->get_encoding(request); + request->destroy(request); + if (lib->fetcher->fetch(lib->fetcher, url, &receive, + FETCH_REQUEST_DATA, send, + FETCH_REQUEST_TYPE, "application/ocsp-request", + FETCH_END) != SUCCESS) + { + DBG1(DBG_CFG, "OCSP request to %s failed", url); + chunk_free(&send); + return NULL; + } + chunk_free(&send); + + response = lib->creds->create(lib->creds, + CRED_CERTIFICATE, CERT_X509_OCSP_RESPONSE, + BUILD_BLOB_ASN1_DER, receive, BUILD_END); + if (!response) + { + DBG1(DBG_CFG, "parsing OCSP response from %s failed", url); + return NULL; + } + + responder = response->get_issuer(response); + auth = auth_info_create(); + wrapper = ocsp_wrapper_create((ocsp_response_t*)response); + this->sets->insert_first(this->sets, wrapper); + issuer_cert = get_trusted_cert(this, KEY_ANY, responder, auth, FALSE, FALSE); + this->sets->remove(this->sets, wrapper, NULL); + free(wrapper); + auth->destroy(auth); + if (!issuer_cert) + { + DBG1(DBG_CFG, "verifying OCSP response failed, no trusted " + "certificate found"); + response->destroy(response); + return NULL; + } + if (!response->issued_by(response, issuer_cert, TRUE)) + { + DBG1(DBG_CFG, "verifying OCSP response signature failed"); + response->destroy(response); + issuer_cert->destroy(issuer_cert); + return NULL; + } + issuer_cert->destroy(issuer_cert); + + /* TODO: cache response? */ + + return (ocsp_response_t*)response; +} + +/** + * validate a x509 certificate using OCSP + */ +static cert_validation_t check_ocsp(private_credential_manager_t *this, + x509_t *subject, x509_t *issuer, + auth_info_t *auth) +{ + public_key_t *public; + enumerator_t *enumerator; + ocsp_response_t *response = NULL; + certificate_t *cert, *sub = (certificate_t*)subject; + cert_validation_t valid = VALIDATION_SKIPPED; + identification_t *keyid = NULL; + char *url; + + cert = &issuer->interface; + public = cert->get_public_key(cert); + if (public) + { + keyid = public->get_id(public, ID_PUBKEY_INFO_SHA1); + } + + /* find a OCSP response by Authority key identifier (cache) */ + if (keyid) + { + time_t update, best_update = 0; + + enumerator = create_cert_enumerator(this, CERT_X509_OCSP_RESPONSE, + KEY_ANY, keyid, TRUE); + while (enumerator->enumerate(enumerator, &cert)) + { /* get newest valid response */ + if (cert->has_subject(cert, sub->get_subject(sub)) && + cert->get_validity(cert, NULL, &update, NULL) && + update > best_update) + { + best_update = update; + DESTROY_IF(&response->certificate); + response = (ocsp_response_t*)cert; + valid = VALIDATION_FAILED; + } + } + enumerator->destroy(enumerator); + } + /* fallback to URL fetching from CDPs */ + if (!response && keyid) + { + enumerator = create_cdp_enumerator(this, CERT_X509_OCSP_RESPONSE, keyid); + while (enumerator->enumerate(enumerator, &url)) + { + valid = VALIDATION_FAILED; + response = fetch_ocsp(this, url, &subject->interface, &issuer->interface); + if (response) + { + break; + } + } + enumerator->destroy(enumerator); + } + /* fallback to URL fetching from subject certificate's URIs */ + if (!response) + { + enumerator = subject->create_ocsp_uri_enumerator(subject); + while (enumerator->enumerate(enumerator, &url)) + { + valid = VALIDATION_FAILED; + response = fetch_ocsp(this, url, &subject->interface, &issuer->interface); + if (response) + { + break; + } + } + enumerator->destroy(enumerator); + } + /* look for subject in response */ + if (response) + { + time_t revocation, this_update, next_update; + crl_reason_t reason; + + valid = response->get_status(response, subject, issuer, &revocation, + &reason, &this_update, &next_update); + switch (valid) + { + case VALIDATION_FAILED: + DBG1(DBG_CFG, "subject not found in OCSP response"); + break; + case VALIDATION_REVOKED: + DBG1(DBG_CFG, "certificate %D revoked by OCSP at %T: %N", + cert->get_subject(cert), &revocation, + crl_reason_names, reason); + break; + case VALIDATION_GOOD: + break; + default: + break; + } + cert = (certificate_t*)response; + cert->destroy(cert); + } + DESTROY_IF(public); + if (auth) + { + auth->add_item(auth, AUTHZ_OCSP_VALIDATION, &valid); + } + return valid; +} + +/** + * fetch a CRL from an URL + */ +static certificate_t* fetch_crl(private_credential_manager_t *this, char *url) +{ + certificate_t *crl_cert; + chunk_t chunk; + + /* TODO: unlock the manager while fetching? */ + DBG1(DBG_CFG, "fetching crl from '%s' ...", url); + if (lib->fetcher->fetch(lib->fetcher, url, &chunk, FETCH_END) != SUCCESS) + { + DBG1(DBG_CFG, " crl fetching failed"); + return NULL; + } + crl_cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509_CRL, + BUILD_BLOB_ASN1_DER, chunk, BUILD_END); + if (!crl_cert) + { + DBG1(DBG_CFG, " crl fetched successfully but parsing failed"); + return NULL; + } + + /* verify the signature of the fetched crl */ + { + bool ok; + identification_t *issuer = crl_cert->get_issuer(crl_cert); + auth_info_t *auth = auth_info_create(); + certificate_t *issuer_cert = get_trusted_cert(this, KEY_ANY, issuer, + auth, FALSE, FALSE); + auth->destroy(auth); + + if (!issuer_cert) + { + DBG1(DBG_CFG, " crl is untrusted: issuer certificate not found"); + crl_cert->destroy(crl_cert); + return NULL; + } + ok = crl_cert->issued_by(crl_cert, issuer_cert, TRUE); + issuer_cert->destroy(issuer_cert); + + DBG1(DBG_CFG, " crl is %strusted: %s signature", + ok ? "":"un", ok ? "good" : "bad"); + if (!ok) + { + crl_cert->destroy(crl_cert); + return NULL; + } + } + return crl_cert; +} + +/** + * validate a x509 certificate using CRL + */ +static cert_validation_t check_crl(private_credential_manager_t *this, + x509_t *subject, x509_t *issuer, + auth_info_t *auth) +{ + identification_t *keyid = NULL; + certificate_t *best_cert = NULL; + cert_validation_t valid = VALIDATION_SKIPPED; + bool stale = TRUE; + + /* derive the authorityKeyIdentifier from the issuer's public key */ + { + certificate_t *cert = &issuer->interface; + public_key_t *public = cert->get_public_key(cert); + + if (public) + { + keyid = public->get_id(public, ID_PUBKEY_SHA1); + public->destroy(public); + } + } + + /* find a local crl by authorityKeyIdentifier */ + if (keyid) + { + enumerator_t *enumerator = create_cert_enumerator(this, CERT_X509_CRL, + KEY_ANY, keyid, TRUE); + certificate_t *cert; + + while (enumerator->enumerate(enumerator, &cert)) + { + crl_t *crl = (crl_t*)cert; + crl_t *best_crl = (crl_t*)best_cert; + + /* select most recent crl */ + if (best_cert == NULL || crl->is_newer(crl, best_crl)) + { + DESTROY_IF(best_cert); + best_cert = cert->get_ref(cert); + } + } + enumerator->destroy(enumerator); + } + + /* check the validity of the local crl if one was found */ + if (best_cert) + { + stale = !best_cert->get_validity(best_cert, NULL, NULL, NULL); + DBG1(DBG_CFG, "locally-stored crl is %s", stale? "stale":"valid"); + } + else + { + DBG1(DBG_CFG, "no locally-stored crl found"); + } + + /* fallback to fetching crls from cdps defined in ca info sections */ + if (stale && keyid) + { + enumerator_t *enumerator = create_cdp_enumerator(this, CERT_X509_CRL, + keyid); + char *uri; + + while (enumerator->enumerate(enumerator, &uri)) + { + certificate_t *cert = fetch_crl(this, uri); + + /* redefine default since we have at least one uri */ + valid = VALIDATION_FAILED; + + if (cert) + { + crl_t *crl = (crl_t*)cert; + crl_t *best_crl = (crl_t*)best_cert; + + /* select most recent crl */ + if (best_cert == NULL || crl->is_newer(crl, best_crl)) + { + DESTROY_IF(best_cert); + best_cert = cert; + stale = !best_cert->get_validity(best_cert, NULL, NULL, NULL); + DBG1(DBG_CFG, "fetched crl is %s", stale? "stale":"valid"); + if (!stale) + { + break; + } + } + else + { + cert->destroy(cert); + } + } + } + enumerator->destroy(enumerator); + } + + /* fallback to fetching crls from cdps defined in the subject's certificate */ + if (stale) + { + enumerator_t *enumerator = subject->create_crl_uri_enumerator(subject); + char *uri; + + while (enumerator->enumerate(enumerator, &uri)) + { + certificate_t *cert = fetch_crl(this, uri); + + /* redefine default since we have at least one uri */ + valid = VALIDATION_FAILED; + + if (cert) + { + crl_t *crl = (crl_t*)cert; + crl_t *best_crl = (crl_t*)best_cert; + + /* select most recent crl */ + if (best_cert == NULL || crl->is_newer(crl, best_crl)) + { + DESTROY_IF(best_cert); + best_cert = cert; + stale = !best_cert->get_validity(best_cert, NULL, NULL, NULL); + DBG1(DBG_CFG, "fetched crl is %s", stale? "stale":"valid"); + if (!stale) + { + break; + } + } + else + { + cert->destroy(cert); + } + } + } + enumerator->destroy(enumerator); + } + + /* if we have a crl, check the revocation status */ + if (best_cert) + { + chunk_t serial; + time_t revocation; + crl_reason_t reason; + crl_t *crl = (crl_t*)best_cert; + enumerator_t *enumerator = crl->create_enumerator(crl); + + /* redefine default */ + valid = stale ? VALIDATION_UNKNOWN : VALIDATION_GOOD; + + while (enumerator->enumerate(enumerator, &serial, &revocation, &reason)) + { + if (chunk_equals(serial, subject->get_serial(subject))) + { + DBG1(DBG_CFG, "certificate was revoked on %T, reason: %N", + &revocation, crl_reason_names, reason); + valid = VALIDATION_REVOKED; + break; + } + } + enumerator->destroy(enumerator); + best_cert->destroy(best_cert); + } + + if (auth) + { + auth->add_item(auth, AUTHZ_CRL_VALIDATION, &valid); + } + return valid; +} + +/** + * check a certificate for its lifetime + */ +static bool check_certificate(private_credential_manager_t *this, + certificate_t *subject, certificate_t *issuer, + bool crl, bool ocsp, auth_info_t *auth) +{ + time_t not_before, not_after; + + if (!subject->get_validity(subject, NULL, ¬_before, ¬_after)) + { + DBG1(DBG_CFG, "certificate invalid (valid from %T to %T)", + ¬_before, ¬_after); + return FALSE; + } + if (issuer && !subject->issued_by(subject, issuer, TRUE)) + { + DBG1(DBG_CFG, "certificate %D not issued by %D", + subject->get_subject(subject), issuer->get_subject(issuer)); + return FALSE; + } + if (issuer && issuer->get_type(issuer) == CERT_X509 && + subject->get_type(subject) == CERT_X509) + { + if (ocsp) + { + switch (check_ocsp(this, (x509_t*)subject, (x509_t*)issuer, auth)) + { + case VALIDATION_GOOD: + DBG1(DBG_CFG, "certificate %D validated by OCSP", + subject->get_subject(subject)); + return TRUE; + case VALIDATION_REVOKED: + return FALSE; + case VALIDATION_SKIPPED: + DBG2(DBG_CFG, "OCSP check skipped, no OCSP URI found"); + break; + case VALIDATION_FAILED: + DBG1(DBG_CFG, "OCSP check failed, fallback to CRL"); + break; + } + } + if (crl) + { + switch (check_crl(this, (x509_t*)subject, (x509_t*)issuer, auth)) + { + case VALIDATION_GOOD: + DBG1(DBG_CFG, "certificate status is good"); + break; + case VALIDATION_REVOKED: + /* has already been logged */ + break; + case VALIDATION_UNKNOWN: + DBG1(DBG_CFG, "certificate status is unknown"); + break; + case VALIDATION_FAILED: + case VALIDATION_SKIPPED: + DBG1(DBG_CFG, "certificate status is not available"); + break; + default: + break; + } + } + } + return TRUE; +} + +/** + * credential_set_t implementation around a auth_info_t + */ +typedef struct auth_wrapper_t { + credential_set_t set; + auth_info_t *auth; +} auth_wrapper_t; + +/** + * enumerator for auth_wrapper_t.create_cert_enumerator() + */ +typedef struct { + enumerator_t public; + enumerator_t *inner; + certificate_type_t cert; + key_type_t key; + identification_t *id; +} auth_wrapper_enumerator_t; + +/** + * enumerate function for auth_wrapper_enumerator_t + */ +static bool auth_wrapper_enum_enumerate(auth_wrapper_enumerator_t *this, + certificate_t **cert) +{ + auth_item_t type; + certificate_t *current; + public_key_t *public; + + while (this->inner->enumerate(this->inner, &type, ¤t)) + { + if (type != AUTHN_SUBJECT_CERT && + type != AUTHN_IM_CERT) + { + continue; + } + + if (this->cert != CERT_ANY && this->cert != current->get_type(current)) + { /* CERT type requested, but does not match */ + continue; + } + public = current->get_public_key(current); + if (this->key != KEY_ANY && !public) + { /* key type requested, but no public key */ + DESTROY_IF(public); + continue; + } + if (this->key != KEY_ANY && public && this->key != public->get_type(public)) + { /* key type requested, but public key has another type */ + DESTROY_IF(public); + continue; + } + DESTROY_IF(public); + if (this->id && !current->has_subject(current, this->id)) + { /* subject requested, but does not match */ + continue; + } + *cert = current; + return TRUE; + } + return FALSE; +} + +/** + * destroy function for auth_wrapper_enumerator_t + */ +static void auth_wrapper_enum_destroy(auth_wrapper_enumerator_t *this) +{ + this->inner->destroy(this->inner); + free(this); +} + +/** + * implementation of auth_wrapper_t.set.create_cert_enumerator + */ +static enumerator_t *auth_wrapper_create_enumerator(auth_wrapper_t *this, + certificate_type_t cert, key_type_t key, + identification_t *id, bool trusted) +{ + auth_wrapper_enumerator_t *enumerator; + + if (trusted) + { + return NULL; + } + + enumerator = malloc_thing(auth_wrapper_enumerator_t); + enumerator->cert = cert; + enumerator->key = key; + enumerator->id = id; + enumerator->inner = this->auth->create_item_enumerator(this->auth); + enumerator->public.enumerate = (void*)auth_wrapper_enum_enumerate; + enumerator->public.destroy = (void*)auth_wrapper_enum_destroy; + return &enumerator->public; +} + +/** + * create credential_set wrapper around auth_info_t + */ +static auth_wrapper_t *auth_wrapper_create(auth_info_t *auth) +{ + auth_wrapper_t *this = malloc_thing(auth_wrapper_t); + + this->auth = auth; + this->set.create_private_enumerator = (void*)return_null; + this->set.create_cert_enumerator = (void*)auth_wrapper_create_enumerator; + this->set.create_shared_enumerator = (void*)return_null; + this->set.create_cdp_enumerator = (void*)return_null; + + return this; +} + +/** + * Get a trusted certificate + */ +static certificate_t *get_trusted_cert(private_credential_manager_t *this, + key_type_t type, identification_t *id, + auth_info_t *auth, bool crl, bool ocsp) +{ + enumerator_t *enumerator; + auth_wrapper_t *wrapper; + certificate_t *subject, *issuer, *candidate; + public_key_t *public; + bool trusted = FALSE; + auth_info_t *auth1, *auth2; + u_int level = 0; + + this->mutex->lock(this->mutex); + wrapper = auth_wrapper_create(auth); + this->sets->insert_first(this->sets, wrapper); + + /* check if we have a trusted certificate for that peer */ + auth1 = auth_info_create(); + subject = get_cert(this, CERT_ANY, type, id, TRUE); + if (subject) + { + if (check_certificate(this, subject, NULL, crl, ocsp, auth1)) + { + public = subject->get_public_key(subject); + if (public) + { + DBG2(DBG_CFG, "using trusted certificate %D", + subject->get_subject(subject)); + this->sets->remove(this->sets, wrapper, NULL); + free(wrapper); + this->mutex->unlock(this->mutex); + auth->add_item(auth1, AUTHZ_SUBJECT_CERT, subject); + public->destroy(public); + auth->merge(auth, auth1); + auth1->destroy(auth1); + return subject; + } + } + subject->destroy(subject); + } + auth1->destroy(auth1); + + /* check for an untrusted certificate */ + auth1 = auth_info_create(); + subject = get_cert(this, CERT_ANY, type, id, FALSE); + if (!subject) + { + DBG1(DBG_CFG, "no end entity certificate found for %D", id); + } + else + { + issuer = subject; + do + { + /* look for a trusted certificate */ + auth2 = auth_info_create(); + enumerator = create_cert_enumerator(this, issuer->get_type(issuer), + KEY_ANY, issuer->get_issuer(issuer), TRUE); + while (enumerator->enumerate(enumerator, &candidate)) + { + if (check_certificate(this, issuer, candidate, crl, ocsp, + issuer == subject ? auth2 : NULL) && + check_certificate(this, candidate, NULL, crl, ocsp, NULL)) + { + DBG2(DBG_CFG, "using trusted root CA certificate %D", + candidate->get_subject(candidate)); + issuer = candidate; + trusted = TRUE; + auth1->merge(auth1, auth2); + auth1->add_item(auth1, AUTHZ_CA_CERT, candidate); + break; + } + } + enumerator->destroy(enumerator); + auth2->destroy(auth2); + if (trusted) + { + break; + } + + /* no trusted certificate found, look for an untrusted */ + enumerator = create_cert_enumerator(this, issuer->get_type(issuer), + KEY_ANY, issuer->get_issuer(issuer), FALSE); + while (enumerator->enumerate(enumerator, &candidate)) + { + auth2 = auth_info_create(); + if (check_certificate(this, issuer, candidate, crl, ocsp, + issuer == subject ? auth2 : NULL)) + { + if (issuer != subject) + { + DBG2(DBG_CFG, "using intermediate CA certificate %D", + candidate->get_subject(candidate)); + auth1->add_item(auth1, AUTHZ_IM_CERT, candidate); + } + else + { + DBG2(DBG_CFG, "using end entity certificate %D", + candidate->get_subject(candidate)); + } + issuer = candidate; + auth1->merge(auth1, auth2); + auth2->destroy(auth2); + /* check next level */ + break; + } + auth2->destroy(auth2); + } + enumerator->destroy(enumerator); + } + while (++level < MAX_CA_LEVELS); + + if (!trusted) + { + subject->destroy(subject); + subject = NULL; + } + } + this->sets->remove(this->sets, wrapper, NULL); + free(wrapper); + this->mutex->unlock(this->mutex); + if (subject) + { + auth->add_item(auth, AUTHZ_SUBJECT_CERT, subject); + auth->merge(auth, auth1); + auth1->destroy(auth1); + return subject; + } + auth1->destroy(auth1); + return NULL; +} + +/** + * Implementation of credential_manager_t.get_public. + */ +static public_key_t *get_public(private_credential_manager_t *this, + key_type_t type, identification_t *id, + auth_info_t *auth) +{ + public_key_t *public; + certificate_t *cert; + + cert = get_trusted_cert(this, type, id, auth, TRUE, TRUE); + if (cert) + { + public = cert->get_public_key(cert); + cert->destroy(cert); + return public; + } + return NULL; +} + +/** + * Get the issuing certificate of a subject certificate + */ +static certificate_t *get_issuer_cert(private_credential_manager_t *this, + certificate_t *subject) +{ + enumerator_t *enumerator; + certificate_t *issuer = NULL, *candidate; + + enumerator = create_cert_enumerator(this, subject->get_type(subject), KEY_ANY, + subject->get_issuer(subject), FALSE); + while (enumerator->enumerate(enumerator, &candidate)) + { + if (subject->issued_by(subject, candidate, FALSE)) + { + issuer = candidate->get_ref(candidate); + break; + } + } + enumerator->destroy(enumerator); + return issuer; +} + +/** + * Check if a certificate's keyid is contained in the auth helper + */ +static bool auth_contains_cacert(auth_info_t *auth, certificate_t *cert) +{ + enumerator_t *enumerator; + identification_t *value; + auth_item_t type; + bool found = FALSE; + + enumerator = auth->create_item_enumerator(auth); + while (enumerator->enumerate(enumerator, &type, &value)) + { + if (type == AUTHN_CA_CERT && cert->equals(cert, (certificate_t*)value)) + { + found = TRUE; + break; + } + } + enumerator->destroy(enumerator); + return found; +} + +/** + * Implementation of credential_manager_t.get_private. + */ +static private_key_t *get_private(private_credential_manager_t *this, + key_type_t type, identification_t *id, + auth_info_t *auth) +{ + enumerator_t *enumerator; + private_key_t *private; + public_key_t *public; + certificate_t *subject, *issuer, *candidate; + auth_info_t *cand_auth; + identification_t* keyid; + bool match = FALSE; + + /* check if this is a lookup by key ID, and do it if so */ + if (id) + { + switch (id->get_type(id)) + { + case ID_PUBKEY_SHA1: + case ID_PUBKEY_INFO_SHA1: + return get_private_by_keyid(this, type, id); + default: + break; + } + } + + this->mutex->lock(this->mutex); + /* Check if peer has included its trust anchors. + * If not we fall back to our trust anchors */ + if (!auth->get_item(auth, AUTHN_CA_CERT, (void**)&issuer)) + { + enumerator = create_cert_enumerator(this, CERT_ANY, type, NULL, TRUE); + while (enumerator->enumerate(enumerator, &issuer)) + { + auth->add_item(auth, AUTHN_CA_CERT, issuer); + } + enumerator->destroy(enumerator); + } + DBG2(DBG_CFG, "finding private key with certificate the peer trusts"); + + /* get all available end entity certificates for us... */ + enumerator = create_cert_enumerator(this, CERT_ANY, type, id, FALSE); + while (enumerator->enumerate(enumerator, &subject)) + { /* ... check for public ... */ + public = subject->get_public_key(subject); + if (public) + { /* ... and private keys for that certificate, ... */ + /* TODO: check other keyid types? */ + keyid = public->get_id(public, ID_PUBKEY_INFO_SHA1); + if (keyid) + { + private = get_private_by_keyid(this, type, keyid); + if (private) + { + u_int level = 0; + bool bad_path = FALSE; + issuer = NULL; + + match = TRUE; + DBG2(DBG_CFG, " checking end entity cert %D", + subject->get_subject(subject)); + cand_auth = auth_info_create(); + /* .. check for a trust-path up to a peer-trusted CA */ + candidate = subject->get_ref(subject); + while (!auth_contains_cacert(auth, candidate)) + { + cand_auth->add_item(cand_auth, subject == candidate ? + AUTHZ_SUBJECT_CERT : AUTHZ_IM_CERT, candidate); + issuer = get_issuer_cert(this, candidate); + /* check if we have an issuing certificate */ + if (!issuer) + { + DBG2(DBG_CFG, " no issuer, checking next cert"); + bad_path = TRUE; + break; + } + /* and it is not self-issued */ + if (issuer->equals(issuer, candidate) || + level > MAX_CA_LEVELS) + { + issuer->destroy(issuer); + issuer = NULL; + bad_path = TRUE; + DBG2(DBG_CFG, " cert is self-signed, skipped"); + break; + } + DBG2(DBG_CFG, " checking issuer cert %D", + issuer->get_subject(issuer)); + candidate->destroy(candidate); + candidate = issuer; + level++; + } + if (bad_path) + { /* no issuer cert found peer trusts, try another path */ + cand_auth->destroy(cand_auth); + private->destroy(private); + public->destroy(public); + continue; + } + if (issuer) + { + DBG2(DBG_CFG, " peer trusts issuer %D", + issuer->get_subject(issuer)); + } + else + { + candidate->destroy(candidate); + } + auth->merge(auth, cand_auth); + cand_auth->destroy(cand_auth); + DESTROY_IF(issuer); + public->destroy(public); + enumerator->destroy(enumerator); + this->mutex->unlock(this->mutex); + return private; + } + } + public->destroy(public); + } + } + this->mutex->unlock(this->mutex); + if (match) + { + DBG1(DBG_CFG, "found a private key/cert for %D, but none which the " + "peer trusts", id); + } + else + { + DBG1(DBG_CFG, "no private key found for %D", id); + } + /* no trusted path found, unable to sign */ + return NULL; +} + +/** + * Implementation of credential_manager_t.add_set. + */ +static void add_set(private_credential_manager_t *this, + credential_set_t *set) +{ + this->mutex->lock(this->mutex); + this->sets->insert_last(this->sets, set); + this->mutex->unlock(this->mutex); +} +/** + * Implementation of credential_manager_t.remove_set. + */ +static void remove_set(private_credential_manager_t *this, credential_set_t *set) +{ + this->mutex->lock(this->mutex); + this->sets->remove(this->sets, set, NULL); + this->mutex->unlock(this->mutex); +} + +/** + * Implementation of credential_manager_t.destroy + */ +static void destroy(private_credential_manager_t *this) +{ + this->sets->destroy(this->sets); + this->mutex->destroy(this->mutex); + free(this); +} + +/* + * see header file + */ +credential_manager_t *credential_manager_create() +{ + private_credential_manager_t *this = malloc_thing(private_credential_manager_t); + + this->public.create_cert_enumerator = (enumerator_t *(*)(credential_manager_t *this,certificate_type_t cert, key_type_t key,identification_t *id,bool))create_cert_enumerator; + this->public.create_shared_enumerator = (enumerator_t *(*)(credential_manager_t *this, shared_key_type_t type,identification_t *me, identification_t *other))create_shared_enumerator; + this->public.create_cdp_enumerator = (enumerator_t *(*)(credential_manager_t*, credential_type_t type, identification_t *id))create_cdp_enumerator; + this->public.get_cert = (certificate_t *(*)(credential_manager_t *this,certificate_type_t cert, key_type_t key,identification_t *, bool))get_cert; + this->public.get_shared = (shared_key_t *(*)(credential_manager_t *this,shared_key_type_t type,identification_t *me, identification_t *other))get_shared; + this->public.get_private = (private_key_t*(*)(credential_manager_t*, key_type_t type, identification_t *, auth_info_t*))get_private; + this->public.get_public = (public_key_t*(*)(credential_manager_t*, key_type_t type, identification_t *, auth_info_t*))get_public; + this->public.add_set = (void(*)(credential_manager_t*, credential_set_t *set))add_set; + this->public.remove_set = (void(*)(credential_manager_t*, credential_set_t *set))remove_set; + this->public.destroy = (void(*)(credential_manager_t*))destroy; + + this->sets = linked_list_create(); + this->mutex = mutex_create(MUTEX_RECURSIVE); + + return &this->public; +} + diff --git a/src/charon/credentials/credential_manager.h b/src/charon/credentials/credential_manager.h new file mode 100644 index 000000000..816b9028e --- /dev/null +++ b/src/charon/credentials/credential_manager.h @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2007-2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +/** + * @defgroup credential_manager credential_manager + * @{ @ingroup ccredentials + */ + +#ifndef CREDENTIAL_MANAGER_H_ +#define CREDENTIAL_MANAGER_H_ + +#include +#include +#include +#include +#include +#include +#include + +typedef struct credential_manager_t credential_manager_t; + +/** + * Manages credentials using credential_sets. + * + * The credential manager is the entry point of the credential framework. It + * uses so called "sets" to access credentials in a modular fashion, these + * are implemented through the credential_set_t interface. + * The manager additionally does trust chain verification and trust status + * chaching. A set may call the managers methods if it needs credentials itself, + * the manager uses recursive locking. + * + * @verbatim + + +-------+ +----------------+ + | A | | | +------------------+ + | u | -----> | | ------> | +------------------+ + | t | | credential- | | | +------------------+ + | h | -----> | manager | ------> +--| | credential- | => IPC + | e | | | +--| sets | + | n | +--> | | ------> +------------------+ + | t | | | | | + | i | | | | | + | c | | +----------------+ | + | a | | | + | t | +----------------------------------------------+ + | o | may be recursive + | r | + +-------+ + + @endverbatim + * + * Synchronization is done completely in the manager, so the sets don't have + * to worry about it. The locking mechanism is reentrant save, so sets can + * call the manager. + */ +struct credential_manager_t { + + /** + * Create an enumerator over all certificates. + * + * @param cert kind of certificate + * @param key kind of key in certificate + * @param id subject this certificate belongs to + * @param trusted TRUE to list trusted certificates only + * @return enumerator over the certificates + */ + enumerator_t *(*create_cert_enumerator)(credential_manager_t *this, + certificate_type_t cert, key_type_t key, + identification_t *id, bool trusted); + /** + * Create an enumerator over all shared keys. + * + * The enumerator enumerates over: + * shared_key_t*, id_match_t me, id_match_t other + * But must accepts values for the id_matches. + * + * @param type kind of requested shared key + * @param first first subject between key is shared + * @param second second subject between key is shared + * @return enumerator over shared keys + */ + enumerator_t *(*create_shared_enumerator)(credential_manager_t *this, + shared_key_type_t type, + identification_t *first, identification_t *second); + /** + * Create an enumerator over all Certificate Distribution Points. + * + * @param type kind of certificate the point distributes + * @param id identification of the distributed certificate + * @return enumerator of CDPs as char* + */ + enumerator_t *(*create_cdp_enumerator)(credential_manager_t *this, + credential_type_t type, identification_t *id); + /** + * Get a trusted or untrusted certificate. + * + * @param cert kind of certificate + * @param key kind of key in certificate + * @param id subject this certificate belongs to + * @param trusted TRUE to get a trusted certificate only + * @return certificate, if found, NULL otherwise + */ + certificate_t *(*get_cert)(credential_manager_t *this, + certificate_type_t cert, key_type_t key, + identification_t *id, bool trusted); + /** + * Get the best matching shared key for two IDs. + * + * @param type kind of requested shared key + * @param me own identity + * @param other peers identity + * @param auth auth_info helper + * @return shared_key_t, NULL if none found + */ + shared_key_t *(*get_shared)(credential_manager_t *this, shared_key_type_t type, + identification_t *me, identification_t *other); + /** + * Get a private key to create a signature. + * + * The get_private() method gets a secret private key identified by either + * the keyid itself or an id the key belongs to. + * The auth parameter contains additional information, such as receipients + * trusted CA certs. Auth gets filled with subject and CA certificates + * needed to validate a created signature. + * + * @param type type of the key to get + * @param id identification the key belongs to + * @param auth auth_info helper, including trusted CA certificates + * @return private_key_t, NULL if none found + */ + private_key_t* (*get_private)(credential_manager_t *this, key_type_t type, + identification_t *id, auth_info_t *auth); + /** + * Get a public key to verify a signature. + * + * The get_public() method gets a trusted public key to verify a signature + * of id. The auth parameter contains additional authentication infos, + * e.g. peer and intermediate certificates. + * + * @param type type of key to get + * @param id identification the key belongs to + * @param auth auth_info helper, including certificates to verify key + * @return public_key_t, NULL if none found + */ + public_key_t* (*get_public)(credential_manager_t *this, key_type_t type, + identification_t *id, auth_info_t *auth); + + /** + * Register a credential set to the manager. + * + * @param set set to register + */ + void (*add_set)(credential_manager_t *this, credential_set_t *set); + + /** + * Unregister a credential set from the manager. + * + * @param set set to unregister + */ + void (*remove_set)(credential_manager_t *this, credential_set_t *set); + + /** + * Destroy a credential_manager instance. + */ + void (*destroy)(credential_manager_t *this); +}; + +/** + * Create a credential_manager instance. + */ +credential_manager_t *credential_manager_create(); + +#endif /* CREDENTIAL_MANAGER_H_ @} */ diff --git a/src/charon/credentials/credential_set.h b/src/charon/credentials/credential_set.h new file mode 100644 index 000000000..a4e891a84 --- /dev/null +++ b/src/charon/credentials/credential_set.h @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +/** + * @defgroup credential_set credential_set + * @{ @ingroup ccredentials + */ + +#ifndef CREDENTIAL_SET_H_ +#define CREDENTIAL_SET_H_ + +#include +#include +#include + +typedef struct credential_set_t credential_set_t; + +/** + * A set of credentials. + * + * Contains private keys, shared keys and different kinds of certificates. + * Enumerators are used because queries might return multiple matches. + * Filter parameters restrict enumeration over specific items only. + * See credential_manager_t for an overview of the credential framework. + */ +struct credential_set_t { + + /** + * Create an enumerator over private keys (private_key_t). + * + * The id is either a key identifier of the requested key, or an identity + * of the key owner. + * + * @param type type of requested private key + * @param id key identifier/owner + * @return enumerator over private_key_t's. + */ + enumerator_t *(*create_private_enumerator)(credential_set_t *this, + key_type_t type, identification_t *id); + /** + * Create an enumerator over certificates (certificate_t). + * + * @param cert kind of certificate + * @param key kind of key in certificate + * @param id identity (subject) this certificate belongs to + * @param trusted whether the certificate must be trustworthy + * @return enumerator as described above + */ + enumerator_t *(*create_cert_enumerator)(credential_set_t *this, + certificate_type_t cert, key_type_t key, + identification_t *id, bool trusted); + /** + * Create an enumerator over shared keys (shared_key_t). + * + * The enumerator enumerates over: + * shared_key_t*, id_match_t me, id_match_t other + * But must accept NULL values for the id_matches. + * + * @param type kind of requested shared key + * @param me own identity + * @param other other identity who owns that secret + * @return enumerator as described above + */ + enumerator_t *(*create_shared_enumerator)(credential_set_t *this, + shared_key_type_t type, + identification_t *me, identification_t *other); + + /** + * Create an enumerator over certificate distribution points. + * + * @param type type of the certificate to get a CDP + * @param id identification of the distributed certificate + * @return an enumerator over CDPs as char* + */ + enumerator_t *(*create_cdp_enumerator)(credential_set_t *this, + certificate_type_t type, identification_t *id); +}; + +#endif /* CREDENTIAL_SET_H_ @} */ diff --git a/src/charon/daemon.c b/src/charon/daemon.c index ee9710424..122c5cfcc 100644 --- a/src/charon/daemon.c +++ b/src/charon/daemon.c @@ -1,13 +1,7 @@ -/** - * @file daemon.c - * - * @brief Implementation of daemon_t and main of IKEv2-Daemon. - * - */ - -/* Copyright (C) 2006-2007 Tobias Brunner +/* + * Copyright (C) 2006-2007 Tobias Brunner * Copyright (C) 2006 Daniel Roethlisberger - * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005-2008 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil * @@ -41,11 +35,9 @@ #include "daemon.h" #include -#include -#include -#include -#include -#include +#include +#include +#include /* on some distros, a capset definition is missing */ #ifdef NO_CAPSET_DEFINED @@ -100,6 +92,12 @@ static void dbg_bus(int level, char *fmt, ...) charon->bus->vsignal(charon->bus, DBG_LIB, level, fmt, args); va_end(args); } +/** + * Logging hook for library logs before logging facility initiated + */ +static void dbg_silent(int level, char *fmt, ...) +{ +} /** * Logging hook for library logs, using stderr output @@ -171,12 +169,17 @@ static void run(private_daemon_t *this) static void destroy(private_daemon_t *this) { /* terminate all idle threads */ - this->public.processor->set_threads(this->public.processor, 0); + if (this->public.processor) + { + this->public.processor->set_threads(this->public.processor, 0); + } /* close all IKE_SAs */ + DESTROY_IF(this->public.plugins); DESTROY_IF(this->public.ike_sa_manager); DESTROY_IF(this->public.kernel_interface); DESTROY_IF(this->public.scheduler); - DESTROY_IF(this->public.interfaces); + DESTROY_IF(this->public.controller); + DESTROY_IF(this->public.eap); #ifdef P2P DESTROY_IF(this->public.connect_manager); DESTROY_IF(this->public.mediation_manager); @@ -323,29 +326,38 @@ static bool initialize(private_daemon_t *this, bool syslog, level_t levels[]) #endif /* INTEGRITY_TEST */ this->public.ike_sa_manager = ike_sa_manager_create(); + if (this->public.ike_sa_manager == NULL) + { + return FALSE; + } this->public.processor = processor_create(); this->public.scheduler = scheduler_create(); /* load secrets, ca certificates and crls */ - this->public.credentials = (credential_store_t*)local_credential_store_create(); - this->public.credentials->load_ca_certificates(this->public.credentials); - this->public.credentials->load_aa_certificates(this->public.credentials); - this->public.credentials->load_attr_certificates(this->public.credentials); - this->public.credentials->load_ocsp_certificates(this->public.credentials); - this->public.credentials->load_crls(this->public.credentials); - this->public.credentials->load_secrets(this->public.credentials, FALSE); - - this->public.interfaces = interface_manager_create(); + this->public.credentials = credential_manager_create(); + this->public.controller = controller_create(); + this->public.eap = eap_manager_create(); this->public.backends = backend_manager_create(); + this->public.plugins = plugin_loader_create(); this->public.kernel_interface = kernel_interface_create(); this->public.socket = socket_create(); this->public.sender = sender_create(); this->public.receiver = receiver_create(); + if (this->public.receiver == NULL) + { + return FALSE; + } #ifdef P2P this->public.connect_manager = connect_manager_create(); + if (this->public.connect_manager == NULL) + { + return FALSE; + } this->public.mediation_manager = mediation_manager_create(); #endif /* P2P */ + + this->public.plugins->load(this->public.plugins, IPSEC_PLUGINDIR, "libcharon-"); return TRUE; } @@ -401,7 +413,9 @@ private_daemon_t *daemon_create(void) this->public.scheduler = NULL; this->public.kernel_interface = NULL; this->public.processor = NULL; - this->public.interfaces = NULL; + this->public.controller = NULL; + this->public.eap = NULL; + this->public.plugins = NULL; this->public.bus = NULL; this->public.outlog = NULL; this->public.syslog = NULL; @@ -443,7 +457,6 @@ static void usage(const char *msg) " [--strictcrlpolicy]\n" " [--cachecrls]\n" " [--crlcheckinterval ]\n" - " [--eapdir ]\n" " [--use-syslog]\n" " [--debug- ]\n" " : log context type (dmn|mgr|ike|chd|job|cfg|knl|net|enc|lib)\n" @@ -460,10 +473,8 @@ static void usage(const char *msg) int main(int argc, char *argv[]) { u_int crl_check_interval = 0; - strict_t strict_crl_policy = STRICT_NO; bool cache_crls = FALSE; bool use_syslog = FALSE; - char *eapdir = IPSEC_EAPDIR; private_daemon_t *private_charon; FILE *pid_file; @@ -471,6 +482,14 @@ int main(int argc, char *argv[]) level_t levels[DBG_MAX]; int signal; + /* silence the library during initialization, as we have no bus yet */ + dbg = dbg_silent; + + /* initialize library */ + library_init(IPSEC_DIR "/strongswan.conf"); + lib->plugins->load(lib->plugins, IPSEC_PLUGINDIR, "libstrongswan-"); + lib->printf_hook->add_handler(lib->printf_hook, 'R', + traffic_selector_get_printf_hooks()); private_charon = daemon_create(); charon = (daemon_t*)private_charon; @@ -491,10 +510,8 @@ int main(int argc, char *argv[]) { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'v' }, { "use-syslog", no_argument, NULL, 'l' }, - { "strictcrlpolicy", required_argument, NULL, 'r' }, { "cachecrls", no_argument, NULL, 'C' }, { "crlcheckinterval", required_argument, NULL, 'x' }, - { "eapdir", required_argument, NULL, 'e' }, /* TODO: handle "debug-all" */ { "debug-dmn", required_argument, &signal, DBG_DMN }, { "debug-mgr", required_argument, &signal, DBG_MGR }, @@ -523,18 +540,12 @@ int main(int argc, char *argv[]) case 'l': use_syslog = TRUE; continue; - case 'r': - strict_crl_policy = atoi(optarg); - continue; case 'C': cache_crls = TRUE; continue; case 'x': crl_check_interval = atoi(optarg); continue; - case 'e': - eapdir = optarg; - continue; case 0: /* option is in signal */ levels[signal] = atoi(optarg); @@ -554,14 +565,6 @@ int main(int argc, char *argv[]) exit(-1); } - /* initialize fetcher_t class */ - fetcher_initialize(); - /* load pluggable EAP modules */ - eap_method_load(eapdir); - - /* set strict_crl_policy, cache_crls and crl_check_interval options */ - ca_info_set_options(strict_crl_policy, cache_crls, crl_check_interval); - /* check/setup PID file */ if (stat(PID_FILE, &stb) == 0) { @@ -586,12 +589,12 @@ int main(int argc, char *argv[]) /* run daemon */ run(private_charon); - eap_method_unload(); - fetcher_finalize(); /* normal termination, cleanup and exit */ destroy(private_charon); unlink(PID_FILE); + library_deinit(); + return 0; } diff --git a/src/charon/daemon.h b/src/charon/daemon.h index 33c63091d..d989c0bba 100644 --- a/src/charon/daemon.h +++ b/src/charon/daemon.h @@ -1,14 +1,7 @@ -/** - * @file daemon.h - * - * @brief Interface of daemon_t. - * - */ - /* * Copyright (C) 2006-2007 Tobias Brunner * Copyright (C) 2006 Daniel Roethlisberger - * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005-2008 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil * @@ -21,345 +14,183 @@ * 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. + * + * $Id$ */ -#ifndef DAEMON_H_ -#define DAEMON_H_ - -typedef struct daemon_t daemon_t; - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef P2P -#include -#include -#endif /* P2P */ - /** * @defgroup charon charon * - * @brief IKEv2 keying daemon. - * - * All IKEv2 stuff is handled in charon. It uses a newer and more flexible - * architecture than pluto. Charon uses a thread-pool (called processor), - * which allows parallel execution SA-management. All threads originate - * from the processor. Work is delegated to the processor by queueing jobs - * to it. - @verbatim - - +--------+ +-------+ +--------+ +-----------+ +-----------+ - | Stroke | | XML | | DBUS | | Local | | SQLite | - +--------+ +-------+ +--------+ +-----------+ +-----------+ - | | | | | - +---------------------------------+ +----------------------------+ - | Interfaces | | Backends | - +---------------------------------+ +----------------------------+ - - - +------------+ +-----------+ +------+ +----------+ - | receiver | | | | | +------+ | CHILD_SA | - +----+-------+ | Scheduler | | IKE- | | IKE- |--+----------+ - | | | | SA |--| SA | | CHILD_SA | - +-------+--+ +-----------+ | | +------+ +----------+ - <->| socket | | | Man- | - +-------+--+ +-----------+ | ager | +------+ +----------+ - | | | | | | IKE- |--| CHILD_SA | - +----+-------+ | Processor |--------| |--| SA | +----------+ - | sender | | | | | +------+ - +------------+ +-----------+ +------+ - - - +---------------------------------+ +----------------------------+ - | Bus | | Kernel Interface | - +---------------------------------+ +----------------------------+ - | | | - +-------------+ +-------------+ V - | File-Logger | | Sys-Logger | ////// - +-------------+ +-------------+ - - - @endverbatim - * The scheduler is responsible to execute timed events. Jobs may be queued to - * the scheduler to get executed at a defined time (e.g. rekeying). The scheduler - * does not execute the jobs itself, it queues them to the processor. - * - * The IKE_SA manager managers all IKE_SA. It further handles the synchronization: - * Each IKE_SA must be checked out strictly and checked in again after use. The - * manager guarantees that only one thread may check out a single IKE_SA. This allows - * us to write the (complex) IKE_SAs routines non-threadsave. - * The IKE_SA contain the state and the logic of each IKE_SA and handle the messages. - * - * The CHILD_SA contains state about a IPsec security association and manages them. - * An IKE_SA may have multiple CHILD_SAs. Communication to the kernel takes place - * here through the kernel interface. - * - * The kernel interface installs IPsec security associations, policies routes and - * virtual addresses. It further provides methods to enumerate interfaces and may notify - * the daemon about state changes at lower layers. - * - * The bus receives signals from the different threads and relais them to interested - * listeners. Debugging signals, but also important state changes or error messages are - * sent over the bus. - * It's listeners are not only for logging, but also to track the state of an IKE_SA. - * - * The interface manager loads pluggable controlling interfaces. These are written to control - * the daemon from external inputs (e.g. initiate IKE_SA, close IKE_SA, ...). The interface - * manager further provides a simple API to establish these tasks. - * Backends are pluggable modules which provide configuration. They have to implement an API - * which the daemon core uses to get configuration. - */ - -/** * @defgroup bus bus - * - * Signaling bus and its listeners. - * * @ingroup charon - */ - -/** - * @defgroup config config - * - * Classes implementing configuration related things. + * + * @defgroup listeners listeners + * @ingroup bus * + * @defgroup config config * @ingroup charon - */ - -/** - * @defgroup backends backends - * - * Classes implementing configuration backends. - * - * @ingroup config - */ - -/** - * @defgroup credentials credentials - * - * Trust chain verification and certificate store. * - * @ingroup config - */ - -/** * @defgroup control control - * - * Handling of loadable control interface modules. - * * @ingroup charon - */ - -/** - * @defgroup interfaces interfaces * - * Classes which control the daemon using IPC mechanisms. + * @defgroup ccredentials credentials + * @ingroup charon * - * @ingroup control - */ - -/** * @defgroup encoding encoding - * - * Classes used to encode and decode IKEv2 messages. - * * @ingroup charon - */ - - /** - * @defgroup payloads payloads - * - * Classes representing specific IKEv2 payloads. * + * @defgroup payloads payloads * @ingroup encoding - */ - -/** - * @defgroup kernel kernel - * - * Classes to configure and query the kernel. * + * @defgroup kernel kernel * @ingroup charon - */ - -/** - * @defgroup network network - * - * Classes for sending and receiving UDP packets over the network. * + * @defgroup network network * @ingroup charon - */ - -/** - * @defgroup processing processing - * - * Queueing, scheduling and processing of jobs * + * @defgroup cplugins plugins * @ingroup charon - */ - -/** - * @defgroup jobs jobs * - * Jobs to queue, schedule and process. + * @defgroup processing processing + * @ingroup charon * + * @defgroup jobs jobs * @ingroup processing - */ - -/** - * @defgroup sa sa - * - * Security associations for IKE and IPSec, and its helper classes. * + * @defgroup sa sa * @ingroup charon - */ - -/** + * * @defgroup authenticators authenticators + * @ingroup sa * - * Authenticator classes to prove identity of a peer. + * @defgroup eap eap + * @ingroup authenticators * + * @defgroup tasks tasks * @ingroup sa - */ - -/** - * @defgroup eap eap * - * EAP module loader, interface and it's implementations. + * @addtogroup charon + * @{ * - * @ingroup authenticators - */ - -/** - * @defgroup tasks tasks + * IKEv2 keying daemon. * - * Tasks process and build message payloads. They are used to create - * and process multiple exchanges. + * All IKEv2 stuff is handled in charon. It uses a newer and more flexible + * architecture than pluto. Charon uses a thread-pool (called processor), + * which allows parallel execution SA-management. All threads originate + * from the processor. Work is delegated to the processor by queueing jobs + * to it. + @verbatim + + +---------------------------------+ +----------------------------+ + | controller | | config | + +---------------------------------+ +----------------------------+ + | | | ^ ^ ^ + V V V | | | + + +----------+ +-----------+ +------+ +----------+ +----+ + | receiver | | | | | +------+ | CHILD_SA | | K | + +---+------+ | Scheduler | | IKE- | | IKE- |--+----------+ | e | + | | | | SA |--| SA | | CHILD_SA | | r | + +------+---+ +-----------+ | | +------+ +----------+ | n | + <->| socket | | | Man- | | e | + +------+---+ +-----------+ | ager | +------+ +----------+ | l | + | | | | | | IKE- |--| CHILD_SA | | - | + +---+------+ | Processor |---| |--| SA | +----------+ | I | + | sender | | | | | +------+ | f | + +----------+ +-----------+ +------+ +----+ + + | | | | | | + V V V V V V + +---------------------------------+ +----------------------------+ + | Bus | | credentials | + +---------------------------------+ +----------------------------+ + + @endverbatim + * The scheduler is responsible to execute timed events. Jobs may be queued to + * the scheduler to get executed at a defined time (e.g. rekeying). The + * scheduler does not execute the jobs itself, it queues them to the processor. + * + * The IKE_SA manager managers all IKE_SA. It further handles the + * synchronization: + * Each IKE_SA must be checked out strictly and checked in again after use. The + * manager guarantees that only one thread may check out a single IKE_SA. This + * allows us to write the (complex) IKE_SAs routines non-threadsave. + * The IKE_SA contain the state and the logic of each IKE_SA and handle the + * messages. + * + * The CHILD_SA contains state about a IPsec security association and manages + * them. An IKE_SA may have multiple CHILD_SAs. Communication to the kernel + * takes place here through the kernel interface. + * + * The kernel interface installs IPsec security associations, policies, routes + * and virtual addresses. It further provides methods to enumerate interfaces + * and may notify the daemon about state changes at lower layers. + * + * The bus receives signals from the different threads and relais them to interested + * listeners. Debugging signals, but also important state changes or error + * messages are sent over the bus. + * It's listeners are not only for logging, but also to track the state of an + * IKE_SA. * - * @ingroup sa + * The controller, credential_manager, bus and backend_manager (config) are + * places where a plugin ca register itself to privide information or observe + * and control the daemon. */ +#ifndef DAEMON_H_ +#define DAEMON_H_ + +typedef struct daemon_t daemon_t; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef P2P +#include +#include +#endif /* P2P */ + /** * Name of the daemon. - * - * @ingroup charon */ #define DAEMON_NAME "charon" /** - * @brief Number of threads in the thread pool. - * - * @ingroup charon + * Number of threads in the thread pool. */ #define WORKER_THREADS 16 /** * UDP Port on which the daemon will listen for incoming traffic. - * - * @ingroup charon */ #define IKEV2_UDP_PORT 500 /** * UDP Port to which the daemon will float to if NAT is detected. - * - * @ingroup charon */ #define IKEV2_NATT_PORT 4500 /** * PID file, in which charon stores its process id - * - * @ingroup charon */ #define PID_FILE IPSEC_PIDDIR "/charon.pid" -/** - * Configuration directory - * - * @ingroup charon - */ -#define CONFIG_DIR IPSEC_CONFDIR - -/** - * Directory of IPsec relevant files - * - * @ingroup charon - */ -#define IPSEC_D_DIR CONFIG_DIR "/ipsec.d" /** - * Default directory for private keys - * - * @ingroup charon - */ -#define PRIVATE_KEY_DIR IPSEC_D_DIR "/private" - -/** - * Default directory for end entity certificates - * - * @ingroup charon - */ -#define CERTIFICATE_DIR IPSEC_D_DIR "/certs" - -/** - * Default directory for trusted Certification Authority certificates - * - * @ingroup charon - */ -#define CA_CERTIFICATE_DIR IPSEC_D_DIR "/cacerts" - -/** - * Default directory for Authorization Authority certificates - * - * @ingroup charon - */ -#define AA_CERTIFICATE_DIR IPSEC_D_DIR "/aacerts" - -/** - * Default directory for Attribute certificates - * - * @ingroup charon - */ -#define ATTR_CERTIFICATE_DIR IPSEC_D_DIR "/acerts" - -/** - * Default directory for OCSP signing certificates - * - * @ingroup charon - */ -#define OCSP_CERTIFICATE_DIR IPSEC_D_DIR "/ocspcerts" - -/** - * Default directory for CRLs - * - * @ingroup charon - */ -#define CRL_DIR IPSEC_D_DIR "/crls" - -/** - * Secrets files - * - * @ingroup charon - */ -#define SECRETS_FILE CONFIG_DIR "/ipsec.secrets" - -/** - * @brief Main class of daemon, contains some globals. - * - * @ingroup charon + * Main class of daemon, contains some globals. */ struct daemon_t { @@ -379,9 +210,9 @@ struct daemon_t { backend_manager_t *backends; /** - * A credential_store_t instance. + * Manager for the credential backends */ - credential_store_t *credentials; + credential_manager_t *credentials; /** * The Sender-Thread. @@ -408,6 +239,11 @@ struct daemon_t { */ bus_t *bus; + /** + * plugin loader + */ + plugin_loader_t *plugins; + /** * A bus listener logging to stdout */ @@ -429,9 +265,14 @@ struct daemon_t { kernel_interface_t *kernel_interface; /** - * Interfaces for IPC + * Controller to control the daemon + */ + controller_t *controller; + + /** + * EAP manager to maintain registered EAP methods */ - interface_manager_t *interfaces; + eap_manager_t *eap; #ifdef P2P /** @@ -446,9 +287,8 @@ struct daemon_t { #endif /* P2P */ /** - * @brief Shut down the daemon. + * Shut down the daemon. * - * @param this the daemon to kill * @param reason describtion why it will be killed */ void (*kill) (daemon_t *this, char *reason); @@ -459,4 +299,4 @@ struct daemon_t { */ extern daemon_t *charon; -#endif /*DAEMON_H_*/ +#endif /*DAEMON_H_ @} */ diff --git a/src/charon/encoding/generator.c b/src/charon/encoding/generator.c index efa845bb3..79aedc259 100644 --- a/src/charon/encoding/generator.c +++ b/src/charon/encoding/generator.c @@ -1,10 +1,3 @@ -/** - * @file generator.c - * - * @brief Implementation of generator_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,8 @@ * 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. + * + * $Id$ */ #include diff --git a/src/charon/encoding/generator.h b/src/charon/encoding/generator.h index 8eff957cc..5cc710070 100644 --- a/src/charon/encoding/generator.h +++ b/src/charon/encoding/generator.h @@ -1,10 +1,3 @@ -/** - * @file generator.h - * - * @brief Interface of generator_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup generator generator + * @{ @ingroup encoding */ #ifndef GENERATOR_H_ @@ -33,21 +33,17 @@ typedef struct generator_t generator_t; /** * Generating is done in a data buffer. * This is thehe start size of this buffer in bytes. - * - * @ingroup enconding */ #define GENERATOR_DATA_BUFFER_SIZE 500 /** * Number of bytes to increase the buffer, if it is to small. - * - * @ingroup enconding */ #define GENERATOR_DATA_BUFFER_INCREASE_VALUE 500 /** - * @brief A generator_t class used to generate IKEv2 payloads. + * A generator_t class used to generate IKEv2 payloads. * * After creation, multiple payloads can be generated with the generate_payload * method. The generated bytes are appended. After all payloads are added, @@ -56,47 +52,36 @@ typedef struct generator_t generator_t; * The generater uses a set of encoding rules, which it can get from * the supplied payload. With this rules, the generater can generate * the payload and all substructures automatically. - * - * @b Constructor: - * - generator_create() - * - * @ingroup encoding */ struct generator_t { /** - * @brief Generates a specific payload from given payload object. + * Generates a specific payload from given payload object. * * Remember: Header and substructures are also handled as payloads. * - * @param this generator_t object - * @param[in] payload interface payload_t implementing object + * @param payload interface payload_t implementing object */ void (*generate_payload) (generator_t *this,payload_t *payload); /** - * @brief Writes all generated data of the generator to a chunk. + * Writes all generated data of the generator to a chunk. * - * @param this generator_t object - * @param[out] data chunk to write the data to + * @param data chunk to write the data to */ void (*write_to_chunk) (generator_t *this,chunk_t *data); /** - * @brief Destroys a generator_t object. - * - * @param this generator_t object + * Destroys a generator_t object. */ void (*destroy) (generator_t *this); }; /** - * @brief Constructor to create a generator. + * Constructor to create a generator. * * @return generator_t object. - * - * @ingroup encoding */ generator_t *generator_create(void); -#endif /*GENERATOR_H_*/ +#endif /*GENERATOR_H_ @} */ diff --git a/src/charon/encoding/message.c b/src/charon/encoding/message.c index 3dfa64fb9..0568b42e5 100644 --- a/src/charon/encoding/message.c +++ b/src/charon/encoding/message.c @@ -1,10 +1,3 @@ -/** - * @file message.c - * - * @brief Implementation of message_t. - * - */ - /* * Copyright (C) 2006-2007 Tobias Brunner * Copyright (C) 2006 Daniel Roethlisberger @@ -21,6 +14,8 @@ * 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. + * + * $Id$ */ #include @@ -82,13 +77,31 @@ struct payload_rule_t { bool sufficient; }; +typedef struct payload_order_t payload_order_t; + +/** + * payload ordering structure allows us to reorder payloads according to RFC. + */ +struct payload_order_t { + + /** + * payload type + */ + payload_type_t type; + + /** + * notify type, if payload == NOTIFY + */ + notify_type_t notify; +}; + + typedef struct message_rule_t message_rule_t; /** * A message rule defines the kind of a message, * if it has encrypted contents and a list - * of payload rules. - * + * of payload ordering rules and payload parsing rules. */ struct message_rule_t { /** @@ -109,124 +122,276 @@ struct message_rule_t { /** * Number of payload rules which will follow */ - size_t payload_rule_count; + int payload_rule_count; /** * Pointer to first payload rule */ payload_rule_t *payload_rules; + + /** + * Number of payload order rules + */ + int payload_order_count; + + /** + * payload ordering rules + */ + payload_order_t *payload_order; }; /** * Message rule for IKE_SA_INIT from initiator. */ static payload_rule_t ike_sa_init_i_payload_rules[] = { - {NOTIFY,0,MAX_NOTIFY_PAYLOADS,FALSE,FALSE}, - {SECURITY_ASSOCIATION,1,1,FALSE,FALSE}, - {KEY_EXCHANGE,1,1,FALSE,FALSE}, - {NONCE,1,1,FALSE,FALSE}, - {VENDOR_ID,0,10,FALSE,FALSE}, +/* payload type min max encr suff */ + {NOTIFY, 0, MAX_NOTIFY_PAYLOADS, FALSE, FALSE}, + {SECURITY_ASSOCIATION, 1, 1, FALSE, FALSE}, + {KEY_EXCHANGE, 1, 1, FALSE, FALSE}, + {NONCE, 1, 1, FALSE, FALSE}, + {VENDOR_ID, 0, 10, FALSE, FALSE}, +}; + +/** + * payload order for IKE_SA_INIT initiator + */ +static payload_order_t ike_sa_init_i_payload_order[] = { +/* payload type notify type */ + {NOTIFY, COOKIE}, + {SECURITY_ASSOCIATION, 0}, + {KEY_EXCHANGE, 0}, + {NONCE, 0}, + {NOTIFY, NAT_DETECTION_SOURCE_IP}, + {NOTIFY, NAT_DETECTION_DESTINATION_IP}, + {VENDOR_ID, 0}, }; /** * Message rule for IKE_SA_INIT from responder. */ static payload_rule_t ike_sa_init_r_payload_rules[] = { - {NOTIFY,0,MAX_NOTIFY_PAYLOADS,FALSE,TRUE}, - {SECURITY_ASSOCIATION,1,1,FALSE,FALSE}, - {KEY_EXCHANGE,1,1,FALSE,FALSE}, - {NONCE,1,1,FALSE,FALSE}, - {VENDOR_ID,0,10,FALSE,FALSE}, +/* payload type min max encr suff */ + {NOTIFY, 0, MAX_NOTIFY_PAYLOADS, FALSE, TRUE}, + {SECURITY_ASSOCIATION, 1, 1, FALSE, FALSE}, + {KEY_EXCHANGE, 1, 1, FALSE, FALSE}, + {NONCE, 1, 1, FALSE, FALSE}, + {VENDOR_ID, 0, 10, FALSE, FALSE}, +}; + +/** + * payload order for IKE_SA_INIT responder + */ +static payload_order_t ike_sa_init_r_payload_order[] = { +/* payload type notify type */ + {SECURITY_ASSOCIATION, 0}, + {KEY_EXCHANGE, 0}, + {NONCE, 0}, + {NOTIFY, NAT_DETECTION_SOURCE_IP}, + {NOTIFY, NAT_DETECTION_DESTINATION_IP}, + {NOTIFY, HTTP_CERT_LOOKUP_SUPPORTED}, + {CERTIFICATE_REQUEST, 0}, + {VENDOR_ID, 0}, }; /** * Message rule for IKE_AUTH from initiator. */ static payload_rule_t ike_auth_i_payload_rules[] = { - {NOTIFY,0,MAX_NOTIFY_PAYLOADS,TRUE,FALSE}, - {EXTENSIBLE_AUTHENTICATION,0,1,TRUE,TRUE}, - {AUTHENTICATION,0,1,TRUE,TRUE}, - {ID_INITIATOR,1,1,TRUE,FALSE}, - {CERTIFICATE,0,1,TRUE,FALSE}, - {CERTIFICATE_REQUEST,0,1,TRUE,FALSE}, - {ID_RESPONDER,0,1,TRUE,FALSE}, +/* payload type min max encr suff */ + {NOTIFY, 0, MAX_NOTIFY_PAYLOADS, TRUE, FALSE}, + {EXTENSIBLE_AUTHENTICATION, 0, 1, TRUE, TRUE}, + {AUTHENTICATION, 0, 1, TRUE, TRUE}, + {ID_INITIATOR, 1, 1, TRUE, FALSE}, + {CERTIFICATE, 0, 4, TRUE, FALSE}, + {CERTIFICATE_REQUEST, 0, 1, TRUE, FALSE}, + {ID_RESPONDER, 0, 1, TRUE, FALSE}, #ifdef P2P - {SECURITY_ASSOCIATION,0,1,TRUE,FALSE}, - {TRAFFIC_SELECTOR_INITIATOR,0,1,TRUE,FALSE}, - {TRAFFIC_SELECTOR_RESPONDER,0,1,TRUE,FALSE}, + {SECURITY_ASSOCIATION, 0, 1, TRUE, FALSE}, + {TRAFFIC_SELECTOR_INITIATOR, 0, 1, TRUE, FALSE}, + {TRAFFIC_SELECTOR_RESPONDER, 0, 1, TRUE, FALSE}, #else - {SECURITY_ASSOCIATION,1,1,TRUE,FALSE}, - {TRAFFIC_SELECTOR_INITIATOR,1,1,TRUE,FALSE}, - {TRAFFIC_SELECTOR_RESPONDER,1,1,TRUE,FALSE}, + {SECURITY_ASSOCIATION, 1, 1, TRUE, FALSE}, + {TRAFFIC_SELECTOR_INITIATOR, 1, 1, TRUE, FALSE}, + {TRAFFIC_SELECTOR_RESPONDER, 1, 1, TRUE, FALSE}, #endif /* P2P */ - {CONFIGURATION,0,1,TRUE,FALSE}, - {VENDOR_ID,0,10,TRUE,FALSE}, + {CONFIGURATION, 0, 1, TRUE, FALSE}, + {VENDOR_ID, 0, 10, TRUE, FALSE}, +}; + +/** + * payload order for IKE_AUTH initiator + */ +static payload_order_t ike_auth_i_payload_order[] = { +/* payload type notify type */ + {ID_INITIATOR, 0}, + {CERTIFICATE, 0}, + {NOTIFY, INITIAL_CONTACT}, + {NOTIFY, HTTP_CERT_LOOKUP_SUPPORTED}, + {CERTIFICATE_REQUEST, 0}, + {ID_RESPONDER, 0}, + {AUTHENTICATION, 0}, + {EXTENSIBLE_AUTHENTICATION, 0}, + {CONFIGURATION, 0}, + {NOTIFY, IPCOMP_SUPPORTED}, + {NOTIFY, USE_TRANSPORT_MODE}, + {NOTIFY, ESP_TFC_PADDING_NOT_SUPPORTED}, + {NOTIFY, NON_FIRST_FRAGMENTS_ALSO}, + {SECURITY_ASSOCIATION, 0}, + {TRAFFIC_SELECTOR_INITIATOR, 0}, + {TRAFFIC_SELECTOR_RESPONDER, 0}, + {NOTIFY, MOBIKE_SUPPORTED}, + {NOTIFY, ADDITIONAL_IP4_ADDRESS}, + {NOTIFY, ADDITIONAL_IP6_ADDRESS}, + {NOTIFY, NO_ADDITIONAL_ADDRESSES}, + {VENDOR_ID, 0}, }; /** * Message rule for IKE_AUTH from responder. */ static payload_rule_t ike_auth_r_payload_rules[] = { - {NOTIFY,0,MAX_NOTIFY_PAYLOADS,TRUE,TRUE}, - {EXTENSIBLE_AUTHENTICATION,0,1,TRUE,TRUE}, - {CERTIFICATE,0,1,TRUE,FALSE}, - {ID_RESPONDER,0,1,TRUE,FALSE}, - {AUTHENTICATION,0,1,TRUE,FALSE}, - {SECURITY_ASSOCIATION,0,1,TRUE,FALSE}, - {TRAFFIC_SELECTOR_INITIATOR,0,1,TRUE,FALSE}, - {TRAFFIC_SELECTOR_RESPONDER,0,1,TRUE,FALSE}, - {CONFIGURATION,0,1,TRUE,FALSE}, - {VENDOR_ID,0,10,TRUE,FALSE}, +/* payload type min max encr suff */ + {NOTIFY, 0, MAX_NOTIFY_PAYLOADS, TRUE, TRUE}, + {EXTENSIBLE_AUTHENTICATION, 0, 1, TRUE, TRUE}, + {CERTIFICATE, 0, 4, TRUE, FALSE}, + {ID_RESPONDER, 0, 1, TRUE, FALSE}, + {AUTHENTICATION, 0, 1, TRUE, FALSE}, + {SECURITY_ASSOCIATION, 0, 1, TRUE, FALSE}, + {TRAFFIC_SELECTOR_INITIATOR, 0, 1, TRUE, FALSE}, + {TRAFFIC_SELECTOR_RESPONDER, 0, 1, TRUE, FALSE}, + {CONFIGURATION, 0, 1, TRUE, FALSE}, + {VENDOR_ID, 0, 10, TRUE, FALSE}, }; +/** + * payload order for IKE_AUTH responder + */ +static payload_order_t ike_auth_r_payload_order[] = { +/* payload type notify type */ + {ID_RESPONDER, 0}, + {CERTIFICATE, 0}, + {AUTHENTICATION, 0}, + {EXTENSIBLE_AUTHENTICATION, 0}, + {CONFIGURATION, 0}, + {NOTIFY, IPCOMP_SUPPORTED}, + {NOTIFY, USE_TRANSPORT_MODE}, + {NOTIFY, ESP_TFC_PADDING_NOT_SUPPORTED}, + {NOTIFY, NON_FIRST_FRAGMENTS_ALSO}, + {SECURITY_ASSOCIATION, 0}, + {TRAFFIC_SELECTOR_INITIATOR, 0}, + {TRAFFIC_SELECTOR_RESPONDER, 0}, + {NOTIFY, AUTH_LIFETIME}, + {NOTIFY, MOBIKE_SUPPORTED}, + {NOTIFY, ADDITIONAL_IP4_ADDRESS}, + {NOTIFY, ADDITIONAL_IP6_ADDRESS}, + {NOTIFY, NO_ADDITIONAL_ADDRESSES}, + {VENDOR_ID, 0}, +}; /** * Message rule for INFORMATIONAL from initiator. */ static payload_rule_t informational_i_payload_rules[] = { - {NOTIFY,0,MAX_NOTIFY_PAYLOADS,TRUE,FALSE}, - {CONFIGURATION,0,1,TRUE,FALSE}, - {DELETE,0,1,TRUE,FALSE}, - {VENDOR_ID,0,10,TRUE,FALSE}, - +/* payload type min max encr suff */ + {NOTIFY, 0, MAX_NOTIFY_PAYLOADS, TRUE, FALSE}, + {CONFIGURATION, 0, 1, TRUE, FALSE}, + {DELETE, 0, 1, TRUE, FALSE}, + {VENDOR_ID, 0, 10, TRUE, FALSE}, +}; + +/** + * payload order for INFORMATIONAL initiator + */ +static payload_order_t informational_i_payload_order[] = { +/* payload type notify type */ + {NOTIFY, 0}, + {DELETE, 0}, + {CONFIGURATION, 0}, }; /** * Message rule for INFORMATIONAL from responder. */ static payload_rule_t informational_r_payload_rules[] = { - {NOTIFY,0,MAX_NOTIFY_PAYLOADS,TRUE,FALSE}, - {CONFIGURATION,0,1,TRUE,FALSE}, - {DELETE,0,1,TRUE,FALSE}, - {VENDOR_ID,0,10,TRUE,FALSE}, +/* payload type min max encr suff */ + {NOTIFY, 0, MAX_NOTIFY_PAYLOADS, TRUE, FALSE}, + {CONFIGURATION, 0, 1, TRUE, FALSE}, + {DELETE, 0, 1, TRUE, FALSE}, + {VENDOR_ID, 0, 10, TRUE, FALSE}, +}; + +/** + * payload order for INFORMATIONAL responder + */ +static payload_order_t informational_r_payload_order[] = { +/* payload type notify type */ + {NOTIFY, 0}, + {DELETE, 0}, + {CONFIGURATION, 0}, }; /** * Message rule for CREATE_CHILD_SA from initiator. */ static payload_rule_t create_child_sa_i_payload_rules[] = { - {NOTIFY,0,MAX_NOTIFY_PAYLOADS,TRUE,FALSE}, - {SECURITY_ASSOCIATION,1,1,TRUE,FALSE}, - {NONCE,1,1,TRUE,FALSE}, - {KEY_EXCHANGE,0,1,TRUE,FALSE}, - {TRAFFIC_SELECTOR_INITIATOR,0,1,TRUE,FALSE}, - {TRAFFIC_SELECTOR_RESPONDER,0,1,TRUE,FALSE}, - {CONFIGURATION,0,1,TRUE,FALSE}, - {VENDOR_ID,0,10,TRUE,FALSE}, +/* payload type min max encr suff */ + {NOTIFY, 0, MAX_NOTIFY_PAYLOADS, TRUE, FALSE}, + {SECURITY_ASSOCIATION, 1, 1, TRUE, FALSE}, + {NONCE, 1, 1, TRUE, FALSE}, + {KEY_EXCHANGE, 0, 1, TRUE, FALSE}, + {TRAFFIC_SELECTOR_INITIATOR, 0, 1, TRUE, FALSE}, + {TRAFFIC_SELECTOR_RESPONDER, 0, 1, TRUE, FALSE}, + {CONFIGURATION, 0, 1, TRUE, FALSE}, + {VENDOR_ID, 0, 10, TRUE, FALSE}, +}; + +/** + * payload order for CREATE_CHILD_SA from initiator. + */ +static payload_order_t create_child_sa_i_payload_order[] = { +/* payload type notify type */ + {NOTIFY, REKEY_SA}, + {NOTIFY, IPCOMP_SUPPORTED}, + {NOTIFY, USE_TRANSPORT_MODE}, + {NOTIFY, ESP_TFC_PADDING_NOT_SUPPORTED}, + {NOTIFY, NON_FIRST_FRAGMENTS_ALSO}, + {SECURITY_ASSOCIATION, 0}, + {NONCE, 0}, + {KEY_EXCHANGE, 0}, + {TRAFFIC_SELECTOR_INITIATOR, 0}, + {TRAFFIC_SELECTOR_RESPONDER, 0}, }; /** * Message rule for CREATE_CHILD_SA from responder. */ static payload_rule_t create_child_sa_r_payload_rules[] = { - {NOTIFY,0,MAX_NOTIFY_PAYLOADS,TRUE,TRUE}, - {SECURITY_ASSOCIATION,1,1,TRUE,FALSE}, - {NONCE,1,1,TRUE,FALSE}, - {KEY_EXCHANGE,0,1,TRUE,FALSE}, - {TRAFFIC_SELECTOR_INITIATOR,0,1,TRUE,FALSE}, - {TRAFFIC_SELECTOR_RESPONDER,0,1,TRUE,FALSE}, - {CONFIGURATION,0,1,TRUE,FALSE}, - {VENDOR_ID,0,10,TRUE,FALSE}, +/* payload type min max encr suff */ + {NOTIFY, 0, MAX_NOTIFY_PAYLOADS, TRUE, TRUE}, + {SECURITY_ASSOCIATION, 1, 1, TRUE, FALSE}, + {NONCE, 1, 1, TRUE, FALSE}, + {KEY_EXCHANGE, 0, 1, TRUE, FALSE}, + {TRAFFIC_SELECTOR_INITIATOR, 0, 1, TRUE, FALSE}, + {TRAFFIC_SELECTOR_RESPONDER, 0, 1, TRUE, FALSE}, + {CONFIGURATION, 0, 1, TRUE, FALSE}, + {VENDOR_ID, 0, 10, TRUE, FALSE}, +}; + +/** + * payload order for CREATE_CHILD_SA from responder. + */ +static payload_order_t create_child_sa_r_payload_order[] = { +/* payload type notify type */ + {NOTIFY, IPCOMP_SUPPORTED}, + {NOTIFY, USE_TRANSPORT_MODE}, + {NOTIFY, ESP_TFC_PADDING_NOT_SUPPORTED}, + {NOTIFY, NON_FIRST_FRAGMENTS_ALSO}, + {SECURITY_ASSOCIATION, 0}, + {NONCE, 0}, + {KEY_EXCHANGE, 0}, + {TRAFFIC_SELECTOR_INITIATOR, 0}, + {TRAFFIC_SELECTOR_RESPONDER, 0}, + {NOTIFY, ADDITIONAL_TS_POSSIBLE}, }; #ifdef P2P @@ -234,17 +399,38 @@ static payload_rule_t create_child_sa_r_payload_rules[] = { * Message rule for P2P_CONNECT from initiator. */ static payload_rule_t p2p_connect_i_payload_rules[] = { - {NOTIFY,0,MAX_NOTIFY_PAYLOADS,TRUE,TRUE}, - {ID_PEER,1,1,TRUE,FALSE}, - {VENDOR_ID,0,10,TRUE,FALSE} +/* payload type min max encr suff */ + {NOTIFY, 0, MAX_NOTIFY_PAYLOADS, TRUE, TRUE}, + {ID_PEER, 1, 1, TRUE, FALSE}, + {VENDOR_ID, 0, 10, TRUE, FALSE} +}; + +/** + * payload order for P2P_CONNECT from initiator. + */ +static payload_order_t p2p_connect_i_payload_order[] = { +/* payload type notify type */ + {NOTIFY, 0}, + {ID_PEER, 0}, + {VENDOR_ID, 0}, }; /** * Message rule for P2P_CONNECT from responder. */ static payload_rule_t p2p_connect_r_payload_rules[] = { - {NOTIFY,0,MAX_NOTIFY_PAYLOADS,TRUE,TRUE}, - {VENDOR_ID,0,10,TRUE,FALSE} +/* payload type min max encr suff */ + {NOTIFY, 0, MAX_NOTIFY_PAYLOADS, TRUE, TRUE}, + {VENDOR_ID, 0, 10, TRUE, FALSE} +}; + +/** + * payload order for P2P_CONNECT from responder. + */ +static payload_order_t p2p_connect_r_payload_order[] = { +/* payload type notify type */ + {NOTIFY, 0}, + {VENDOR_ID, 0}, }; #endif /* P2P */ @@ -252,17 +438,67 @@ static payload_rule_t p2p_connect_r_payload_rules[] = { * Message rules, defines allowed payloads. */ static message_rule_t message_rules[] = { - {IKE_SA_INIT,TRUE,FALSE,(sizeof(ike_sa_init_i_payload_rules)/sizeof(payload_rule_t)),ike_sa_init_i_payload_rules}, - {IKE_SA_INIT,FALSE,FALSE,(sizeof(ike_sa_init_r_payload_rules)/sizeof(payload_rule_t)),ike_sa_init_r_payload_rules}, - {IKE_AUTH,TRUE,TRUE,(sizeof(ike_auth_i_payload_rules)/sizeof(payload_rule_t)),ike_auth_i_payload_rules}, - {IKE_AUTH,FALSE,TRUE,(sizeof(ike_auth_r_payload_rules)/sizeof(payload_rule_t)),ike_auth_r_payload_rules}, - {INFORMATIONAL,TRUE,TRUE,(sizeof(informational_i_payload_rules)/sizeof(payload_rule_t)),informational_i_payload_rules}, - {INFORMATIONAL,FALSE,TRUE,(sizeof(informational_r_payload_rules)/sizeof(payload_rule_t)),informational_r_payload_rules}, - {CREATE_CHILD_SA,TRUE,TRUE,(sizeof(create_child_sa_i_payload_rules)/sizeof(payload_rule_t)),create_child_sa_i_payload_rules}, - {CREATE_CHILD_SA,FALSE,TRUE,(sizeof(create_child_sa_r_payload_rules)/sizeof(payload_rule_t)),create_child_sa_r_payload_rules}, + {IKE_SA_INIT, TRUE, FALSE, + (sizeof(ike_sa_init_i_payload_rules)/sizeof(payload_rule_t)), + ike_sa_init_i_payload_rules, + (sizeof(ike_sa_init_i_payload_order)/sizeof(payload_order_t)), + ike_sa_init_i_payload_order, + }, + {IKE_SA_INIT, FALSE, FALSE, + (sizeof(ike_sa_init_r_payload_rules)/sizeof(payload_rule_t)), + ike_sa_init_r_payload_rules, + (sizeof(ike_sa_init_r_payload_order)/sizeof(payload_order_t)), + ike_sa_init_r_payload_order, + }, + {IKE_AUTH, TRUE, TRUE, + (sizeof(ike_auth_i_payload_rules)/sizeof(payload_rule_t)), + ike_auth_i_payload_rules, + (sizeof(ike_auth_i_payload_order)/sizeof(payload_order_t)), + ike_auth_i_payload_order, + }, + {IKE_AUTH, FALSE, TRUE, + (sizeof(ike_auth_r_payload_rules)/sizeof(payload_rule_t)), + ike_auth_r_payload_rules, + (sizeof(ike_auth_r_payload_order)/sizeof(payload_order_t)), + ike_auth_r_payload_order, + }, + {INFORMATIONAL, TRUE, TRUE, + (sizeof(informational_i_payload_rules)/sizeof(payload_rule_t)), + informational_i_payload_rules, + (sizeof(informational_i_payload_order)/sizeof(payload_order_t)), + informational_i_payload_order, + }, + {INFORMATIONAL, FALSE, TRUE, + (sizeof(informational_r_payload_rules)/sizeof(payload_rule_t)), + informational_r_payload_rules, + (sizeof(informational_r_payload_order)/sizeof(payload_order_t)), + informational_r_payload_order, + }, + {CREATE_CHILD_SA, TRUE, TRUE, + (sizeof(create_child_sa_i_payload_rules)/sizeof(payload_rule_t)), + create_child_sa_i_payload_rules, + (sizeof(create_child_sa_i_payload_order)/sizeof(payload_order_t)), + create_child_sa_i_payload_order, + }, + {CREATE_CHILD_SA, FALSE, TRUE, + (sizeof(create_child_sa_r_payload_rules)/sizeof(payload_rule_t)), + create_child_sa_r_payload_rules, + (sizeof(create_child_sa_r_payload_order)/sizeof(payload_order_t)), + create_child_sa_r_payload_order, + }, #ifdef P2P - {P2P_CONNECT,TRUE,TRUE,(sizeof(p2p_connect_i_payload_rules)/sizeof(payload_rule_t)),p2p_connect_i_payload_rules}, - {P2P_CONNECT,FALSE,TRUE,(sizeof(p2p_connect_r_payload_rules)/sizeof(payload_rule_t)),p2p_connect_r_payload_rules}, + {P2P_CONNECT, TRUE, TRUE, + (sizeof(p2p_connect_i_payload_rules)/sizeof(payload_rule_t)), + p2p_connect_i_payload_rules, + (sizeof(p2p_connect_i_payload_order)/sizeof(payload_order_t)), + p2p_connect_i_payload_order, + }, + {P2P_CONNECT, FALSE, TRUE, + (sizeof(p2p_connect_r_payload_rules)/sizeof(payload_rule_t)), + p2p_connect_r_payload_rules, + (sizeof(p2p_connect_r_payload_order)/sizeof(payload_order_t)), + p2p_connect_r_payload_order, + }, #endif /* P2P */ }; @@ -517,38 +753,19 @@ static bool is_encoded(private_message_t *this) */ static void add_payload(private_message_t *this, payload_t *payload) { - payload_t *last_payload, *first_payload; - - if ((this->is_request && payload->get_type(payload) == ID_INITIATOR) || - (!this->is_request && payload->get_type(payload) == ID_RESPONDER)) + payload_t *last_payload; + + if (this->payloads->get_count(this->payloads) > 0) { - /* HOTD: insert ID payload in the beginning to respect RFC */ - if (this->payloads->get_first(this->payloads, - (void **)&first_payload) == SUCCESS) - { - payload->set_next_type(payload, first_payload->get_type(first_payload)); - } - else - { - payload->set_next_type(payload, NO_PAYLOAD); - } - this->first_payload = payload->get_type(payload); - this->payloads->insert_first(this->payloads, payload); + this->payloads->get_last(this->payloads, (void **)&last_payload); + last_payload->set_next_type(last_payload, payload->get_type(payload)); } else { - if (this->payloads->get_count(this->payloads) > 0) - { - this->payloads->get_last(this->payloads,(void **) &last_payload); - last_payload->set_next_type(last_payload, payload->get_type(payload)); - } - else - { - this->first_payload = payload->get_type(payload); - } - payload->set_next_type(payload, NO_PAYLOAD); - this->payloads->insert_last(this->payloads, payload); + this->first_payload = payload->get_type(payload); } + payload->set_next_type(payload, NO_PAYLOAD); + this->payloads->insert_last(this->payloads, payload); DBG2(DBG_ENC ,"added payload of type %N to message", payload_type_names, payload->get_type(payload)); @@ -693,10 +910,66 @@ static char* get_string(private_message_t *this, char *buf, int len) return buf; } +/** + * reorder payloads depending on reordering rules + */ +static void order_payloads(private_message_t *this) +{ + linked_list_t *list; + payload_t *payload; + int i; + + /* move to temp list */ + list = linked_list_create(); + while (this->payloads->remove_last(this->payloads, + (void**)&payload) == SUCCESS) + { + list->insert_first(list, payload); + } + /* for each rule, ... */ + for (i = 0; i < this->message_rule->payload_order_count; i++) + { + enumerator_t *enumerator; + notify_payload_t *notify; + payload_order_t order = this->message_rule->payload_order[i]; + + /* ... find all payload ... */ + enumerator = list->create_enumerator(list); + while (enumerator->enumerate(enumerator, &payload)) + { + /* ... with that type ... */ + if (payload->get_type(payload) == order.type) + { + notify = (notify_payload_t*)payload; + + /**... and check notify for type. */ + if (order.type != NOTIFY || order.notify == 0 || + order.notify == notify->get_notify_type(notify)) + { + list->remove_at(list, enumerator); + add_payload(this, payload); + } + } + } + enumerator->destroy(enumerator); + } + /* append all payloads without a rule to the end */ + while (list->remove_last(list, (void**)&payload) == SUCCESS) + { + DBG1(DBG_ENC, "payload %N has no ordering rule in %N %s", + payload_type_names, payload->get_type(payload), + exchange_type_names, this->message_rule->exchange_type, + this->message_rule->is_request ? "request" : "response"); + add_payload(this, payload); + } + list->destroy(list); +} + /** * Implementation of private_message_t.encrypt_payloads. */ -static status_t encrypt_payloads (private_message_t *this,crypter_t *crypter, signer_t* signer) +static status_t encrypt_payloads(private_message_t *this, + crypter_t *crypter, signer_t* signer) { encryption_payload_t *encryption_payload = NULL; status_t status; @@ -778,7 +1051,8 @@ static status_t encrypt_payloads (private_message_t *this,crypter_t *crypter, si /** * Implementation of message_t.generate. */ -static status_t generate(private_message_t *this, crypter_t *crypter, signer_t* signer, packet_t **packet) +static status_t generate(private_message_t *this, crypter_t *crypter, + signer_t* signer, packet_t **packet) { generator_t *generator; ike_header_t *ike_header; @@ -795,8 +1069,6 @@ static status_t generate(private_message_t *this, crypter_t *crypter, signer_t* return SUCCESS; } - DBG1(DBG_ENC, "generating %s", get_string(this, str, sizeof(str))); - if (this->exchange_type == EXCHANGE_TYPE_UNDEFINED) { DBG1(DBG_ENC, "exchange type is not defined"); @@ -819,6 +1091,10 @@ static status_t generate(private_message_t *this, crypter_t *crypter, signer_t* return NOT_SUPPORTED; } + order_payloads(this); + + DBG1(DBG_ENC, "generating %s", get_string(this, str, sizeof(str))); + /* going to encrypt all content which have to be encrypted */ status = encrypt_payloads(this, crypter, signer); if (status != SUCCESS) @@ -842,7 +1118,7 @@ static status_t generate(private_message_t *this, crypter_t *crypter, signer_t* payload = (payload_t*)ike_header; - /* generate every payload expect last one, this is doen later*/ + /* generate every payload expect last one, this is done later*/ iterator = this->payloads->create_iterator(this->payloads, TRUE); while(iterator->iterate(iterator, (void**)&next_payload)) { @@ -1346,3 +1622,4 @@ message_t *message_create() { return message_create_from_packet(NULL); } + diff --git a/src/charon/encoding/message.h b/src/charon/encoding/message.h index 35b659f33..a7637b90c 100644 --- a/src/charon/encoding/message.h +++ b/src/charon/encoding/message.h @@ -1,10 +1,3 @@ -/** - * @file message.h - * - * @brief Interface of message_t. - * - */ - /* * Copyright (C) 2006-2007 Tobias Brunner * Copyright (C) 2006 Daniel Roethlisberger @@ -21,6 +14,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup message message + * @{ @ingroup encoding */ #ifndef MESSAGE_H_ @@ -38,148 +38,126 @@ typedef struct message_t message_t; #include /** - * @brief This class is used to represent an IKEv2-Message. + * This class is used to represent an IKEv2-Message. * * The message handles parsing and generation of payloads * via parser_t/generator_t. Encryption is done transparently * via the encryption_payload_t. A set of rules for messages * and payloads does check parsed messages. - * - * @b Constructors: - * - message_create() - * - message_create_from_packet() - * - message_create_notify_reply() - * - * @ingroup encoding */ struct message_t { /** - * @brief Sets the IKE major version of the message. + * Sets the IKE major version of the message. * - * @param this message_t object * @param major_version major version to set */ void (*set_major_version) (message_t *this,u_int8_t major_version); /** - * @brief Gets the IKE major version of the message. + * Gets the IKE major version of the message. * - * @param this message_t object * @return major version of the message */ u_int8_t (*get_major_version) (message_t *this); /** - * @brief Sets the IKE minor version of the message. + * Sets the IKE minor version of the message. * - * @param this message_t object * @param minor_version minor version to set */ void (*set_minor_version) (message_t *this,u_int8_t minor_version); /** - * @brief Gets the IKE minor version of the message. + * Gets the IKE minor version of the message. * - * @param this message_t object * @return minor version of the message */ u_int8_t (*get_minor_version) (message_t *this); /** - * @brief Sets the Message ID of the message. + * Sets the Message ID of the message. * - * @param this message_t object - * @param message_id message_id to set + * @param message_id message_id to set */ void (*set_message_id) (message_t *this,u_int32_t message_id); /** - * @brief Gets the Message ID of the message. + * Gets the Message ID of the message. * - * @param this message_t object * @return message_id type of the message */ u_int32_t (*get_message_id) (message_t *this); /** - * @brief Gets the initiator SPI of the message. + * Gets the initiator SPI of the message. * - * @param this message_t object * @return initiator spi of the message */ u_int64_t (*get_initiator_spi) (message_t *this); /** - * @brief Gets the responder SPI of the message. + * Gets the responder SPI of the message. * - * @param this message_t object * @return responder spi of the message */ u_int64_t (*get_responder_spi) (message_t *this); /** - * @brief Sets the IKE_SA ID of the message. + * Sets the IKE_SA ID of the message. * * ike_sa_id gets cloned. * - * @param this message_t object * @param ike_sa_id ike_sa_id to set */ void (*set_ike_sa_id) (message_t *this, ike_sa_id_t * ike_sa_id); /** - * @brief Gets the IKE_SA ID of the message. + * Gets the IKE_SA ID of the message. * * The ike_sa_id points to the message internal id, do not modify. * - * @param this message_t object * @return ike_sa_id of message */ ike_sa_id_t *(*get_ike_sa_id) (message_t *this); /** - * @brief Sets the exchange type of the message. + * Sets the exchange type of the message. * - * @param this message_t object * @param exchange_type exchange_type to set */ void (*set_exchange_type) (message_t *this,exchange_type_t exchange_type); /** - * @brief Gets the exchange type of the message. + * Gets the exchange type of the message. * - * @param this message_t object * @return exchange type of the message */ exchange_type_t (*get_exchange_type) (message_t *this); /** - * @brief Gets the payload type of the first payload. + * Gets the payload type of the first payload. * - * @param this message_t object * @return payload type of the first payload */ payload_type_t (*get_first_payload_type) (message_t *this); /** - * @brief Sets the request flag. + * Sets the request flag. * - * @param this message_t object - * @param original_initiator TRUE if message is a request, FALSE if it is a reply + * @param request TRUE if message is a request, FALSE if it is a reply */ - void (*set_request) (message_t *this,bool request); + void (*set_request) (message_t *this, bool request); /** - * @brief Gets request flag. + * Gets request flag. * - * @param this message_t object * @return TRUE if message is a request, FALSE if it is a reply */ bool (*get_request) (message_t *this); /** - * @brief Append a payload to the message. + * Append a payload to the message. * * If the payload must be encrypted is not specified here. Encryption * of payloads is evaluated via internal rules for the messages and @@ -187,19 +165,17 @@ struct message_t { * all payloads to encrypt are added to the encryption payload, which is * always the last one. * - * @param this message_t object * @param payload payload to append */ void (*add_payload) (message_t *this, payload_t *payload); /** - * @brief Build a notify payload and add it to the message. + * Build a notify payload and add it to the message. * * This is a helper method to create notify messages or add * notify payload to messages. The flush parameter specifies if existing * payloads should get removed before appending the notify. * - * @param this message_t object * @param flush TRUE to remove existing payloads * @param type type of the notify * @param data a chunk of data to add to the notify, gets cloned @@ -208,13 +184,12 @@ struct message_t { chunk_t data); /** - * @brief Parses header of message. + * Parses header of message. * * Begins parisng of a message created via message_create_from_packet(). * The parsing context is stored, so a subsequent call to parse_body() * will continue the parsing process. * - * @param this message_t object * @return * - SUCCESS if header could be parsed * - PARSE_ERROR if corrupted/invalid data found @@ -223,7 +198,7 @@ struct message_t { status_t (*parse_header) (message_t *this); /** - * @brief Parses body of message. + * Parses body of message. * * The body gets not only parsed, but rather it gets verified. * All payloads are verified if they are allowed to exist in the message @@ -234,7 +209,6 @@ struct message_t { * Crypter/signer can be omitted (by passing NULL) when no encryption * payload is expected. * - * @param this message_t object * @param crypter crypter to decrypt encryption payloads * @param signer signer to verifiy a message with an encryption payload * @return @@ -249,7 +223,7 @@ struct message_t { status_t (*parse_body) (message_t *this, crypter_t *crypter, signer_t *signer); /** - * @brief Generates the UDP packet of specific message. + * Generates the UDP packet of specific message. * * Payloads which must be encrypted are generated first and added to * an encryption payload. This encryption payload will get encrypted via @@ -260,7 +234,6 @@ struct message_t { * payload is expected. * Generation is only done once, multiple calls will just return a packet copy. * - * @param this message_t object * @param crypter crypter to use when a payload must be encrypted * @param signer signer to build a mac * @param packet copy of generated packet @@ -273,103 +246,91 @@ struct message_t { status_t (*generate) (message_t *this, crypter_t *crypter, signer_t *signer, packet_t **packet); /** - * @brief Gets the source host informations. + * Gets the source host informations. * * @warning Returned host_t object is not getting cloned, * do not destroy nor modify. * - * @param this message_t object * @return host_t object representing source host */ host_t * (*get_source) (message_t *this); /** - * @brief Sets the source host informations. + * Sets the source host informations. * * @warning host_t object is not getting cloned and gets destroyed by * message_t.destroy or next call of message_t.set_source. * - * @param this message_t object * @param host host_t object representing source host */ void (*set_source) (message_t *this, host_t *host); /** - * @brief Gets the destination host informations. + * Gets the destination host informations. * * @warning Returned host_t object is not getting cloned, * do not destroy nor modify. * - * @param this message_t object * @return host_t object representing destination host */ host_t * (*get_destination) (message_t *this); /** - * @brief Sets the destination host informations. + * Sets the destination host informations. * * @warning host_t object is not getting cloned and gets destroyed by * message_t.destroy or next call of message_t.set_destination. * - * @param this message_t object * @param host host_t object representing destination host */ void (*set_destination) (message_t *this, host_t *host); /** - * @brief Returns an iterator on all stored payloads. + * Returns an iterator on all stored payloads. * * @warning Don't insert payloads over this iterator. * Use add_payload() instead. * - * @param this message_t object * @return iterator_t object which has to get destroyd by the caller */ iterator_t * (*get_payload_iterator) (message_t *this); /** - * @brief Find a payload of a specific type. + * Find a payload of a specific type. * * Returns the first occurance. * - * @param this message_t object * @param type type of the payload to find * @return payload, or NULL if no such payload found */ payload_t* (*get_payload) (message_t *this, payload_type_t type); /** - * @brief Returns a clone of the internal stored packet_t object. + * Returns a clone of the internal stored packet_t object. * - * @param this message_t object * @return packet_t object as clone of internal one */ packet_t * (*get_packet) (message_t *this); /** - * @brief Returns a clone of the internal stored packet_t data. + * Returns a clone of the internal stored packet_t data. * - * @param this message_t object * @return clone of the internal stored packet_t data. */ chunk_t (*get_packet_data) (message_t *this); /** - * @brief Destroys a message and all including objects. - * - * @param this message_t object + * Destroys a message and all including objects. */ void (*destroy) (message_t *this); }; /** - * @brief Creates an message_t object from a incoming UDP Packet. + * Creates an message_t object from a incoming UDP Packet. * * @warning the given packet_t object is not copied and gets * destroyed in message_t's destroy call. * - * @warning Packet is not parsed in here! - * * - exchange_type is set to NOT_SET * - original_initiator is set to TRUE * - is_request is set to TRUE @@ -377,23 +338,19 @@ struct message_t { * * @param packet packet_t object which is assigned to message * @return message_t object - * - * @ingroup encoding */ message_t * message_create_from_packet(packet_t *packet); /** - * @brief Creates an empty message_t object. + * Creates an empty message_t object. * * - exchange_type is set to NOT_SET * - original_initiator is set to TRUE * - is_request is set to TRUE * * @return message_t object - * - * @ingroup encoding */ message_t * message_create(void); -#endif /*MESSAGE_H_*/ +#endif /*MESSAGE_H_ @} */ diff --git a/src/charon/encoding/parser.c b/src/charon/encoding/parser.c index d7caf7099..161ceff94 100644 --- a/src/charon/encoding/parser.c +++ b/src/charon/encoding/parser.c @@ -1,10 +1,3 @@ -/** - * @file parser.c - * - * @brief Implementation of parser_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,8 @@ * 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. + * + * $Id$ */ #include @@ -67,7 +62,7 @@ struct private_parser_t { parser_t public; /** - * @brief Parse a 4-Bit unsigned integer from the current parsing position. + * Parse a 4-Bit unsigned integer from the current parsing position. * * @param this parser_t object * @param rule_number number of current rule @@ -79,7 +74,7 @@ struct private_parser_t { status_t (*parse_uint4) (private_parser_t *this, int rule_number, u_int8_t *output_pos); /** - * @brief Parse a 8-Bit unsigned integer from the current parsing position. + * Parse a 8-Bit unsigned integer from the current parsing position. * * @param this parser_t object * @param rule_number number of current rule @@ -91,7 +86,7 @@ struct private_parser_t { status_t (*parse_uint8) (private_parser_t *this, int rule_number, u_int8_t *output_pos); /** - * @brief Parse a 15-Bit unsigned integer from the current parsing position. + * Parse a 15-Bit unsigned integer from the current parsing position. * * This is a special case used for ATTRIBUTE_TYPE. * Big-/Little-endian conversion is done here. @@ -106,7 +101,7 @@ struct private_parser_t { status_t (*parse_uint15) (private_parser_t *this, int rule_number, u_int16_t *output_pos); /** - * @brief Parse a 16-Bit unsigned integer from the current parsing position. + * Parse a 16-Bit unsigned integer from the current parsing position. * * Big-/Little-endian conversion is done here. * @@ -120,7 +115,7 @@ struct private_parser_t { status_t (*parse_uint16) (private_parser_t *this, int rule_number, u_int16_t *output_pos); /** - * @brief Parse a 32-Bit unsigned integer from the current parsing position. + * Parse a 32-Bit unsigned integer from the current parsing position. * * Big-/Little-endian conversion is done here. * @@ -134,7 +129,7 @@ struct private_parser_t { status_t (*parse_uint32) (private_parser_t *this, int rule_number, u_int32_t *output_pos); /** - * @brief Parse a 64-Bit unsigned integer from the current parsing position. + * Parse a 64-Bit unsigned integer from the current parsing position. * * @todo add support for big-endian machines. * @@ -148,7 +143,7 @@ struct private_parser_t { status_t (*parse_uint64) (private_parser_t *this, int rule_number, u_int64_t *output_pos); /** - * @brief Parse a given amount of bytes and writes them to a specific location + * Parse a given amount of bytes and writes them to a specific location * * @param this parser_t object * @param rule_number number of current rule @@ -161,7 +156,7 @@ struct private_parser_t { status_t (*parse_bytes) (private_parser_t *this, int rule_number, u_int8_t *output_pos,size_t bytes); /** - * @brief Parse a single Bit from the current parsing position + * Parse a single Bit from the current parsing position * * @param this parser_t object * @param rule_number number of current rule @@ -173,7 +168,7 @@ struct private_parser_t { status_t (*parse_bit) (private_parser_t *this, int rule_number, bool *output_pos); /** - * @brief Parse substructures in a list + * Parse substructures in a list * * This function calls the parser recursively to parse contained substructures * in a linked_list_t. The list must already be created. Payload defines @@ -192,7 +187,7 @@ struct private_parser_t { status_t (*parse_list) (private_parser_t *this, int rule_number, linked_list_t **output_pos, payload_type_t payload_ype, size_t length); /** - * @brief Parse data from current parsing position in a chunk. + * Parse data from current parsing position in a chunk. * * This function clones length number of bytes to output_pos, without * modifiyng them. Space will be allocated and must be freed by caller. diff --git a/src/charon/encoding/parser.h b/src/charon/encoding/parser.h index e9978524c..d3bcbc20f 100644 --- a/src/charon/encoding/parser.h +++ b/src/charon/encoding/parser.h @@ -1,10 +1,3 @@ -/** - * @file parser.h - * - * @brief Interface of parser_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup parser parser + * @{ @ingroup encoding */ #ifndef PARSER_H_ @@ -31,65 +31,51 @@ typedef struct parser_t parser_t; #include /** - * @brief A parser_t class to parse IKEv2 payloads. + * A parser_t class to parse IKEv2 payloads. * * A parser is used for parsing one chunk of data. Multiple * payloads can be parsed out of the chunk using parse_payload. * The parser remains the state until destroyed. - * - * @b Constructors: - * - parser_create() - * - * @ingroup encoding */ struct parser_t { /** - * @brief Parses the next payload. + * Parses the next payload. * * @warning Caller is responsible for freeing allocated payload. * * Rules for parsing are described in the payload definition. * - * @param this parser_t bject - * @param payload_type payload type to parse - * @param[out] payload pointer where parsed payload was allocated + * @param payload_type payload type to parse + * @param payload pointer where parsed payload was allocated * @return - * - SUCCESSFUL if succeeded, - * - PARSE_ERROR if corrupted/invalid data found + * - SUCCESSFUL if succeeded, + * - PARSE_ERROR if corrupted/invalid data found */ status_t (*parse_payload) (parser_t *this, payload_type_t payload_type, payload_t **payload); /** * Gets the remaining byte count which is not currently parsed. - * - * @param parser parser_t object */ int (*get_remaining_byte_count) (parser_t *this); /** - * @brief Resets the current parser context. - * - * @param parser parser_t object + * Resets the current parser context. */ void (*reset_context) (parser_t *this); /** - * @brief Destroys a parser_t object. - * - * @param parser parser_t object + * Destroys a parser_t object. */ void (*destroy) (parser_t *this); }; /** - * @brief Constructor to create a parser_t object. - * - * @param data chunk of data to parse with this parser_t object - * @return parser_t object + * Constructor to create a parser_t object. * - * @ingroup encoding + * @param data chunk of data to parse with this parser_t object + * @return parser_t object */ parser_t *parser_create(chunk_t data); -#endif /*PARSER_H_*/ +#endif /*PARSER_H_ @} */ diff --git a/src/charon/encoding/payloads/auth_payload.c b/src/charon/encoding/payloads/auth_payload.c index 256d6c8a4..5df9e9023 100644 --- a/src/charon/encoding/payloads/auth_payload.c +++ b/src/charon/encoding/payloads/auth_payload.c @@ -1,10 +1,3 @@ -/** - * @file auth_payload.h - * - * @brief Implementation of auth_payload_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,8 @@ * 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. + * + * $Id$ */ #include "auth_payload.h" diff --git a/src/charon/encoding/payloads/auth_payload.h b/src/charon/encoding/payloads/auth_payload.h index 2db82ec0b..6e0596c4b 100644 --- a/src/charon/encoding/payloads/auth_payload.h +++ b/src/charon/encoding/payloads/auth_payload.h @@ -1,10 +1,3 @@ -/** - * @file auth_payload.h - * - * @brief Interface of auth_payload_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup auth_payload auth_payload + * @{ @ingroup payloads */ #ifndef AUTH_PAYLOAD_H_ @@ -32,20 +32,13 @@ typedef struct auth_payload_t auth_payload_t; /** * Length of a auth payload without the auth data in bytes. - * - * @ingroup payloads */ #define AUTH_PAYLOAD_HEADER_LENGTH 8 /** - * @brief Class representing an IKEv2 AUTH payload. + * Class representing an IKEv2 AUTH payload. * * The AUTH payload format is described in RFC section 3.8. - * - * @b Constructors: - * - auth_payload_create() - * - * @ingroup payloads */ struct auth_payload_t { @@ -55,67 +48,57 @@ struct auth_payload_t { payload_t payload_interface; /** - * @brief Set the AUTH method. + * Set the AUTH method. * - * @param this calling auth_payload_t object * @param method auth_method_t to use */ void (*set_auth_method) (auth_payload_t *this, auth_method_t method); /** - * @brief Get the AUTH method. + * Get the AUTH method. * - * @param this calling auth_payload_t object * @return auth_method_t used */ auth_method_t (*get_auth_method) (auth_payload_t *this); /** - * @brief Set the AUTH data. + * Set the AUTH data. * - * Data are getting cloned. + * Data gets cloned. * - * @param this calling auth_payload_t object * @param data AUTH data as chunk_t */ void (*set_data) (auth_payload_t *this, chunk_t data); /** - * @brief Get the AUTH data. + * Get the AUTH data. * * Returned data are a copy of the internal one. * - * @param this calling auth_payload_t object * @return AUTH data as chunk_t */ chunk_t (*get_data_clone) (auth_payload_t *this); /** - * @brief Get the AUTH data. + * Get the AUTH data. * * Returned data are NOT copied * - * @param this calling auth_payload_t object * @return AUTH data as chunk_t */ chunk_t (*get_data) (auth_payload_t *this); /** - * @brief Destroys an auth_payload_t object. - * - * @param this auth_payload_t object to destroy + * Destroys an auth_payload_t object. */ void (*destroy) (auth_payload_t *this); }; /** - * @brief Creates an empty auth_payload_t object. + * Creates an empty auth_payload_t object. * * @return auth_payload_t object - * - * @ingroup payloads */ auth_payload_t *auth_payload_create(void); - -#endif /* AUTH_PAYLOAD_H_ */ +#endif /* AUTH_PAYLOAD_H_ @} */ diff --git a/src/charon/encoding/payloads/cert_payload.c b/src/charon/encoding/payloads/cert_payload.c index c456f4936..e641cfb0e 100644 --- a/src/charon/encoding/payloads/cert_payload.c +++ b/src/charon/encoding/payloads/cert_payload.c @@ -1,12 +1,5 @@ -/** - * @file cert_payload.c - * - * @brief Implementation of cert_payload_t. - * - */ - /* - * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005-2007 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil * @@ -19,29 +12,31 @@ * 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. + * + * $Id$ */ #include -#include "cert_payload.h" +#include +#include "cert_payload.h" -ENUM(cert_encoding_names, CERT_NONE, CERT_OCSP_CONTENT, - "CERT_NONE", - "CERT_PKCS7_WRAPPED_X509", - "CERT_PGP", - "CERT_DNS_SIGNED_KEY", - "CERT_X509_SIGNATURE", - "CERT_X509_KEY_EXCHANGE", - "CERT_KERBEROS_TOKENS", - "CERT_CRL", - "CERT_ARL", - "CERT_SPKI", - "CERT_X509_ATTRIBUTE", - "CERT_RAW_RSA_KEY", - "CERT_X509_HASH_AND_URL", - "CERT_X509_HASH_AND_URL_BUNDLE", - "CERT_OCSP_CONTENT", +ENUM(cert_encoding_names, ENC_PKCS7_WRAPPED_X509, ENC_OCSP_CONTENT, + "ENC_PKCS7_WRAPPED_X509", + "ENC_PGP", + "ENC_DNS_SIGNED_KEY", + "ENC_X509_SIGNATURE", + "ENC_X509_KEY_EXCHANGE", + "ENC_KERBEROS_TOKENS", + "ENC_CRL", + "ENC_ARL", + "ENC_SPKI", + "ENC_X509_ATTRIBUTE", + "ENC_RAW_RSA_KEY", + "ENC_X509_HASH_AND_URL", + "ENC_X509_HASH_AND_URL_BUNDLE", + "ENC_OCSP_CONTENT", ); typedef struct private_cert_payload_t private_cert_payload_t; @@ -74,12 +69,12 @@ struct private_cert_payload_t { /** * Encoding of the CERT Data. */ - u_int8_t cert_encoding; + u_int8_t encoding; /** * The contained cert data value. */ - chunk_t cert_data; + chunk_t data; }; /** @@ -105,9 +100,9 @@ encoding_rule_t cert_payload_encodings[] = { /* Length of the whole payload*/ { PAYLOAD_LENGTH, offsetof(private_cert_payload_t, payload_length)}, /* 1 Byte CERT type*/ - { U_INT_8, offsetof(private_cert_payload_t, cert_encoding) }, + { U_INT_8, offsetof(private_cert_payload_t, encoding) }, /* some cert data bytes, length is defined in PAYLOAD_LENGTH */ - { CERT_DATA, offsetof(private_cert_payload_t, cert_data) } + { CERT_DATA, offsetof(private_cert_payload_t, data) } }; /* @@ -128,19 +123,14 @@ encoding_rule_t cert_payload_encodings[] = { */ static status_t verify(private_cert_payload_t *this) { - if ((this->cert_encoding == 0) || - ((this->cert_encoding >= CERT_ROOF) && (this->cert_encoding <= 200))) - { - /* reserved IDs */ - return FAILED; - } return SUCCESS; } /** * Implementation of cert_payload_t.get_encoding_rules. */ -static void get_encoding_rules(private_cert_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +static void get_encoding_rules(private_cert_payload_t *this, + encoding_rule_t **rules, size_t *rule_count) { *rules = cert_payload_encodings; *rule_count = sizeof(cert_payload_encodings) / sizeof(encoding_rule_t); @@ -159,7 +149,7 @@ static payload_type_t get_payload_type(private_cert_payload_t *this) */ static payload_type_t get_next_type(private_cert_payload_t *this) { - return (this->next_payload); + return this->next_payload; } /** @@ -179,56 +169,37 @@ static size_t get_length(private_cert_payload_t *this) } /** - * Implementation of cert_payload_t.set_cert_encoding. - */ -static void set_cert_encoding (private_cert_payload_t *this, cert_encoding_t encoding) -{ - this->cert_encoding = encoding; -} - -/** - * Implementation of cert_payload_t.get_cert_encoding. - */ -static cert_encoding_t get_cert_encoding (private_cert_payload_t *this) -{ - return (this->cert_encoding); -} - -/** - * Implementation of cert_payload_t.set_data. + * Implementation of cert_payload_t.get_cert. */ -static void set_data (private_cert_payload_t *this, chunk_t data) +static certificate_t* get_cert(private_cert_payload_t *this) { - if (this->cert_data.ptr != NULL) - { - chunk_free(&(this->cert_data)); - } - this->cert_data.ptr = clalloc(data.ptr,data.len); - this->cert_data.len = data.len; - this->payload_length = CERT_PAYLOAD_HEADER_LENGTH + this->cert_data.len; -} - -/** - * Implementation of cert_payload_t.get_data. - */ -static chunk_t get_data (private_cert_payload_t *this) -{ - return (this->cert_data); -} - -/** - * Implementation of cert_payload_t.get_data_clone. - */ -static chunk_t get_data_clone (private_cert_payload_t *this) -{ - chunk_t cloned_data; - if (this->cert_data.ptr == NULL) + certificate_type_t type; + + switch (this->encoding) { - return (this->cert_data); + case ENC_X509_SIGNATURE: + type = CERT_X509; + break; + case ENC_PKCS7_WRAPPED_X509: + case ENC_PGP: + case ENC_DNS_SIGNED_KEY: + case ENC_KERBEROS_TOKEN: + case ENC_CRL: + case ENC_ARL: + case ENC_SPKI: + case ENC_X509_ATTRIBUTE: + case ENC_RAW_RSA_KEY: + case ENC_X509_HASH_AND_URL: + case ENC_X509_HASH_AND_URL_BUNDLE: + case ENC_OCSP_CONTENT: + default: + DBG1(DBG_ENC, "certificate encoding %N not supported", + cert_encoding_names, this->encoding); + return NULL; } - cloned_data.ptr = clalloc(this->cert_data.ptr,this->cert_data.len); - cloned_data.len = this->cert_data.len; - return cloned_data; + return lib->creds->create(lib->creds, CRED_CERTIFICATE, type, + BUILD_BLOB_ASN1_DER, chunk_clone(this->data), + BUILD_END); } /** @@ -236,11 +207,7 @@ static chunk_t get_data_clone (private_cert_payload_t *this) */ static void destroy(private_cert_payload_t *this) { - if (this->cert_data.ptr != NULL) - { - chunk_free(&(this->cert_data)); - } - + chunk_free(&this->data); free(this); } @@ -251,7 +218,6 @@ cert_payload_t *cert_payload_create() { private_cert_payload_t *this = malloc_thing(private_cert_payload_t); - /* interface functions */ this->public.payload_interface.verify = (status_t (*) (payload_t*))verify; this->public.payload_interface.get_encoding_rules = (void (*) (payload_t*,encoding_rule_t**, size_t*))get_encoding_rules; this->public.payload_interface.get_length = (size_t (*) (payload_t*))get_length; @@ -260,31 +226,38 @@ cert_payload_t *cert_payload_create() this->public.payload_interface.get_type = (payload_type_t (*) (payload_t*))get_payload_type; this->public.payload_interface.destroy = (void (*) (payload_t*))destroy; - /* public functions */ this->public.destroy = (void (*) (cert_payload_t*))destroy; - this->public.set_cert_encoding = (void (*) (cert_payload_t*,cert_encoding_t))set_cert_encoding; - this->public.get_cert_encoding = (cert_encoding_t (*) (cert_payload_t*))get_cert_encoding; - this->public.set_data = (void (*) (cert_payload_t*,chunk_t))set_data; - this->public.get_data_clone = (chunk_t (*) (cert_payload_t*))get_data_clone; - this->public.get_data = (chunk_t (*) (cert_payload_t*))get_data; + this->public.get_cert = (certificate_t* (*) (cert_payload_t*))get_cert; - /* private variables */ this->critical = FALSE; this->next_payload = NO_PAYLOAD; this->payload_length = CERT_PAYLOAD_HEADER_LENGTH; - this->cert_data = chunk_empty; + this->data = chunk_empty; + this->encoding = 0; - return (&(this->public)); + return &this->public; } /* * Described in header */ -cert_payload_t *cert_payload_create_from_x509(x509_t *cert) +cert_payload_t *cert_payload_create_from_cert(certificate_t *cert) { - cert_payload_t *this = cert_payload_create(); + private_cert_payload_t *this = (private_cert_payload_t*)cert_payload_create(); - this->set_cert_encoding(this, CERT_X509_SIGNATURE); - this->set_data(this, cert->get_certificate(cert)); - return this; + switch (cert->get_type(cert)) + { + case CERT_X509: + this->encoding = ENC_X509_SIGNATURE; + break; + default: + DBG1(DBG_ENC, "embedding %N certificate in payload failed", + certificate_type_names, cert->get_type(cert)); + free(this); + return NULL; + } + this->data = cert->get_encoding(cert); + this->payload_length = CERT_PAYLOAD_HEADER_LENGTH + this->data.len; + return &this->public; } + diff --git a/src/charon/encoding/payloads/cert_payload.h b/src/charon/encoding/payloads/cert_payload.h index bcb961398..6b8228bb6 100644 --- a/src/charon/encoding/payloads/cert_payload.h +++ b/src/charon/encoding/payloads/cert_payload.h @@ -1,12 +1,5 @@ -/** - * @file cert_payload.h - * - * @brief Interface of cert_payload_t. - * - */ - /* - * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005-2007 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil * @@ -19,69 +12,58 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup cert_payload cert_payload + * @{ @ingroup payloads */ #ifndef CERT_PAYLOAD_H_ #define CERT_PAYLOAD_H_ -typedef enum cert_encoding_t cert_encoding_t; typedef struct cert_payload_t cert_payload_t; +typedef enum cert_encoding_t cert_encoding_t; #include -#include +#include #include /** * Length of a cert payload without the cert data in bytes. - * - * @ingroup payloads */ #define CERT_PAYLOAD_HEADER_LENGTH 5 /** - * @brief Certificate encoding, as described in IKEv2 RFC section 3.6 - * - * @ingroup payloads + * Certifcate encodings, as in RFC4306 */ enum cert_encoding_t { - CERT_NONE = 0, - CERT_PKCS7_WRAPPED_X509 = 1, - CERT_PGP = 2, - CERT_DNS_SIGNED_KEY = 3, - CERT_X509_SIGNATURE = 4, - CERT_KERBEROS_TOKEN = 6, - CERT_CRL = 7, - CERT_ARL = 8, - CERT_SPKI = 9, - CERT_X509_ATTRIBUTE = 10, - CERT_RAW_RSA_KEY = 11, - CERT_X509_HASH_AND_URL = 12, - CERT_X509_HASH_AND_URL_BUNDLE = 13, - CERT_OCSP_CONTENT = 14, /* from RFC 4806 */ - CERT_ROOF = 15 + ENC_PKCS7_WRAPPED_X509 = 1, + ENC_PGP = 2, + ENC_DNS_SIGNED_KEY = 3, + ENC_X509_SIGNATURE = 4, + ENC_KERBEROS_TOKEN = 6, + ENC_CRL = 7, + ENC_ARL = 8, + ENC_SPKI = 9, + ENC_X509_ATTRIBUTE = 10, + ENC_RAW_RSA_KEY = 11, + ENC_X509_HASH_AND_URL = 12, + ENC_X509_HASH_AND_URL_BUNDLE = 13, + ENC_OCSP_CONTENT = 14, /* from RFC 4806 */ }; /** - * string mappings for cert_encoding_t. - * - * @ingroup payloads + * Enum names for cert_encoding_t */ extern enum_name_t *cert_encoding_names; /** - * @brief Class representing an IKEv2 CERT payload. + * Class representing an IKEv2 CERT payload. * * The CERT payload format is described in RFC section 3.6. - * This is just a dummy implementation to fullfill the standards - * requirements. A full implementation would offer setters/getters - * for the different encoding types. - * - * @b Constructors: - * - cert_payload_create() - * - * @todo Implement setters/getters for the different certificate encodings. - * - * @ingroup payloads */ struct cert_payload_t { @@ -89,78 +71,34 @@ struct cert_payload_t { * The payload_t interface. */ payload_t payload_interface; - - /** - * @brief Set the CERT encoding. - * - * @param this calling cert_payload_t object - * @param encoding CERT encoding - */ - void (*set_cert_encoding) (cert_payload_t *this, cert_encoding_t encoding); - - /** - * @brief Get the CERT encoding. - * - * @param this calling cert_payload_t object - * @return Encoding of the CERT - */ - cert_encoding_t (*get_cert_encoding) (cert_payload_t *this); - - /** - * @brief Set the CERT data. - * - * Data are getting cloned. - * - * @param this calling cert_payload_t object - * @param data CERT data as chunk_t - */ - void (*set_data) (cert_payload_t *this, chunk_t data); /** - * @brief Get the CERT data. - * - * Returned data are a copy of the internal one. + * Get the playoads encoded certifcate. * - * @param this calling cert_payload_t object - * @return CERT data as chunk_t + * @return certifcate copy */ - chunk_t (*get_data_clone) (cert_payload_t *this); + certificate_t *(*get_cert)(cert_payload_t *this); /** - * @brief Get the CERT data. - * - * Returned data are NOT copied. - * - * @param this calling cert_payload_t object - * @return CERT data as chunk_t - */ - chunk_t (*get_data) (cert_payload_t *this); - - /** - * @brief Destroys an cert_payload_t object. - * - * @param this cert_payload_t object to destroy + * Destroys the cert_payload object. */ void (*destroy) (cert_payload_t *this); }; /** - * @brief Creates an empty cert_payload_t object. + * Creates an empty certificate payload. * + * @param cert certificate to embed * @return cert_payload_t object - * - * @ingroup payloads */ cert_payload_t *cert_payload_create(void); /** - * @brief Creates a cert_payload_t object with an X.509 certificate. + * Creates a certificate payload with an embedded certificate. * - * @param cert X.509 certificate + * @param cert certificate to embed * @return cert_payload_t object - * - * @ingroup payloads */ -cert_payload_t *cert_payload_create_from_x509(x509_t *cert); +cert_payload_t *cert_payload_create_from_cert(certificate_t *cert); -#endif /* CERT_PAYLOAD_H_ */ +#endif /* CERT_PAYLOAD_H_ @} */ diff --git a/src/charon/encoding/payloads/certreq_payload.c b/src/charon/encoding/payloads/certreq_payload.c index 46663811a..8e6342439 100644 --- a/src/charon/encoding/payloads/certreq_payload.c +++ b/src/charon/encoding/payloads/certreq_payload.c @@ -1,10 +1,3 @@ -/** - * @file certreq_payload.c - * - * @brief Implementation of certreq_payload_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,14 +12,15 @@ * 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. + * + * $Id$ */ #include -#include #include #include -#include +#include #include "certreq_payload.h" @@ -61,12 +55,12 @@ struct private_certreq_payload_t { /** * Encoding of the CERT Data. */ - u_int8_t cert_encoding; + u_int8_t encoding; /** * The contained certreq data value. */ - chunk_t certreq_data; + chunk_t data; }; /** @@ -90,11 +84,11 @@ encoding_rule_t certreq_payload_encodings[] = { { RESERVED_BIT, 0 }, { RESERVED_BIT, 0 }, /* Length of the whole payload*/ - { PAYLOAD_LENGTH, offsetof(private_certreq_payload_t, payload_length)}, + { PAYLOAD_LENGTH, offsetof(private_certreq_payload_t, payload_length) }, /* 1 Byte CERTREQ type*/ - { U_INT_8, offsetof(private_certreq_payload_t, cert_encoding)}, + { U_INT_8, offsetof(private_certreq_payload_t, encoding) }, /* some certreq data bytes, length is defined in PAYLOAD_LENGTH */ - { CERTREQ_DATA, offsetof(private_certreq_payload_t, certreq_data)} + { CERTREQ_DATA, offsetof(private_certreq_payload_t, data) } }; /* @@ -115,11 +109,15 @@ encoding_rule_t certreq_payload_encodings[] = { */ static status_t verify(private_certreq_payload_t *this) { - if ((this->cert_encoding == 0) || - ((this->cert_encoding >= CERT_ROOF) && (this->cert_encoding <= 200))) + if (this->encoding == ENC_X509_SIGNATURE) { - /* reserved IDs */ - return FAILED; + if (this->data.len < HASH_SIZE_SHA1 || + this->data.len % HASH_SIZE_SHA1) + { + DBG1(DBG_ENC, "invalid X509 hash length (%d) in certreq", + this->data.len); + return FAILED; + } } return SUCCESS; } @@ -164,58 +162,78 @@ static size_t get_length(private_certreq_payload_t *this) { return this->payload_length; } - + /** - * Implementation of certreq_payload_t.set_cert_encoding. + * Implementation of certreq_payload_t.add_keyid. */ -static void set_cert_encoding (private_certreq_payload_t *this, cert_encoding_t encoding) +static void add_keyid(private_certreq_payload_t *this, chunk_t keyid) { - this->cert_encoding = encoding; + this->data = chunk_cat("mc", this->data, keyid); + this->payload_length += keyid.len; } +typedef struct keyid_enumerator_t keyid_enumerator_t; + /** - * Implementation of certreq_payload_t.get_cert_encoding. + * enumerator to enumerate keyids */ -static cert_encoding_t get_cert_encoding (private_certreq_payload_t *this) -{ - return (this->cert_encoding); -} +struct keyid_enumerator_t { + enumerator_t public; + chunk_t full; + u_char *pos; +}; /** - * Implementation of certreq_payload_t.set_data. + * enumerate function for keyid_enumerator */ -static void set_data (private_certreq_payload_t *this, chunk_t data) +static bool keyid_enumerate(keyid_enumerator_t *this, chunk_t *chunk) { - if (this->certreq_data.ptr != NULL) + if (this->pos == NULL) + { + this->pos = this->full.ptr; + } + else { - chunk_free(&(this->certreq_data)); + this->pos += HASH_SIZE_SHA1; + if (this->pos > (this->full.ptr + this->full.len - HASH_SIZE_SHA1)) + { + this->pos = NULL; + } } - this->certreq_data.ptr = clalloc(data.ptr,data.len); - this->certreq_data.len = data.len; - this->payload_length = CERTREQ_PAYLOAD_HEADER_LENGTH + this->certreq_data.len; + if (this->pos) + { + chunk->ptr = this->pos; + chunk->len = HASH_SIZE_SHA1; + return TRUE; + } + return FALSE; } /** - * Implementation of certreq_payload_t.get_data. + * Implementation of certreq_payload_t.create_keyid_enumerator. */ -static chunk_t get_data (private_certreq_payload_t *this) +static enumerator_t* create_keyid_enumerator(private_certreq_payload_t *this) { - return (this->certreq_data); + keyid_enumerator_t *enumerator = malloc_thing(keyid_enumerator_t); + enumerator->public.enumerate = (void*)keyid_enumerate; + enumerator->public.destroy = (void*)free; + enumerator->full = this->data; + enumerator->pos = NULL; + return &enumerator->public; } /** - * Implementation of certreq_payload_t.get_data_clone. + * Implementation of certreq_payload_t.get_cert_type. */ -static chunk_t get_data_clone (private_certreq_payload_t *this) +static certificate_type_t get_cert_type(private_certreq_payload_t *this) { - chunk_t cloned_data; - if (this->certreq_data.ptr == NULL) + switch (this->encoding) { - return (this->certreq_data); + case ENC_X509_SIGNATURE: + return CERT_X509; + default: + return CERT_ANY; } - cloned_data.ptr = clalloc(this->certreq_data.ptr,this->certreq_data.len); - cloned_data.len = this->certreq_data.len; - return cloned_data; } /** @@ -223,11 +241,7 @@ static chunk_t get_data_clone (private_certreq_payload_t *this) */ static void destroy(private_certreq_payload_t *this) { - if (this->certreq_data.ptr != NULL) - { - chunk_free(&(this->certreq_data)); - } - + chunk_free(&this->data); free(this); } @@ -249,87 +263,38 @@ certreq_payload_t *certreq_payload_create() /* public functions */ this->public.destroy = (void (*) (certreq_payload_t*)) destroy; - this->public.set_cert_encoding = (void (*) (certreq_payload_t*,cert_encoding_t))set_cert_encoding; - this->public.get_cert_encoding = (cert_encoding_t (*) (certreq_payload_t*))get_cert_encoding; - this->public.set_data = (void (*) (certreq_payload_t*,chunk_t))set_data; - this->public.get_data_clone = (chunk_t (*) (certreq_payload_t*))get_data_clone; - this->public.get_data = (chunk_t (*) (certreq_payload_t*))get_data; + this->public.create_keyid_enumerator = (enumerator_t*(*)(certreq_payload_t*))create_keyid_enumerator; + this->public.get_cert_type = (certificate_type_t(*)(certreq_payload_t*))get_cert_type; + this->public.add_keyid = (void(*)(certreq_payload_t*, chunk_t keyid))add_keyid; /* private variables */ this->critical = FALSE; this->next_payload = NO_PAYLOAD; - this->payload_length =CERTREQ_PAYLOAD_HEADER_LENGTH; - this->certreq_data = chunk_empty; + this->payload_length = CERTREQ_PAYLOAD_HEADER_LENGTH; + this->data = chunk_empty; + this->encoding = 0; - return (&(this->public)); + return &this->public; } /* * Described in header */ -certreq_payload_t *certreq_payload_create_from_cacert(identification_t *id) +certreq_payload_t *certreq_payload_create_type(certificate_type_t type) { - x509_t *cacert; - rsa_public_key_t *pubkey; - chunk_t keyid; - certreq_payload_t *this; + private_certreq_payload_t *this = (private_certreq_payload_t*)certreq_payload_create(); - cacert = charon->credentials->get_auth_certificate(charon->credentials, AUTH_CA, id); - if (cacert == NULL) + switch (type) { - /* no such CA cert */ - return NULL; + case CERT_X509: + this->encoding = ENC_X509_SIGNATURE; + break; + default: + DBG1(DBG_ENC, "certificate type %N not supported in requests", + certificate_type_names, type); + free(this); + return NULL; } - - this = certreq_payload_create(); - pubkey = cacert->get_public_key(cacert); - keyid = pubkey->get_keyid(pubkey); - - DBG2(DBG_IKE, "requesting certificate issued by '%D'", id); - DBG2(DBG_IKE, " with keyid %#B", &keyid); - - this->set_cert_encoding(this, CERT_X509_SIGNATURE); - this->set_data(this, keyid); - return this; + return &this->public; } -/* - * Described in header - */ -certreq_payload_t *certreq_payload_create_from_cacerts(void) -{ - certreq_payload_t *this; - chunk_t keyids; - u_char *pos; - ca_info_t *cainfo; - - iterator_t *iterator = charon->credentials->create_cainfo_iterator(charon->credentials); - int count = iterator->get_count(iterator); - - if (count == 0) - { - iterator->destroy(iterator); - return NULL; - } - - this = certreq_payload_create(); - keyids = chunk_alloc(count * HASH_SIZE_SHA1); - pos = keyids.ptr; - - while (iterator->iterate(iterator, (void**)&cainfo)) - { - x509_t *cacert = cainfo->get_certificate(cainfo); - chunk_t keyid = cacert->get_keyid(cacert); - - DBG2(DBG_IKE, "requesting certificate issued by '%D'", cacert->get_subject(cacert)); - DBG2(DBG_IKE, " with keyid %#B", &keyid); - memcpy(pos, keyid.ptr, keyid.len); - pos += HASH_SIZE_SHA1; - } - iterator->destroy(iterator); - - this->set_cert_encoding(this, CERT_X509_SIGNATURE); - this->set_data(this, keyids); - free(keyids.ptr); - return this; -} diff --git a/src/charon/encoding/payloads/certreq_payload.h b/src/charon/encoding/payloads/certreq_payload.h index 2985fdae1..9ef4fb9d9 100644 --- a/src/charon/encoding/payloads/certreq_payload.h +++ b/src/charon/encoding/payloads/certreq_payload.h @@ -1,10 +1,3 @@ -/** - * @file certreq_payload.h - * - * @brief Interface of certreq_payload_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup certreq_payload certreq_payload + * @{ @ingroup payloads */ #ifndef CERTREQ_PAYLOAD_H_ @@ -32,26 +32,13 @@ typedef struct certreq_payload_t certreq_payload_t; /** * Length of a CERTREQ payload without the CERTREQ data in bytes. - * - * @ingroup payloads */ #define CERTREQ_PAYLOAD_HEADER_LENGTH 5 - /** - * @brief Class representing an IKEv2 CERTREQ payload. + * Class representing an IKEv2 CERTREQ payload. * * The CERTREQ payload format is described in RFC section 3.7. - * This is just a dummy implementation to fullfill the standards - * requirements. A full implementation would offer setters/getters - * for the different encoding types. - * - * @b Constructors: - * - certreq_payload_create() - * - * @todo Implement payload functionality. - * - * @ingroup payloads */ struct certreq_payload_t { /** @@ -60,85 +47,46 @@ struct certreq_payload_t { payload_t payload_interface; /** - * @brief Set the CERT encoding. - * - * @param this calling certreq_payload_t object - * @param encoding CERT encoding - */ - void (*set_cert_encoding) (certreq_payload_t *this, cert_encoding_t encoding); - - /** - * @brief Get the CERT encoding. - * - * @param this calling certreq_payload_t object - * @return Encoding of the CERT - */ - cert_encoding_t (*get_cert_encoding) (certreq_payload_t *this); - - /** - * @brief Set the CERTREQ data. - * - * Data are getting cloned. + * Create an enumerator over contained keyids. * - * @param this calling certreq_payload_t object - * @param data CERTREQ data as chunk_t + * @return enumerator over chunk_t's. */ - void (*set_data) (certreq_payload_t *this, chunk_t data); + enumerator_t* (*create_keyid_enumerator)(certreq_payload_t *this); /** - * @brief Get the CERTREQ data. - * - * Returned data are a copy of the internal one. + * Get the type of contained certificate keyids. * - * @param this calling certreq_payload_t object - * @return CERTREQ data as chunk_t + * @return certificate keyid type */ - chunk_t (*get_data_clone) (certreq_payload_t *this); + certificate_type_t (*get_cert_type)(certreq_payload_t *this); /** - * @brief Get the CERTREQ data. - * - * Returned data are NOT copied. + * Add a certificates keyid to the payload. * - * @param this calling certreq_payload_t object - * @return CERTREQ data as chunk_t + * @param keyid keyid of the trusted certifcate + * @return */ - chunk_t (*get_data) (certreq_payload_t *this); + void (*add_keyid)(certreq_payload_t *this, chunk_t keyid); /** - * @brief Destroys an certreq_payload_t object. - * - * @param this certreq_payload_t object to destroy + * Destroys an certreq_payload_t object. */ void (*destroy) (certreq_payload_t *this); }; /** - * @brief Creates an empty certreq_payload_t object. + * Creates an empty certreq_payload_t object. * - * @return certreq_payload_t object - * - * @ingroup payloads + * @return certreq payload */ certreq_payload_t *certreq_payload_create(void); /** - * @brief Creates a certreq_payload_t object from a ca certificate - * - * @param id subject distinguished name of CA certificate - * @return certreq_payload_t object - * - * @ingroup payloads - */ -certreq_payload_t *certreq_payload_create_from_cacert(identification_t *id); - -/** - * @brief Creates a certreq_payload_t object from all ca certificates - * - * @return certreq_payload_t object + * Creates an empty certreq_payload_t for a kind of certificates. * - * @ingroup payloads + * @param type type of the added keyids + * @return certreq payload */ -certreq_payload_t *certreq_payload_create_from_cacerts(void); +certreq_payload_t *certreq_payload_create_type(certificate_type_t type); -#endif /* CERTREQ_PAYLOAD_H_ */ +#endif /* CERTREQ_PAYLOAD_H_ @} */ diff --git a/src/charon/encoding/payloads/configuration_attribute.c b/src/charon/encoding/payloads/configuration_attribute.c index afd08c6be..1d0c00926 100644 --- a/src/charon/encoding/payloads/configuration_attribute.c +++ b/src/charon/encoding/payloads/configuration_attribute.c @@ -1,10 +1,3 @@ -/** - * @file configuration_attribute.c - * - * @brief Implementation of configuration_attribute_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,8 @@ * 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. + * + * $Id$ */ #include diff --git a/src/charon/encoding/payloads/configuration_attribute.h b/src/charon/encoding/payloads/configuration_attribute.h index 5c4f65b14..151237360 100644 --- a/src/charon/encoding/payloads/configuration_attribute.h +++ b/src/charon/encoding/payloads/configuration_attribute.h @@ -1,10 +1,3 @@ -/** - * @file configuration_attribute.h - * - * @brief Interface of configuration_attribute_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup configuration_attribute configuration_attribute + * @{ @ingroup payloads */ #ifndef CONFIGURATION_ATTRIBUTE_H_ @@ -33,15 +33,11 @@ typedef struct configuration_attribute_t configuration_attribute_t; /** * Configuration attribute header length in bytes. - * - * @ingroup payloads */ #define CONFIGURATION_ATTRIBUTE_HEADER_LENGTH 4 /** * Type of the attribute, as in IKEv2 RFC 3.15.1. - * - * @ingroup payloads */ enum configuration_attribute_type_t { INTERNAL_IP4_ADDRESS = 1, @@ -62,20 +58,13 @@ enum configuration_attribute_type_t { /** * enum names for configuration_attribute_type_t. - * - * @ingroup payloads */ extern enum_name_t *configuration_attribute_type_names; /** - * @brief Class representing an IKEv2-CONFIGURATION Attribute. + * Class representing an IKEv2-CONFIGURATION Attribute. * * The CONFIGURATION ATTRIBUTE format is described in RFC section 3.15.1. - * - * @b Constructors: - * - configuration_attribute_create() - * - * @ingroup payloads */ struct configuration_attribute_t { /** @@ -84,64 +73,55 @@ struct configuration_attribute_t { payload_t payload_interface; /** - * @brief Returns the currently set value of the attribute. + * Returns the currently set value of the attribute. * * @warning Returned data are not copied. * - * @param this calling configuration_attribute_t object * @return chunk_t pointing to the value */ chunk_t (*get_value) (configuration_attribute_t *this); /** - * @brief Sets the value of the attribute. + * Sets the value of the attribute. * - * @warning Value is getting copied. + * Value is getting copied. * - * @param this calling configuration_attribute_t object * @param value chunk_t pointing to the value to set */ void (*set_value) (configuration_attribute_t *this, chunk_t value); /** - * @brief Sets the type of the attribute. + * Sets the type of the attribute. * - * @param this calling configuration_attribute_t object * @param type type to set (most significant bit is set to zero) */ void (*set_type) (configuration_attribute_t *this, u_int16_t type); /** - * @brief get the type of the attribute. + * get the type of the attribute. * - * @param this calling configuration_attribute_t object * @return type of the value */ u_int16_t (*get_type) (configuration_attribute_t *this); /** - * @brief get the length of an attribute. + * get the length of an attribute. * - * @param this calling configuration_attribute_t object * @return type of the value */ u_int16_t (*get_length) (configuration_attribute_t *this); /** - * @brief Destroys an configuration_attribute_t object. - * - * @param this configuration_attribute_t object to destroy + * Destroys an configuration_attribute_t object. */ void (*destroy) (configuration_attribute_t *this); }; /** - * @brief Creates an empty configuration_attribute_t object. + * Creates an empty configuration_attribute_t object. * * @return created configuration_attribute_t object - * - * @ingroup payloads */ configuration_attribute_t *configuration_attribute_create(void); -#endif /* CONFIGURATION_ATTRIBUTE_H_*/ +#endif /* CONFIGURATION_ATTRIBUTE_H_ @} */ diff --git a/src/charon/encoding/payloads/cp_payload.c b/src/charon/encoding/payloads/cp_payload.c index 380ed9681..844182a5f 100644 --- a/src/charon/encoding/payloads/cp_payload.c +++ b/src/charon/encoding/payloads/cp_payload.c @@ -1,10 +1,3 @@ -/** - * @file cp_payload.c - * - * @brief Implementation of cp_payload_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,8 @@ * 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. + * + * $Id$ */ #include diff --git a/src/charon/encoding/payloads/cp_payload.h b/src/charon/encoding/payloads/cp_payload.h index 27ff41005..d2e94197c 100644 --- a/src/charon/encoding/payloads/cp_payload.h +++ b/src/charon/encoding/payloads/cp_payload.h @@ -1,10 +1,3 @@ -/** - * @file cp_payload.h - * - * @brief Interface of cp_payload_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup cp_payload cp_payload + * @{ @ingroup payloads */ #ifndef CP_PAYLOAD_H_ @@ -34,15 +34,11 @@ typedef struct cp_payload_t cp_payload_t; /** * CP_PAYLOAD length in bytes without any proposal substructure. - * - * @ingroup payloads */ #define CP_PAYLOAD_HEADER_LENGTH 8 /** * Config Type of an Configuration Payload. - * - * @ingroup payloads */ enum config_type_t { CFG_REQUEST = 1, @@ -53,20 +49,13 @@ enum config_type_t { /** * enum name for config_type_t. - * - * @ingroup payloads */ extern enum_name_t *config_type_names; /** - * @brief Class representing an IKEv2-CP Payload. + * Class representing an IKEv2-CP Payload. * * The CP Payload format is described in RFC section 3.15. - * - * @b Constructors: - * - cp_payload_create() - * - * @ingroup payloads */ struct cp_payload_t { /** @@ -75,58 +64,50 @@ struct cp_payload_t { payload_t payload_interface; /** - * @brief Creates an iterator of stored configuration_attribute_t objects. + * Creates an iterator of stored configuration_attribute_t objects. * * When deleting an attribute using this iterator, the length of this * configuration_attribute_t has to be refreshed by calling get_length()! * - * @param this calling cp_payload_t object * @return created iterator_t object */ iterator_t *(*create_attribute_iterator) (cp_payload_t *this); /** - * @brief Adds a configuration_attribute_t object to this object. + * Adds a configuration_attribute_t object to this object. * * The added configuration_attribute_t object is getting destroyed in * destroy function of cp_payload_t. * - * @param this calling cp_payload_t object * @param attribute configuration_attribute_t object to add */ void (*add_configuration_attribute) (cp_payload_t *this, configuration_attribute_t *attribute); /** - * @brief Set the config type. + * Set the config type. * - * @param this calling cp_payload_t object * @param config_type config_type_t to set */ void (*set_config_type) (cp_payload_t *this,config_type_t config_type); /** - * @brief Get the config type. + * Get the config type. * - * @param this calling cp_payload_t object * @return config_type_t */ config_type_t (*get_config_type) (cp_payload_t *this); /** - * @brief Destroys an cp_payload_t object. - * - * @param this cp_payload_t object to destroy + * Destroys an cp_payload_t object. */ void (*destroy) (cp_payload_t *this); }; /** - * @brief Creates an empty cp_payload_t object + * Creates an empty cp_payload_t object * * @return cp_payload_t object - * - * @ingroup payloads */ cp_payload_t *cp_payload_create(void); -#endif /*CP_PAYLOAD_H_*/ +#endif /*CP_PAYLOAD_H_ @} */ diff --git a/src/charon/encoding/payloads/delete_payload.c b/src/charon/encoding/payloads/delete_payload.c index 1d42a3af2..928e6523a 100644 --- a/src/charon/encoding/payloads/delete_payload.c +++ b/src/charon/encoding/payloads/delete_payload.c @@ -1,10 +1,3 @@ -/** - * @file delete_payload.c - * - * @brief Implementation of delete_payload_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,8 @@ * 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. + * + * $Id$ */ #include diff --git a/src/charon/encoding/payloads/delete_payload.h b/src/charon/encoding/payloads/delete_payload.h index 508f7fba2..150a87470 100644 --- a/src/charon/encoding/payloads/delete_payload.h +++ b/src/charon/encoding/payloads/delete_payload.h @@ -1,10 +1,3 @@ -/** - * @file delete_payload.h - * - * @brief Interface of delete_payload_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup delete_payload delete_payload + * @{ @ingroup payloads */ #ifndef DELETE_PAYLOAD_H_ @@ -32,22 +32,13 @@ typedef struct delete_payload_t delete_payload_t; /** * Length of a delete payload without the SPI in bytes. - * - * @ingroup payloads */ #define DELETE_PAYLOAD_HEADER_LENGTH 8 /** - * @brief Class representing an IKEv2 DELETE payload. + * Class representing an IKEv2 DELETE payload. * * The DELETE payload format is described in RFC section 3.11. - * - * @b Constructors: - * - delete_payload_create() - * - * @todo Implement better setter/getters - * - * @ingroup payloads */ struct delete_payload_t { /** @@ -56,47 +47,40 @@ struct delete_payload_t { payload_t payload_interface; /** - * @brief Get the protocol ID. + * Get the protocol ID. * - * @param this calling delete_payload_t object * @return protocol ID */ protocol_id_t (*get_protocol_id) (delete_payload_t *this); /** - * @brief Add an SPI to the list of deleted SAs. + * Add an SPI to the list of deleted SAs. * - * @param this calling delete_payload_t object * @param spi spi to add */ void (*add_spi) (delete_payload_t *this, u_int32_t spi); /** - * @brief Get an iterator over the SPIs. + * Get an iterator over the SPIs. * * The iterate() function returns a pointer to a u_int32_t SPI. * - * @param this calling delete_payload_t object * @return iterator over SPIs */ iterator_t *(*create_spi_iterator) (delete_payload_t *this); /** - * @brief Destroys an delete_payload_t object. - * - * @param this delete_payload_t object to destroy + * Destroys an delete_payload_t object. */ void (*destroy) (delete_payload_t *this); }; /** - * @brief Creates an empty delete_payload_t object. + * Creates an empty delete_payload_t object. * * @param protocol_id protocol, such as AH|ESP * @return delete_payload_t object - * - * @ingroup payloads */ delete_payload_t *delete_payload_create(protocol_id_t protocol_id); -#endif /* DELETE_PAYLOAD_H_ */ +#endif /* DELETE_PAYLOAD_H_ @} */ diff --git a/src/charon/encoding/payloads/eap_payload.c b/src/charon/encoding/payloads/eap_payload.c index da2498c5e..551c908c6 100644 --- a/src/charon/encoding/payloads/eap_payload.c +++ b/src/charon/encoding/payloads/eap_payload.c @@ -1,10 +1,3 @@ -/** - * @file eap_payload.c - * - * @brief Implementation of eap_payload_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,8 @@ * 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. + * + * $Id$ */ #include diff --git a/src/charon/encoding/payloads/eap_payload.h b/src/charon/encoding/payloads/eap_payload.h index e4f8663c2..fe723ef63 100644 --- a/src/charon/encoding/payloads/eap_payload.h +++ b/src/charon/encoding/payloads/eap_payload.h @@ -1,10 +1,3 @@ -/** - * @file eap_payload.h - * - * @brief Interface of eap_payload_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup eap_payload eap_payload + * @{ @ingroup payloads */ #ifndef EAP_PAYLOAD_H_ @@ -32,20 +32,13 @@ typedef struct eap_payload_t eap_payload_t; /** * Length of a EAP payload without the EAP Message in bytes. - * - * @ingroup payloads */ #define EAP_PAYLOAD_HEADER_LENGTH 4 /** - * @brief Class representing an IKEv2 EAP payload. + * Class representing an IKEv2 EAP payload. * * The EAP payload format is described in RFC section 3.16. - * - * @b Constructors: - * - eap_payload_create() - * - * @ingroup payloads */ struct eap_payload_t { @@ -55,79 +48,68 @@ struct eap_payload_t { payload_t payload_interface; /** - * @brief Set the contained EAP data. + * Set the contained EAP data. * * This contains the FULL EAP message starting with "code". * Chunk gets cloned. * - * @param this calling eap_payload_t object * @param message EAP data */ void (*set_data) (eap_payload_t *this, chunk_t data); /** - * @brief Get the contained EAP data. + * Get the contained EAP data. * * This contains the FULL EAP message starting with "code". * - * @param this calling eap_payload_t object * @return EAP data (pointer to internal data) */ chunk_t (*get_data) (eap_payload_t *this); /** - * @brief Get the EAP code. + * Get the EAP code. * - * @param this calling eap_payload_t object * @return EAP message as chunk_t */ eap_code_t (*get_code) (eap_payload_t *this); /** - * @brief Get the EAP identifier. + * Get the EAP identifier. * - * @param this calling eap_payload_t object * @return unique identifier */ u_int8_t (*get_identifier) (eap_payload_t *this); /** - * @brief Get the EAP method type. + * Get the EAP method type. * - * @param this calling eap_payload_t object * @param vendor pointer receiving vendor identifier * @return EAP method type, vendor specific if vendor != 0 */ eap_type_t (*get_type) (eap_payload_t *this, u_int32_t *vendor); /** - * @brief Destroys an eap_payload_t object. - * - * @param this eap_payload_t object to destroy + * Destroys an eap_payload_t object. */ void (*destroy) (eap_payload_t *this); }; /** - * @brief Creates an empty eap_payload_t object. + * Creates an empty eap_payload_t object. * * @return eap_payload_t object - * - * @ingroup payloads */ eap_payload_t *eap_payload_create(void); /** - * @brief Creates an eap_payload_t object with data. + * Creates an eap_payload_t object with data. * * @return eap_payload_t object - * - * @ingroup payloads */ eap_payload_t *eap_payload_create_data(chunk_t data); /** - * @brief Creates an eap_payload_t object with a code. + * Creates an eap_payload_t object with a code. * * Could should be either EAP_SUCCESS/EAP_FAILURE, use * constructor above otherwise. @@ -135,19 +117,15 @@ eap_payload_t *eap_payload_create_data(chunk_t data); * @param code EAP status code * @param identifier EAP identifier to use in payload * @return eap_payload_t object - * - * @ingroup payloads */ eap_payload_t *eap_payload_create_code(eap_code_t code, u_int8_t identifier); /** - * @brief Creates an eap_payload_t EAP_RESPONSE containing an EAP_NAK. + * Creates an eap_payload_t EAP_RESPONSE containing an EAP_NAK. * * @param identifier EAP identifier to use in payload * @return eap_payload_t object - * - * @ingroup payloads */ eap_payload_t *eap_payload_create_nak(u_int8_t identifier); -#endif /* EAP_PAYLOAD_H_ */ +#endif /* EAP_PAYLOAD_H_ @} */ diff --git a/src/charon/encoding/payloads/encodings.c b/src/charon/encoding/payloads/encodings.c index 55a7cf132..7db9e189f 100644 --- a/src/charon/encoding/payloads/encodings.c +++ b/src/charon/encoding/payloads/encodings.c @@ -1,10 +1,3 @@ -/** - * @file encodings.c - * - * @brief String mappings of encoding_type_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,8 @@ * 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. + * + * $Id$ */ diff --git a/src/charon/encoding/payloads/encodings.h b/src/charon/encoding/payloads/encodings.h index 5e07fbfab..b4658e285 100644 --- a/src/charon/encoding/payloads/encodings.h +++ b/src/charon/encoding/payloads/encodings.h @@ -1,10 +1,3 @@ -/** - * @file encodings.h - * - * @brief Definition of encoding_type_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup encodings encodings + * @{ @ingroup payloads */ #ifndef ENCODINGS_H_ @@ -30,7 +30,7 @@ typedef struct encoding_rule_t encoding_rule_t; #include /** - * @brief All different kinds of encoding types. + * All different kinds of encoding types. * * Each field of an IKEv2-Message (in header or payload) * which has to be parsed or generated differently has its own @@ -40,8 +40,6 @@ typedef struct encoding_rule_t encoding_rule_t; * from PRIVATE USE space. Also the substructures * of specific payload types get their own payload_id * from PRIVATE_USE space. See IKEv2-Draft for more informations. - * - * @ingroup payloads */ enum encoding_type_t { @@ -114,7 +112,7 @@ enum encoding_type_t { U_INT_64, /** - * @brief represents a RESERVED_BIT used in FLAG-Bytes. + * represents a RESERVED_BIT used in FLAG-Bytes. * * When generating, the next bit is set to zero and the current write * position is moved one bit forward. @@ -128,7 +126,7 @@ enum encoding_type_t { RESERVED_BIT, /** - * @brief represents a RESERVED_BYTE. + * represents a RESERVED_BYTE. * * When generating, the next byte is set to zero and the current write * position is moved one byte forward. @@ -499,21 +497,16 @@ enum encoding_type_t { /** * enum name for encoding_type_t - * - * @ingroup payloads */ extern enum_name_t *encoding_type_names; /** + * Rule how to en-/decode a payload field. + * * An encoding rule is a mapping of a specific encoding type to * a location in the data struct where the current field is stored to * or read from. - * - * For examples see files in this directory. - * * This rules are used by parser and generator. - * - * @ingroup payloads */ struct encoding_rule_t { @@ -534,4 +527,4 @@ struct encoding_rule_t { u_int32_t offset; }; -#endif /*ENCODINGS_H_*/ +#endif /*ENCODINGS_H_ @} */ diff --git a/src/charon/encoding/payloads/encryption_payload.c b/src/charon/encoding/payloads/encryption_payload.c index 23b6e8d9f..cdfda3d5e 100644 --- a/src/charon/encoding/payloads/encryption_payload.c +++ b/src/charon/encoding/payloads/encryption_payload.c @@ -1,10 +1,3 @@ -/** - * @file encryption_payload.c - * - * @brief Implementation of encryption_payload_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,8 @@ * 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. + * + * $Id$ */ #include diff --git a/src/charon/encoding/payloads/encryption_payload.h b/src/charon/encoding/payloads/encryption_payload.h index 7cf53619f..817006409 100644 --- a/src/charon/encoding/payloads/encryption_payload.h +++ b/src/charon/encoding/payloads/encryption_payload.h @@ -1,9 +1,3 @@ -/** - * @file encryption_payload.h - * - * @brief Interface of encryption_payload_t. - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -18,6 +12,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup encryption_payload encryption_payload + * @{ @ingroup payloads */ #ifndef ENCRYPTION_PAYLOAD_H_ @@ -33,14 +34,12 @@ typedef struct encryption_payload_t encryption_payload_t; /** * Encrpytion payload length in bytes without IV and following data. - * - * @ingroup payloads */ #define ENCRYPTION_PAYLOAD_HEADER_LENGTH 4 /** - * @brief The encryption payload as described in RFC section 3.14. + * The encryption payload as described in RFC section 3.14. * * Before any crypt/decrypt/sign/verify operation can occur, * the transforms must be set. After that, a parsed encryption payload @@ -51,11 +50,6 @@ typedef struct encryption_payload_t encryption_payload_t; * must be builded after generation of all payloads and the encryption * of the encryption payload. * Signature verificatin is done before decryption. - * - * @b Constructors: - * - encryption_payload_create() - * - * @ingroup payloads */ struct encryption_payload_t { /** @@ -64,29 +58,26 @@ struct encryption_payload_t { payload_t payload_interface; /** - * @brief Creates an iterator for all contained payloads. + * Creates an iterator for all contained payloads. * - * @warning iterator_t object has to get destroyed by the caller. + * iterator_t object has to get destroyed by the caller. * - * @param this calling encryption_payload_t object - * @param[in] forward iterator direction (TRUE: front to end) + * @param forward iterator direction (TRUE: front to end) * return created iterator_t object */ iterator_t *(*create_payload_iterator) (encryption_payload_t *this, bool forward); /** - * @brief Adds a payload to this encryption payload. + * Adds a payload to this encryption payload. * - * @param this calling encryption_payload_t object * @param payload payload_t object to add */ void (*add_payload) (encryption_payload_t *this, payload_t *payload); /** - * @brief Reove the last payload in the contained payload list. + * Reove the last payload in the contained payload list. * - * @param this calling encryption_payload_t object - * @param[out] payload removed payload + * @param payload removed payload * @return * - SUCCESS, or * - NOT_FOUND if list empty @@ -94,15 +85,14 @@ struct encryption_payload_t { status_t (*remove_first_payload) (encryption_payload_t *this, payload_t **payload); /** - * @brief Get the number of payloads. + * Get the number of payloads. * - * @param this calling encryption_payload_t object * @return number of contained payloads */ size_t (*get_payload_count) (encryption_payload_t *this); /** - * @brief Set transforms to use. + * Set transforms to use. * * To decryption, encryption, signature building and verifying, * the payload needs a crypter and a signer object. @@ -110,34 +100,29 @@ struct encryption_payload_t { * @warning Do NOT call this function again after encryption, since * the signer must be the same while encrypting and signature building! * - * @param this calling encryption_payload_t * @param crypter crypter_t to use for data de-/encryption * @param signer signer_t to use for data signing/verifying */ void (*set_transforms) (encryption_payload_t *this, crypter_t *crypter, signer_t *signer); /** - * @brief Generate and encrypt contained payloads. + * Generate and encrypt contained payloads. * * This function generates the content for added payloads * and encrypts them. Signature is not built, since we need * additional data (the full message). * - * @param this calling encryption_payload_t - * @return - * - SUCCESS, or - * - INVALID_STATE if transforms not set + * @return SUCCESS, or INVALID_STATE if transforms not set */ status_t (*encrypt) (encryption_payload_t *this); /** - * @brief Decrypt and parse contained payloads. + * Decrypt and parse contained payloads. * * This function decrypts the contained data. After, * the payloads are parsed internally and are accessible * via the iterator. * - * @param this calling encryption_payload_t * @return * - SUCCESS, or * - INVALID_STATE if transforms not set, or @@ -146,13 +131,12 @@ struct encryption_payload_t { status_t (*decrypt) (encryption_payload_t *this); /** - * @brief Build the signature. + * Build the signature. * * The signature is built over the FULL message, so the header * and every payload (inclusive this one) must already be generated. * The generated message is supplied via the data paramater. * - * @param this calling encryption_payload_t * @param data chunk contains the already generated message * @return * - SUCCESS, or @@ -161,13 +145,12 @@ struct encryption_payload_t { status_t (*build_signature) (encryption_payload_t *this, chunk_t data); /** - * @brief Verify the signature. + * Verify the signature. * * Since the signature is built over the full message, we need * this data to do the verification. The message data * is supplied via the data argument. * - * @param this calling encryption_payload_t * @param data chunk contains the message * @return * - SUCCESS, or @@ -177,21 +160,16 @@ struct encryption_payload_t { status_t (*verify_signature) (encryption_payload_t *this, chunk_t data); /** - * @brief Destroys an encryption_payload_t object. - * - * @param this encryption_payload_t object to destroy + * Destroys an encryption_payload_t object. */ void (*destroy) (encryption_payload_t *this); }; /** - * @brief Creates an empty encryption_payload_t object. + * Creates an empty encryption_payload_t object. * * @return encryption_payload_t object - * - * @ingroup payloads */ encryption_payload_t *encryption_payload_create(void); - -#endif /*ENCRYPTION_PAYLOAD_H_*/ +#endif /*ENCRYPTION_PAYLOAD_H_ @} */ diff --git a/src/charon/encoding/payloads/endpoint_notify.c b/src/charon/encoding/payloads/endpoint_notify.c index 98bfb2ea0..bef51a249 100644 --- a/src/charon/encoding/payloads/endpoint_notify.c +++ b/src/charon/encoding/payloads/endpoint_notify.c @@ -1,10 +1,3 @@ -/** - * @file endpoint_notify.c - * - * @brief Implementation of endpoint_notify_t. - * - */ - /* * Copyright (C) 2007 Tobias Brunner * Hochschule fuer Technik Rapperswil @@ -18,6 +11,8 @@ * 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. + * + * $Id$ */ #include "endpoint_notify.h" diff --git a/src/charon/encoding/payloads/endpoint_notify.h b/src/charon/encoding/payloads/endpoint_notify.h index 4a3a68f95..9203dc8ec 100644 --- a/src/charon/encoding/payloads/endpoint_notify.h +++ b/src/charon/encoding/payloads/endpoint_notify.h @@ -1,10 +1,3 @@ -/** - * @file endpoint_notify.h - * - * @brief Interface of endpoint_notify_t. - * - */ - /* * Copyright (C) 2007 Tobias Brunner * Hochschule fuer Technik Rapperswil @@ -18,8 +11,14 @@ * 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. + * + * $Id$ */ +/** + * @defgroup endpoint_notify endpoint_notify + * @{ @ingroup payloads + */ #ifndef ENDPOINT_NOTIFY_H_ #define ENDPOINT_NOTIFY_H_ @@ -36,9 +35,7 @@ typedef struct endpoint_notify_t endpoint_notify_t; #include /** - * @brief P2P endpoint families. - * - * @ingroup payloads + * P2P endpoint families. */ enum p2p_endpoint_family_t { @@ -53,9 +50,7 @@ enum p2p_endpoint_family_t { }; /** - * @brief P2P endpoint types. - * - * @ingroup payloads + * P2P endpoint types. */ enum p2p_endpoint_type_t { @@ -75,128 +70,106 @@ enum p2p_endpoint_type_t { /** * enum name for p2p_endpoint_type_t. - * - * @ingroup payloads */ extern enum_name_t *p2p_endpoint_type_names; /** - * @brief Class representing a P2P_ENDPOINT notify. In fact it's not + * Class representing a P2P_ENDPOINT notify. In fact it's not * the notify per se, but the notification data of that notify that is * handled with this class. - * - * @b Constructors: - * - endpoint_notify_create() - * - endpoint_notify_create_from_host() - * - * @ingroup payloads */ struct endpoint_notify_t { /** - * @brief Returns the priority of this endpoint. + * Returns the priority of this endpoint. * - * @param this object * @return priority */ u_int32_t (*get_priority) (endpoint_notify_t *this); /** - * @brief Sets the priority of this endpoint. + * Sets the priority of this endpoint. * - * @param this object * @param priority priority */ void (*set_priority) (endpoint_notify_t *this, u_int32_t priority); /** - * @brief Returns the endpoint type of this endpoint. + * Returns the endpoint type of this endpoint. * - * @param this object * @return endpoint type */ p2p_endpoint_type_t (*get_type) (endpoint_notify_t *this); /** - * @brief Returns the endpoint family of this endpoint. + * Returns the endpoint family of this endpoint. * - * @param this object * @return endpoint family */ p2p_endpoint_family_t (*get_family) (endpoint_notify_t *this); /** - * @brief Returns the host of this endpoint. + * Returns the host of this endpoint. * - * @param this object * @return host */ host_t *(*get_host) (endpoint_notify_t *this); /** - * @brief Returns the base of this endpoint. + * Returns the base of this endpoint. * * If this is not a SERVER_REFLEXIVE endpoint, the returned host is the same * as the one returned by get_host. * - * @param this object * @return host */ host_t *(*get_base) (endpoint_notify_t *this); /** - * @brief Generates a notification payload from this endpoint. + * Generates a notification payload from this endpoint. * - * @param this object * @return built notify_payload_t */ notify_payload_t *(*build_notify) (endpoint_notify_t *this); /** - * @brief Clones an endpoint_notify_t object. + * Clones an endpoint_notify_t object. * - * @param this endpoint_notify_t object to clone - * @return cloned object + * @return cloned object */ endpoint_notify_t *(*clone) (endpoint_notify_t *this); /** - * @brief Destroys an endpoint_notify_t object. - * - * @param this endpoint_notify_t object to destroy + * Destroys an endpoint_notify_t object. */ void (*destroy) (endpoint_notify_t *this); }; /** - * @brief Creates an empty endpoint_notify_t object. + * Creates an empty endpoint_notify_t object. * * @return created endpoint_notify_t object - * - * @ingroup payloads */ endpoint_notify_t *endpoint_notify_create(void); /** - * @brief Creates an endpoint_notify_t object from a host. + * Creates an endpoint_notify_t object from a host. * * @param type the endpoint type * @param host host to base the notify on (gets cloned) * @param base base of the endpoint, applies only to reflexive endpoints (gets cloned) * @return created endpoint_notify_t object - * - * @ingroup payloads */ -endpoint_notify_t *endpoint_notify_create_from_host(p2p_endpoint_type_t type, host_t *host, host_t *base); +endpoint_notify_t *endpoint_notify_create_from_host(p2p_endpoint_type_t type, + host_t *host, host_t *base); /** - * @brief Creates an endpoint_notify_t object from a notify payload. + * Creates an endpoint_notify_t object from a notify payload. * * @param notify the notify payload * @return - created endpoint_notify_t object * - NULL if invalid payload - * @ingroup payloads */ endpoint_notify_t *endpoint_notify_create_from_payload(notify_payload_t *notify); -#endif /*ENDPOINT_NOTIFY_H_*/ +#endif /*ENDPOINT_NOTIFY_H_ @} */ diff --git a/src/charon/encoding/payloads/id_payload.c b/src/charon/encoding/payloads/id_payload.c index aef8f6b7e..f3168db81 100644 --- a/src/charon/encoding/payloads/id_payload.c +++ b/src/charon/encoding/payloads/id_payload.c @@ -1,10 +1,3 @@ -/** - * @file id_payload.h - * - * @brief Interface of id_payload_t. - * - */ - /* * Copyright (C) 2007 Tobias Brunner * Copyright (C) 2005-2006 Martin Willi @@ -21,6 +14,8 @@ * 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. + * + * $Id$ */ #include diff --git a/src/charon/encoding/payloads/id_payload.h b/src/charon/encoding/payloads/id_payload.h index 8e9322b4a..a45b0a14c 100644 --- a/src/charon/encoding/payloads/id_payload.h +++ b/src/charon/encoding/payloads/id_payload.h @@ -1,10 +1,3 @@ -/** - * @file id_payload.h - * - * @brief Interface of id_payload_t. - * - */ - /* * Copyright (C) 2007 Tobias Brunner * Copyright (C) 2005-2006 Martin Willi @@ -20,8 +13,14 @@ * 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. + * + * $Id$ */ +/** + * @defgroup id_payload id_payload + * @{ @ingroup payloads + */ #ifndef ID_PAYLOAD_H_ #define ID_PAYLOAD_H_ @@ -34,8 +33,6 @@ typedef struct id_payload_t id_payload_t; /** * Length of a id payload without the data in bytes. - * - * @ingroup payloads */ #define ID_PAYLOAD_HEADER_LENGTH 8 @@ -43,12 +40,6 @@ typedef struct id_payload_t id_payload_t; * Object representing an IKEv2 ID payload. * * The ID payload format is described in RFC section 3.5. - * - * @b Constructors: - * - id_payload_create_from_identification() - * - id_payload_create() - * - * @ingroup payloads */ struct id_payload_t { /** @@ -57,90 +48,77 @@ struct id_payload_t { payload_t payload_interface; /** - * @brief Set the ID type. + * Set the ID type. * - * @param this calling id_payload_t object * @param type Type of ID */ void (*set_id_type) (id_payload_t *this, id_type_t type); /** - * @brief Get the ID type. + * Get the ID type. * - * @param this calling id_payload_t object * @return type of the ID */ id_type_t (*get_id_type) (id_payload_t *this); /** - * @brief Set the ID data. + * Set the ID data. * * Data are getting cloned. * - * @param this calling id_payload_t object * @param data ID data as chunk_t */ void (*set_data) (id_payload_t *this, chunk_t data); /** - * @brief Get the ID data. + * Get the ID data. * * Returned data are a copy of the internal one * - * @param this calling id_payload_t object * @return ID data as chunk_t */ chunk_t (*get_data_clone) (id_payload_t *this); /** - * @brief Get the ID data. + * Get the ID data. * * Returned data are NOT copied. * - * @param this calling id_payload_t object * @return ID data as chunk_t */ chunk_t (*get_data) (id_payload_t *this); /** - * @brief Creates an identification object of this id payload. + * Creates an identification object of this id payload. * * Returned object has to get destroyed by the caller. * - * @param this calling id_payload_t object * @return identification_t object */ identification_t *(*get_identification) (id_payload_t *this); /** - * @brief Destroys an id_payload_t object. - * - * @param this id_payload_t object to destroy + * Destroys an id_payload_t object. */ void (*destroy) (id_payload_t *this); }; /** - * @brief Creates an empty id_payload_t object. + * Creates an empty id_payload_t object. * * @param payload_type one of ID_INITIATOR, ID_RESPONDER * @return id_payload_t object - * - * @ingroup payloads */ id_payload_t *id_payload_create(payload_type_t payload_type); /** - * @brief Creates an id_payload_t from an existing identification_t object. + * Creates an id_payload_t from an existing identification_t object. * * @param payload_type one of ID_INITIATOR, ID_RESPONDER * @param identification identification_t object * @return id_payload_t object - * - * @ingroup payloads */ -id_payload_t *id_payload_create_from_identification(payload_type_t payload_type, identification_t *identification); - - +id_payload_t *id_payload_create_from_identification(payload_type_t payload_type, + identification_t *identification); -#endif /* ID_PAYLOAD_H_ */ +#endif /* ID_PAYLOAD_H_ @} */ diff --git a/src/charon/encoding/payloads/ike_header.c b/src/charon/encoding/payloads/ike_header.c index 3a171b095..dbe0ee2a1 100644 --- a/src/charon/encoding/payloads/ike_header.c +++ b/src/charon/encoding/payloads/ike_header.c @@ -1,10 +1,3 @@ -/** - * @file ike_header.c - * - * @brief Implementation of ike_header_t. - * - */ - /* * Copyright (C) 2007 Tobias Brunner * Copyright (C) 2005-2006 Martin Willi @@ -20,6 +13,8 @@ * 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. + * + * $Id$ */ /* offsetof macro */ diff --git a/src/charon/encoding/payloads/ike_header.h b/src/charon/encoding/payloads/ike_header.h index e80964482..d66db9374 100644 --- a/src/charon/encoding/payloads/ike_header.h +++ b/src/charon/encoding/payloads/ike_header.h @@ -1,10 +1,3 @@ -/** - * @file ike_header.h - * - * @brief Interface of ike_header_t. - * - */ - /* * Copyright (C) 2007 Tobias Brunner * Copyright (C) 2005-2006 Martin Willi @@ -20,6 +13,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup ike_header ike_header + * @{ @ingroup payloads */ #ifndef IKE_HEADER_H_ @@ -33,38 +33,28 @@ typedef struct ike_header_t ike_header_t; /** * Major Version of IKEv2. - * - * @ingroup payloads */ #define IKE_MAJOR_VERSION 2 /** * Minor Version of IKEv2. - * - * @ingroup payloads */ #define IKE_MINOR_VERSION 0 /** * Flag in IKEv2-Header. Always 0. - * - * @ingroup payloads */ #define HIGHER_VERSION_SUPPORTED_FLAG 0 /** * Length of IKE Header in Bytes. - * - * @ingroup payloads */ #define IKE_HEADER_LENGTH 28 /** - * @brief Different types of IKE-Exchanges. + * Different types of IKE-Exchanges. * - * See Draft for different types. - * - * @ingroup payloads + * See RFC for different types. */ enum exchange_type_t{ @@ -102,23 +92,16 @@ enum exchange_type_t{ /** * enum name for exchange_type_t - * - * @ingroup payloads */ extern enum_name_t *exchange_type_names; /** - * @brief An object of this type represents an IKEv2 header and is used to + * An object of this type represents an IKEv2 header and is used to * generate and parse IKEv2 headers. * * The header format of an IKEv2-Message is compatible to the * ISAKMP-Header format to allow implementations supporting * both versions of the IKE-protocol. - * - * @b Constructors: - * - ike_header_create() - * - * @ingroup payloads */ struct ike_header_t { /** @@ -127,141 +110,121 @@ struct ike_header_t { payload_t payload_interface; /** - * @brief Get the initiator spi. + * Get the initiator spi. * - * @param this ike_header_t object * @return initiator_spi */ u_int64_t (*get_initiator_spi) (ike_header_t *this); /** - * @brief Set the initiator spi. + * Set the initiator spi. * - * @param this ike_header_t object * @param initiator_spi initiator_spi */ void (*set_initiator_spi) (ike_header_t *this, u_int64_t initiator_spi); /** - * @brief Get the responder spi. + * Get the responder spi. * - * @param this ike_header_t object * @return responder_spi */ u_int64_t (*get_responder_spi) (ike_header_t *this); /** - * @brief Set the responder spi. + * Set the responder spi. * - * @param this ike_header_t object * @param responder_spi responder_spi */ void (*set_responder_spi) (ike_header_t *this, u_int64_t responder_spi); /** - * @brief Get the major version. + * Get the major version. * - * @param this ike_header_t object * @return major version */ u_int8_t (*get_maj_version) (ike_header_t *this); /** - * @brief Get the minor version. + * Get the minor version. * - * @param this ike_header_t object * @return minor version */ u_int8_t (*get_min_version) (ike_header_t *this); /** - * @brief Get the response flag. + * Get the response flag. * - * @param this ike_header_t object * @return response flag */ bool (*get_response_flag) (ike_header_t *this); /** - * @brief Set the response flag- + * Set the response flag- * - * @param this ike_header_t object * @param response response flag * */ void (*set_response_flag) (ike_header_t *this, bool response); /** - * @brief Get "higher version supported"-flag. + * Get "higher version supported"-flag. * - * @param this ike_header_t object * @return version flag */ bool (*get_version_flag) (ike_header_t *this); /** - * @brief Get the initiator flag. + * Get the initiator flag. * - * @param this ike_header_t object * @return initiator flag */ bool (*get_initiator_flag) (ike_header_t *this); /** - * @brief Set the initiator flag. + * Set the initiator flag. * - * @param this ike_header_t object * @param initiator initiator flag - * */ void (*set_initiator_flag) (ike_header_t *this, bool initiator); /** - * @brief Get the exchange type. + * Get the exchange type. * - * @param this ike_header_t object - * @return exchange type + * @return exchange type */ u_int8_t (*get_exchange_type) (ike_header_t *this); /** - * @brief Set the exchange type. + * Set the exchange type. * - * @param this ike_header_t object * @param exchange_type exchange type */ void (*set_exchange_type) (ike_header_t *this, u_int8_t exchange_type); /** - * @brief Get the message id. + * Get the message id. * - * @param this ike_header_t object * @return message id */ u_int32_t (*get_message_id) (ike_header_t *this); /** - * @brief Set the message id. + * Set the message id. * - * @param this ike_header_t object * @param initiator_spi message id */ void (*set_message_id) (ike_header_t *this, u_int32_t message_id); /** - * @brief Destroys a ike_header_t object. - * - * @param this ike_header_t object to destroy + * Destroys a ike_header_t object. */ void (*destroy) (ike_header_t *this); }; /** - * @brief Create an ike_header_t object + * Create an ike_header_t object * * @return ike_header_t object - * - * @ingroup payloads */ ike_header_t *ike_header_create(void); -#endif /*IKE_HEADER_H_*/ +#endif /*IKE_HEADER_H_ @} */ diff --git a/src/charon/encoding/payloads/ke_payload.c b/src/charon/encoding/payloads/ke_payload.c index 8926b15f9..200ec4d94 100644 --- a/src/charon/encoding/payloads/ke_payload.c +++ b/src/charon/encoding/payloads/ke_payload.c @@ -1,10 +1,3 @@ -/** - * @file ke_payload.c - * - * @brief Implementation of ke_payload_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,8 @@ * 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. + * + * $Id$ */ #include diff --git a/src/charon/encoding/payloads/ke_payload.h b/src/charon/encoding/payloads/ke_payload.h index 52be8ffe3..7cd2448ba 100644 --- a/src/charon/encoding/payloads/ke_payload.h +++ b/src/charon/encoding/payloads/ke_payload.h @@ -1,10 +1,3 @@ -/** - * @file ke_payload.h - * - * @brief Interface of ke_payload_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup ke_payload ke_payload + * @{ @ingroup payloads */ #ifndef KE_PAYLOAD_H_ @@ -34,20 +34,13 @@ typedef struct ke_payload_t ke_payload_t; /** * KE payload length in bytes without any key exchange data. - * - * @ingroup payloads */ #define KE_PAYLOAD_HEADER_LENGTH 8 /** - * @brief Class representing an IKEv2-KE Payload. + * Class representing an IKEv2-KE Payload. * * The KE Payload format is described in RFC section 3.4. - * - * @b Constructors: - * - ke_payload_create() - * - * @ingroup payloads */ struct ke_payload_t { /** @@ -56,66 +49,58 @@ struct ke_payload_t { payload_t payload_interface; /** - * @brief Returns the currently set key exchange data of this KE payload. + * Returns the currently set key exchange data of this KE payload. * * @warning Returned data are not copied. * - * @param this calling ke_payload_t object * @return chunk_t pointing to the value */ chunk_t (*get_key_exchange_data) (ke_payload_t *this); /** - * @brief Sets the key exchange data of this KE payload. + * Sets the key exchange data of this KE payload. * - * @warning Value is getting copied. + * Value is getting copied. * - * @param this calling ke_payload_t object - * @param key_exchange_data chunk_t pointing to the value to set + * @param key_exchange_data chunk_t pointing to the value to set */ void (*set_key_exchange_data) (ke_payload_t *this, chunk_t key_exchange_data); /** - * @brief Gets the Diffie-Hellman Group Number of this KE payload. + * Gets the Diffie-Hellman Group Number of this KE payload. * - * @param this calling ke_payload_t object - * @return DH Group Number of this payload + * @return DH Group Number of this payload */ diffie_hellman_group_t (*get_dh_group_number) (ke_payload_t *this); /** - * @brief Sets the Diffie-Hellman Group Number of this KE payload. + * Sets the Diffie-Hellman Group Number of this KE payload. * - * @param this calling ke_payload_t object * @param dh_group_number DH Group to set */ - void (*set_dh_group_number) (ke_payload_t *this, diffie_hellman_group_t dh_group_number); + void (*set_dh_group_number) (ke_payload_t *this, + diffie_hellman_group_t dh_group_number); /** - * @brief Destroys an ke_payload_t object. - * - * @param this ke_payload_t object to destroy + * Destroys an ke_payload_t object. */ void (*destroy) (ke_payload_t *this); }; /** - * @brief Creates an empty ke_payload_t object + * Creates an empty ke_payload_t object * * @return ke_payload_t object - * - * @ingroup payloads */ ke_payload_t *ke_payload_create(void); /** - * @brief Creates a ke_payload_t from a diffie_hellman_t + * Creates a ke_payload_t from a diffie_hellman_t * * @param diffie_hellman diffie hellman object containing group and key * @return ke_payload_t object - * - * @ingroup payloads */ -ke_payload_t *ke_payload_create_from_diffie_hellman(diffie_hellman_t *diffie_hellman); +ke_payload_t *ke_payload_create_from_diffie_hellman( + diffie_hellman_t *diffie_hellman); -#endif /* KE_PAYLOAD_H_ */ +#endif /* KE_PAYLOAD_H_ @} */ diff --git a/src/charon/encoding/payloads/nonce_payload.c b/src/charon/encoding/payloads/nonce_payload.c index 8e1fc505e..4afe3807e 100644 --- a/src/charon/encoding/payloads/nonce_payload.c +++ b/src/charon/encoding/payloads/nonce_payload.c @@ -1,10 +1,3 @@ -/** - * @file nonce_payload.h - * - * @brief Implementation of nonce_payload_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,8 @@ * 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. + * + * $Id$ */ /* offsetof macro */ diff --git a/src/charon/encoding/payloads/nonce_payload.h b/src/charon/encoding/payloads/nonce_payload.h index 96d83b028..b0a63a28a 100644 --- a/src/charon/encoding/payloads/nonce_payload.h +++ b/src/charon/encoding/payloads/nonce_payload.h @@ -1,10 +1,3 @@ -/** - * @file nonce_payload.h - * - * @brief Interface of nonce_payload_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup nonce_payload nonce_payload + * @{ @ingroup payloads */ #ifndef NONCE_PAYLOAD_H_ @@ -31,17 +31,11 @@ typedef struct nonce_payload_t nonce_payload_t; /** * Nonce size in bytes for nonces sending to other peer. - * - * @warning Nonce size MUST be between 16 and 256 bytes. - * - * @ingroup payloads */ #define NONCE_SIZE 16 /** * Length of a nonce payload without a nonce in bytes. - * - * @ingroup payloads */ #define NONCE_PAYLOAD_HEADER_LENGTH 4 @@ -49,11 +43,6 @@ typedef struct nonce_payload_t nonce_payload_t; * Object representing an IKEv2 Nonce payload. * * The Nonce payload format is described in RFC section 3.3. - * - * @b Constructors: - * - nonce_payload_create() - * - * @ingroup payloads */ struct nonce_payload_t { /** @@ -62,38 +51,30 @@ struct nonce_payload_t { payload_t payload_interface; /** - * @brief Set the nonce value. + * Set the nonce value. * - * @param this calling nonce_payload_t object * @param nonce chunk containing the nonce, will be cloned */ void (*set_nonce) (nonce_payload_t *this, chunk_t nonce); /** - * @brief Get the nonce value. + * Get the nonce value. * - * @param this calling nonce_payload_t object * @return a chunk containing the cloned nonce */ chunk_t (*get_nonce) (nonce_payload_t *this); /** - * @brief Destroys an nonce_payload_t object. - * - * @param this nonce_payload_t object to destroy + * Destroys an nonce_payload_t object. */ void (*destroy) (nonce_payload_t *this); }; /** - * @brief Creates an empty nonce_payload_t object + * Creates an empty nonce_payload_t object * * @return nonce_payload_t object - * - * @ingroup payloads */ - nonce_payload_t *nonce_payload_create(void); - -#endif /*NONCE_PAYLOAD_H_*/ +#endif /*NONCE_PAYLOAD_H_ @} */ diff --git a/src/charon/encoding/payloads/notify_payload.c b/src/charon/encoding/payloads/notify_payload.c index d32257af6..0950f6b8a 100644 --- a/src/charon/encoding/payloads/notify_payload.c +++ b/src/charon/encoding/payloads/notify_payload.c @@ -1,10 +1,3 @@ -/** - * @file notify_payload.c - * - * @brief Implementation of notify_payload_t. - * - */ - /* * Copyright (C) 2006-2007 Tobias Brunner * Copyright (C) 2006 Daniel Roethlisberger @@ -21,6 +14,8 @@ * 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. + * + * $Id$ */ #include diff --git a/src/charon/encoding/payloads/notify_payload.h b/src/charon/encoding/payloads/notify_payload.h index 03f61d473..2f147c929 100644 --- a/src/charon/encoding/payloads/notify_payload.h +++ b/src/charon/encoding/payloads/notify_payload.h @@ -1,10 +1,3 @@ -/** - * @file notify_payload.h - * - * @brief Interface of notify_payload_t. - * - */ - /* * Copyright (C) 2006-2007 Tobias Brunner * Copyright (C) 2006 Daniel Roethlisberger @@ -21,8 +14,14 @@ * 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. + * + * $Id$ */ +/** + * @defgroup notify_payload notify_payload + * @{ @ingroup payloads + */ #ifndef NOTIFY_PAYLOAD_H_ #define NOTIFY_PAYLOAD_H_ @@ -37,17 +36,13 @@ typedef struct notify_payload_t notify_payload_t; /** * Notify payload length in bytes without any spi and notification data. - * - * @ingroup payloads */ #define NOTIFY_PAYLOAD_HEADER_LENGTH 8 /** - * @brief Notify message types. + * Notify message types. * * See IKEv2 RFC 3.10.1. - * - * @ingroup payloads */ enum notify_type_t { /* notify error messages */ @@ -109,30 +104,18 @@ enum notify_type_t { /** * enum name for notify_type_t. - * - * @ingroup payloads */ extern enum_name_t *notify_type_names; /** * enum name for notify_type_t (shorter strings). - * - * @ingroup payloads */ extern enum_name_t *notify_type_short_names; /** - * @brief Class representing an IKEv2-Notify Payload. + * Class representing an IKEv2-Notify Payload. * * The Notify Payload format is described in Draft section 3.10. - * - * @b Constructors: - * - notify_payload_create() - * - notify_payload_create_from_protocol_and_type() - * - * @todo Build specified constructor/getter for notify's - * - * @ingroup payloads */ struct notify_payload_t { /** @@ -141,104 +124,91 @@ struct notify_payload_t { payload_t payload_interface; /** - * @brief Gets the protocol id of this payload. + * Gets the protocol id of this payload. * - * @param this calling notify_payload_t object * @return protocol id of this payload */ u_int8_t (*get_protocol_id) (notify_payload_t *this); /** - * @brief Sets the protocol id of this payload. + * Sets the protocol id of this payload. * - * @param this calling notify_payload_t object * @param protocol_id protocol id to set */ void (*set_protocol_id) (notify_payload_t *this, u_int8_t protocol_id); /** - * @brief Gets the notify message type of this payload. + * Gets the notify message type of this payload. * - * @param this calling notify_payload_t object * @return notify message type of this payload */ notify_type_t (*get_notify_type) (notify_payload_t *this); /** - * @brief Sets notify message type of this payload. + * Sets notify message type of this payload. * - * @param this calling notify_payload_t object * @param type notify message type to set */ void (*set_notify_type) (notify_payload_t *this, notify_type_t type); /** - * @brief Returns the currently set spi of this payload. + * Returns the currently set spi of this payload. * * This is only valid for notifys with protocol AH|ESP * - * @param this calling notify_payload_t object * @return SPI value */ u_int32_t (*get_spi) (notify_payload_t *this); /** - * @brief Sets the spi of this payload. + * Sets the spi of this payload. * * This is only valid for notifys with protocol AH|ESP * - * @param this calling notify_payload_t object * @param spi SPI value */ void (*set_spi) (notify_payload_t *this, u_int32_t spi); /** - * @brief Returns the currently set notification data of payload. + * Returns the currently set notification data of payload. * - * @warning Returned data are not copied. + * Returned data are not copied. * - * @param this calling notify_payload_t object * @return chunk_t pointing to the value */ chunk_t (*get_notification_data) (notify_payload_t *this); /** - * @brief Sets the notification data of this payload. + * Sets the notification data of this payload. * * @warning Value is getting copied. * - * @param this calling notify_payload_t object * @param notification_data chunk_t pointing to the value to set */ - void (*set_notification_data) (notify_payload_t *this, chunk_t notification_data); + void (*set_notification_data) (notify_payload_t *this, + chunk_t notification_data); /** - * @brief Destroys an notify_payload_t object. - * - * @param this notify_payload_t object to destroy + * Destroys an notify_payload_t object. */ void (*destroy) (notify_payload_t *this); }; /** - * @brief Creates an empty notify_payload_t object + * Creates an empty notify_payload_t object * * @return created notify_payload_t object - * - * @ingroup payloads */ notify_payload_t *notify_payload_create(void); /** - * @brief Creates an notify_payload_t object of specific type for specific protocol id. + * Creates an notify_payload_t object of specific type for specific protocol id. * * @param protocol_id protocol id (IKE, AH or ESP) * @param type notify type (see notify_type_t) * @return notify_payload_t object - * - * @ingroup payloads */ -notify_payload_t *notify_payload_create_from_protocol_and_type(protocol_id_t protocol_id, notify_type_t type); - +notify_payload_t *notify_payload_create_from_protocol_and_type( + protocol_id_t protocol_id, notify_type_t type); -#endif /*NOTIFY_PAYLOAD_H_*/ +#endif /*NOTIFY_PAYLOAD_H_ @} */ diff --git a/src/charon/encoding/payloads/payload.c b/src/charon/encoding/payloads/payload.c index 2c51c60de..6e6a6e281 100644 --- a/src/charon/encoding/payloads/payload.c +++ b/src/charon/encoding/payloads/payload.c @@ -1,11 +1,3 @@ -/** - * @file payload.c - * - * @brief Generic constructor to the payload_t interface. - * - * - */ - /* * Copyright (C) 2007 Tobias Brunner * Copyright (C) 2005-2006 Martin Willi @@ -21,6 +13,8 @@ * 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. + * + * $Id$ */ diff --git a/src/charon/encoding/payloads/payload.h b/src/charon/encoding/payloads/payload.h index ab902d755..a2c6e296d 100644 --- a/src/charon/encoding/payloads/payload.h +++ b/src/charon/encoding/payloads/payload.h @@ -1,10 +1,3 @@ -/** - * @file payload.h - * - * @brief Interface payload_t. - * - */ - /* * Copyright (C) 2007 Tobias Brunner * Copyright (C) 2005-2006 Martin Willi @@ -20,6 +13,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup payload payload + * @{ @ingroup payloads */ #ifndef PAYLOAD_H_ @@ -33,12 +33,10 @@ typedef struct payload_t payload_t; /** - * @brief Payload-Types of a IKEv2-Message. + * Payload-Types of a IKEv2-Message. * * Header and substructures are also defined as * payload types with values from PRIVATE USE space. - * - * @ingroup payloads */ enum payload_type_t{ @@ -204,80 +202,65 @@ extern enum_name_t *payload_type_names; extern enum_name_t *payload_type_short_names; /** - * @brief Generic interface for all payload types (incl.header and substructures). + * Generic interface for all payload types (incl.header and substructures). * * To handle all kinds of payloads on a generic way, this interface must * be implemented by every payload. This allows parser_t/generator_t a simple * handling of all payloads. - * - * @b Constructors: - * - payload_create() with the payload to instantiate. - * - * @ingroup payloads */ struct payload_t { /** - * @brief Get encoding rules for this payload. + * Get encoding rules for this payload. * - * @param this calling object - * @param[out] rules location to store pointer of first rule - * @param[out] rule_count location to store number of rules + * @param rules location to store pointer of first rule + * @param rule_count location to store number of rules */ void (*get_encoding_rules) (payload_t *this, encoding_rule_t **rules, size_t *rule_count); /** - * @brief Get type of payload. + * Get type of payload. * - * @param this calling object - * @return type of this payload + * @return type of this payload */ payload_type_t (*get_type) (payload_t *this); /** - * @brief Get type of next payload or NO_PAYLOAD (0) if this is the last one. + * Get type of next payload or NO_PAYLOAD (0) if this is the last one. * - * @param this calling object - * @return type of next payload + * @return type of next payload */ payload_type_t (*get_next_type) (payload_t *this); /** - * @brief Set type of next payload. + * Set type of next payload. * - * @param this calling object - * @param type type of next payload + * @param type type of next payload */ void (*set_next_type) (payload_t *this,payload_type_t type); /** - * @brief Get length of payload. + * Get length of payload. * - * @param this calling object - * @return length of this payload + * @return length of this payload */ size_t (*get_length) (payload_t *this); /** - * @brief Verifies payload structure and makes consistence check. + * Verifies payload structure and makes consistence check. * - * @param this calling object - * @return - * - SUCCESS - * - FAILED if consistence not given + * @return SUCCESS, FAILED if consistence not given */ status_t (*verify) (payload_t *this); /** - * @brief Destroys a payload and all included substructures. - * - * @param this payload to destroy + * Destroys a payload and all included substructures. */ void (*destroy) (payload_t *this); }; /** - * @brief Create an empty payload. + * Create an empty payload. * * Useful for the parser, who wants a generic constructor for all payloads. * It supports all payload_t methods. If a payload type is not known, @@ -288,4 +271,4 @@ struct payload_t { */ payload_t *payload_create(payload_type_t type); -#endif /*PAYLOAD_H_*/ +#endif /*PAYLOAD_H_ @} */ diff --git a/src/charon/encoding/payloads/proposal_substructure.c b/src/charon/encoding/payloads/proposal_substructure.c index 182d2b6e8..0baa5c286 100644 --- a/src/charon/encoding/payloads/proposal_substructure.c +++ b/src/charon/encoding/payloads/proposal_substructure.c @@ -1,10 +1,3 @@ -/** - * @file proposal_substructure.h - * - * @brief Implementation of proposal_substructure_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,8 @@ * 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. + * + * $Id$ */ #include diff --git a/src/charon/encoding/payloads/proposal_substructure.h b/src/charon/encoding/payloads/proposal_substructure.h index 93a8d7b2f..c3a57ab22 100644 --- a/src/charon/encoding/payloads/proposal_substructure.h +++ b/src/charon/encoding/payloads/proposal_substructure.h @@ -1,10 +1,3 @@ -/** - * @file proposal_substructure.h - * - * @brief Interface of proposal_substructure_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup proposal_substructure proposal_substructure + * @{ @ingroup payloads */ #ifndef PROPOSAL_SUBSTRUCTURE_H_ @@ -35,20 +35,13 @@ typedef struct proposal_substructure_t proposal_substructure_t; /** * Length of the proposal substructure header (without spi). - * - * @ingroup payloads */ #define PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH 8 /** - * @brief Class representing an IKEv2-PROPOSAL SUBSTRUCTURE. + * Class representing an IKEv2-PROPOSAL SUBSTRUCTURE. * * The PROPOSAL SUBSTRUCTURE format is described in RFC section 3.3.1. - * - * @b Constructors: - * - proposal_substructure_create() - * - * @ingroup payloads */ struct proposal_substructure_t { /** @@ -57,150 +50,126 @@ struct proposal_substructure_t { payload_t payload_interface; /** - * @brief Creates an iterator of stored transform_substructure_t objects. - * - * @warning The created iterator has to get destroyed by the caller! - * When deleting any transform over this iterator, call - * get_size to make sure the length and number values are ok. + * Creates an iterator of stored transform_substructure_t objects. * - * @param this calling proposal_substructure_t object * @param forward iterator direction (TRUE: front to end) * @return created iterator_t object */ - iterator_t *(*create_transform_substructure_iterator) (proposal_substructure_t *this, bool forward); + iterator_t *(*create_transform_substructure_iterator) ( + proposal_substructure_t *this, bool forward); /** - * @brief Adds a transform_substructure_t object to this object. - * - * @warning The added transform_substructure_t object is - * getting destroyed in destroy function of proposal_substructure_t. + * Adds a transform_substructure_t object to this object. * - * @param this calling proposal_substructure_t object - * @param transform transform_substructure_t object to add + * @param transform transform_substructure_t object to add */ - void (*add_transform_substructure) (proposal_substructure_t *this,transform_substructure_t *transform); + void (*add_transform_substructure) (proposal_substructure_t *this, + transform_substructure_t *transform); /** - * @brief Sets the proposal number of current proposal. + * Sets the proposal number of current proposal. * - * @param this calling proposal_substructure_t object - * @param id proposal number to set + * @param id proposal number to set */ - void (*set_proposal_number) (proposal_substructure_t *this,u_int8_t proposal_number); + void (*set_proposal_number) (proposal_substructure_t *this, + u_int8_t proposal_number); /** - * @brief get proposal number of current proposal. + * get proposal number of current proposal. * - * @param this calling proposal_substructure_t object * @return proposal number of current proposal substructure. */ u_int8_t (*get_proposal_number) (proposal_substructure_t *this); /** - * @brief get the number of transforms in current proposal. + * get the number of transforms in current proposal. * - * @param this calling proposal_substructure_t object * @return transform count in current proposal */ size_t (*get_transform_count) (proposal_substructure_t *this); /** - * @brief get size of the set spi in bytes. + * get size of the set spi in bytes. * - * @param this calling proposal_substructure_t object * @return size of the spi in bytes */ size_t (*get_spi_size) (proposal_substructure_t *this); /** - * @brief Sets the protocol id of current proposal. + * Sets the protocol id of current proposal. * - * @param this calling proposal_substructure_t object - * @param id protocol id to set + * @param id protocol id to set */ - void (*set_protocol_id) (proposal_substructure_t *this,u_int8_t protocol_id); + void (*set_protocol_id) (proposal_substructure_t *this, + u_int8_t protocol_id); /** - * @brief get protocol id of current proposal. + * get protocol id of current proposal. * - * @param this calling proposal_substructure_t object * @return protocol id of current proposal substructure. */ u_int8_t (*get_protocol_id) (proposal_substructure_t *this); /** - * @brief Sets the next_payload field of this substructure + * Sets the next_payload field of this substructure * * If this is the last proposal, next payload field is set to 0, * otherwise to 2 * - * @param this calling proposal_substructure_t object * @param is_last When TRUE, next payload field is set to 0, otherwise to 2 */ void (*set_is_last_proposal) (proposal_substructure_t *this, bool is_last); /** - * @brief Returns the currently set SPI of this proposal. - * - * @warning Returned data are not copied - * - * @param this calling proposal_substructure_t object - * @return chunk_t pointing to the value + * Returns the currently set SPI of this proposal. + * + * @return chunk_t pointing to the value */ chunk_t (*get_spi) (proposal_substructure_t *this); /** - * @brief Sets the SPI of the current proposal. + * Sets the SPI of the current proposal. * * @warning SPI is getting copied * - * @param this calling proposal_substructure_t object - * @param spi chunk_t pointing to the value to set + * @param spi chunk_t pointing to the value to set */ void (*set_spi) (proposal_substructure_t *this, chunk_t spi); /** - * @brief Get a proposal_t from the propsal_substructure_t. + * Get a proposal_t from the propsal_substructure_t. * - * @param this calling proposal_substructure_t object * @return proposal_t */ proposal_t * (*get_proposal) (proposal_substructure_t *this); /** - * @brief Clones an proposal_substructure_t object. + * Clones an proposal_substructure_t object. * - * @param this proposal_substructure_t object to clone * @return cloned object */ proposal_substructure_t* (*clone) (proposal_substructure_t *this); /** - * @brief Destroys an proposal_substructure_t object. - * - * @param this proposal_substructure_t object to destroy + * Destroys an proposal_substructure_t object. */ void (*destroy) (proposal_substructure_t *this); }; /** - * @brief Creates an empty proposal_substructure_t object + * Creates an empty proposal_substructure_t object * * @return proposal_substructure_t object - * - * @ingroup payloads */ proposal_substructure_t *proposal_substructure_create(void); /** - * @brief Creates a proposal_substructure_t from a proposal_t. + * Creates a proposal_substructure_t from a proposal_t. * * @param proposal proposal to build a substruct out of it * @return proposal_substructure_t object - * - * @ingroup payloads */ -proposal_substructure_t *proposal_substructure_create_from_proposal(proposal_t *proposal); - +proposal_substructure_t *proposal_substructure_create_from_proposal( + proposal_t *proposal); -#endif /*PROPOSAL_SUBSTRUCTURE_H_*/ +#endif /*PROPOSAL_SUBSTRUCTURE_H_ @} */ diff --git a/src/charon/encoding/payloads/sa_payload.c b/src/charon/encoding/payloads/sa_payload.c index 304f1b64c..950e16d25 100644 --- a/src/charon/encoding/payloads/sa_payload.c +++ b/src/charon/encoding/payloads/sa_payload.c @@ -1,10 +1,3 @@ -/** - * @file sa_payload.c - * - * @brief Implementation of sa_payload_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,8 @@ * 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. + * + * $Id$ */ #include diff --git a/src/charon/encoding/payloads/sa_payload.h b/src/charon/encoding/payloads/sa_payload.h index 67d687857..97beecf4e 100644 --- a/src/charon/encoding/payloads/sa_payload.h +++ b/src/charon/encoding/payloads/sa_payload.h @@ -1,10 +1,3 @@ -/** - * @file sa_payload.h - * - * @brief Interface of sa_payload_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup sa_payload sa_payload + * @{ @ingroup payloads */ #ifndef SA_PAYLOAD_H_ @@ -33,24 +33,13 @@ typedef struct sa_payload_t sa_payload_t; /** * SA_PAYLOAD length in bytes without any proposal substructure. - * - * @ingroup payloads */ #define SA_PAYLOAD_HEADER_LENGTH 4 /** - * @brief Class representing an IKEv2-SA Payload. + * Class representing an IKEv2-SA Payload. * * The SA Payload format is described in RFC section 3.3. - * - * @b Constructors: - * - sa_payload_create() - * - sa_payload_create_from_ike_proposals() - * - sa_payload_create_from_proposal() - * - * @todo Add support of algorithms without specified keylength in get_proposals and get_ike_proposals. - * - * @ingroup payloads */ struct sa_payload_t { /** @@ -59,83 +48,70 @@ struct sa_payload_t { payload_t payload_interface; /** - * @brief Creates an iterator of stored proposal_substructure_t objects. + * Creates an iterator of stored proposal_substructure_t objects. * - * @warning The created iterator has to get destroyed by the caller! - * - * @warning When deleting an proposal using this iterator, - * the length of this transform substructure has to be refreshed - * by calling get_length()! + * When deleting an proposal using this iterator, + * the length of this transform substructure has to be refreshed + * by calling get_length()! * - * @param this calling sa_payload_t object - * @param[in] forward iterator direction (TRUE: front to end) - * @return created iterator_t object + * @param forward iterator direction (TRUE: front to end) + * @return created iterator_t object */ - iterator_t *(*create_proposal_substructure_iterator) (sa_payload_t *this, bool forward); + iterator_t *(*create_proposal_substructure_iterator) (sa_payload_t *this, + bool forward); /** - * @brief Adds a proposal_substructure_t object to this object. - * - * @warning The added proposal_substructure_t object is - * getting destroyed in destroy function of sa_payload_t. + * Adds a proposal_substructure_t object to this object. * - * @param this calling sa_payload_t object * @param proposal proposal_substructure_t object to add */ - void (*add_proposal_substructure) (sa_payload_t *this,proposal_substructure_t *proposal); + void (*add_proposal_substructure) (sa_payload_t *this, + proposal_substructure_t *proposal); /** - * @brief Gets the proposals in this payload as a list. + * Gets the proposals in this payload as a list. * * @return a list containing proposal_t s */ linked_list_t *(*get_proposals) (sa_payload_t *this); /** - * @brief Add a child proposal (AH/ESP) to the payload. + * Add a child proposal (AH/ESP) to the payload. * * @param proposal child proposal to add to the payload */ void (*add_proposal) (sa_payload_t *this, proposal_t *proposal); /** - * @brief Destroys an sa_payload_t object. - * - * @param this sa_payload_t object to destroy + * Destroys an sa_payload_t object. */ void (*destroy) (sa_payload_t *this); }; /** - * @brief Creates an empty sa_payload_t object + * Creates an empty sa_payload_t object * * @return created sa_payload_t object - * - * @ingroup payloads */ sa_payload_t *sa_payload_create(void); /** - * @brief Creates a sa_payload_t object from a list of proposals. + * Creates a sa_payload_t object from a list of proposals. * * @param proposals list of proposals to build the payload from * @return sa_payload_t object - * - * @ingroup payloads */ sa_payload_t *sa_payload_create_from_proposal_list(linked_list_t *proposals); /** - * @brief Creates a sa_payload_t object from a single proposal. + * Creates a sa_payload_t object from a single proposal. * * This is only for convenience. Use sa_payload_create_from_proposal_list * if you want to add more than one proposal. * * @param proposal proposal from which the payload should be built. * @return sa_payload_t object - * - * @ingroup payloads */ sa_payload_t *sa_payload_create_from_proposal(proposal_t *proposal); -#endif /*SA_PAYLOAD_H_*/ +#endif /*SA_PAYLOAD_H_ @} */ diff --git a/src/charon/encoding/payloads/traffic_selector_substructure.c b/src/charon/encoding/payloads/traffic_selector_substructure.c index 573139bf3..58ca408d5 100644 --- a/src/charon/encoding/payloads/traffic_selector_substructure.c +++ b/src/charon/encoding/payloads/traffic_selector_substructure.c @@ -1,10 +1,3 @@ -/** - * @file traffic_selector_substructure.c - * - * @brief Interface of traffic_selector_substructure_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,8 @@ * 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. + * + * $Id$ */ #include "traffic_selector_substructure.h" diff --git a/src/charon/encoding/payloads/traffic_selector_substructure.h b/src/charon/encoding/payloads/traffic_selector_substructure.h index 14efccc89..1355b6599 100644 --- a/src/charon/encoding/payloads/traffic_selector_substructure.h +++ b/src/charon/encoding/payloads/traffic_selector_substructure.h @@ -1,10 +1,3 @@ -/** - * @file traffic_selector_substructure.h - * - * @brief Interface of traffic_selector_substructure_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,8 +12,14 @@ * 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. + * + * $Id$ */ +/** + * @defgroup traffic_selector_substructure traffic_selector_substructure + * @{ @ingroup payloads + */ #ifndef TRAFFIC_SELECTOR_SUBSTRUCTURE_H_ #define TRAFFIC_SELECTOR_SUBSTRUCTURE_H_ @@ -34,21 +33,13 @@ typedef struct traffic_selector_substructure_t traffic_selector_substructure_t; /** * Length of a TRAFFIC SELECTOR SUBSTRUCTURE without start and end address. - * - * @ingroup payloads */ #define TRAFFIC_SELECTOR_HEADER_LENGTH 8 /** - * @brief Class representing an IKEv2 TRAFFIC SELECTOR. + * Class representing an IKEv2 TRAFFIC SELECTOR. * * The TRAFFIC SELECTOR format is described in RFC section 3.13.1. - * - * @b Constructors: - * - traffic_selector_substructure_create() - * - traffic_selector_substructure_create_from_traffic_selector() - * - * @ingroup payloads */ struct traffic_selector_substructure_t { /** @@ -57,116 +48,106 @@ struct traffic_selector_substructure_t { payload_t payload_interface; /** - * @brief Get the type of Traffic selector. + * Get the type of Traffic selector. * - * @param this calling traffic_selector_substructure_t object * @return type of traffic selector * */ ts_type_t (*get_ts_type) (traffic_selector_substructure_t *this); /** - * @brief Set the type of Traffic selector. + * Set the type of Traffic selector. * - * @param this calling traffic_selector_substructure_t object * @param ts_type type of traffic selector */ - void (*set_ts_type) (traffic_selector_substructure_t *this,ts_type_t ts_type); + void (*set_ts_type) (traffic_selector_substructure_t *this, + ts_type_t ts_type); /** - * @brief Get the IP protocol ID of Traffic selector. + * Get the IP protocol ID of Traffic selector. * - * @param this calling traffic_selector_substructure_t object * @return type of traffic selector * */ u_int8_t (*get_protocol_id) (traffic_selector_substructure_t *this); /** - * @brief Set the IP protocol ID of Traffic selector + * Set the IP protocol ID of Traffic selector * - * @param this calling traffic_selector_substructure_t object * @param protocol_id protocol ID of traffic selector */ - void (*set_protocol_id) (traffic_selector_substructure_t *this,u_int8_t protocol_id); + void (*set_protocol_id) (traffic_selector_substructure_t *this, + u_int8_t protocol_id); /** - * @brief Get the start port and address as host_t object. + * Get the start port and address as host_t object. * * Returned host_t object has to get destroyed by the caller. * - * @param this calling traffic_selector_substructure_t object * @return start host as host_t object * */ host_t *(*get_start_host) (traffic_selector_substructure_t *this); /** - * @brief Set the start port and address as host_t object. + * Set the start port and address as host_t object. * - * @param this calling traffic_selector_substructure_t object * @param start_host start host as host_t object */ - void (*set_start_host) (traffic_selector_substructure_t *this,host_t *start_host); + void (*set_start_host) (traffic_selector_substructure_t *this, + host_t *start_host); /** - * @brief Get the end port and address as host_t object. + * Get the end port and address as host_t object. * * Returned host_t object has to get destroyed by the caller. * - * @param this calling traffic_selector_substructure_t object * @return end host as host_t object * */ host_t *(*get_end_host) (traffic_selector_substructure_t *this); /** - * @brief Set the end port and address as host_t object. + * Set the end port and address as host_t object. * - * @param this calling traffic_selector_substructure_t object * @param end_host end host as host_t object */ - void (*set_end_host) (traffic_selector_substructure_t *this,host_t *end_host); + void (*set_end_host) (traffic_selector_substructure_t *this, + host_t *end_host); /** - * @brief Get a traffic_selector_t from this substructure. + * Get a traffic_selector_t from this substructure. * * @warning traffic_selector_t must be destroyed after usage. * - * @param this calling traffic_selector_substructure_t object * @return contained traffic_selector_t */ - traffic_selector_t *(*get_traffic_selector) (traffic_selector_substructure_t *this); + traffic_selector_t *(*get_traffic_selector) ( + traffic_selector_substructure_t *this); /** - * @brief Destroys an traffic_selector_substructure_t object. - * - * @param this traffic_selector_substructure_t object to destroy + * Destroys an traffic_selector_substructure_t object. */ void (*destroy) (traffic_selector_substructure_t *this); }; /** - * @brief Creates an empty traffic_selector_substructure_t object. + * Creates an empty traffic_selector_substructure_t object. * * TS type is set to default TS_IPV4_ADDR_RANGE! * * @return traffic_selector_substructure_t object - * - * @ingroup payloads */ traffic_selector_substructure_t *traffic_selector_substructure_create(void); /** - * @brief Creates an initialized traffif selector substructure using + * Creates an initialized traffif selector substructure using * the values from a traffic_selector_t. * * @param traffic_selector traffic_selector_t to use for initialization * @return traffic_selector_substructure_t object - * - * @ingroup payloads */ -traffic_selector_substructure_t *traffic_selector_substructure_create_from_traffic_selector(traffic_selector_t *traffic_selector); - +traffic_selector_substructure_t *traffic_selector_substructure_create_from_traffic_selector( + traffic_selector_t *traffic_selector); -#endif /* /TRAFFIC_SELECTOR_SUBSTRUCTURE_H_ */ +#endif /* /TRAFFIC_SELECTOR_SUBSTRUCTURE_H_ @} */ diff --git a/src/charon/encoding/payloads/transform_attribute.c b/src/charon/encoding/payloads/transform_attribute.c index 066885c55..2dfb77713 100644 --- a/src/charon/encoding/payloads/transform_attribute.c +++ b/src/charon/encoding/payloads/transform_attribute.c @@ -1,10 +1,3 @@ -/** - * @file transform_attribute.c - * - * @brief Implementation of transform_attribute_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,8 @@ * 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. + * + * $Id$ */ #include diff --git a/src/charon/encoding/payloads/transform_attribute.h b/src/charon/encoding/payloads/transform_attribute.h index 30583b23f..32039cbaf 100644 --- a/src/charon/encoding/payloads/transform_attribute.h +++ b/src/charon/encoding/payloads/transform_attribute.h @@ -1,10 +1,3 @@ -/** - * @file transform_attribute.h - * - * @brief Interface of transform_attribute_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup transform_attribute transform_attribute + * @{ @ingroup payloads */ #ifndef TRANSFORM_ATTRIBUTE_H_ @@ -33,8 +33,6 @@ typedef struct transform_attribute_t transform_attribute_t; /** * Type of the attribute, as in IKEv2 RFC 3.3.5. - * - * @ingroup payloads */ enum transform_attribute_type_t { ATTRIBUTE_UNDEFINED = 16384, @@ -43,17 +41,13 @@ enum transform_attribute_type_t { /** * enum name for transform_attribute_type_t. - * - * @ingroup payloads */ extern enum_name_t *transform_attribute_type_names; /** - * @brief Class representing an IKEv2- TRANSFORM Attribute. + * Class representing an IKEv2- TRANSFORM Attribute. * * The TRANSFORM ATTRIBUTE format is described in RFC section 3.3.5. - * - * @ingroup payloads */ struct transform_attribute_t { /** @@ -62,93 +56,79 @@ struct transform_attribute_t { payload_t payload_interface; /** - * @brief Returns the currently set value of the attribute. + * Returns the currently set value of the attribute. * - * @warning Returned data are not copied. + * Returned data are not copied. * - * @param this calling transform_attribute_t object * @return chunk_t pointing to the value */ chunk_t (*get_value_chunk) (transform_attribute_t *this); /** - * @brief Returns the currently set value of the attribute. + * Returns the currently set value of the attribute. * - * @warning Returned data are not copied. + * Returned data are not copied. * - * @param this calling transform_attribute_t object * @return value */ u_int16_t (*get_value) (transform_attribute_t *this); /** - * @brief Sets the value of the attribute. + * Sets the value of the attribute. * - * @warning Value is getting copied. + * Value is getting copied. * - * @param this calling transform_attribute_t object * @param value chunk_t pointing to the value to set */ void (*set_value_chunk) (transform_attribute_t *this, chunk_t value); /** - * @brief Sets the value of the attribute. + * Sets the value of the attribute. * - * @param this calling transform_attribute_t object * @param value value to set */ void (*set_value) (transform_attribute_t *this, u_int16_t value); /** - * @brief Sets the type of the attribute. + * Sets the type of the attribute. * - * @param this calling transform_attribute_t object * @param type type to set (most significant bit is set to zero) */ void (*set_attribute_type) (transform_attribute_t *this, u_int16_t type); /** - * @brief get the type of the attribute. + * get the type of the attribute. * - * @param this calling transform_attribute_t object * @return type of the value */ u_int16_t (*get_attribute_type) (transform_attribute_t *this); /** - * @brief Clones an transform_attribute_t object. + * Clones an transform_attribute_t object. * - * @param this transform_attribute_t object to clone * @return cloned transform_attribute_t object */ transform_attribute_t * (*clone) (transform_attribute_t *this); /** - * @brief Destroys an transform_attribute_t object. - * - * @param this transform_attribute_t object to destroy + * Destroys an transform_attribute_t object. */ void (*destroy) (transform_attribute_t *this); }; /** - * @brief Creates an empty transform_attribute_t object. + * Creates an empty transform_attribute_t object. * * @return transform_attribute_t object - * - * @ingroup payloads */ transform_attribute_t *transform_attribute_create(void); /** - * @brief Creates an transform_attribute_t of type KEY_LENGTH. + * Creates an transform_attribute_t of type KEY_LENGTH. * * @param key_length key length in bytes * @return transform_attribute_t object - * - * @ingroup payloads */ transform_attribute_t *transform_attribute_create_key_length(u_int16_t key_length); - -#endif /*TRANSFORM_ATTRIBUTE_H_*/ +#endif /*TRANSFORM_ATTRIBUTE_H_ @} */ diff --git a/src/charon/encoding/payloads/transform_substructure.c b/src/charon/encoding/payloads/transform_substructure.c index d64d6c754..6706cf802 100644 --- a/src/charon/encoding/payloads/transform_substructure.c +++ b/src/charon/encoding/payloads/transform_substructure.c @@ -1,10 +1,3 @@ -/** - * @file transform_substructure.h - * - * @brief Implementation of transform_substructure_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,8 @@ * 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. + * + * $Id$ */ #include diff --git a/src/charon/encoding/payloads/transform_substructure.h b/src/charon/encoding/payloads/transform_substructure.h index 97f587d5d..0194b9904 100644 --- a/src/charon/encoding/payloads/transform_substructure.h +++ b/src/charon/encoding/payloads/transform_substructure.h @@ -1,10 +1,3 @@ -/** - * @file transform_substructure.h - * - * @brief Interface of transform_substructure_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup transform_substructure transform_substructure + * @{ @ingroup payloads */ #ifndef TRANSFORM_SUBSTRUCTURE_H_ @@ -39,25 +39,19 @@ typedef struct transform_substructure_t transform_substructure_t; /** * IKEv1 Value for a transform payload. - * - * @ingroup payloads */ #define TRANSFORM_TYPE_VALUE 3 /** * Length of the transform substructure header in bytes. - * - * @ingroup payloads */ #define TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH 8 /** - * @brief Class representing an IKEv2- TRANSFORM SUBSTRUCTURE. + * Class representing an IKEv2- TRANSFORM SUBSTRUCTURE. * * The TRANSFORM SUBSTRUCTURE format is described in RFC section 3.3.2. - * - * @ingroup payloads */ struct transform_substructure_t { /** @@ -66,121 +60,105 @@ struct transform_substructure_t { payload_t payload_interface; /** - * @brief Creates an iterator of stored transform_attribute_t objects. - * - * @warning The created iterator has to get destroyed by the caller! + * Creates an iterator of stored transform_attribute_t objects. * - * @warning When deleting an transform attribute using this iterator, - * the length of this transform substructure has to be refreshed - * by calling get_length()! + * When deleting an transform attribute using this iterator, + * the length of this transform substructure has to be refreshed + * by calling get_length(). * - * @param this calling transform_substructure_t object - * @param[in] forward iterator direction (TRUE: front to end) + * @param forward iterator direction (TRUE: front to end) * @return created iterator_t object. */ - iterator_t * (*create_transform_attribute_iterator) (transform_substructure_t *this, bool forward); + iterator_t * (*create_transform_attribute_iterator) ( + transform_substructure_t *this, bool forward); /** - * @brief Adds a transform_attribute_t object to this object. - * - * @warning The added proposal_substructure_t object is - * getting destroyed in destroy function of transform_substructure_t. + * Adds a transform_attribute_t object to this object. * - * @param this calling transform_substructure_t object * @param proposal transform_attribute_t object to add */ - void (*add_transform_attribute) (transform_substructure_t *this,transform_attribute_t *attribute); + void (*add_transform_attribute) (transform_substructure_t *this, + transform_attribute_t *attribute); /** - * @brief Sets the next_payload field of this substructure + * Sets the next_payload field of this substructure * * If this is the last transform, next payload field is set to 0, * otherwise to 3 * - * @param this calling transform_substructure_t object * @param is_last When TRUE, next payload field is set to 0, otherwise to 3 */ void (*set_is_last_transform) (transform_substructure_t *this, bool is_last); /** - * @brief Checks if this is the last transform. + * Checks if this is the last transform. * - * @param this calling transform_substructure_t object * @return TRUE if this is the last Transform, FALSE otherwise */ bool (*get_is_last_transform) (transform_substructure_t *this); /** - * @brief Sets transform type of the current transform substructure. + * Sets transform type of the current transform substructure. * - * @param this calling transform_substructure_t object * @param type type value to set */ - void (*set_transform_type) (transform_substructure_t *this,u_int8_t type); + void (*set_transform_type) (transform_substructure_t *this, u_int8_t type); /** - * @brief get transform type of the current transform. + * get transform type of the current transform. * - * @param this calling transform_substructure_t object * @return Transform type of current transform substructure. */ u_int8_t (*get_transform_type) (transform_substructure_t *this); /** - * @brief Sets transform id of the current transform substructure. + * Sets transform id of the current transform substructure. * - * @param this calling transform_substructure_t object - * @param id transform id to set + * @param id transform id to set */ - void (*set_transform_id) (transform_substructure_t *this,u_int16_t id); + void (*set_transform_id) (transform_substructure_t *this, u_int16_t id); /** - * @brief get transform id of the current transform. + * get transform id of the current transform. * - * @param this calling transform_substructure_t object * @return Transform id of current transform substructure. */ u_int16_t (*get_transform_id) (transform_substructure_t *this); /** - * @brief get transform id of the current transform. + * get transform id of the current transform. * - * @param this calling transform_substructure_t object - * @param key_length The key length is written to this location + * @param key_length The key length is written to this location * @return * - SUCCESS if a key length attribute is contained * - FAILED if no key length attribute is part of this * transform or key length uses more then 16 bit! */ - status_t (*get_key_length) (transform_substructure_t *this,u_int16_t *key_length); + status_t (*get_key_length) (transform_substructure_t *this, + u_int16_t *key_length); /** - * @brief Clones an transform_substructure_t object. + * Clones an transform_substructure_t object. * - * @param this transform_substructure_t object to clone * @return cloned transform_substructure_t object */ transform_substructure_t* (*clone) (transform_substructure_t *this); /** - * @brief Destroys an transform_substructure_t object. - * - * @param this transform_substructure_t object to destroy + * Destroys an transform_substructure_t object. */ void (*destroy) (transform_substructure_t *this); }; /** - * @brief Creates an empty transform_substructure_t object. + * Creates an empty transform_substructure_t object. * * @return created transform_substructure_t object - * - * @ingroup payloads */ transform_substructure_t *transform_substructure_create(void); /** - * @brief Creates an empty transform_substructure_t object. + * Creates an empty transform_substructure_t object. * * The key length is used for the transport types ENCRYPTION_ALGORITHM, * PSEUDO_RANDOM_FUNCTION, INTEGRITY_ALGORITHM. For all @@ -190,9 +168,9 @@ transform_substructure_t *transform_substructure_create(void); * @param transform_id transform id specifying the specific algorithm of a transform type * @param key_length Key length for key lenght attribute * @return transform_substructure_t object - * - * @ingroup payloads */ -transform_substructure_t *transform_substructure_create_type(transform_type_t transform_type, u_int16_t transform_id, u_int16_t key_length); +transform_substructure_t *transform_substructure_create_type( + transform_type_t transform_type, u_int16_t transform_id, + u_int16_t key_length); -#endif /*TRANSFORM_SUBSTRUCTURE_H_*/ +#endif /*TRANSFORM_SUBSTRUCTURE_H_ @} */ diff --git a/src/charon/encoding/payloads/ts_payload.c b/src/charon/encoding/payloads/ts_payload.c index ae89919f6..249894b3b 100644 --- a/src/charon/encoding/payloads/ts_payload.c +++ b/src/charon/encoding/payloads/ts_payload.c @@ -1,10 +1,3 @@ -/** - * @file ts_payload.c - * - * @brief Implementation of ts_payload_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,8 @@ * 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. + * + * $Id$ */ #include diff --git a/src/charon/encoding/payloads/ts_payload.h b/src/charon/encoding/payloads/ts_payload.h index 1addee22c..6f216a396 100644 --- a/src/charon/encoding/payloads/ts_payload.h +++ b/src/charon/encoding/payloads/ts_payload.h @@ -1,10 +1,3 @@ -/** - * @file ts_payload.h - * - * @brief Interface of ts_payload_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup ts_payload ts_payload + * @{ @ingroup payloads */ @@ -35,22 +35,14 @@ typedef struct ts_payload_t ts_payload_t; /** * Length of a TS payload without the Traffic selectors. - * - * @ingroup payloads */ #define TS_PAYLOAD_HEADER_LENGTH 8 /** - * @brief Class representing an IKEv2 TS payload. + * Class representing an IKEv2 TS payload. * * The TS payload format is described in RFC section 3.13. - * - * @b Constructors: - * - ts_payload_create() - * - ts_payload_create_from_traffic_selectors() - * - * @ingroup payloads */ struct ts_payload_t { /** @@ -59,9 +51,8 @@ struct ts_payload_t { payload_t payload_interface; /** - * @brief Get the type of TSpayload (TSi or TSr). + * Get the type of TSpayload (TSi or TSr). * - * @param this calling id_payload_t object * @return * - TRUE if this payload is of type TSi * - FALSE if this payload is of type TSr @@ -69,9 +60,8 @@ struct ts_payload_t { bool (*get_initiator) (ts_payload_t *this); /** - * @brief Set the type of TS payload (TSi or TSr). + * Set the type of TS payload (TSi or TSr). * - * @param this calling id_payload_t object * @param is_initiator * - TRUE if this payload is of type TSi * - FALSE if this payload is of type TSr @@ -79,75 +69,61 @@ struct ts_payload_t { void (*set_initiator) (ts_payload_t *this,bool is_initiator); /** - * @brief Adds a traffic_selector_substructure_t object to this object. - * - * @warning The added traffic_selector_substructure_t object is - * getting destroyed in destroy function of ts_payload_t. + * Adds a traffic_selector_substructure_t object to this object. * - * @param this calling ts_payload_t object * @param traffic_selector traffic_selector_substructure_t object to add */ - void (*add_traffic_selector_substructure) (ts_payload_t *this,traffic_selector_substructure_t *traffic_selector); + void (*add_traffic_selector_substructure) (ts_payload_t *this, + traffic_selector_substructure_t *traffic_selector); /** - * @brief Creates an iterator of stored traffic_selector_substructure_t objects. + * Creates an iterator of stored traffic_selector_substructure_t objects. * - * @warning The created iterator has to get destroyed by the caller! - * - * @warning When removing an traffic_selector_substructure_t object - * using this iterator, the length of this payload - * has to get refreshed by calling payload_t.get_length! + * When removing an traffic_selector_substructure_t object + * using this iterator, the length of this payload + * has to get refreshed by calling payload_t.get_length! * - * @param this calling ts_payload_t object - * @param[in] forward iterator direction (TRUE: front to end) + * @param forward iterator direction (TRUE: front to end) * @return created iterator_t object */ - iterator_t *(*create_traffic_selector_substructure_iterator) (ts_payload_t *this, bool forward); + iterator_t *(*create_traffic_selector_substructure_iterator) ( + ts_payload_t *this, bool forward); /** - * @brief Get a list of nested traffic selectors as traffic_selector_t. + * Get a list of nested traffic selectors as traffic_selector_t. * * Resulting list and its traffic selectors must be destroyed after usage * - * @param this calling ts_payload_t object * @return list of traffic selectors */ linked_list_t *(*get_traffic_selectors) (ts_payload_t *this); /** - * @brief Destroys an ts_payload_t object. - * - * @param this ts_payload_t object to destroy + * Destroys an ts_payload_t object. */ void (*destroy) (ts_payload_t *this); }; /** - * @brief Creates an empty ts_payload_t object. - * + * Creates an empty ts_payload_t object. * * @param is_initiator * - TRUE if this payload is of type TSi * - FALSE if this payload is of type TSr * @return ts_payload_t object - * - * @ingroup payloads */ ts_payload_t *ts_payload_create(bool is_initiator); /** - * @brief Creates ts_payload with a list of traffic_selector_t - * + * Creates ts_payload with a list of traffic_selector_t * * @param is_initiator * - TRUE if this payload is of type TSi * - FALSE if this payload is of type TSr * @param traffic_selectors list of traffic selectors to include * @return ts_payload_t object - * - * @ingroup payloads */ -ts_payload_t *ts_payload_create_from_traffic_selectors(bool is_initiator, linked_list_t *traffic_selectors); - +ts_payload_t *ts_payload_create_from_traffic_selectors(bool is_initiator, + linked_list_t *traffic_selectors); -#endif /* TS_PAYLOAD_H_ */ +#endif /* TS_PAYLOAD_H_ @} */ diff --git a/src/charon/encoding/payloads/unknown_payload.c b/src/charon/encoding/payloads/unknown_payload.c index bbe736085..8c09de7cd 100644 --- a/src/charon/encoding/payloads/unknown_payload.c +++ b/src/charon/encoding/payloads/unknown_payload.c @@ -1,10 +1,3 @@ -/** - * @file unknown_payload.c - * - * @brief Implementation of unknown_payload_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,8 @@ * 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. + * + * $Id$ */ #include diff --git a/src/charon/encoding/payloads/unknown_payload.h b/src/charon/encoding/payloads/unknown_payload.h index 8d13a03a3..605f19285 100644 --- a/src/charon/encoding/payloads/unknown_payload.h +++ b/src/charon/encoding/payloads/unknown_payload.h @@ -1,10 +1,3 @@ -/** - * @file unknown_payload.h - * - * @brief Interface of unknown_payload_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup unknown_payload unknown_payload + * @{ @ingroup payloads */ #ifndef UNKNOWN_PAYLOAD_H_ @@ -31,22 +31,15 @@ typedef struct unknown_payload_t unknown_payload_t; /** * Header length of the unknown payload. - * - * @ingroup payloads */ #define UNKNOWN_PAYLOAD_HEADER_LENGTH 4 /** - * @brief Payload which can't be processed further. + * Payload which can't be processed further. * * When the parser finds an unknown payload, he builds an instance of * this class. This allows further processing of this payload, such as * a check for the critical bit in the header. - * - * @b Constructors: - * - unknown_payload_create() - * - * @ingroup payloads */ struct unknown_payload_t { @@ -56,40 +49,33 @@ struct unknown_payload_t { payload_t payload_interface; /** - * @brief Get the raw data of this payload, without + * Get the raw data of this payload, without * the generic payload header. * * Returned data are NOT copied and must not be freed. * - * @param this calling unknown_payload_t object * @return data as chunk_t */ chunk_t (*get_data) (unknown_payload_t *this); /** - * @brief Get the critical flag. + * Get the critical flag. * - * @param this calling unknown_payload_t object * @return TRUE if payload is critical, FALSE if not */ bool (*is_critical) (unknown_payload_t *this); /** - * @brief Destroys an unknown_payload_t object. - * - * @param this unknown_payload_t object to destroy + * Destroys an unknown_payload_t object. */ void (*destroy) (unknown_payload_t *this); }; /** - * @brief Creates an empty unknown_payload_t object. + * Creates an empty unknown_payload_t object. * * @return unknown_payload_t object - * - * @ingroup payloads */ unknown_payload_t *unknown_payload_create(void); - -#endif /* UNKNOWN_PAYLOAD_H_ */ +#endif /* UNKNOWN_PAYLOAD_H_ @} */ diff --git a/src/charon/encoding/payloads/vendor_id_payload.c b/src/charon/encoding/payloads/vendor_id_payload.c index e3a4d2e1f..6bee95339 100644 --- a/src/charon/encoding/payloads/vendor_id_payload.c +++ b/src/charon/encoding/payloads/vendor_id_payload.c @@ -1,10 +1,3 @@ -/** - * @file vendor_id_payload.c - * - * @brief Implementation of vendor_id_payload_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,8 @@ * 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. + * + * $Id$ */ #include diff --git a/src/charon/encoding/payloads/vendor_id_payload.h b/src/charon/encoding/payloads/vendor_id_payload.h index c7eebc155..a805a366f 100644 --- a/src/charon/encoding/payloads/vendor_id_payload.h +++ b/src/charon/encoding/payloads/vendor_id_payload.h @@ -1,10 +1,3 @@ -/** - * @file vendor_id_payload.h - * - * @brief Interface of vendor_id_payload_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup vendor_id_payload vendor_id_payload + * @{ @ingroup payloads */ #ifndef VENDOR_ID_PAYLOAD_H_ @@ -31,21 +31,14 @@ typedef struct vendor_id_payload_t vendor_id_payload_t; /** * Length of a VENDOR ID payload without the VID data in bytes. - * - * @ingroup payloads */ #define VENDOR_ID_PAYLOAD_HEADER_LENGTH 4 /** - * @brief Class representing an IKEv2 VENDOR ID payload. + * Class representing an IKEv2 VENDOR ID payload. * * The VENDOR ID payload format is described in RFC section 3.12. - * - * @b Constructors: - * - vendor_id_payload_create() - * - * @ingroup payloads */ struct vendor_id_payload_t { /** @@ -54,51 +47,43 @@ struct vendor_id_payload_t { payload_t payload_interface; /** - * @brief Set the VID data. + * Set the VID data. * * Data are getting cloned. * - * @param this calling vendor_id_payload_t object * @param data VID data as chunk_t */ void (*set_data) (vendor_id_payload_t *this, chunk_t data); /** - * @brief Get the VID data. + * Get the VID data. * * Returned data are a copy of the internal one. * - * @param this calling vendor_id_payload_t object * @return VID data as chunk_t */ chunk_t (*get_data_clone) (vendor_id_payload_t *this); /** - * @brief Get the VID data. + * Get the VID data. * * Returned data are NOT copied. * - * @param this calling vendor_id_payload_t object * @return VID data as chunk_t */ chunk_t (*get_data) (vendor_id_payload_t *this); /** - * @brief Destroys an vendor_id_payload_t object. - * - * @param this vendor_id_payload_t object to destroy + * Destroys an vendor_id_payload_t object. */ void (*destroy) (vendor_id_payload_t *this); }; /** - * @brief Creates an empty vendor_id_payload_t object. + * Creates an empty vendor_id_payload_t object. * * @return vendor_id_payload_t object - * - * @ingroup payloads */ vendor_id_payload_t *vendor_id_payload_create(void); - -#endif /* VENDOR_ID_PAYLOAD_H_ */ +#endif /* VENDOR_ID_PAYLOAD_H_ @} */ diff --git a/src/charon/kernel/kernel_interface.c b/src/charon/kernel/kernel_interface.c index b7f6a1def..88df4f3d2 100644 --- a/src/charon/kernel/kernel_interface.c +++ b/src/charon/kernel/kernel_interface.c @@ -1,10 +1,3 @@ -/** - * @file kernel_interface.c - * - * @brief Implementation of kernel_interface_t. - * - */ - /* * Copyright (C) 2005-2007 Martin Willi * Copyright (C) 2006-2007 Tobias Brunner @@ -25,6 +18,8 @@ * 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. + * + * $Id$ */ #include diff --git a/src/charon/kernel/kernel_interface.h b/src/charon/kernel/kernel_interface.h index 256c20797..624316d97 100644 --- a/src/charon/kernel/kernel_interface.h +++ b/src/charon/kernel/kernel_interface.h @@ -1,10 +1,3 @@ -/** - * @file kernel_interface.h - * - * @brief Interface of kernel_interface_t. - * - */ - /* * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger * Copyright (C) 2005-2006 Martin Willi @@ -20,6 +13,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup kernel_interface kernel_interface + * @{ @ingroup kernel */ #ifndef KERNEL_INTERFACE_H_ @@ -37,8 +37,6 @@ typedef struct kernel_interface_t kernel_interface_t; * Direction of a policy. These are equal to those * defined in xfrm.h, but we want to stay implementation * neutral here. - * - * @ingroup kernel */ enum policy_dir_t { /** Policy for inbound traffic */ @@ -50,7 +48,7 @@ enum policy_dir_t { }; /** - * @brief Interface to the kernel. + * Interface to the kernel. * * The kernel interface handles the communication with the kernel * for SA and policy management. It allows setup of these, and provides @@ -59,36 +57,28 @@ enum policy_dir_t { * reference counting. The Linux kernel does not allow the same policy * installed twice, but we need this as CHILD_SA exist multiple times * when rekeying. Thats why we do reference counting of policies. - * - * @b Constructors: - * - kernel_interface_create() - * - * @ingroup kernel */ struct kernel_interface_t { /** - * @brief Get a SPI from the kernel. + * Get a SPI from the kernel. * * @warning get_spi() implicitely creates an SA with * the allocated SPI, therefore the replace flag * in add_sa() must be set when installing this SA. * - * @param this calling object * @param src source address of SA * @param dst destination address of SA * @param protocol protocol for SA (ESP/AH) * @param reqid unique ID for this SA - * @param[out] spi allocated spi - * @return - * - SUCCESS - * - FAILED if kernel comm failed + * @param spi allocated spi + * @return SUCCESS if operation completed */ status_t (*get_spi)(kernel_interface_t *this, host_t *src, host_t *dst, protocol_id_t protocol, u_int32_t reqid, u_int32_t *spi); /** - * @brief Add an SA to the SAD. + * Add an SA to the SAD. * * add_sa() may update an already allocated * SPI (via get_spi). In this case, the replace @@ -98,7 +88,6 @@ struct kernel_interface_t { * gets the keys itself from the PRF, as we don't know * his algorithms and key sizes. * - * @param this calling object * @param src source address for this SA * @param dst destination address for this SA * @param spi SPI allocated by us or remote peer @@ -112,9 +101,7 @@ struct kernel_interface_t { * @param mode mode of the SA (tunnel, transport) * @param encap enable UDP encapsulation for NAT traversal * @param replace Should an already installed SA be updated? - * @return - * - SUCCESS - * - FAILED if kernel comm failed + * @return SUCCESS if operation completed */ status_t (*add_sa) (kernel_interface_t *this, host_t *src, host_t *dst, u_int32_t spi, @@ -125,14 +112,13 @@ struct kernel_interface_t { bool update); /** - * @brief Update the hosts on an installed SA. + * Update the hosts on an installed SA. * * We cannot directly update the destination address as the kernel * requires the spi, the protocol AND the destination address (and family) * to identify SAs. Therefore if the destination address changed we * create a new SA and delete the old one. * - * @param this calling object * @param spi SPI of the SA * @param protocol protocol for this SA (ESP/AH) * @param src current source address @@ -140,9 +126,7 @@ struct kernel_interface_t { * @param new_src new source address * @param new_dst new destination address * @param encap use UDP encapsulation - * @return - * - SUCCESS - * - FAILED if kernel comm failed + * @return SUCCESS if operation completed */ status_t (*update_sa)(kernel_interface_t *this, u_int32_t spi, protocol_id_t protocol, @@ -150,44 +134,37 @@ struct kernel_interface_t { host_t *new_src, host_t *new_dst, bool encap); /** - * @brief Query the use time of an SA. + * Query the use time of an SA. * * The use time of an SA is not the time of the last usage, but * the time of the first usage of the SA. * - * @param this calling object * @param dst destination address for this SA * @param spi SPI allocated by us or remote peer * @param protocol protocol for this SA (ESP/AH) - * @param[out] use_time the time of this SA's last use - * @return - * - SUCCESS - * - FAILED if kernel comm failed + * @param use_time pointer receives the time of this SA's last use + * @return SUCCESS if operation completed */ status_t (*query_sa) (kernel_interface_t *this, host_t *dst, u_int32_t spi, protocol_id_t protocol, u_int32_t *use_time); /** - * @brief Delete a previusly installed SA from the SAD. + * Delete a previusly installed SA from the SAD. * - * @param this calling object * @param dst destination address for this SA * @param spi SPI allocated by us or remote peer * @param protocol protocol for this SA (ESP/AH) - * @return - * - SUCCESS - * - FAILED if kernel comm failed + * @return SUCCESS if operation completed */ status_t (*del_sa) (kernel_interface_t *this, host_t *dst, u_int32_t spi, protocol_id_t protocol); /** - * @brief Add a policy to the SPD. + * Add a policy to the SPD. * * A policy is always associated to an SA. Traffic which matches a * policy is handled by the SA with the same reqid. * - * @param this calling object * @param src source address of SA * @param dst dest address of SA * @param src_ts traffic selector to match traffic source @@ -197,9 +174,7 @@ struct kernel_interface_t { * @param reqid uniqe ID of an SA to use to enforce policy * @param high_prio if TRUE, uses a higher priority than any with FALSE * @param mode mode of SA (tunnel, transport) - * @return - * - SUCCESS - * - FAILED if kernel comm failed + * @return SUCCESS if operation completed */ status_t (*add_policy) (kernel_interface_t *this, host_t *src, host_t *dst, @@ -209,19 +184,16 @@ struct kernel_interface_t { u_int32_t reqid, bool high_prio, mode_t mode); /** - * @brief Query the use time of a policy. + * Query the use time of a policy. * * The use time of a policy is the time the policy was used * for the last time. * - * @param this calling object * @param src_ts traffic selector to match traffic source * @param dst_ts traffic selector to match traffic dest * @param direction direction of traffic, POLICY_IN, POLICY_OUT, POLICY_FWD * @param[out] use_time the time of this SA's last use - * @return - * - SUCCESS - * - FAILED if kernel comm failed + * @return SUCCESS if operation completed */ status_t (*query_policy) (kernel_interface_t *this, traffic_selector_t *src_ts, @@ -229,20 +201,17 @@ struct kernel_interface_t { policy_dir_t direction, u_int32_t *use_time); /** - * @brief Remove a policy from the SPD. + * Remove a policy from the SPD. * * The kernel interface implements reference counting for policies. * If the same policy is installed multiple times (in the case of rekeying), * the reference counter is increased. del_policy() decreases the ref counter * and removes the policy only when no more references are available. * - * @param this calling object * @param src_ts traffic selector to match traffic source * @param dst_ts traffic selector to match traffic dest * @param direction direction of traffic, POLICY_IN, POLICY_OUT, POLICY_FWD - * @return - * - SUCCESS - * - FAILED if kernel comm failed + * @return SUCCESS if operation completed */ status_t (*del_policy) (kernel_interface_t *this, traffic_selector_t *src_ts, @@ -250,82 +219,69 @@ struct kernel_interface_t { policy_dir_t direction); /** - * @brief Get our outgoing source address for a destination. + * Get our outgoing source address for a destination. * * Does a route lookup to get the source address used to reach dest. * The returned host is allocated and must be destroyed. * - * @param this calling object * @param dest target destination address * @return outgoing source address, NULL if unreachable */ host_t* (*get_source_addr)(kernel_interface_t *this, host_t *dest); /** - * @brief Get the interface name of a local address. + * Get the interface name of a local address. * - * @param this calling object * @param host address to get interface name from * @return allocated interface name, or NULL if not found */ char* (*get_interface) (kernel_interface_t *this, host_t *host); /** - * @brief Creates an iterator over all local addresses. + * Creates an iterator over all local addresses. * * This function blocks an internal cached address list until the * iterator gets destroyed. * These hosts are read-only, do not modify or free. * - * @param this calling object * @return iterator over host_t's */ iterator_t *(*create_address_iterator) (kernel_interface_t *this); /** - * @brief Add a virtual IP to an interface. + * Add a virtual IP to an interface. * * Virtual IPs are attached to an interface. If an IP is added multiple * times, the IP is refcounted and not removed until del_ip() was called * as many times as add_ip(). * The virtual IP is attached to the interface where the iface_ip is found. * - * @param this calling object * @param virtual_ip virtual ip address to assign * @param iface_ip IP of an interface to attach virtual IP - * @return - * - SUCCESS - * - FAILED if kernel comm failed + * @return SUCCESS if operation completed */ status_t (*add_ip) (kernel_interface_t *this, host_t *virtual_ip, host_t *iface_ip); /** - * @brief Remove a virtual IP from an interface. + * Remove a virtual IP from an interface. * * The kernel interface uses refcounting, see add_ip(). * - * @param this calling object * @param virtual_ip virtual ip address to assign - * @return - * - SUCCESS - * - FAILED if kernel comm failed + * @return SUCCESS if operation completed */ status_t (*del_ip) (kernel_interface_t *this, host_t *virtual_ip); /** - * @brief Destroys a kernel_interface object. - * - * @param kernel_interface_t calling object + * Destroys a kernel_interface object. */ void (*destroy) (kernel_interface_t *kernel_interface); }; /** - * @brief Creates an object of type kernel_interface_t. - * - * @ingroup kernel + * Creates an object of type kernel_interface_t. */ kernel_interface_t *kernel_interface_create(void); -#endif /*KERNEL_INTERFACE_H_*/ +#endif /*KERNEL_INTERFACE_H_ @} */ diff --git a/src/charon/network/packet.c b/src/charon/network/packet.c index f2fa91569..fb5f9920f 100644 --- a/src/charon/network/packet.c +++ b/src/charon/network/packet.c @@ -1,10 +1,3 @@ -/** - * @file packet.c - * - * @brief Implementation of packet_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,12 +12,12 @@ * 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. + * + * $Id$ */ - #include "packet.h" - typedef struct private_packet_t private_packet_t; /** diff --git a/src/charon/network/packet.h b/src/charon/network/packet.h index acf953032..c9818be6f 100644 --- a/src/charon/network/packet.h +++ b/src/charon/network/packet.h @@ -1,10 +1,3 @@ -/** - * @file packet.h - * - * @brief Interface of packet_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup packet packet + * @{ @ingroup network */ #ifndef PACKET_H_ @@ -30,105 +30,88 @@ typedef struct packet_t packet_t; #include /** - * @brief Abstraction of an UDP-Packet, contains data, sender and receiver. - * - * @b Constructors: - * - packet_create() - * - * @ingroup network + * Abstraction of an UDP-Packet, contains data, sender and receiver. */ struct packet_t { /** - * @brief Set the source address. + * Set the source address. * * Set host_t is now owned by packet_t, it will destroy * it if necessary. * - * @param this calling object * @param source address to set as source */ void (*set_source) (packet_t *packet, host_t *source); /** - * @brief Set the destination address. + * Set the destination address. * * Set host_t is now owned by packet_t, it will destroy * it if necessary. * - * @param this calling object * @param source address to set as destination */ void (*set_destination) (packet_t *packet, host_t *destination); /** - * @brief Get the source address. + * Get the source address. * * Set host_t is still owned by packet_t, clone it * if needed. * - * @param this calling object * @return source address */ host_t *(*get_source) (packet_t *packet); /** - * @brief Get the destination address. + * Get the destination address. * * Set host_t is still owned by packet_t, clone it * if needed. * - * @param this calling object * @return destination address */ host_t *(*get_destination) (packet_t *packet); /** - * @brief Get the data from the packet. + * Get the data from the packet. * * The data pointed by the chunk is still owned * by the packet. Clone it if needed. * - * @param this calling object * @return chunk containing the data */ chunk_t (*get_data) (packet_t *packet); /** - * @brief Set the data in the packet. + * Set the data in the packet. * * Supplied chunk data is now owned by the * packet. It will free it. * - * @param this calling object * @param data chunk with data to set */ void (*set_data) (packet_t *packet, chunk_t data); /** - * @brief Clones a packet_t object. + * Clones a packet_t object. * - * @param packet calling object - * @param clone pointer to a packet_t object pointer where the new object is stored + * @param clone clone of the packet */ packet_t* (*clone) (packet_t *packet); /** - * @brief Destroy the packet, freeing contained data. - * - * @param packet packet to destroy + * Destroy the packet, freeing contained data. */ void (*destroy) (packet_t *packet); }; /** - * @brief create an empty packet + * create an empty packet * * @return packet_t object - * - * @ingroup network */ packet_t *packet_create(void); - -#endif /*PACKET_H_*/ +#endif /*PACKET_H_ @} */ diff --git a/src/charon/network/receiver.c b/src/charon/network/receiver.c index 1de1dd3d2..2f3bf6cb2 100644 --- a/src/charon/network/receiver.c +++ b/src/charon/network/receiver.c @@ -1,10 +1,3 @@ -/** - * @file receiver.c - * - * @brief Implementation of receiver_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,8 @@ * 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. + * + * $Id$ */ #include @@ -33,9 +28,8 @@ #include #include #include +#include -/** length of the full cookie, including time (u_int32_t + SHA1()) */ -#define COOKIE_LENGTH 24 /** lifetime of a cookie, in seconds */ #define COOKIE_LIFETIME 10 /** how many times to reuse the secret */ @@ -145,11 +139,12 @@ static chunk_t cookie_build(private_receiver_t *this, message_t *message, { u_int64_t spi = message->get_initiator_spi(message); host_t *ip = message->get_source(message); - chunk_t input, hash = chunk_alloca(this->hasher->get_hash_size(this->hasher)); + chunk_t input, hash; /* COOKIE = t | sha1( IPi | SPIi | t | secret ) */ input = chunk_cata("cccc", ip->get_address(ip), chunk_from_thing(spi), chunk_from_thing(t), secret); + hash = chunk_alloca(this->hasher->get_hash_size(this->hasher)); this->hasher->get_hash(this->hasher, input, hash.ptr); return chunk_cat("cc", chunk_from_thing(t), hash); } @@ -167,7 +162,8 @@ static bool cookie_verify(private_receiver_t *this, message_t *message, now = time(NULL); t = *(u_int32_t*)cookie.ptr; - if (cookie.len != COOKIE_LENGTH || + if (cookie.len != sizeof(u_int32_t) + + this->hasher->get_hash_size(this->hasher) || t < now - this->secret_offset - COOKIE_LIFETIME) { DBG2(DBG_NET, "received cookie lifetime expired, rejecting"); @@ -212,7 +208,8 @@ static bool cookie_required(private_receiver_t *this, message_t *message) packet_t *packet = message->get_packet(message); chunk_t data = packet->get_data(packet); if (data.len < - IKE_HEADER_LENGTH + NOTIFY_PAYLOAD_HEADER_LENGTH + COOKIE_LENGTH || + IKE_HEADER_LENGTH + NOTIFY_PAYLOAD_HEADER_LENGTH + + sizeof(u_int32_t) + this->hasher->get_hash_size(this->hasher) || *(data.ptr + 16) != NOTIFY || *(u_int16_t*)(data.ptr + IKE_HEADER_LENGTH + 6) != htons(COOKIE)) { @@ -222,7 +219,7 @@ static bool cookie_required(private_receiver_t *this, message_t *message) else { data.ptr += IKE_HEADER_LENGTH + NOTIFY_PAYLOAD_HEADER_LENGTH; - data.len = COOKIE_LENGTH; + data.len = sizeof(u_int32_t) + this->hasher->get_hash_size(this->hasher); if (!cookie_verify(this, message, data)) { DBG2(DBG_NET, "found cookie, but content invalid"); @@ -351,8 +348,14 @@ receiver_t *receiver_create() this->public.destroy = (void(*)(receiver_t*)) destroy; + this->hasher = lib->crypto->create_hasher(lib->crypto, HASH_PREFERRED); + if (this->hasher == NULL) + { + DBG1(DBG_NET, "creating cookie hasher failed, no hashers supported"); + free(this); + return NULL; + } this->randomizer = randomizer_create(); - this->hasher = hasher_create(HASH_SHA1); this->secret_switch = now; this->secret_offset = random() % now; this->secret_used = 0; diff --git a/src/charon/network/receiver.h b/src/charon/network/receiver.h index 1bfa7b764..00315490a 100644 --- a/src/charon/network/receiver.h +++ b/src/charon/network/receiver.h @@ -1,10 +1,3 @@ -/** - * @file receiver.h - * - * @brief Interface of receiver_t. - * - */ - /* * Copyright (C) 2005-2007 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup receiver receiver + * @{ @ingroup network */ #ifndef RECEIVER_H_ @@ -30,7 +30,7 @@ typedef struct receiver_t receiver_t; #include /** - * @brief Receives packets from the socket and adds them to the job queue. + * Receives packets from the socket and adds them to the job queue. * * The receiver starts a thread, wich reads on the blocking socket. A received * packet is preparsed and a process_message_job is queued in the job queue. @@ -50,32 +50,23 @@ typedef struct receiver_t receiver_t; * * Further, the number of half-initiated IKE_SAs is limited per peer. This * mades it impossible for a peer to flood the server with its real IP address. - * - * @b Constructors: - * - receiver_create() - * - * @ingroup network */ struct receiver_t { /** - * @brief Destroys a receiver_t object. - * - * @param receiver receiver object + * Destroys a receiver_t object. */ void (*destroy) (receiver_t *receiver); }; /** - * @brief Create a receiver_t object. + * Create a receiver_t object. * * The receiver thread will start working, get data * from the socket and add those packets to the job queue. * - * @return receiver_t object - * - * @ingroup network + * @return receiver_t object, NULL if initialization fails */ receiver_t * receiver_create(void); -#endif /*RECEIVER_H_*/ +#endif /*RECEIVER_H_ @} */ diff --git a/src/charon/network/sender.c b/src/charon/network/sender.c index f934dc509..942401a82 100644 --- a/src/charon/network/sender.c +++ b/src/charon/network/sender.c @@ -1,10 +1,3 @@ -/** - * @file sender.c - * - * @brief Implementation of sender_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,8 @@ * 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. + * + * $Id$ */ #include diff --git a/src/charon/network/sender.h b/src/charon/network/sender.h index 8d611cc90..6b62dcc97 100644 --- a/src/charon/network/sender.h +++ b/src/charon/network/sender.h @@ -1,10 +1,3 @@ -/** - * @file sender.h - * - * @brief Interface of sender_t. - * - */ - /* * Copyright (C) 2005-2007 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup sender sender + * @{ @ingroup network */ #ifndef SENDER_H_ @@ -30,45 +30,35 @@ typedef struct sender_t sender_t; #include /** - * @brief Thread responsible for sending packets over the socket. - * - * @b Constructors: - * - sender_create() - * - * @ingroup network + * Thread responsible for sending packets over the socket. */ struct sender_t { /** - * @brief Send a packet over the network. + * Send a packet over the network. * * This function is non blocking and adds the packet to a queue. * Whenever the sender thread thinks it's good to send the packet, * it'll do so. * - * @param this calling object * @param packet packet to send */ void (*send) (sender_t *this, packet_t *packet); /** - * @brief Destroys a sender object. - * - * @param this calling object + * Destroys a sender object. */ void (*destroy) (sender_t *this); }; /** - * @brief Create the sender thread. + * Create the sender thread. * * The thread will start to work, getting packets * from its queue and sends them out. * * @return created sender object - * - * @ingroup network */ sender_t * sender_create(void); -#endif /*SENDER_H_*/ +#endif /*SENDER_H_ @} */ diff --git a/src/charon/network/socket-raw.c b/src/charon/network/socket-raw.c index 3b76ae570..72ee6bbca 100644 --- a/src/charon/network/socket-raw.c +++ b/src/charon/network/socket-raw.c @@ -1,10 +1,3 @@ -/** - * @file socket.c - * - * @brief Implementation of socket_t. - * - */ - /* * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger * Copyright (C) 2005-2006 Martin Willi @@ -20,6 +13,8 @@ * 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. + * + * $Id$ */ #include diff --git a/src/charon/network/socket.c b/src/charon/network/socket.c index a4c407579..cedfc0890 100644 --- a/src/charon/network/socket.c +++ b/src/charon/network/socket.c @@ -1,10 +1,3 @@ -/** - * @file socket.c - * - * @brief Implementation of socket_t. - * - */ - /* * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger * Copyright (C) 2005-2007 Martin Willi @@ -20,6 +13,8 @@ * 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. + * + * $Id$ */ #include diff --git a/src/charon/network/socket.h b/src/charon/network/socket.h index 4d8251325..7ddde6190 100644 --- a/src/charon/network/socket.h +++ b/src/charon/network/socket.h @@ -1,10 +1,3 @@ -/** - * @file socket.h - * - * @brief Interface for socket_t. - * - */ - /* * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger * Copyright (C) 2005-2006 Martin Willi @@ -20,6 +13,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup socket socket + * @{ @ingroup network */ #ifndef SOCKET_H_ @@ -33,38 +33,36 @@ typedef struct socket_t socket_t; #include /** - * @brief Maximum size of a packet. - * - * 3000 Bytes should be sufficient, see IKEv2 RFC. + * Maximum size of a packet. * - * @ingroup network + * 3000 Bytes should be sufficient, see IKEv2 RFC. However, we currently + * do not support HASH_AND_URL certificates, so we require to transmit + * the full certificates. To run our multi-CA test with 2 intermediate CAs, + * 5000 bytes is sufficient. */ -#define MAX_PACKET 3000 +#define MAX_PACKET 5000 /** - * @brief Abstraction of all sockets (IPv6/IPv6 send/receive). + * Abstraction of all sockets (IPv4/IPv6 send/receive). * * All available sockets are bound and the receive function - * reads from them. To allow binding of other daemons (pluto) to - * UDP/500, this implementation uses RAW sockets. An installed - * "Linux socket filter" filters out all non-IKEv2 traffic and handles - * just IKEv2 messages. An other daemon (pluto) must handle all traffic - * seperatly, e.g. ignore IKEv2 traffic, since charon handles that. - * - * @b Constructors: - * - socket_create() - * - * @ingroup network + * reads from them. There are actually two implementations: + * The first uses raw sockets to allow binding of other daemons (pluto) to + * UDP/500. An installed "Linux socket filter" filters out all non-IKEv2 + * traffic and handles just IKEv2 messages. An other daemon (pluto) must + * handle all traffic seperatly, e.g. ignore IKEv2 traffic, since charon + * handles that. + * The other implementation uses normal sockets and is built if + * --disable-pluto is given to the configure script. */ struct socket_t { /** - * @brief Receive a packet. + * Receive a packet. * * Reads a packet from the socket and sets source/dest * appropriately. * - * @param this socket_t object to work on * @param packet pinter gets address from allocated packet_t * @return * - SUCCESS when packet successfully received @@ -73,14 +71,13 @@ struct socket_t { status_t (*receive) (socket_t *this, packet_t **packet); /** - * @brief Send a packet. + * Send a packet. * * Sends a packet to the net using destination from the packet. * Packet is sent using default routing mechanisms, thus the * source address in packet is ignored. * - * @param this socket_t object to work on - * @param packet[out] packet_t to send + * @param packet packet_t to send * @return * - SUCCESS when packet successfully sent * - FAILED when unable to send @@ -88,23 +85,16 @@ struct socket_t { status_t (*send) (socket_t *this, packet_t *packet); /** - * @brief Destroy sockets. - * - * close sockets and destroy socket_t object - * - * @param this socket_t to destroy + * Destroy socket. */ void (*destroy) (socket_t *this); }; /** - * @brief Create a socket_t, wich binds multiple sockets. + * Create a socket_t, wich binds multiple sockets. * * @return socket_t object - * - * @ingroup network */ socket_t *socket_create(); - -#endif /*SOCKET_H_*/ +#endif /*SOCKET_H_ @} */ diff --git a/src/charon/plugins/dbus/Makefile.am b/src/charon/plugins/dbus/Makefile.am new file mode 100644 index 000000000..ccfada4ee --- /dev/null +++ b/src/charon/plugins/dbus/Makefile.am @@ -0,0 +1,11 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon ${dbus_CFLAGS} + +AM_CFLAGS = -rdynamic + +plugin_LTLIBRARIES = libcharon-dbus.la + +libcharon_dbus_la_SOURCES = dbus.h dbus.c +libcharon_dbus_la_LDFLAGS = -module +libcharon_dbus_la_LIBADD = ${dbus_LIBS} + diff --git a/src/charon/plugins/dbus/dbus.c b/src/charon/plugins/dbus/dbus.c new file mode 100644 index 000000000..ac29db773 --- /dev/null +++ b/src/charon/plugins/dbus/dbus.c @@ -0,0 +1,422 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#define DBUS_API_SUBJECT_TO_CHANGE +#include +#include +#include +#include + +#include "dbus.h" + +#include +#include +#include + + +#define NM_DBUS_SERVICE_STRONG "org.freedesktop.NetworkManager.strongswan" +#define NM_dbus_STRONG "org.freedesktop.NetworkManager.strongswan" +#define NM_DBUS_PATH_STRONG "/org/freedesktop/NetworkManager/strongswan" + +typedef struct private_dbus_t private_dbus_t; + +/** + * Private data of an dbus_t object. + */ +struct private_dbus_t { + + /** + * Public part of dbus_t object. + */ + dbus_t public; + + /** + * DBUS connection + */ + DBusConnection* conn; + + /** + * error value used here and there + */ + DBusError err; + + /** + * state of the daemon + */ + NMVPNState state; + + /** + * job accepting stroke messages + */ + callback_job_t *job; + + /** + * name of the currently active connection + */ + char *name; +}; + +/** + * set daemon state and send StateChange signal to the bus + */ +static void set_state(private_dbus_t *this, NMVPNState state) +{ + DBusMessage* msg; + + msg = dbus_message_new_signal(NM_DBUS_PATH_STRONG, NM_dbus_STRONG, NM_DBUS_VPN_SIGNAL_STATE_CHANGE); + + if (!dbus_message_append_args(msg, DBUS_TYPE_UINT32, &this->state, + DBUS_TYPE_UINT32, &state, DBUS_TYPE_INVALID) || + !dbus_connection_send(this->conn, msg, NULL)) + { + DBG1(DBG_CFG, "unable to send DBUS StateChange signal"); + } + dbus_connection_flush(this->conn); + dbus_message_unref(msg); + this->state = state; +} + + +/** + * get the child_cfg with the same name as the peer cfg + */ +static child_cfg_t* get_child_from_peer(peer_cfg_t *peer_cfg, char *name) +{ + child_cfg_t *current, *found = NULL; + iterator_t *iterator; + + iterator = peer_cfg->create_child_cfg_iterator(peer_cfg); + while (iterator->iterate(iterator, (void**)¤t)) + { + if (streq(current->get_name(current), name)) + { + found = current; + found->get_ref(found); + break; + } + } + iterator->destroy(iterator); + return found; +} + + +/** + * process NetworkManagers startConnection method call + */ +static bool start_connection(private_dbus_t *this, DBusMessage* msg) +{ + DBusMessage *reply, *signal; + char *name, *user, **data, **passwords, **routes; + int data_count, passwords_count, routes_count; + u_int32_t me, other, p2p, netmask, mss; + char *dev, *domain, *banner; + const dbus_int32_t array[] = {}; + const dbus_int32_t *varray = array; + peer_cfg_t *peer_cfg; + child_cfg_t *child_cfg; + status_t status = FAILED; + + dbus_error_free(&this->err); + + if (!dbus_message_get_args(msg, &this->err, + DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &user, + DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &passwords, &passwords_count, + DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &data, &data_count, + DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &routes, &routes_count, + DBUS_TYPE_INVALID)) + { + return FALSE; + } + set_state(this, NM_VPN_STATE_STARTING); + + peer_cfg = charon->backends->get_peer_cfg_by_name(charon->backends, name); + if (peer_cfg) + { + free(this->name); + this->name = strdup(peer_cfg->get_name(peer_cfg)); + child_cfg = get_child_from_peer(peer_cfg, name); + if (child_cfg) + { + status = charon->controller->initiate(charon->controller, + peer_cfg, child_cfg, controller_cb_empty, NULL); + } + else + { + peer_cfg->destroy(peer_cfg); + } + } + reply = dbus_message_new_method_return(msg); + dbus_connection_send(this->conn, reply, NULL); + dbus_message_unref(reply); + + if (status == SUCCESS) + { + + set_state(this, NM_VPN_STATE_STARTED); + signal = dbus_message_new_signal(NM_DBUS_PATH_STRONG, + NM_dbus_STRONG, + NM_DBUS_VPN_SIGNAL_IP4_CONFIG); + me = other = p2p = mss = netmask = 0; + dev = domain = banner = ""; + if (dbus_message_append_args(signal, + DBUS_TYPE_UINT32, &other, + DBUS_TYPE_STRING, &dev, + DBUS_TYPE_UINT32, &me, + DBUS_TYPE_UINT32, &p2p, + DBUS_TYPE_UINT32, &netmask, + DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &varray, 0, + DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &varray, 0, + DBUS_TYPE_UINT32, &mss, + DBUS_TYPE_STRING, &domain, + DBUS_TYPE_STRING, &banner, DBUS_TYPE_INVALID)) + { + dbus_connection_send(this->conn, signal, NULL); + } + dbus_message_unref(signal); + } + else + { + set_state(this, NM_VPN_STATE_STOPPED); + } + + dbus_connection_flush(this->conn); + return TRUE; +} + +/** + * process NetworkManagers stopConnection method call + */ +static bool stop_connection(private_dbus_t *this, DBusMessage* msg) +{ + u_int32_t id; + iterator_t *iterator; + ike_sa_t *ike_sa; + + if (this->name == NULL) + { + return FALSE; + } + + dbus_error_free(&this->err); + + set_state(this, NM_VPN_STATE_STOPPING); + + iterator = charon->controller->create_ike_sa_iterator(charon->controller); + while (iterator->iterate(iterator, (void**)&ike_sa)) + { + child_sa_t *child_sa; + iterator_t *children; + + if (this->name && streq(this->name, ike_sa->get_name(ike_sa))) + { + id = ike_sa->get_unique_id(ike_sa); + iterator->destroy(iterator); + charon->controller->terminate_ike(charon->controller, id, NULL, NULL); + set_state(this, NM_VPN_STATE_STOPPED); + return TRUE;; + } + children = ike_sa->create_child_sa_iterator(ike_sa); + while (children->iterate(children, (void**)&child_sa)) + { + if (this->name && streq(this->name, child_sa->get_name(child_sa))) + { + id = child_sa->get_reqid(child_sa); + children->destroy(children); + iterator->destroy(iterator); + charon->controller->terminate_child(charon->controller, id, NULL, NULL); + set_state(this, NM_VPN_STATE_STOPPED); + return TRUE; + } + } + children->destroy(children); + } + iterator->destroy(iterator); + set_state(this, NM_VPN_STATE_STOPPED); + return TRUE; +} + +/** + * process NetworkManagers getState method call + */ +static bool get_state(private_dbus_t *this, DBusMessage* msg) +{ + DBusMessage* reply; + reply = dbus_message_new_method_return(msg); + if (!reply || !dbus_message_append_args(reply, + DBUS_TYPE_UINT32, &this->state, + DBUS_TYPE_INVALID)) + { + return FALSE; + } + dbus_connection_send(this->conn, reply, NULL); + return TRUE; +} + +/** + * Handle incoming messages + */ +static DBusHandlerResult message_handler(DBusConnection *con, DBusMessage *msg, + private_dbus_t *this) +{ + bool handled; + + if (dbus_message_is_method_call(msg, NM_dbus_STRONG, + "startConnection")) + { + handled = start_connection(this, msg); + } + else if (dbus_message_is_method_call(msg, NM_dbus_STRONG, + "stopConnection")) + { + handled = stop_connection(this, msg); + } + else if (dbus_message_is_method_call(msg, NM_dbus_STRONG, + "getState")) + { + handled = get_state(this, msg); + } + else + { + DBG1(DBG_CFG, "ignoring DBUS message %s.%s", + dbus_message_get_interface(msg), dbus_message_get_member(msg)); + handled = FALSE; + } + + if (handled) + { + return DBUS_HANDLER_RESULT_HANDLED; + } + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +/** + * Handle received signals + +static DBusHandlerResult signal_handler(DBusConnection *con, DBusMessage *msg, + private_dbus_t *this) +{ + bool handled; + + if (dbus_message_is_signal(msg, NM_dbus, "VPNConnectionStateChange")) + { + NMVPNState state; + char *name; + + if (dbus_message_get_args(msg, &this->err, DBUS_TYPE_STRING, &name, + DBUS_TYPE_UINT32, &state, DBUS_TYPE_INVALID)) + { + DBG1(DBG_CFG, "got state %d for %s", state, name); + } + handled = TRUE; + } + else + { + DBG1(DBG_CFG, "ignoring DBUS signal %s.%s", + dbus_message_get_interface(msg), dbus_message_get_member(msg)); + handled = FALSE; + } + if (handled) + { + return DBUS_HANDLER_RESULT_HANDLED; + } + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} */ + +/** + * dispatcher function processed by a seperate thread + */ +static job_requeue_t dispatch(private_dbus_t *this) +{ + if (dbus_connection_read_write_dispatch(this->conn, -1)) + { + return JOB_REQUEUE_DIRECT; + } + return JOB_REQUEUE_NONE; +} + +/** + * Implementation of interface_t.destroy. + */ +static void destroy(private_dbus_t *this) +{ + this->job->cancel(this->job); + dbus_connection_close(this->conn); + dbus_error_free(&this->err); + dbus_shutdown(); + free(this->name); + free(this); +} + +/* + * Described in header file + */ +plugin_t *plugin_create() +{ + int ret; + DBusObjectPathVTable v = {NULL, (void*)&message_handler, NULL, NULL, NULL, NULL}; + private_dbus_t *this = malloc_thing(private_dbus_t); + + this->public.plugin.destroy = (void (*)(plugin_t*))destroy; + + dbus_error_init(&this->err); + this->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &this->err); + if (dbus_error_is_set(&this->err)) + { + DBG1(DBG_CFG, "unable to open DBUS connection: %s", this->err.message); + charon->kill(charon, "DBUS initialization failed"); + } + dbus_connection_set_exit_on_disconnect(this->conn, FALSE); + + ret = dbus_bus_request_name(this->conn, NM_DBUS_SERVICE_STRONG, + DBUS_NAME_FLAG_REPLACE_EXISTING , &this->err); + if (dbus_error_is_set(&this->err)) + { + DBG1(DBG_CFG, "unable to set DBUS name: %s", this->err.message); + charon->kill(charon, "unable to set DBUS name"); + } + if (ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) + { + charon->kill(charon, "DBUS name already owned"); + } + if (!dbus_connection_register_object_path(this->conn, NM_DBUS_PATH_STRONG, &v, this)) + { + charon->kill(charon, "unable to register DBUS message handler"); + } + /* + if (!dbus_connection_add_filter(this->conn, (void*)signal_handler, this, NULL)) + { + charon->kill(charon, "unable to register DBUS signal handler"); + } + + dbus_bus_add_match(this->conn, "type='signal', " + "interface='" NM_dbus_VPN "'," + "path='" NM_DBUS_PATH_VPN "'", &this->err); + if (dbus_error_is_set (&this->err)) + { + charon->kill(charon, "unable to add DBUS signal match"); + }*/ + + this->name = NULL; + this->state = NM_VPN_STATE_INIT; + set_state(this, NM_VPN_STATE_STOPPED); + + this->job = callback_job_create((callback_job_cb_t)dispatch, this, NULL, NULL); + charon->processor->queue_job(charon->processor, (job_t*)this->job); + + return &this->public.plugin; +} + diff --git a/src/charon/plugins/dbus/dbus.h b/src/charon/plugins/dbus/dbus.h new file mode 100644 index 000000000..e5bc2d20c --- /dev/null +++ b/src/charon/plugins/dbus/dbus.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2007-2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 dbus dbus + * @ingroup cplugins + * + * @defgroup dbus_i dbus + * @{ @ingroup dbus + */ + +#ifndef DBUS_H_ +#define DBUS_H_ + +#include + +typedef struct dbus_t dbus_t; + +/** + * NetworkManager DBUS control plugin. + * + * This plugin uses a DBUS connection. It is designed to work in conjuction + * with NetworkManager to configure and control the daemon. + */ +struct dbus_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +/** + * Create a dbus plugin instance. + */ +plugin_t *plugin_create(); + +#endif /* DBUS_H_ @}*/ diff --git a/src/charon/plugins/eap_aka/Makefile.am b/src/charon/plugins/eap_aka/Makefile.am new file mode 100644 index 000000000..c938716f9 --- /dev/null +++ b/src/charon/plugins/eap_aka/Makefile.am @@ -0,0 +1,11 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon + +AM_CFLAGS = -rdynamic + +plugin_LTLIBRARIES = libcharon-eapaka.la + +libcharon_eapaka_la_SOURCES = eap_aka_plugin.h eap_aka_plugin.c eap_aka.h eap_aka.c +libcharon_eapaka_la_LDFLAGS = -module +libcharon_eapaka_la_LIBADD = -lgmp + diff --git a/src/charon/plugins/eap_aka/eap_aka.c b/src/charon/plugins/eap_aka/eap_aka.c new file mode 100644 index 000000000..3dd842b9e --- /dev/null +++ b/src/charon/plugins/eap_aka/eap_aka.c @@ -0,0 +1,1557 @@ +/* + * Copyright (C) 2006 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + + +/* The EAP-AKA method uses it's own simple parser for processing EAP-AKA + * payloads, as the IKEv2 parser is not suitable for that job. There are + * two simple methods for parsing payloads, read_header() and read_attribute(). + * Every EAP-AKA payload consists of a header and a list of attributes. Those + * functions mentioned read the data and return the type of the found + * attribute/EAP-AKA-type. For generating a EAP-AKA message, we have a + * build_aka_payload(), which builds the whole message from a variable + * argument list containing its attributes. + * The processing of messages is split up in various functions: + * - peer_process() - General processing multiplexer for the peer + * - peer_process_challenge() - Specific AKA-Challenge processor + * - peer_process_notification() - Processing of AKA-Notification + * - server_process() - General processing multiplexer for the server + * - peer_process_challenge() - Processing of a received Challenge response + * - peer_process_synchronize() - Process a sequence number synchronization + * - server_initiate() - Initiation method for the server, calls + * - server_initiate_challenge() - Initiation of AKA-Challenge + */ + +#include +#include +#include +#include +#include + +#include "eap_aka.h" + +#include +#include +#include +#include + +/* Use test vectors specified in S.S0055 +#define TEST_VECTORS */ + +#define RAND_LENGTH 16 +#define RES_LENGTH 16 +#define SQN_LENGTH 6 +#define K_LENGTH 16 +#define MAC_LENGTH 8 +#define CK_LENGTH 16 +#define IK_LENGTH 16 +#define AK_LENGTH 6 +#define AMF_LENGTH 2 +#define FMK_LENGTH 4 +#define AUTN_LENGTH (SQN_LENGTH + AMF_LENGTH + MAC_LENGTH) +#define AUTS_LENGTH (SQN_LENGTH + MAC_LENGTH) +#define PAYLOAD_LENGTH 64 +#define MK_LENGTH 20 +#define MSK_LENGTH 64 +#define EMSK_LENGTH 64 +#define KAUTH_LENGTH 16 +#define KENCR_LENGTH 16 +#define AT_MAC_LENGTH 16 + +#define F1 0x42 +#define F1STAR 0x43 +#define F2 0x44 +#define F3 0x45 +#define F4 0x46 +#define F5 0x47 +#define F5STAR 0x48 + +typedef enum aka_subtype_t aka_subtype_t; +typedef enum aka_attribute_t aka_attribute_t; + +/** + * Subtypes of AKA messages + */ +enum aka_subtype_t { + AKA_CHALLENGE = 1, + AKA_AUTHENTICATION_REJECT = 2, + AKA_SYNCHRONIZATION_FAILURE = 4, + AKA_IDENTITY = 5, + AKA_NOTIFICATION = 12, + AKA_REAUTHENTICATION = 13, + AKA_CLIENT_ERROR = 14, +}; + +/** + * Attribute types in AKA messages + */ +enum aka_attribute_t { + /** defines the end of attribute list */ + AT_END = -1, + AT_RAND = 1, + AT_AUTN = 2, + AT_RES = 3, + AT_AUTS = 4, + AT_PADDING = 6, + AT_NONCE_MT = 7, + AT_PERMANENT_ID_REQ = 10, + AT_MAC = 11, + AT_NOTIFICATION = 12, + AT_ANY_ID_REQ = 13, + AT_IDENTITY = 14, + AT_VERSION_LIST = 15, + AT_SELECTED_VERSION = 16, + AT_FULLAUTH_ID_REQ = 17, + AT_COUNTER = 19, + AT_COUNTER_TOO_SMALL = 20, + AT_NONCE_S = 21, + AT_CLIENT_ERROR_CODE = 22, + AT_IV = 129, + AT_ENCR_DATA = 130, + AT_NEXT_PSEUDONYM = 132, + AT_NEXT_REAUTH_ID = 133, + AT_CHECKCODE = 134, + AT_RESULT_IND = 135, +}; + +ENUM_BEGIN(aka_subtype_names, AKA_CHALLENGE, AKA_IDENTITY, + "AKA_CHALLENGE", + "AKA_AUTHENTICATION_REJECT", + "AKA_3", + "AKA_SYNCHRONIZATION_FAILURE", + "AKA_IDENTITY"); +ENUM_NEXT(aka_subtype_names, AKA_NOTIFICATION, AKA_CLIENT_ERROR, AKA_IDENTITY, + "AKA_NOTIFICATION", + "AKA_REAUTHENTICATION", + "AKA_CLIENT_ERROR"); +ENUM_END(aka_subtype_names, AKA_CLIENT_ERROR); + + +ENUM_BEGIN(aka_attribute_names, AT_END, AT_CLIENT_ERROR_CODE, + "AT_END", + "AT_0", + "AT_RAND", + "AT_AUTN", + "AT_RES", + "AT_AUTS", + "AT_5", + "AT_PADDING", + "AT_NONCE_MT", + "AT_8", + "AT_9", + "AT_PERMANENT_ID_REQ", + "AT_MAC", + "AT_NOTIFICATION", + "AT_ANY_ID_REQ", + "AT_IDENTITY", + "AT_VERSION_LIST", + "AT_SELECTED_VERSION", + "AT_FULLAUTH_ID_REQ", + "AT_18", + "AT_COUNTER", + "AT_COUNTER_TOO_SMALL", + "AT_NONCE_S", + "AT_CLIENT_ERROR_CODE"); +ENUM_NEXT(aka_attribute_names, AT_IV, AT_RESULT_IND, AT_CLIENT_ERROR_CODE, + "AT_IV", + "AT_ENCR_DATA", + "AT_131", + "AT_NEXT_PSEUDONYM", + "AT_NEXT_REAUTH_ID", + "AT_CHECKCODE", + "AT_RESULT_IND"); +ENUM_END(aka_attribute_names, AT_RESULT_IND); + + +typedef struct private_eap_aka_t private_eap_aka_t; + +/** + * Private data of an eap_aka_t object. + */ +struct private_eap_aka_t { + + /** + * Public authenticator_t interface. + */ + eap_aka_t public; + + /** + * ID of the server + */ + identification_t *server; + + /** + * ID of the peer + */ + identification_t *peer; + + /** + * SHA11 hasher + */ + hasher_t *sha1; + + /** + * SHA1_NOFINAL hasher for G() function + */ + hasher_t *sha1_nof; + + /** + * MAC function used in EAP-AKA + */ + signer_t *signer; + + /** + * pseudo random function used in EAP-aka + */ + prf_t *prf; + + /** + * Key for EAP MAC + */ + chunk_t k_auth; + + /** + * Key for EAP encryption + */ + chunk_t k_encr; + + /** + * MSK + */ + chunk_t msk; + + /** + * Extendend MSK + */ + chunk_t emsk; + + /** + * Expected result from client XRES + */ + chunk_t xres; + + /** + * Shared secret K from ipsec.conf (padded) + */ + chunk_t k; + + /** + * random value RAND generated by server + */ + chunk_t rand; +}; + +/** Family key, as proposed in S.S0055 */ +static u_int8_t fmk_buf[] = {0x41, 0x48, 0x41, 0x47}; +static chunk_t fmk = chunk_from_buf(fmk_buf); + +/** Authentication management field */ +static u_int8_t amf_buf[] = {0x00, 0x01}; +static chunk_t amf = chunk_from_buf(amf_buf); + +/** AT_CLIENT_ERROR_CODE AKA attribute */ +static u_int8_t client_error_code_buf[] = {0, 0}; +static chunk_t client_error_code = chunk_from_buf(client_error_code_buf); + +/** previously used sqn by peer, next one must be greater */ +static u_int8_t peer_sqn_buf[6]; +static chunk_t peer_sqn = chunk_from_buf(peer_sqn_buf); + +/** set SQN to the current time */ +static void update_sqn(u_int8_t *sqn, time_t offset) +{ + timeval_t time; + gettimeofday(&time, NULL); + /* set sqb_sqn to an integer containing seconds followed by most + * significant useconds */ + time.tv_sec = htonl(time.tv_sec + offset); + /* usec's are never larger than 0x000f423f, so we shift the 12 first bits */ + time.tv_usec <<= 12; + time.tv_usec = htonl(time.tv_usec); + memcpy(sqn, &time.tv_sec, 4); + memcpy(sqn + 4, &time.tv_usec, 2); +} + +/** initialize peers SQN to the current system time at startup */ +static void __attribute__ ((constructor))init_sqn(void) +{ + update_sqn(peer_sqn_buf, 0); +} + +/** + * Binary represnation of the polynom T^160 + T^5 + T^3 + T^2 + 1 + */ +static u_int8_t g[] = { + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x2d +}; + +/** + * Predefined random bits from the RAND Corporation book + */ +static u_int8_t a[] = { + 0x9d, 0xe9, 0xc9, 0xc8, 0xef, 0xd5, 0x78, 0x11, + 0x48, 0x23, 0x14, 0x01, 0x90, 0x1f, 0x2d, 0x49, + 0x3f, 0x4c, 0x63, 0x65 +}; + +/** + * Predefined random bits from the RAND Corporation book + */ +static u_int8_t b[] = { + 0x75, 0xef, 0xd1, 0x5c, 0x4b, 0x8f, 0x8f, 0x51, + 0x4e, 0xf3, 0xbc, 0xc3, 0x79, 0x4a, 0x76, 0x5e, + 0x7e, 0xec, 0x45, 0xe0 +}; + +/** + * Multiplicate two mpz_t with bits interpreted as polynoms. + */ +static void mpz_mul_poly(mpz_t r, mpz_t a, mpz_t b) +{ + mpz_t bm, rm; + int current = 0, shifted = 0, shift; + + mpz_init_set(bm, b); + mpz_init_set_ui(rm, 0); + /* scan through a, for each found bit: */ + while ((current = mpz_scan1(a, current)) != ULONG_MAX) + { + /* XOR shifted b into r */ + shift = current - shifted; + mpz_mul_2exp(bm, bm, shift); + shifted += shift; + mpz_xor(rm, rm, bm); + current++; + } + + mpz_swap(r, rm); + mpz_clear(rm); + mpz_clear(bm); +} + +/** + * Calculate the sum of a + b interpreted as polynoms. + */ +static void mpz_add_poly(mpz_t res, mpz_t a, mpz_t b) +{ + /* addition of polynominals is just the XOR */ + mpz_xor(res, a, b); +} + +/** + * Calculate the remainder of a/b interpreted as polynoms. + */ +static void mpz_mod_poly(mpz_t r, mpz_t a, mpz_t b) +{ + /* Example: + * a = 10001010 + * b = 00000101 + */ + int a_bit, b_bit, diff; + mpz_t bm, am; + + mpz_init_set(am, a); + mpz_init(bm); + + a_bit = mpz_sizeinbase(a, 2); + b_bit = mpz_sizeinbase(b, 2); + + /* don't do anything if b > a */ + if (a_bit >= b_bit) + { + /* shift b left to align up most signaficant "1" to a: + * a = 10001010 + * b = 10100000 + */ + mpz_mul_2exp(bm, b, a_bit - b_bit); + do + { + /* XOR b into a, this kills the most significant "1": + * a = 00101010 + */ + mpz_xor(am, am, bm); + /* find the next most significant "1" in a, and align up b: + * a = 00101010 + * b = 00101000 + */ + diff = a_bit - mpz_sizeinbase(am, 2); + mpz_div_2exp(bm, bm, diff); + a_bit -= diff; + } + while (b_bit <= mpz_sizeinbase(bm, 2)); + /* While b is not shifted to its original value */ + } + /* after another iteration: + * a = 00000010 + * which is the polynomial modulo + */ + + mpz_swap(r, am); + mpz_clear(am); + mpz_clear(bm); +} + +/** + * Step 4 of the various fx() functions: + * Polynomial whiten calculations + */ +static void step4(private_eap_aka_t *this, u_int8_t x[]) +{ + mpz_t xm, am, bm, gm; + + mpz_init(xm); + mpz_init(am); + mpz_init(bm); + mpz_init(gm); + + mpz_import(xm, HASH_SIZE_SHA1, 1, 1, 1, 0, x); + mpz_import(am, sizeof(a), 1, 1, 1, 0, a); + mpz_import(bm, sizeof(b), 1, 1, 1, 0, b); + mpz_import(gm, sizeof(g), 1, 1, 1, 0, g); + + mpz_mul_poly(xm, am, xm); + mpz_add_poly(xm, bm, xm); + mpz_mod_poly(xm, xm, gm); + + mpz_export(x, NULL, 1, HASH_SIZE_SHA1, 1, 0, xm); + + mpz_clear(xm); + mpz_clear(am); + mpz_clear(bm); + mpz_clear(gm); +} + +/** + * Implementation of the G() function based on SHA1 + */ +static void g_sha1(private_eap_aka_t *this, + u_int8_t t[], chunk_t c, u_int8_t res[]) +{ + u_int8_t buf[64]; + + if (c.len < sizeof(buf)) + { + /* pad c with zeros */ + memset(buf, 0, sizeof(buf)); + memcpy(buf, c.ptr, c.len); + c.ptr = buf; + c.len = sizeof(buf); + } + else + { + /* not more than 512 bits can be G()-ed */ + c.len = sizeof(buf); + } + + /* calculate the special (HASH_SHA1_STATE) hash*/ + this->sha1_nof->get_hash(this->sha1_nof, c, res); +} + +/** + * Step 3 of the various fx() functions: + * XOR the key into the SHA1 IV + */ +static void step3(private_eap_aka_t *this, + chunk_t k, chunk_t payload, u_int8_t h[]) +{ + u_int8_t iv[] = { + 0x67,0x45,0x23,0x01,0xEF,0xCD,0xAB,0x89,0x98,0xBA, + 0xDC,0xFE,0x10,0x32,0x54,0x76,0xC3,0xD2,0xE1,0xF0, + }; + + /* XOR key into IV */ + memxor(iv, k.ptr, k.len); + + /* hash it with the G() function defined in FIPS 186-2 from fips_prf.h */ + g_sha1(this, iv, payload, h); +} + +/** + * Calculation function for f2(), f3(), f4() + */ +static void fx(private_eap_aka_t *this, + u_int8_t f, chunk_t k, chunk_t rand, u_int8_t out[]) +{ + chunk_t payload = chunk_alloca(PAYLOAD_LENGTH); + u_int8_t h[HASH_SIZE_SHA1]; + u_int8_t i; + + for (i = 0; i < 2; i++) + { + memset(payload.ptr, 0x5c, payload.len); + payload.ptr[11] ^= f; + memxor(payload.ptr + 12, fmk.ptr, fmk.len); + memxor(payload.ptr + 24, rand.ptr, rand.len); + + payload.ptr[3] ^= i; + payload.ptr[19] ^= i; + payload.ptr[35] ^= i; + payload.ptr[51] ^= i; + + step3(this, k, payload, h); + step4(this, h); + memcpy(out + i * 8, h, 8); + } +} + +/** + * Calculation function of f1() and f1star() + */ +static void f1x(private_eap_aka_t *this, + u_int8_t f, chunk_t k, chunk_t rand, chunk_t sqn, + chunk_t amf, u_int8_t mac[]) +{ + /* generate MAC = f1(FMK, SQN, RAND, AMF) + * K is loaded into hashers IV; FMK, RAND, SQN, AMF are XORed in a 512-bit + * payload which gets hashed + */ + chunk_t payload = chunk_alloca(PAYLOAD_LENGTH); + u_int8_t h[HASH_SIZE_SHA1]; + + memset(payload.ptr, 0x5c, PAYLOAD_LENGTH); + payload.ptr[11] ^= f; + memxor(payload.ptr + 12, fmk.ptr, fmk.len); + memxor(payload.ptr + 16, rand.ptr, rand.len); + memxor(payload.ptr + 34, sqn.ptr, sqn.len); + memxor(payload.ptr + 42, amf.ptr, amf.len); + + step3(this, k, payload, h); + step4(this, h); + memcpy(mac, h, MAC_LENGTH); +} + +/** + * Calculation function of f5() and f5star() + */ +static void f5x(private_eap_aka_t *this, + u_int8_t f, chunk_t k, chunk_t rand, u_int8_t ak[]) +{ + chunk_t payload = chunk_alloca(PAYLOAD_LENGTH); + u_int8_t h[HASH_SIZE_SHA1]; + + memset(payload.ptr, 0x5c, payload.len); + payload.ptr[11] ^= f; + memxor(payload.ptr + 12, fmk.ptr, fmk.len); + memxor(payload.ptr + 16, rand.ptr, rand.len); + + step3(this, k, payload, h); + step4(this, h); + memcpy(ak, h, AK_LENGTH); +} + +/** + * Calculate the MAC from a RAND, SQN, AMF value using K + */ +static void f1(private_eap_aka_t *this, chunk_t k, chunk_t rand, chunk_t sqn, + chunk_t amf, u_int8_t mac[]) +{ + f1x(this, F1, k, rand, sqn, amf, mac); + DBG3(DBG_IKE, "MAC %b", mac, MAC_LENGTH); +} + +/** + * Calculate the MACS from a RAND, SQN, AMF value using K + */ +static void f1star(private_eap_aka_t *this, chunk_t k, chunk_t rand, + chunk_t sqn, chunk_t amf, u_int8_t macs[]) +{ + f1x(this, F1STAR, k, rand, sqn, amf, macs); + DBG3(DBG_IKE, "MACS %b", macs, MAC_LENGTH); +} + +/** + * Calculate RES from RAND using K + */ +static void f2(private_eap_aka_t *this, chunk_t k, chunk_t rand, u_int8_t res[]) +{ + fx(this, F2, k, rand, res); + DBG3(DBG_IKE, "RES %b", res, RES_LENGTH); +} + +/** + * Calculate CK from RAND using K + */ +static void f3(private_eap_aka_t *this, chunk_t k, chunk_t rand, u_int8_t ck[]) +{ + fx(this, F3, k, rand, ck); + DBG3(DBG_IKE, "CK %b", ck, CK_LENGTH); +} + +/** + * Calculate IK from RAND using K + */ +static void f4(private_eap_aka_t *this, chunk_t k, chunk_t rand, u_int8_t ik[]) +{ + fx(this, F4, k, rand, ik); + DBG3(DBG_IKE, "IK %b", ik, IK_LENGTH); +} + +/** + * Calculate AK from a RAND using K + */ +static void f5(private_eap_aka_t *this, chunk_t k, chunk_t rand, u_int8_t ak[]) +{ + f5x(this, F5, k, rand, ak); + DBG3(DBG_IKE, "AK %b", ak, AK_LENGTH); +} + +/** + * Calculate AKS from a RAND using K + */ +static void f5star(private_eap_aka_t *this, chunk_t k, chunk_t rand, u_int8_t aks[]) +{ + f5x(this, F5STAR, k, rand, aks); + DBG3(DBG_IKE, "AKS %b", aks, AK_LENGTH); +} + +/** + * derive the keys needed for EAP_AKA + */ +static bool derive_keys(private_eap_aka_t *this, identification_t *id) +{ + chunk_t ck, ik, mk, identity, tmp; + + ck = chunk_alloca(CK_LENGTH); + ik = chunk_alloca(IK_LENGTH); + mk = chunk_alloca(MK_LENGTH); + identity = id->get_encoding(id); + + /* MK = SHA1( Identity | IK | CK ) */ + f3(this, this->k, this->rand, ck.ptr); + f4(this, this->k, this->rand, ik.ptr); + DBG3(DBG_IKE, "Identity %B", &identity); + tmp = chunk_cata("ccc", identity, ik, ck); + DBG3(DBG_IKE, "Identity|IK|CK %B", &tmp); + this->sha1->get_hash(this->sha1, tmp, mk.ptr); + + /* K_encr | K_auth | MSK | EMSK = prf(0) | prf(0) + * FIPS PRF has 320 bit block size, we need 160 byte for keys + * => run prf four times */ + this->prf->set_key(this->prf, mk); + tmp = chunk_alloca(this->prf->get_block_size(this->prf) * 4); + this->prf->get_bytes(this->prf, chunk_empty, tmp.ptr); + this->prf->get_bytes(this->prf, chunk_empty, tmp.ptr + tmp.len / 4 * 1); + this->prf->get_bytes(this->prf, chunk_empty, tmp.ptr + tmp.len / 4 * 2); + this->prf->get_bytes(this->prf, chunk_empty, tmp.ptr + tmp.len / 4 * 3); + chunk_free(&this->k_encr); + chunk_free(&this->k_auth); + chunk_free(&this->msk); + chunk_free(&this->emsk); + chunk_split(tmp, "aaaa", 16, &this->k_encr, 16, &this->k_auth, + 64, &this->msk, 64, &this->emsk); + DBG3(DBG_IKE, "MK %B", &mk); + DBG3(DBG_IKE, "PRF res %B", &tmp); + DBG3(DBG_IKE, "K_encr %B", &this->k_encr); + DBG3(DBG_IKE, "K_auth %B", &this->k_auth); + DBG3(DBG_IKE, "MSK %B", &this->msk); + DBG3(DBG_IKE, "EMSK %B", &this->emsk); + return TRUE; +} + +/* + * Get a shared key from ipsec.secrets. + * We use the standard keys as used in preshared key authentication. As + * these keys have an undefined length, we: + * - strip them if they are longer + * - fill them up with '\0' if they are shorter + */ +static status_t load_key(identification_t *me, identification_t *other, chunk_t *k) +{ + shared_key_t *shared; + chunk_t key; + + shared = charon->credentials->get_shared(charon->credentials, SHARED_EAP, + me, other); + if (shared == NULL) + { + return NOT_FOUND; + } + key = shared->get_key(shared); + chunk_free(k); + *k = chunk_alloc(K_LENGTH); + memset(k->ptr, '\0', k->len); + memcpy(k->ptr, key.ptr, min(key.len, k->len)); + shared->destroy(shared); + return SUCCESS; +} + +/** + * skip EAP_AKA header in message and returns its AKA subtype + */ +static aka_subtype_t read_header(chunk_t *message) +{ + aka_subtype_t type; + + if (message->len < 8) + { + *message = chunk_empty; + return 0; + } + type = *(message->ptr + 5); + *message = chunk_skip(*message, 8); + return type; +} + +/** + * read the next attribute from the chunk data + */ +static aka_attribute_t read_attribute(chunk_t *data, chunk_t *attr_data) +{ + aka_attribute_t attribute; + size_t length; + + DBG3(DBG_IKE, "reading attribute from %B", data); + + if (data->len < 2) + { + return AT_END; + } + /* read attribute and length */ + attribute = *data->ptr++; + length = *data->ptr++ * 4 - 2; + data->len -= 2; + DBG3(DBG_IKE, "found attribute %N with length %d", + aka_attribute_names, attribute, length); + if (length > data->len) + { + return AT_END; + } + /* apply attribute value to attr_data */ + attr_data->len = length; + attr_data->ptr = data->ptr; + /* update data to point to next attribute */ + *data = chunk_skip(*data, length); + return attribute; +} + +/** + * Build an AKA payload from different attributes. + * The variable argument takes an aka_attribute_t + * followed by its data in a chunk. + */ +static eap_payload_t *build_aka_payload(private_eap_aka_t *this, eap_code_t code, + u_int8_t identifier, aka_subtype_t type, ...) +{ + chunk_t message = chunk_alloca(512); /* is enought for all current messages */ + chunk_t pos = message; + eap_payload_t *payload; + va_list args; + aka_attribute_t attr; + u_int8_t *mac_pos = NULL; + + /* write EAP header, skip length bytes */ + *pos.ptr++ = code; + *pos.ptr++ = identifier; + pos.ptr += 2; + pos.len -= 4; + /* write AKA header with type and subtype, null reserved bytes */ + *pos.ptr++ = EAP_AKA; + *pos.ptr++ = type; + *pos.ptr++ = 0; + *pos.ptr++ = 0; + pos.len -= 4; + + va_start(args, type); + while ((attr = va_arg(args, aka_attribute_t)) != AT_END) + { + chunk_t data = va_arg(args, chunk_t); + + DBG3(DBG_IKE, "building %N %B", aka_attribute_names, attr, &data); + + /* write attribute header */ + *pos.ptr++ = attr; + pos.len--; + + switch (attr) + { + case AT_RES: + { + /* attribute length in 4byte words */ + *pos.ptr = data.len/4 + 1; + pos = chunk_skip(pos, 1); + /* RES length in bits */ + *(u_int16_t*)pos.ptr = htons(data.len * 8); + pos = chunk_skip(pos, sizeof(u_int16_t)); + memcpy(pos.ptr, data.ptr, data.len); + pos = chunk_skip(pos, data.len); + break; + } + case AT_AUTN: + case AT_RAND: + { + *pos.ptr++ = data.len/4 + 1; pos.len--; + *pos.ptr++ = 0; pos.len--; + *pos.ptr++ = 0; pos.len--; + memcpy(pos.ptr, data.ptr, data.len); + pos = chunk_skip(pos, data.len); + break; + } + case AT_MAC: + { + *pos.ptr++ = 5; pos.len--; + *pos.ptr++ = 0; pos.len--; + *pos.ptr++ = 0; pos.len--; + mac_pos = pos.ptr; + /* MAC is calculated over message including zeroed AT_MAC attribute */ + memset(mac_pos, 0, AT_MAC_LENGTH); + pos.ptr += AT_MAC_LENGTH; + pos.len -= AT_MAC_LENGTH; + break; + } + default: + { + /* length is data length in 4-bytes + 1 for header */ + *pos.ptr = data.len/4 + 1; + pos = chunk_skip(pos, 1); + memcpy(pos.ptr, data.ptr, data.len); + pos = chunk_skip(pos, data.len); + } + } + } + va_end(args); + + /* calculate message length, write into header */ + message.len = pos.ptr - message.ptr; + *(u_int16_t*)(message.ptr + 2) = htons(message.len); + + /* create MAC if AT_MAC attribte was included */ + if (mac_pos) + { + this->signer->set_key(this->signer, this->k_auth); + DBG3(DBG_IKE, "AT_MAC signature of %B", &message); + DBG3(DBG_IKE, "using key %B", &this->k_auth); + this->signer->get_signature(this->signer, message, mac_pos); + DBG3(DBG_IKE, "is %b", mac_pos, AT_MAC_LENGTH); + } + + /* payload constructor takes data with some bytes skipped */ + payload = eap_payload_create_data(message); + + DBG3(DBG_IKE, "created EAP message %B", &message); + return payload; +} + +/** + * Initiate a AKA-Challenge using SQN + */ +static status_t server_initiate_challenge(private_eap_aka_t *this, chunk_t sqn, + eap_payload_t **out) +{ + randomizer_t *randomizer; + status_t status; + chunk_t mac, ak, autn; + + mac = chunk_alloca(MAC_LENGTH); + ak = chunk_alloca(AK_LENGTH); + chunk_free(&this->rand); + chunk_free(&this->xres); + + /* generate RAND: + * we use our standard randomizer, not f0() proposed in S.S0055 + */ + randomizer = randomizer_create(); + status = randomizer->allocate_pseudo_random_bytes(randomizer, RAND_LENGTH, &this->rand); + randomizer->destroy(randomizer); + if (status != SUCCESS) + { + DBG1(DBG_IKE, "generating RAND for EAP-AKA authentication failed"); + return FAILED; + } + +# ifdef TEST_VECTORS + /* Test vector for RAND */ + u_int8_t test_rand[] = { + 0x4b,0x05,0x2b,0x20,0xe2,0xa0,0x6c,0x8f, + 0xf7,0x00,0xda,0x51,0x2b,0x4e,0x11,0x1e, + }; + memcpy(this->rand.ptr, test_rand, this->rand.len); +# endif /* TEST_VECTORS */ + + /* Get the shared key K: */ + if (load_key(this->server, this->peer, &this->k) != SUCCESS) + { + DBG1(DBG_IKE, "no shared key found for IDs '%D' - '%D' to authenticate " + "with EAP-AKA", this->server, this->peer); + return FAILED; + } + +# ifdef TEST_VECTORS + /* Test vector for K */ + u_int8_t test_k[] = { + 0xad,0x1b,0x5a,0x15,0x9b,0xe8,0x6b,0x2c, + 0xa6,0x6c,0x7a,0xe4,0x0b,0xba,0x9b,0x9d, + }; + memcpy(this->k.ptr, test_k, this->k.len); +# endif /* TEST_VECTORS */ + + /* generate MAC */ + f1(this, this->k, this->rand, sqn, amf, mac.ptr); + + /* generate AK */ + f5(this, this->k, this->rand, ak.ptr); + + /* precalculate XRES as expected from client */ + this->xres = chunk_alloc(RES_LENGTH); + f2(this, this->k, this->rand, this->xres.ptr); + + /* calculate AUTN = (SQN xor AK) || AMF || MAC */ + autn = chunk_cata("ccc", sqn, amf, mac); + memxor(autn.ptr, ak.ptr, ak.len); + DBG3(DBG_IKE, "AUTN %B", &autn); + + + /* derive K_encr, K_auth, MSK, EMSK */ + derive_keys(this, this->peer); + + /* build payload */ + *out = build_aka_payload(this, EAP_REQUEST, 0, AKA_CHALLENGE, + AT_RAND, this->rand, AT_AUTN, autn, AT_MAC, + chunk_empty, AT_END); + return NEED_MORE; +} + +/** + * Implementation of eap_method_t.initiate for an EAP_AKA server + */ +static status_t server_initiate(private_eap_aka_t *this, eap_payload_t **out) +{ + chunk_t sqn = chunk_alloca(SQN_LENGTH); + + /* we use an offset of 3 minutes to tolerate clock inaccuracy + * without the need to synchronize sequence numbers */ + update_sqn(sqn.ptr, 180); + +# ifdef TEST_VECTORS + /* Test vector for SQN */ + u_int8_t test_sqn[] = {0x00,0x00,0x00,0x00,0x00,0x01}; + memcpy(sqn.ptr, test_sqn, sqn.len); +# endif /* TEST_VECTORS */ + + return server_initiate_challenge(this, sqn, out); +} + +static status_t server_process_synchronize(private_eap_aka_t *this, + eap_payload_t *in, eap_payload_t **out) +{ + chunk_t attr, auts = chunk_empty, pos, message, macs, xmacs, sqn, aks, amf; + u_int i; + + message = in->get_data(in); + pos = message; + read_header(&pos); + + /* iterate over attributes */ + while (TRUE) + { + aka_attribute_t attribute = read_attribute(&pos, &attr); + switch (attribute) + { + case AT_END: + break; + case AT_AUTS: + auts = attr; + continue; + default: + if (attribute >= 0 && attribute <= 127) + { + DBG1(DBG_IKE, "found non skippable attribute %N", + aka_attribute_names, attribute); + return FAILED; + } + DBG1(DBG_IKE, "ignoring skippable attribute %N", + aka_attribute_names, attribute); + continue; + } + break; + } + + if (auts.len != AUTS_LENGTH) + { + DBG1(DBG_IKE, "synchronization request didn't contain useable AUTS"); + return FAILED; + } + + chunk_split(auts, "mm", SQN_LENGTH, &sqn, MAC_LENGTH, &macs); + aks = chunk_alloca(AK_LENGTH); + f5star(this, this->k, this->rand, aks.ptr); + /* decrypt serial number by XORing AKS */ + memxor(sqn.ptr, aks.ptr, aks.len); + + /* verify MACS */ + xmacs = chunk_alloca(MAC_LENGTH); + amf = chunk_alloca(AMF_LENGTH); + /* an AMF of zero is used for MACS calculation */ + memset(amf.ptr, 0, amf.len); + f1star(this, this->k, this->rand, sqn, amf, xmacs.ptr); + if (!chunk_equals(macs, xmacs)) + { + DBG1(DBG_IKE, "received MACS does not match XMACS"); + DBG3(DBG_IKE, "MACS %B XMACS %B", &macs, &xmacs); + return FAILED; + } + + /* retry the challenge with the received SQN + 1*/ + for (i = SQN_LENGTH - 1; i >= 0; i--) + { + if (++sqn.ptr[i] != 0) + { + break; + } + } + return server_initiate_challenge(this, sqn, out); +} + +/** + * process an AKA_Challenge response + */ +static status_t server_process_challenge(private_eap_aka_t *this, eap_payload_t *in) +{ + chunk_t attr, res = chunk_empty, at_mac = chunk_empty, pos, message; + + message = in->get_data(in); + pos = message; + read_header(&pos); + + /* iterate over attributes */ + while (TRUE) + { + aka_attribute_t attribute = read_attribute(&pos, &attr); + switch (attribute) + { + case AT_END: + break; + case AT_RES: + res = attr; + if (attr.len == 2 + RES_LENGTH && + *(u_int16_t*)attr.ptr == htons(RES_LENGTH * 8)) + { + res = chunk_skip(attr, 2); + } + continue; + + case AT_MAC: + attr = chunk_skip(attr, 2); + at_mac = chunk_clonea(attr); + /* zero MAC in message for MAC verification */ + memset(attr.ptr, 0, attr.len); + continue; + default: + if (attribute >= 0 && attribute <= 127) + { + DBG1(DBG_IKE, "found non skippable attribute %N", + aka_attribute_names, attribute); + return FAILED; + } + DBG1(DBG_IKE, "ignoring skippable attribute %N", + aka_attribute_names, attribute); + continue; + } + break; + } + + /* verify EAP message MAC AT_MAC */ + { + this->signer->set_key(this->signer, this->k_auth); + DBG3(DBG_IKE, "verifying AT_MAC signature of %B", &message); + DBG3(DBG_IKE, "using key %B", &this->k_auth); + if (!this->signer->verify_signature(this->signer, message, at_mac)) + { + DBG1(DBG_IKE, "MAC in AT_MAC attribute verification failed"); + return FAILED; + } + } + + /* compare received RES against stored precalculated XRES */ + if (!chunk_equals(res, this->xres)) + { + DBG1(DBG_IKE, "received RES does not match XRES"); + DBG3(DBG_IKE, "RES %Bb XRES %B", &res, &this->xres); + return FAILED; + } + return SUCCESS; +} + +/** + * Implementation of eap_method_t.process for EAP_AKA servers + */ +static status_t server_process(private_eap_aka_t *this, + eap_payload_t *in, eap_payload_t **out) +{ + chunk_t message; + aka_subtype_t type; + + message = in->get_data(in); + type = read_header(&message); + + DBG3(DBG_IKE, "received EAP message %B", &message); + + switch (type) + { + case AKA_CHALLENGE: + { + return server_process_challenge(this, in); + } + case AKA_AUTHENTICATION_REJECT: + case AKA_CLIENT_ERROR: + { + DBG1(DBG_IKE, "received %N, authentication failed", + aka_subtype_names, type); + return FAILED; + } + case AKA_SYNCHRONIZATION_FAILURE: + { + DBG1(DBG_IKE, "received %N, retrying with received SQN", + aka_subtype_names, type); + return server_process_synchronize(this, in, out); + } + default: + DBG1(DBG_IKE, "received unknown AKA subtype %N, authentication failed", + aka_subtype_names, type); + return FAILED; + } +} + +/** + * Process an incoming AKA-Challenge client side + */ +static status_t peer_process_challenge(private_eap_aka_t *this, + eap_payload_t *in, eap_payload_t **out) +{ + chunk_t attr = chunk_empty; + chunk_t autn = chunk_empty, at_mac = chunk_empty; + chunk_t ak, sqn, sqn_ak, mac, xmac, res, amf, message, pos; + u_int8_t identifier; + + ak = chunk_alloca(AK_LENGTH); + xmac = chunk_alloca(MAC_LENGTH); + res = chunk_alloca(RES_LENGTH); + chunk_free(&this->rand); + + message = in->get_data(in); + pos = message; + read_header(&pos); + identifier = in->get_identifier(in); + + DBG3(DBG_IKE, "reading attributes from %B", &pos); + + /* iterate over attributes */ + while (TRUE) + { + aka_attribute_t attribute = read_attribute(&pos, &attr); + switch (attribute) + { + case AT_END: + break; + case AT_RAND: + this->rand = chunk_clone(chunk_skip(attr, 2)); + continue; + case AT_AUTN: + autn = chunk_skip(attr, 2); + continue; + case AT_MAC: + attr = chunk_skip(attr, 2); + at_mac = chunk_clonea(attr); + /* set MAC in message to zero for own MAC verification */ + memset(attr.ptr, 0, attr.len); + continue; + default: + if (attribute >= 0 && attribute <= 127) + { + /* non skippable attribute, abort */ + *out = build_aka_payload(this, EAP_RESPONSE, identifier, AKA_CLIENT_ERROR, + AT_CLIENT_ERROR_CODE, client_error_code, AT_END); + DBG1(DBG_IKE, "found non skippable attribute %N, sending %N %d", + aka_attribute_names, attribute, + aka_attribute_names, AT_CLIENT_ERROR_CODE, 0); + return NEED_MORE; + } + DBG1(DBG_IKE, "ignoring skippable attribute %N", + aka_attribute_names, attribute); + continue; + } + break; + } + + if (this->rand.len != RAND_LENGTH || autn.len != AUTN_LENGTH) + { + /* required attributes wrong/not found, abort */ + *out = build_aka_payload(this, EAP_RESPONSE, identifier, AKA_CLIENT_ERROR, + AT_CLIENT_ERROR_CODE, client_error_code, AT_END); + DBG1(DBG_IKE, "could not find valid RAND/AUTN attribute, sending %N %d", + aka_attribute_names, AT_CLIENT_ERROR_CODE, 0); + return NEED_MORE; + } + + DBG3(DBG_IKE, "using autn %B", &autn); + /* split up AUTN = SQN xor AK | AMF | MAC */ + chunk_split(autn, "mmm", SQN_LENGTH, &sqn_ak, AMF_LENGTH, &amf, MAC_LENGTH, &mac); + + /* Get the shared key K: */ + chunk_free(&this->k); + if (load_key(this->peer, this->server, &this->k) != SUCCESS) + { + *out = build_aka_payload(this, EAP_RESPONSE, identifier, + AKA_AUTHENTICATION_REJECT, AT_END); + DBG3(DBG_IKE, "no shared key found for IDs '%D' - '%D' to authenticate " + "with EAP-AKA, sending %N", this->peer, this->server, + aka_subtype_names, AKA_AUTHENTICATION_REJECT); + return NEED_MORE; + } + DBG3(DBG_IKE, "using K %B", &this->k); +# ifdef TEST_VECTORS + /* Test vector for K */ + u_int8_t test_k[] = { + 0xad,0x1b,0x5a,0x15,0x9b,0xe8,0x6b,0x2c, + 0xa6,0x6c,0x7a,0xe4,0x0b,0xba,0x9b,0x9d, + }; + memcpy(this->k.ptr, test_k, this->k.len); +# endif /* TEST_VECTORS */ + + /* calculate anonymity key AK */ + f5(this, this->k, this->rand, ak.ptr); + DBG3(DBG_IKE, "using rand %B", &this->rand); + DBG3(DBG_IKE, "using ak %B", &ak); + /* XOR AK into SQN to decrypt it */ + + sqn = chunk_clonea(sqn_ak); + + DBG3(DBG_IKE, "using ak xor sqn %B", &sqn_ak); + memxor(sqn.ptr, ak.ptr, sqn.len); + DBG3(DBG_IKE, "using sqn %B", &sqn); + + /* calculate expected MAC and compare against received one */ + f1(this, this->k, this->rand, sqn, amf, xmac.ptr); + if (!chunk_equals(mac, xmac)) + { + *out = build_aka_payload(this, EAP_RESPONSE, identifier, + AKA_AUTHENTICATION_REJECT, AT_END); + DBG1(DBG_IKE, "received MAC does not match XMAC, sending %N", + aka_subtype_names, AKA_AUTHENTICATION_REJECT); + DBG3(DBG_IKE, "MAC %B\nXMAC %B", &mac, &xmac); + return NEED_MORE; + } + +#if SEQ_CHECK + if (memcmp(peer_sqn.ptr, sqn.ptr, sqn.len) >= 0) + { + /* sequence number invalid. send AUTS */ + chunk_t auts, macs, aks, amf; + + macs = chunk_alloca(MAC_LENGTH); + aks = chunk_alloca(AK_LENGTH); + amf = chunk_alloca(AMF_LENGTH); + + /* AMF is set to zero in AKA_SYNCHRONIZATION_FAILURE */ + memset(amf.ptr, 0, amf.len); + /* AKS = f5*(RAND) */ + f5star(this, this->k, this->rand, aks.ptr); + /* MACS = f1*(RAND) */ + f1star(this, this->k, this->rand, peer_sqn, amf, macs.ptr); + /* AUTS = SQN xor AKS | MACS */ + memxor(aks.ptr, peer_sqn.ptr, aks.len); + auts = chunk_cata("cc", aks, macs); + + *out = build_aka_payload(this, EAP_RESPONSE, identifier, + AKA_SYNCHRONIZATION_FAILURE, + AT_AUTS, auts, AT_END); + DBG1(DBG_IKE, "received SQN invalid, sending %N", + aka_subtype_names, AKA_SYNCHRONIZATION_FAILURE); + DBG3(DBG_IKE, "received SQN %B\ncurrent SQN %B", &sqn, &peer_sqn); + return NEED_MORE; + } +#endif /* SEQ_CHECK */ + + /* derive K_encr, K_auth, MSK, EMSK */ + derive_keys(this, this->peer); + + /* verify EAP message MAC AT_MAC */ + DBG3(DBG_IKE, "verifying AT_MAC signature of %B", &message); + DBG3(DBG_IKE, "using key %B", &this->k_auth); + if (!this->signer->verify_signature(this->signer, message, at_mac)) + { + *out = build_aka_payload(this, EAP_RESPONSE, identifier, AKA_CLIENT_ERROR, + AT_CLIENT_ERROR_CODE, client_error_code, AT_END); + DBG1(DBG_IKE, "MAC in AT_MAC attribute verification " + "failed, sending %N %d", aka_attribute_names, + AT_CLIENT_ERROR_CODE, 0); + return NEED_MORE; + } + + /* update stored SQN to the received one */ + memcpy(peer_sqn.ptr, sqn.ptr, sqn.len); + + /* calculate RES */ + f2(this, this->k, this->rand, res.ptr); + + /* build response */ + *out = build_aka_payload(this, EAP_RESPONSE, identifier, AKA_CHALLENGE, + AT_RES, res, AT_MAC, chunk_empty, AT_END); + return NEED_MORE; +} + +/** + * Process an incoming AKA-Notification as client + */ +static status_t peer_process_notification(private_eap_aka_t *this, + eap_payload_t *in, eap_payload_t **out) +{ + chunk_t message, pos, attr; + u_int8_t identifier; + + message = in->get_data(in); + pos = message; + read_header(&pos); + identifier = in->get_identifier(in); + + DBG3(DBG_IKE, "reading attributes from %B", &pos); + + /* iterate over attributes */ + while (TRUE) + { + aka_attribute_t attribute = read_attribute(&pos, &attr); + switch (attribute) + { + case AT_END: + break; + case AT_NOTIFICATION: + { + u_int16_t code; + + if (attr.len != 2) + { + DBG1(DBG_IKE, "received invalid AKA notification, ignored"); + continue; + } + code = ntohs(*(u_int16_t*)attr.ptr); + switch (code) + { + case 0: + DBG1(DBG_IKE, "received AKA notification 'general " + "failure after authentication' (%d)", code); + return FAILED; + case 16384: + DBG1(DBG_IKE, "received AKA notification 'general " + "failure' (%d)", code); + return FAILED; + case 32768: + DBG1(DBG_IKE, "received AKA notification 'successfully " + "authenticated' (%d)", code); + continue; + case 1026: + DBG1(DBG_IKE, "received AKA notification 'access " + "temporarily denied' (%d)", code); + return FAILED; + case 1031: + DBG1(DBG_IKE, "received AKA notification 'not " + "subscribed to service' (%d)", code); + return FAILED; + default: + DBG1(DBG_IKE, "received AKA notification code %d, " + "ignored", code); + continue; + } + } + default: + if (attribute >= 0 && attribute <= 127) + { + DBG1(DBG_IKE, "ignoring non-skippable attribute %N in %N", + aka_attribute_names, attribute, aka_subtype_names, + AKA_NOTIFICATION); + } + else + { + DBG1(DBG_IKE, "ignoring skippable attribute %N", + aka_attribute_names, attribute); + } + continue; + } + break; + } + return NEED_MORE; +} + +/** + * Implementation of eap_method_t.process for an EAP_AKA peer + */ +static status_t peer_process(private_eap_aka_t *this, + eap_payload_t *in, eap_payload_t **out) +{ + aka_subtype_t type; + chunk_t message; + u_int8_t identifier; + + message = in->get_data(in); + type = read_header(&message); + identifier = in->get_identifier(in); + + DBG3(DBG_IKE, "received EAP message %B", &message); + + switch (type) + { + case AKA_CHALLENGE: + { + return peer_process_challenge(this, in, out); + } + case AKA_NOTIFICATION: + { + return peer_process_notification(this, in, out); + } + default: + { + *out = build_aka_payload(this, EAP_RESPONSE, identifier, AKA_CLIENT_ERROR, + AT_CLIENT_ERROR_CODE, client_error_code, AT_END); + DBG1(DBG_IKE, "received unsupported %N request, sending %N %d", + aka_subtype_names, type, + aka_attribute_names, AT_CLIENT_ERROR_CODE, 0); + return NEED_MORE; + } + } +} + +/** + * Implementation of eap_method_t.initiate for an EAP AKA peer + */ +static status_t peer_initiate(private_eap_aka_t *this, eap_payload_t **out) +{ + /* peer never initiates */ + return FAILED; +} + +/** + * Implementation of eap_method_t.get_type. + */ +static eap_type_t get_type(private_eap_aka_t *this, u_int32_t *vendor) +{ + *vendor = 0; + return EAP_AKA; +} + +/** + * Implementation of eap_method_t.get_msk. + */ +static status_t get_msk(private_eap_aka_t *this, chunk_t *msk) +{ + if (this->msk.ptr) + { + *msk = this->msk; + return SUCCESS; + } + return FAILED; +} + +/** + * Implementation of eap_method_t.is_mutual. + */ +static bool is_mutual(private_eap_aka_t *this) +{ + return TRUE; +} + +/** + * Implementation of eap_method_t.destroy. + */ +static void destroy(private_eap_aka_t *this) +{ + DESTROY_IF(this->sha1); + DESTROY_IF(this->sha1_nof); + DESTROY_IF(this->signer); + DESTROY_IF(this->prf); + chunk_free(&this->k_encr); + chunk_free(&this->k_auth); + chunk_free(&this->msk); + chunk_free(&this->emsk); + chunk_free(&this->xres); + chunk_free(&this->k); + chunk_free(&this->rand); + free(this); +} + +/** + * generic constructor used by client & server + */ +static private_eap_aka_t *eap_aka_create_generic(identification_t *server, + identification_t *peer) +{ + private_eap_aka_t *this = malloc_thing(private_eap_aka_t); + + this->public.eap_method_interface.initiate = NULL; + this->public.eap_method_interface.process = NULL; + this->public.eap_method_interface.get_type = (eap_type_t(*)(eap_method_t*,u_int32_t*))get_type; + this->public.eap_method_interface.is_mutual = (bool(*)(eap_method_t*))is_mutual; + this->public.eap_method_interface.get_msk = (status_t(*)(eap_method_t*,chunk_t*))get_msk; + this->public.eap_method_interface.destroy = (void(*)(eap_method_t*))destroy; + + /* private data */ + this->server = server; + this->peer = peer; + this->k_encr = chunk_empty; + this->k_auth = chunk_empty; + this->msk = chunk_empty; + this->emsk = chunk_empty; + this->xres = chunk_empty; + this->k = chunk_empty; + this->rand = chunk_empty; + + this->sha1 = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); + this->sha1_nof = lib->crypto->create_hasher(lib->crypto, HASH_SHA1_NOFINAL); + this->signer = lib->crypto->create_signer(lib->crypto, AUTH_HMAC_SHA1_128); + this->prf = lib->crypto->create_prf(lib->crypto, PRF_FIPS_SHA1_160); + + if (!this->sha1 || !this->sha1_nof || !this->signer || !this->prf) + { + DBG1(DBG_IKE, "unable to initiate EAP-AKA, FIPS-PRF/SHA1 not supported"); + DESTROY_IF(this->sha1); + DESTROY_IF(this->sha1_nof); + DESTROY_IF(this->signer); + DESTROY_IF(this->prf); + destroy(this); + return NULL; + } + return this; +} + +/* + * Described in header. + */ +eap_aka_t *eap_aka_create_server(identification_t *server, identification_t *peer) +{ + private_eap_aka_t *this = eap_aka_create_generic(server, peer); + + if (this) + { + this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))server_initiate; + this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))server_process; + } + return (eap_aka_t*)this; +} + +/* + * Described in header. + */ +eap_aka_t *eap_aka_create_peer(identification_t *server, identification_t *peer) +{ + private_eap_aka_t *this = eap_aka_create_generic(server, peer); + + if (this) + { + this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))peer_initiate; + this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))peer_process; + } + return (eap_aka_t*)this; +} + diff --git a/src/charon/plugins/eap_aka/eap_aka.h b/src/charon/plugins/eap_aka/eap_aka.h new file mode 100644 index 000000000..1ee8496b2 --- /dev/null +++ b/src/charon/plugins/eap_aka/eap_aka.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +/** + * @defgroup eap_aka_i eap_aka + * @{ @ingroup eap_aka + */ + +#ifndef EAP_AKA_H_ +#define EAP_AKA_H_ + +typedef struct eap_aka_t eap_aka_t; + +#include + +/** check SEQ values as client for validity, disabled by default */ +#ifndef SEQ_CHECK +# define SEQ_CHECK 0 +#endif + +/** + * Implementation of the eap_method_t interface using EAP-AKA. + * + * EAP-AKA uses 3rd generation mobile phone standard authentication + * mechanism for authentication. It is a mutual authentication + * mechanism which establishs a shared key and therefore supports EAP_ONLY + * authentication. This implementation follows the standard of the + * 3GPP2 (S.S0055) and not the one of 3GGP. + * The shared key used for authentication is from ipsec.secrets. The + * peers ID is used to query it. + * The AKA mechanism uses sequence numbers to detect replay attacks. The + * peer stores the sequence number normally in a USIM and accepts + * incremental sequence numbers (incremental for lifetime of the USIM). To + * prevent a complex sequence number management, this implementation uses + * a sequence number derived from time. It is initialized to the startup + * time of the daemon. As long as the (UTC) time of the system is not + * turned back while the daemon is not running, this method is secure. + * To enable time based SEQs, #define SEQ_CHECK as 1. Default is to accept + * any SEQ numbers. This allows an attacker to do replay attacks. But since + * the server has proven his identity via IKE, such an attack is only + * possible between server and AAA (if any). + */ +struct eap_aka_t { + + /** + * Implemented eap_method_t interface. + */ + eap_method_t eap_method_interface; +}; + +/** + * Creates the server implementation of the EAP method EAP-AKA. + * + * @param server ID of the EAP server + * @param peer ID of the EAP client + * @return eap_aka_t object + */ +eap_aka_t *eap_aka_create_server(identification_t *server, identification_t *peer); + +/** + * Creates the peer implementation of the EAP method EAP-AKA. + * + * @param server ID of the EAP server + * @param peer ID of the EAP client + * @return eap_aka_t object + */ +eap_aka_t *eap_aka_create_peer(identification_t *server, identification_t *peer); + +#endif /* EAP_AKA_H_ @}*/ diff --git a/src/charon/plugins/eap_aka/eap_aka_plugin.c b/src/charon/plugins/eap_aka/eap_aka_plugin.c new file mode 100644 index 000000000..1975d6fd3 --- /dev/null +++ b/src/charon/plugins/eap_aka/eap_aka_plugin.c @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "eap_aka_plugin.h" + +#include "eap_aka.h" + +#include + +/** + * Implementation of plugin_t.destroy + */ +static void destroy(eap_aka_plugin_t *this) +{ + charon->eap->remove_method(charon->eap, + (eap_constructor_t)eap_aka_create_server); + charon->eap->remove_method(charon->eap, + (eap_constructor_t)eap_aka_create_peer); + free(this); +} + +/* + * see header file + */ +plugin_t *plugin_create() +{ + eap_aka_plugin_t *this = malloc_thing(eap_aka_plugin_t); + + this->plugin.destroy = (void(*)(plugin_t*))destroy; + + charon->eap->add_method(charon->eap, EAP_AKA, 0, EAP_SERVER, + (eap_constructor_t)eap_aka_create_server); + charon->eap->add_method(charon->eap, EAP_AKA, 0, EAP_PEER, + (eap_constructor_t)eap_aka_create_peer); + + return &this->plugin; +} + diff --git a/src/charon/plugins/eap_aka/eap_aka_plugin.h b/src/charon/plugins/eap_aka/eap_aka_plugin.h new file mode 100644 index 000000000..07fcc8294 --- /dev/null +++ b/src/charon/plugins/eap_aka/eap_aka_plugin.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +/** + * @defgroup eap_aka eap_aka + * @ingroup cplugins + * + * @defgroup eap_aka_plugin eap_aka_plugin + * @{ @ingroup eap_aka + */ + +#ifndef EAP_AKA_PLUGIN_H_ +#define EAP_AKA_PLUGIN_H_ + +#include + +typedef struct eap_aka_plugin_t eap_aka_plugin_t; + +/** + * EAP-AKA plugin + */ +struct eap_aka_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +/** + * Create a eap_aka_plugin instance. + */ +plugin_t *plugin_create(); + +#endif /* EAP_AKA_PLUGIN_H_ @}*/ diff --git a/src/charon/plugins/eap_identity/Makefile.am b/src/charon/plugins/eap_identity/Makefile.am new file mode 100644 index 000000000..1ce2426f2 --- /dev/null +++ b/src/charon/plugins/eap_identity/Makefile.am @@ -0,0 +1,10 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon + +AM_CFLAGS = -rdynamic + +plugin_LTLIBRARIES = libcharon-eapidentity.la +libcharon_eapidentity_la_SOURCES = \ + eap_identity_plugin.h eap_identity_plugin.c eap_identity.h eap_identity.c +libcharon_eapidentity_la_LDFLAGS = -module + diff --git a/src/charon/plugins/eap_identity/eap_identity.c b/src/charon/plugins/eap_identity/eap_identity.c new file mode 100644 index 000000000..f6835c7f2 --- /dev/null +++ b/src/charon/plugins/eap_identity/eap_identity.c @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "eap_identity.h" + +#include +#include + +typedef struct private_eap_identity_t private_eap_identity_t; + +/** + * Private data of an eap_identity_t object. + */ +struct private_eap_identity_t { + + /** + * Public authenticator_t interface. + */ + eap_identity_t public; + + /** + * ID of the peer + */ + identification_t *peer; +}; + +/** + * Implementation of eap_method_t.process for the peer + */ +static status_t process(private_eap_identity_t *this, + eap_payload_t *in, eap_payload_t **out) +{ + chunk_t id, hdr; + + hdr = chunk_alloca(5); + id = this->peer->get_encoding(this->peer); + + *(hdr.ptr + 0) = EAP_RESPONSE; + *(hdr.ptr + 1) = in->get_identifier(in); + *(u_int16_t*)(hdr.ptr + 2) = htons(hdr.len + id.len); + *(hdr.ptr + 4) = EAP_IDENTITY; + + *out = eap_payload_create_data(chunk_cata("cc", hdr, id)); + return SUCCESS; + +} + +/** + * Implementation of eap_method_t.initiate for the peer + */ +static status_t initiate(private_eap_identity_t *this, eap_payload_t **out) +{ + /* peer never initiates */ + return FAILED; +} + +/** + * Implementation of eap_method_t.get_type. + */ +static eap_type_t get_type(private_eap_identity_t *this, u_int32_t *vendor) +{ + *vendor = 0; + return EAP_IDENTITY; +} + +/** + * Implementation of eap_method_t.get_msk. + */ +static status_t get_msk(private_eap_identity_t *this, chunk_t *msk) +{ + return FAILED; +} + +/** + * Implementation of eap_method_t.is_mutual. + */ +static bool is_mutual(private_eap_identity_t *this) +{ + return FALSE; +} + +/** + * Implementation of eap_method_t.destroy. + */ +static void destroy(private_eap_identity_t *this) +{ + free(this); +} + +/* + * Described in header. + */ +eap_identity_t *eap_identity_create_peer(identification_t *server, + identification_t *peer) +{ + private_eap_identity_t *this = malloc_thing(private_eap_identity_t); + + /* public functions */ + this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))initiate; + this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))process; + this->public.eap_method_interface.get_type = (eap_type_t(*)(eap_method_t*,u_int32_t*))get_type; + this->public.eap_method_interface.is_mutual = (bool(*)(eap_method_t*))is_mutual; + this->public.eap_method_interface.get_msk = (status_t(*)(eap_method_t*,chunk_t*))get_msk; + this->public.eap_method_interface.destroy = (void(*)(eap_method_t*))destroy; + + /* private data */ + this->peer = peer; + + return &this->public; +} + diff --git a/src/charon/plugins/eap_identity/eap_identity.h b/src/charon/plugins/eap_identity/eap_identity.h new file mode 100644 index 000000000..5d297f798 --- /dev/null +++ b/src/charon/plugins/eap_identity/eap_identity.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +/** + * @defgroup eap_identity_i eap_identity + * @{ @ingroup eap_identity + */ + +#ifndef EAP_IDENTITY_H_ +#define EAP_IDENTITY_H_ + +typedef struct eap_identity_t eap_identity_t; + +#include + +/** + * Implementation of the eap_method_t interface using EAP Identity. + */ +struct eap_identity_t { + + /** + * Implemented eap_method_t interface. + */ + eap_method_t eap_method_interface; +}; + +/** + * Creates the EAP method EAP Identity, acting as peer. + * + * @param server ID of the EAP server + * @param peer ID of the EAP client + * @return eap_identity_t object + */ +eap_identity_t *eap_identity_create_peer(identification_t *server, + identification_t *peer); + +#endif /* EAP_IDENTITY_H_ @}*/ diff --git a/src/charon/plugins/eap_identity/eap_identity_plugin.c b/src/charon/plugins/eap_identity/eap_identity_plugin.c new file mode 100644 index 000000000..22a884a3e --- /dev/null +++ b/src/charon/plugins/eap_identity/eap_identity_plugin.c @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "eap_identity_plugin.h" + +#include "eap_identity.h" + +#include + +/** + * Implementation of plugin_t.destroy + */ +static void destroy(eap_identity_plugin_t *this) +{ + charon->eap->remove_method(charon->eap, + (eap_constructor_t)eap_identity_create_peer); + free(this); +} + +/* + * see header file + */ +plugin_t *plugin_create() +{ + eap_identity_plugin_t *this = malloc_thing(eap_identity_plugin_t); + + this->plugin.destroy = (void(*)(plugin_t*))destroy; + + charon->eap->add_method(charon->eap, EAP_IDENTITY, 0, EAP_PEER, + (eap_constructor_t)eap_identity_create_peer); + + return &this->plugin; +} + diff --git a/src/charon/plugins/eap_identity/eap_identity_plugin.h b/src/charon/plugins/eap_identity/eap_identity_plugin.h new file mode 100644 index 000000000..d41c14114 --- /dev/null +++ b/src/charon/plugins/eap_identity/eap_identity_plugin.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +/** + * @defgroup eap_identity eap_identity + * @ingroup cplugins + * + * @defgroup eap_identity_plugin eap_identity_plugin + * @{ @ingroup eap_identity + */ + +#ifndef EAP_IDENTITY_PLUGIN_H_ +#define EAP_IDENTITY_PLUGIN_H_ + +#include + +typedef struct eap_identity_plugin_t eap_identity_plugin_t; + +/** + * EAP-IDENTITY plugin. + */ +struct eap_identity_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +/** + * Create a eap_identity_plugin instance. + */ +plugin_t *plugin_create(); + +#endif /* EAP_IDENTITY_PLUGIN_H_ @}*/ diff --git a/src/charon/plugins/eap_md5/Makefile.am b/src/charon/plugins/eap_md5/Makefile.am new file mode 100644 index 000000000..2d6d68f15 --- /dev/null +++ b/src/charon/plugins/eap_md5/Makefile.am @@ -0,0 +1,10 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon + +AM_CFLAGS = -rdynamic + +plugin_LTLIBRARIES = libcharon-eapmd5.la + +libcharon_eapmd5_la_SOURCES = eap_md5_plugin.h eap_md5_plugin.c eap_md5.h eap_md5.c +libcharon_eapmd5_la_LDFLAGS = -module + diff --git a/src/charon/plugins/eap_md5/eap_md5.c b/src/charon/plugins/eap_md5/eap_md5.c new file mode 100644 index 000000000..702042f37 --- /dev/null +++ b/src/charon/plugins/eap_md5/eap_md5.c @@ -0,0 +1,300 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "eap_md5.h" + +#include +#include +#include + +typedef struct private_eap_md5_t private_eap_md5_t; + +/** + * Private data of an eap_md5_t object. + */ +struct private_eap_md5_t { + + /** + * Public authenticator_t interface. + */ + eap_md5_t public; + + /** + * ID of the server + */ + identification_t *server; + + /** + * ID of the peer + */ + identification_t *peer; + + /** + * challenge sent by the server + */ + chunk_t challenge; + + /** + * EAP message identififier + */ + u_int8_t identifier; +}; + +typedef struct eap_md5_header_t eap_md5_header_t; + +/** + * packed eap MD5 header struct + */ +struct eap_md5_header_t { + /** EAP code (REQUEST/RESPONSE) */ + u_int8_t code; + /** unique message identifier */ + u_int8_t identifier; + /** length of whole message */ + u_int16_t length; + /** EAP type */ + u_int8_t type; + /** length of value (challenge) */ + u_int8_t value_size; + /** actual value */ + u_int8_t value[]; +} __attribute__((__packed__)); + +#define CHALLENGE_LEN 16 +#define PAYLOAD_LEN (CHALLENGE_LEN + sizeof(eap_md5_header_t)) + +/** + * Hash the challenge string, create response + */ +static status_t hash_challenge(private_eap_md5_t *this, chunk_t *response) +{ + shared_key_t *shared; + chunk_t concat; + hasher_t *hasher; + + shared = charon->credentials->get_shared(charon->credentials, SHARED_EAP, + this->server, this->peer); + if (shared == NULL) + { + DBG1(DBG_IKE, "no EAP key found for hosts '%D' - '%D'", + this->server, this->peer); + return NOT_FOUND; + } + concat = chunk_cata("ccc", chunk_from_thing(this->identifier), + shared->get_key(shared), this->challenge); + shared->destroy(shared); + hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5); + if (hasher == NULL) + { + DBG1(DBG_IKE, "EAP-MD5 failed, MD5 not supported"); + return FAILED; + } + hasher->allocate_hash(hasher, concat, response); + hasher->destroy(hasher); + return SUCCESS; +} + +/** + * Implementation of eap_method_t.initiate for the peer + */ +static status_t initiate_peer(private_eap_md5_t *this, eap_payload_t **out) +{ + /* peer never initiates */ + return FAILED; +} + +/** + * Implementation of eap_method_t.initiate for the server + */ +static status_t initiate_server(private_eap_md5_t *this, eap_payload_t **out) +{ + randomizer_t *randomizer; + status_t status; + eap_md5_header_t *req; + + randomizer = randomizer_create(); + status = randomizer->allocate_pseudo_random_bytes(randomizer, CHALLENGE_LEN, + &this->challenge); + randomizer->destroy(randomizer); + if (status != SUCCESS) + { + return FAILED; + } + + req = alloca(PAYLOAD_LEN); + req->length = htons(PAYLOAD_LEN); + req->code = EAP_REQUEST; + req->identifier = this->identifier; + req->type = EAP_MD5; + req->value_size = this->challenge.len; + memcpy(req->value, this->challenge.ptr, this->challenge.len); + + *out = eap_payload_create_data(chunk_create((void*)req, PAYLOAD_LEN)); + return NEED_MORE; +} + +/** + * Implementation of eap_method_t.process for the peer + */ +static status_t process_peer(private_eap_md5_t *this, + eap_payload_t *in, eap_payload_t **out) +{ + chunk_t response; + chunk_t data; + eap_md5_header_t *req; + + this->identifier = in->get_identifier(in); + data = in->get_data(in); + this->challenge = chunk_clone(chunk_skip(data, 6)); + if (data.len < 6 || this->challenge.len < *(data.ptr + 5)) + { + DBG1(DBG_IKE, "received invalid EAP-MD5 message"); + return FAILED; + } + if (hash_challenge(this, &response) != SUCCESS) + { + return FAILED; + } + req = alloca(PAYLOAD_LEN); + req->length = htons(PAYLOAD_LEN); + req->code = EAP_RESPONSE; + req->identifier = this->identifier; + req->type = EAP_MD5; + req->value_size = response.len; + memcpy(req->value, response.ptr, response.len); + chunk_free(&response); + + *out = eap_payload_create_data(chunk_create((void*)req, PAYLOAD_LEN)); + return NEED_MORE; +} + +/** + * Implementation of eap_method_t.process for the server + */ +static status_t process_server(private_eap_md5_t *this, + eap_payload_t *in, eap_payload_t **out) +{ + chunk_t response, expected; + chunk_t data; + + if (this->identifier != in->get_identifier(in)) + { + DBG1(DBG_IKE, "received invalid EAP-MD5 message"); + return FAILED; + } + if (hash_challenge(this, &expected) != SUCCESS) + { + return FAILED; + } + data = in->get_data(in); + response = chunk_skip(data, 6); + + if (response.len < expected.len || + !memeq(response.ptr, expected.ptr, expected.len)) + { + chunk_free(&expected); + DBG1(DBG_IKE, "EAP-MD5 verification failed"); + return FAILED; + } + chunk_free(&expected); + return SUCCESS; +} + +/** + * Implementation of eap_method_t.get_type. + */ +static eap_type_t get_type(private_eap_md5_t *this, u_int32_t *vendor) +{ + *vendor = 0; + return EAP_MD5; +} + +/** + * Implementation of eap_method_t.get_msk. + */ +static status_t get_msk(private_eap_md5_t *this, chunk_t *msk) +{ + return FAILED; +} + +/** + * Implementation of eap_method_t.is_mutual. + */ +static bool is_mutual(private_eap_md5_t *this) +{ + return FALSE; +} + +/** + * Implementation of eap_method_t.destroy. + */ +static void destroy(private_eap_md5_t *this) +{ + chunk_free(&this->challenge); + free(this); +} + +/** + * Generic constructor + */ +static private_eap_md5_t *eap_md5_create_generic(identification_t *server, + identification_t *peer) +{ + private_eap_md5_t *this = malloc_thing(private_eap_md5_t); + + this->public.eap_method_interface.initiate = NULL; + this->public.eap_method_interface.process = NULL; + this->public.eap_method_interface.get_type = (eap_type_t(*)(eap_method_t*,u_int32_t*))get_type; + this->public.eap_method_interface.is_mutual = (bool(*)(eap_method_t*))is_mutual; + this->public.eap_method_interface.get_msk = (status_t(*)(eap_method_t*,chunk_t*))get_msk; + this->public.eap_method_interface.destroy = (void(*)(eap_method_t*))destroy; + + /* private data */ + this->peer = peer; + this->server = server; + this->challenge = chunk_empty; + this->identifier = random(); + + return this; +} + +/* + * see header + */ +eap_md5_t *eap_md5_create_server(identification_t *server, identification_t *peer) +{ + private_eap_md5_t *this = eap_md5_create_generic(server, peer); + + this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))initiate_server; + this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))process_server; + + return &this->public; +} + +/* + * see header + */ +eap_md5_t *eap_md5_create_peer(identification_t *server, identification_t *peer) +{ + private_eap_md5_t *this = eap_md5_create_generic(server, peer); + + this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))initiate_peer; + this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))process_peer; + + return &this->public; +} + diff --git a/src/charon/plugins/eap_md5/eap_md5.h b/src/charon/plugins/eap_md5/eap_md5.h new file mode 100644 index 000000000..bcd505c59 --- /dev/null +++ b/src/charon/plugins/eap_md5/eap_md5.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +/** + * @defgroup eap_md5_i eap_md5 + * @{ @ingroup eap_md5 + */ + +#ifndef EAP_MD5_H_ +#define EAP_MD5_H_ + +typedef struct eap_md5_t eap_md5_t; + +#include + +/** + * Implementation of the eap_method_t interface using EAP-MD5 (CHAP). + */ +struct eap_md5_t { + + /** + * Implemented eap_method_t interface. + */ + eap_method_t eap_method_interface; +}; + +/** + * Creates the EAP method EAP-MD5 acting as server. + * + * @param server ID of the EAP server + * @param peer ID of the EAP client + * @return eap_md5_t object + */ +eap_md5_t *eap_md5_create_server(identification_t *server, identification_t *peer); + +/** + * Creates the EAP method EAP-MD5 acting as peer. + * + * @param server ID of the EAP server + * @param peer ID of the EAP client + * @return eap_md5_t object + */ +eap_md5_t *eap_md5_create_peer(identification_t *server, identification_t *peer); + +#endif /* EAP_MD5_H_ @}*/ diff --git a/src/charon/plugins/eap_md5/eap_md5_plugin.c b/src/charon/plugins/eap_md5/eap_md5_plugin.c new file mode 100644 index 000000000..d00bf7165 --- /dev/null +++ b/src/charon/plugins/eap_md5/eap_md5_plugin.c @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "eap_md5_plugin.h" + +#include "eap_md5.h" + +#include + +/** + * Implementation of plugin_t.destroy + */ +static void destroy(eap_md5_plugin_t *this) +{ + charon->eap->remove_method(charon->eap, + (eap_constructor_t)eap_md5_create_server); + charon->eap->remove_method(charon->eap, + (eap_constructor_t)eap_md5_create_peer); + free(this); +} + +/* + * see header file + */ +plugin_t *plugin_create() +{ + eap_md5_plugin_t *this = malloc_thing(eap_md5_plugin_t); + + this->plugin.destroy = (void(*)(plugin_t*))destroy; + + charon->eap->add_method(charon->eap, EAP_MD5, 0, EAP_SERVER, + (eap_constructor_t)eap_md5_create_server); + charon->eap->add_method(charon->eap, EAP_MD5, 0, EAP_PEER, + (eap_constructor_t)eap_md5_create_peer); + + return &this->plugin; +} + diff --git a/src/charon/plugins/eap_md5/eap_md5_plugin.h b/src/charon/plugins/eap_md5/eap_md5_plugin.h new file mode 100644 index 000000000..8387a209b --- /dev/null +++ b/src/charon/plugins/eap_md5/eap_md5_plugin.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +/** + * @defgroup eap_md5 eap_md5 + * @ingroup cplugins + * + * @defgroup eap_md5_plugin eap_md5_plugin + * @{ @ingroup eap_md5 + */ + +#ifndef EAP_MD5_PLUGIN_H_ +#define EAP_MD5_PLUGIN_H_ + +#include + +typedef struct eap_md5_plugin_t eap_md5_plugin_t; + +/** + * EAP-MD5 plugin + */ +struct eap_md5_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +/** + * Create a eap_md5_plugin instance. + */ +plugin_t *plugin_create(); + +#endif /* EAP_MD5_PLUGIN_H_ @}*/ diff --git a/src/charon/plugins/eap_sim/Makefile.am b/src/charon/plugins/eap_sim/Makefile.am new file mode 100644 index 000000000..549e92afa --- /dev/null +++ b/src/charon/plugins/eap_sim/Makefile.am @@ -0,0 +1,13 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon + +AM_CFLAGS = -rdynamic -DIPSEC_CONFDIR=\"${confdir}\" -DSIM_READER_LIB=\"${simreader}\" + +plugin_LTLIBRARIES = libcharon-eapsim.la libeapsim-file.la + +libcharon_eapsim_la_SOURCES = eap_sim_plugin.h eap_sim_plugin.c eap_sim.h eap_sim.c +libcharon_eapsim_la_LDFLAGS = -module + +libeapsim_file_la_SOURCES = eap_sim_file.c +libeapsim_file_la_LDFLAGS = -module + diff --git a/src/charon/plugins/eap_sim/eap_sim.c b/src/charon/plugins/eap_sim/eap_sim.c new file mode 100644 index 000000000..70651c91d --- /dev/null +++ b/src/charon/plugins/eap_sim/eap_sim.c @@ -0,0 +1,1150 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "eap_sim.h" + +#include + +#include +#include + +#define MAX_TRIES 3 + +/* number of triplets for one authentication */ +#define TRIPLET_COUNT 3 + +typedef enum sim_subtype_t sim_subtype_t; + +/** + * Subtypes of SIM messages + */ +enum sim_subtype_t { + SIM_START = 10, + SIM_CHALLENGE = 11, + SIM_NOTIFICATION = 12, + SIM_CLIENT_ERROR = 14, +}; + +ENUM(sim_subtype_names, SIM_START, SIM_CLIENT_ERROR, + "SIM_START", + "SIM_CHALLENGE", + "SIM_NOTIFICATION", + "SIM_13", + "SIM_CLIENT_ERROR", +); + +typedef enum sim_attribute_t sim_attribute_t; + +/** + * Attributes in SIM messages + */ +enum sim_attribute_t { + /** defines the end of attribute list */ + AT_END = -1, + AT_RAND = 1, + AT_AUTN = 2, + AT_RES = 3, + AT_AUTS = 4, + AT_PADDING = 6, + AT_NONCE_MT = 7, + AT_PERMANENT_ID_REQ = 10, + AT_MAC = 11, + AT_NOTIFICATION = 12, + AT_ANY_ID_REQ = 13, + AT_IDENTITY = 14, + AT_VERSION_LIST = 15, + AT_SELECTED_VERSION = 16, + AT_FULLAUTH_ID_REQ = 17, + AT_COUNTER = 19, + AT_COUNTER_TOO_SMALL = 20, + AT_NONCE_S = 21, + AT_CLIENT_ERROR_CODE = 22, + AT_IV = 129, + AT_ENCR_DATA = 130, + AT_NEXT_PSEUDONYM = 132, + AT_NEXT_REAUTH_ID = 133, + AT_CHECKCODE = 134, + AT_RESULT_IND = 135, +}; + +ENUM_BEGIN(sim_attribute_names, AT_END, AT_CLIENT_ERROR_CODE, + "AT_END", + "AT_0", + "AT_RAND", + "AT_AUTN", + "AT_RES", + "AT_AUTS", + "AT_5", + "AT_PADDING", + "AT_NONCE_MT", + "AT_8", + "AT_9", + "AT_PERMANENT_ID_REQ", + "AT_MAC", + "AT_NOTIFICATION", + "AT_ANY_ID_REQ", + "AT_IDENTITY", + "AT_VERSION_LIST", + "AT_SELECTED_VERSION", + "AT_FULLAUTH_ID_REQ", + "AT_18", + "AT_COUNTER", + "AT_COUNTER_TOO_SMALL", + "AT_NONCE_S", + "AT_CLIENT_ERROR_CODE"); +ENUM_NEXT(sim_attribute_names, AT_IV, AT_RESULT_IND, AT_CLIENT_ERROR_CODE, + "AT_IV", + "AT_ENCR_DATA", + "AT_131", + "AT_NEXT_PSEUDONYM", + "AT_NEXT_REAUTH_ID", + "AT_CHECKCODE", + "AT_RESULT_IND"); +ENUM_END(sim_attribute_names, AT_RESULT_IND); + + +typedef struct private_eap_sim_t private_eap_sim_t; + +/** + * Private data of an eap_sim_t object. + */ +struct private_eap_sim_t { + + /** + * Public authenticator_t interface. + */ + eap_sim_t public; + + /** + * ID of ourself + */ + identification_t *peer; + + /** + * hashing function + */ + hasher_t *hasher; + + /** + * prf + */ + prf_t *prf; + + /** + * MAC function + */ + signer_t *signer; + + /** + * SIM cardreader function loaded from library + */ + sim_algo_t alg; + + /** + * libraries get_triplet() function returning a triplet + */ + sim_get_triplet_t get_triplet; + + /** + * handle of the loaded library + */ + void *handle; + + /** + * how many times we try to authenticate + */ + int tries; + + /** + * unique EAP identifier + */ + u_int8_t identifier; + + /** + * EAP message type this role sends + */ + u_int8_t type; + + /** + * version this implementation uses + */ + chunk_t version; + + /** + * version list received from server + */ + chunk_t version_list; + + /** + * Nonce value used in AT_NONCE_MT + */ + chunk_t nonce; + + /** + * concatenated SRES values + */ + chunk_t sreses; + + /** + * k_encr key derived from MK + */ + chunk_t k_encr; + + /** + * k_auth key derived from MK, used for AT_MAC verification + */ + chunk_t k_auth; + + /** + * MSK, used for EAP-SIM based IKEv2 authentication + */ + chunk_t msk; + + /** + * EMSK, extendes MSK for further uses + */ + chunk_t emsk; +}; + +/** length of the AT_NONCE_MT nonce value */ +#define NONCE_LEN 16 +/** length of the AT_MAC value */ +#define MAC_LEN 16 +/** length of the AT_RAND value */ +#define RAND_LEN 16 +/** length of Kc */ +#define KC_LEN 8 +/** length of SRES */ +#define SRES_LEN 4 +/** length of the k_encr key */ +#define KENCR_LEN 16 +/** length of the k_auth key */ +#define KAUTH_LEN 16 +/** length of the MSK */ +#define MSK_LEN 64 +/** length of the EMSK */ +#define EMSK_LEN 64 + +static char version[] = {0x00,0x01}; +/* client error codes used in AT_CLIENT_ERROR_CODE */ +char client_error_general_buf[] = {0x00, 0x01}; +char client_error_unsupported_buf[] = {0x00, 0x02}; +char client_error_insufficient_buf[] = {0x00, 0x03}; +char client_error_notfresh_buf[] = {0x00, 0x04}; +chunk_t client_error_general = chunk_from_buf(client_error_general_buf); +chunk_t client_error_unsupported = chunk_from_buf(client_error_unsupported_buf); +chunk_t client_error_insufficient = chunk_from_buf(client_error_insufficient_buf); +chunk_t client_error_notfresh = chunk_from_buf(client_error_notfresh_buf); + +/** + * Read EAP and EAP-SIM header, return SIM type + */ +static sim_subtype_t read_header(chunk_t *message) +{ + sim_subtype_t type; + + if (message->len < 8) + { + *message = chunk_empty; + return 0; + } + type = *(message->ptr + 5); + *message = chunk_skip(*message, 8); + return type; +} + +/** + * read the next attribute from the chunk data + */ +static sim_attribute_t read_attribute(chunk_t *message, chunk_t *data) +{ + sim_attribute_t attribute; + size_t length; + + DBG3(DBG_IKE, "reading attribute from %B", message); + + if (message->len < 2) + { + return AT_END; + } + attribute = *message->ptr++; + length = *message->ptr++ * 4 - 2; + message->len -= 2; + DBG3(DBG_IKE, "found attribute %N with length %d", + sim_attribute_names, attribute, length); + + if (length > message->len) + { + return AT_END; + } + data->len = length; + data->ptr = message->ptr; + *message = chunk_skip(*message, length); + return attribute; +} + +/** + * Build an EAP-SIM payload using a variable length attribute list. + * The variable argument takes a sim_attribute_t followed by its data in a chunk. + */ +static eap_payload_t *build_payload(private_eap_sim_t *this, u_int8_t identifier, + sim_subtype_t type, ...) +{ + chunk_t message = chunk_alloca(512); + chunk_t pos = message; + eap_payload_t *payload; + va_list args; + sim_attribute_t attr; + u_int8_t *mac_pos = NULL; + chunk_t mac_data = chunk_empty; + + /* write EAP header, skip length bytes */ + *pos.ptr++ = this->type; + *pos.ptr++ = identifier; + pos.ptr += 2; + pos.len -= 4; + /* write SIM header with type and subtype, zero reserved bytes */ + *pos.ptr++ = EAP_SIM; + *pos.ptr++ = type; + *pos.ptr++ = 0; + *pos.ptr++ = 0; + pos.len -= 4; + + va_start(args, type); + while ((attr = va_arg(args, sim_attribute_t)) != AT_END) + { + chunk_t data = va_arg(args, chunk_t); + + DBG3(DBG_IKE, "building %N %B", sim_attribute_names, attr, &data); + + /* write attribute header */ + *pos.ptr++ = attr; + pos.len--; + + switch (attr) + { + case AT_CLIENT_ERROR_CODE: + case AT_SELECTED_VERSION: + { + *pos.ptr = data.len/4 + 1; + pos = chunk_skip(pos, 1); + memcpy(pos.ptr, data.ptr, data.len); + pos = chunk_skip(pos, data.len); + break; + } + case AT_IDENTITY: + case AT_VERSION_LIST: + { + u_int16_t act_len = data.len; + /* align up to four byte */ + if (data.len % 4) + { + chunk_t tmp = chunk_alloca((data.len/4)*4 + 4); + memset(tmp.ptr, 0, tmp.len); + memcpy(tmp.ptr, data.ptr, data.len); + data = tmp; + } + *pos.ptr = data.len/4 + 1; + pos = chunk_skip(pos, 1); + /* actual length in bytes */ + *(u_int16_t*)pos.ptr = htons(act_len); + pos = chunk_skip(pos, sizeof(u_int16_t)); + memcpy(pos.ptr, data.ptr, data.len); + pos = chunk_skip(pos, data.len); + break; + } + case AT_NONCE_MT: + { + *pos.ptr = data.len/4 + 1; + pos = chunk_skip(pos, 1); + memset(pos.ptr, 0, 2); + pos = chunk_skip(pos, 2); + memcpy(pos.ptr, data.ptr, data.len); + pos = chunk_skip(pos, data.len); + break; + } + case AT_MAC: + { + *pos.ptr++ = 5; pos.len--; + *pos.ptr++ = 0; pos.len--; + *pos.ptr++ = 0; pos.len--; + mac_pos = pos.ptr; + memset(mac_pos, 0, MAC_LEN); + pos = chunk_skip(pos, MAC_LEN); + mac_data = data; + break; + } + case AT_RAND: + { + *pos.ptr++ = data.len/4 + 1; pos.len--; + *pos.ptr++ = 0; pos.len--; + *pos.ptr++ = 0; pos.len--; + memcpy(pos.ptr, data.ptr, data.len); + pos = chunk_skip(pos, data.len); + break; + } + default: + DBG1(DBG_IKE, "no rule to build EAP_SIM attribute %N, skipped", + sim_attribute_names, attr); + break; + } + } + va_end(args); + + /* calculate message length, write into header */ + message.len = pos.ptr - message.ptr; + *(u_int16_t*)(message.ptr + 2) = htons(message.len); + + /* create MAC if AT_MAC attribte was included. Append supplied va_arg + * chunk mac_data to "to-sign" chunk */ + if (mac_pos) + { + this->signer->set_key(this->signer, this->k_auth); + mac_data = chunk_cata("cc", message, mac_data); + this->signer->get_signature(this->signer, mac_data, mac_pos); + DBG3(DBG_IKE, "AT_MAC signature of %B\n is %b", + &mac_data, mac_pos, MAC_LEN); + } + + payload = eap_payload_create_data(message); + + DBG3(DBG_IKE, "created EAP message %B", &message); + return payload; +} + +/** + * process an EAP-SIM/Request/Start message + */ +static status_t peer_process_start(private_eap_sim_t *this, eap_payload_t *in, + eap_payload_t **out) +{ + chunk_t message, data; + sim_attribute_t attribute, include_id = AT_END; + u_int8_t identifier; + + identifier = in->get_identifier(in); + message = in->get_data(in); + read_header(&message); + + while ((attribute = read_attribute(&message, &data)) != AT_END) + { + switch (attribute) + { + case AT_VERSION_LIST: + { + /* check if server supports our implementation */ + bool found = FALSE; + if (data.len > 2) + { + /* read actual length first */ + data.len = min(data.len, ntohs(*(u_int16_t*)data.ptr) + 2); + data = chunk_skip(data, 2); + chunk_free(&this->version_list); + this->version_list = chunk_clone(data); + while (data.len >= this->version.len) + { + if (memeq(data.ptr, this->version.ptr, this->version.len)) + { + found = TRUE; + break; + } + data = chunk_skip(data, this->version.len); + } + } + if (!found) + { + DBG1(DBG_IKE, "server does not support EAP_SIM " + "version number %#B", &this->version); + *out = build_payload(this, identifier, SIM_CLIENT_ERROR, + AT_CLIENT_ERROR_CODE, client_error_unsupported, + AT_END); + return NEED_MORE; + } + break; + } + case AT_PERMANENT_ID_REQ: + case AT_FULLAUTH_ID_REQ: + case AT_ANY_ID_REQ: + /* only include AT_IDENTITY if requested */ + include_id = AT_IDENTITY; + break; + case AT_NOTIFICATION: + { + u_int16_t code = 0; + if (data.len == 2) + { + code = ntohs(*(u_int16_t*)data.ptr); + } + if (code <= 32767) /* no success bit */ + { + DBG1(DBG_IKE, "received %N error %d", + sim_attribute_names, attribute, code); + *out = build_payload(this, + in->get_identifier(in), SIM_CLIENT_ERROR, + AT_CLIENT_ERROR_CODE, client_error_general, + AT_END); + return NEED_MORE; + } + else + { + DBG1(DBG_IKE, "received %N code %d", + sim_attribute_names, attribute, code); + } + break; + } + default: + DBG1(DBG_IKE, "ignoring EAP_SIM attribute %N", + sim_attribute_names, attribute); + break; + } + } + + /* build payload. If "include_id" is AT_END, AT_IDENTITY is ommited */ + *out = build_payload(this, identifier, SIM_START, + AT_SELECTED_VERSION, this->version, + AT_NONCE_MT, this->nonce, + include_id, this->peer->get_encoding(this->peer), + AT_END); + return NEED_MORE; +} + +/** + * derive EAP keys from kc + */ +static void derive_keys(private_eap_sim_t *this, chunk_t kcs) +{ + chunk_t tmp, mk; + int i; + + /* build MK = SHA1(Identity|n*Kc|NONCE_MT|Version List|Selected Version) */ + tmp = chunk_cata("ccccc", this->peer->get_encoding(this->peer), kcs, + this->nonce, this->version_list, this->version); + mk = chunk_alloca(this->hasher->get_hash_size(this->hasher)); + this->hasher->get_hash(this->hasher, tmp, mk.ptr); + DBG3(DBG_IKE, "MK = SHA1(%B\n) = %B", &tmp, &mk); + + /* K_encr | K_auth | MSK | EMSK = prf() | prf() | prf() | prf() + * FIPS PRF has 320 bit block size, we need 160 byte for keys + * => run prf four times */ + this->prf->set_key(this->prf, mk); + tmp = chunk_alloca(this->prf->get_block_size(this->prf) * 4); + for (i = 0; i < 4; i++) + { + this->prf->get_bytes(this->prf, chunk_empty, tmp.ptr + tmp.len / 4 * i); + } + chunk_free(&this->k_encr); + chunk_free(&this->k_auth); + chunk_free(&this->msk); + chunk_free(&this->emsk); + chunk_split(tmp, "aaaa", KENCR_LEN, &this->k_encr, KAUTH_LEN, &this->k_auth, + MSK_LEN, &this->msk, EMSK_LEN, &this->emsk); + DBG3(DBG_IKE, "K_encr %B\nK_auth %B\nMSK %B\nEMSK %B", + &this->k_encr, &this->k_auth, &this->msk, &this->emsk); +} + +/** + * process an EAP-SIM/Request/Challenge message + */ +static status_t peer_process_challenge(private_eap_sim_t *this, + eap_payload_t *in, eap_payload_t **out) +{ + chunk_t message, data, tmp, kcs, kc, sreses, sres; + sim_attribute_t attribute; + u_int8_t identifier; + chunk_t mac = chunk_empty, rands = chunk_empty; + + if (this->tries-- <= 0) + { + /* give up without notification. This hack is required as some buggy + * server implementations won't respect our client-error. */ + return FAILED; + } + + identifier = in->get_identifier(in); + message = in->get_data(in); + read_header(&message); + + while ((attribute = read_attribute(&message, &data)) != AT_END) + { + switch (attribute) + { + case AT_RAND: + { + rands = chunk_skip(data, 2); + break; + } + case AT_MAC: + { + /* backup MAC, zero it inline for later verification */ + data = chunk_skip(data, 2); + mac = chunk_clonea(data); + memset(data.ptr, 0, data.len); + break; + } + case AT_NOTIFICATION: + { + u_int16_t code = 0; + if (data.len == 2) + { + code = ntohs(*(u_int16_t*)data.ptr); + } + if (code <= 32767) /* no success bit */ + { + DBG1(DBG_IKE, "received %N error %d", + sim_attribute_names, attribute, code); + *out = build_payload(this, + in->get_identifier(in), SIM_CLIENT_ERROR, + AT_CLIENT_ERROR_CODE, client_error_general, + AT_END); + return NEED_MORE; + } + else + { + DBG1(DBG_IKE, "received %N code %d", + sim_attribute_names, attribute, code); + } + break; + } + default: + DBG1(DBG_IKE, "ignoring EAP_SIM attribute %N", + sim_attribute_names, attribute); + break; + } + } + + /* excepting two or three RAND, each 16 bytes. We require two valid + * and different RANDs */ + if ((rands.len != 2 * RAND_LEN && rands.len != 3 * RAND_LEN) || + memeq(rands.ptr, rands.ptr + RAND_LEN, RAND_LEN)) + { + DBG1(DBG_IKE, "no valid AT_RAND received"); + *out = build_payload(this, identifier, SIM_CLIENT_ERROR, + AT_CLIENT_ERROR_CODE, client_error_insufficient, + AT_END); + return NEED_MORE; + } + if (mac.len != MAC_LEN) + { + DBG1(DBG_IKE, "no valid AT_MAC received"); + *out = build_payload(this, identifier, SIM_CLIENT_ERROR, + AT_CLIENT_ERROR_CODE, client_error_general, + AT_END); + return NEED_MORE; + } + + /* get two or three KCs/SRESes from SIM using RANDs */ + kcs = kc = chunk_alloca(rands.len / 2); + sreses = sres = chunk_alloca(rands.len / 4); + while (rands.len > 0) + { + int kc_len = kc.len, sres_len = sres.len; + + if (this->alg(rands.ptr, RAND_LEN, sres.ptr, &sres_len, kc.ptr, &kc_len)) + { + DBG1(DBG_IKE, "unable to get EAP-SIM triplet"); + *out = build_payload(this, identifier, SIM_CLIENT_ERROR, + AT_CLIENT_ERROR_CODE, client_error_general, + AT_END); + return NEED_MORE; + } + DBG3(DBG_IKE, "got triplet for RAND %b\n Kc %b\n SRES %b", + rands.ptr, RAND_LEN, sres.ptr, sres_len, kc.ptr, kc_len); + kc = chunk_skip(kc, kc_len); + sres = chunk_skip(sres, sres_len); + rands = chunk_skip(rands, RAND_LEN); + } + + derive_keys(this, kcs); + + /* verify AT_MAC attribute, signature is over "EAP packet | NONCE_MT" */ + this->signer->set_key(this->signer, this->k_auth); + tmp = chunk_cata("cc", in->get_data(in), this->nonce); + if (!this->signer->verify_signature(this->signer, tmp, mac)) + { + DBG1(DBG_IKE, "AT_MAC verification failed"); + *out = build_payload(this, identifier, SIM_CLIENT_ERROR, + AT_CLIENT_ERROR_CODE, client_error_general, + AT_END); + return NEED_MORE; + } + + /* build response, AT_MAC is built over "EAP packet | n*SRES" */ + *out = build_payload(this, identifier, SIM_CHALLENGE, + AT_MAC, sreses, + AT_END); + return NEED_MORE; +} + +/** + * process an EAP-SIM/Response/Challenge message + */ +static status_t server_process_challenge(private_eap_sim_t *this, + eap_payload_t *in, eap_payload_t **out) +{ + chunk_t message, data; + sim_attribute_t attribute; + chunk_t mac = chunk_empty, tmp; + + message = in->get_data(in); + read_header(&message); + + while ((attribute = read_attribute(&message, &data)) != AT_END) + { + switch (attribute) + { + case AT_MAC: + /* MAC has two reserved bytes */ + if (data.len == MAC_LEN + 2) + { /* clone and zero MAC for verification */ + mac = chunk_clonea(chunk_skip(data, 2)); + memset(data.ptr, 0, data.len); + } + break; + default: + DBG1(DBG_IKE, "ignoring EAP_SIM attribute %N", + sim_attribute_names, attribute); + break; + } + } + if (!mac.ptr) + { + DBG1(DBG_IKE, "no valid AT_MAC attribute received"); + return FAILED; + } + /* verify AT_MAC attribute, signature is over "EAP packet | n*SRES" */ + this->signer->set_key(this->signer, this->k_auth); + tmp = chunk_cata("cc", in->get_data(in), this->sreses); + if (!this->signer->verify_signature(this->signer, tmp, mac)) + { + DBG1(DBG_IKE, "AT_MAC verification failed"); + return FAILED; + } + return SUCCESS; +} + +/** + * process an EAP-SIM/Response/Start message + */ +static status_t server_process_start(private_eap_sim_t *this, + eap_payload_t *in, eap_payload_t **out) +{ + chunk_t message, data; + sim_attribute_t attribute; + bool supported = FALSE; + chunk_t rands, rand, kcs, kc, sreses, sres; + char id[64]; + int len, i, rand_len, kc_len, sres_len; + + message = in->get_data(in); + read_header(&message); + + while ((attribute = read_attribute(&message, &data)) != AT_END) + { + switch (attribute) + { + case AT_NONCE_MT: + if (data.len == NONCE_LEN + 2) + { + this->nonce = chunk_clone(chunk_skip(data, 2)); + } + break; + case AT_SELECTED_VERSION: + if (chunk_equals(data, this->version)) + { + supported = TRUE; + } + break; + default: + DBG1(DBG_IKE, "ignoring EAP_SIM attribute %N", + sim_attribute_names, attribute); + break; + } + } + if (!supported || !this->nonce.ptr) + { + DBG1(DBG_IKE, "received incomplete EAP-SIM/Response/Start"); + return FAILED; + } + len = snprintf(id, sizeof(id), "%D", this->peer); + if (len > sizeof(id) || len < 0) + { + return FAILED; + } + + /* read triplets from provider */ + rand = rands = chunk_alloca(RAND_LEN * TRIPLET_COUNT); + kc = kcs = chunk_alloca(KC_LEN * TRIPLET_COUNT); + sres = sreses = chunk_alloca(SRES_LEN * TRIPLET_COUNT); + rands.len = 0; + kcs.len = 0; + sreses.len = 0; + for (i = 0; i < TRIPLET_COUNT; i++) + { + rand_len = RAND_LEN; + kc_len = KC_LEN; + sres_len = SRES_LEN; + if (this->get_triplet(id, rand.ptr, &rand_len, sres.ptr, &sres_len, + kc.ptr, &kc_len)) + { + DBG1(DBG_IKE, "getting EAP-SIM triplet %d failed", i); + return FAILED; + } + rands.len += rand_len; + kcs.len += kc_len; + sreses.len += sres_len; + rand = chunk_skip(rand, rand_len); + kc = chunk_skip(kc, kc_len); + sres = chunk_skip(sres, sres_len); + } + derive_keys(this, kcs); + + /* build MAC over "EAP packet | NONCE_MT" */ + *out = build_payload(this, this->identifier++, SIM_CHALLENGE, AT_RAND, + rands, AT_MAC, this->nonce, AT_END); + this->sreses = chunk_clone(sreses); + return NEED_MORE; +} + +/** + * process an EAP-SIM/Request/Notification message + */ +static status_t peer_process_notification(private_eap_sim_t *this, + eap_payload_t *in, eap_payload_t **out) +{ + chunk_t message, data; + sim_attribute_t attribute; + + message = in->get_data(in); + read_header(&message); + + while ((attribute = read_attribute(&message, &data)) != AT_END) + { + switch (attribute) + { + case AT_NOTIFICATION: + { + u_int16_t code = 0; + if (data.len == 2) + { + code = ntohs(*(u_int16_t*)data.ptr); + } + if (code <= 32767) /* no success bit */ + { + DBG1(DBG_IKE, "received %N error %d", + sim_attribute_names, attribute, code); + *out = build_payload(this, + in->get_identifier(in), SIM_CLIENT_ERROR, + AT_CLIENT_ERROR_CODE, client_error_general, + AT_END); + return NEED_MORE; + } + else + { + DBG1(DBG_IKE, "received %N code %d", + sim_attribute_names, attribute, code); + } + break; + } + default: + DBG1(DBG_IKE, "ignoring EAP_SIM attribute %N", + sim_attribute_names, attribute); + break; + } + } + /* reply with empty notification */ + *out = build_payload(this, in->get_identifier(in), SIM_NOTIFICATION, AT_END); + return NEED_MORE; +} + +/** + * Process a client error + */ +static status_t server_process_client_error(private_eap_sim_t *this, + eap_payload_t *in, eap_payload_t **out) +{ + chunk_t message, data; + sim_attribute_t attribute; + + message = in->get_data(in); + read_header(&message); + + while ((attribute = read_attribute(&message, &data)) != AT_END) + { + if (attribute == AT_CLIENT_ERROR_CODE) + { + u_int16_t code = 0; + if (data.len == 2) + { + code = ntohs(*(u_int16_t*)data.ptr); + } + DBG1(DBG_IKE, "received %N error %d", + sim_attribute_names, attribute, code); + } + else + { + DBG1(DBG_IKE, "ignoring EAP_SIM attribute %N", + sim_attribute_names, attribute); + } + } + return FAILED; +} + +/** + * Implementation of eap_method_t.process for the peer + */ +static status_t peer_process(private_eap_sim_t *this, + eap_payload_t *in, eap_payload_t **out) +{ + sim_subtype_t type; + chunk_t message; + + message = in->get_data(in); + type = read_header(&message); + + switch (type) + { + case SIM_START: + return peer_process_start(this, in, out); + case SIM_CHALLENGE: + return peer_process_challenge(this, in, out); + case SIM_NOTIFICATION: + return peer_process_notification(this, in, out); + default: + DBG1(DBG_IKE, "unable to process EAP_SIM subtype %N", + sim_subtype_names, type); + *out = build_payload(this, in->get_identifier(in), SIM_CLIENT_ERROR, + AT_CLIENT_ERROR_CODE, client_error_general, AT_END); + return NEED_MORE; + } +} + +/** + * Implementation of eap_method_t.process for the server + */ +static status_t server_process(private_eap_sim_t *this, + eap_payload_t *in, eap_payload_t **out) +{ + sim_subtype_t type; + chunk_t message; + + message = in->get_data(in); + type = read_header(&message); + + switch (type) + { + case SIM_START: + return server_process_start(this, in, out); + case SIM_CHALLENGE: + return server_process_challenge(this, in, out); + case SIM_CLIENT_ERROR: + return server_process_client_error(this, in, out); + default: + DBG1(DBG_IKE, "unable to process EAP_SIM subtype %N", + sim_subtype_names, type); + return FAILED; + } +} + +/** + * Implementation of eap_method_t.initiate for the peer + */ +static status_t peer_initiate(private_eap_sim_t *this, eap_payload_t **out) +{ + /* peer never initiates */ + return FAILED; +} + +/** + * Implementation of eap_method_t.initiate for the server + */ +static status_t server_initiate(private_eap_sim_t *this, eap_payload_t **out) +{ + /* version_list to derive MK, no padding */ + this->version_list = chunk_clone(this->version); + /* build_payloads adds padding itself */ + *out = build_payload(this, this->identifier++, SIM_START, + AT_VERSION_LIST, this->version, AT_END); + return NEED_MORE; +} + +/** + * Implementation of eap_method_t.get_type. + */ +static eap_type_t get_type(private_eap_sim_t *this, u_int32_t *vendor) +{ + *vendor = 0; + return EAP_SIM; +} + +/** + * Implementation of eap_method_t.get_msk. + */ +static status_t get_msk(private_eap_sim_t *this, chunk_t *msk) +{ + if (this->msk.ptr) + { + *msk = this->msk; + return SUCCESS; + } + return FAILED; +} + +/** + * Implementation of eap_method_t.is_mutual. + */ +static bool is_mutual(private_eap_sim_t *this) +{ + return TRUE; +} + +/** + * Implementation of eap_method_t.destroy. + */ +static void destroy(private_eap_sim_t *this) +{ + dlclose(this->handle); + DESTROY_IF(this->hasher); + DESTROY_IF(this->prf); + DESTROY_IF(this->signer); + chunk_free(&this->nonce); + chunk_free(&this->sreses); + chunk_free(&this->version_list); + chunk_free(&this->k_auth); + chunk_free(&this->k_encr); + chunk_free(&this->msk); + chunk_free(&this->emsk); + free(this); +} + +/** + * Generic constructor for both roles + */ +eap_sim_t *eap_sim_create_generic(eap_role_t role, identification_t *server, + identification_t *peer) +{ + private_eap_sim_t *this; + randomizer_t *randomizer; + void *symbol; + char *name; + + this = malloc_thing(private_eap_sim_t); + this->alg = NULL; + this->get_triplet = NULL; + this->nonce = chunk_empty; + this->sreses = chunk_empty; + this->peer = peer; + this->tries = MAX_TRIES; + this->version.ptr = version; + this->version.len = sizeof(version); + this->version_list = chunk_empty; + this->k_auth = chunk_empty; + this->k_encr = chunk_empty; + this->msk = chunk_empty; + this->emsk = chunk_empty; + this->identifier = random(); + + this->handle = dlopen(SIM_READER_LIB, RTLD_LAZY); + if (this->handle == NULL) + { + DBG1(DBG_IKE, "unable to open SIM reader '%s'", SIM_READER_LIB); + free(this); + return NULL; + } + switch (role) + { + case EAP_PEER: + name = SIM_READER_ALG; + break; + case EAP_SERVER: + name = SIM_READER_GET_TRIPLET; + break; + default: + free(this); + return NULL; + } + symbol = dlsym(this->handle, name); + if (symbol == NULL) + { + DBG1(DBG_IKE, "unable to open SIM function '%s' in '%s'", + name, SIM_READER_LIB); + dlclose(this->handle); + free(this); + return NULL; + } + switch (role) + { + case EAP_SERVER: + this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))server_initiate; + this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))server_process; + this->get_triplet = symbol; + this->type = EAP_REQUEST; + break; + case EAP_PEER: + this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))peer_initiate; + this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))peer_process; + this->alg = symbol; + this->type = EAP_RESPONSE; + randomizer = randomizer_create(); + if (randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_LEN, + &this->nonce)) + { + DBG1(DBG_IKE, "unable to generate NONCE for EAP_SIM"); + randomizer->destroy(randomizer); + free(this); + return NULL; + } + randomizer->destroy(randomizer); + break; + default: + free(this); + return NULL; + } + this->public.eap_method_interface.get_type = (eap_type_t(*)(eap_method_t*,u_int32_t*))get_type; + this->public.eap_method_interface.is_mutual = (bool(*)(eap_method_t*))is_mutual; + this->public.eap_method_interface.get_msk = (status_t(*)(eap_method_t*,chunk_t*))get_msk; + this->public.eap_method_interface.destroy = (void(*)(eap_method_t*))destroy; + + this->hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); + this->prf = lib->crypto->create_prf(lib->crypto, PRF_FIPS_SHA1_160); + this->signer = lib->crypto->create_signer(lib->crypto, AUTH_HMAC_SHA1_128); + if (!this->hasher || !this->prf || !this->signer) + { + DBG1(DBG_IKE, "initiating EAP-SIM failed, FIPS-PRF/SHA1 not supported"); + destroy(this); + return NULL; + } + return &this->public; +} + +/* + * Described in header. + */ +eap_sim_t *eap_sim_create_server(identification_t *server, + identification_t *peer) +{ + return eap_sim_create_generic(EAP_SERVER, server, peer); +} + +/* + * Described in header. + */ +eap_sim_t *eap_sim_create_peer(identification_t *server, + identification_t *peer) +{ + return eap_sim_create_generic(EAP_PEER, server, peer); +} + diff --git a/src/charon/plugins/eap_sim/eap_sim.h b/src/charon/plugins/eap_sim/eap_sim.h new file mode 100644 index 000000000..65020aa64 --- /dev/null +++ b/src/charon/plugins/eap_sim/eap_sim.h @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2007-2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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_sim_i eap_sim + * @{ @ingroup eap_sim + */ + +#ifndef EAP_SIM_H_ +#define EAP_SIM_H_ + +typedef struct eap_sim_t eap_sim_t; + +#include + +/** the library containing with the triplet functions */ +#ifndef SIM_READER_LIB +#error SIM_READER_LIB not specified, use --with-sim-reader option +#endif /* SIM_READER_LIB */ + +/** + * Cardreaders SIM function. + * + * @param rand RAND to run algo with + * @param rand_length length of value in rand + * @param sres buffer to get SRES + * @param sres_length size of buffer in sres, returns bytes written to SRES + * @param kc buffer to get Kc + * @param kc_length size of buffer in Kc, returns bytes written to Kc + * @return zero on success + */ +typedef int (*sim_algo_t)(const unsigned char *rand, int rand_length, + unsigned char *sres, int *sres_length, + unsigned char *kc, int *kc_length); + +#ifndef SIM_READER_ALG +/** the SIM_READER_LIB's algorithm, uses sim_algo_t signature */ +#define SIM_READER_ALG "sim_run_alg" +#endif /* SIM_READER_ALG */ + +/** + * Function to get a SIM triplet. + * + * @param identity identity (imsi) to get a triplet for + * @param rand buffer to get RAND + * @param rand_length size of buffer in rand, returns bytes written to RAND + * @param sres buffer to get SRES + * @param sres_length size of buffer in sres, returns bytes written to SRES + * @param kc buffer to get Kc + * @param kc_length size of buffer in Kc, returns bytes written to Kc + * @return zero on success + */ +typedef int (*sim_get_triplet_t)(char *identity, + unsigned char *rand, int *rand_length, + unsigned char *sres, int *sres_length, + unsigned char *kc, int *kc_length); + +#ifndef SIM_READER_GET_TRIPLET +/** the SIM_READER_LIB's get-triplet function, uses sim_get_triplet_t signature */ +#define SIM_READER_GET_TRIPLET "sim_get_triplet" +#endif /* SIM_READER_GET_TRIPLET */ + +/** + * Implementation of the eap_method_t interface using EAP-SIM. + * + * This EAP-SIM client implementation uses another pluggable library to + * access the SIM card/triplet provider. This module is specified using the + * SIM_READER_LIB definition. It has to privde a sim_run_alg() function to + * calculate a triplet (client), and/or a sim_get_triplet() function to get + * a triplet (server). These functions are named to the SIM_READER_ALG and + * the SIM_READER_GET_TRIPLET definitions. + */ +struct eap_sim_t { + + /** + * Implemented eap_method_t interface. + */ + eap_method_t eap_method_interface; +}; + +/** + * Creates the EAP method EAP-SIM acting as server. + * + * @param server ID of the EAP server + * @param peer ID of the EAP client + * @return eap_sim_t object + */ +eap_sim_t *eap_sim_create_server(identification_t *server, identification_t *peer); + +/** + * Creates the EAP method EAP-SIM acting as peer. + * + * @param server ID of the EAP server + * @param peer ID of the EAP client + * @return eap_sim_t object + */ +eap_sim_t *eap_sim_create_peer(identification_t *server, identification_t *peer); + +#endif /* EAP_SIM_H_ @}*/ diff --git a/src/charon/plugins/eap_sim/eap_sim_file.c b/src/charon/plugins/eap_sim/eap_sim_file.c new file mode 100644 index 000000000..7040a5ace --- /dev/null +++ b/src/charon/plugins/eap_sim/eap_sim_file.c @@ -0,0 +1,283 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include +#include +#include + +#include + +#define IMSI_LEN 64 +#define RAND_LEN 16 +#define SRES_LEN 4 +#define KC_LEN 8 + +typedef struct triplet_t triplet_t; + +struct triplet_t { + unsigned char imsi[IMSI_LEN]; + unsigned char rand[RAND_LEN]; + unsigned char sres[SRES_LEN]; + unsigned char kc[KC_LEN]; +}; + +static triplet_t *triplets = NULL; +static int triplet_count = 0; + +#define TRIPLET_FILE IPSEC_CONFDIR "/ipsec.d/triplets.dat" + +/** + * convert a single HEX char to its integer value + */ +static int hexchr(char chr) +{ + switch (chr) + { + case '0'...'9': + return chr - '0'; + case 'A'...'F': + return 10 + chr - 'A'; + case 'a'...'f': + return 10 + chr - 'a'; + } + return 0; +} + +/** + * convert a HEX string into a char array bin, limited by array length len + */ +static void hex2bin(char *hex, unsigned char *bin, size_t len) +{ + char *pos; + int i, even = 1; + + pos = hex - 1; + /* find the end, as we convert bottom up */ + while (TRUE) + { + switch (*(pos+1)) + { + case '0'...'9': + case 'A'...'F': + case 'a'...'f': + pos++; + continue; + } + break; + } + /* convert two hex chars into a single bin byte */ + for (i = 0; pos >= hex && i < len; pos--) + { + if (even) + { + bin[len - 1 - i] = hexchr(*pos); + } + else + { + bin[len - 1 - i] |= 16 * hexchr(*pos); + i++; + } + even = !even; + } +} + +/** + * free up allocated triplets + */ +static void __attribute__ ((destructor)) free_triplets() +{ + free(triplets); +} + +/** + * read the triplets from the file, using freeradius triplet file syntax: + * http://www.freeradius.org/radiusd/doc/rlm_sim_triplets + */ +static void __attribute__ ((constructor)) read_triplets() +{ + char line[512], *data[4], *pos; + FILE *file; + int i, nr = 0; + triplet_t *triplet; + + file = fopen(TRIPLET_FILE, "r"); + if (file == NULL) + { + DBG1(DBG_CFG, "opening triplet file %s failed: %s", + TRIPLET_FILE, strerror(errno)); + return; + } + + if (triplets) + { + free(triplets); + triplets = NULL; + triplet_count = 0; + } + + /* read line by line */ + while (fgets(line, sizeof(line), file)) + { + nr++; + /* skip comments, empty lines */ + switch (line[0]) + { + case '\n': + case '\r': + case '#': + case '\0': + continue; + default: + break; + } + /* read comma separated values */ + pos = line; + for (i = 0; i < 4; i++) + { + data[i] = pos; + pos = strchr(pos, ','); + if (pos) + { + *pos = '\0'; + pos++; + } + else if (i != 3) + { + DBG1(DBG_CFG, "error in triplet file, line %d", nr); + fclose(file); + return; + } + } + /* allocate new triplet */ + triplet_count++; + triplets = realloc(triplets, triplet_count * sizeof(triplet_t)); + triplet = &triplets[triplet_count - 1]; + memset(triplet, 0, sizeof(triplet_t)); + + /* convert/copy triplet data */ + for (i = 0; i < IMSI_LEN - 1; i++) + { + switch (data[0][i]) + { + case '\n': + case '\r': + case '\0': + break; + default: + triplet->imsi[i] = data[0][i]; + continue; + } + break; + } + hex2bin(data[1], triplet->rand, RAND_LEN); + hex2bin(data[2], triplet->sres, SRES_LEN); + hex2bin(data[3], triplet->kc, KC_LEN); + + DBG4(DBG_CFG, "triplet: imsi %b\nrand %b\nsres %b\nkc %b", + triplet->imsi, IMSI_LEN, triplet->rand, RAND_LEN, + triplet->sres, SRES_LEN, triplet->kc, KC_LEN); + } + fclose(file); + DBG2(DBG_CFG, "read %d triplets from %s", triplet_count, TRIPLET_FILE); +} + +/** + * Run the sim algorithm, see eap_sim.h + */ +int sim_run_alg(const unsigned char *rand, int rand_length, + unsigned char *sres, int *sres_length, + unsigned char *kc, int *kc_length) +{ + int current; + + if (rand_length != RAND_LEN || + *sres_length < SRES_LEN || + *kc_length < KC_LEN) + { + return 1; + } + + for (current = 0; current < triplet_count; current++) + { + if (memcmp(triplets[current].rand, rand, RAND_LEN) == 0) + { + memcpy(sres, triplets[current].sres, SRES_LEN); + memcpy(kc, triplets[current].kc, KC_LEN); + *sres_length = SRES_LEN; + *kc_length = KC_LEN; + return 0; + } + } + return 2; +} + +/** + * Get a single triplet, see_eap_sim.h + */ +int sim_get_triplet(char *imsi, + unsigned char *rand, int *rand_length, + unsigned char *sres, int *sres_length, + unsigned char *kc, int *kc_length) +{ + int current; + triplet_t *triplet; + static int skip = -1; + + DBG2(DBG_CFG, "getting triplet for %s", imsi); + + if (*rand_length < RAND_LEN || + *sres_length < SRES_LEN || + *kc_length < KC_LEN) + { + return 1; + } + if (triplet_count == 0) + { + return 2; + } + for (current = 0; current < triplet_count; current++) + { + triplet = &triplets[current]; + + if (streq(imsi, triplet->imsi)) + { + /* skip triplet if already used */ + if (skip >= current) + { + continue; + } + *rand_length = RAND_LEN; + *sres_length = SRES_LEN; + *kc_length = KC_LEN; + memcpy(rand, triplet->rand, RAND_LEN); + memcpy(sres, triplet->sres, SRES_LEN); + memcpy(kc, triplet->kc, KC_LEN); + /* remember used triplet */ + skip = current; + return 0; + } + } + if (skip > -1) + { + /* no triplet left, reuse triplets */ + skip = -1; + return sim_get_triplet(imsi, rand, rand_length, + sres, sres_length, kc, kc_length); + } + return 2; +} + diff --git a/src/charon/plugins/eap_sim/eap_sim_plugin.c b/src/charon/plugins/eap_sim/eap_sim_plugin.c new file mode 100644 index 000000000..8fbad4211 --- /dev/null +++ b/src/charon/plugins/eap_sim/eap_sim_plugin.c @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "eap_sim_plugin.h" + +#include "eap_sim.h" + +#include + +/** + * Implementation of plugin_t.destroy + */ +static void destroy(eap_sim_plugin_t *this) +{ + charon->eap->remove_method(charon->eap, + (eap_constructor_t)eap_sim_create_server); + charon->eap->remove_method(charon->eap, + (eap_constructor_t)eap_sim_create_peer); + free(this); +} + +/* + * see header file + */ +plugin_t *plugin_create() +{ + eap_sim_plugin_t *this = malloc_thing(eap_sim_plugin_t); + + this->plugin.destroy = (void(*)(plugin_t*))destroy; + + charon->eap->add_method(charon->eap, EAP_SIM, 0, EAP_SERVER, + (eap_constructor_t)eap_sim_create_server); + charon->eap->add_method(charon->eap, EAP_SIM, 0, EAP_PEER, + (eap_constructor_t)eap_sim_create_peer); + + return &this->plugin; +} + diff --git a/src/charon/plugins/eap_sim/eap_sim_plugin.h b/src/charon/plugins/eap_sim/eap_sim_plugin.h new file mode 100644 index 000000000..e142b8991 --- /dev/null +++ b/src/charon/plugins/eap_sim/eap_sim_plugin.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +/** + * @defgroup eap_sim eap_sim + * @ingroup cplugins + * + * @defgroup eap_sim_plugin eap_sim_plugin + * @{ @ingroup eap_sim + */ + +#ifndef EAP_SIM_PLUGIN_H_ +#define EAP_SIM_PLUGIN_H_ + +#include + +typedef struct eap_sim_plugin_t eap_sim_plugin_t; + +/** + * EAP-sim plugin + */ +struct eap_sim_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +/** + * Create a eap_sim_plugin instance. + */ +plugin_t *plugin_create(); + +#endif /* EAP_SIM_PLUGIN_H_ @}*/ diff --git a/src/charon/plugins/med_db/Makefile.am b/src/charon/plugins/med_db/Makefile.am new file mode 100644 index 000000000..f7608da05 --- /dev/null +++ b/src/charon/plugins/med_db/Makefile.am @@ -0,0 +1,10 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon + +AM_CFLAGS = -rdynamic + +plugin_LTLIBRARIES = libcharon-med-db.la +libcharon_med_db_la_SOURCES = med_db_plugin.h med_db_plugin.c \ + med_db_creds.h med_db_creds.c +libcharon_med_db_la_LDFLAGS = -module + diff --git a/src/charon/plugins/med_db/med_db_creds.c b/src/charon/plugins/med_db/med_db_creds.c new file mode 100644 index 000000000..f8aed2597 --- /dev/null +++ b/src/charon/plugins/med_db/med_db_creds.c @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "med_db_creds.h" + +#include +#include +#include + +typedef struct private_med_db_creds_t private_med_db_creds_t; + +/** + * Private data of an med_db_creds_t object + */ +struct private_med_db_creds_t { + + /** + * Public part + */ + med_db_creds_t public; + + /** + * underlying database handle + */ + database_t *db; +}; + +/** + * data passed between enumerate calls + */ +typedef struct { + /** current shared key */ + shared_key_t *current; +} data_t; + +typedef struct private_shared_key_t private_shared_key_t; +/** + * shared key implementation + */ +struct private_shared_key_t { + /** implements shared_key_t*/ + shared_key_t public; + /** data of the key */ + chunk_t key; + /** reference counter */ + refcount_t ref; +}; + +/** + * Destroy allocated data_t struct + */ +static void data_destroy(data_t *this) +{ + DESTROY_IF(this->current); + free(this); +} + +/** + * Implementation of shared_key_t.get_type. + */ +static shared_key_type_t get_type(private_shared_key_t *this) +{ + return SHARED_IKE; +} + +/** + * Implementation of shared_key_t.get_ref. + */ +static private_shared_key_t* get_ref(private_shared_key_t *this) +{ + ref_get(&this->ref); + return this; +} + +/** + * Implementation of shared_key_t.destroy + */ +static void shared_key_destroy(private_shared_key_t *this) +{ + if (ref_put(&this->ref)) + { + chunk_free(&this->key); + free(this); + } +} + +/** + * Implementation of shared_key_t.get_key. + */ +static chunk_t get_key(private_shared_key_t *this) +{ + return this->key; +} + +/** + * create a shared key + */ +static shared_key_t *shared_key_create(chunk_t key) +{ + private_shared_key_t *this = malloc_thing(private_shared_key_t); + + this->public.get_type = (shared_key_type_t(*)(shared_key_t*))get_type; + this->public.get_key = (chunk_t(*)(shared_key_t*))get_key; + this->public.get_ref = (shared_key_t*(*)(shared_key_t*))get_ref; + this->public.destroy = (void(*)(shared_key_t*))shared_key_destroy; + + this->key = chunk_clone(key); + this->ref = 1; + return &this->public; +} + +/** + * filter for enumerator, returns for each SQL result a shared key and match + */ +static bool filter(data_t *this, chunk_t *chunk, shared_key_t **out, + void **unused1, id_match_t *match_me, + void **unused2, id_match_t *match_other) +{ + DESTROY_IF(this->current); + this->current = shared_key_create(*chunk); + *out = this->current; + /* we have unique matches only, but do not compare own ID */ + if (match_me) + { + *match_me = ID_MATCH_ANY; + } + if (match_other) + { + *match_other = ID_MATCH_PERFECT; + } + return TRUE; +} + + +/** + * Implements credential_set_t.create_shared_enumerator + */ +static enumerator_t* create_shared_enumerator(private_med_db_creds_t *this, + shared_key_type_t type, identification_t *me, + identification_t *other) +{ + enumerator_t *enumerator; + data_t *data; + + if (type != SHARED_IKE) + { + return NULL; + } + enumerator = this->db->query(this->db, + "SELECT Psk FROM Peer WHERE PeerId = ?", + DB_BLOB, other->get_encoding(other), + DB_BLOB); + if (enumerator) + { + data = malloc_thing(data_t); + data->current = NULL; + return enumerator_create_filter(enumerator, (void*)filter, + data, (void*)data_destroy); + } + return NULL; +} + +/** + * returns null + */ +static void *return_null() +{ + return NULL; +} + +/** + * Implementation of backend_t.destroy. + */ +static void destroy(private_med_db_creds_t *this) +{ + free(this); +} + +/** + * Described in header. + */ +med_db_creds_t *med_db_creds_create(database_t *db) +{ + private_med_db_creds_t *this = malloc_thing(private_med_db_creds_t); + + this->public.set.create_private_enumerator = (void*)return_null; + this->public.set.create_cert_enumerator = (void*)return_null; + this->public.set.create_shared_enumerator = (void*)create_shared_enumerator; + this->public.set.create_cdp_enumerator = (void*)return_null; + + this->public.destroy = (void (*)(med_db_creds_t*))destroy; + + this->db = db; + + return &this->public; +} + diff --git a/src/charon/plugins/med_db/med_db_creds.h b/src/charon/plugins/med_db/med_db_creds.h new file mode 100644 index 000000000..1665b8718 --- /dev/null +++ b/src/charon/plugins/med_db/med_db_creds.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2007-2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +/** + * @defgroup med_db_creds_i med_db_creds + * @{ @ingroup med_db_creds + */ + +#ifndef MED_DB_CREDS_H_ +#define MED_DB_CREDS_H_ + +#include +#include + +typedef struct med_db_creds_t med_db_creds_t; + +/** + * Mediation credentials database. + */ +struct med_db_creds_t { + + /** + * Implements credential_set_t interface + */ + credential_set_t set; + + /** + * Destroy the credentials databse. + */ + void (*destroy)(med_db_creds_t *this); +}; + +/** + * Create the med_db credentials db. + * + * @param database underlying database + * @return credential set implementation on that database + */ +med_db_creds_t *med_db_creds_create(database_t *database); + +#endif /* MED_DB_CREDS_H_ @}*/ diff --git a/src/charon/plugins/med_db/med_db_plugin.c b/src/charon/plugins/med_db/med_db_plugin.c new file mode 100644 index 000000000..033ec91c7 --- /dev/null +++ b/src/charon/plugins/med_db/med_db_plugin.c @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "med_db_plugin.h" + +#include "med_db_creds.h" + +#include + +typedef struct private_med_db_plugin_t private_med_db_plugin_t; + +/** + * private data of med_db plugin + */ +struct private_med_db_plugin_t { + + /** + * implements plugin interface + */ + med_db_plugin_t public; + + /** + * database connection instance + */ + database_t *db; + + /** + * med_db credential set instance + */ + med_db_creds_t *creds; +}; + +/** + * Implementation of plugin_t.destroy + */ +static void destroy(private_med_db_plugin_t *this) +{ + charon->credentials->remove_set(charon->credentials, &this->creds->set); + this->creds->destroy(this->creds); + free(this); +} + +/* + * see header file + */ +plugin_t *plugin_create() +{ + char *uri; + private_med_db_plugin_t *this = malloc_thing(private_med_db_plugin_t); + + this->public.plugin.destroy = (void(*)(plugin_t*))destroy; + + uri = lib->settings->get_str(lib->settings, "plugins.med_db.database", NULL); + if (!uri) + { + DBG1(DBG_CFG, "mediation database URI not defined, skipped"); + free(this); + return NULL; + } + + if (this->db == NULL) + { + DBG1(DBG_CFG, "opening mediation server database failed"); + free(this); + return NULL; + } + + this->creds = med_db_creds_create(this->db); + + charon->credentials->add_set(charon->credentials, &this->creds->set); + + return &this->public.plugin; +} + diff --git a/src/charon/plugins/med_db/med_db_plugin.h b/src/charon/plugins/med_db/med_db_plugin.h new file mode 100644 index 000000000..42d55adda --- /dev/null +++ b/src/charon/plugins/med_db/med_db_plugin.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +/** + * @defgroup med_db med_db + * @ingroup cplugins + * + * @defgroup med_db_plugin med_db_plugin + * @{ @ingroup med_db + */ + +#ifndef MED_DB_PLUGIN_H_ +#define MED_DB_PLUGIN_H_ + +#include + +typedef struct med_db_plugin_t med_db_plugin_t; + +/** + * Mediation server database plugin. + */ +struct med_db_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +/** + * Create a med_db_plugin instance. + */ +plugin_t *plugin_create(); + +#endif /* MED_DB_PLUGIN_H_ @}*/ diff --git a/src/charon/plugins/sql/Makefile.am b/src/charon/plugins/sql/Makefile.am new file mode 100644 index 000000000..813c601eb --- /dev/null +++ b/src/charon/plugins/sql/Makefile.am @@ -0,0 +1,10 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon + +AM_CFLAGS = -rdynamic + +plugin_LTLIBRARIES = libcharon-sql.la +libcharon_sql_la_SOURCES = sql_plugin.h sql_plugin.c \ + sql_config.h sql_config.c +libcharon_sql_la_LDFLAGS = -module + diff --git a/src/charon/plugins/sql/config.sql b/src/charon/plugins/sql/config.sql new file mode 100644 index 000000000..64aaea7d7 --- /dev/null +++ b/src/charon/plugins/sql/config.sql @@ -0,0 +1,73 @@ + +DROP TABLE IF EXISTS ike_configs; +CREATE TABLE ike_configs ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + certreq INTEGER, + force_encap INTEGER, + local TEXT, + remote TEXT +); + +DROP TABLE IF EXISTS child_configs; +CREATE TABLE child_configs ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT, + lifetime INTEGER, + rekeytime INTEGER, + jitter INTEGER, + updown TEXT, + hostaccess INTEGER, + mode INTEGER +); + +DROP TABLE IF EXISTS peer_config_child_config; +CREATE TABLE peer_config_child_config ( + peer_cfg INTEGER, + child_cfg INTEGER +); + +DROP TABLE IF EXISTS traffic_selectors; +CREATE TABLE traffic_selectors ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + type INTEGER, + protocol INTEGER, + start_addr TEXT, + end_addr TEXT, + start_port INTEGER, + end_port INTEGER +); + +DROP TABLE IF EXISTS child_config_traffic_selector; +CREATE TABLE child_config_traffic_selector ( + child_cfg INTEGER, + traffic_selector INTEGER, + kind INTEGER +); + +DROP TABLE IF EXISTS peer_configs; +CREATE TABLE peer_configs ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT, + ike_version INTEGER, + ike_cfg INTEGER, + local_id TEXT, + remote_id TEXT, + cert_policy INTEGER, + auth_method INTEGER, + eap_type INTEGER, + eap_vendor INTEGER, + keyingtries INTEGER, + rekeytime INTEGER, + reauthtime INTEGER, + jitter INTEGER, + overtime INTEGER, + mobike INTEGER, + dpd_delay INTEGER, + dpd_action INTEGER, + local_vip TEXT, + remote_vip TEXT, + mediation INTEGER, + mediated_by INTEGER, + peer_id TEXT +); + diff --git a/src/charon/plugins/sql/cred.sql b/src/charon/plugins/sql/cred.sql new file mode 100644 index 000000000..4b53e4e4b --- /dev/null +++ b/src/charon/plugins/sql/cred.sql @@ -0,0 +1,24 @@ + +DROP TABLE IF EXISTS shared_secrets; +CREATE TABLE shared_secrets ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + type INTEGER, + local TEXT, + remote TEXT +); + +DROP TABLE IF EXISTS certificates; +CREATE TABLE certificates ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + type INTEGER, + subject TEXT, + data BLOB, +); + +DROP TABLE IF EXISTS private_keys; +CREATE TABLE private_keys ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + type INTEGER, + keyid BLOB, + data BLOB, +); diff --git a/src/charon/plugins/sql/sql_config.c b/src/charon/plugins/sql/sql_config.c new file mode 100644 index 000000000..eaa9da5ef --- /dev/null +++ b/src/charon/plugins/sql/sql_config.c @@ -0,0 +1,538 @@ +/* + * Copyright (C) 2006-2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include + +#include "sql_config.h" + +#include + +typedef struct private_sql_config_t private_sql_config_t; + +/** + * Private data of an sql_config_t object + */ +struct private_sql_config_t { + + /** + * Public part + */ + sql_config_t public; + + /** + * database connection + */ + database_t *db; +}; + +/** + * forward declaration + */ +static peer_cfg_t *build_peer_cfg(private_sql_config_t *this, enumerator_t *e, + identification_t *me, identification_t *other); + +/** + * build a traffic selector from a SQL query + */ +static traffic_selector_t *build_traffic_selector(private_sql_config_t *this, + enumerator_t *e, bool *local) +{ + int type, protocol, start_port, end_port; + char *start_addr, *end_addr; + traffic_selector_t *ts; + enum { + TS_LOCAL = 0, + TS_REMOTE = 1, + TS_LOCAL_DYNAMIC = 2, + TS_REMOTE_DYNAMIC = 3, + } kind; + + while (e->enumerate(e, &kind, &type, &protocol, + &start_addr, &end_addr, &start_port, &end_port)) + { + *local = FALSE; + switch (kind) + { + case TS_LOCAL: + *local = TRUE; + /* FALL */ + case TS_REMOTE: + ts = traffic_selector_create_from_string(protocol, type, + start_addr, start_port, end_addr, end_port); + break; + case TS_LOCAL_DYNAMIC: + *local = TRUE; + /* FALL */ + case TS_REMOTE_DYNAMIC: + ts = traffic_selector_create_dynamic(protocol, type, + start_port, end_port); + break; + default: + continue; + } + if (ts) + { + return ts; + } + } + return NULL; +} + +/** + * Add traffic selectors to a child config + */ +static void add_traffic_selectors(private_sql_config_t *this, + child_cfg_t *child, int id) +{ + enumerator_t *e; + traffic_selector_t *ts; + bool local; + + e = this->db->query(this->db, + "SELECT kind, type, protocol, " + "start_addr, end_addr, start_port, end_port " + "FROM traffic_selectors JOIN child_config_traffic_selector " + "ON id = traffic_selector WHERE child_cfg = ?", + DB_INT, id, + DB_INT, DB_INT, DB_INT, + DB_TEXT, DB_TEXT, DB_INT, DB_INT); + if (e) + { + while ((ts = build_traffic_selector(this, e, &local))) + { + child->add_traffic_selector(child, local, ts); + } + e->destroy(e); + } +} + +/** + * build a Child configuration from a SQL query + */ +static child_cfg_t *build_child_cfg(private_sql_config_t *this, enumerator_t *e) +{ + int id, lifetime, rekeytime, jitter, hostaccess, mode; + char *name, *updown; + child_cfg_t *child_cfg; + + if (e->enumerate(e, &id, &name, &lifetime, &rekeytime, &jitter, + &updown, &hostaccess, &mode)) + { + child_cfg = child_cfg_create(name, lifetime, rekeytime, jitter, + updown, hostaccess, mode); + /* TODO: read proposal from db */ + child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP)); + add_traffic_selectors(this, child_cfg, id); + return child_cfg; + } + return NULL; +} + +/** + * Add child configs to peer config + */ +static void add_child_cfgs(private_sql_config_t *this, peer_cfg_t *peer, int id) +{ + enumerator_t *e; + child_cfg_t *child_cfg; + + e = this->db->query(this->db, + "SELECT id, name, lifetime, rekeytime, jitter, " + "updown, hostaccess, mode " + "FROM child_configs JOIN peer_config_child_config ON id = child_cfg " + "WHERE peer_cfg = ?", + DB_INT, id, + DB_INT, DB_TEXT, DB_INT, DB_INT, DB_INT, + DB_TEXT, DB_INT, DB_INT); + if (e) + { + while ((child_cfg = build_child_cfg(this, e))) + { + peer->add_child_cfg(peer, child_cfg); + } + e->destroy(e); + } +} + +/** + * build a ike configuration from a SQL query + */ +static ike_cfg_t *build_ike_cfg(private_sql_config_t *this, enumerator_t *e, + host_t *my_host, host_t *other_host) +{ + int certreq, force_encap; + char *local, *remote; + + while (e->enumerate(e, &certreq, &force_encap, &local, &remote)) + { + host_t *me, *other; + ike_cfg_t *ike_cfg; + + me = host_create_from_string(local, 500); + if (!me) + { + continue; + } + if (my_host && !me->is_anyaddr(me) && + !me->ip_equals(me, my_host)) + { + me->destroy(me); + continue; + } + other = host_create_from_string(remote, 500); + if (!other) + { + me->destroy(me); + continue; + } + if (other_host && !other->is_anyaddr(other) && + !other->ip_equals(other, other_host)) + { + me->destroy(me); + other->destroy(other); + continue; + } + ike_cfg = ike_cfg_create(certreq, force_encap, me, other); + /* TODO: read proposal from db */ + ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE)); + return ike_cfg; + } + return NULL; +} + +/** + * Query a IKE config by its id + */ +static ike_cfg_t* get_ike_cfg_by_id(private_sql_config_t *this, int id) +{ + enumerator_t *e; + ike_cfg_t *ike_cfg = NULL; + + e = this->db->query(this->db, + "SELECT certreq, force_encap, local, remote " + "FROM ike_configs WHERE id = ?", + DB_INT, id, + DB_INT, DB_INT, DB_TEXT, DB_TEXT); + if (e) + { + ike_cfg = build_ike_cfg(this, e, NULL, NULL); + e->destroy(e); + } + return ike_cfg; +} + +/** + * Query a peer config by its id + */ +static peer_cfg_t *get_peer_cfg_by_id(private_sql_config_t *this, int id) +{ + enumerator_t *e; + peer_cfg_t *peer_cfg = NULL; + + e = this->db->query(this->db, + "SELECT id, name, ike_cfg, local_id, remote_id, cert_policy, " + "auth_method, eap_type, eap_vendor, keyingtries, " + "rekeytime, reauthtime, jitter, overtime, mobike, " + "dpd_delay, dpd_action, local_vip, remote_vip, " + "mediation, mediated_by, peer_id " + "FROM peer_configs WHERE id = ?", + DB_INT, id, + DB_INT, DB_INT, DB_TEXT, DB_TEXT, DB_INT, + DB_INT, DB_INT, DB_INT, DB_INT, + DB_INT, DB_INT, DB_INT, DB_INT, DB_INT, + DB_INT, DB_INT, DB_TEXT, DB_TEXT, + DB_INT, DB_INT, DB_TEXT); + if (e) + { + peer_cfg = build_peer_cfg(this, e, NULL, NULL); + e->destroy(e); + } + return peer_cfg; +} + +/** + * build a peer configuration from a SQL query + */ +static peer_cfg_t *build_peer_cfg(private_sql_config_t *this, enumerator_t *e, + identification_t *me, identification_t *other) +{ + int id, ike_cfg, cert_policy, auth_method, eap_type, eap_vendor, + keyingtries, rekeytime, reauthtime, jitter, overtime, mobike, + dpd_delay, dpd_action, mediation, mediated_by; + char *local_id, *remote_id, *local_vip, *remote_vip, *peer_id, *name; + + while (e->enumerate(e, &id, &name, &ike_cfg, &local_id, &remote_id, &cert_policy, + &auth_method, &eap_type, &eap_vendor, &keyingtries, + &rekeytime, &reauthtime, &jitter, &overtime, &mobike, + &dpd_delay, &dpd_action, &local_vip, &remote_vip, + &mediation, &mediated_by, &peer_id)) + { + ike_cfg_t *ike; + peer_cfg_t *peer_cfg, *mediated_cfg; + identification_t *my_id, *other_id, *peer; + host_t *my_vip, *other_vip; + + my_id = identification_create_from_string(local_id); + if (!my_id) + { + continue; + } + if (me && !me->matches(me, my_id)) + { + my_id->destroy(my_id); + continue; + } + other_id = identification_create_from_string(remote_id); + if (!other_id) + { + my_id->destroy(my_id); + continue; + } + if (other && !other->matches(other, other_id)) + { + other_id->destroy(other_id); + my_id->destroy(my_id); + continue; + } + ike = get_ike_cfg_by_id(this, ike_cfg); + mediated_cfg = mediated_by ? get_peer_cfg_by_id(this, mediated_by) : NULL; + peer = peer_id ? identification_create_from_string(peer_id) : NULL; + my_vip = local_vip ? host_create_from_string(local_vip, 0) : NULL; + other_vip = remote_vip ? host_create_from_string(remote_vip, 0) : NULL; + + if (ike) + { + peer_cfg = peer_cfg_create( + name, 2, ike, my_id, other_id, cert_policy, + auth_method, eap_type, eap_vendor, keyingtries, + rekeytime, reauthtime, jitter, overtime, mobike, + dpd_delay, dpd_action, my_vip, other_vip, + mediation, mediated_cfg, peer); + add_child_cfgs(this, peer_cfg, id); + return peer_cfg; + } + DESTROY_IF(ike); + DESTROY_IF(mediated_cfg); + DESTROY_IF(peer); + DESTROY_IF(my_vip); + DESTROY_IF(other_vip); + DESTROY_IF(my_id); + DESTROY_IF(other_id); + } + return NULL; +} + +/** + * implements backend_t.get_peer_cfg_by_name. + */ +static peer_cfg_t *get_peer_cfg_by_name(private_sql_config_t *this, char *name) +{ + enumerator_t *e; + peer_cfg_t *peer_cfg = NULL; + + e = this->db->query(this->db, + "SELECT id, name, ike_cfg, local_id, remote_id, cert_policy, " + "auth_method, eap_type, eap_vendor, keyingtries, " + "rekeytime, reauthtime, jitter, overtime, mobike, " + "dpd_delay, dpd_action, local_vip, remote_vip, " + "mediation, mediated_by, peer_id " + "FROM peer_configs WHERE ike_version = ? AND name = ?", + DB_INT, 2, DB_TEXT, name, + DB_INT, DB_TEXT, DB_INT, DB_TEXT, DB_TEXT, DB_INT, + DB_INT, DB_INT, DB_INT, DB_INT, + DB_INT, DB_INT, DB_INT, DB_INT, DB_INT, + DB_INT, DB_INT, DB_TEXT, DB_TEXT, + DB_INT, DB_INT, DB_TEXT); + if (e) + { + peer_cfg = build_peer_cfg(this, e, NULL, NULL); + e->destroy(e); + } + return peer_cfg; +} + +typedef struct { + /** implements enumerator */ + enumerator_t public; + /** reference to context */ + private_sql_config_t *this; + /** filtering own host */ + host_t *me; + /** filtering remote host */ + host_t *other; + /** inner SQL enumerator */ + enumerator_t *inner; + /** currently enumerated peer config */ + ike_cfg_t *current; +} ike_enumerator_t; + +/** + * Implementation of ike_enumerator_t.public.enumerate + */ +static bool ike_enumerator_enumerate(ike_enumerator_t *this, ike_cfg_t **cfg) +{ + DESTROY_IF(this->current); + this->current = build_ike_cfg(this->this, this->inner, this->me, this->other); + if (this->current) + { + *cfg = this->current; + return TRUE; + } + return FALSE; +} + +/** + * Implementation of ike_enumerator_t.public.destroy + */ +static void ike_enumerator_destroy(ike_enumerator_t *this) +{ + DESTROY_IF(this->current); + this->inner->destroy(this->inner); + free(this); +} + +/** + * Implementation of backend_t.create_ike_cfg_enumerator. + */ +static enumerator_t* create_ike_cfg_enumerator(private_sql_config_t *this, + host_t *me, host_t *other) +{ + ike_enumerator_t *e = malloc_thing(ike_enumerator_t); + + e->this = this; + e->me = me; + e->other = other; + e->current = NULL; + e->public.enumerate = (void*)ike_enumerator_enumerate; + e->public.destroy = (void*)ike_enumerator_destroy; + + e->inner = this->db->query(this->db, + "SELECT certreq, force_encap, local, remote " + "FROM ike_configs", + DB_INT, DB_INT, DB_TEXT, DB_TEXT); + if (!e->inner) + { + free(e); + return NULL; + } + return &e->public; +} + + +typedef struct { + /** implements enumerator */ + enumerator_t public; + /** reference to context */ + private_sql_config_t *this; + /** filtering own identity */ + identification_t *me; + /** filtering remote identity */ + identification_t *other; + /** inner SQL enumerator */ + enumerator_t *inner; + /** currently enumerated peer config */ + peer_cfg_t *current; +} peer_enumerator_t; + +/** + * Implementation of peer_enumerator_t.public.enumerate + */ +static bool peer_enumerator_enumerate(peer_enumerator_t *this, peer_cfg_t **cfg) +{ + DESTROY_IF(this->current); + this->current = build_peer_cfg(this->this, this->inner, this->me, this->other); + if (this->current) + { + *cfg = this->current; + return TRUE; + } + return FALSE; +} + +/** + * Implementation of peer_enumerator_t.public.destroy + */ +static void peer_enumerator_destroy(peer_enumerator_t *this) +{ + DESTROY_IF(this->current); + this->inner->destroy(this->inner); + free(this); +} + +/** + * Implementation of backend_t.create_peer_cfg_enumerator. + */ +static enumerator_t* create_peer_cfg_enumerator(private_sql_config_t *this, + identification_t *me, + identification_t *other) +{ + peer_enumerator_t *e = malloc_thing(peer_enumerator_t); + + e->this = this; + e->me = me; + e->other = other; + e->current = NULL; + e->public.enumerate = (void*)peer_enumerator_enumerate; + e->public.destroy = (void*)peer_enumerator_destroy; + + /* TODO: only get configs whose IDs match exactly or contain wildcards */ + e->inner = this->db->query(this->db, + "SELECT id, name, ike_cfg, local_id, remote_id, cert_policy, " + "auth_method, eap_type, eap_vendor, keyingtries, " + "rekeytime, reauthtime, jitter, overtime, mobike, " + "dpd_delay, dpd_action, local_vip, remote_vip, " + "mediation, mediated_by, peer_id " + "FROM peer_configs WHERE ike_version = ? ", + DB_INT, 2, + DB_INT, DB_TEXT, DB_INT, DB_TEXT, DB_TEXT, DB_INT, + DB_INT, DB_INT, DB_INT, DB_INT, + DB_INT, DB_INT, DB_INT, DB_INT, DB_INT, + DB_INT, DB_INT, DB_TEXT, DB_TEXT, + DB_INT, DB_INT, DB_TEXT); + if (!e->inner) + { + free(e); + return NULL; + } + return &e->public; +} + +/** + * Implementation of sql_config_t.destroy. + */ +static void destroy(private_sql_config_t *this) +{ + free(this); +} + +/** + * Described in header. + */ +sql_config_t *sql_config_create(database_t *db) +{ + private_sql_config_t *this = malloc_thing(private_sql_config_t); + + this->public.backend.create_peer_cfg_enumerator = (enumerator_t*(*)(backend_t*, identification_t *me, identification_t *other))create_peer_cfg_enumerator; + this->public.backend.create_ike_cfg_enumerator = (enumerator_t*(*)(backend_t*, host_t *me, host_t *other))create_ike_cfg_enumerator; + this->public.backend.get_peer_cfg_by_name = (peer_cfg_t* (*)(backend_t*,char*))get_peer_cfg_by_name; + this->public.destroy = (void(*)(sql_config_t*))destroy; + + this->db = db; + + return &this->public; +} + diff --git a/src/charon/plugins/sql/sql_config.h b/src/charon/plugins/sql/sql_config.h new file mode 100644 index 000000000..829d80da8 --- /dev/null +++ b/src/charon/plugins/sql/sql_config.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +/** + * @defgroup sql_config_i sql_config + * @{ @ingroup sql_config + */ + +#ifndef SQL_CONFIG_H_ +#define SQL_CONFIG_H_ + +#include +#include + +typedef struct sql_config_t sql_config_t; + +/** + * SQL database configuration backend. + */ +struct sql_config_t { + + /** + * Implements backend_t interface + */ + backend_t backend; + + /** + * Destry the backend. + */ + void (*destroy)(sql_config_t *this); +}; + +/** + * Create a sql_config backend instance. + * + * @param db underlying database + * @return backend instance + */ +sql_config_t *sql_config_create(database_t *db); + +#endif /* SQL_CONFIG_H_ @}*/ diff --git a/src/charon/plugins/sql/sql_plugin.c b/src/charon/plugins/sql/sql_plugin.c new file mode 100644 index 000000000..8ee6400ba --- /dev/null +++ b/src/charon/plugins/sql/sql_plugin.c @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "sql_plugin.h" + +#include +#include "sql_config.h" + +typedef struct private_sql_plugin_t private_sql_plugin_t; + +/** + * private data of sql plugin + */ +struct private_sql_plugin_t { + + /** + * implements plugin interface + */ + sql_plugin_t public; + + /** + * database connection instance + */ + database_t *db; + + /** + * configuration backend + */ + sql_config_t *config; +}; + +/** + * Implementation of plugin_t.destroy + */ +static void destroy(private_sql_plugin_t *this) +{ + charon->backends->remove_backend(charon->backends, &this->config->backend); + this->config->destroy(this->config); + this->db->destroy(this->db); + free(this); +} + +/* + * see header file + */ +plugin_t *plugin_create() +{ + char *uri; + private_sql_plugin_t *this; + + uri = lib->settings->get_str(lib->settings, "charon.plugins.sql.database", NULL); + if (!uri) + { + DBG1(DBG_CFG, "SQL plugin database URI not set"); + return NULL; + } + + this = malloc_thing(private_sql_plugin_t); + + this->public.plugin.destroy = (void(*)(plugin_t*))destroy; + + this->db = lib->db->create(lib->db, uri); + if (!this->db) + { + DBG1(DBG_CFG, "SQL plugin failed to connect to database"); + free(this); + return NULL; + } + this->config = sql_config_create(this->db); + + charon->backends->add_backend(charon->backends, &this->config->backend); + + return &this->public.plugin; +} + diff --git a/src/charon/plugins/sql/sql_plugin.h b/src/charon/plugins/sql/sql_plugin.h new file mode 100644 index 000000000..978df3744 --- /dev/null +++ b/src/charon/plugins/sql/sql_plugin.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +/** + * @defgroup sql sql + * @ingroup cplugins + * + * @defgroup sql_plugin sql_plugin + * @{ @ingroup sql + */ + +#ifndef SQL_PLUGIN_H_ +#define SQL_PLUGIN_H_ + +#include + +typedef struct sql_plugin_t sql_plugin_t; + +/** + * SQL database configuration plugin + */ +struct sql_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +/** + * Create a sql_plugin instance. + */ +plugin_t *plugin_create(); + +#endif /* SQL_PLUGIN_H_ @}*/ diff --git a/src/charon/plugins/sql/test.sql b/src/charon/plugins/sql/test.sql new file mode 100644 index 000000000..ec5b401c5 --- /dev/null +++ b/src/charon/plugins/sql/test.sql @@ -0,0 +1,47 @@ + +INSERT INTO ike_configs ( + certreq, force_encap, local, remote +) VALUES ( + 0, 0, '0.0.0.0', '152.96.52.150' +); + +INSERT INTO child_configs ( + name, lifetime, rekeytime, jitter, updown, hostaccess, mode +) VALUES ( + 'sqltest', 500, 400, 50, NULL, 1, 1 +); + +INSERT INTO peer_config_child_config ( + peer_cfg, child_cfg +) VALUES ( + 1, 1 +); + +INSERT INTO traffic_selectors ( + type, protocol +) values ( + 7, 0 +); + +INSERT INTO child_config_traffic_selector ( + child_cfg, traffic_selector, kind +) VALUES ( + 1, 1, 2 +); + +INSERT INTO child_config_traffic_selector ( + child_cfg, traffic_selector, kind +) VALUES ( + 1, 1, 3 +); + +INSERT INTO peer_configs ( + name, ike_version, ike_cfg, local_id, remote_id, cert_policy, auth_method, + eap_type, eap_vendor, keyingtries, rekeytime, reauthtime, jitter, overtime, + mobike, dpd_delay, dpd_action, local_vip, remote_vip, + mediation, mediated_by, peer_id +) VALUES ( + 'sqltest', 2, 1, 'C=CH, O=Linux strongSwan, CN=martin', 'sidv0150.hsr.ch', 0, 0, + 0, 0, 0, 500, 2000, 20, 20, + 1, 120, 0, NULL, NULL, 0, 0, NULL +); diff --git a/src/charon/plugins/stroke/Makefile.am b/src/charon/plugins/stroke/Makefile.am new file mode 100644 index 000000000..b2aeec132 --- /dev/null +++ b/src/charon/plugins/stroke/Makefile.am @@ -0,0 +1,10 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon -I$(top_srcdir)/src/stroke + +AM_CFLAGS = -rdynamic -DIPSEC_CONFDIR=\"${confdir}\" -DIPSEC_PIDDIR=\"${piddir}\" + +plugin_LTLIBRARIES = libcharon-stroke.la + +libcharon_stroke_la_SOURCES = stroke.h stroke.c +libcharon_stroke_la_LDFLAGS = -module + diff --git a/src/charon/plugins/stroke/stroke.c b/src/charon/plugins/stroke/stroke.c new file mode 100755 index 000000000..9d112844d --- /dev/null +++ b/src/charon/plugins/stroke/stroke.c @@ -0,0 +1,3335 @@ +/* + * Copyright (C) 2007 Tobias Brunner + * Copyright (C) 2006-2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "stroke.h" + +/* stroke message format definition */ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* configuration directories and files */ +#define CONFIG_DIR IPSEC_CONFDIR +#define IPSEC_D_DIR CONFIG_DIR "/ipsec.d" +#define PRIVATE_KEY_DIR IPSEC_D_DIR "/private" +#define CERTIFICATE_DIR IPSEC_D_DIR "/certs" +#define CA_CERTIFICATE_DIR IPSEC_D_DIR "/cacerts" +#define AA_CERTIFICATE_DIR IPSEC_D_DIR "/aacerts" +#define ATTR_CERTIFICATE_DIR IPSEC_D_DIR "/acerts" +#define OCSP_CERTIFICATE_DIR IPSEC_D_DIR "/ocspcerts" +#define CRL_DIR IPSEC_D_DIR "/crls" +#define SECRETS_FILE CONFIG_DIR "/ipsec.secrets" + +/* warning intervals for list functions */ +#define CERT_WARNING_INTERVAL 30 /* days */ +#define CRL_WARNING_INTERVAL 7 /* days */ + +typedef struct private_stroke_t private_stroke_t; +typedef struct stroke_credentials_t stroke_credentials_t; +typedef struct ca_creds_t ca_creds_t; +typedef struct creds_t creds_t; +typedef struct ca_section_t ca_section_t; +typedef struct configs_t configs_t; + +/** + * loaded ipsec.conf CA sections + */ +struct ca_section_t { + + /** + * name of the CA section + */ + char *name; + + /** + * reference to cert in trusted_credential_t + */ + certificate_t *cert; + + /** + * CRL URIs + */ + linked_list_t *crl; + + /** + * OCSP URIs + */ + linked_list_t *ocsp; +}; + +/** + * private credentail_set_t implementation for CA sections + */ +struct ca_creds_t { + /** + * implements credential set + */ + credential_set_t set; + + /** + * list of starters CA sections and its certificates (ca_section_t) + */ + linked_list_t *sections; + + /** + * mutex to lock sections list + */ + mutex_t *mutex; + +}; + +/** + * private credential_set_t implementation for trusted certificates and keys + */ +struct creds_t { + /** + * implements credential set + */ + credential_set_t set; + + /** + * list of trusted peer/signer/CA certificates (certificate_t) + */ + linked_list_t *certs; + + /** + * list of shared secrets (private_shared_key_t) + */ + linked_list_t *shared; + + /** + * list of private keys (private_key_t) + */ + linked_list_t *private; + + /** + * mutex to lock lists above + */ + mutex_t *mutex; +}; + + +typedef struct private_shared_key_t private_shared_key_t; +/** + * private data of shared_key + */ +struct private_shared_key_t { + + /** + * implements shared_key_t + */ + shared_key_t public; + + /** + * type of this key + */ + shared_key_type_t type; + + /** + * data of the key + */ + chunk_t key; + + /** + * list of key owners, as identification_t + */ + linked_list_t *owners; + + /** + * reference counter + */ + refcount_t ref; +}; + + +/** + * configuration backend including peer_cfg list + */ +struct configs_t { + + /** + * implements backend_t interface + */ + backend_t backend; + + /** + * list of peer_cfg_t + */ + linked_list_t *list; + + /** + * mutex to lock config list + */ + mutex_t *mutex; +}; + +/** + * Private data of an stroke_t object. + */ +struct private_stroke_t { + + /** + * Public part of stroke_t object. + */ + stroke_t public; + + /** + * Unix socket to listen for strokes + */ + int socket; + + /** + * job accepting stroke messages + */ + callback_job_t *job; + + /** + * CA credentials + */ + ca_creds_t ca_creds; + + /** + * other credentials + */ + creds_t creds; + + /** + * configuration backend + */ + configs_t configs; +}; + +typedef struct stroke_log_info_t stroke_log_info_t; + +/** + * helper struct to say what and where to log when using controller callback + */ +struct stroke_log_info_t { + + /** + * level to log up to + */ + level_t level; + + /** + * where to write log + */ + FILE* out; +}; + +/** + * create a new CA section + */ +static ca_section_t *ca_section_create(char *name, certificate_t *cert) +{ + ca_section_t *ca = malloc_thing(ca_section_t); + + ca->name = strdup(name); + ca->crl = linked_list_create(); + ca->ocsp = linked_list_create(); + ca->cert = cert; + return ca; +} + +/** + * destroy a ca section entry + */ +static void ca_section_destroy(ca_section_t *this) +{ + this->crl->destroy_function(this->crl, free); + this->ocsp->destroy_function(this->ocsp, free); + free(this->name); + free(this); +} + +/** + * another return NULL + */ +static void* return_null() +{ + return NULL; +} + +/** + * data to pass to create_inner_cdp + */ +typedef struct { + ca_creds_t *this; + certificate_type_t type; + identification_t *id; +} cdp_data_t; + +/** + * destroy cdp enumerator data and unlock list + */ +static void cdp_data_destroy(cdp_data_t *data) +{ + data->this->mutex->unlock(data->this->mutex); + free(data); +} + +/** + * inner enumerator constructor for CDP URIs + */ +static enumerator_t *create_inner_cdp(ca_section_t *section, cdp_data_t *data) +{ + public_key_t *public; + identification_t *keyid; + enumerator_t *enumerator = NULL; + linked_list_t *list; + + if (data->type == CERT_X509_OCSP_RESPONSE) + { + list = section->ocsp; + } + else + { + list = section->crl; + } + + public = section->cert->get_public_key(section->cert); + if (public) + { + if (!data->id) + { + enumerator = list->create_enumerator(list); + } + else + { + keyid = public->get_id(public, data->id->get_type(data->id)); + if (keyid && keyid->matches(keyid, data->id)) + { + enumerator = list->create_enumerator(list); + } + } + public->destroy(public); + } + return enumerator; +} + +/** + * Implementation of ca_creds_t.set.create_cdp_enumerator. + */ +static enumerator_t *create_cdp_enumerator(ca_creds_t *this, + certificate_type_t type, identification_t *id) +{ + cdp_data_t *data; + + switch (type) + { /* we serve CRLs and OCSP responders */ + case CERT_X509_CRL: + case CERT_X509_OCSP_RESPONSE: + case CERT_ANY: + break; + default: + return NULL; + } + data = malloc_thing(cdp_data_t); + data->this = this; + data->type = type; + data->id = id; + + this->mutex->lock(this->mutex); + return enumerator_create_nested(this->sections->create_enumerator(this->sections), + (void*)create_inner_cdp, data, + (void*)cdp_data_destroy); +} + +/** + * data to pass to various filters + */ +typedef struct { + creds_t *this; + identification_t *id; +} id_data_t; + +/** + * destroy id enumerator data and unlock list + */ +static void id_data_destroy(id_data_t *data) +{ + data->this->mutex->unlock(data->this->mutex); + free(data); +} + + +/** + * filter function for private key enumerator + */ +static bool private_filter(id_data_t *data, + private_key_t **in, private_key_t **out) +{ + identification_t *candidate; + + if (data->id == NULL) + { + *out = *in; + return TRUE; + } + candidate = (*in)->get_id(*in, data->id->get_type(data->id)); + if (candidate && data->id->equals(data->id, candidate)) + { + *out = *in; + return TRUE; + } + return FALSE; +} + +/** + * Implements creds_t.set.create_private_enumerator + */ +static enumerator_t* create_private_enumerator(creds_t *this, + key_type_t type, identification_t *id) +{ + id_data_t *data; + + if (type != KEY_RSA && type != KEY_ANY) + { /* we only have RSA keys */ + return NULL; + } + data = malloc_thing(id_data_t); + data->this = this; + data->id = id; + + this->mutex->lock(this->mutex); + return enumerator_create_filter(this->private->create_enumerator(this->private), + (void*)private_filter, data, + (void*)id_data_destroy); +} + +/** + * filter function for certs enumerator + */ +static bool certs_filter(id_data_t *data, certificate_t **in, certificate_t **out) +{ + public_key_t *public; + identification_t *candidate; + certificate_t *cert = *in; + + if (cert->get_type(cert) == CERT_X509_CRL) + { + return FALSE; + } + + if (data->id == NULL || cert->has_subject(cert, data->id)) + { + *out = *in; + return TRUE; + } + + public = (cert)->get_public_key(cert); + if (public) + { + candidate = public->get_id(public, data->id->get_type(data->id)); + if (candidate && data->id->equals(data->id, candidate)) + { + public->destroy(public); + *out = *in; + return TRUE; + } + public->destroy(public); + } + return FALSE; +} + +/** + * filter function for crl enumerator + */ +static bool crl_filter(id_data_t *data, certificate_t **in, certificate_t **out) +{ + certificate_t *cert = *in; + + if (cert->get_type(cert) != CERT_X509_CRL) + { + return FALSE; + } + + if (data->id == NULL || cert->has_issuer(cert, data->id)) + { + *out = *in; + return TRUE; + } + return FALSE; +} + +/** + * Implements creds_t.set.create_cert_enumerator + */ +static enumerator_t* create_cert_enumerator(creds_t *this, + certificate_type_t cert, key_type_t key, + identification_t *id, bool trusted) +{ + id_data_t *data; + + if (cert == CERT_X509_CRL) + { + data = malloc_thing(id_data_t); + data->this = this; + data->id = id; + + this->mutex->lock(this->mutex); + return enumerator_create_filter(this->certs->create_enumerator(this->certs), + (void*)crl_filter, data, + (void*)id_data_destroy); + } + if (cert != CERT_X509 && cert != CERT_ANY) + { /* we only have X509 certificates. TODO: ACs? */ + return NULL; + } + if (key != KEY_RSA && key != KEY_ANY) + { /* we only have RSA keys */ + return NULL; + } + data = malloc_thing(id_data_t); + data->this = this; + data->id = id; + + this->mutex->lock(this->mutex); + return enumerator_create_filter(this->certs->create_enumerator(this->certs), + (void*)certs_filter, data, + (void*)id_data_destroy); +} + +/** + * Implementation of shared_key_t.get_type. + */ +static shared_key_type_t get_type(private_shared_key_t *this) +{ + return this->type; +} + +/** + * Implementation of shared_key_t.get_ref. + */ +static private_shared_key_t* get_ref(private_shared_key_t *this) +{ + ref_get(&this->ref); + return this; +} + +/** + * Implementation of shared_key_t.destroy + */ +static void shared_key_destroy(private_shared_key_t *this) +{ + if (ref_put(&this->ref)) + { + this->owners->destroy_offset(this->owners, offsetof(identification_t, destroy)); + chunk_free(&this->key); + free(this); + } +} + +/** + * Implementation of shared_key_t.get_key. + */ +static chunk_t get_key(private_shared_key_t *this) +{ + return this->key; +} + +/** + * create a shared key + */ +static private_shared_key_t *shared_key_create(shared_key_type_t type, chunk_t key) +{ + private_shared_key_t *this = malloc_thing(private_shared_key_t); + + this->public.get_type = (shared_key_type_t(*)(shared_key_t*))get_type; + this->public.get_key = (chunk_t(*)(shared_key_t*))get_key; + this->public.get_ref = (shared_key_t*(*)(shared_key_t*))get_ref; + this->public.destroy = (void(*)(shared_key_t*))shared_key_destroy; + + this->owners = linked_list_create(); + this->type = type; + this->key = key; + this->ref = 1; + return this; +} + +/** + * Check if a key has such an owner + */ +static id_match_t has_owner(private_shared_key_t *this, identification_t *owner) +{ + enumerator_t *enumerator; + id_match_t match, best = ID_MATCH_NONE; + identification_t *current; + + enumerator = this->owners->create_enumerator(this->owners); + while (enumerator->enumerate(enumerator, ¤t)) + { + match = owner->matches(owner, current); + if (match > best) + { + best = match; + } + } + enumerator->destroy(enumerator); + return best; +} + +typedef struct { + creds_t *this; + identification_t *me; + identification_t *other; + shared_key_type_t type; +} shared_data_t; + +/** + * free shared key enumerator data and unlock list + */ +static void shared_data_destroy(shared_data_t *data) +{ + data->this->mutex->unlock(data->this->mutex); + free(data); +} + +/** + * filter function for certs enumerator + */ +static bool shared_filter(shared_data_t *data, + private_shared_key_t **in, private_shared_key_t **out, + void **unused1, id_match_t *me, + void **unused2, id_match_t *other) +{ + id_match_t my_match, other_match; + + if (!(*in)->type == SHARED_ANY && !(*in)->type == data->type) + { + return FALSE; + } + my_match = has_owner(*in, data->me); + other_match = has_owner(*in, data->other); + if (!my_match && !other_match) + { + return FALSE; + } + *out = *in; + if (me) + { + *me = my_match; + } + if (other) + { + *other = other_match; + } + return TRUE; +} + +/** + * Implements creds_t.set.create_shared_enumerator + */ +static enumerator_t* create_shared_enumerator(creds_t *this, + shared_key_type_t type, identification_t *me, + identification_t *other) +{ + shared_data_t *data = malloc_thing(shared_data_t); + + data->this = this; + data->me = me; + data->other = other; + data->type = type; + this->mutex->lock(this->mutex); + return enumerator_create_filter(this->shared->create_enumerator(this->shared), + (void*)shared_filter, data, + (void*)shared_data_destroy); +} + +/** + * Helper function which corrects the string pointers + * in a stroke_msg_t. Strings in a stroke_msg sent over "wire" + * contains RELATIVE addresses (relative to the beginning of the + * stroke_msg). They must be corrected if they reach our address + * space... + */ +static void pop_string(stroke_msg_t *msg, char **string) +{ + if (*string == NULL) + { + return; + } + + /* check for sanity of string pointer and string */ + if (string < (char**)msg || + string > (char**)msg + sizeof(stroke_msg_t) || + (unsigned long)*string < (unsigned long)((char*)msg->buffer - (char*)msg) || + (unsigned long)*string > msg->length) + { + *string = "(invalid pointer in stroke msg)"; + } + else + { + *string = (char*)msg + (unsigned long)*string; + } +} + +/** + * Load an X.509 certificate + */ +static x509_t* load_cert(char *path, x509_flag_t flag) +{ + bool pgp = FALSE; + chunk_t chunk; + x509_flag_t flags; + x509_t *x509; + certificate_t *cert; + + if (!pem_asn1_load_file(path, NULL, &chunk, &pgp)) + { + DBG1(DBG_CFG, " could not load certificate file '%s'", path); + return NULL; + } + x509 = (x509_t*)lib->creds->create(lib->creds, + CRED_CERTIFICATE, CERT_X509, + BUILD_BLOB_ASN1_DER, chunk, BUILD_END); + if (x509 == NULL) + { + DBG1(DBG_CFG, " could not load certificate file '%s'", path); + return NULL; + } + DBG1(DBG_CFG, " loaded certificate file '%s'", path); + + cert = &x509->interface; + flags = x509->get_flags(x509); + + /* check basicConstraints */ + if ((flag & X509_CA) && !(flags & X509_CA)) + { + DBG1(DBG_CFG, " isCA basicConstraint is not set, certificate discarded"); + cert->destroy(cert); + return NULL; + } + + /* set cert flags to flag but keep X509_SELF_SIGNED property */ + x509->set_flags(x509, flag | (flags & X509_SELF_SIGNED)); + + /* check validity */ + { + time_t notBefore, notAfter, now = time(NULL); + + cert->get_validity(cert, &now, ¬Before, ¬After); + if (now > notAfter) + { + DBG1(DBG_CFG, " certificate expired at %T, discarded", ¬After); + cert->destroy(cert); + return NULL; + } + if (now < notBefore) + { + DBG1(DBG_CFG, " certificate not valid before %T", ¬Before); + } + } + return x509; +} + +/** + * Add X.509 certificate to chain + */ +static certificate_t* add_x509_cert(private_stroke_t *this, x509_t* x509) +{ + certificate_t *current, *cert = &x509->interface; + enumerator_t *enumerator; + bool new = TRUE; + + this->creds.mutex->lock(this->creds.mutex); + enumerator = this->creds.certs->create_enumerator(this->creds.certs); + while (enumerator->enumerate(enumerator, (void**)¤t)) + { + if (current->equals(current, cert)) + { + x509_flag_t flags = x509->get_flags(x509); + x509_t *x509c = (x509_t*)current; + + /* cert already in queue - add flags and discard */ + x509c->set_flags(x509c, flags | x509c->get_flags(x509c)); + cert->destroy(cert); + cert = current; + new = FALSE; + break; + } + } + enumerator->destroy(enumerator); + + if (new) + { + this->creds.certs->insert_last(this->creds.certs, cert); + } + this->creds.mutex->unlock(this->creds.mutex); + return cert; +} + +/** + * Verify the signature of an X.509 CRL + */ +static bool verify_crl(crl_t* crl) +{ + certificate_t *crl_cert = &crl->certificate; + identification_t *issuer = crl_cert->get_issuer(crl_cert); + identification_t *authKeyIdentifier = crl->get_authKeyIdentifier(crl); + certificate_t *issuer_cert; + + DBG1(DBG_CFG, " issuer: %D", issuer); + if (authKeyIdentifier) + { + DBG1(DBG_CFG, " authkey: %D", authKeyIdentifier); + } + + issuer_cert = charon->credentials->get_cert(charon->credentials, CERT_X509, + KEY_ANY, issuer, TRUE); + + if (issuer_cert) + { + + bool ok = crl_cert->issued_by(crl_cert, issuer_cert, TRUE); + + DBG1(DBG_CFG, " crl is %strusted: %s signature", + ok? "":"un", ok? "good":"bad"); + return ok; + } + else + { + DBG1(DBG_CFG, " crl is untrusted: issuer certificate not found"); + return FALSE; + } +} + +/** + * Add X.509 CRL to chain + */ +static void add_crl(private_stroke_t *this, crl_t* crl) +{ + certificate_t *current, *cert = &crl->certificate; + enumerator_t *enumerator; + bool new = TRUE, found = FALSE; + + this->creds.mutex->lock(this->creds.mutex); + enumerator = this->creds.certs->create_enumerator(this->creds.certs); + while (enumerator->enumerate(enumerator, (void**)¤t)) + { + if (current->get_type(current) == CERT_X509_CRL) + { + crl_t *crl_c = (crl_t*)current; + identification_t *authkey = crl->get_authKeyIdentifier(crl); + identification_t *authkey_c = crl_c->get_authKeyIdentifier(crl_c); + + /* if compare authorityKeyIdentifiers if available */ + if (authkey != NULL && authkey_c != NULL && + authkey->equals(authkey, authkey_c)) + { + found = TRUE; + } + else + { + identification_t *issuer = cert->get_issuer(cert); + identification_t *issuer_c = current->get_issuer(current); + + /* otherwise compare issuer distinguished names */ + if (issuer->equals(issuer, issuer_c)) + { + found = TRUE; + } + } + if (found) + { + new = crl->is_newer(crl, crl_c); + if (new) + { + this->creds.certs->remove_at(this->creds.certs, enumerator); + } + else + { + cert->destroy(cert); + } + break; + } + } + } + enumerator->destroy(enumerator); + + if (new) + { + this->creds.certs->insert_last(this->creds.certs, cert); + } + this->creds.mutex->unlock(this->creds.mutex); +} + +/** + * Load end entitity certificate + */ +static void load_peer_cert(private_stroke_t *this, + char *filename, identification_t **id) +{ + char path[PATH_MAX]; + x509_t *x509; + identification_t *peerid = *id; + + if (*filename == '/') + { + snprintf(path, sizeof(path), "%s", filename); + } + else + { + snprintf(path, sizeof(path), "%s/%s", CERTIFICATE_DIR, filename); + } + + x509 = load_cert(path, X509_PEER); + + if (x509) + { + certificate_t *cert = &x509->interface;; + identification_t *subject = cert->get_subject(cert); + + if (!cert->has_subject(cert, peerid)) + { + DBG1(DBG_CFG, " peerid %D not confirmed by certificate, " + "defaulting to subject DN", peerid); + peerid->destroy(peerid); + *id = subject->clone(subject); + } + add_x509_cert(this, x509); + } +} + +/** + * Load ca certificate + */ +static certificate_t* load_ca_cert(private_stroke_t *this, char *filename) +{ + char path[PATH_MAX]; + x509_t *x509; + + if (*filename == '/') + { + snprintf(path, sizeof(path), "%s", filename); + } + else + { + snprintf(path, sizeof(path), "%s/%s", CA_CERTIFICATE_DIR, filename); + } + + x509 = load_cert(path, X509_CA); + + if (x509) + { + return add_x509_cert(this, x509); + } + else + { + return NULL; + } +} + +/** + * load trusted certificates from a directory + */ +static void load_certdir(private_stroke_t *this, + char *path, certificate_type_t type, x509_flag_t flag) +{ + struct stat st; + char *file; + + enumerator_t *enumerator = enumerator_create_directory(path); + + if (!enumerator) + { + DBG1(DBG_CFG, " reading directory failed"); + return; + } + + while (enumerator->enumerate(enumerator, NULL, &file, &st)) + { + if (!S_ISREG(st.st_mode)) + { + /* skip special file */ + continue; + } + if (type == CERT_X509) + { + x509_t *x509 = load_cert(file, flag); + + if (x509) + { + add_x509_cert(this, x509); + } + } + else + { + certificate_t *cert; + bool pgp = FALSE; + chunk_t chunk; + + if (!pem_asn1_load_file(file, NULL, &chunk, &pgp)) + { + continue; + } + cert = lib->creds->create(lib->creds, + CRED_CERTIFICATE, type, + BUILD_BLOB_ASN1_DER, chunk, BUILD_END); + if (type == CERT_X509_CRL) + { + if (cert) + { + crl_t *crl = (crl_t*)cert; + + DBG1(DBG_CFG, " loaded crl file '%s'", file); + + /* only trusted crls are added to the store */ + if (verify_crl(crl)) + { + add_crl(this, crl); + } + else + { + DBG1(DBG_CFG, " crl discarded"); + cert->destroy(cert); + } + } + else + { + DBG1(DBG_CFG, " could not load crl file '%s'", file); + } + } + } + } + enumerator->destroy(enumerator); +} + +/** + * Convert a string of characters into a binary secret + * A string between single or double quotes is treated as ASCII characters + * A string prepended by 0x is treated as HEX and prepended by 0s as Base64 + */ +static err_t extract_secret(chunk_t *secret, chunk_t *line) +{ + chunk_t raw_secret; + char delimiter = ' '; + bool quotes = FALSE; + + if (!eat_whitespace(line)) + { + return "missing secret"; + } + + if (*line->ptr == '\'' || *line->ptr == '"') + { + quotes = TRUE; + delimiter = *line->ptr; + line->ptr++; line->len--; + } + + if (!extract_token(&raw_secret, delimiter, line)) + { + if (delimiter == ' ') + { + raw_secret = *line; + } + else + { + return "missing second delimiter"; + } + } + + if (quotes) + { + /* treat as an ASCII string */ + *secret = chunk_clone(raw_secret); + } + else + { + size_t len; + err_t ugh; + + /* secret converted to binary form doesn't use more space than the raw_secret */ + *secret = chunk_alloc(raw_secret.len); + + /* convert from HEX or Base64 to binary */ + ugh = ttodata(raw_secret.ptr, raw_secret.len, 0, secret->ptr, secret->len, &len); + + if (ugh != NULL) + { + chunk_free_randomized(secret); + return ugh; + } + secret->len = len; + } + return NULL; +} + +/** + * reload ipsec.secrets + */ +static void load_secrets(private_stroke_t *this) +{ + size_t bytes; + int line_nr = 0; + chunk_t chunk, src, line; + FILE *fd; + private_key_t *private; + shared_key_t *shared; + + DBG1(DBG_CFG, "loading secrets from '%s'", SECRETS_FILE); + + fd = fopen(SECRETS_FILE, "r"); + if (fd == NULL) + { + DBG1(DBG_CFG, "opening secrets file '%s' failed"); + return; + } + + /* TODO: do error checks */ + fseek(fd, 0, SEEK_END); + chunk.len = ftell(fd); + rewind(fd); + chunk.ptr = malloc(chunk.len); + bytes = fread(chunk.ptr, 1, chunk.len, fd); + fclose(fd); + src = chunk; + + this->creds.mutex->lock(this->creds.mutex); + while (this->creds.shared->remove_last(this->creds.shared, + (void**)&shared) == SUCCESS) + { + shared->destroy(shared); + } + while (this->creds.private->remove_last(this->creds.private, + (void**)&private) == SUCCESS) + { + private->destroy(private); + } + + while (fetchline(&src, &line)) + { + chunk_t ids, token; + shared_key_type_t type; + + line_nr++; + + if (!eat_whitespace(&line)) + { + continue; + } + if (!extract_token(&ids, ':', &line)) + { + DBG1(DBG_CFG, "line %d: missing ':' separator", line_nr); + goto error; + } + /* NULL terminate the ids string by replacing the : separator */ + *(ids.ptr + ids.len) = '\0'; + + if (!eat_whitespace(&line) || !extract_token(&token, ' ', &line)) + { + DBG1(DBG_CFG, "line %d: missing token", line_nr); + goto error; + } + if (match("RSA", &token)) + { + char path[PATH_MAX]; + chunk_t filename; + chunk_t secret = chunk_empty; + private_key_t *key; + bool pgp = FALSE; + chunk_t chunk = chunk_empty; + + err_t ugh = extract_value(&filename, &line); + + if (ugh != NULL) + { + DBG1(DBG_CFG, "line %d: %s", line_nr, ugh); + goto error; + } + if (filename.len == 0) + { + DBG1(DBG_CFG, "line %d: empty filename", line_nr); + goto error; + } + if (*filename.ptr == '/') + { + /* absolute path name */ + snprintf(path, sizeof(path), "%.*s", filename.len, filename.ptr); + } + else + { + /* relative path name */ + snprintf(path, sizeof(path), "%s/%.*s", PRIVATE_KEY_DIR, + filename.len, filename.ptr); + } + + /* check for optional passphrase */ + if (eat_whitespace(&line)) + { + ugh = extract_secret(&secret, &line); + if (ugh != NULL) + { + DBG1(DBG_CFG, "line %d: malformed passphrase: %s", line_nr, ugh); + goto error; + } + } + + if (pem_asn1_load_file(path, &secret, &chunk, &pgp)) + { + key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA, + BUILD_BLOB_ASN1_DER, chunk, BUILD_END); + if (key) + { + DBG1(DBG_CFG, " loaded private key file '%s'", path); + this->creds.private->insert_last(this->creds.private, key); + } + } + chunk_free_randomized(&secret); + } + else if ((match("PSK", &token) && (type = SHARED_IKE)) || + (match("EAP", &token) && (type = SHARED_EAP)) || + (match("XAUTH", &token) && (type = SHARED_EAP)) || + (match("PIN", &token) && (type = SHARED_PIN))) + { + private_shared_key_t *shared_key; + chunk_t secret = chunk_empty; + bool any = TRUE; + + err_t ugh = extract_secret(&secret, &line); + if (ugh != NULL) + { + DBG1(DBG_CFG, "line %d: malformed secret: %s", line_nr, ugh); + goto error; + } + shared_key = shared_key_create(type, secret); + DBG1(DBG_CFG, " loaded %N secret for %s", shared_key_type_names, type, + ids.len > 0 ? (char*)ids.ptr : "%any"); + DBG4(DBG_CFG, " secret:", secret); + + this->creds.shared->insert_last(this->creds.shared, shared_key); + while (ids.len > 0) + { + chunk_t id; + identification_t *peer_id; + + ugh = extract_value(&id, &ids); + if (ugh != NULL) + { + DBG1(DBG_CFG, "line %d: %s", line_nr, ugh); + goto error; + } + if (id.len == 0) + { + continue; + } + + /* NULL terminate the ID string */ + *(id.ptr + id.len) = '\0'; + + peer_id = identification_create_from_string(id.ptr); + if (peer_id == NULL) + { + DBG1(DBG_CFG, "line %d: malformed ID: %s", line_nr, id.ptr); + goto error; + } + if (peer_id->get_type(peer_id) == ID_ANY) + { + peer_id->destroy(peer_id); + continue; + } + + shared_key->owners->insert_last(shared_key->owners, peer_id); + any = FALSE; + } + if (any) + { + shared_key->owners->insert_last(shared_key->owners, + identification_create_from_encoding(ID_ANY, chunk_empty)); + } + } + else + { + DBG1(DBG_CFG, "line %d: token must be either " + "RSA, PSK, EAP, or PIN", line_nr); + goto error; + } + } +error: + this->creds.mutex->unlock(this->creds.mutex); + chunk_free_randomized(&chunk); +} + +/** + * data to pass peer_filter + */ +typedef struct { + configs_t *this; + identification_t *me; + identification_t *other; +} peer_data_t; + +/** + * destroy id enumerator data and unlock list + */ +static void peer_data_destroy(peer_data_t *data) +{ + data->this->mutex->unlock(data->this->mutex); + free(data); +} + +/** + * filter function for peer configs + */ +static bool peer_filter(peer_data_t *data, peer_cfg_t **in, peer_cfg_t **out) +{ + + if ((!data->me || data->me->matches(data->me, (*in)->get_my_id(*in))) && + (!data->other || data->other->matches(data->other, (*in)->get_other_id(*in)))) + { + *out = *in; + return TRUE; + } + return FALSE; +} + +/** + * Implementation of backend_t.create_peer_cfg_enumerator. + */ +static enumerator_t* create_peer_cfg_enumerator(configs_t *this, + identification_t *me, + identification_t *other) +{ + peer_data_t *data; + + data = malloc_thing(peer_data_t); + data->this = this; + data->me = me; + data->other = other; + + this->mutex->lock(this->mutex); + return enumerator_create_filter(this->list->create_enumerator(this->list), + (void*)peer_filter, data, + (void*)peer_data_destroy); +} + +/** + * data to pass ike_filter + */ +typedef struct { + configs_t *this; + host_t *me; + host_t *other; +} ike_data_t; + +/** + * destroy id enumerator data and unlock list + */ +static void ike_data_destroy(ike_data_t *data) +{ + data->this->mutex->unlock(data->this->mutex); + free(data); +} + +/** + * filter function for ike configs + */ +static bool ike_filter(ike_data_t *data, peer_cfg_t **in, ike_cfg_t **out) +{ + ike_cfg_t *ike_cfg; + host_t *me, *other; + + ike_cfg = (*in)->get_ike_cfg(*in); + + me = ike_cfg->get_my_host(ike_cfg); + other = ike_cfg->get_other_host(ike_cfg); + if ((!data->me || me->is_anyaddr(me) || me->ip_equals(me, data->me)) && + (!data->other || other->is_anyaddr(other) || other->ip_equals(other, data->me))) + { + *out = ike_cfg; + return TRUE; + } + return FALSE; +} + +/** + * Implementation of backend_t.create_ike_cfg_enumerator. + */ +static enumerator_t* create_ike_cfg_enumerator(configs_t *this, + host_t *me, host_t *other) +{ + ike_data_t *data; + + data = malloc_thing(ike_data_t); + data->this = this; + data->me = me; + data->other = other; + + this->mutex->lock(this->mutex); + return enumerator_create_filter(this->list->create_enumerator(this->list), + (void*)ike_filter, data, + (void*)ike_data_destroy); +} + +/** + * implements backend_t.get_peer_cfg_by_name. + */ +static peer_cfg_t *get_peer_cfg_by_name(configs_t *this, char *name) +{ + enumerator_t *e1, *e2; + peer_cfg_t *current, *found = NULL; + child_cfg_t *child; + + this->mutex->lock(this->mutex); + e1 = this->list->create_enumerator(this->list); + while (e1->enumerate(e1, ¤t)) + { + /* compare peer_cfgs name first */ + if (streq(current->get_name(current), name)) + { + found = current; + found->get_ref(found); + break; + } + /* compare all child_cfg names otherwise */ + e2 = current->create_child_cfg_enumerator(current); + while (e2->enumerate(e2, &child)) + { + if (streq(child->get_name(child), name)) + { + found = current; + found->get_ref(found); + break; + } + } + e2->destroy(e2); + if (found) + { + break; + } + } + e1->destroy(e1); + this->mutex->unlock(this->mutex); + return found; +} + +/** + * Pop the strings of a stroke_end_t struct and log them for debugging purposes + */ +static void pop_end(stroke_msg_t *msg, const char* label, stroke_end_t *end) +{ + pop_string(msg, &end->address); + pop_string(msg, &end->subnet); + pop_string(msg, &end->sourceip); + pop_string(msg, &end->id); + pop_string(msg, &end->cert); + pop_string(msg, &end->ca); + pop_string(msg, &end->groups); + pop_string(msg, &end->updown); + + DBG2(DBG_CFG, " %s=%s", label, end->address); + DBG2(DBG_CFG, " %ssubnet=%s", label, end->subnet); + DBG2(DBG_CFG, " %ssourceip=%s", label, end->sourceip); + DBG2(DBG_CFG, " %sid=%s", label, end->id); + DBG2(DBG_CFG, " %scert=%s", label, end->cert); + DBG2(DBG_CFG, " %sca=%s", label, end->ca); + DBG2(DBG_CFG, " %sgroups=%s", label, end->groups); + DBG2(DBG_CFG, " %supdown=%s", label, end->updown); +} + +/** + * Add a connection to the configuration list + */ +static void stroke_add_conn(private_stroke_t *this, + stroke_msg_t *msg, FILE *out) +{ + ike_cfg_t *ike_cfg; + peer_cfg_t *peer_cfg; + peer_cfg_t *mediated_by_cfg = NULL; + child_cfg_t *child_cfg; + auth_info_t *auth; + identification_t *my_id, *other_id; + identification_t *my_ca = NULL; + identification_t *other_ca = NULL; + identification_t *peer_id = NULL; + bool my_ca_same = FALSE; + bool other_ca_same =FALSE; + host_t *my_host = NULL, *other_host = NULL, *my_subnet, *other_subnet; + host_t *my_vip = NULL, *other_vip = NULL; + proposal_t *proposal; + traffic_selector_t *my_ts, *other_ts; + char *interface; + bool use_existing = FALSE; + enumerator_t *enumerator; + u_int32_t vendor; + + pop_string(msg, &msg->add_conn.name); + DBG1(DBG_CFG, "received stroke: add connection '%s'", msg->add_conn.name); + DBG2(DBG_CFG, "conn %s", msg->add_conn.name); + pop_end(msg, "left", &msg->add_conn.me); + pop_end(msg, "right", &msg->add_conn.other); + pop_string(msg, &msg->add_conn.algorithms.ike); + pop_string(msg, &msg->add_conn.algorithms.esp); + DBG2(DBG_CFG, " ike=%s", msg->add_conn.algorithms.ike); + DBG2(DBG_CFG, " esp=%s", msg->add_conn.algorithms.esp); + pop_string(msg, &msg->add_conn.p2p.mediated_by); + pop_string(msg, &msg->add_conn.p2p.peerid); + DBG2(DBG_CFG, " p2p_mediation=%s", msg->add_conn.p2p.mediation ? "yes" : "no"); + DBG2(DBG_CFG, " p2p_mediated_by=%s", msg->add_conn.p2p.mediated_by); + DBG2(DBG_CFG, " p2p_peerid=%s", msg->add_conn.p2p.peerid); + + if (msg->add_conn.me.address) + { + my_host = host_create_from_string(msg->add_conn.me.address, + IKEV2_UDP_PORT); + } + if (my_host == NULL) + { + DBG1(DBG_CFG, "invalid host: %s\n", msg->add_conn.me.address); + return; + } + if (msg->add_conn.other.address) + { + other_host = host_create_from_string(msg->add_conn.other.address, + IKEV2_UDP_PORT); + } + if (other_host == NULL) + { + DBG1(DBG_CFG, "invalid host: %s\n", msg->add_conn.other.address); + my_host->destroy(my_host); + return; + } + + interface = charon->kernel_interface->get_interface(charon->kernel_interface, + other_host); + if (interface) + { + stroke_end_t tmp_end; + host_t *tmp_host; + + DBG2(DBG_CFG, "left is other host, swapping ends\n"); + + tmp_host = my_host; + my_host = other_host; + other_host = tmp_host; + + tmp_end = msg->add_conn.me; + msg->add_conn.me = msg->add_conn.other; + msg->add_conn.other = tmp_end; + free(interface); + } + else + { + interface = charon->kernel_interface->get_interface( + charon->kernel_interface, my_host); + if (!interface) + { + DBG1(DBG_CFG, "left nor right host is our side, assuming left=local"); + } + else + { + free(interface); + } + } + + my_id = identification_create_from_string(msg->add_conn.me.id ? + msg->add_conn.me.id : msg->add_conn.me.address); + if (my_id == NULL) + { + DBG1(DBG_CFG, "invalid ID: %s\n", msg->add_conn.me.id); + goto destroy_hosts; + } + + other_id = identification_create_from_string(msg->add_conn.other.id ? + msg->add_conn.other.id : msg->add_conn.other.address); + if (other_id == NULL) + { + DBG1(DBG_CFG, "invalid ID: %s\n", msg->add_conn.other.id); + my_id->destroy(my_id); + goto destroy_hosts; + } + +#ifdef P2P + if (msg->add_conn.p2p.mediation && msg->add_conn.p2p.mediated_by) + { + DBG1(DBG_CFG, "a mediation connection cannot be a" + " mediated connection at the same time, aborting"); + goto destroy_ids; + } + + if (msg->add_conn.p2p.mediated_by) + { + mediated_by_cfg = charon->backends->get_peer_cfg_by_name(charon->backends, + msg->add_conn.p2p.mediated_by); + if (!mediated_by_cfg) + { + DBG1(DBG_CFG, "mediation connection '%s' not found, aborting", + msg->add_conn.p2p.mediated_by); + goto destroy_ids; + } + + if (!mediated_by_cfg->is_mediation(mediated_by_cfg)) + { + DBG1(DBG_CFG, "connection '%s' as referred to by '%s' is" + "no mediation connection, aborting", + msg->add_conn.p2p.mediated_by, msg->add_conn.name); + goto destroy_ids; + } + } + + if (msg->add_conn.p2p.peerid) + { + peer_id = identification_create_from_string(msg->add_conn.p2p.peerid); + if (!peer_id) + { + DBG1(DBG_CFG, "invalid peer ID: %s\n", msg->add_conn.p2p.peerid); + goto destroy_ids; + } + } + else + { + /* no peer ID supplied, assume right ID */ + peer_id = other_id->clone(other_id); + } +#endif /* P2P */ + + my_subnet = host_create_from_string( + msg->add_conn.me.subnet ? msg->add_conn.me.subnet + : msg->add_conn.me.address, + IKEV2_UDP_PORT); + if (my_subnet == NULL) + { + DBG1(DBG_CFG, "invalid subnet: %s\n", msg->add_conn.me.subnet); + goto destroy_ids; + } + + other_subnet = host_create_from_string( + msg->add_conn.other.subnet ? msg->add_conn.other.subnet + : msg->add_conn.other.address, + IKEV2_UDP_PORT); + if (other_subnet == NULL) + { + DBG1(DBG_CFG, "invalid subnet: %s\n", msg->add_conn.me.subnet); + my_subnet->destroy(my_subnet); + goto destroy_ids; + } + + if (msg->add_conn.me.virtual_ip && msg->add_conn.me.sourceip) + { + my_vip = host_create_from_string(msg->add_conn.me.sourceip, 0); + } + if (msg->add_conn.other.virtual_ip && msg->add_conn.other.sourceip) + { + other_vip = host_create_from_string(msg->add_conn.other.sourceip, 0); + } + + if (msg->add_conn.me.tohost) + { + my_ts = traffic_selector_create_dynamic(msg->add_conn.me.protocol, + my_host->get_family(my_host) == AF_INET ? + TS_IPV4_ADDR_RANGE : TS_IPV6_ADDR_RANGE, + msg->add_conn.me.port ? msg->add_conn.me.port : 0, + msg->add_conn.me.port ? msg->add_conn.me.port : 65535); + } + else + { + my_ts = traffic_selector_create_from_subnet(my_subnet, + msg->add_conn.me.subnet ? msg->add_conn.me.subnet_mask : 0, + msg->add_conn.me.protocol, msg->add_conn.me.port); + } + my_subnet->destroy(my_subnet); + + if (msg->add_conn.other.tohost) + { + other_ts = traffic_selector_create_dynamic(msg->add_conn.other.protocol, + other_host->get_family(other_host) == AF_INET ? + TS_IPV4_ADDR_RANGE : TS_IPV6_ADDR_RANGE, + msg->add_conn.other.port ? msg->add_conn.other.port : 0, + msg->add_conn.other.port ? msg->add_conn.other.port : 65535); + } + else + { + other_ts = traffic_selector_create_from_subnet(other_subnet, + msg->add_conn.other.subnet ? msg->add_conn.other.subnet_mask : 0, + msg->add_conn.other.protocol, msg->add_conn.other.port); + } + other_subnet->destroy(other_subnet); + + if (msg->add_conn.me.ca) + { + if (streq(msg->add_conn.me.ca, "%same")) + { + my_ca_same = TRUE; + } + else + { + my_ca = identification_create_from_string(msg->add_conn.me.ca); + } + } + if (msg->add_conn.other.ca) + { + if (streq(msg->add_conn.other.ca, "%same")) + { + other_ca_same = TRUE; + } + else + { + other_ca = identification_create_from_string(msg->add_conn.other.ca); + } + } + if (msg->add_conn.me.cert) + { + load_peer_cert(this, msg->add_conn.me.cert, &my_id); + } + if (msg->add_conn.other.cert) + { + load_peer_cert(this, msg->add_conn.other.cert, &other_id); + } + if (other_ca_same && my_ca) + { + other_ca = my_ca->clone(my_ca); + } + else if (my_ca_same && other_ca) + { + my_ca = other_ca->clone(other_ca); + } + + if (my_ca) + { + DBG2(DBG_CFG, " my ca: %D", my_ca); + } + if (other_ca) + { + DBG2(DBG_CFG, " other ca: %D", other_ca); + } + + if (msg->add_conn.other.groups) + { + /* TODO: AC groups */ + } + + /* TODO: update matching */ + /* have a look for an (almost) identical peer config to reuse */ + enumerator = create_peer_cfg_enumerator(&this->configs, NULL, NULL); + while (enumerator->enumerate(enumerator, &peer_cfg)) + { + host_t *my_vip_conf, *other_vip_conf; + bool my_vip_equals = FALSE, other_vip_equals = FALSE; + + my_vip_conf = peer_cfg->get_my_virtual_ip(peer_cfg); + if ((my_vip && my_vip_conf && my_vip->equals(my_vip, my_vip_conf)) || + (!my_vip_conf && !my_vip)) + { + my_vip_equals = TRUE; + } + DESTROY_IF(my_vip_conf); + other_vip_conf = peer_cfg->get_other_virtual_ip(peer_cfg, NULL); + if ((other_vip && other_vip_conf && other_vip->equals(other_vip, other_vip_conf)) || + (!other_vip_conf && !other_vip)) + { + other_vip_equals = TRUE; + } + DESTROY_IF(other_vip_conf); + + ike_cfg = peer_cfg->get_ike_cfg(peer_cfg); + if (my_id->equals(my_id, peer_cfg->get_my_id(peer_cfg)) + && other_id->equals(other_id, peer_cfg->get_other_id(peer_cfg)) + && my_host->equals(my_host, ike_cfg->get_my_host(ike_cfg)) + && other_host->equals(other_host, ike_cfg->get_other_host(ike_cfg)) + && peer_cfg->get_ike_version(peer_cfg) == (msg->add_conn.ikev2 ? 2 : 1) + && peer_cfg->get_auth_method(peer_cfg) == msg->add_conn.auth_method + && peer_cfg->get_eap_type(peer_cfg, &vendor) == msg->add_conn.eap_type + && vendor == msg->add_conn.eap_vendor + && my_vip_equals && other_vip_equals) + { + DBG1(DBG_CFG, "reusing existing configuration '%s'", + peer_cfg->get_name(peer_cfg)); + use_existing = TRUE; + break; + } + } + enumerator->destroy(enumerator); + + if (use_existing) + { + DESTROY_IF(my_vip); + DESTROY_IF(other_vip); + my_host->destroy(my_host); + my_id->destroy(my_id); + DESTROY_IF(my_ca); + other_host->destroy(other_host); + other_id->destroy(other_id); + DESTROY_IF(other_ca); + DESTROY_IF(peer_id); + DESTROY_IF(mediated_by_cfg); + } + else + { + ike_cfg = ike_cfg_create(msg->add_conn.other.sendcert != CERT_NEVER_SEND, + msg->add_conn.force_encap, my_host, other_host); + + if (msg->add_conn.algorithms.ike) + { + char *proposal_string; + char *strict = msg->add_conn.algorithms.ike + strlen(msg->add_conn.algorithms.ike) - 1; + + if (*strict == '!') + *strict = '\0'; + else + strict = NULL; + + while ((proposal_string = strsep(&msg->add_conn.algorithms.ike, ","))) + { + proposal = proposal_create_from_string(PROTO_IKE, proposal_string); + if (proposal == NULL) + { + DBG1(DBG_CFG, "invalid IKE proposal string: %s", proposal_string); + my_id->destroy(my_id); + other_id->destroy(other_id); + my_ts->destroy(my_ts); + other_ts->destroy(other_ts); + DESTROY_IF(my_ca); + DESTROY_IF(other_ca); + ike_cfg->destroy(ike_cfg); + return; + } + ike_cfg->add_proposal(ike_cfg, proposal); + } + if (!strict) + { + proposal = proposal_create_default(PROTO_IKE); + ike_cfg->add_proposal(ike_cfg, proposal); + } + } + else + { + proposal = proposal_create_default(PROTO_IKE); + ike_cfg->add_proposal(ike_cfg, proposal); + } + + u_int32_t rekey = 0, reauth = 0, over, jitter; + cert_validation_t valid; + + jitter = msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100; + over = msg->add_conn.rekey.margin; + if (msg->add_conn.rekey.reauth) + { + reauth = msg->add_conn.rekey.ike_lifetime - over; + } + else + { + rekey = msg->add_conn.rekey.ike_lifetime - over; + } + + peer_cfg = peer_cfg_create(msg->add_conn.name, + msg->add_conn.ikev2 ? 2 : 1, ike_cfg, my_id, other_id, + msg->add_conn.me.sendcert, msg->add_conn.auth_method, + msg->add_conn.eap_type, msg->add_conn.eap_vendor, + msg->add_conn.rekey.tries, rekey, reauth, jitter, over, + msg->add_conn.mobike, + msg->add_conn.dpd.delay, msg->add_conn.dpd.action, my_vip, other_vip, + msg->add_conn.p2p.mediation, mediated_by_cfg, peer_id); + auth = peer_cfg->get_auth(peer_cfg); + switch (msg->add_conn.crl_policy) + { + case CRL_STRICT_YES: + valid = VALIDATION_GOOD; + auth->add_item(auth, AUTHZ_CRL_VALIDATION, &valid); + break; + case CRL_STRICT_IFURI: + valid = VALIDATION_SKIPPED; + auth->add_item(auth, AUTHZ_CRL_VALIDATION, &valid); + break; + default: + break; + } + + if (other_ca) + { + DBG1(DBG_CFG, " required other CA: %D", other_ca); + certificate_t *cert = charon->credentials->get_cert(charon->credentials, + CERT_X509, KEY_ANY, other_ca, TRUE); + if (!cert) + { + DBG1(DBG_CFG, "deleted connection '%s': " + "no trusted certificate found for required other CA", + msg->add_conn.name); + peer_cfg->destroy(peer_cfg); + other_ca->destroy(other_ca); + my_ts->destroy(my_ts); + other_ts->destroy(other_ts); + return; + } + /* require peer to authenticate against this cert */ + auth->add_item(auth, AUTHZ_CA_CERT, cert); + cert->destroy(cert); + other_ca->destroy(other_ca); + } + if (my_ca) + { + certificate_t *cert = charon->credentials->get_cert(charon->credentials, + CERT_X509, KEY_ANY, my_ca, TRUE); + if (!cert) + { + DBG1(DBG_CFG, "deleted connection '%s': " + "no trusted certificate found for my CA", + msg->add_conn.name); + peer_cfg->destroy(peer_cfg); + my_ca->destroy(my_ca); + my_ts->destroy(my_ts); + other_ts->destroy(other_ts); + return; + } + /* we authenticate against this cert */ + auth->add_item(auth, AUTHN_CA_CERT, cert); + cert->destroy(cert); + } + } + child_cfg = child_cfg_create( + msg->add_conn.name, msg->add_conn.rekey.ipsec_lifetime, + msg->add_conn.rekey.ipsec_lifetime - msg->add_conn.rekey.margin, + msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100, + msg->add_conn.me.updown, msg->add_conn.me.hostaccess, + msg->add_conn.mode); + + peer_cfg->add_child_cfg(peer_cfg, child_cfg); + + child_cfg->add_traffic_selector(child_cfg, TRUE, my_ts); + child_cfg->add_traffic_selector(child_cfg, FALSE, other_ts); + + if (msg->add_conn.algorithms.esp) + { + char *proposal_string; + char *strict = msg->add_conn.algorithms.esp + strlen(msg->add_conn.algorithms.esp) - 1; + + if (*strict == '!') + *strict = '\0'; + else + strict = NULL; + + while ((proposal_string = strsep(&msg->add_conn.algorithms.esp, ","))) + { + proposal = proposal_create_from_string(PROTO_ESP, proposal_string); + if (proposal == NULL) + { + DBG1(DBG_CFG, "invalid ESP proposal string: %s", proposal_string); + peer_cfg->destroy(peer_cfg); + return; + } + child_cfg->add_proposal(child_cfg, proposal); + } + if (!strict) + { + proposal = proposal_create_default(PROTO_ESP); + child_cfg->add_proposal(child_cfg, proposal); + } + } + else + { + proposal = proposal_create_default(PROTO_ESP); + child_cfg->add_proposal(child_cfg, proposal); + } + + if (!use_existing) + { + /* add config to backend */ + this->configs.mutex->lock(this->configs.mutex); + this->configs.list->insert_last(this->configs.list, peer_cfg); + this->configs.mutex->unlock(this->configs.mutex); + DBG1(DBG_CFG, "added configuration '%s': %H[%D]...%H[%D]", + msg->add_conn.name, my_host, my_id, other_host, other_id); + } + return; + + /* mopping up after parsing errors */ + +destroy_ids: + my_id->destroy(my_id); + other_id->destroy(other_id); + DESTROY_IF(mediated_by_cfg); + DESTROY_IF(peer_id); + +destroy_hosts: + my_host->destroy(my_host); + other_host->destroy(other_host); +} + +/** + * Delete a connection from the list + */ +static void stroke_del_conn(private_stroke_t *this, stroke_msg_t *msg, FILE *out) +{ + enumerator_t *enumerator, *children; + peer_cfg_t *peer; + child_cfg_t *child; + + pop_string(msg, &(msg->del_conn.name)); + DBG1(DBG_CFG, "received stroke: delete connection '%s'", msg->del_conn.name); + + this->configs.mutex->lock(this->configs.mutex); + enumerator = this->configs.list->create_enumerator(this->configs.list); + while (enumerator->enumerate(enumerator, (void**)&peer)) + { + /* remove peer config with such a name */ + if (streq(peer->get_name(peer), msg->del_conn.name)) + { + this->configs.list->remove_at(this->configs.list, enumerator); + peer->destroy(peer); + continue; + } + /* remove any child with such a name */ + children = peer->create_child_cfg_enumerator(peer); + while (children->enumerate(children, &child)) + { + if (streq(child->get_name(child), msg->del_conn.name)) + { + peer->remove_child_cfg(peer, enumerator); + child->destroy(child); + } + } + children->destroy(children); + } + enumerator->destroy(enumerator); + this->configs.mutex->unlock(this->configs.mutex); + + fprintf(out, "deleted connection '%s'\n", msg->del_conn.name); +} + +/** + * get the child_cfg with the same name as the peer cfg + */ +static child_cfg_t* get_child_from_peer(peer_cfg_t *peer_cfg, char *name) +{ + child_cfg_t *current, *found = NULL; + enumerator_t *enumerator; + + enumerator = peer_cfg->create_child_cfg_enumerator(peer_cfg); + while (enumerator->enumerate(enumerator, ¤t)) + { + if (streq(current->get_name(current), name)) + { + found = current; + found->get_ref(found); + break; + } + } + enumerator->destroy(enumerator); + return found; +} + +/** + * logging to the stroke interface + */ +static bool stroke_log(stroke_log_info_t *info, signal_t signal, level_t level, + ike_sa_t *ike_sa, char *format, va_list args) +{ + if (level <= info->level) + { + if (vfprintf(info->out, format, args) < 0 || + fprintf(info->out, "\n") < 0 || + fflush(info->out) != 0) + { + return FALSE; + } + } + return TRUE; +} + +/** + * initiate a connection by name + */ +static void stroke_initiate(private_stroke_t *this, stroke_msg_t *msg, FILE *out) +{ + peer_cfg_t *peer_cfg; + child_cfg_t *child_cfg; + stroke_log_info_t info; + + pop_string(msg, &(msg->initiate.name)); + DBG1(DBG_CFG, "received stroke: initiate '%s'", msg->initiate.name); + + peer_cfg = charon->backends->get_peer_cfg_by_name(charon->backends, + msg->initiate.name); + if (peer_cfg == NULL) + { + fprintf(out, "no config named '%s'\n", msg->initiate.name); + return; + } + if (peer_cfg->get_ike_version(peer_cfg) != 2) + { + DBG1(DBG_CFG, "ignoring initiation request for IKEv%d config", + peer_cfg->get_ike_version(peer_cfg)); + peer_cfg->destroy(peer_cfg); + return; + } + + child_cfg = get_child_from_peer(peer_cfg, msg->initiate.name); + if (child_cfg == NULL) + { + fprintf(out, "no child config named '%s'\n", msg->initiate.name); + peer_cfg->destroy(peer_cfg); + return; + } + + if (msg->output_verbosity < 0) + { + charon->controller->initiate(charon->controller, peer_cfg, child_cfg, + NULL, NULL); + } + else + { + info.out = out; + info.level = msg->output_verbosity; + charon->controller->initiate(charon->controller, peer_cfg, child_cfg, + (controller_cb_t)stroke_log, &info); + } +} + +/** + * route a policy (install SPD entries) + */ +static void stroke_route(private_stroke_t *this, stroke_msg_t *msg, FILE *out) +{ + peer_cfg_t *peer_cfg; + child_cfg_t *child_cfg; + stroke_log_info_t info; + + pop_string(msg, &(msg->route.name)); + DBG1(DBG_CFG, "received stroke: route '%s'", msg->route.name); + + peer_cfg = charon->backends->get_peer_cfg_by_name(charon->backends, + msg->route.name); + if (peer_cfg == NULL) + { + fprintf(out, "no config named '%s'\n", msg->route.name); + return; + } + if (peer_cfg->get_ike_version(peer_cfg) != 2) + { + peer_cfg->destroy(peer_cfg); + return; + } + + child_cfg = get_child_from_peer(peer_cfg, msg->route.name); + if (child_cfg == NULL) + { + fprintf(out, "no child config named '%s'\n", msg->route.name); + peer_cfg->destroy(peer_cfg); + return; + } + + info.out = out; + info.level = msg->output_verbosity; + charon->controller->route(charon->controller, peer_cfg, child_cfg, + (controller_cb_t)stroke_log, &info); + peer_cfg->destroy(peer_cfg); + child_cfg->destroy(child_cfg); +} + +/** + * unroute a policy + */ +static void stroke_unroute(private_stroke_t *this, stroke_msg_t *msg, FILE *out) +{ + char *name; + ike_sa_t *ike_sa; + iterator_t *iterator; + stroke_log_info_t info; + + pop_string(msg, &(msg->terminate.name)); + name = msg->terminate.name; + + info.out = out; + info.level = msg->output_verbosity; + + iterator = charon->controller->create_ike_sa_iterator(charon->controller); + while (iterator->iterate(iterator, (void**)&ike_sa)) + { + child_sa_t *child_sa; + iterator_t *children; + u_int32_t id; + + children = ike_sa->create_child_sa_iterator(ike_sa); + while (children->iterate(children, (void**)&child_sa)) + { + if (child_sa->get_state(child_sa) == CHILD_ROUTED && + streq(name, child_sa->get_name(child_sa))) + { + id = child_sa->get_reqid(child_sa); + children->destroy(children); + iterator->destroy(iterator); + charon->controller->unroute(charon->controller, id, + (controller_cb_t)stroke_log, &info); + return; + } + } + children->destroy(children); + } + iterator->destroy(iterator); + DBG1(DBG_CFG, "no such SA found"); +} + +/** + * terminate a connection by name + */ +static void stroke_terminate(private_stroke_t *this, stroke_msg_t *msg, FILE *out) +{ + char *string, *pos = NULL, *name = NULL; + u_int32_t id = 0; + bool child; + int len; + ike_sa_t *ike_sa; + iterator_t *iterator; + stroke_log_info_t info; + + pop_string(msg, &(msg->terminate.name)); + string = msg->terminate.name; + DBG1(DBG_CFG, "received stroke: terminate '%s'", string); + + len = strlen(string); + if (len < 1) + { + DBG1(DBG_CFG, "error parsing string"); + return; + } + switch (string[len-1]) + { + case '}': + child = TRUE; + pos = strchr(string, '{'); + break; + case ']': + child = FALSE; + pos = strchr(string, '['); + break; + default: + name = string; + child = FALSE; + break; + } + + if (name) + { + /* is a single name */ + } + else if (pos == string + len - 2) + { /* is name[] or name{} */ + string[len-2] = '\0'; + name = string; + } + else + { /* is name[123] or name{23} */ + string[len-1] = '\0'; + id = atoi(pos + 1); + if (id == 0) + { + DBG1(DBG_CFG, "error parsing string"); + return; + } + } + + info.out = out; + info.level = msg->output_verbosity; + + iterator = charon->controller->create_ike_sa_iterator(charon->controller); + while (iterator->iterate(iterator, (void**)&ike_sa)) + { + child_sa_t *child_sa; + iterator_t *children; + + if (child) + { + children = ike_sa->create_child_sa_iterator(ike_sa); + while (children->iterate(children, (void**)&child_sa)) + { + if ((name && streq(name, child_sa->get_name(child_sa))) || + (id && id == child_sa->get_reqid(child_sa))) + { + id = child_sa->get_reqid(child_sa); + children->destroy(children); + iterator->destroy(iterator); + + charon->controller->terminate_child(charon->controller, id, + (controller_cb_t)stroke_log, &info); + return; + } + } + children->destroy(children); + } + else if ((name && streq(name, ike_sa->get_name(ike_sa))) || + (id && id == ike_sa->get_unique_id(ike_sa))) + { + id = ike_sa->get_unique_id(ike_sa); + /* unlock manager first */ + iterator->destroy(iterator); + + charon->controller->terminate_ike(charon->controller, id, + (controller_cb_t)stroke_log, &info); + return; + } + + } + iterator->destroy(iterator); + DBG1(DBG_CFG, "no such SA found"); +} + +/** + * Add a ca information record to the cainfo list + */ +static void stroke_add_ca(private_stroke_t *this, + stroke_msg_t *msg, FILE *out) +{ + certificate_t *cert; + ca_section_t *ca; + + pop_string(msg, &msg->add_ca.name); + pop_string(msg, &msg->add_ca.cacert); + pop_string(msg, &msg->add_ca.crluri); + pop_string(msg, &msg->add_ca.crluri2); + pop_string(msg, &msg->add_ca.ocspuri); + pop_string(msg, &msg->add_ca.ocspuri2); + + DBG1(DBG_CFG, "received stroke: add ca '%s'", msg->add_ca.name); + + DBG2(DBG_CFG, "ca %s", msg->add_ca.name); + DBG2(DBG_CFG, " cacert=%s", msg->add_ca.cacert); + DBG2(DBG_CFG, " crluri=%s", msg->add_ca.crluri); + DBG2(DBG_CFG, " crluri2=%s", msg->add_ca.crluri2); + DBG2(DBG_CFG, " ocspuri=%s", msg->add_ca.ocspuri); + DBG2(DBG_CFG, " ocspuri2=%s", msg->add_ca.ocspuri2); + + if (msg->add_ca.cacert == NULL) + { + DBG1(DBG_CFG, "missing cacert parameter"); + return; + } + + cert = load_ca_cert(this, msg->add_ca.cacert); + if (cert) + { + ca = ca_section_create(msg->add_ca.name, cert); + if (msg->add_ca.crluri) + { + ca->crl->insert_last(ca->crl, strdup(msg->add_ca.crluri)); + } + if (msg->add_ca.crluri2) + { + ca->crl->insert_last(ca->crl, strdup(msg->add_ca.crluri2)); + } + if (msg->add_ca.ocspuri) + { + ca->ocsp->insert_last(ca->ocsp, strdup(msg->add_ca.ocspuri)); + } + if (msg->add_ca.ocspuri2) + { + ca->ocsp->insert_last(ca->ocsp, strdup(msg->add_ca.ocspuri2)); + } + this->ca_creds.mutex->lock(this->ca_creds.mutex); + this->ca_creds.sections->insert_last(this->ca_creds.sections, ca); + this->ca_creds.mutex->unlock(this->ca_creds.mutex); + DBG1(DBG_CFG, "added ca '%s'", msg->add_ca.name); + } +} + +/** + * Delete a ca information record from the cainfo list + */ +static void stroke_del_ca(private_stroke_t *this, + stroke_msg_t *msg, FILE *out) +{ + enumerator_t *enumerator; + ca_section_t *ca = NULL; + + pop_string(msg, &(msg->del_ca.name)); + DBG1(DBG_CFG, "received stroke: delete ca '%s'", msg->del_ca.name); + + this->ca_creds.mutex->lock(this->ca_creds.mutex); + enumerator = this->ca_creds.sections->create_enumerator(this->ca_creds.sections); + while (enumerator->enumerate(enumerator, &ca)) + { + if (streq(ca->name, msg->del_ca.name)) + { + this->ca_creds.sections->remove_at(this->ca_creds.sections, enumerator); + break; + } + ca = NULL; + } + enumerator->destroy(enumerator); + this->ca_creds.mutex->unlock(this->ca_creds.mutex); + if (ca == NULL) + { + fprintf(out, "no ca named '%s' found\n", msg->del_ca.name); + return; + } + ca_section_destroy(ca); + /* TODO: flush cached certs */ +} + +/** + * log an IKE_SA to out + */ +static void log_ike_sa(FILE *out, ike_sa_t *ike_sa, bool all) +{ + ike_sa_id_t *id = ike_sa->get_id(ike_sa); + u_int32_t rekey, reauth; + + fprintf(out, "%12s[%d]: %N, %H[%D]...%H[%D]\n", + ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa), + ike_sa_state_names, ike_sa->get_state(ike_sa), + ike_sa->get_my_host(ike_sa), ike_sa->get_my_id(ike_sa), + ike_sa->get_other_host(ike_sa), ike_sa->get_other_id(ike_sa)); + + if (all) + { + fprintf(out, "%12s[%d]: IKE SPIs: %.16llx_i%s %.16llx_r%s", + ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa), + id->get_initiator_spi(id), id->is_initiator(id) ? "*" : "", + id->get_responder_spi(id), id->is_initiator(id) ? "" : "*"); + + rekey = ike_sa->get_statistic(ike_sa, STAT_REKEY_TIME); + reauth = ike_sa->get_statistic(ike_sa, STAT_REAUTH_TIME); + if (rekey) + { + fprintf(out, ", rekeying in %V", &rekey); + } + if (reauth) + { + fprintf(out, ", reauthentication in %V", &reauth); + } + if (!rekey && !reauth) + { + fprintf(out, ", rekeying disabled"); + } + fprintf(out, "\n"); + } +} + +/** + * log an CHILD_SA to out + */ +static void log_child_sa(FILE *out, child_sa_t *child_sa, bool all) +{ + u_int32_t rekey, now = time(NULL); + u_int32_t use_in, use_out, use_fwd; + encryption_algorithm_t encr_alg; + integrity_algorithm_t int_alg; + size_t encr_len, int_len; + mode_t mode; + + child_sa->get_stats(child_sa, &mode, &encr_alg, &encr_len, + &int_alg, &int_len, &rekey, &use_in, &use_out, + &use_fwd); + + fprintf(out, "%12s{%d}: %N, %N", + child_sa->get_name(child_sa), child_sa->get_reqid(child_sa), + child_sa_state_names, child_sa->get_state(child_sa), + mode_names, mode); + + if (child_sa->get_state(child_sa) == CHILD_INSTALLED) + { + fprintf(out, ", %N SPIs: %.8x_i %.8x_o", + protocol_id_names, child_sa->get_protocol(child_sa), + htonl(child_sa->get_spi(child_sa, TRUE)), + htonl(child_sa->get_spi(child_sa, FALSE))); + + if (all) + { + fprintf(out, "\n%12s{%d}: ", child_sa->get_name(child_sa), + child_sa->get_reqid(child_sa)); + + + if (child_sa->get_protocol(child_sa) == PROTO_ESP) + { + fprintf(out, "%N", encryption_algorithm_names, encr_alg); + + if (encr_len) + { + fprintf(out, "-%d", encr_len); + } + fprintf(out, "/"); + } + + fprintf(out, "%N", integrity_algorithm_names, int_alg); + if (int_len) + { + fprintf(out, "-%d", int_len); + } + fprintf(out, ", rekeying "); + + if (rekey) + { + fprintf(out, "in %#V", &now, &rekey); + } + else + { + fprintf(out, "disabled"); + } + + fprintf(out, ", last use: "); + use_in = max(use_in, use_fwd); + if (use_in) + { + fprintf(out, "%ds_i ", now - use_in); + } + else + { + fprintf(out, "no_i "); + } + if (use_out) + { + fprintf(out, "%ds_o ", now - use_out); + } + else + { + fprintf(out, "no_o "); + } + } + } + + fprintf(out, "\n%12s{%d}: %#R=== %#R\n", + child_sa->get_name(child_sa), child_sa->get_reqid(child_sa), + child_sa->get_traffic_selectors(child_sa, TRUE), + child_sa->get_traffic_selectors(child_sa, FALSE)); +} + +/** + * show status of daemon + */ +static void stroke_status(private_stroke_t *this, stroke_msg_t *msg, FILE *out, + bool all) +{ + enumerator_t *enumerator, *children; + iterator_t *iterator; + host_t *host; + peer_cfg_t *peer_cfg; + ike_cfg_t *ike_cfg; + child_cfg_t *child_cfg; + ike_sa_t *ike_sa; + char *name = NULL; + + if (msg->status.name) + { + pop_string(msg, &(msg->status.name)); + name = msg->status.name; + } + + if (all) + { + fprintf(out, "Performance:\n"); + fprintf(out, " worker threads: %d idle of %d,", + charon->processor->get_idle_threads(charon->processor), + charon->processor->get_total_threads(charon->processor)); + fprintf(out, " job queue load: %d,", + charon->processor->get_job_load(charon->processor)); + fprintf(out, " scheduled events: %d\n", + charon->scheduler->get_job_load(charon->scheduler)); + iterator = charon->kernel_interface->create_address_iterator( + charon->kernel_interface); + fprintf(out, "Listening IP addresses:\n"); + while (iterator->iterate(iterator, (void**)&host)) + { + fprintf(out, " %H\n", host); + } + iterator->destroy(iterator); + + fprintf(out, "Connections:\n"); + enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends); + while (enumerator->enumerate(enumerator, (void**)&peer_cfg)) + { + if (peer_cfg->get_ike_version(peer_cfg) != 2 || + (name && !streq(name, peer_cfg->get_name(peer_cfg)))) + { + continue; + } + + ike_cfg = peer_cfg->get_ike_cfg(peer_cfg); + fprintf(out, "%12s: %H[%D]...%H[%D]\n", peer_cfg->get_name(peer_cfg), + ike_cfg->get_my_host(ike_cfg), peer_cfg->get_my_id(peer_cfg), + ike_cfg->get_other_host(ike_cfg), peer_cfg->get_other_id(peer_cfg)); + /* TODO: list CAs and groups */ + children = peer_cfg->create_child_cfg_enumerator(peer_cfg); + while (children->enumerate(children, &child_cfg)) + { + linked_list_t *my_ts, *other_ts; + my_ts = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, NULL); + other_ts = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL, NULL); + fprintf(out, "%12s: %#R=== %#R\n", child_cfg->get_name(child_cfg), + my_ts, other_ts); + my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy)); + other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy)); + } + children->destroy(children); + } + enumerator->destroy(enumerator); + } + + iterator = charon->ike_sa_manager->create_iterator(charon->ike_sa_manager); + if (all && iterator->get_count(iterator) > 0) + { + fprintf(out, "Security Associations:\n"); + } + while (iterator->iterate(iterator, (void**)&ike_sa)) + { + bool ike_printed = FALSE; + child_sa_t *child_sa; + iterator_t *children = ike_sa->create_child_sa_iterator(ike_sa); + + if (name == NULL || streq(name, ike_sa->get_name(ike_sa))) + { + log_ike_sa(out, ike_sa, all); + ike_printed = TRUE; + } + + while (children->iterate(children, (void**)&child_sa)) + { + if (name == NULL || streq(name, child_sa->get_name(child_sa))) + { + if (!ike_printed) + { + log_ike_sa(out, ike_sa, all); + ike_printed = TRUE; + } + log_child_sa(out, child_sa, all); + } + } + children->destroy(children); + } + iterator->destroy(iterator); +} + +/** + * list all X.509 certificates matching the flags + */ +static void stroke_list_certs(char *label, x509_flag_t flags, bool utc, FILE *out) +{ + bool first = TRUE; + time_t now = time(NULL); + certificate_t *cert; + enumerator_t *enumerator; + + enumerator = charon->credentials->create_cert_enumerator( + charon->credentials, CERT_X509, KEY_ANY, NULL, FALSE); + while (enumerator->enumerate(enumerator, (void**)&cert)) + { + x509_t *x509 = (x509_t*)cert; + x509_flag_t x509_flags = x509->get_flags(x509); + + if (x509_flags & flags) + { + enumerator_t *enumerator; + identification_t *altName; + bool first_altName = TRUE; + chunk_t serial = x509->get_serial(x509); + identification_t *authkey = x509->get_authKeyIdentifier(x509); + time_t notBefore, notAfter; + public_key_t *public = cert->get_public_key(cert); + + if (first) + { + fprintf(out, "\n"); + fprintf(out, "List of %s:\n", label); + first = FALSE; + } + fprintf(out, "\n"); + + /* list subjectAltNames */ + enumerator = x509->create_subjectAltName_enumerator(x509); + while (enumerator->enumerate(enumerator, (void**)&altName)) + { + if (first_altName) + { + fprintf(out, " altNames: "); + first_altName = FALSE; + } + else + { + fprintf(out, ", "); + } + fprintf(out, "%D", altName); + } + if (!first_altName) + { + fprintf(out, "\n"); + } + enumerator->destroy(enumerator); + + fprintf(out, " subject: %D\n", cert->get_subject(cert)); + fprintf(out, " issuer: %D\n", cert->get_issuer(cert)); + fprintf(out, " serial: %#B\n", &serial); + + /* list validity */ + cert->get_validity(cert, &now, ¬Before, ¬After); + fprintf(out, " validity: not before %#T, ", ¬Before, utc); + if (now < notBefore) + { + fprintf(out, "not valid yet (valid in %#V)\n", &now, ¬Before); + } + else + { + fprintf(out, "ok\n"); + } + fprintf(out, " not after %#T, ", ¬After, utc); + if (now > notAfter) + { + fprintf(out, "expired (%#V ago)\n", &now, ¬After); + } + else + { + fprintf(out, "ok"); + if (now > notAfter - CERT_WARNING_INTERVAL * 60 * 60 * 24) + { + fprintf(out, " (expires in %#V)", &now, ¬After); + } + fprintf(out, " \n"); + } + + /* list public key information */ + if (public) + { + private_key_t *private = NULL; + identification_t *id, *keyid; + + id = public->get_id(public, ID_PUBKEY_SHA1); + keyid = public->get_id(public, ID_PUBKEY_INFO_SHA1); + + if (flags & X509_PEER) + { + private = charon->credentials->get_private( + charon->credentials, + public->get_type(public), id, NULL); + } + fprintf(out, " pubkey: %N %d bits%s\n", + key_type_names, public->get_type(public), + public->get_keysize(public) * 8, + private ? ", has private key" : ""); + fprintf(out, " keyid: %D\n", keyid); + fprintf(out, " subjkey: %D\n", id); + DESTROY_IF(private); + public->destroy(public); + } + + /* list optional authorityKeyIdentifier */ + if (authkey) + { + fprintf(out, " authkey: %D\n", authkey); + } + } + } + enumerator->destroy(enumerator); +} + +/** + * list all X.509 CRLs + */ +static void stroke_list_crls(bool utc, FILE *out) +{ + bool first = TRUE; + time_t thisUpdate, nextUpdate, now = time(NULL); + certificate_t *cert; + enumerator_t *enumerator; + + enumerator = charon->credentials->create_cert_enumerator( + charon->credentials, CERT_X509_CRL, KEY_ANY, NULL, FALSE); + while (enumerator->enumerate(enumerator, (void**)&cert)) + { + crl_t *crl = (crl_t*)cert; + chunk_t serial = crl->get_serial(crl); + identification_t *authkey = crl->get_authKeyIdentifier(crl); + + if (first) + { + fprintf(out, "\n"); + fprintf(out, "List of X.509 CRLs:\n"); + first = FALSE; + } + fprintf(out, "\n"); + + fprintf(out, " issuer: %D\n", cert->get_issuer(cert)); + + /* list optional crlNumber */ + if (serial.ptr) + { + fprintf(out, " serial: %#B\n", &serial); + } + + /* count the number of revoked certificates */ + { + int count = 0; + enumerator_t *enumerator = crl->create_enumerator(crl); + + while (enumerator->enumerate(enumerator, NULL, NULL, NULL)) + { + count++; + } + fprintf(out, " revoked: %d certificate%s\n", count, + (count == 1)? "" : "s"); + enumerator->destroy(enumerator); + } + + /* list validity */ + cert->get_validity(cert, &now, &thisUpdate, &nextUpdate); + fprintf(out, " updates: this %#T\n", &thisUpdate, utc); + fprintf(out, " next %#T, ", &nextUpdate, utc); + if (now > nextUpdate) + { + fprintf(out, "expired (%#V ago)\n", &now, &nextUpdate); + } + else + { + fprintf(out, "ok"); + if (now > nextUpdate - CRL_WARNING_INTERVAL * 60 * 60 * 24) + { + fprintf(out, " (expires in %#V)", &now, &nextUpdate); + } + fprintf(out, " \n"); + } + + /* list optional authorityKeyIdentifier */ + if (authkey) + { + fprintf(out, " authkey: %D\n", authkey); + } + } + enumerator->destroy(enumerator); +} + +/** + * list all CA information sections + */ +static void stroke_list_cainfos(private_stroke_t *this, FILE *out) +{ + bool first = TRUE; + ca_section_t *section; + enumerator_t *enumerator; + + this->ca_creds.mutex->lock(this->ca_creds.mutex); + enumerator = this->ca_creds.sections->create_enumerator(this->ca_creds.sections); + while (enumerator->enumerate(enumerator, (void**)§ion)) + { + certificate_t *cert = section->cert; + public_key_t *public = cert->get_public_key(cert); + + if (first) + { + fprintf(out, "\n"); + fprintf(out, "List of CA Information Sections:\n"); + first = FALSE; + } + fprintf(out, "\n"); + fprintf(out, " authname: %D\n", cert->get_subject(cert)); + + /* list authkey and keyid */ + if (public) + { + fprintf(out, " authkey: %D\n", + public->get_id(public, ID_PUBKEY_SHA1)); + fprintf(out, " keyid: %D\n", + public->get_id(public, ID_PUBKEY_INFO_SHA1)); + public->destroy(public); + } + + /* list CRL URIs */ + { + bool first = TRUE; + char *crluri; + enumerator_t *enumerator; + + enumerator = section->crl->create_enumerator(section->crl); + while (enumerator->enumerate(enumerator, (void**)&crluri)) + { + if (first) + { + fprintf(out, " crluris: "); + first = FALSE; + } + else + { + fprintf(out, " "); + } + fprintf(out, "'%s'\n", crluri); + } + enumerator->destroy(enumerator); + } + + /* list OCSP URIs */ + { + bool first = TRUE; + char *ocspuri; + enumerator_t *enumerator; + + enumerator = section->ocsp->create_enumerator(section->ocsp); + while (enumerator->enumerate(enumerator, (void**)&ocspuri)) + { + if (first) + { + fprintf(out, " ocspuris: "); + first = FALSE; + } + else + { + fprintf(out, " "); + } + fprintf(out, "'%s'\n", ocspuri); + } + enumerator->destroy(enumerator); + } + } + enumerator->destroy(enumerator); + this->ca_creds.mutex->unlock(this->ca_creds.mutex); +} + +/** + * list various information + */ +static void stroke_list(private_stroke_t *this, stroke_msg_t *msg, FILE *out) +{ + if (msg->list.flags & LIST_CERTS) + { + stroke_list_certs("X.509 End Entity Certificates", + X509_PEER, msg->list.utc, out); + } + if (msg->list.flags & LIST_CACERTS) + { + stroke_list_certs("X.509 CA Certificates", + X509_CA, msg->list.utc, out); + } + if (msg->list.flags & LIST_OCSPCERTS) + { + stroke_list_certs("X.509 OCSP Signer Certificates", + X509_OCSP_SIGNER, msg->list.utc, out); + } + if (msg->list.flags & LIST_AACERTS) + { + stroke_list_certs("X.509 AA Certificates", + X509_AA, msg->list.utc, out); + } + if (msg->list.flags & LIST_ACERTS) + { + + } + if (msg->list.flags & LIST_CAINFOS) + { + stroke_list_cainfos(this, out); + } + if (msg->list.flags & LIST_CRLS) + { + stroke_list_crls(msg->list.utc, out); + } + if (msg->list.flags & LIST_OCSP) + { + + } +} + +/** + * reread various information + */ +static void stroke_reread(private_stroke_t *this, + stroke_msg_t *msg, FILE *out) +{ + if (msg->reread.flags & REREAD_SECRETS) + { + DBG1(DBG_CFG, "rereading secrets"); + load_secrets(this); + } + if (msg->reread.flags & REREAD_CACERTS) + { + DBG1(DBG_CFG, "rereading CA certificates from '%s'", + CA_CERTIFICATE_DIR); + load_certdir(this, CA_CERTIFICATE_DIR, CERT_X509, X509_CA); + } + if (msg->reread.flags & REREAD_OCSPCERTS) + { + DBG1(DBG_CFG, "rereading OCSP signer certificates from '%s'", + OCSP_CERTIFICATE_DIR); + load_certdir(this, OCSP_CERTIFICATE_DIR, CERT_X509, + X509_OCSP_SIGNER); + } + if (msg->reread.flags & REREAD_AACERTS) + { + DBG1(DBG_CFG, "rereading AA certificates from '%s'", + AA_CERTIFICATE_DIR); + load_certdir(this, AA_CERTIFICATE_DIR, CERT_X509, X509_AA); + } + if (msg->reread.flags & REREAD_ACERTS) + { + DBG1(DBG_CFG, "rereading attribute certificates from '%s'", + ATTR_CERTIFICATE_DIR); + load_certdir(this, ATTR_CERTIFICATE_DIR, CERT_X509_AC, 0); + } + if (msg->reread.flags & REREAD_CRLS) + { + DBG1(DBG_CFG, "rereading CRLs from '%s'", + CRL_DIR); + load_certdir(this, CRL_DIR, CERT_X509_CRL, 0); + } +} + +/** + * purge various information + */ +static void stroke_purge(private_stroke_t *this, stroke_msg_t *msg, FILE *out) +{ + /* TODO: flush cache */ +} + +signal_t get_signal_from_logtype(char *type) +{ + if (strcasecmp(type, "any") == 0) return SIG_ANY; + else if (strcasecmp(type, "mgr") == 0) return DBG_MGR; + else if (strcasecmp(type, "ike") == 0) return DBG_IKE; + else if (strcasecmp(type, "chd") == 0) return DBG_CHD; + else if (strcasecmp(type, "job") == 0) return DBG_JOB; + else if (strcasecmp(type, "cfg") == 0) return DBG_CFG; + else if (strcasecmp(type, "knl") == 0) return DBG_KNL; + else if (strcasecmp(type, "net") == 0) return DBG_NET; + else if (strcasecmp(type, "enc") == 0) return DBG_ENC; + else if (strcasecmp(type, "lib") == 0) return DBG_LIB; + else return -1; +} + +/** + * set the verbosity debug output + */ +static void stroke_loglevel(private_stroke_t *this, stroke_msg_t *msg, FILE *out) +{ + signal_t signal; + + pop_string(msg, &(msg->loglevel.type)); + DBG1(DBG_CFG, "received stroke: loglevel %d for %s", + msg->loglevel.level, msg->loglevel.type); + + signal = get_signal_from_logtype(msg->loglevel.type); + if (signal < 0) + { + fprintf(out, "invalid type (%s)!\n", msg->loglevel.type); + return; + } + + charon->outlog->set_level(charon->outlog, signal, msg->loglevel.level); + charon->syslog->set_level(charon->syslog, signal, msg->loglevel.level); +} + +typedef struct stroke_job_context_t stroke_job_context_t; + +/** job context to pass to processing thread */ +struct stroke_job_context_t { + + /** file descriptor to read from */ + int fd; + + /** global stroke interface */ + private_stroke_t *this; +}; + +/** + * destroy a job context + */ +static void stroke_job_context_destroy(stroke_job_context_t *this) +{ + close(this->fd); + free(this); +} + +/** + * process a stroke request from the socket pointed by "fd" + */ +static job_requeue_t stroke_process(stroke_job_context_t *ctx) +{ + stroke_msg_t *msg; + u_int16_t msg_length; + ssize_t bytes_read; + FILE *out; + private_stroke_t *this = ctx->this; + int strokefd = ctx->fd; + + /* peek the length */ + bytes_read = recv(strokefd, &msg_length, sizeof(msg_length), MSG_PEEK); + if (bytes_read != sizeof(msg_length)) + { + DBG1(DBG_CFG, "reading length of stroke message failed: %s", + strerror(errno)); + close(strokefd); + return JOB_REQUEUE_NONE; + } + + /* read message */ + msg = malloc(msg_length); + bytes_read = recv(strokefd, msg, msg_length, 0); + if (bytes_read != msg_length) + { + DBG1(DBG_CFG, "reading stroke message failed: %s", strerror(errno)); + close(strokefd); + return JOB_REQUEUE_NONE; + } + + out = fdopen(strokefd, "w"); + if (out == NULL) + { + DBG1(DBG_CFG, "opening stroke output channel failed: %s", strerror(errno)); + close(strokefd); + free(msg); + return JOB_REQUEUE_NONE; + } + + DBG3(DBG_CFG, "stroke message %b", (void*)msg, msg_length); + + /* the stroke_* functions are blocking, as they listen on the bus. Add + * cancellation handlers. */ + pthread_cleanup_push((void*)fclose, out); + pthread_cleanup_push(free, msg); + + switch (msg->type) + { + case STR_INITIATE: + stroke_initiate(this, msg, out); + break; + case STR_ROUTE: + stroke_route(this, msg, out); + break; + case STR_UNROUTE: + stroke_unroute(this, msg, out); + break; + case STR_TERMINATE: + stroke_terminate(this, msg, out); + break; + case STR_STATUS: + stroke_status(this, msg, out, FALSE); + break; + case STR_STATUS_ALL: + stroke_status(this, msg, out, TRUE); + break; + case STR_ADD_CONN: + stroke_add_conn(this, msg, out); + break; + case STR_DEL_CONN: + stroke_del_conn(this, msg, out); + break; + case STR_ADD_CA: + stroke_add_ca(this, msg, out); + break; + case STR_DEL_CA: + stroke_del_ca(this, msg, out); + break; + case STR_LOGLEVEL: + stroke_loglevel(this, msg, out); + break; + case STR_LIST: + stroke_list(this, msg, out); + break; + case STR_REREAD: + stroke_reread(this, msg, out); + break; + case STR_PURGE: + stroke_purge(this, msg, out); + break; + default: + DBG1(DBG_CFG, "received unknown stroke"); + } + /* remove and execute cancellation handlers */ + pthread_cleanup_pop(1); + pthread_cleanup_pop(1); + + return JOB_REQUEUE_NONE; +} + +/** + * Implementation of private_stroke_t.stroke_receive. + */ +static job_requeue_t stroke_receive(private_stroke_t *this) +{ + struct sockaddr_un strokeaddr; + int strokeaddrlen = sizeof(strokeaddr); + int strokefd; + int oldstate; + callback_job_t *job; + stroke_job_context_t *ctx; + + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); + strokefd = accept(this->socket, (struct sockaddr *)&strokeaddr, &strokeaddrlen); + pthread_setcancelstate(oldstate, NULL); + + if (strokefd < 0) + { + DBG1(DBG_CFG, "accepting stroke connection failed: %s", strerror(errno)); + return JOB_REQUEUE_FAIR; + } + + ctx = malloc_thing(stroke_job_context_t); + ctx->fd = strokefd; + ctx->this = this; + job = callback_job_create((callback_job_cb_t)stroke_process, + ctx, (void*)stroke_job_context_destroy, this->job); + charon->processor->queue_job(charon->processor, (job_t*)job); + + return JOB_REQUEUE_FAIR; +} + +/** + * Implementation of interface_t.destroy. + */ +static void destroy(private_stroke_t *this) +{ + this->job->cancel(this->job); + charon->credentials->remove_set(charon->credentials, &this->ca_creds.set); + charon->credentials->remove_set(charon->credentials, &this->creds.set); + charon->backends->remove_backend(charon->backends, &this->configs.backend); + this->ca_creds.sections->destroy_function(this->ca_creds.sections, (void*)ca_section_destroy); + this->ca_creds.mutex->destroy(this->ca_creds.mutex); + this->creds.certs->destroy_offset(this->creds.certs, offsetof(certificate_t, destroy)); + this->creds.shared->destroy_offset(this->creds.shared, offsetof(shared_key_t, destroy)); + this->creds.private->destroy_offset(this->creds.private, offsetof(private_key_t, destroy)); + this->creds.mutex->destroy(this->creds.mutex); + this->configs.list->destroy_offset(this->configs.list, offsetof(peer_cfg_t, destroy)); + this->configs.mutex->destroy(this->configs.mutex); + free(this); +} + +/** + * initialize and open stroke socket + */ +static bool open_socket(private_stroke_t *this) +{ + struct sockaddr_un socket_addr = { AF_UNIX, STROKE_SOCKET}; + mode_t old; + + /* set up unix socket */ + this->socket = socket(AF_UNIX, SOCK_STREAM, 0); + if (this->socket == -1) + { + DBG1(DBG_CFG, "could not create stroke socket"); + return FALSE; + } + + unlink(socket_addr.sun_path); + old = umask(~(S_IRWXU | S_IRWXG)); + if (bind(this->socket, (struct sockaddr *)&socket_addr, sizeof(socket_addr)) < 0) + { + DBG1(DBG_CFG, "could not bind stroke socket: %s", strerror(errno)); + close(this->socket); + return FALSE; + } + umask(old); + if (chown(socket_addr.sun_path, IPSEC_UID, IPSEC_GID) != 0) + { + DBG1(DBG_CFG, "changing stroke socket permissions failed: %s", + strerror(errno)); + } + + if (listen(this->socket, 0) < 0) + { + DBG1(DBG_CFG, "could not listen on stroke socket: %s", strerror(errno)); + close(this->socket); + unlink(socket_addr.sun_path); + return FALSE; + } + return TRUE; +} + +/** + * load all certificates from ipsec.d + */ +static void load_certs(private_stroke_t *this) +{ + DBG1(DBG_CFG, "loading CA certificates from '%s'", + CA_CERTIFICATE_DIR); + load_certdir(this, CA_CERTIFICATE_DIR, CERT_X509, X509_CA); + + DBG1(DBG_CFG, "loading AA certificates from '%s'", + AA_CERTIFICATE_DIR); + load_certdir(this, AA_CERTIFICATE_DIR, CERT_X509, X509_AA); + + DBG1(DBG_CFG, "loading OCSP signer certificates from '%s'", + OCSP_CERTIFICATE_DIR); + load_certdir(this, OCSP_CERTIFICATE_DIR, CERT_X509, X509_OCSP_SIGNER); + + DBG1(DBG_CFG, "loading attribute certificates from '%s'", + ATTR_CERTIFICATE_DIR); + load_certdir(this, ATTR_CERTIFICATE_DIR, CERT_X509_AC, 0); + + DBG1(DBG_CFG, "loading CRLs from '%s'", + CRL_DIR); + load_certdir(this, CRL_DIR, CERT_X509_CRL, 0); +} + +/* + * Described in header-file + */ +plugin_t *plugin_create() +{ + private_stroke_t *this = malloc_thing(private_stroke_t); + + /* public functions */ + this->public.plugin.destroy = (void (*)(plugin_t*))destroy; + + if (!open_socket(this)) + { + free(this); + return NULL; + } + + this->ca_creds.sections = linked_list_create(); + this->ca_creds.mutex = mutex_create(MUTEX_RECURSIVE); + this->creds.certs = linked_list_create(); + this->creds.shared = linked_list_create(); + this->creds.private = linked_list_create(); + this->creds.mutex = mutex_create(MUTEX_RECURSIVE); + this->configs.list = linked_list_create(); + this->configs.mutex = mutex_create(MUTEX_RECURSIVE); + + this->ca_creds.set.create_private_enumerator = (void*)return_null; + this->ca_creds.set.create_cert_enumerator = (void*)return_null; + this->ca_creds.set.create_shared_enumerator = (void*)return_null; + this->ca_creds.set.create_cdp_enumerator = (void*)create_cdp_enumerator; + charon->credentials->add_set(charon->credentials, &this->ca_creds.set); + + this->creds.set.create_private_enumerator = (void*)create_private_enumerator; + this->creds.set.create_cert_enumerator = (void*)create_cert_enumerator; + this->creds.set.create_shared_enumerator = (void*)create_shared_enumerator; + this->creds.set.create_cdp_enumerator = (void*)return_null; + charon->credentials->add_set(charon->credentials, &this->creds.set); + + load_certs(this); + load_secrets(this); + + this->configs.backend.create_peer_cfg_enumerator = (enumerator_t*(*)(backend_t*, identification_t *me, identification_t *other))create_peer_cfg_enumerator; + this->configs.backend.create_ike_cfg_enumerator = (enumerator_t*(*)(backend_t*, host_t *me, host_t *other))create_ike_cfg_enumerator; + this->configs.backend.get_peer_cfg_by_name = (peer_cfg_t* (*)(backend_t*,char*))get_peer_cfg_by_name; + charon->backends->add_backend(charon->backends, &this->configs.backend); + + this->job = callback_job_create((callback_job_cb_t)stroke_receive, + this, NULL, NULL); + charon->processor->queue_job(charon->processor, (job_t*)this->job); + + return &this->public.plugin; +} + diff --git a/src/charon/plugins/stroke/stroke.h b/src/charon/plugins/stroke/stroke.h new file mode 100644 index 000000000..b61f4109d --- /dev/null +++ b/src/charon/plugins/stroke/stroke.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2006-2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +/** + * @defgroup stroke stroke + * @ingroup cplugins + * + * @defgroup stroke_i stroke + * @{ @ingroup stroke + */ + +#ifndef STROKE_H_ +#define STROKE_H_ + +#include + +typedef struct stroke_t stroke_t; + +/** + * strongSwan 2.x style configuration and control interface. + * + * Stroke is a home-brewed communication interface inspired by whack. It + * uses a unix socket (/var/run/charon.ctl). + */ +struct stroke_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +/** + * Instanciate stroke plugin. + */ +plugin_t *plugin_create(); + +#endif /* STROKE_H_ @}*/ diff --git a/src/charon/plugins/unit_tester/Makefile.am b/src/charon/plugins/unit_tester/Makefile.am new file mode 100644 index 000000000..fb5244314 --- /dev/null +++ b/src/charon/plugins/unit_tester/Makefile.am @@ -0,0 +1,17 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon + +AM_CFLAGS = -rdynamic + +plugin_LTLIBRARIES = libcharon-unit-tester.la + +libcharon_unit_tester_la_SOURCES = unit_tester.c unit_tester.h \ + tests/test_enumerator.c \ + tests/test_auth_info.c \ + tests/test_fips_prf.c \ + tests/test_curl.c \ + tests/test_mysql.c \ + tests/test_sqlite.c \ + tests/test_mutex.c +libcharon_unit_tester_la_LDFLAGS = -module + diff --git a/src/charon/plugins/unit_tester/tests.h b/src/charon/plugins/unit_tester/tests.h new file mode 100644 index 000000000..5def0b0a5 --- /dev/null +++ b/src/charon/plugins/unit_tester/tests.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +/** + * @defgroup tests tests + * @{ @ingroup unit_tester + */ + +DEFINE_TEST("linked_list_t->remove()", test_list_remove, FALSE) +DEFINE_TEST("simple enumerator", test_enumerate, FALSE) +DEFINE_TEST("nested enumerator", test_enumerate_nested, FALSE) +DEFINE_TEST("filtered enumerator", test_enumerate_filtered, FALSE) +DEFINE_TEST("auth info", test_auth_info, FALSE) +DEFINE_TEST("FIPS PRF", fips_prf_test, FALSE) +DEFINE_TEST("CURL get", test_curl_get, FALSE) +DEFINE_TEST("MySQL operations", test_mysql, FALSE) +DEFINE_TEST("SQLite operations", test_sqlite, FALSE) +DEFINE_TEST("mutex primitive", test_mutex, TRUE) + diff --git a/src/charon/plugins/unit_tester/tests/test_auth_info.c b/src/charon/plugins/unit_tester/tests/test_auth_info.c new file mode 100644 index 000000000..2640c951c --- /dev/null +++ b/src/charon/plugins/unit_tester/tests/test_auth_info.c @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 +#include +#include + + +char buf[] = {0x01,0x02,0x03,0x04}; +chunk_t chunk = chunk_from_buf(buf); +char certbuf[] = { + 0x30,0x82,0x02,0xfa,0x30,0x82,0x01,0xe2,0xa0,0x03,0x02,0x01,0x02,0x02,0x10,0x5a, + 0xf2,0x65,0xae,0x78,0xff,0x23,0xde,0xf7,0xa6,0xa3,0x94,0x8c,0x3f,0xa0,0xc1,0x30, + 0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x30,0x39, + 0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x43,0x48,0x31,0x19,0x30, + 0x17,0x06,0x03,0x55,0x04,0x0a,0x13,0x10,0x4c,0x69,0x6e,0x75,0x78,0x20,0x73,0x74, + 0x72,0x6f,0x6e,0x67,0x53,0x77,0x61,0x6e,0x31,0x0f,0x30,0x0d,0x06,0x03,0x55,0x04, + 0x03,0x13,0x06,0x6d,0x61,0x72,0x74,0x69,0x6e,0x30,0x1e,0x17,0x0d,0x30,0x37,0x30, + 0x34,0x32,0x37,0x30,0x37,0x31,0x34,0x32,0x36,0x5a,0x17,0x0d,0x31,0x32,0x30,0x34, + 0x32,0x35,0x30,0x37,0x31,0x34,0x32,0x36,0x5a,0x30,0x39,0x31,0x0b,0x30,0x09,0x06, + 0x03,0x55,0x04,0x06,0x13,0x02,0x43,0x48,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04, + 0x0a,0x13,0x10,0x4c,0x69,0x6e,0x75,0x78,0x20,0x73,0x74,0x72,0x6f,0x6e,0x67,0x53, + 0x77,0x61,0x6e,0x31,0x0f,0x30,0x0d,0x06,0x03,0x55,0x04,0x03,0x13,0x06,0x6d,0x61, + 0x72,0x74,0x69,0x6e,0x30,0x82,0x01,0x22,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86, + 0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0f,0x00,0x30,0x82,0x01,0x0a, + 0x02,0x82,0x01,0x01,0x00,0xd7,0xb9,0xba,0x4d,0xe2,0x3b,0x3d,0x35,0x7a,0x3f,0x88, + 0x67,0x95,0xe7,0xfd,0x9f,0xe9,0x0a,0x0d,0x79,0x3a,0x9e,0x21,0x8f,0xcb,0xe4,0x67, + 0x24,0xae,0x0c,0xda,0xb3,0xcc,0xec,0x36,0xb4,0xa8,0x4d,0xf1,0x3d,0xad,0xe4,0x8c, + 0x63,0x92,0x54,0xb7,0xb2,0x02,0xa2,0x00,0x62,0x8b,0x04,0xac,0xa0,0x17,0xad,0x17, + 0x9a,0x05,0x0d,0xd7,0xb3,0x08,0x02,0xc5,0x26,0xcf,0xdd,0x05,0x42,0xfc,0x13,0x6d, + 0x9f,0xb1,0xf3,0x4f,0x82,0x1d,0xef,0x01,0xc9,0x91,0xea,0x37,0x1b,0x79,0x28,0xfa, + 0xbf,0x9f,0xb3,0xeb,0x82,0x4f,0x10,0xc6,0x4b,0xa4,0x08,0xf7,0x8e,0xf2,0x00,0xea, + 0x04,0x97,0x80,0x9f,0x65,0x86,0xde,0x6b,0xc7,0xda,0x83,0xfc,0xad,0x4a,0xaf,0x52, + 0x8b,0x4d,0x33,0xee,0x49,0x87,0x2f,0x3b,0x60,0x45,0x66,0x8f,0xe6,0x89,0xcc,0xb1, + 0x92,0x02,0x17,0x2b,0x7b,0x8e,0x90,0x47,0x84,0x84,0x59,0x95,0x81,0xd8,0xe0,0xf3, + 0x87,0xe0,0x04,0x09,0xfd,0xcc,0x3a,0x21,0x34,0xfa,0xec,0xbe,0xf5,0x9c,0xcf,0x55, + 0x80,0x7b,0xe3,0x75,0x9d,0x36,0x68,0xab,0x83,0xe3,0xad,0x01,0x53,0x0d,0x8a,0x9a, + 0xa6,0xb0,0x15,0xc9,0xc5,0xf8,0x9b,0x51,0x32,0xcf,0x97,0x6c,0xfe,0x4a,0x56,0x3c, + 0xc8,0x8f,0x4a,0x70,0x23,0x4f,0xf6,0xf7,0xe6,0x9f,0x09,0xcd,0x8f,0xea,0x20,0x7d, + 0x34,0xc0,0xc5,0xc0,0x34,0x06,0x6f,0x8b,0xeb,0x04,0x54,0x3f,0x0e,0xcd,0xe2,0x85, + 0xab,0x94,0x3e,0x91,0x6c,0x18,0x6f,0x96,0x5d,0xf2,0x8b,0x10,0xe9,0x90,0x43,0xb0, + 0x61,0x52,0xac,0xcf,0x75,0x02,0x03,0x01,0x00,0x01,0x30,0x0d,0x06,0x09,0x2a,0x86, + 0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x09,0x63, + 0x42,0xad,0xe5,0xa3,0xf6,0xc9,0x5d,0x08,0xf2,0x78,0x7b,0xeb,0x8a,0xef,0x50,0x00, + 0xc8,0xeb,0xe9,0x26,0x94,0xcb,0x84,0x10,0x7e,0x42,0x6b,0x86,0x38,0x57,0xa6,0x02, + 0x98,0x5a,0x2c,0x8f,0x44,0x32,0x1b,0x97,0x8c,0x7e,0x4b,0xd8,0xe8,0xe8,0x0f,0x4a, + 0xb9,0x31,0x9f,0xf6,0x9f,0x0e,0x67,0x26,0x05,0x2a,0x99,0x14,0x35,0x41,0x47,0x9a, + 0xfa,0x12,0x94,0x0b,0xe9,0x27,0x7c,0x71,0x20,0xd7,0x8d,0x3b,0x97,0x19,0x2d,0x15, + 0xff,0xa4,0xf3,0x89,0x8d,0x29,0x5f,0xf6,0x3f,0x93,0xaf,0x78,0x61,0xe4,0xe1,0x2e, + 0x75,0xc1,0x2c,0xc4,0x76,0x95,0x19,0xf8,0x37,0xdc,0xd8,0x00,0x7a,0x3c,0x0f,0x49, + 0x2e,0x88,0x09,0x16,0xb3,0x92,0x33,0xdf,0x77,0x83,0x4f,0xb5,0x9e,0x30,0x8c,0x48, + 0x1d,0xd8,0x84,0xfb,0xf1,0xb9,0xa0,0xbe,0x25,0xff,0x4c,0xeb,0xef,0x2b,0xcd,0xfa, + 0x0b,0x94,0x66,0x3b,0x28,0x08,0x3f,0x3a,0xda,0x41,0xd0,0x6b,0xab,0x5e,0xbb,0x8a, + 0x9f,0xdc,0x98,0x3e,0x59,0x37,0x48,0xbe,0x69,0xde,0x85,0x82,0xf2,0x53,0x8b,0xe4, + 0x44,0xe4,0x71,0x91,0x14,0x85,0x0e,0x1e,0x79,0xdd,0x62,0xf5,0xdc,0x25,0x89,0xab, + 0x50,0x5b,0xaa,0xae,0xe3,0x64,0x6a,0x23,0x34,0xd7,0x30,0xe2,0x2a,0xc8,0x81,0x0c, + 0xec,0xd2,0x31,0xc6,0x1e,0xb6,0xc0,0x57,0xd9,0xe1,0x14,0x06,0x9b,0xf8,0x51,0x69, + 0x47,0xf0,0x9c,0xcd,0x69,0xef,0x8e,0x5f,0x62,0xda,0x10,0xf7,0x3c,0x6d,0x0f,0x33, + 0xec,0x6f,0xfd,0x94,0x07,0x16,0x41,0x32,0x06,0xa4,0xe1,0x08,0x31,0x87, +}; +chunk_t certchunk = chunk_from_buf(certbuf); + +/******************************************************************************* + * auth info test + ******************************************************************************/ +bool test_auth_info() +{ + auth_info_t *auth = auth_info_create(), *auth2; + certificate_t *c1, *c2; + enumerator_t *enumerator; + int round = 0; + void *value; + auth_item_t type; + + c1 = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, + BUILD_BLOB_ASN1_DER, chunk_clone(certchunk), + BUILD_END); + if (!c1) + { + return FALSE; + } + + auth->add_item(auth, AUTHN_SUBJECT_CERT, c1); + if (!auth->get_item(auth, AUTHN_SUBJECT_CERT, (void**)&c2)) + { + return FALSE; + } + if (!c1->equals(c1, c2)) + { + return FALSE; + } + + enumerator = auth->create_item_enumerator(auth); + while (enumerator->enumerate(enumerator, &type, &value)) + { + round++; + if (round == 1 && type == AUTHN_SUBJECT_CERT && value == c1) + { + continue; + } + return FALSE; + } + enumerator->destroy(enumerator); + + auth2 = auth_info_create(); + auth2->add_item(auth2, AUTHN_CA_CERT, c1); + auth2->merge(auth2, auth); + + round = 0; + enumerator = auth2->create_item_enumerator(auth2); + while (enumerator->enumerate(enumerator, &type, &value)) + { + round++; + if (round == 1 && type == AUTHN_CA_CERT && value == c1) + { + continue; + } + if (round == 2 && type == AUTHN_SUBJECT_CERT && value == c1) + { + continue; + } + return FALSE; + } + enumerator->destroy(enumerator); + auth->destroy(auth); + auth2->destroy(auth2); + c1->destroy(c1); + return TRUE; +} + diff --git a/src/charon/plugins/unit_tester/tests/test_curl.c b/src/charon/plugins/unit_tester/tests/test_curl.c new file mode 100644 index 000000000..c011617a7 --- /dev/null +++ b/src/charon/plugins/unit_tester/tests/test_curl.c @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 +#include +#include +#include + +/******************************************************************************* + * curl get test + ******************************************************************************/ + +bool test_curl_get() +{ + chunk_t chunk; + + if (lib->fetcher->fetch(lib->fetcher, "http://www.strongswan.org", + &chunk, FETCH_END) != SUCCESS) + { + return FALSE; + } + free(chunk.ptr); + + if (lib->fetcher->fetch(lib->fetcher, "http://www.google.com", + &chunk, FETCH_END) != SUCCESS) + { + return FALSE; + } + free(chunk.ptr); + return TRUE; +} + diff --git a/src/charon/plugins/unit_tester/tests/test_enumerator.c b/src/charon/plugins/unit_tester/tests/test_enumerator.c new file mode 100644 index 000000000..d17d62bef --- /dev/null +++ b/src/charon/plugins/unit_tester/tests/test_enumerator.c @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 + + +/******************************************************************************* + * linked list remove test + ******************************************************************************/ +bool test_list_remove() +{ + void *a = (void*)1, *b = (void*)2; + linked_list_t *list; + + list = linked_list_create(); + list->insert_last(list, a); + if (list->remove(list, a, NULL) != 1) + { + return FALSE; + } + list->insert_last(list, a); + list->insert_first(list, a); + list->insert_last(list, a); + list->insert_last(list, b); + if (list->remove(list, a, NULL) != 3) + { + return FALSE; + } + if (list->remove(list, a, NULL) != 0) + { + return FALSE; + } + if (list->get_count(list) != 1) + { + return FALSE; + } + if (list->remove(list, b, NULL) != 1) + { + return FALSE; + } + if (list->remove(list, b, NULL) != 0) + { + return FALSE; + } + list->destroy(list); + return TRUE; +} + +/******************************************************************************* + * Simple insert first/last and enumerate test + ******************************************************************************/ +bool test_enumerate() +{ + int round, x; + void *a = (void*)4, *b = (void*)3, *c = (void*)2, *d = (void*)5, *e = (void*)1; + linked_list_t *list; + enumerator_t *enumerator; + + list = linked_list_create(); + + list->insert_last(list, a); + list->insert_first(list, b); + list->insert_first(list, c); + list->insert_last(list, d); + list->insert_first(list, e); + + round = 1; + enumerator = list->create_enumerator(list); + while (enumerator->enumerate(enumerator, &x)) + { + if (round != x) + { + return FALSE; + } + round++; + } + enumerator->destroy(enumerator); + + list->destroy(list); + return TRUE; +} + +/******************************************************************************* + * nested enumerator test + ******************************************************************************/ + +static bool bad_data; + +static enumerator_t* create_inner(linked_list_t *outer, void *data) +{ + if (data != (void*)101) + { + bad_data = TRUE; + } + return outer->create_enumerator(outer); +} + + +static void destroy_data(void *data) +{ + if (data != (void*)101) + { + bad_data = TRUE; + } +} + +bool test_enumerate_nested() +{ + int round, x; + void *a = (void*)1, *b = (void*)2, *c = (void*)3, *d = (void*)4, *e = (void*)5; + linked_list_t *list, *l1, *l2, *l3; + enumerator_t *enumerator; + + bad_data = FALSE; + list = linked_list_create(); + l1 = linked_list_create(); + l2 = linked_list_create(); + l3 = linked_list_create(); + list->insert_last(list, l1); + list->insert_last(list, l2); + list->insert_last(list, l3); + + l1->insert_last(l1, a); + l1->insert_last(l1, b); + l3->insert_last(l3, c); + l3->insert_last(l3, d); + l3->insert_last(l3, e); + + round = 1; + enumerator = enumerator_create_nested(list->create_enumerator(list), + (void*)create_inner, (void*)101, destroy_data); + while (enumerator->enumerate(enumerator, &x)) + { + if (round != x) + { + return FALSE; + } + round++; + } + enumerator->destroy(enumerator); + + list->destroy(list); + l1->destroy(l1); + l2->destroy(l2); + l3->destroy(l3); + return !bad_data; +} + + +/******************************************************************************* + * filtered enumerator test + ******************************************************************************/ +static bool filter(void *data, int *v, int *vo, int *w, int *wo, + int *x, int *xo, int *y, int *yo, int *z, int *zo) +{ + int val = *v; + + *vo = val++; + *wo = val++; + *xo = val++; + *yo = val++; + *zo = val++; + if (data != (void*)101) + { + return FALSE; + } + return TRUE; +} + +bool test_enumerate_filtered() +{ + int round, v, w, x, y, z; + void *a = (void*)1, *b = (void*)2, *c = (void*)3, *d = (void*)4, *e = (void*)5; + linked_list_t *list; + enumerator_t *enumerator; + + bad_data = FALSE; + list = linked_list_create(); + + list->insert_last(list, a); + list->insert_last(list, b); + list->insert_last(list, c); + list->insert_last(list, d); + list->insert_last(list, e); + + round = 1; + enumerator = enumerator_create_filter(list->create_enumerator(list), + (void*)filter, (void*)101, destroy_data); + while (enumerator->enumerate(enumerator, &v, &w, &x, &y, &z)) + { + if (v != round || w != round + 1 || x != round + 2 || + y != round + 3 || z != round + 4) + { + return FALSE; + } + round++; + } + enumerator->destroy(enumerator); + + list->destroy(list); + return !bad_data; +} diff --git a/src/charon/plugins/unit_tester/tests/test_fips_prf.c b/src/charon/plugins/unit_tester/tests/test_fips_prf.c new file mode 100644 index 000000000..56ba556f5 --- /dev/null +++ b/src/charon/plugins/unit_tester/tests/test_fips_prf.c @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 +#include + +/******************************************************************************* + * fips prf known value test + ******************************************************************************/ +bool fips_prf_test() +{ + prf_t *prf; + u_int8_t key_buf[] = { + 0xbd, 0x02, 0x9b, 0xbe, 0x7f, 0x51, 0x96, 0x0b, + 0xcf, 0x9e, 0xdb, 0x2b, 0x61, 0xf0, 0x6f, 0x0f, + 0xeb, 0x5a, 0x38, 0xb6 + }; + u_int8_t seed_buf[] = { + 0x00 + }; + u_int8_t result_buf[] = { + 0x20, 0x70, 0xb3, 0x22, 0x3d, 0xba, 0x37, 0x2f, + 0xde, 0x1c, 0x0f, 0xfc, 0x7b, 0x2e, 0x3b, 0x49, + 0x8b, 0x26, 0x06, 0x14, 0x3c, 0x6c, 0x18, 0xba, + 0xcb, 0x0f, 0x6c, 0x55, 0xba, 0xbb, 0x13, 0x78, + 0x8e, 0x20, 0xd7, 0x37, 0xa3, 0x27, 0x51, 0x16 + }; + chunk_t key = chunk_from_buf(key_buf); + chunk_t seed = chunk_from_buf(seed_buf); + chunk_t expected = chunk_from_buf(result_buf); + chunk_t result; + + prf = lib->crypto->create_prf(lib->crypto, PRF_FIPS_SHA1_160); + if (prf == NULL) + { + return FALSE; + } + prf->set_key(prf, key); + prf->allocate_bytes(prf, seed, &result); + prf->destroy(prf); + if (!chunk_equals(result, expected)) + { + chunk_free(&result); + return FALSE; + } + chunk_free(&result); + return TRUE; +} + diff --git a/src/charon/plugins/unit_tester/tests/test_mutex.c b/src/charon/plugins/unit_tester/tests/test_mutex.c new file mode 100644 index 000000000..a305d5082 --- /dev/null +++ b/src/charon/plugins/unit_tester/tests/test_mutex.c @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 +#include + +#include +#include +#include + + +static mutex_t *mutex; + +static int locked = 0; + +static bool failed = FALSE; + +static pthread_barrier_t barrier; + +static void* run(void* null) +{ + int i; + + /* wait for all threads before getting in action */ + pthread_barrier_wait(&barrier); + + for (i = 0; i < 100; i++) + { + mutex->lock(mutex); + mutex->lock(mutex); + mutex->lock(mutex); + locked++; + sched_yield(); + if (locked > 1) + { + failed = TRUE; + } + locked--; + mutex->unlock(mutex); + mutex->unlock(mutex); + mutex->unlock(mutex); + } + return NULL; +} + +#define THREADS 20 + +/******************************************************************************* + * mutex test + ******************************************************************************/ +bool test_mutex() +{ + int i; + pthread_t threads[THREADS]; + + mutex = mutex_create(MUTEX_RECURSIVE); + + for (i = 0; i < 10; i++) + { + mutex->lock(mutex); + mutex->unlock(mutex); + } + for (i = 0; i < 10; i++) + { + mutex->lock(mutex); + } + for (i = 0; i < 10; i++) + { + mutex->unlock(mutex); + } + + pthread_barrier_init(&barrier, NULL, THREADS); + + for (i = 0; i < THREADS; i++) + { + pthread_create(&threads[i], NULL, run, NULL); + } + for (i = 0; i < THREADS; i++) + { + pthread_join(threads[i], NULL); + } + pthread_barrier_destroy(&barrier); + + mutex->destroy(mutex); + + return !failed; +} + diff --git a/src/charon/plugins/unit_tester/tests/test_mysql.c b/src/charon/plugins/unit_tester/tests/test_mysql.c new file mode 100644 index 000000000..ff3d38ad8 --- /dev/null +++ b/src/charon/plugins/unit_tester/tests/test_mysql.c @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 +#include +#include + +/******************************************************************************* + * mysql simple test + ******************************************************************************/ +bool test_mysql() +{ + database_t *db; + char *txt = "I'm a superduper test"; + char buf[] = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08}; + chunk_t data = chunk_from_buf(buf); + int row; + chunk_t qdata; + char *qtxt; + bool good = FALSE; + enumerator_t *enumerator; + + db = lib->db->create(lib->db, "mysql://testuser:testpass@localhost/test"); + if (!db) + { + return FALSE; + } + if (db->execute(db, NULL, "CREATE TABLE test (" + "id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, " + "txt TEXT, data BLOB)") < 0) + { + return FALSE; + } + if (db->execute(db, &row, "INSERT INTO test (txt, data) VALUES (?,?)", + DB_TEXT, txt, DB_BLOB, data) < 0) + { + return FALSE; + } + if (row != 1) + { + return FALSE; + } + enumerator = db->query(db, "SELECT txt, data FROM test WHERE id = ?", + DB_INT, row, + DB_TEXT, DB_BLOB); + if (!enumerator) + { + return FALSE; + } + while (enumerator->enumerate(enumerator, &qtxt, &qdata)) + { + if (good) + { /* only one row */ + good = FALSE; + break; + } + if (streq(qtxt, txt) && chunk_equals(data, qdata)) + { + good = TRUE; + } + } + enumerator->destroy(enumerator); + if (!good) + { + return FALSE; + } + if (db->execute(db, NULL, "DELETE FROM test WHERE id = ?", DB_INT, row) != 1) + { + return FALSE; + } + if (db->execute(db, NULL, "DROP TABLE test") < 0) + { + return FALSE; + } + db->destroy(db); + return TRUE; +} + diff --git a/src/charon/plugins/unit_tester/tests/test_sqlite.c b/src/charon/plugins/unit_tester/tests/test_sqlite.c new file mode 100644 index 000000000..d152fc594 --- /dev/null +++ b/src/charon/plugins/unit_tester/tests/test_sqlite.c @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 +#include +#include + +#include + + +#define DBFILE "/tmp/strongswan-test.db" + +/******************************************************************************* + * sqlite simple test + ******************************************************************************/ +bool test_sqlite() +{ + database_t *db; + char *txt = "I'm a superduper test"; + char buf[] = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08}; + chunk_t data = chunk_from_buf(buf); + int row; + chunk_t qdata; + char *qtxt; + bool good = FALSE; + enumerator_t *enumerator; + + db = lib->db->create(lib->db, "sqlite://" DBFILE); + if (!db) + { + return FALSE; + } + if (db->execute(db, NULL, "CREATE TABLE test (txt TEXT, data BLOB)") < 0) + { + return FALSE; + } + if (db->execute(db, &row, "INSERT INTO test (txt, data) VALUES (?,?)", + DB_TEXT, txt, DB_BLOB, data) < 0) + { + return FALSE; + } + if (row != 1) + { + return FALSE; + } + enumerator = db->query(db, "SELECT txt, data FROM test WHERE oid = ?", + DB_INT, row, + DB_TEXT, DB_BLOB); + if (!enumerator) + { + return FALSE; + } + while (enumerator->enumerate(enumerator, &qtxt, &qdata)) + { + if (good) + { /* only one row */ + good = FALSE; + break; + } + if (streq(qtxt, txt) && chunk_equals(data, qdata)) + { + good = TRUE; + } + } + enumerator->destroy(enumerator); + if (!good) + { + return FALSE; + } + if (db->execute(db, NULL, "DELETE FROM test WHERE oid = ?", DB_INT, row) != 1) + { + return FALSE; + } + if (db->execute(db, NULL, "DROP TABLE test") < 0) + { + return FALSE; + } + db->destroy(db); + unlink(DBFILE); + return TRUE; +} + diff --git a/src/charon/plugins/unit_tester/unit_tester.c b/src/charon/plugins/unit_tester/unit_tester.c new file mode 100644 index 000000000..f996a4988 --- /dev/null +++ b/src/charon/plugins/unit_tester/unit_tester.c @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "unit_tester.h" + +#include + +typedef struct private_unit_tester_t private_unit_tester_t; +typedef struct unit_test_t unit_test_t; +typedef enum test_status_t test_status_t; + +/** + * private data of unit_tester + */ +struct private_unit_tester_t { + + /** + * public functions + */ + unit_tester_t public; +}; + +struct unit_test_t { + + /** + * name of the test + */ + char *name; + + /** + * test function + */ + bool (*test)(void); + + /** + * run the test? + */ + bool enabled; +}; + +#undef DEFINE_TEST +#define DEFINE_TEST(name, function, enabled) bool function(); +#include +#undef DEFINE_TEST +#define DEFINE_TEST(name, function, enabled) {name, function, enabled}, +static unit_test_t tests[] = { +#include +}; + +static void run_tests(private_unit_tester_t *this) +{ + int i, run = 0, failed = 0, success = 0, skipped = 0; + + DBG1(DBG_CFG, "running unit tests, %d tests registered", + sizeof(tests)/sizeof(unit_test_t)); + + for (i = 0; i < sizeof(tests)/sizeof(unit_test_t); i++) + { + if (tests[i].enabled) + { + run++; + if (tests[i].test()) + { + DBG1(DBG_CFG, "test '%s' successful", tests[i].name); + success++; + } + else + { + DBG1(DBG_CFG, "test '%s' failed", tests[i].name); + failed++; + } + } + else + { + DBG1(DBG_CFG, "test '%s' disabled", tests[i].name); + skipped++; + } + } + DBG1(DBG_CFG, "%d/%d tests successful (%d failed, %d disabled)", + success, run, failed, skipped); +} + +/** + * Implementation of 2007_t.destroy + */ +static void destroy(private_unit_tester_t *this) +{ + free(this); +} + +/* + * see header file + */ +plugin_t *plugin_create() +{ + private_unit_tester_t *this = malloc_thing(private_unit_tester_t); + + this->public.plugin.destroy = (void(*)(plugin_t*))destroy; + + run_tests(this); + + return &this->public.plugin; +} + diff --git a/src/charon/plugins/unit_tester/unit_tester.h b/src/charon/plugins/unit_tester/unit_tester.h new file mode 100644 index 000000000..a87c86251 --- /dev/null +++ b/src/charon/plugins/unit_tester/unit_tester.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +/** + * @defgroup unit_tester unit_tester + * @{ @ingroup cplugins + */ + +#ifndef UNIT_TESTER_H_ +#define UNIT_TESTER_H_ + +#include + +typedef struct unit_tester_t unit_tester_t; + +/** + * Unit testing plugin. + * + * The unit testing plugin runs tests on plugin initialization. Tests are + * defined in tests.h using the DEFINE_TEST macro. Implementation of the + * tests is done in the tests folder. Each test has uses a function which + * returns TRUE for success or FALSE for failure. + */ +struct unit_tester_t { + + /** + * Implements the plugin interface. + */ + plugin_t plugin; +}; + +/** + * Create a unit_tester plugin. + */ +plugin_t *plugin_create(); + +#endif /* UNIT_TESTER_H_ @}*/ diff --git a/src/charon/plugins/xml/Makefile.am b/src/charon/plugins/xml/Makefile.am new file mode 100644 index 000000000..0e4735a41 --- /dev/null +++ b/src/charon/plugins/xml/Makefile.am @@ -0,0 +1,10 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon ${xml_CFLAGS} + +AM_CFLAGS = -rdynamic -DIPSEC_PIDDIR=\"${piddir}\" + +plugin_LTLIBRARIES = libcharon-xml.la +libcharon_xml_la_SOURCES = xml.h xml.c +libcharon_xml_la_LDFLAGS = -module +libcharon_xml_la_LIBADD = ${xml_LIBS} + diff --git a/src/charon/plugins/xml/schema.xml b/src/charon/plugins/xml/schema.xml new file mode 100644 index 000000000..66a51117e --- /dev/null +++ b/src/charon/plugins/xml/schema.xml @@ -0,0 +1,400 @@ + + + + + + + + + + + + + + + + request + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + response + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + created + connecting + established + rekeying + deleting + + + + + initiator + responder + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + any + + + + + + ipv4 + + + + + + ipv6 + + + + + + fqdn + + + + + + email + + + + + + asn1gn + + + + + + asn1dn + + + + + + keyid + + + + + + + + + + ipv4 + + + + + + ipv6 + + + + + + + + (([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(/([0-9]|[1-2][0-9]|3[0-2]))? + + + + + ([0-9a-fA-F]{1,4}:|:){1,7}([0-9a-fA-F]{1,4}|:)(/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8]))? + + + + + [a-z0-9\-](\.[a-z0-9\-]+)* + + + + + [a-zA-Z0-9_\-\.]+@(([a-z0-9\-](\.[a-z0-9\-]+)*)|(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])) + + + + + + + + + + + + + + + diff --git a/src/charon/plugins/xml/xml.c b/src/charon/plugins/xml/xml.c new file mode 100644 index 000000000..85778f608 --- /dev/null +++ b/src/charon/plugins/xml/xml.c @@ -0,0 +1,749 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include + +#include "xml.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +typedef struct private_xml_t private_xml_t; + +/** + * Private data of an xml_t object. + */ +struct private_xml_t { + + /** + * Public part of xml_t object. + */ + xml_t public; + + /** + * XML unix socket fd + */ + int socket; + + /** + * job accepting stroke messages + */ + callback_job_t *job; +}; + +ENUM(ike_sa_state_lower_names, IKE_CREATED, IKE_DELETING, + "created", + "connecting", + "established", + "rekeying", + "deleting", +); + +/** + * write a bool into element + */ +static void write_bool(xmlTextWriterPtr writer, char *element, bool val) +{ + xmlTextWriterWriteElement(writer, element, val ? "true" : "false"); +} + +/** + * write a identification_t into element + */ +static void write_id(xmlTextWriterPtr writer, char *element, identification_t *id) +{ + xmlTextWriterStartElement(writer, element); + switch (id->get_type(id)) + { + { + char *type = ""; + while (TRUE) + { + case ID_ANY: + type = "any"; + break; + case ID_IPV4_ADDR: + type = "ipv4"; + break; + case ID_IPV6_ADDR: + type = "ipv6"; + break; + case ID_FQDN: + type = "fqdn"; + break; + case ID_RFC822_ADDR: + type = "email"; + break; + case ID_DER_ASN1_DN: + type = "asn1dn"; + break; + case ID_DER_ASN1_GN: + type = "asn1gn"; + break; + } + xmlTextWriterWriteAttribute(writer, "type", type); + xmlTextWriterWriteFormatString(writer, "%D", id); + break; + } + default: + /* TODO: base64 keyid */ + xmlTextWriterWriteAttribute(writer, "type", "keyid"); + break; + } + xmlTextWriterEndElement(writer); +} + +/** + * write a host_t address into an element + */ +static void write_address(xmlTextWriterPtr writer, char *element, host_t *host) +{ + xmlTextWriterStartElement(writer, element); + xmlTextWriterWriteAttribute(writer, "type", + host->get_family(host) == AF_INET ? "ipv4" : "ipv6"); + if (host->is_anyaddr(host)) + { /* do not use %any for XML */ + xmlTextWriterWriteFormatString(writer, "%s", + host->get_family(host) == AF_INET ? "0.0.0.0" : "::"); + } + else + { + xmlTextWriterWriteFormatString(writer, "%H", host); + } + xmlTextWriterEndElement(writer); +} + +/** + * write networks element + */ +static void write_networks(xmlTextWriterPtr writer, char *element, + linked_list_t *list) +{ + iterator_t *iterator; + traffic_selector_t *ts; + + xmlTextWriterStartElement(writer, element); + iterator = list->create_iterator(list, TRUE); + while (iterator->iterate(iterator, (void**)&ts)) + { + xmlTextWriterStartElement(writer, "network"); + xmlTextWriterWriteAttribute(writer, "type", + ts->get_type(ts) == TS_IPV4_ADDR_RANGE ? "ipv4" : "ipv6"); + xmlTextWriterWriteFormatString(writer, "%R", ts); + xmlTextWriterEndElement(writer); + } + iterator->destroy(iterator); + xmlTextWriterEndElement(writer); +} + +/** + * write a childEnd + */ +static void write_childend(xmlTextWriterPtr writer, child_sa_t *child, bool local) +{ + linked_list_t *list; + + xmlTextWriterWriteFormatElement(writer, "spi", "%lx", + htonl(child->get_spi(child, local))); + list = child->get_traffic_selectors(child, local); + write_networks(writer, "networks", list); +} + +/** + * write a child_sa_t + */ +static void write_child(xmlTextWriterPtr writer, child_sa_t *child) +{ + mode_t mode; + encryption_algorithm_t encr; + integrity_algorithm_t int_algo; + size_t encr_len, int_len; + u_int32_t rekey, use_in, use_out, use_fwd; + child_cfg_t *config; + + config = child->get_config(child); + child->get_stats(child, &mode, &encr, &encr_len, &int_algo, &int_len, + &rekey, &use_in, &use_out, &use_fwd); + + xmlTextWriterStartElement(writer, "childsa"); + xmlTextWriterWriteFormatElement(writer, "reqid", "%d", child->get_reqid(child)); + xmlTextWriterWriteFormatElement(writer, "childconfig", "%s", + config->get_name(config)); + xmlTextWriterStartElement(writer, "local"); + write_childend(writer, child, TRUE); + xmlTextWriterEndElement(writer); + xmlTextWriterStartElement(writer, "remote"); + write_childend(writer, child, FALSE); + xmlTextWriterEndElement(writer); + xmlTextWriterEndElement(writer); +} + +/** + * process a ikesalist query request message + */ +static void request_query_ikesa(xmlTextReaderPtr reader, xmlTextWriterPtr writer) +{ + iterator_t *iterator; + ike_sa_t *ike_sa; + + /* */ + xmlTextWriterStartElement(writer, "ikesalist"); + + iterator = charon->ike_sa_manager->create_iterator(charon->ike_sa_manager); + while (iterator->iterate(iterator, (void**)&ike_sa)) + { + ike_sa_id_t *id; + host_t *local, *remote; + iterator_t *children; + child_sa_t *child_sa; + + id = ike_sa->get_id(ike_sa); + + xmlTextWriterStartElement(writer, "ikesa"); + xmlTextWriterWriteFormatElement(writer, "id", "%d", + ike_sa->get_unique_id(ike_sa)); + xmlTextWriterWriteFormatElement(writer, "status", "%N", + ike_sa_state_lower_names, ike_sa->get_state(ike_sa)); + xmlTextWriterWriteElement(writer, "role", + id->is_initiator(id) ? "initiator" : "responder"); + xmlTextWriterWriteElement(writer, "peerconfig", ike_sa->get_name(ike_sa)); + + /* */ + local = ike_sa->get_my_host(ike_sa); + xmlTextWriterStartElement(writer, "local"); + xmlTextWriterWriteFormatElement(writer, "spi", "%.16llx", + id->is_initiator(id) ? id->get_initiator_spi(id) + : id->get_responder_spi(id)); + write_id(writer, "identification", ike_sa->get_my_id(ike_sa)); + write_address(writer, "address", local); + xmlTextWriterWriteFormatElement(writer, "port", "%d", + local->get_port(local)); + if (ike_sa->supports_extension(ike_sa, EXT_NATT)) + { + write_bool(writer, "nat", ike_sa->has_condition(ike_sa, COND_NAT_HERE)); + } + xmlTextWriterEndElement(writer); + /* */ + + /* */ + remote = ike_sa->get_other_host(ike_sa); + xmlTextWriterStartElement(writer, "remote"); + xmlTextWriterWriteFormatElement(writer, "spi", "%.16llx", + id->is_initiator(id) ? id->get_responder_spi(id) + : id->get_initiator_spi(id)); + write_id(writer, "identification", ike_sa->get_other_id(ike_sa)); + write_address(writer, "address", remote); + xmlTextWriterWriteFormatElement(writer, "port", "%d", + remote->get_port(remote)); + if (ike_sa->supports_extension(ike_sa, EXT_NATT)) + { + write_bool(writer, "nat", ike_sa->has_condition(ike_sa, COND_NAT_THERE)); + } + xmlTextWriterEndElement(writer); + /* */ + + /* */ + xmlTextWriterStartElement(writer, "childsalist"); + children = ike_sa->create_child_sa_iterator(ike_sa); + while (children->iterate(children, (void**)&child_sa)) + { + write_child(writer, child_sa); + } + children->destroy(children); + /* */ + xmlTextWriterEndElement(writer); + + /* */ + xmlTextWriterEndElement(writer); + } + iterator->destroy(iterator); + + /* */ + xmlTextWriterEndElement(writer); +} + +/** + * process a configlist query request message + */ +static void request_query_config(xmlTextReaderPtr reader, xmlTextWriterPtr writer) +{ + enumerator_t *enumerator; + peer_cfg_t *peer_cfg; + + /* */ + xmlTextWriterStartElement(writer, "configlist"); + + enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends); + while (enumerator->enumerate(enumerator, (void**)&peer_cfg)) + { + enumerator_t *children; + child_cfg_t *child_cfg; + ike_cfg_t *ike_cfg; + linked_list_t *list; + + if (peer_cfg->get_ike_version(peer_cfg) != 2) + { /* only IKEv2 connections yet */ + continue; + } + + /* */ + xmlTextWriterStartElement(writer, "peerconfig"); + xmlTextWriterWriteElement(writer, "name", peer_cfg->get_name(peer_cfg)); + write_id(writer, "local", peer_cfg->get_my_id(peer_cfg)); + write_id(writer, "remote", peer_cfg->get_other_id(peer_cfg)); + + /* */ + ike_cfg = peer_cfg->get_ike_cfg(peer_cfg); + xmlTextWriterStartElement(writer, "ikeconfig"); + write_address(writer, "local", ike_cfg->get_my_host(ike_cfg)); + write_address(writer, "remote", ike_cfg->get_other_host(ike_cfg)); + xmlTextWriterEndElement(writer); + /* */ + + /* */ + xmlTextWriterStartElement(writer, "childconfiglist"); + children = peer_cfg->create_child_cfg_enumerator(peer_cfg); + while (children->enumerate(children, &child_cfg)) + { + /* */ + xmlTextWriterStartElement(writer, "childconfig"); + xmlTextWriterWriteElement(writer, "name", + child_cfg->get_name(child_cfg)); + list = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, NULL); + write_networks(writer, "local", list); + list->destroy_offset(list, offsetof(traffic_selector_t, destroy)); + list = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL, NULL); + write_networks(writer, "remote", list); + list->destroy_offset(list, offsetof(traffic_selector_t, destroy)); + xmlTextWriterEndElement(writer); + /* */ + } + children->destroy(children); + /* */ + xmlTextWriterEndElement(writer); + /* */ + xmlTextWriterEndElement(writer); + } + enumerator->destroy(enumerator); + /* */ + xmlTextWriterEndElement(writer); +} + +/** + * callback which logs to a XML writer + */ +static bool xml_callback(xmlTextWriterPtr writer, signal_t signal, level_t level, + ike_sa_t* ike_sa, char* format, va_list args) +{ + if (level <= 1) + { + /* */ + xmlTextWriterStartElement(writer, "item"); + xmlTextWriterWriteFormatAttribute(writer, "level", "%d", level); + xmlTextWriterWriteFormatAttribute(writer, "source", "%N", signal_names, signal); + xmlTextWriterWriteFormatAttribute(writer, "thread", "%u", pthread_self()); + xmlTextWriterWriteVFormatString(writer, format, args); + xmlTextWriterEndElement(writer); + /* */ + } + return TRUE; +} + +/** + * process a *terminate control request message + */ +static void request_control_terminate(xmlTextReaderPtr reader, + xmlTextWriterPtr writer, bool ike) +{ + if (xmlTextReaderRead(reader) && + xmlTextReaderNodeType(reader) == XML_READER_TYPE_TEXT) + { + const char *str; + u_int32_t id; + status_t status; + + str = xmlTextReaderConstValue(reader); + if (str == NULL || !(id = atoi(str))) + { + DBG1(DBG_CFG, "error parsing XML id string"); + return; + } + DBG1(DBG_CFG, "terminating %s_SA %d", ike ? "IKE" : "CHILD", id); + + /* */ + xmlTextWriterStartElement(writer, "log"); + if (ike) + { + status = charon->controller->terminate_ike( + charon->controller, id, + (controller_cb_t)xml_callback, writer); + } + else + { + status = charon->controller->terminate_child( + charon->controller, id, + (controller_cb_t)xml_callback, writer); + } + /* */ + xmlTextWriterEndElement(writer); + xmlTextWriterWriteFormatElement(writer, "status", "%d", status); + } +} + +/** + * process a *initiate control request message + */ +static void request_control_initiate(xmlTextReaderPtr reader, + xmlTextWriterPtr writer, bool ike) +{ + if (xmlTextReaderRead(reader) && + xmlTextReaderNodeType(reader) == XML_READER_TYPE_TEXT) + { + const char *str; + status_t status = FAILED; + peer_cfg_t *peer; + child_cfg_t *child = NULL; + enumerator_t *enumerator; + + str = xmlTextReaderConstValue(reader); + if (str == NULL) + { + DBG1(DBG_CFG, "error parsing XML config name string"); + return; + } + DBG1(DBG_CFG, "initiating %s_SA %s", ike ? "IKE" : "CHILD", str); + + /* */ + xmlTextWriterStartElement(writer, "log"); + peer = charon->backends->get_peer_cfg_by_name(charon->backends, (char*)str); + if (peer) + { + enumerator = peer->create_child_cfg_enumerator(peer); + if (ike) + { + if (!enumerator->enumerate(enumerator, &child)) + { + child = NULL; + } + child->get_ref(child); + } + else + { + while (enumerator->enumerate(enumerator, &child)) + { + if (streq(child->get_name(child), str)) + { + child->get_ref(child); + break; + } + child = NULL; + } + } + enumerator->destroy(enumerator); + if (child) + { + status = charon->controller->initiate(charon->controller, + peer, child, (controller_cb_t)xml_callback, + writer); + } + else + { + peer->destroy(peer); + } + } + /* */ + xmlTextWriterEndElement(writer); + xmlTextWriterWriteFormatElement(writer, "status", "%d", status); + } +} + +/** + * process a query request + */ +static void request_query(xmlTextReaderPtr reader, xmlTextWriterPtr writer) +{ + /* */ + xmlTextWriterStartElement(writer, "query"); + while (xmlTextReaderRead(reader)) + { + if (xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) + { + if (streq(xmlTextReaderConstName(reader), "ikesalist")) + { + request_query_ikesa(reader, writer); + break; + } + if (streq(xmlTextReaderConstName(reader), "configlist")) + { + request_query_config(reader, writer); + break; + } + } + } + /* */ + xmlTextWriterEndElement(writer); +} + +/** + * process a control request + */ +static void request_control(xmlTextReaderPtr reader, xmlTextWriterPtr writer) +{ + /* */ + xmlTextWriterStartElement(writer, "control"); + while (xmlTextReaderRead(reader)) + { + if (xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) + { + if (streq(xmlTextReaderConstName(reader), "ikesaterminate")) + { + request_control_terminate(reader, writer, TRUE); + break; + } + if (streq(xmlTextReaderConstName(reader), "childsaterminate")) + { + request_control_terminate(reader, writer, FALSE); + break; + } + if (streq(xmlTextReaderConstName(reader), "ikesainitiate")) + { + request_control_initiate(reader, writer, TRUE); + break; + } + if (streq(xmlTextReaderConstName(reader), "childsainitiate")) + { + request_control_initiate(reader, writer, FALSE); + break; + } + } + } + /* */ + xmlTextWriterEndElement(writer); +} + +/** + * process a request message + */ +static void request(xmlTextReaderPtr reader, char *id, int fd) +{ + xmlTextWriterPtr writer; + + writer = xmlNewTextWriter(xmlOutputBufferCreateFd(fd, NULL)); + if (writer == NULL) + { + DBG1(DBG_CFG, "opening SMP XML writer failed"); + return; + } + + xmlTextWriterStartDocument(writer, NULL, NULL, NULL); + /* */ + xmlTextWriterStartElement(writer, "message"); + xmlTextWriterWriteAttribute(writer, "xmlns", + "http://www.strongswan.org/smp/1.0"); + xmlTextWriterWriteAttribute(writer, "id", id); + xmlTextWriterWriteAttribute(writer, "type", "response"); + + while (xmlTextReaderRead(reader)) + { + if (xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) + { + if (streq(xmlTextReaderConstName(reader), "query")) + { + request_query(reader, writer); + break; + } + if (streq(xmlTextReaderConstName(reader), "control")) + { + request_control(reader, writer); + break; + } + } + } + /* and close document */ + xmlTextWriterEndDocument(writer); + xmlFreeTextWriter(writer); +} + +/** + * cleanup helper function for open file descriptors + */ +static void closefdp(int *fd) +{ + close(*fd); +} + +/** + * read from a opened connection and process it + */ +static job_requeue_t process(int *fdp) +{ + int oldstate, fd = *fdp; + char buffer[4096]; + size_t len; + xmlTextReaderPtr reader; + char *id = NULL, *type = NULL; + + pthread_cleanup_push((void*)closefdp, (void*)&fd); + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); + len = read(fd, buffer, sizeof(buffer)); + pthread_setcancelstate(oldstate, NULL); + pthread_cleanup_pop(0); + if (len <= 0) + { + close(fd); + DBG2(DBG_CFG, "SMP XML connection closed"); + return JOB_REQUEUE_NONE; + } + DBG3(DBG_CFG, "got XML request: %b", buffer, len); + + reader = xmlReaderForMemory(buffer, len, NULL, NULL, 0); + if (reader == NULL) + { + DBG1(DBG_CFG, "opening SMP XML reader failed"); + return JOB_REQUEUE_FAIR;; + } + + /* read message type and id */ + while (xmlTextReaderRead(reader)) + { + if (xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT && + streq(xmlTextReaderConstName(reader), "message")) + { + id = xmlTextReaderGetAttribute(reader, "id"); + type = xmlTextReaderGetAttribute(reader, "type"); + break; + } + } + + /* process message */ + if (id && type) + { + if (streq(type, "request")) + { + request(reader, id, fd); + } + else + { + /* response(reader, id) */ + } + } + xmlFreeTextReader(reader); + return JOB_REQUEUE_FAIR;; +} + +/** + * accept from XML socket and create jobs to process connections + */ +static job_requeue_t dispatch(private_xml_t *this) +{ + struct sockaddr_un strokeaddr; + int oldstate, fd, *fdp, strokeaddrlen = sizeof(strokeaddr); + callback_job_t *job; + + /* wait for connections, but allow thread to terminate */ + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); + fd = accept(this->socket, (struct sockaddr *)&strokeaddr, &strokeaddrlen); + pthread_setcancelstate(oldstate, NULL); + + if (fd < 0) + { + DBG1(DBG_CFG, "accepting SMP XML socket failed: %s", strerror(errno)); + sleep(1); + return JOB_REQUEUE_FAIR;; + } + + fdp = malloc_thing(int); + *fdp = fd; + job = callback_job_create((callback_job_cb_t)process, fdp, free, this->job); + charon->processor->queue_job(charon->processor, (job_t*)job); + + return JOB_REQUEUE_DIRECT; +} + +/** + * Implementation of itnerface_t.destroy. + */ +static void destroy(private_xml_t *this) +{ + this->job->cancel(this->job); + close(this->socket); + free(this); +} + +/* + * Described in header file + */ +plugin_t *plugin_create() +{ + struct sockaddr_un unix_addr = { AF_UNIX, IPSEC_PIDDIR "/charon.xml"}; + private_xml_t *this = malloc_thing(private_xml_t); + mode_t old; + + this->public.plugin.destroy = (void (*)(plugin_t*))destroy; + + /* set up unix socket */ + this->socket = socket(AF_UNIX, SOCK_STREAM, 0); + if (this->socket == -1) + { + DBG1(DBG_CFG, "could not create XML socket"); + free(this); + return NULL; + } + + unlink(unix_addr.sun_path); + old = umask(~(S_IRWXU | S_IRWXG)); + if (bind(this->socket, (struct sockaddr *)&unix_addr, sizeof(unix_addr)) < 0) + { + DBG1(DBG_CFG, "could not bind XML socket: %s", strerror(errno)); + close(this->socket); + free(this); + return NULL; + } + umask(old); + if (chown(unix_addr.sun_path, IPSEC_UID, IPSEC_GID) != 0) + { + DBG1(DBG_CFG, "changing XML socket permissions failed: %s", strerror(errno)); + } + + if (listen(this->socket, 5) < 0) + { + DBG1(DBG_CFG, "could not listen on XML socket: %s", strerror(errno)); + close(this->socket); + free(this); + return NULL; + } + + this->job = callback_job_create((callback_job_cb_t)dispatch, this, NULL, NULL); + charon->processor->queue_job(charon->processor, (job_t*)this->job); + + return &this->public.plugin; +} + diff --git a/src/charon/plugins/xml/xml.h b/src/charon/plugins/xml/xml.h new file mode 100644 index 000000000..289fca5f6 --- /dev/null +++ b/src/charon/plugins/xml/xml.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2007-2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +/** + * @defgroup xml xml + * @ingroup cplugins + * + * @defgroup xml_i xml + * @{ @ingroup xml + */ + +#ifndef XML_H_ +#define XML_H_ + +#include + +typedef struct xml_t xml_t; + +/** + * XML configuration and control interface. + * + * The XML interface uses a socket and a to communicate. The syntax is strict + * XML, defined in the schema.xml specification. + */ +struct xml_t { + + /** + * implements the plugin interface. + */ + plugin_t plugin; +}; + +/** + * Create a xml plugin instance. + */ +plugin_t *plugin_create(); + +#endif /* XML_H_ @}*/ diff --git a/src/charon/processing/jobs/acquire_job.c b/src/charon/processing/jobs/acquire_job.c index 48a77f558..e066cbac5 100644 --- a/src/charon/processing/jobs/acquire_job.c +++ b/src/charon/processing/jobs/acquire_job.c @@ -1,10 +1,3 @@ -/** - * @file acquire_job.c - * - * @brief Implementation of acquire_job_t. - * - */ - /* * Copyright (C) 2006 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,8 @@ * 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. + * + * $Id$ */ #include "acquire_job.h" diff --git a/src/charon/processing/jobs/acquire_job.h b/src/charon/processing/jobs/acquire_job.h index 226966215..b256c7fc1 100644 --- a/src/charon/processing/jobs/acquire_job.h +++ b/src/charon/processing/jobs/acquire_job.h @@ -1,10 +1,3 @@ -/** - * @file acquire_job.h - * - * @brief Interface of acquire_job_t. - * - */ - /* * Copyright (C) 2006 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup acquire_job acquire_job + * @{ @ingroup jobs */ #ifndef ACQUIRE_JOB_H_ @@ -29,14 +29,9 @@ typedef struct acquire_job_t acquire_job_t; #include /** - * @brief Class representing an ACQUIRE Job. + * Class representing an ACQUIRE Job. * * This job initiates a CHILD SA on kernel request. - * - * @b Constructors: - * - acquire_job_create() - * - * @ingroup jobs */ struct acquire_job_t { /** @@ -46,15 +41,13 @@ struct acquire_job_t { }; /** - * @brief Creates a job of type ACQUIRE. + * Creates a job of type ACQUIRE. * * We use the reqid to find the routed CHILD_SA. * * @param reqid reqid of the CHILD_SA to acquire * @return acquire_job_t object - * - * @ingroup jobs */ acquire_job_t *acquire_job_create(u_int32_t reqid); -#endif /* REKEY_CHILD_SA_JOB_H_ */ +#endif /* REKEY_CHILD_SA_JOB_H_ @} */ diff --git a/src/charon/processing/jobs/callback_job.c b/src/charon/processing/jobs/callback_job.c index 53297916e..ae2236a3e 100644 --- a/src/charon/processing/jobs/callback_job.c +++ b/src/charon/processing/jobs/callback_job.c @@ -1,10 +1,3 @@ -/** - * @file callback_job.c - * - * @brief Implementation of callback_job_t. - * - */ - /* * Copyright (C) 2007 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,8 @@ * 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. + * + * $Id$ */ #include "callback_job.h" diff --git a/src/charon/processing/jobs/callback_job.h b/src/charon/processing/jobs/callback_job.h index 169f2d207..1fa9fa2d6 100644 --- a/src/charon/processing/jobs/callback_job.h +++ b/src/charon/processing/jobs/callback_job.h @@ -1,10 +1,3 @@ -/** - * @file callback_job.h - * - * @brief Interface of callback_job_t. - * - */ - /* * Copyright (C) 2007 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup callback_job callback_job + * @{ @ingroup jobs */ #ifndef CALLBACK_JOB_H_ @@ -32,12 +32,10 @@ typedef struct callback_job_t callback_job_t; typedef enum job_requeue_t job_requeue_t; /** - * @brief Job requeueing policy + * Job requeueing policy * * The job requeueing policy defines how a job is handled when the callback * function returns. - * - * @ingroup jobs */ enum job_requeue_t { @@ -58,20 +56,18 @@ enum job_requeue_t { }; /** - * @brief The callback function to use for the callback job. + * The callback function to use for the callback job. * * This is the function to use as callback for a callback job. It receives * a parameter supplied to the callback jobs constructor. * * @param data param supplied to job * @return requeing policy how to requeue the job - * - * @ingroup jobs */ typedef job_requeue_t (*callback_job_cb_t)(void *data); /** - * @brief Cleanup function to use for data cleanup. + * Cleanup function to use for data cleanup. * * The callback has an optional user argument which receives data. However, * this data may be cleaned up if it is allocated. This is the function @@ -79,22 +75,15 @@ typedef job_requeue_t (*callback_job_cb_t)(void *data); * * @param data param supplied to job * @return requeing policy how to requeue the job - * - * @ingroup jobs */ typedef void (*callback_job_cleanup_t)(void *data); /** - * @brief Class representing an callback Job. + * Class representing an callback Job. * * This is a special job which allows a simple callback function to * be executed by a thread of the thread pool. This allows simple execution * of asynchronous methods, without to manage threads. - * - * @b Constructors: - * - callback_job_create() - * - * @ingroup jobs */ struct callback_job_t { /** @@ -103,15 +92,13 @@ struct callback_job_t { job_t job_interface; /** - * @brief Cancel the jobs thread and wait for its termination. - * - * @param this calling object + * Cancel the jobs thread and wait for its termination. */ void (*cancel)(callback_job_t *this); }; /** - * @brief Creates a callback job. + * Creates a callback job. * * The cleanup function is called when the job gets destroyed to destroy * the associated data. @@ -124,12 +111,9 @@ struct callback_job_t { * @param cleanup destructor for data on destruction, or NULL * @param parent parent of this job * @return callback_job_t object - * - * @ingroup jobs */ callback_job_t *callback_job_create(callback_job_cb_t cb, void *data, callback_job_cleanup_t cleanup, callback_job_t *parent); -#endif /* CALLBACK_JOB_H_ */ - +#endif /* CALLBACK_JOB_H_ @} */ diff --git a/src/charon/processing/jobs/delete_child_sa_job.c b/src/charon/processing/jobs/delete_child_sa_job.c index 23f330293..e3492c73d 100644 --- a/src/charon/processing/jobs/delete_child_sa_job.c +++ b/src/charon/processing/jobs/delete_child_sa_job.c @@ -1,10 +1,3 @@ -/** - * @file delete_child_sa_job.c - * - * @brief Implementation of delete_child_sa_job_t. - * - */ - /* * Copyright (C) 2006 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,8 @@ * 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. + * + * $Id$ */ #include "delete_child_sa_job.h" diff --git a/src/charon/processing/jobs/delete_child_sa_job.h b/src/charon/processing/jobs/delete_child_sa_job.h index 0b90e008d..35d884be7 100644 --- a/src/charon/processing/jobs/delete_child_sa_job.h +++ b/src/charon/processing/jobs/delete_child_sa_job.h @@ -1,10 +1,3 @@ -/** - * @file delete_child_sa_job.h - * - * @brief Interface of delete_child_sa_job_t. - * - */ - /* * Copyright (C) 2006 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup delete_child_sa_job delete_child_sa_job + * @{ @ingroup jobs */ #ifndef DELETE_CHILD_SA_JOB_H_ @@ -32,14 +32,9 @@ typedef struct delete_child_sa_job_t delete_child_sa_job_t; /** - * @brief Class representing an DELETE_CHILD_SA Job. + * Class representing an DELETE_CHILD_SA Job. * * This job initiates the delete of a CHILD SA. - * - * @b Constructors: - * - delete_child_sa_job_create() - * - * @ingroup jobs */ struct delete_child_sa_job_t { /** @@ -49,7 +44,7 @@ struct delete_child_sa_job_t { }; /** - * @brief Creates a job of type DELETE_CHILD_SA. + * Creates a job of type DELETE_CHILD_SA. * * The CHILD_SA is identified by its reqid, protocol (AH/ESP) and its * inbound SPI. @@ -58,11 +53,9 @@ struct delete_child_sa_job_t { * @param protocol protocol of the CHILD_SA * @param spi security parameter index of the CHILD_SA * @return delete_child_sa_job_t object - * - * @ingroup jobs */ delete_child_sa_job_t *delete_child_sa_job_create(u_int32_t reqid, protocol_id_t protocol, u_int32_t spi); -#endif /* DELETE_CHILD_SA_JOB_H_ */ +#endif /* DELETE_CHILD_SA_JOB_H_ @} */ diff --git a/src/charon/processing/jobs/delete_ike_sa_job.c b/src/charon/processing/jobs/delete_ike_sa_job.c index 8d8c0cf36..a4d412fc5 100644 --- a/src/charon/processing/jobs/delete_ike_sa_job.c +++ b/src/charon/processing/jobs/delete_ike_sa_job.c @@ -1,10 +1,3 @@ -/** - * @file delete_ike_sa_job.c - * - * @brief Implementation of delete_ike_sa_job_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,8 @@ * 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. + * + * $Id$ */ #include "delete_ike_sa_job.h" diff --git a/src/charon/processing/jobs/delete_ike_sa_job.h b/src/charon/processing/jobs/delete_ike_sa_job.h index 11bb46e73..773305d0b 100644 --- a/src/charon/processing/jobs/delete_ike_sa_job.h +++ b/src/charon/processing/jobs/delete_ike_sa_job.h @@ -1,10 +1,3 @@ -/** - * @file delete_ike_sa_job.h - * - * @brief Interface of delete_ike_sa_job_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup delete_child_sa_job delete_child_sa_job + * @{ @ingroup jobs */ #ifndef DELETE_IKE_SA_JOB_H_ @@ -32,16 +32,11 @@ typedef struct delete_ike_sa_job_t delete_ike_sa_job_t; /** - * @brief Class representing an DELETE_IKE_SA Job. + * Class representing an DELETE_IKE_SA Job. * * This job is responsible for deleting established or half open IKE_SAs. * A half open IKE_SA is every IKE_SA which hasn't reache the SA_ESTABLISHED * state. - * - * @b Constructors: - * - delete_ike_sa_job_create() - * - * @ingroup jobs */ struct delete_ike_sa_job_t { @@ -52,15 +47,13 @@ struct delete_ike_sa_job_t { }; /** - * @brief Creates a job of type DELETE_IKE_SA. + * Creates a job of type DELETE_IKE_SA. * * @param ike_sa_id id of the IKE_SA to delete * @param delete_if_established should the IKE_SA be deleted if it is established? * @return created delete_ike_sa_job_t object - * - * @ingroup jobs */ delete_ike_sa_job_t *delete_ike_sa_job_create(ike_sa_id_t *ike_sa_id, bool delete_if_established); -#endif /* DELETE_IKE_SA_JOB_H_ */ +#endif /* DELETE_IKE_SA_JOB_H_ @} */ diff --git a/src/charon/processing/jobs/initiate_mediation_job.c b/src/charon/processing/jobs/initiate_mediation_job.c index b8d516e22..99da4d1ed 100644 --- a/src/charon/processing/jobs/initiate_mediation_job.c +++ b/src/charon/processing/jobs/initiate_mediation_job.c @@ -1,10 +1,3 @@ -/** - * @file initiate_mediation_job.c - * - * @brief Implementation of initiate_mediation_job_t. - * - */ - /* * Copyright (C) 2007 Tobias Brunner * Hochschule fuer Technik Rapperswil @@ -18,9 +11,10 @@ * 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. + * + * $Id$ */ - #include "initiate_mediation_job.h" #include diff --git a/src/charon/processing/jobs/initiate_mediation_job.h b/src/charon/processing/jobs/initiate_mediation_job.h index 9fb3b0f7d..dbc6cca15 100644 --- a/src/charon/processing/jobs/initiate_mediation_job.h +++ b/src/charon/processing/jobs/initiate_mediation_job.h @@ -1,9 +1,3 @@ -/** - * @file initiate_mediation_job.h - * - * @brief Interface of initiate_mediation_job_t. - */ - /* * Copyright (C) 2007 Tobias Brunner * Hochschule fuer Technik Rapperswil @@ -17,6 +11,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup initiate_mediation_job initiate_mediation_job + * @{ @ingroup jobs */ #ifndef INITIATE_MEDIATION_JOB_H_ @@ -29,15 +30,10 @@ typedef struct initiate_mediation_job_t initiate_mediation_job_t; #include /** - * @brief Class representing a INITIATE_MEDIATION Job. + * Class representing a INITIATE_MEDIATION Job. * * This job will initiate a mediation on behalf of a mediated connection. * If required the mediation connection is established. - * - * @b Constructors: - * - initiate_mediation_job_create() - * - * @ingroup jobs */ struct initiate_mediation_job_t { /** @@ -47,28 +43,24 @@ struct initiate_mediation_job_t { }; /** - * @brief Creates a job of type INITIATE_MEDIATION. + * Creates a job of type INITIATE_MEDIATION. * * @param ike_sa_id identification of the ike_sa as ike_sa_id_t object (gets cloned) * @param child_cfg child config of the child_sa (gets cloned) * @return job object - * - * @ingroup jobs */ initiate_mediation_job_t *initiate_mediation_job_create(ike_sa_id_t *ike_sa_id, child_cfg_t *child_cfg); /** - * @brief Creates a special job of type INITIATE_MEDIATION that reinitiates a + * Creates a special job of type INITIATE_MEDIATION that reinitiates a * specific connection. * * @param mediation_sa_id identification of the mediation sa (gets cloned) * @param mediated_sa_id identification of the mediated sa (gets cloned) * @return job object - * - * @ingroup jobs */ initiate_mediation_job_t *reinitiate_mediation_job_create(ike_sa_id_t *mediation_sa_id, ike_sa_id_t *mediated_sa_id); -#endif /*INITIATE_MEDIATION_JOB_H_*/ +#endif /*INITIATE_MEDIATION_JOB_H_ @} */ diff --git a/src/charon/processing/jobs/job.h b/src/charon/processing/jobs/job.h index 1826c53b4..dc7821616 100644 --- a/src/charon/processing/jobs/job.h +++ b/src/charon/processing/jobs/job.h @@ -1,10 +1,3 @@ -/** - * @file job.h - * - * @brief Interface job_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup job job + * @{ @ingroup jobs */ #ifndef JOB_H_ @@ -28,38 +28,27 @@ typedef struct job_t job_t; #include - /** - * @brief Job-Interface as it is stored in the job queue. - * - * @b Constructors: - * - None, use specific implementation of the interface. - * - * @ingroup jobs + * Job-Interface as it is stored in the job queue. */ struct job_t { /** - * @brief Execute a job. + * Execute a job. * * The processing facility executes a job using this method. Jobs are * one-shot, they destroy themself after execution, so don't use a job * once it has been executed. - * - * @param this calling object */ void (*execute) (job_t *this); /** - * @brief Destroy a job. + * Destroy a job. * * Is only called whenever a job was not executed (e.g. due daemon shutdown). * After execution, jobs destroy themself. - * - * @param job_t calling object */ void (*destroy) (job_t *job); }; -#endif /* JOB_H_ */ - +#endif /* JOB_H_ @} */ diff --git a/src/charon/processing/jobs/mediation_job.c b/src/charon/processing/jobs/mediation_job.c index 3b9d363d7..6f3e004c6 100644 --- a/src/charon/processing/jobs/mediation_job.c +++ b/src/charon/processing/jobs/mediation_job.c @@ -1,10 +1,3 @@ -/** - * @file mediation_job.c - * - * @brief Implementation of mediation_job_t. - * - */ - /* * Copyright (C) 2007 Tobias Brunner * Hochschule fuer Technik Rapperswil @@ -18,9 +11,10 @@ * 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. + * + * $Id$ */ - #include "mediation_job.h" #include diff --git a/src/charon/processing/jobs/mediation_job.h b/src/charon/processing/jobs/mediation_job.h index 6130b2e27..8bf8a7e63 100644 --- a/src/charon/processing/jobs/mediation_job.h +++ b/src/charon/processing/jobs/mediation_job.h @@ -1,9 +1,3 @@ -/** - * @file mediation_job.h - * - * @brief Interface of mediation_job_t. - */ - /* * Copyright (C) 2007 Tobias Brunner * Hochschule fuer Technik Rapperswil @@ -17,6 +11,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup mediation_job mediation_job + * @{ @ingroup jobs */ #ifndef MEDIATION_JOB_H_ @@ -30,14 +31,9 @@ typedef struct mediation_job_t mediation_job_t; #include /** - * @brief Class representing a MEDIATION Job. + * Class representing a MEDIATION Job. * * This job handles the mediation on the mediation server. - * - * @b Constructors: - * - mediation_job_create() - * - * @ingroup jobs */ struct mediation_job_t { /** @@ -47,7 +43,7 @@ struct mediation_job_t { }; /** - * @brief Creates a job of type MEDIATION. + * Creates a job of type MEDIATION. * * Parameters get cloned. * @@ -58,8 +54,6 @@ struct mediation_job_t { * @param endpoints list of submitted endpoints * @param response TRUE if this is a response * @return job object - * - * @ingroup jobs */ mediation_job_t *mediation_job_create(identification_t *peer_id, identification_t *requester, chunk_t session_id, chunk_t session_key, @@ -67,7 +61,7 @@ mediation_job_t *mediation_job_create(identification_t *peer_id, /** - * @brief Creates a special job of type MEDIATION that is used to send a callback + * Creates a special job of type MEDIATION that is used to send a callback * notification to a peer. * * Parameters get cloned. @@ -75,10 +69,8 @@ mediation_job_t *mediation_job_create(identification_t *peer_id, * @param requester ID of the waiting peer * @param peer_id ID of the requested peer * @return job object - * - * @ingroup jobs */ mediation_job_t *mediation_callback_job_create(identification_t *requester, identification_t *peer_id); -#endif /*MEDIATION_JOB_H_*/ +#endif /*MEDIATION_JOB_H_ @} */ diff --git a/src/charon/processing/jobs/process_message_job.c b/src/charon/processing/jobs/process_message_job.c index 91e7a80bf..9d7ab04f3 100644 --- a/src/charon/processing/jobs/process_message_job.c +++ b/src/charon/processing/jobs/process_message_job.c @@ -1,10 +1,3 @@ -/** - * @file process_message_job.h - * - * @brief Implementation of process_message_job_t. - * - */ - /* * Copyright (C) 2005-2007 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,9 +12,10 @@ * 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. + * + * $Id$ */ - #include "process_message_job.h" #include diff --git a/src/charon/processing/jobs/process_message_job.h b/src/charon/processing/jobs/process_message_job.h index 5bb18155a..31c2d11fd 100644 --- a/src/charon/processing/jobs/process_message_job.h +++ b/src/charon/processing/jobs/process_message_job.h @@ -1,10 +1,3 @@ -/** - * @file process_message_job.h - * - * @brief Interface of process_message_job_t. - * - */ - /* * Copyright (C) 2005-2007 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup process_message_job process_message_job + * @{ @ingroup jobs */ #ifndef PROCESS_MESSAGE_JOB_H_ @@ -31,12 +31,7 @@ typedef struct process_message_job_t process_message_job_t; #include /** - * @brief Class representing an PROCESS_MESSAGE job. - * - * @b Constructors: - * - process_message_job_create() - * - * @ingroup jobs + * Class representing an PROCESS_MESSAGE job. */ struct process_message_job_t { /** @@ -46,13 +41,11 @@ struct process_message_job_t { }; /** - * @brief Creates a job of type PROCESS_MESSAGE. + * Creates a job of type PROCESS_MESSAGE. * * @param message message to process * @return created process_message_job_t object - * - * @ingroup jobs */ process_message_job_t *process_message_job_create(message_t *message); -#endif /*PROCESS_MESSAGE_JOB_H_*/ +#endif /*PROCESS_MESSAGE_JOB_H_ @} */ diff --git a/src/charon/processing/jobs/rekey_child_sa_job.c b/src/charon/processing/jobs/rekey_child_sa_job.c index f754e5a1f..05da22576 100644 --- a/src/charon/processing/jobs/rekey_child_sa_job.c +++ b/src/charon/processing/jobs/rekey_child_sa_job.c @@ -1,10 +1,3 @@ -/** - * @file rekey_child_sa_job.c - * - * @brief Implementation of rekey_child_sa_job_t. - * - */ - /* * Copyright (C) 2006 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,8 @@ * 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. + * + * $Id$ */ #include "rekey_child_sa_job.h" diff --git a/src/charon/processing/jobs/rekey_child_sa_job.h b/src/charon/processing/jobs/rekey_child_sa_job.h index df86070bc..db1357abe 100644 --- a/src/charon/processing/jobs/rekey_child_sa_job.h +++ b/src/charon/processing/jobs/rekey_child_sa_job.h @@ -1,10 +1,3 @@ -/** - * @file rekey_child_sa_job.h - * - * @brief Interface of rekey_child_sa_job_t. - * - */ - /* * Copyright (C) 2006 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup rekey_child_sa_job rekey_child_sa_job + * @{ @ingroup jobs */ #ifndef REKEY_CHILD_SA_JOB_H_ @@ -31,14 +31,9 @@ typedef struct rekey_child_sa_job_t rekey_child_sa_job_t; #include /** - * @brief Class representing an REKEY_CHILD_SA Job. + * Class representing an REKEY_CHILD_SA Job. * * This job initiates the rekeying of a CHILD SA. - * - * @b Constructors: - * - rekey_child_sa_job_create() - * - * @ingroup jobs */ struct rekey_child_sa_job_t { /** @@ -48,7 +43,7 @@ struct rekey_child_sa_job_t { }; /** - * @brief Creates a job of type REKEY_CHILD_SA. + * Creates a job of type REKEY_CHILD_SA. * * The CHILD_SA is identified by its protocol (AH/ESP) and its * inbound SPI. @@ -57,9 +52,8 @@ struct rekey_child_sa_job_t { * @param protocol protocol of the CHILD_SA * @param spi security parameter index of the CHILD_SA * @return rekey_child_sa_job_t object - * - * @ingroup jobs */ -rekey_child_sa_job_t *rekey_child_sa_job_create(u_int32_t reqid, protocol_id_t protocol, u_int32_t spi); - -#endif /* REKEY_CHILD_SA_JOB_H_ */ +rekey_child_sa_job_t *rekey_child_sa_job_create(u_int32_t reqid, + protocol_id_t protocol, + u_int32_t spi); +#endif /* REKEY_CHILD_SA_JOB_H_ @} */ diff --git a/src/charon/processing/jobs/rekey_ike_sa_job.c b/src/charon/processing/jobs/rekey_ike_sa_job.c index 020c3cce8..0960f5166 100644 --- a/src/charon/processing/jobs/rekey_ike_sa_job.c +++ b/src/charon/processing/jobs/rekey_ike_sa_job.c @@ -1,10 +1,3 @@ -/** - * @file rekey_ike_sa_job.c - * - * @brief Implementation of rekey_ike_sa_job_t. - * - */ - /* * Copyright (C) 2006 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,13 +11,14 @@ * 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. + * + * $Id$ */ - + #include "rekey_ike_sa_job.h" #include - typedef struct private_rekey_ike_sa_job_t private_rekey_ike_sa_job_t; /** diff --git a/src/charon/processing/jobs/rekey_ike_sa_job.h b/src/charon/processing/jobs/rekey_ike_sa_job.h index 4031b3813..fa45460cc 100644 --- a/src/charon/processing/jobs/rekey_ike_sa_job.h +++ b/src/charon/processing/jobs/rekey_ike_sa_job.h @@ -1,10 +1,3 @@ -/** - * @file rekey_ike_sa_job.h - * - * @brief Interface of rekey_ike_sa_job_t. - * - */ - /* * Copyright (C) 2006 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup rekey_ike_sa_job rekey_ike_sa_job + * @{ @ingroup jobs */ #ifndef REKEY_IKE_SA_JOB_H_ @@ -30,14 +30,9 @@ typedef struct rekey_ike_sa_job_t rekey_ike_sa_job_t; #include /** - * @brief Class representing an REKEY_IKE_SA Job. + * Class representing an REKEY_IKE_SA Job. * * This job initiates the rekeying of an IKE_SA. - * - * @b Constructors: - * - rekey_ike_sa_job_create() - * - * @ingroup jobs */ struct rekey_ike_sa_job_t { /** @@ -47,14 +42,12 @@ struct rekey_ike_sa_job_t { }; /** - * @brief Creates a job of type REKEY_IKE_SA. + * Creates a job of type REKEY_IKE_SA. * * @param ike_sa_id ID of the IKE_SA to rekey * @param reauth TRUE to reauthenticate peer, FALSE for rekeying only * @return rekey_ike_sa_job_t object - * - * @ingroup jobs */ rekey_ike_sa_job_t *rekey_ike_sa_job_create(ike_sa_id_t *ike_sa_id, bool reauth); -#endif /* REKEY_IKE_SA_JOB_H_ */ +#endif /* REKEY_IKE_SA_JOB_H_ @} */ diff --git a/src/charon/processing/jobs/retransmit_job.c b/src/charon/processing/jobs/retransmit_job.c index 8c15aa651..cd7652617 100644 --- a/src/charon/processing/jobs/retransmit_job.c +++ b/src/charon/processing/jobs/retransmit_job.c @@ -1,10 +1,3 @@ -/** - * @file retransmit_job.c - * - * @brief Implementation of retransmit_job_t. - * - */ - /* * Copyright (C) 2005-2007 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,8 @@ * 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. + * + * $Id$ */ #include "retransmit_job.h" diff --git a/src/charon/processing/jobs/retransmit_job.h b/src/charon/processing/jobs/retransmit_job.h index 93bb548e7..bbacf0094 100644 --- a/src/charon/processing/jobs/retransmit_job.h +++ b/src/charon/processing/jobs/retransmit_job.h @@ -1,10 +1,3 @@ -/** - * @file retransmit_job.h - * - * @brief Interface of retransmit_job_t. - * - */ - /* * Copyright (C) 2005-2007 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup retransmit_job retransmit_job + * @{ @ingroup jobs */ #ifndef RETRANSMIT_JOB_H_ @@ -31,16 +31,11 @@ typedef struct retransmit_job_t retransmit_job_t; #include /** - * @brief Class representing an retransmit Job. + * Class representing an retransmit Job. * * This job is scheduled every time a request is sent over the * wire. If the response to the request is not received at schedule * time, the retransmission will be initiated. - * - * @b Constructors: - * - retransmit_job_create() - * - * @ingroup jobs */ struct retransmit_job_t { /** @@ -50,15 +45,13 @@ struct retransmit_job_t { }; /** - * @brief Creates a job of type retransmit. + * Creates a job of type retransmit. * * @param message_id message_id of the request to resend * @param ike_sa_id identification of the ike_sa as ike_sa_id_t * @return retransmit_job_t object - * - * @ingroup jobs */ retransmit_job_t *retransmit_job_create(u_int32_t message_id, ike_sa_id_t *ike_sa_id); -#endif /* RETRANSMIT_JOB_H_ */ +#endif /* RETRANSMIT_JOB_H_ @} */ diff --git a/src/charon/processing/jobs/roam_job.c b/src/charon/processing/jobs/roam_job.c index 842f57405..3574b3539 100644 --- a/src/charon/processing/jobs/roam_job.c +++ b/src/charon/processing/jobs/roam_job.c @@ -1,10 +1,3 @@ -/** - * @file roam_job.c - * - * @brief Implementation of roam_job_t. - * - */ - /* * Copyright (C) 2007 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,9 +11,10 @@ * 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. + * + * $Id$ */ - #include #include "roam_job.h" diff --git a/src/charon/processing/jobs/roam_job.h b/src/charon/processing/jobs/roam_job.h index 293b09f08..4dafdd532 100644 --- a/src/charon/processing/jobs/roam_job.h +++ b/src/charon/processing/jobs/roam_job.h @@ -1,9 +1,3 @@ -/** - * @file roam_job.h - * - * @brief Interface of roam_job_t. - */ - /* * Copyright (C) 2007 Martin Willi * Hochschule fuer Technik Rapperswil @@ -17,6 +11,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup roam_job roam_job + * @{ @ingroup jobs */ #ifndef ROAM_JOB_H_ @@ -29,15 +30,10 @@ typedef struct roam_job_t roam_job_t; #include /** - * @brief A job to inform IKE_SAs about changed local address setup. + * A job to inform IKE_SAs about changed local address setup. * * If a local address appears or disappears, the kernel fires this job to * update all IKE_SAs. - * - * @b Constructors: - * - roam_job_create() - * - * @ingroup jobs */ struct roam_job_t { @@ -48,14 +44,11 @@ struct roam_job_t { }; /** - * @brief Creates a job to inform IKE_SAs about an updated address list. + * Creates a job to inform IKE_SAs about an updated address list. * * @param address TRUE if address list changed, FALSE if routing changed * @return initiate_ike_sa_job_t object - * - * @ingroup jobs */ roam_job_t *roam_job_create(bool address); -#endif /*ROAM_JOB_H_*/ - +#endif /*ROAM_JOB_H_ @} */ diff --git a/src/charon/processing/jobs/send_dpd_job.c b/src/charon/processing/jobs/send_dpd_job.c index d9c457ab6..c74c4c0df 100644 --- a/src/charon/processing/jobs/send_dpd_job.c +++ b/src/charon/processing/jobs/send_dpd_job.c @@ -1,10 +1,3 @@ -/** - * @file send_dpd_job.c - * - * @brief Implementation of send_dpd_job_t. - * - */ - /* * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger * Hochschule fuer Technik Rapperswil @@ -18,9 +11,10 @@ * 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. + * + * $Id$ */ - #include #include "send_dpd_job.h" diff --git a/src/charon/processing/jobs/send_dpd_job.h b/src/charon/processing/jobs/send_dpd_job.h index 0e4059131..73aa720b3 100644 --- a/src/charon/processing/jobs/send_dpd_job.h +++ b/src/charon/processing/jobs/send_dpd_job.h @@ -1,9 +1,3 @@ -/** - * @file send_dpd_job.h - * - * @brief Interface of send_dpd_job_t. - */ - /* * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger * Hochschule fuer Technik Rapperswil @@ -17,6 +11,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup send_dpd_job send_dpd_job + * @{ @ingroup jobs */ #ifndef SEND_DPD_JOB_H_ @@ -29,16 +30,11 @@ typedef struct send_dpd_job_t send_dpd_job_t; #include /** - * @brief Class representing a SEND_DPD Job. + * Class representing a SEND_DPD Job. * * Job to periodically send a Dead Peer Detection (DPD) request, * ie. an IKE request with no payloads other than the encrypted payload * required by the syntax. - * - * @b Constructors: - * - send_dpd_job_create() - * - * @ingroup jobs */ struct send_dpd_job_t { /** @@ -48,13 +44,11 @@ struct send_dpd_job_t { }; /** - * @brief Creates a job of type SEND_DPD. + * Creates a job of type SEND_DPD. * * @param ike_sa_id identification of the ike_sa as ike_sa_id_t object (gets cloned) * @return initiate_ike_sa_job_t object - * - * @ingroup jobs */ send_dpd_job_t *send_dpd_job_create(ike_sa_id_t *ike_sa_id); -#endif /*SEND_DPD_JOB_H_*/ +#endif /*SEND_DPD_JOB_H_ @} */ diff --git a/src/charon/processing/jobs/send_keepalive_job.c b/src/charon/processing/jobs/send_keepalive_job.c index 34198deb0..04408de76 100644 --- a/src/charon/processing/jobs/send_keepalive_job.c +++ b/src/charon/processing/jobs/send_keepalive_job.c @@ -1,10 +1,3 @@ -/** - * @file send_keepalive_job.c - * - * @brief Implementation of send_keepalive_job_t. - * - */ - /* * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger * Hochschule fuer Technik Rapperswil @@ -18,9 +11,10 @@ * 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. + * + * $Id$ */ - #include #include "send_keepalive_job.h" diff --git a/src/charon/processing/jobs/send_keepalive_job.h b/src/charon/processing/jobs/send_keepalive_job.h index e8d214aed..e3bb9f9e4 100644 --- a/src/charon/processing/jobs/send_keepalive_job.h +++ b/src/charon/processing/jobs/send_keepalive_job.h @@ -1,9 +1,3 @@ -/** - * @file send_keepalive_job.h - * - * @brief Interface of send_keepalive_job_t. - */ - /* * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger * Hochschule fuer Technik Rapperswil @@ -17,6 +11,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup send_keepalive_job send_keepalive_job + * @{ @ingroup jobs */ #ifndef SEND_KEEPALIVE_JOB_H_ @@ -29,15 +30,10 @@ typedef struct send_keepalive_job_t send_keepalive_job_t; #include /** - * @brief Class representing a SEND_KEEPALIVE Job. + * Class representing a SEND_KEEPALIVE Job. * * This job will send a NAT keepalive packet if the IKE SA is still alive, * and reinsert itself into the event queue. - * - * @b Constructors: - * - send_keepalive_job_create() - * - * @ingroup jobs */ struct send_keepalive_job_t { /** @@ -47,13 +43,11 @@ struct send_keepalive_job_t { }; /** - * @brief Creates a job of type SEND_KEEPALIVE. + * Creates a job of type SEND_KEEPALIVE. * * @param ike_sa_id identification of the ike_sa as ike_sa_id_t object (gets cloned) * @return initiate_ike_sa_job_t object - * - * @ingroup jobs */ send_keepalive_job_t *send_keepalive_job_create(ike_sa_id_t *ike_sa_id); -#endif /*SEND_KEEPALIVE_JOB_H_*/ +#endif /*SEND_KEEPALIVE_JOB_H_ @} */ diff --git a/src/charon/processing/processor.c b/src/charon/processing/processor.c index b3815eeb1..bfae7bdff 100644 --- a/src/charon/processing/processor.c +++ b/src/charon/processing/processor.c @@ -1,10 +1,3 @@ -/** - * @file processor.c - * - * @brief Implementation of processor_t. - * - */ - /* * Copyright (C) 2005-2007 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,8 @@ * 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. + * + * $Id$ */ #include @@ -35,7 +30,7 @@ typedef struct private_processor_t private_processor_t; /** - * @brief Private data of processor_t class. + * Private data of processor_t class. */ struct private_processor_t { /** diff --git a/src/charon/processing/processor.h b/src/charon/processing/processor.h index f12c7f10e..342cfa048 100644 --- a/src/charon/processing/processor.h +++ b/src/charon/processing/processor.h @@ -1,10 +1,3 @@ -/** - * @file processor.h - * - * @brief Interface of processor_t. - * - */ - /* * Copyright (C) 2005-2007 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup processor processor + * @{ @ingroup processing */ #ifndef PROCESSOR_H_ @@ -32,80 +32,65 @@ typedef struct processor_t processor_t; #include /** - * @brief The processor uses threads to process queued jobs. - * - * @b Constructors: - * - processor_create() - * - * @ingroup processing + * The processor uses threads to process queued jobs. */ struct processor_t { /** - * @brief Get the total number of threads used by the processor. - * - * @param this calling object + * Get the total number of threads used by the processor. + * * @return size of thread pool */ u_int (*get_total_threads) (processor_t *this); /** - * @brief Get the number of threads currently waiting. - * - * @param this calling object + * Get the number of threads currently waiting. + * * @return number of idle threads */ u_int (*get_idle_threads) (processor_t *this); /** - * @brief Get the number of queued jobs. + * Get the number of queued jobs. * - * @param this calling object * @returns number of items in queue */ u_int (*get_job_load) (processor_t *this); /** - * @brief Adds a job to the queue. + * Adds a job to the queue. * * This function is non blocking and adds a job_t to the queue. * - * @param this calling object * @param job job to add to the queue */ void (*queue_job) (processor_t *this, job_t *job); /** - * @brief Set the number of threads to use in the processor. + * Set the number of threads to use in the processor. * * If the number of threads is smaller than number of currently running * threads, thread count is decreased. Use 0 to disable the processor. * This call blocks if it decreases thread count until threads have * terminated, so make sure there are not too many blocking jobs. * - * @param this calling object * @param count number of threads to allocate */ void (*set_threads)(processor_t *this, u_int count); /** - * @brief Destroy a processor object. - * - * @param processor calling object + * Destroy a processor object. */ void (*destroy) (processor_t *processor); }; /** - * @brief Create the thread pool without any threads. + * Create the thread pool without any threads. * * Use the set_threads method to start processing jobs. * * @return processor_t object - * - * @ingroup processing */ processor_t *processor_create(); -#endif /*PROCESSOR_H_*/ - +#endif /*PROCESSOR_H_ @} */ diff --git a/src/charon/processing/scheduler.c b/src/charon/processing/scheduler.c index ededb479a..bbf1dc1a4 100644 --- a/src/charon/processing/scheduler.c +++ b/src/charon/processing/scheduler.c @@ -1,10 +1,3 @@ -/** - * @file scheduler.c - * - * @brief Implementation of scheduler_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,8 @@ * 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. + * + * $Id$ */ #include diff --git a/src/charon/processing/scheduler.h b/src/charon/processing/scheduler.h index 7bde6e638..441f053cf 100644 --- a/src/charon/processing/scheduler.h +++ b/src/charon/processing/scheduler.h @@ -1,10 +1,3 @@ -/** - * @file scheduler.h - * - * @brief Interface of scheduler_t. - * - */ - /* * Copyright (C) 2005-2007 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup scheduler scheduler + * @{ @ingroup processing */ #ifndef SCHEDULER_H_ @@ -30,52 +30,40 @@ typedef struct scheduler_t scheduler_t; #include /** - * @brief The scheduler queues and executes timed events. + * The scheduler queues and executes timed events. * * The scheduler stores timed events and passes them to the processor. - * - * @b Constructors: - * - scheduler_create() - * - * @ingroup processing */ struct scheduler_t { /** - * @brief Adds a event to the queue, using a relative time offset. + * Adds a event to the queue, using a relative time offset. * * Schedules a job for execution using a relative time offset. * - * @param this calling object * @param job job to schedule * @param time relative to to schedule job (in ms) */ void (*schedule_job) (scheduler_t *this, job_t *job, u_int32_t time); /** - * @brief Returns number of jobs scheduled. + * Returns number of jobs scheduled. * - * @param this calling object * @return number of scheduled jobs */ u_int (*get_job_load) (scheduler_t *this); /** - * @brief Destroys a scheduler object. - * - * @param this calling object + * Destroys a scheduler object. */ void (*destroy) (scheduler_t *this); }; /** - * @brief Create a scheduler. + * Create a scheduler. * * @return scheduler_t object - * - * @ingroup processing */ scheduler_t *scheduler_create(void); -#endif /*SCHEDULER_H_*/ - +#endif /*SCHEDULER_H_ @} */ diff --git a/src/charon/sa/authenticators/authenticator.c b/src/charon/sa/authenticators/authenticator.c index 707aae9ad..fc528ff54 100644 --- a/src/charon/sa/authenticators/authenticator.c +++ b/src/charon/sa/authenticators/authenticator.c @@ -1,10 +1,3 @@ -/** - * @file authenticator.c - * - * @brief Generic constructor for authenticators. - * - */ - /* * Copyright (C) 2006 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,8 @@ * 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. + * + * $Id$ */ #include diff --git a/src/charon/sa/authenticators/authenticator.h b/src/charon/sa/authenticators/authenticator.h index c7b0fc81a..d0286be3e 100644 --- a/src/charon/sa/authenticators/authenticator.h +++ b/src/charon/sa/authenticators/authenticator.h @@ -1,10 +1,3 @@ -/** - * @file authenticator.h - * - * @brief Interface of authenticator_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup authenticator authenticator + * @{ @ingroup authenticators */ #ifndef AUTHENTICATOR_H_ @@ -33,8 +33,6 @@ typedef struct authenticator_t authenticator_t; /** * Method to use for authentication. - * - * @ingroup authenticators */ enum auth_method_t { /** @@ -65,29 +63,21 @@ enum auth_method_t { /** * enum names for auth_method_t. - * - * @ingroup authenticators */ extern enum_name_t *auth_method_names; /** - * @brief Authenticator interface implemented by the various authenticators. + * Authenticator interface implemented by the various authenticators. * * Currently the following two AUTH methods are supported: * - shared key message integrity code (AUTH_PSK) * - RSA digital signature (AUTH_RSA) - * - * @b Constructors: - * - authenticator_create() - * - * @ingroup authenticators */ struct authenticator_t { /** - * @brief Verify a received authentication payload. + * Verify a received authentication payload. * - * @param this calling object * @param ike_sa_init binary representation of received ike_sa_init * @param my_nonce the sent nonce * @param auth_payload authentication payload to verify @@ -102,9 +92,8 @@ struct authenticator_t { chunk_t my_nonce, auth_payload_t *auth_payload); /** - * @brief Build an authentication payload to send to the other peer. + * Build an authentication payload to send to the other peer. * - * @param this calling object * @param ike_sa_init binary representation of sent ike_sa_init * @param other_nonce the received nonce * @param[out] auth_payload the resulting authentication payload @@ -117,23 +106,19 @@ struct authenticator_t { chunk_t other_nonce, auth_payload_t **auth_payload); /** - * @brief Destroys a authenticator_t object. - * - * @param this calling object + * Destroys a authenticator_t object. */ void (*destroy) (authenticator_t *this); }; /** - * @brief Creates an authenticator for the specified auth method. + * Creates an authenticator for the specified auth method. * * @param ike_sa associated ike_sa * @param auth_method authentication method to use for build()/verify() * * @return authenticator_t object - * - * @ingroup authenticators */ authenticator_t *authenticator_create(ike_sa_t *ike_sa, auth_method_t auth_method); -#endif /* AUTHENTICATOR_H_ */ +#endif /* AUTHENTICATOR_H_ @} */ diff --git a/src/charon/sa/authenticators/eap/eap_aka.c b/src/charon/sa/authenticators/eap/eap_aka.c deleted file mode 100644 index 8fb1f85cd..000000000 --- a/src/charon/sa/authenticators/eap/eap_aka.c +++ /dev/null @@ -1,1440 +0,0 @@ -/** - * @file eap_aka.c - * - * @brief Implementation of eap_aka_t. - * - */ - -/* - * Copyright (C) 2006 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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. - */ - - -/* The EAP-AKA method uses it's own simple parser for processing EAP-AKA - * payloads, as the IKEv2 parser is not suitable for that job. There are - * two simple methods for parsing payloads, read_header() and read_attribute(). - * Every EAP-AKA payload consists of a header and a list of attributes. Those - * functions mentioned read the data and return the type of the found - * attribute/EAP-AKA-type. For generating a EAP-AKA message, we have a - * build_aka_payload(), which builds the whole message from a variable - * argument list containing its attributes. - * The processing of messages is split up in various functions: - * - peer_process() - General processing multiplexer for the peer - * - peer_process_challenge() - Specific AKA-Challenge processor - * - peer_process_notification() - Processing of AKA-Notification - * - server_process() - General processing multiplexer for the server - * - peer_process_challenge() - Processing of a received Challenge response - * - peer_process_synchronize() - Process a sequence number synchronization - * - server_initiate() - Initiation method for the server, calls - * - server_initiate_challenge() - Initiation of AKA-Challenge - */ - -#include -#include -#include -#include - -#include "eap_aka.h" - -#include -#include -#include -#include -#include - -/* Use test vectors specified in S.S0055 -#define TEST_VECTORS */ - -#define RAND_LENGTH 16 -#define RES_LENGTH 16 -#define SQN_LENGTH 6 -#define K_LENGTH 16 -#define MAC_LENGTH 8 -#define CK_LENGTH 16 -#define IK_LENGTH 16 -#define AK_LENGTH 6 -#define AMF_LENGTH 2 -#define FMK_LENGTH 4 -#define AUTN_LENGTH (SQN_LENGTH + AMF_LENGTH + MAC_LENGTH) -#define AUTS_LENGTH (SQN_LENGTH + MAC_LENGTH) -#define PAYLOAD_LENGTH 64 -#define MK_LENGTH 20 -#define MSK_LENGTH 64 -#define EMSK_LENGTH 64 -#define KAUTH_LENGTH 16 -#define KENCR_LENGTH 16 -#define AT_MAC_LENGTH 16 - -#define F1 0x42 -#define F1STAR 0x43 -#define F2 0x44 -#define F3 0x45 -#define F4 0x46 -#define F5 0x47 -#define F5STAR 0x48 - -ENUM_BEGIN(aka_subtype_names, AKA_CHALLENGE, AKA_IDENTITY, - "AKA_CHALLENGE", - "AKA_AUTHENTICATION_REJECT", - "AKA_3", - "AKA_SYNCHRONIZATION_FAILURE", - "AKA_IDENTITY"); -ENUM_NEXT(aka_subtype_names, AKA_NOTIFICATION, AKA_CLIENT_ERROR, AKA_IDENTITY, - "AKA_NOTIFICATION", - "AKA_REAUTHENTICATION", - "AKA_CLIENT_ERROR"); -ENUM_END(aka_subtype_names, AKA_CLIENT_ERROR); - - -ENUM_BEGIN(aka_attribute_names, AT_END, AT_CLIENT_ERROR_CODE, - "AT_END", - "AT_0", - "AT_RAND", - "AT_AUTN", - "AT_RES", - "AT_AUTS", - "AT_5", - "AT_PADDING", - "AT_NONCE_MT", - "AT_8", - "AT_9", - "AT_PERMANENT_ID_REQ", - "AT_MAC", - "AT_NOTIFICATION", - "AT_ANY_ID_REQ", - "AT_IDENTITY", - "AT_VERSION_LIST", - "AT_SELECTED_VERSION", - "AT_FULLAUTH_ID_REQ", - "AT_18", - "AT_COUNTER", - "AT_COUNTER_TOO_SMALL", - "AT_NONCE_S", - "AT_CLIENT_ERROR_CODE"); -ENUM_NEXT(aka_attribute_names, AT_IV, AT_RESULT_IND, AT_CLIENT_ERROR_CODE, - "AT_IV", - "AT_ENCR_DATA", - "AT_131", - "AT_NEXT_PSEUDONYM", - "AT_NEXT_REAUTH_ID", - "AT_CHECKCODE", - "AT_RESULT_IND"); -ENUM_END(aka_attribute_names, AT_RESULT_IND); - - -typedef struct private_eap_aka_t private_eap_aka_t; - -/** - * Private data of an eap_aka_t object. - */ -struct private_eap_aka_t { - - /** - * Public authenticator_t interface. - */ - eap_aka_t public; - - /** - * ID of the server - */ - identification_t *server; - - /** - * ID of the peer - */ - identification_t *peer; - - /** - * Key for EAP MAC - */ - chunk_t k_auth; - - /** - * Key for EAP encryption - */ - chunk_t k_encr; - - /** - * MSK - */ - chunk_t msk; - - /** - * Extendend MSK - */ - chunk_t emsk; - - /** - * Expected result from client XRES - */ - chunk_t xres; - - /** - * Shared secret K from ipsec.conf (padded) - */ - chunk_t k; - - /** - * random value RAND generated by server - */ - chunk_t rand; -}; - -/** Family key, as proposed in S.S0055 */ -static u_int8_t fmk_buf[] = {0x41, 0x48, 0x41, 0x47}; -static chunk_t fmk = chunk_from_buf(fmk_buf); - -/** Authentication management field */ -static u_int8_t amf_buf[] = {0x00, 0x01}; -static chunk_t amf = chunk_from_buf(amf_buf); - -/** AT_CLIENT_ERROR_CODE AKA attribute */ -static u_int8_t client_error_code_buf[] = {0, 0}; -static chunk_t client_error_code = chunk_from_buf(client_error_code_buf); - -/** previously used sqn by peer, next one must be greater */ -static u_int8_t peer_sqn_buf[6]; -static chunk_t peer_sqn = chunk_from_buf(peer_sqn_buf); - -/** set SQN to the current time */ -static void update_sqn(u_int8_t *sqn, time_t offset) -{ - timeval_t time; - gettimeofday(&time, NULL); - /* set sqb_sqn to an integer containing seconds followed by most - * significant useconds */ - time.tv_sec = htonl(time.tv_sec + offset); - /* usec's are never larger than 0x000f423f, so we shift the 12 first bits */ - time.tv_usec <<= 12; - time.tv_usec = htonl(time.tv_usec); - memcpy(sqn, &time.tv_sec, 4); - memcpy(sqn + 4, &time.tv_usec, 2); -} - -/** initialize peers SQN to the current system time at startup */ -static void __attribute__ ((constructor))init_sqn(void) -{ - update_sqn(peer_sqn_buf, 0); -} - -/** - * Binary represnation of the polynom T^160 + T^5 + T^3 + T^2 + 1 - */ -static u_int8_t g[] = { - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x2d -}; - -/** - * Predefined random bits from the RAND Corporation book - */ -static u_int8_t a[] = { - 0x9d, 0xe9, 0xc9, 0xc8, 0xef, 0xd5, 0x78, 0x11, - 0x48, 0x23, 0x14, 0x01, 0x90, 0x1f, 0x2d, 0x49, - 0x3f, 0x4c, 0x63, 0x65 -}; - -/** - * Predefined random bits from the RAND Corporation book - */ -static u_int8_t b[] = { - 0x75, 0xef, 0xd1, 0x5c, 0x4b, 0x8f, 0x8f, 0x51, - 0x4e, 0xf3, 0xbc, 0xc3, 0x79, 0x4a, 0x76, 0x5e, - 0x7e, 0xec, 0x45, 0xe0 -}; - -/** - * Multiplicate two mpz_t with bits interpreted as polynoms. - */ -static void mpz_mul_poly(mpz_t r, mpz_t a, mpz_t b) -{ - mpz_t bm, rm; - int current = 0, shifted = 0, shift; - - mpz_init_set(bm, b); - mpz_init_set_ui(rm, 0); - /* scan through a, for each found bit: */ - while ((current = mpz_scan1(a, current)) != ULONG_MAX) - { - /* XOR shifted b into r */ - shift = current - shifted; - mpz_mul_2exp(bm, bm, shift); - shifted += shift; - mpz_xor(rm, rm, bm); - current++; - } - - mpz_swap(r, rm); - mpz_clear(rm); - mpz_clear(bm); -} - -/** - * Calculate the sum of a + b interpreted as polynoms. - */ -static void mpz_add_poly(mpz_t res, mpz_t a, mpz_t b) -{ - /* addition of polynominals is just the XOR */ - mpz_xor(res, a, b); -} - -/** - * Calculate the remainder of a/b interpreted as polynoms. - */ -static void mpz_mod_poly(mpz_t r, mpz_t a, mpz_t b) -{ - /* Example: - * a = 10001010 - * b = 00000101 - */ - int a_bit, b_bit, diff; - mpz_t bm, am; - - mpz_init_set(am, a); - mpz_init(bm); - - a_bit = mpz_sizeinbase(a, 2); - b_bit = mpz_sizeinbase(b, 2); - - /* don't do anything if b > a */ - if (a_bit >= b_bit) - { - /* shift b left to align up most signaficant "1" to a: - * a = 10001010 - * b = 10100000 - */ - mpz_mul_2exp(bm, b, a_bit - b_bit); - do - { - /* XOR b into a, this kills the most significant "1": - * a = 00101010 - */ - mpz_xor(am, am, bm); - /* find the next most significant "1" in a, and align up b: - * a = 00101010 - * b = 00101000 - */ - diff = a_bit - mpz_sizeinbase(am, 2); - mpz_div_2exp(bm, bm, diff); - a_bit -= diff; - } - while (b_bit <= mpz_sizeinbase(bm, 2)); - /* While b is not shifted to its original value */ - } - /* after another iteration: - * a = 00000010 - * which is the polynomial modulo - */ - - mpz_swap(r, am); - mpz_clear(am); - mpz_clear(bm); -} - -/** - * Step 4 of the various fx() functions: - * Polynomial whiten calculations - */ -static void step4(u_int8_t x[]) -{ - mpz_t xm, am, bm, gm; - - mpz_init(xm); - mpz_init(am); - mpz_init(bm); - mpz_init(gm); - - mpz_import(xm, HASH_SIZE_SHA1, 1, 1, 1, 0, x); - mpz_import(am, sizeof(a), 1, 1, 1, 0, a); - mpz_import(bm, sizeof(b), 1, 1, 1, 0, b); - mpz_import(gm, sizeof(g), 1, 1, 1, 0, g); - - mpz_mul_poly(xm, am, xm); - mpz_add_poly(xm, bm, xm); - mpz_mod_poly(xm, xm, gm); - - mpz_export(x, NULL, 1, HASH_SIZE_SHA1, 1, 0, xm); - - mpz_clear(xm); - mpz_clear(am); - mpz_clear(bm); - mpz_clear(gm); -} - -/** - * Step 3 of the various fx() functions: - * XOR the key into the SHA1 IV - */ -static void step3(chunk_t k, chunk_t payload, u_int8_t h[]) -{ - u_int8_t iv[] = { - 0x67,0x45,0x23,0x01,0xEF,0xCD,0xAB,0x89,0x98,0xBA, - 0xDC,0xFE,0x10,0x32,0x54,0x76,0xC3,0xD2,0xE1,0xF0, - }; - - /* XOR key into IV */ - memxor(iv, k.ptr, k.len); - - /* hash it with the G() function defined in FIPS 186-2 from fips_prf.h */ - g_sha1(iv, payload, h); -} - -/** - * Calculation function for f2(), f3(), f4() - */ -static void fx(u_int8_t f, chunk_t k, chunk_t rand, u_int8_t out[]) -{ - chunk_t payload = chunk_alloca(PAYLOAD_LENGTH); - u_int8_t h[HASH_SIZE_SHA1]; - u_int8_t i; - - for (i = 0; i < 2; i++) - { - memset(payload.ptr, 0x5c, payload.len); - payload.ptr[11] ^= f; - memxor(payload.ptr + 12, fmk.ptr, fmk.len); - memxor(payload.ptr + 24, rand.ptr, rand.len); - - payload.ptr[3] ^= i; - payload.ptr[19] ^= i; - payload.ptr[35] ^= i; - payload.ptr[51] ^= i; - - step3(k, payload, h); - step4(h); - memcpy(out + i * 8, h, 8); - } -} - -/** - * Calculation function of f1() and f1star() - */ -static void f1x(u_int8_t f, chunk_t k, chunk_t rand, chunk_t sqn, - chunk_t amf, u_int8_t mac[]) -{ - /* generate MAC = f1(FMK, SQN, RAND, AMF) - * K is loaded into hashers IV; FMK, RAND, SQN, AMF are XORed in a 512-bit - * payload which gets hashed - */ - chunk_t payload = chunk_alloca(PAYLOAD_LENGTH); - u_int8_t h[HASH_SIZE_SHA1]; - - memset(payload.ptr, 0x5c, PAYLOAD_LENGTH); - payload.ptr[11] ^= f; - memxor(payload.ptr + 12, fmk.ptr, fmk.len); - memxor(payload.ptr + 16, rand.ptr, rand.len); - memxor(payload.ptr + 34, sqn.ptr, sqn.len); - memxor(payload.ptr + 42, amf.ptr, amf.len); - - step3(k, payload, h); - step4(h); - memcpy(mac, h, MAC_LENGTH); -} - -/** - * Calculation function of f5() and f5star() - */ -static void f5x(u_int8_t f, chunk_t k, chunk_t rand, u_int8_t ak[]) -{ - chunk_t payload = chunk_alloca(PAYLOAD_LENGTH); - u_int8_t h[HASH_SIZE_SHA1]; - - memset(payload.ptr, 0x5c, payload.len); - payload.ptr[11] ^= f; - memxor(payload.ptr + 12, fmk.ptr, fmk.len); - memxor(payload.ptr + 16, rand.ptr, rand.len); - - step3(k, payload, h); - step4(h); - memcpy(ak, h, AK_LENGTH); -} - -/** - * Calculate the MAC from a RAND, SQN, AMF value using K - */ -static void f1(chunk_t k, chunk_t rand, chunk_t sqn, chunk_t amf, u_int8_t mac[]) -{ - f1x(F1, k, rand, sqn, amf, mac); - DBG3(DBG_IKE, "MAC %b", mac, MAC_LENGTH); -} - -/** - * Calculate the MACS from a RAND, SQN, AMF value using K - */ -static void f1star(chunk_t k, chunk_t rand, chunk_t sqn, chunk_t amf, u_int8_t macs[]) -{ - f1x(F1STAR, k, rand, sqn, amf, macs); - DBG3(DBG_IKE, "MACS %b", macs, MAC_LENGTH); -} - -/** - * Calculate RES from RAND using K - */ -static void f2(chunk_t k, chunk_t rand, u_int8_t res[]) -{ - fx(F2, k, rand, res); - DBG3(DBG_IKE, "RES %b", res, RES_LENGTH); -} - -/** - * Calculate CK from RAND using K - */ -static void f3(chunk_t k, chunk_t rand, u_int8_t ck[]) -{ - fx(F3, k, rand, ck); - DBG3(DBG_IKE, "CK %b", ck, CK_LENGTH); -} - -/** - * Calculate IK from RAND using K - */ -static void f4(chunk_t k, chunk_t rand, u_int8_t ik[]) -{ - fx(F4, k, rand, ik); - DBG3(DBG_IKE, "IK %b", ik, IK_LENGTH); -} - -/** - * Calculate AK from a RAND using K - */ -static void f5(chunk_t k, chunk_t rand, u_int8_t ak[]) -{ - f5x(F5, k, rand, ak); - DBG3(DBG_IKE, "AK %b", ak, AK_LENGTH); -} - -/** - * Calculate AKS from a RAND using K - */ -static void f5star(chunk_t k, chunk_t rand, u_int8_t aks[]) -{ - f5x(F5STAR, k, rand, aks); - DBG3(DBG_IKE, "AKS %b", aks, AK_LENGTH); -} - -/** - * derive the keys needed for EAP_AKA - */ -static void derive_keys(private_eap_aka_t *this, identification_t *id) -{ - hasher_t *hasher; - prf_t *prf; - chunk_t ck, ik, mk, identity, tmp; - - ck = chunk_alloca(CK_LENGTH); - ik = chunk_alloca(IK_LENGTH); - mk = chunk_alloca(MK_LENGTH); - identity = id->get_encoding(id); - - /* MK = SHA1( Identity | IK | CK ) */ - f3(this->k, this->rand, ck.ptr); - f4(this->k, this->rand, ik.ptr); - DBG3(DBG_IKE, "Identity %B", &identity); - tmp = chunk_cata("ccc", identity, ik, ck); - DBG3(DBG_IKE, "Identity|IK|CK %B", &tmp); - hasher = hasher_create(HASH_SHA1); - hasher->get_hash(hasher, tmp, mk.ptr); - hasher->destroy(hasher); - - /* K_encr | K_auth | MSK | EMSK = prf(0) | prf(0) - * FIPS PRF has 320 bit block size, we need 160 byte for keys - * => run prf four times */ - prf = prf_create(PRF_FIPS_SHA1_160); - prf->set_key(prf, mk); - tmp = chunk_alloca(prf->get_block_size(prf) * 4); - prf->get_bytes(prf, chunk_empty, tmp.ptr); - prf->get_bytes(prf, chunk_empty, tmp.ptr + tmp.len / 4 * 1); - prf->get_bytes(prf, chunk_empty, tmp.ptr + tmp.len / 4 * 2); - prf->get_bytes(prf, chunk_empty, tmp.ptr + tmp.len / 4 * 3); - prf->destroy(prf); - chunk_free(&this->k_encr); - chunk_free(&this->k_auth); - chunk_free(&this->msk); - chunk_free(&this->emsk); - chunk_split(tmp, "aaaa", 16, &this->k_encr, 16, &this->k_auth, - 64, &this->msk, 64, &this->emsk); - DBG3(DBG_IKE, "MK %B", &mk); - DBG3(DBG_IKE, "PRF res %B", &tmp); - DBG3(DBG_IKE, "K_encr %B", &this->k_encr); - DBG3(DBG_IKE, "K_auth %B", &this->k_auth); - DBG3(DBG_IKE, "MSK %B", &this->msk); - DBG3(DBG_IKE, "EMSK %B", &this->emsk); -} - -/* - * Get a shared key from ipsec.secrets. - * We use the standard keys as used in preshared key authentication. As - * these keys have an undefined length, we: - * - strip them if they are longer - * - fill them up with '\0' if they are shorter - */ -static status_t load_key(identification_t *me, identification_t *other, chunk_t *k) -{ - chunk_t shared_key; - - if (charon->credentials->get_eap_key(charon->credentials, me, - other, &shared_key) != SUCCESS) - { - return NOT_FOUND; - } - chunk_free(k); - *k = chunk_alloc(K_LENGTH); - memset(k->ptr, '\0', k->len); - memcpy(k->ptr, shared_key.ptr, min(shared_key.len, k->len)); - chunk_free(&shared_key); - return SUCCESS; -} - -/** - * skip EAP_AKA header in message and returns its AKA subtype - */ -static aka_subtype_t read_header(chunk_t *message) -{ - aka_subtype_t type; - - if (message->len < 8) - { - *message = chunk_empty; - return 0; - } - type = *(message->ptr + 5); - *message = chunk_skip(*message, 8); - return type; -} - -/** - * read the next attribute from the chunk data - */ -static aka_attribute_t read_attribute(chunk_t *data, chunk_t *attr_data) -{ - aka_attribute_t attribute; - size_t length; - - DBG3(DBG_IKE, "reading attribute from %B", data); - - if (data->len < 2) - { - return AT_END; - } - /* read attribute and length */ - attribute = *data->ptr++; - length = *data->ptr++ * 4 - 2; - data->len -= 2; - DBG3(DBG_IKE, "found attribute %N with length %d", - aka_attribute_names, attribute, length); - if (length > data->len) - { - return AT_END; - } - /* apply attribute value to attr_data */ - attr_data->len = length; - attr_data->ptr = data->ptr; - /* update data to point to next attribute */ - *data = chunk_skip(*data, length); - return attribute; -} - -/** - * Build an AKA payload from different attributes. - * The variable argument takes an aka_attribute_t - * followed by its data in a chunk. - */ -static eap_payload_t *build_aka_payload(private_eap_aka_t *this, eap_code_t code, - u_int8_t identifier, aka_subtype_t type, ...) -{ - chunk_t message = chunk_alloca(512); /* is enought for all current messages */ - chunk_t pos = message; - eap_payload_t *payload; - va_list args; - aka_attribute_t attr; - u_int8_t *mac_pos = NULL; - - /* write EAP header, skip length bytes */ - *pos.ptr++ = code; - *pos.ptr++ = identifier; - pos.ptr += 2; - pos.len -= 4; - /* write AKA header with type and subtype, null reserved bytes */ - *pos.ptr++ = EAP_AKA; - *pos.ptr++ = type; - *pos.ptr++ = 0; - *pos.ptr++ = 0; - pos.len -= 4; - - va_start(args, type); - while ((attr = va_arg(args, aka_attribute_t)) != AT_END) - { - chunk_t data = va_arg(args, chunk_t); - - DBG3(DBG_IKE, "building %N %B", aka_attribute_names, attr, &data); - - /* write attribute header */ - *pos.ptr++ = attr; - pos.len--; - - switch (attr) - { - case AT_RES: - { - /* attribute length in 4byte words */ - *pos.ptr = data.len/4 + 1; - pos = chunk_skip(pos, 1); - /* RES length in bits */ - *(u_int16_t*)pos.ptr = htons(data.len * 8); - pos = chunk_skip(pos, sizeof(u_int16_t)); - memcpy(pos.ptr, data.ptr, data.len); - pos = chunk_skip(pos, data.len); - break; - } - case AT_AUTN: - case AT_RAND: - { - *pos.ptr++ = data.len/4 + 1; pos.len--; - *pos.ptr++ = 0; pos.len--; - *pos.ptr++ = 0; pos.len--; - memcpy(pos.ptr, data.ptr, data.len); - pos = chunk_skip(pos, data.len); - break; - } - case AT_MAC: - { - *pos.ptr++ = 5; pos.len--; - *pos.ptr++ = 0; pos.len--; - *pos.ptr++ = 0; pos.len--; - mac_pos = pos.ptr; - /* MAC is calculated over message including zeroed AT_MAC attribute */ - memset(mac_pos, 0, AT_MAC_LENGTH); - pos.ptr += AT_MAC_LENGTH; - pos.len -= AT_MAC_LENGTH; - break; - } - default: - { - /* length is data length in 4-bytes + 1 for header */ - *pos.ptr = data.len/4 + 1; - pos = chunk_skip(pos, 1); - memcpy(pos.ptr, data.ptr, data.len); - pos = chunk_skip(pos, data.len); - } - } - } - va_end(args); - - /* calculate message length, write into header */ - message.len = pos.ptr - message.ptr; - *(u_int16_t*)(message.ptr + 2) = htons(message.len); - - /* create MAC if AT_MAC attribte was included */ - if (mac_pos) - { - signer_t *signer = signer_create(AUTH_HMAC_SHA1_128); - signer->set_key(signer, this->k_auth); - DBG3(DBG_IKE, "AT_MAC signature of %B", &message); - DBG3(DBG_IKE, "using key %B", &this->k_auth); - signer->get_signature(signer, message, mac_pos); - DBG3(DBG_IKE, "is %b", mac_pos, AT_MAC_LENGTH); - signer->destroy(signer); - } - - /* payload constructor takes data with some bytes skipped */ - payload = eap_payload_create_data(message); - - DBG3(DBG_IKE, "created EAP message %B", &message); - return payload; -} - -/** - * Initiate a AKA-Challenge using SQN - */ -static status_t server_initiate_challenge(private_eap_aka_t *this, chunk_t sqn, eap_payload_t **out) -{ - randomizer_t *randomizer; - status_t status; - chunk_t mac, ak, autn; - - mac = chunk_alloca(MAC_LENGTH); - ak = chunk_alloca(AK_LENGTH); - chunk_free(&this->rand); - chunk_free(&this->xres); - - /* generate RAND: - * we use our standard randomizer, not f0() proposed in S.S0055 - */ - randomizer = randomizer_create(); - status = randomizer->allocate_pseudo_random_bytes(randomizer, RAND_LENGTH, &this->rand); - randomizer->destroy(randomizer); - if (status != SUCCESS) - { - DBG1(DBG_IKE, "generating RAND for EAP-AKA authentication failed"); - return FAILED; - } - -# ifdef TEST_VECTORS - /* Test vector for RAND */ - u_int8_t test_rand[] = { - 0x4b,0x05,0x2b,0x20,0xe2,0xa0,0x6c,0x8f, - 0xf7,0x00,0xda,0x51,0x2b,0x4e,0x11,0x1e, - }; - memcpy(this->rand.ptr, test_rand, this->rand.len); -# endif /* TEST_VECTORS */ - - /* Get the shared key K: */ - if (load_key(this->server, this->peer, &this->k) != SUCCESS) - { - DBG1(DBG_IKE, "no shared key found for IDs '%D' - '%D' to authenticate " - "with EAP-AKA", this->server, this->peer); - return FAILED; - } - -# ifdef TEST_VECTORS - /* Test vector for K */ - u_int8_t test_k[] = { - 0xad,0x1b,0x5a,0x15,0x9b,0xe8,0x6b,0x2c, - 0xa6,0x6c,0x7a,0xe4,0x0b,0xba,0x9b,0x9d, - }; - memcpy(this->k.ptr, test_k, this->k.len); -# endif /* TEST_VECTORS */ - - /* generate MAC */ - f1(this->k, this->rand, sqn, amf, mac.ptr); - - /* generate AK */ - f5(this->k, this->rand, ak.ptr); - - /* precalculate XRES as expected from client */ - this->xres = chunk_alloc(RES_LENGTH); - f2(this->k, this->rand, this->xres.ptr); - - /* calculate AUTN = (SQN xor AK) || AMF || MAC */ - autn = chunk_cata("ccc", sqn, amf, mac); - memxor(autn.ptr, ak.ptr, ak.len); - DBG3(DBG_IKE, "AUTN %B", &autn); - - - /* derive K_encr, K_auth, MSK, EMSK */ - derive_keys(this, this->peer); - - /* build payload */ - *out = build_aka_payload(this, EAP_REQUEST, 0, AKA_CHALLENGE, - AT_RAND, this->rand, AT_AUTN, autn, AT_MAC, - chunk_empty, AT_END); - return NEED_MORE; -} - -/** - * Implementation of eap_method_t.initiate for an EAP_AKA server - */ -static status_t server_initiate(private_eap_aka_t *this, eap_payload_t **out) -{ - chunk_t sqn = chunk_alloca(SQN_LENGTH); - - /* we use an offset of 3 minutes to tolerate clock inaccuracy - * without the need to synchronize sequence numbers */ - update_sqn(sqn.ptr, 180); - -# ifdef TEST_VECTORS - /* Test vector for SQN */ - u_int8_t test_sqn[] = {0x00,0x00,0x00,0x00,0x00,0x01}; - memcpy(sqn.ptr, test_sqn, sqn.len); -# endif /* TEST_VECTORS */ - - return server_initiate_challenge(this, sqn, out); -} - -static status_t server_process_synchronize(private_eap_aka_t *this, - eap_payload_t *in, eap_payload_t **out) -{ - chunk_t attr, auts = chunk_empty, pos, message, macs, xmacs, sqn, aks, amf; - u_int i; - - message = in->get_data(in); - pos = message; - read_header(&pos); - - /* iterate over attributes */ - while (TRUE) - { - aka_attribute_t attribute = read_attribute(&pos, &attr); - switch (attribute) - { - case AT_END: - break; - case AT_AUTS: - auts = attr; - continue; - default: - if (attribute >= 0 && attribute <= 127) - { - DBG1(DBG_IKE, "found non skippable attribute %N", - aka_attribute_names, attribute); - return FAILED; - } - DBG1(DBG_IKE, "ignoring skippable attribute %N", - aka_attribute_names, attribute); - continue; - } - break; - } - - if (auts.len != AUTS_LENGTH) - { - DBG1(DBG_IKE, "synchronization request didn't contain useable AUTS"); - return FAILED; - } - - chunk_split(auts, "mm", SQN_LENGTH, &sqn, MAC_LENGTH, &macs); - aks = chunk_alloca(AK_LENGTH); - f5star(this->k, this->rand, aks.ptr); - /* decrypt serial number by XORing AKS */ - memxor(sqn.ptr, aks.ptr, aks.len); - - /* verify MACS */ - xmacs = chunk_alloca(MAC_LENGTH); - amf = chunk_alloca(AMF_LENGTH); - /* an AMF of zero is used for MACS calculation */ - memset(amf.ptr, 0, amf.len); - f1star(this->k, this->rand, sqn, amf, xmacs.ptr); - if (!chunk_equals(macs, xmacs)) - { - DBG1(DBG_IKE, "received MACS does not match XMACS"); - DBG3(DBG_IKE, "MACS %B XMACS %B", &macs, &xmacs); - return FAILED; - } - - /* retry the challenge with the received SQN + 1*/ - for (i = SQN_LENGTH - 1; i >= 0; i--) - { - if (++sqn.ptr[i] != 0) - { - break; - } - } - return server_initiate_challenge(this, sqn, out); -} - -/** - * process an AKA_Challenge response - */ -static status_t server_process_challenge(private_eap_aka_t *this, eap_payload_t *in) -{ - chunk_t attr, res = chunk_empty, at_mac = chunk_empty, pos, message; - - message = in->get_data(in); - pos = message; - read_header(&pos); - - /* iterate over attributes */ - while (TRUE) - { - aka_attribute_t attribute = read_attribute(&pos, &attr); - switch (attribute) - { - case AT_END: - break; - case AT_RES: - res = attr; - if (attr.len == 2 + RES_LENGTH && - *(u_int16_t*)attr.ptr == htons(RES_LENGTH * 8)) - { - res = chunk_skip(attr, 2); - } - continue; - - case AT_MAC: - attr = chunk_skip(attr, 2); - at_mac = chunk_clonea(attr); - /* zero MAC in message for MAC verification */ - memset(attr.ptr, 0, attr.len); - continue; - default: - if (attribute >= 0 && attribute <= 127) - { - DBG1(DBG_IKE, "found non skippable attribute %N", - aka_attribute_names, attribute); - return FAILED; - } - DBG1(DBG_IKE, "ignoring skippable attribute %N", - aka_attribute_names, attribute); - continue; - } - break; - } - - /* verify EAP message MAC AT_MAC */ - { - bool valid; - signer_t *signer = signer_create(AUTH_HMAC_SHA1_128); - signer->set_key(signer, this->k_auth); - DBG3(DBG_IKE, "verifying AT_MAC signature of %B", &message); - DBG3(DBG_IKE, "using key %B", &this->k_auth); - valid = signer->verify_signature(signer, message, at_mac); - signer->destroy(signer); - if (!valid) - { - DBG1(DBG_IKE, "MAC in AT_MAC attribute verification failed"); - return FAILED; - } - } - - /* compare received RES against stored precalculated XRES */ - if (!chunk_equals(res, this->xres)) - { - DBG1(DBG_IKE, "received RES does not match XRES"); - DBG3(DBG_IKE, "RES %Bb XRES %B", &res, &this->xres); - return FAILED; - } - return SUCCESS; -} - -/** - * Implementation of eap_method_t.process for EAP_AKA servers - */ -static status_t server_process(private_eap_aka_t *this, - eap_payload_t *in, eap_payload_t **out) -{ - chunk_t message; - aka_subtype_t type; - - message = in->get_data(in); - type = read_header(&message); - - DBG3(DBG_IKE, "received EAP message %B", &message); - - switch (type) - { - case AKA_CHALLENGE: - { - return server_process_challenge(this, in); - } - case AKA_AUTHENTICATION_REJECT: - case AKA_CLIENT_ERROR: - { - DBG1(DBG_IKE, "received %N, authentication failed", - aka_subtype_names, type); - return FAILED; - } - case AKA_SYNCHRONIZATION_FAILURE: - { - DBG1(DBG_IKE, "received %N, retrying with received SQN", - aka_subtype_names, type); - return server_process_synchronize(this, in, out); - } - default: - DBG1(DBG_IKE, "received unknown AKA subtype %N, authentication failed", - aka_subtype_names, type); - return FAILED; - } -} - -/** - * Process an incoming AKA-Challenge client side - */ -static status_t peer_process_challenge(private_eap_aka_t *this, - eap_payload_t *in, eap_payload_t **out) -{ - chunk_t attr = chunk_empty; - chunk_t autn = chunk_empty, at_mac = chunk_empty; - chunk_t ak, sqn, sqn_ak, mac, xmac, res, amf, message, pos; - u_int8_t identifier; - - ak = chunk_alloca(AK_LENGTH); - xmac = chunk_alloca(MAC_LENGTH); - res = chunk_alloca(RES_LENGTH); - chunk_free(&this->rand); - - message = in->get_data(in); - pos = message; - read_header(&pos); - identifier = in->get_identifier(in); - - DBG3(DBG_IKE, "reading attributes from %B", &pos); - - /* iterate over attributes */ - while (TRUE) - { - aka_attribute_t attribute = read_attribute(&pos, &attr); - switch (attribute) - { - case AT_END: - break; - case AT_RAND: - this->rand = chunk_clone(chunk_skip(attr, 2)); - continue; - case AT_AUTN: - autn = chunk_skip(attr, 2); - continue; - case AT_MAC: - attr = chunk_skip(attr, 2); - at_mac = chunk_clonea(attr); - /* set MAC in message to zero for own MAC verification */ - memset(attr.ptr, 0, attr.len); - continue; - default: - if (attribute >= 0 && attribute <= 127) - { - /* non skippable attribute, abort */ - *out = build_aka_payload(this, EAP_RESPONSE, identifier, AKA_CLIENT_ERROR, - AT_CLIENT_ERROR_CODE, client_error_code, AT_END); - DBG1(DBG_IKE, "found non skippable attribute %N, sending %N %d", - aka_attribute_names, attribute, - aka_attribute_names, AT_CLIENT_ERROR_CODE, 0); - return NEED_MORE; - } - DBG1(DBG_IKE, "ignoring skippable attribute %N", - aka_attribute_names, attribute); - continue; - } - break; - } - - if (this->rand.len != RAND_LENGTH || autn.len != AUTN_LENGTH) - { - /* required attributes wrong/not found, abort */ - *out = build_aka_payload(this, EAP_RESPONSE, identifier, AKA_CLIENT_ERROR, - AT_CLIENT_ERROR_CODE, client_error_code, AT_END); - DBG1(DBG_IKE, "could not find valid RAND/AUTN attribute, sending %N %d", - aka_attribute_names, AT_CLIENT_ERROR_CODE, 0); - return NEED_MORE; - } - - DBG3(DBG_IKE, "using autn %B", &autn); - /* split up AUTN = SQN xor AK | AMF | MAC */ - chunk_split(autn, "mmm", SQN_LENGTH, &sqn_ak, AMF_LENGTH, &amf, MAC_LENGTH, &mac); - - /* Get the shared key K: */ - chunk_free(&this->k); - if (load_key(this->peer, this->server, &this->k) != SUCCESS) - { - *out = build_aka_payload(this, EAP_RESPONSE, identifier, - AKA_AUTHENTICATION_REJECT, AT_END); - DBG3(DBG_IKE, "no shared key found for IDs '%D' - '%D' to authenticate " - "with EAP-AKA, sending %N", this->peer, this->server, - aka_subtype_names, AKA_AUTHENTICATION_REJECT); - return NEED_MORE; - } - DBG3(DBG_IKE, "using K %B", &this->k); -# ifdef TEST_VECTORS - /* Test vector for K */ - u_int8_t test_k[] = { - 0xad,0x1b,0x5a,0x15,0x9b,0xe8,0x6b,0x2c, - 0xa6,0x6c,0x7a,0xe4,0x0b,0xba,0x9b,0x9d, - }; - memcpy(this->k.ptr, test_k, this->k.len); -# endif /* TEST_VECTORS */ - - /* calculate anonymity key AK */ - f5(this->k, this->rand, ak.ptr); - DBG3(DBG_IKE, "using rand %B", &this->rand); - DBG3(DBG_IKE, "using ak %B", &ak); - /* XOR AK into SQN to decrypt it */ - - sqn = chunk_clonea(sqn_ak); - - DBG3(DBG_IKE, "using ak xor sqn %B", &sqn_ak); - memxor(sqn.ptr, ak.ptr, sqn.len); - DBG3(DBG_IKE, "using sqn %B", &sqn); - - /* calculate expected MAC and compare against received one */ - f1(this->k, this->rand, sqn, amf, xmac.ptr); - if (!chunk_equals(mac, xmac)) - { - *out = build_aka_payload(this, EAP_RESPONSE, identifier, - AKA_AUTHENTICATION_REJECT, AT_END); - DBG1(DBG_IKE, "received MAC does not match XMAC, sending %N", - aka_subtype_names, AKA_AUTHENTICATION_REJECT); - DBG3(DBG_IKE, "MAC %B\nXMAC %B", &mac, &xmac); - return NEED_MORE; - } - -#if SEQ_CHECK - if (memcmp(peer_sqn.ptr, sqn.ptr, sqn.len) >= 0) - { - /* sequence number invalid. send AUTS */ - chunk_t auts, macs, aks, amf; - - macs = chunk_alloca(MAC_LENGTH); - aks = chunk_alloca(AK_LENGTH); - amf = chunk_alloca(AMF_LENGTH); - - /* AMF is set to zero in AKA_SYNCHRONIZATION_FAILURE */ - memset(amf.ptr, 0, amf.len); - /* AKS = f5*(RAND) */ - f5star(this->k, this->rand, aks.ptr); - /* MACS = f1*(RAND) */ - f1star(this->k, this->rand, peer_sqn, amf, macs.ptr); - /* AUTS = SQN xor AKS | MACS */ - memxor(aks.ptr, peer_sqn.ptr, aks.len); - auts = chunk_cata("cc", aks, macs); - - *out = build_aka_payload(this, EAP_RESPONSE, identifier, - AKA_SYNCHRONIZATION_FAILURE, - AT_AUTS, auts, AT_END); - DBG1(DBG_IKE, "received SQN invalid, sending %N", - aka_subtype_names, AKA_SYNCHRONIZATION_FAILURE); - DBG3(DBG_IKE, "received SQN %B\ncurrent SQN %B", &sqn, &peer_sqn); - return NEED_MORE; - } -#endif /* SEQ_CHECK */ - - /* derive K_encr, K_auth, MSK, EMSK */ - derive_keys(this, this->peer); - - /* verify EAP message MAC AT_MAC */ - { - bool valid; - signer_t *signer = signer_create(AUTH_HMAC_SHA1_128); - signer->set_key(signer, this->k_auth); - - DBG3(DBG_IKE, "verifying AT_MAC signature of %B", &message); - DBG3(DBG_IKE, "using key %B", &this->k_auth); - valid = signer->verify_signature(signer, message, at_mac); - signer->destroy(signer); - if (!valid) - { - *out = build_aka_payload(this, EAP_RESPONSE, identifier, AKA_CLIENT_ERROR, - AT_CLIENT_ERROR_CODE, client_error_code, AT_END); - DBG1(DBG_IKE, "MAC in AT_MAC attribute verification " - "failed, sending %N %d", aka_attribute_names, - AT_CLIENT_ERROR_CODE, 0); - return NEED_MORE; - } - } - - /* update stored SQN to the received one */ - memcpy(peer_sqn.ptr, sqn.ptr, sqn.len); - - /* calculate RES */ - f2(this->k, this->rand, res.ptr); - - /* build response */ - *out = build_aka_payload(this, EAP_RESPONSE, identifier, AKA_CHALLENGE, - AT_RES, res, AT_MAC, chunk_empty, AT_END); - return NEED_MORE; -} - -/** - * Process an incoming AKA-Notification as client - */ -static status_t peer_process_notification(private_eap_aka_t *this, - eap_payload_t *in, eap_payload_t **out) -{ - chunk_t message, pos, attr; - u_int8_t identifier; - - message = in->get_data(in); - pos = message; - read_header(&pos); - identifier = in->get_identifier(in); - - DBG3(DBG_IKE, "reading attributes from %B", &pos); - - /* iterate over attributes */ - while (TRUE) - { - aka_attribute_t attribute = read_attribute(&pos, &attr); - switch (attribute) - { - case AT_END: - break; - case AT_NOTIFICATION: - { - u_int16_t code; - - if (attr.len != 2) - { - DBG1(DBG_IKE, "received invalid AKA notification, ignored"); - continue; - } - code = ntohs(*(u_int16_t*)attr.ptr); - switch (code) - { - case 0: - DBG1(DBG_IKE, "received AKA notification 'general " - "failure after authentication' (%d)", code); - return FAILED; - case 16384: - DBG1(DBG_IKE, "received AKA notification 'general " - "failure' (%d)", code); - return FAILED; - case 32768: - DBG1(DBG_IKE, "received AKA notification 'successfully " - "authenticated' (%d)", code); - continue; - case 1026: - DBG1(DBG_IKE, "received AKA notification 'access " - "temporarily denied' (%d)", code); - return FAILED; - case 1031: - DBG1(DBG_IKE, "received AKA notification 'not " - "subscribed to service' (%d)", code); - return FAILED; - default: - DBG1(DBG_IKE, "received AKA notification code %d, " - "ignored", code); - continue; - } - } - default: - if (attribute >= 0 && attribute <= 127) - { - DBG1(DBG_IKE, "ignoring non-skippable attribute %N in %N", - aka_attribute_names, attribute, aka_subtype_names, - AKA_NOTIFICATION); - } - else - { - DBG1(DBG_IKE, "ignoring skippable attribute %N", - aka_attribute_names, attribute); - } - continue; - } - break; - } - return NEED_MORE; -} - -/** - * Implementation of eap_method_t.process for an EAP_AKA peer - */ -static status_t peer_process(private_eap_aka_t *this, - eap_payload_t *in, eap_payload_t **out) -{ - aka_subtype_t type; - chunk_t message; - u_int8_t identifier; - - message = in->get_data(in); - type = read_header(&message); - identifier = in->get_identifier(in); - - DBG3(DBG_IKE, "received EAP message %B", &message); - - switch (type) - { - case AKA_CHALLENGE: - { - return peer_process_challenge(this, in, out); - } - case AKA_NOTIFICATION: - { - return peer_process_notification(this, in, out); - } - default: - { - *out = build_aka_payload(this, EAP_RESPONSE, identifier, AKA_CLIENT_ERROR, - AT_CLIENT_ERROR_CODE, client_error_code, AT_END); - DBG1(DBG_IKE, "received unsupported %N request, sending %N %d", - aka_subtype_names, type, - aka_attribute_names, AT_CLIENT_ERROR_CODE, 0); - return NEED_MORE; - } - } -} - -/** - * Implementation of eap_method_t.initiate for an EAP AKA peer - */ -static status_t peer_initiate(private_eap_aka_t *this, eap_payload_t **out) -{ - /* peer never initiates */ - return FAILED; -} - -/** - * Implementation of eap_method_t.get_type. - */ -static eap_type_t get_type(private_eap_aka_t *this, u_int32_t *vendor) -{ - *vendor = 0; - return EAP_AKA; -} - -/** - * Implementation of eap_method_t.get_msk. - */ -static status_t get_msk(private_eap_aka_t *this, chunk_t *msk) -{ - if (this->msk.ptr) - { - *msk = this->msk; - return SUCCESS; - } - return FAILED; -} - -/** - * Implementation of eap_method_t.is_mutual. - */ -static bool is_mutual(private_eap_aka_t *this) -{ - return TRUE; -} - -/** - * Implementation of eap_method_t.destroy. - */ -static void destroy(private_eap_aka_t *this) -{ - chunk_free(&this->k_encr); - chunk_free(&this->k_auth); - chunk_free(&this->msk); - chunk_free(&this->emsk); - chunk_free(&this->xres); - chunk_free(&this->k); - chunk_free(&this->rand); - free(this); -} - -/* - * Described in header. - */ -eap_aka_t *eap_create(eap_role_t role, - identification_t *server, identification_t *peer) -{ - private_eap_aka_t *this = malloc_thing(private_eap_aka_t); - - /* public functions */ - switch (role) - { - case EAP_SERVER: - this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))server_initiate; - this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))server_process; - break; - case EAP_PEER: - this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))peer_initiate; - this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))peer_process; - break; - default: - free(this); - return NULL; - } - this->public.eap_method_interface.get_type = (eap_type_t(*)(eap_method_t*,u_int32_t*))get_type; - this->public.eap_method_interface.is_mutual = (bool(*)(eap_method_t*))is_mutual; - this->public.eap_method_interface.get_msk = (status_t(*)(eap_method_t*,chunk_t*))get_msk; - this->public.eap_method_interface.destroy = (void(*)(eap_method_t*))destroy; - - /* private data */ - this->server = server; - this->peer = peer; - this->k_encr = chunk_empty; - this->k_auth = chunk_empty; - this->msk = chunk_empty; - this->emsk = chunk_empty; - this->xres = chunk_empty; - this->k = chunk_empty; - this->rand = chunk_empty; - - return &this->public; -} diff --git a/src/charon/sa/authenticators/eap/eap_aka.h b/src/charon/sa/authenticators/eap/eap_aka.h deleted file mode 100644 index a886863be..000000000 --- a/src/charon/sa/authenticators/eap/eap_aka.h +++ /dev/null @@ -1,141 +0,0 @@ -/** - * @file eap_aka.h - * - * @brief Interface of eap_aka_t. - * - */ - -/* - * Copyright (C) 2006 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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 EAP_AKA_H_ -#define EAP_AKA_H_ - -typedef struct eap_aka_t eap_aka_t; -typedef enum aka_subtype_t aka_subtype_t; -typedef enum aka_attribute_t aka_attribute_t; - -#include - - -/** - * Subtypes of AKA messages - */ -enum aka_subtype_t { - AKA_CHALLENGE = 1, - AKA_AUTHENTICATION_REJECT = 2, - AKA_SYNCHRONIZATION_FAILURE = 4, - AKA_IDENTITY = 5, - AKA_NOTIFICATION = 12, - AKA_REAUTHENTICATION = 13, - AKA_CLIENT_ERROR = 14, -}; - -/** - * enum names for aka_subtype_t - */ -extern enum_name_t *aka_subtype_names; - -/** - * Attribute types in AKA messages - */ -enum aka_attribute_t { - /** defines the end of attribute list */ - AT_END = -1, - AT_RAND = 1, - AT_AUTN = 2, - AT_RES = 3, - AT_AUTS = 4, - AT_PADDING = 6, - AT_NONCE_MT = 7, - AT_PERMANENT_ID_REQ = 10, - AT_MAC = 11, - AT_NOTIFICATION = 12, - AT_ANY_ID_REQ = 13, - AT_IDENTITY = 14, - AT_VERSION_LIST = 15, - AT_SELECTED_VERSION = 16, - AT_FULLAUTH_ID_REQ = 17, - AT_COUNTER = 19, - AT_COUNTER_TOO_SMALL = 20, - AT_NONCE_S = 21, - AT_CLIENT_ERROR_CODE = 22, - AT_IV = 129, - AT_ENCR_DATA = 130, - AT_NEXT_PSEUDONYM = 132, - AT_NEXT_REAUTH_ID = 133, - AT_CHECKCODE = 134, - AT_RESULT_IND = 135, -}; - -/** - * enum names for aka_attribute_t - */ -extern enum_name_t *aka_attribute_names; - -/** check SEQ values as client for validity, disabled by default */ -#ifndef SEQ_CHECK -# define SEQ_CHECK 0 -#endif - -/** - * @brief Implementation of the eap_method_t interface using EAP-AKA. - * - * EAP-AKA uses 3rd generation mobile phone standard authentication - * mechanism for authentication. It is a mutual authentication - * mechanism which establishs a shared key and therefore supports EAP_ONLY - * authentication. This implementation follows the standard of the - * 3GPP2 (S.S0055) and not the one of 3GGP. - * The shared key used for authentication is from ipsec.secrets. The - * peers ID is used to query it. - * The AKA mechanism uses sequence numbers to detect replay attacks. The - * peer stores the sequence number normally in a USIM and accepts - * incremental sequence numbers (incremental for lifetime of the USIM). To - * prevent a complex sequence number management, this implementation uses - * a sequence number derived from time. It is initialized to the startup - * time of the daemon. As long as the (UTC) time of the system is not - * turned back while the daemon is not running, this method is secure. - * To enable time based SEQs, #define SEQ_CHECK as 1. Default is to accept - * any SEQ numbers. This allows an attacker to do replay attacks. But since - * the server has proven his identity via IKE, such an attack is only - * possible between server and AAA (if any). - * - * @b Constructors: - * - eap_aka_create() - * - eap_client_create() using eap_method EAP_AKA - * - * @ingroup eap - */ -struct eap_aka_t { - - /** - * Implemented eap_method_t interface. - */ - eap_method_t eap_method_interface; -}; - -/** - * @brief Creates the EAP method EAP-AKA. - * - * @param server ID of the EAP server - * @param peer ID of the EAP client - * @return eap_aka_t object - * - * @ingroup eap - */ -eap_aka_t *eap_create(eap_role_t role, - identification_t *server, identification_t *peer); - -#endif /* EAP_AKA_H_ */ diff --git a/src/charon/sa/authenticators/eap/eap_identity.c b/src/charon/sa/authenticators/eap/eap_identity.c deleted file mode 100644 index 12a8bf7cc..000000000 --- a/src/charon/sa/authenticators/eap/eap_identity.c +++ /dev/null @@ -1,135 +0,0 @@ -/** - * @file eap_identity.c - * - * @brief Implementation of eap_identity_t. - * - */ - -/* - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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_identity.h" - -#include -#include - -typedef struct private_eap_identity_t private_eap_identity_t; - -/** - * Private data of an eap_identity_t object. - */ -struct private_eap_identity_t { - - /** - * Public authenticator_t interface. - */ - eap_identity_t public; - - /** - * ID of the peer - */ - identification_t *peer; -}; - -/** - * Implementation of eap_method_t.process for the peer - */ -static status_t process(private_eap_identity_t *this, - eap_payload_t *in, eap_payload_t **out) -{ - chunk_t id, hdr; - - hdr = chunk_alloca(5); - id = this->peer->get_encoding(this->peer); - - *(hdr.ptr + 0) = EAP_RESPONSE; - *(hdr.ptr + 1) = in->get_identifier(in); - *(u_int16_t*)(hdr.ptr + 2) = htons(hdr.len + id.len); - *(hdr.ptr + 4) = EAP_IDENTITY; - - *out = eap_payload_create_data(chunk_cata("cc", hdr, id)); - return SUCCESS; - -} - -/** - * Implementation of eap_method_t.initiate for the peer - */ -static status_t initiate(private_eap_identity_t *this, eap_payload_t **out) -{ - /* peer never initiates */ - return FAILED; -} - -/** - * Implementation of eap_method_t.get_type. - */ -static eap_type_t get_type(private_eap_identity_t *this) -{ - return EAP_IDENTITY; -} - -/** - * Implementation of eap_method_t.get_msk. - */ -static status_t get_msk(private_eap_identity_t *this, chunk_t *msk) -{ - return FAILED; -} - -/** - * Implementation of eap_method_t.is_mutual. - */ -static bool is_mutual(private_eap_identity_t *this) -{ - return FALSE; -} - -/** - * Implementation of eap_method_t.destroy. - */ -static void destroy(private_eap_identity_t *this) -{ - free(this); -} - -/* - * Described in header. - */ -eap_identity_t *eap_create(eap_role_t role, - identification_t *server, identification_t *peer) -{ - private_eap_identity_t *this; - - if (role != EAP_PEER) - { - return NULL; - } - - this = malloc_thing(private_eap_identity_t); - - /* public functions */ - this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))initiate; - this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))process; - this->public.eap_method_interface.get_type = (eap_type_t(*)(eap_method_t*))get_type; - this->public.eap_method_interface.is_mutual = (bool(*)(eap_method_t*))is_mutual; - this->public.eap_method_interface.get_msk = (status_t(*)(eap_method_t*,chunk_t*))get_msk; - this->public.eap_method_interface.destroy = (void(*)(eap_method_t*))destroy; - - /* private data */ - this->peer = peer; - - return &this->public; -} diff --git a/src/charon/sa/authenticators/eap/eap_identity.h b/src/charon/sa/authenticators/eap/eap_identity.h deleted file mode 100644 index 20f0f0b67..000000000 --- a/src/charon/sa/authenticators/eap/eap_identity.h +++ /dev/null @@ -1,59 +0,0 @@ -/** - * @file eap_identity.h - * - * @brief Interface of eap_identity_t. - * - */ - -/* - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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 EAP_IDENTITY_H_ -#define EAP_IDENTITY_H_ - -typedef struct eap_identity_t eap_identity_t; - -#include - -/** - * @brief Implementation of the eap_method_t interface using EAP Identity. - * - * @b Constructors: - * - eap_identity_create() - * - eap_client_create() using eap_method EAP_IDENTITY - * - * @ingroup eap - */ -struct eap_identity_t { - - /** - * Implemented eap_method_t interface. - */ - eap_method_t eap_method_interface; -}; - -/** - * @brief Creates the EAP method EAP Identity. - * - * @param server ID of the EAP server - * @param peer ID of the EAP client - * @return eap_identity_t object - * - * @ingroup eap - */ -eap_identity_t *eap_create(eap_role_t role, - identification_t *server, identification_t *peer); - -#endif /* EAP_IDENTITY_H_ */ diff --git a/src/charon/sa/authenticators/eap/eap_manager.c b/src/charon/sa/authenticators/eap/eap_manager.c new file mode 100644 index 000000000..8a4d4eea5 --- /dev/null +++ b/src/charon/sa/authenticators/eap/eap_manager.c @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "eap_manager.h" + +#include + +#include + +typedef struct private_eap_manager_t private_eap_manager_t; +typedef struct eap_entry_t eap_entry_t; + +/** + * EAP constructor entry + */ +struct eap_entry_t { + + /** + * EAP method type, vendor specific if vendor is set + */ + eap_type_t type; + + /** + * vendor ID, 0 for default EAP methods + */ + u_int32_t vendor; + + /** + * Role of the method returned by the constructor, EAP_SERVER or EAP_PEER + */ + eap_role_t role; + + /** + * constructor function to create instance + */ + eap_constructor_t constructor; +}; + +/** + * private data of eap_manager + */ +struct private_eap_manager_t { + + /** + * public functions + */ + eap_manager_t public; + + /** + * list of eap_entry_t's + */ + linked_list_t *methods; + + /** + * mutex to lock methods + */ + pthread_mutex_t mutex; +}; + +/** + * Implementation of eap_manager_t.add_method. + */ +static void add_method(private_eap_manager_t *this, eap_type_t type, + u_int32_t vendor, eap_role_t role, + eap_constructor_t constructor) +{ + eap_entry_t *entry = malloc_thing(eap_entry_t); + + entry->type = type; + entry->vendor = vendor; + entry->role = role; + entry->constructor = constructor; + + pthread_mutex_lock(&this->mutex); + this->methods->insert_last(this->methods, entry); + pthread_mutex_unlock(&this->mutex); +} + +/** + * Implementation of eap_manager_t.remove_method. + */ +static void remove_method(private_eap_manager_t *this, eap_constructor_t constructor) +{ + enumerator_t *enumerator; + eap_entry_t *entry; + + pthread_mutex_lock(&this->mutex); + enumerator = this->methods->create_enumerator(this->methods); + while (enumerator->enumerate(enumerator, &entry)) + { + if (constructor == entry->constructor) + { + this->methods->remove_at(this->methods, enumerator); + free(entry); + } + } + enumerator->destroy(enumerator); + pthread_mutex_unlock(&this->mutex); +} + +/** + * Implementation of eap_manager_t.create_instance. + */ +static eap_method_t* create_instance(private_eap_manager_t *this, + eap_type_t type, u_int32_t vendor, + eap_role_t role, identification_t *server, + identification_t *peer) +{ + enumerator_t *enumerator; + eap_entry_t *entry; + eap_method_t *method = NULL; + + pthread_mutex_lock(&this->mutex); + enumerator = this->methods->create_enumerator(this->methods); + while (enumerator->enumerate(enumerator, &entry)) + { + if (type == entry->type && vendor == entry->vendor && + role == entry->role) + { + method = entry->constructor(server, peer); + if (method) + { + break; + } + } + } + enumerator->destroy(enumerator); + pthread_mutex_unlock(&this->mutex); + return method; +} + +/** + * Implementation of 2008_t.destroy + */ +static void destroy(private_eap_manager_t *this) +{ + this->methods->destroy_function(this->methods, free); + free(this); +} + +/* + * see header file + */ +eap_manager_t *eap_manager_create() +{ + private_eap_manager_t *this = malloc_thing(private_eap_manager_t); + + this->public.add_method = (void(*)(eap_manager_t*, eap_type_t type, u_int32_t vendor, eap_role_t role, eap_constructor_t constructor))add_method; + this->public.remove_method = (void(*)(eap_manager_t*, eap_constructor_t constructor))remove_method; + this->public.create_instance = (eap_method_t*(*)(eap_manager_t*, eap_type_t type, u_int32_t vendor, eap_role_t role, identification_t*,identification_t*))create_instance; + this->public.destroy = (void(*)(eap_manager_t*))destroy; + + this->methods = linked_list_create(); + pthread_mutex_init(&this->mutex, NULL); + + return &this->public; +} + diff --git a/src/charon/sa/authenticators/eap/eap_manager.h b/src/charon/sa/authenticators/eap/eap_manager.h new file mode 100644 index 000000000..273734582 --- /dev/null +++ b/src/charon/sa/authenticators/eap/eap_manager.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +/** + * @defgroup eap_manager eap_manager + * @{ @ingroup eap + */ + +#ifndef EAP_MANAGER_H_ +#define EAP_MANAGER_H_ + +#include + +typedef struct eap_manager_t eap_manager_t; + +/** + * The EAP manager manages all EAP implementations and creates instances. + * + * A plugin registers it's implemented EAP method at the manager by + * providing type and a contructor function. The manager then instanciates + * eap_method_t instances through the provided constructor to handle + * EAP authentication. + */ +struct eap_manager_t { + + /** + * Register a EAP method implementation. + * + * @param method vendor specific method, if vendor != 0 + * @param vendor vendor ID, 0 for non-vendor (default) EAP methods + * @param role EAP role of the registered method + * @param constructor constructor function, returns an eap_method_t + */ + void (*add_method)(eap_manager_t *this, eap_type_t type, u_int32_t vendor, + eap_role_t role, eap_constructor_t constructor); + + /** + * Unregister a EAP method implementation using it's constructor. + * + * @param constructor constructor function to remove, as added in add_method + */ + void (*remove_method)(eap_manager_t *this, eap_constructor_t constructor); + + /** + * Create a new EAP method instance. + * + * @param type type of the EAP method + * @param vendor vendor ID, 0 for non-vendor (default) EAP methods + * @param role role of EAP method, either EAP_SERVER or EAP_PEER + * @param server identity of the server + * @param peer identity of the peer (client) + * @return EAP method instance, NULL if no constructor found + */ + eap_method_t* (*create_instance)(eap_manager_t *this, eap_type_t type, + u_int32_t vendor, eap_role_t role, + identification_t *server, + identification_t *peer); + + /** + * Destroy a eap_manager instance. + */ + void (*destroy)(eap_manager_t *this); +}; + +/** + * Create a eap_manager instance. + */ +eap_manager_t *eap_manager_create(); + +#endif /* EAP_MANAGER_H_ @}*/ diff --git a/src/charon/sa/authenticators/eap/eap_md5.c b/src/charon/sa/authenticators/eap/eap_md5.c deleted file mode 100644 index 0ca9fc566..000000000 --- a/src/charon/sa/authenticators/eap/eap_md5.c +++ /dev/null @@ -1,282 +0,0 @@ -/** - * @file eap_md5.c - * - * @brief Implementation of eap_md5_t. - * - */ - -/* - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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_md5.h" - -#include -#include - -typedef struct private_eap_md5_t private_eap_md5_t; - -/** - * Private data of an eap_md5_t object. - */ -struct private_eap_md5_t { - - /** - * Public authenticator_t interface. - */ - eap_md5_t public; - - /** - * ID of the server - */ - identification_t *server; - - /** - * ID of the peer - */ - identification_t *peer; - - /** - * challenge sent by the server - */ - chunk_t challenge; - - /** - * EAP message identififier - */ - u_int8_t identifier; -}; - -typedef struct eap_md5_header_t eap_md5_header_t; - -/** - * packed eap MD5 header struct - */ -struct eap_md5_header_t { - /** EAP code (REQUEST/RESPONSE) */ - u_int8_t code; - /** unique message identifier */ - u_int8_t identifier; - /** length of whole message */ - u_int16_t length; - /** EAP type */ - u_int8_t type; - /** length of value (challenge) */ - u_int8_t value_size; - /** actual value */ - u_int8_t value[]; -} __attribute__((__packed__)); - -#define CHALLENGE_LEN 16 -#define PAYLOAD_LEN (CHALLENGE_LEN + sizeof(eap_md5_header_t)) - -/** - * Hash the challenge string, create response - */ -static status_t hash_challenge(private_eap_md5_t *this, chunk_t *response) -{ - chunk_t concat, secret; - hasher_t *hasher; - - if (charon->credentials->get_eap_key(charon->credentials, this->server, - this->peer, &secret) != SUCCESS) - { - DBG1(DBG_IKE, "no EAP key found for hosts '%D' - '%D'", - this->server, this->peer); - return NOT_FOUND; - } - concat = chunk_cata("cmc", chunk_from_thing(this->identifier), - secret, this->challenge); - hasher = hasher_create(HASH_MD5); - hasher->allocate_hash(hasher, concat, response); - hasher->destroy(hasher); - return SUCCESS; -} - -/** - * Implementation of eap_method_t.initiate for the peer - */ -static status_t initiate_peer(private_eap_md5_t *this, eap_payload_t **out) -{ - /* peer never initiates */ - return FAILED; -} - -/** - * Implementation of eap_method_t.initiate for the server - */ -static status_t initiate_server(private_eap_md5_t *this, eap_payload_t **out) -{ - randomizer_t *randomizer; - status_t status; - eap_md5_header_t *req; - - randomizer = randomizer_create(); - status = randomizer->allocate_pseudo_random_bytes(randomizer, CHALLENGE_LEN, - &this->challenge); - randomizer->destroy(randomizer); - if (status != SUCCESS) - { - return FAILED; - } - - req = alloca(PAYLOAD_LEN); - req->length = htons(PAYLOAD_LEN); - req->code = EAP_REQUEST; - req->identifier = this->identifier; - req->type = EAP_MD5; - req->value_size = this->challenge.len; - memcpy(req->value, this->challenge.ptr, this->challenge.len); - - *out = eap_payload_create_data(chunk_create((void*)req, PAYLOAD_LEN)); - return NEED_MORE; -} - -/** - * Implementation of eap_method_t.process for the peer - */ -static status_t process_peer(private_eap_md5_t *this, - eap_payload_t *in, eap_payload_t **out) -{ - chunk_t response; - chunk_t data; - eap_md5_header_t *req; - - this->identifier = in->get_identifier(in); - data = in->get_data(in); - this->challenge = chunk_clone(chunk_skip(data, 6)); - if (data.len < 6 || this->challenge.len < *(data.ptr + 5)) - { - DBG1(DBG_IKE, "received invalid EAP-MD5 message"); - return FAILED; - } - if (hash_challenge(this, &response) != SUCCESS) - { - return FAILED; - } - req = alloca(PAYLOAD_LEN); - req->length = htons(PAYLOAD_LEN); - req->code = EAP_RESPONSE; - req->identifier = this->identifier; - req->type = EAP_MD5; - req->value_size = response.len; - memcpy(req->value, response.ptr, response.len); - chunk_free(&response); - - *out = eap_payload_create_data(chunk_create((void*)req, PAYLOAD_LEN)); - return NEED_MORE; -} - -/** - * Implementation of eap_method_t.process for the server - */ -static status_t process_server(private_eap_md5_t *this, - eap_payload_t *in, eap_payload_t **out) -{ - chunk_t response, expected; - chunk_t data; - - if (this->identifier != in->get_identifier(in)) - { - DBG1(DBG_IKE, "received invalid EAP-MD5 message"); - return FAILED; - } - if (hash_challenge(this, &expected) != SUCCESS) - { - return FAILED; - } - data = in->get_data(in); - response = chunk_skip(data, 6); - - if (response.len < expected.len || - !memeq(response.ptr, expected.ptr, expected.len)) - { - chunk_free(&expected); - DBG1(DBG_IKE, "EAP-MD5 verification failed"); - return FAILED; - } - chunk_free(&expected); - return SUCCESS; -} - -/** - * Implementation of eap_method_t.get_type. - */ -static eap_type_t get_type(private_eap_md5_t *this, u_int32_t *vendor) -{ - *vendor = 0; - return EAP_MD5; -} - -/** - * Implementation of eap_method_t.get_msk. - */ -static status_t get_msk(private_eap_md5_t *this, chunk_t *msk) -{ - return FAILED; -} - -/** - * Implementation of eap_method_t.is_mutual. - */ -static bool is_mutual(private_eap_md5_t *this) -{ - return FALSE; -} - -/** - * Implementation of eap_method_t.destroy. - */ -static void destroy(private_eap_md5_t *this) -{ - chunk_free(&this->challenge); - free(this); -} - -/* - * Described in header. - */ -eap_md5_t *eap_create(eap_role_t role, - identification_t *server, identification_t *peer) -{ - private_eap_md5_t *this = malloc_thing(private_eap_md5_t); - - /* public functions */ - switch (role) - { - case EAP_SERVER: - this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))initiate_server; - this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))process_server; - break; - case EAP_PEER: - this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))initiate_peer; - this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))process_peer; - break; - default: - free(this); - return NULL; - } - this->public.eap_method_interface.get_type = (eap_type_t(*)(eap_method_t*,u_int32_t*))get_type; - this->public.eap_method_interface.is_mutual = (bool(*)(eap_method_t*))is_mutual; - this->public.eap_method_interface.get_msk = (status_t(*)(eap_method_t*,chunk_t*))get_msk; - this->public.eap_method_interface.destroy = (void(*)(eap_method_t*))destroy; - - /* private data */ - this->peer = peer; - this->server = server; - this->challenge = chunk_empty; - this->identifier = random(); - - return &this->public; -} diff --git a/src/charon/sa/authenticators/eap/eap_md5.h b/src/charon/sa/authenticators/eap/eap_md5.h deleted file mode 100644 index 260210b59..000000000 --- a/src/charon/sa/authenticators/eap/eap_md5.h +++ /dev/null @@ -1,59 +0,0 @@ -/** - * @file eap_md5.h - * - * @brief Interface of eap_md5_t. - * - */ - -/* - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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 EAP_MD5_H_ -#define EAP_MD5_H_ - -typedef struct eap_md5_t eap_md5_t; - -#include - -/** - * @brief Implementation of the eap_method_t interface using EAP-MD5 (CHAP). - * - * @b Constructors: - * - eap_md5_create() - * - eap_client_create() using eap_method EAP_MD5 - * - * @ingroup eap - */ -struct eap_md5_t { - - /** - * Implemented eap_method_t interface. - */ - eap_method_t eap_method_interface; -}; - -/** - * @brief Creates the EAP method EAP-MD5. - * - * @param server ID of the EAP server - * @param peer ID of the EAP client - * @return eap_md5_t object - * - * @ingroup eap - */ -eap_md5_t *eap_create(eap_role_t role, - identification_t *server, identification_t *peer); - -#endif /* EAP_MD5_H_ */ diff --git a/src/charon/sa/authenticators/eap/eap_method.c b/src/charon/sa/authenticators/eap/eap_method.c index 7434ca2a1..a9f7abda0 100644 --- a/src/charon/sa/authenticators/eap/eap_method.c +++ b/src/charon/sa/authenticators/eap/eap_method.c @@ -1,10 +1,3 @@ -/** - * @file eap_method.c - * - * @brief Generic constructor for eap_methods. - * - */ - /* * Copyright (C) 2006 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,22 +11,12 @@ * 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. + * + * $Id$ */ -#include -#include -#include -#include -#include - #include "eap_method.h" -#include -#include -#include -#include - - ENUM_BEGIN(eap_type_names, EAP_IDENTITY, EAP_TOKEN_CARD, "EAP_IDENTITY", "EAP_NOTIFICATION", @@ -62,171 +45,3 @@ ENUM(eap_role_names, EAP_SERVER, EAP_PEER, "EAP_PEER", ); - -typedef struct module_entry_t module_entry_t; - -/** - * Representation of a loaded module: EAP type, library handle, constructor - */ -struct module_entry_t { - eap_type_t type; - u_int32_t vendor; - void *handle; - eap_constructor_t constructor; -}; - -/** List of module_entry_t's */ -static linked_list_t *modules = NULL; - -/** - * unload modules at daemon shutdown - */ -void eap_method_unload() -{ - if (modules) - { - module_entry_t *entry; - - while (modules->remove_last(modules, (void**)&entry) == SUCCESS) - { - DBG2(DBG_CFG, "unloaded module EAP module %d-%d", - entry->type, entry->vendor); - dlclose(entry->handle); - free(entry); - } - modules->destroy(modules); - modules = NULL; - } -} - -/** - * Load EAP modules at daemon startup - */ -void eap_method_load(char *directory) -{ - struct dirent* entry; - DIR* dir; - - eap_method_unload(); - modules = linked_list_create(); - - dir = opendir(directory); - if (dir == NULL) - { - DBG1(DBG_CFG, "error opening EAP modules directory %s", directory); - return; - } - - DBG1(DBG_CFG, "loading EAP modules from '%s'", directory); - - while ((entry = readdir(dir)) != NULL) - { - char file[256]; - module_entry_t module, *loaded_module; - eap_method_t *method; - identification_t *id; - char *ending; - - snprintf(file, sizeof(file), "%s/%s", directory, entry->d_name); - - ending = entry->d_name + strlen(entry->d_name) - 3; - if (ending <= entry->d_name || !streq(ending, ".so")) - { - /* skip anything which does not look like a library */ - DBG2(DBG_CFG, " skipping %s, doesn't look like a library", - entry->d_name); - continue; - } - - /* try to load the library */ - module.handle = dlopen(file, RTLD_LAZY); - if (module.handle == NULL) - { - DBG1(DBG_CFG, " opening EAP module %s failed: %s", entry->d_name, - dlerror()); - continue; - } - module.constructor = dlsym(module.handle, "eap_create"); - if (module.constructor == NULL) - { - DBG1(DBG_CFG, " EAP module %s has no eap_create() function, skipped", - entry->d_name); - dlclose(module.handle); - continue; - } - - /* get the type implemented in the method, create an instance for it */ - id = identification_create_from_string("john@doe.xyz"); - method = module.constructor(EAP_SERVER, id, id); - if (method == NULL) - { - method = module.constructor(EAP_PEER, id, id); - } - id->destroy(id); - if (method == NULL) - { - DBG1(DBG_CFG, " unable to create instance of EAP method %s, skipped", - entry->d_name); - dlclose(module.handle); - continue; - } - module.type = method->get_type(method, &module.vendor); - method->destroy(method); - - if (module.vendor) - { - DBG1(DBG_CFG, " loaded EAP method %d, vendor %d successfully from %s", - module.type, module.vendor, entry->d_name); - } - else - { - DBG1(DBG_CFG, " loaded EAP method %N successfully from %s", - eap_type_names, module.type, entry->d_name); - } - - loaded_module = malloc_thing(module_entry_t); - memcpy(loaded_module, &module, sizeof(module)); - modules->insert_last(modules, loaded_module); - } - closedir(dir); -} - -/* - * Described in header. - */ -eap_method_t *eap_method_create(eap_type_t type, u_int32_t vendor, eap_role_t role, - identification_t *server, identification_t *peer) -{ - eap_method_t *method = NULL; - iterator_t *iterator; - module_entry_t *entry; - - iterator = modules->create_iterator(modules, TRUE); - while (iterator->iterate(iterator, (void**)&entry)) - { - if (entry->type == type && entry->vendor == vendor) - { - method = entry->constructor(role, server, peer); - if (method) - { - break; - } - } - } - iterator->destroy(iterator); - - if (method == NULL) - { - if (vendor) - { - DBG1(DBG_CFG, "no vendor %d specific EAP module found for method " - "%d %N", vendor, type, eap_role_names, role); - } - else - { - DBG1(DBG_CFG, "no EAP module found for %N %N", - eap_type_names, type, eap_role_names, role); - } - } - return method; -} diff --git a/src/charon/sa/authenticators/eap/eap_method.h b/src/charon/sa/authenticators/eap/eap_method.h index 8675fd8ec..ca7b36800 100644 --- a/src/charon/sa/authenticators/eap/eap_method.h +++ b/src/charon/sa/authenticators/eap/eap_method.h @@ -1,10 +1,3 @@ -/** - * @file eap_method.h - * - * @brief Interface eap_method_t. - * - */ - /* * Copyright (C) 2006 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup eap_method eap_method + * @{ @ingroup eap */ #ifndef EAP_METHOD_H_ @@ -34,8 +34,6 @@ typedef enum eap_code_t eap_code_t; /** * Role of an eap_method, SERVER or PEER (client) - * - * @ingroup eap */ enum eap_role_t { EAP_SERVER, @@ -43,15 +41,11 @@ enum eap_role_t { }; /** * enum names for eap_role_t. - * - * @ingroup eap */ extern enum_name_t *eap_role_names; /** * EAP types, defines the EAP method implementation - * - * @ingroup eap */ enum eap_type_t { EAP_IDENTITY = 1, @@ -68,15 +62,11 @@ enum eap_type_t { /** * enum names for eap_type_t. - * - * @ingroup eap */ extern enum_name_t *eap_type_names; /** * EAP code, type of an EAP message - * - * @ingroup eap */ enum eap_code_t { EAP_REQUEST = 1, @@ -87,14 +77,12 @@ enum eap_code_t { /** * enum names for eap_code_t. - * - * @ingroup eap */ extern enum_name_t *eap_code_names; /** - * @brief Interface of an EAP method for server and client side. + * Interface of an EAP method for server and client side. * * An EAP method initiates an EAP exchange and processes requests and * responses. An EAP method may need multiple exchanges before succeeding, and @@ -107,22 +95,16 @@ extern enum_name_t *eap_code_names; * authentication. Even if a mutual EAP method is used, the traditional * AUTH payloads are required. Only these include the nonces and messages from * ike_sa_init and therefore prevent man in the middle attacks. - * - * @b Constructors: - * - eap_method_create() - * - * @ingroup eap */ struct eap_method_t { /** - * @brief Initiate the EAP exchange. + * Initiate the EAP exchange. * * initiate() is only useable for server implementations, as clients only * reply to server requests. * A eap_payload is created in "out" if result is NEED_MORE. * - * @param this calling object * @param out eap_payload to send to the client * @return * - NEED_MORE, if an other exchange is required @@ -131,11 +113,10 @@ struct eap_method_t { status_t (*initiate) (eap_method_t *this, eap_payload_t **out); /** - * @brief Process a received EAP message. + * Process a received EAP message. * * A eap_payload is created in "out" if result is NEED_MORE. * - * @param this calling object * @param in eap_payload response received * @param out created eap_payload to send * @return @@ -147,31 +128,28 @@ struct eap_method_t { eap_payload_t **out); /** - * @brief Get the EAP type implemented in this method. + * Get the EAP type implemented in this method. * - * @param this calling object * @param vendor pointer receiving vendor identifier for type, 0 for none * @return type of the EAP method */ eap_type_t (*get_type) (eap_method_t *this, u_int32_t *vendor); /** - * @brief Check if this EAP method authenticates the server. + * Check if this EAP method authenticates the server. * * Some EAP methods provide mutual authentication and * allow authentication using only EAP, if the peer supports it. * - * @param this calling object * @return TRUE if methods provides mutual authentication */ bool (*is_mutual) (eap_method_t *this); /** - * @brief Get the MSK established by this EAP method. + * Get the MSK established by this EAP method. * * Not all EAP methods establish a shared secret. * - * @param this calling object * @param msk chunk receiving internal stored MSK * @return * - SUCCESS, or @@ -180,68 +158,25 @@ struct eap_method_t { status_t (*get_msk) (eap_method_t *this, chunk_t *msk); /** - * @brief Destroys a eap_method_t object. - * - * @param this calling object + * Destroys a eap_method_t object. */ void (*destroy) (eap_method_t *this); }; /** - * @brief Creates an EAP method for a specific type and role. - * - * @param eap_type EAP type to use - * @param eap_vendor vendor identifier if a vendor specifc EAP type is used - * @param role role of the eap_method, server or peer - * @param server ID of acting server - * @param peer ID of involved peer (client) - * @return eap_method_t object - * - * @ingroup eap - */ -eap_method_t *eap_method_create(eap_type_t eap_type, u_int32_t eap_vendor, - eap_role_t role, identification_t *server, - identification_t *peer); - -/** - * @brief (Re-)Load all EAP modules in the EAP modules directory. - * - * For security reasons, the directory and all it's modules must be owned - * by root and must not be writeable by someone else. - * - * @param dir directory of the EAP modules - * - * @ingroup eap - */ -void eap_method_load(char *directory); - -/** - * @brief Unload all loaded EAP modules - * - * @ingroup eap - */ -void eap_method_unload(); - -/** - * @brief Constructor definition for a pluggable EAP module. + * Constructor definition for a pluggable EAP method. * * Each EAP module must define a constructor function which will return - * an initialized object with the methods defined in eap_method_t. The - * constructor must be named eap_create() and it's signature must be equal - * to that of eap_constructor_t. - * A module may implement only a single role. If it does not support the role - * requested, NULL should be returned. Multiple modules are allowed of the - * same EAP type to support seperate implementations of peer/server. + * an initialized object with the methods defined in eap_method_t. + * Constructors for server and peers are identical, to support both roles + * of a EAP method, a plugin needs register two constructors in the + * eap_manager_t. * - * @param role role the module will play, peer or server * @param server ID of the server to use for credential lookup * @param peer ID of the peer to use for credential lookup * @return implementation of the eap_method_t interface - * - * @ingroup eap */ -typedef eap_method_t *(*eap_constructor_t)(eap_role_t role, - identification_t *server, +typedef eap_method_t *(*eap_constructor_t)(identification_t *server, identification_t *peer); -#endif /* EAP_METHOD_H_ */ +#endif /* EAP_METHOD_H_ @} */ diff --git a/src/charon/sa/authenticators/eap/eap_sim.c b/src/charon/sa/authenticators/eap/eap_sim.c deleted file mode 100644 index 90898fb46..000000000 --- a/src/charon/sa/authenticators/eap/eap_sim.c +++ /dev/null @@ -1,1125 +0,0 @@ -/** - * @file eap_sim.c - * - * @brief Implementation of eap_sim_t. - * - */ - -/* - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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_sim.h" - -#include - -#include -#include - -#define MAX_TRIES 3 - -/* number of triplets for one authentication */ -#define TRIPLET_COUNT 3 - -typedef enum sim_subtype_t sim_subtype_t; - -/** - * Subtypes of SIM messages - */ -enum sim_subtype_t { - SIM_START = 10, - SIM_CHALLENGE = 11, - SIM_NOTIFICATION = 12, - SIM_CLIENT_ERROR = 14, -}; - -ENUM(sim_subtype_names, SIM_START, SIM_CLIENT_ERROR, - "SIM_START", - "SIM_CHALLENGE", - "SIM_NOTIFICATION", - "SIM_13", - "SIM_CLIENT_ERROR", -); - -typedef enum sim_attribute_t sim_attribute_t; - -/** - * Attributes in SIM messages - */ -enum sim_attribute_t { - /** defines the end of attribute list */ - AT_END = -1, - AT_RAND = 1, - AT_AUTN = 2, - AT_RES = 3, - AT_AUTS = 4, - AT_PADDING = 6, - AT_NONCE_MT = 7, - AT_PERMANENT_ID_REQ = 10, - AT_MAC = 11, - AT_NOTIFICATION = 12, - AT_ANY_ID_REQ = 13, - AT_IDENTITY = 14, - AT_VERSION_LIST = 15, - AT_SELECTED_VERSION = 16, - AT_FULLAUTH_ID_REQ = 17, - AT_COUNTER = 19, - AT_COUNTER_TOO_SMALL = 20, - AT_NONCE_S = 21, - AT_CLIENT_ERROR_CODE = 22, - AT_IV = 129, - AT_ENCR_DATA = 130, - AT_NEXT_PSEUDONYM = 132, - AT_NEXT_REAUTH_ID = 133, - AT_CHECKCODE = 134, - AT_RESULT_IND = 135, -}; - -ENUM_BEGIN(sim_attribute_names, AT_END, AT_CLIENT_ERROR_CODE, - "AT_END", - "AT_0", - "AT_RAND", - "AT_AUTN", - "AT_RES", - "AT_AUTS", - "AT_5", - "AT_PADDING", - "AT_NONCE_MT", - "AT_8", - "AT_9", - "AT_PERMANENT_ID_REQ", - "AT_MAC", - "AT_NOTIFICATION", - "AT_ANY_ID_REQ", - "AT_IDENTITY", - "AT_VERSION_LIST", - "AT_SELECTED_VERSION", - "AT_FULLAUTH_ID_REQ", - "AT_18", - "AT_COUNTER", - "AT_COUNTER_TOO_SMALL", - "AT_NONCE_S", - "AT_CLIENT_ERROR_CODE"); -ENUM_NEXT(sim_attribute_names, AT_IV, AT_RESULT_IND, AT_CLIENT_ERROR_CODE, - "AT_IV", - "AT_ENCR_DATA", - "AT_131", - "AT_NEXT_PSEUDONYM", - "AT_NEXT_REAUTH_ID", - "AT_CHECKCODE", - "AT_RESULT_IND"); -ENUM_END(sim_attribute_names, AT_RESULT_IND); - - -typedef struct private_eap_sim_t private_eap_sim_t; - -/** - * Private data of an eap_sim_t object. - */ -struct private_eap_sim_t { - - /** - * Public authenticator_t interface. - */ - eap_sim_t public; - - /** - * ID of ourself - */ - identification_t *peer; - - /** - * SIM cardreader function loaded from library - */ - sim_algo_t alg; - - /** - * libraries get_triplet() function returning a triplet - */ - sim_get_triplet_t get_triplet; - - /** - * handle of the loaded library - */ - void *handle; - - /** - * how many times we try to authenticate - */ - int tries; - - /** - * unique EAP identifier - */ - u_int8_t identifier; - - /** - * EAP message type this role sends - */ - u_int8_t type; - - /** - * version this implementation uses - */ - chunk_t version; - - /** - * version list received from server - */ - chunk_t version_list; - - /** - * Nonce value used in AT_NONCE_MT - */ - chunk_t nonce; - - /** - * concatenated SRES values - */ - chunk_t sreses; - - /** - * k_encr key derived from MK - */ - chunk_t k_encr; - - /** - * k_auth key derived from MK, used for AT_MAC verification - */ - chunk_t k_auth; - - /** - * MSK, used for EAP-SIM based IKEv2 authentication - */ - chunk_t msk; - - /** - * EMSK, extendes MSK for further uses - */ - chunk_t emsk; -}; - -/** length of the AT_NONCE_MT nonce value */ -#define NONCE_LEN 16 -/** length of the AT_MAC value */ -#define MAC_LEN 16 -/** length of the AT_RAND value */ -#define RAND_LEN 16 -/** length of Kc */ -#define KC_LEN 8 -/** length of SRES */ -#define SRES_LEN 4 -/** length of the k_encr key */ -#define KENCR_LEN 16 -/** length of the k_auth key */ -#define KAUTH_LEN 16 -/** length of the MSK */ -#define MSK_LEN 64 -/** length of the EMSK */ -#define EMSK_LEN 64 - -static char version[] = {0x00,0x01}; -/* client error codes used in AT_CLIENT_ERROR_CODE */ -char client_error_general_buf[] = {0x00, 0x01}; -char client_error_unsupported_buf[] = {0x00, 0x02}; -char client_error_insufficient_buf[] = {0x00, 0x03}; -char client_error_notfresh_buf[] = {0x00, 0x04}; -chunk_t client_error_general = chunk_from_buf(client_error_general_buf); -chunk_t client_error_unsupported = chunk_from_buf(client_error_unsupported_buf); -chunk_t client_error_insufficient = chunk_from_buf(client_error_insufficient_buf); -chunk_t client_error_notfresh = chunk_from_buf(client_error_notfresh_buf); - -/** - * Read EAP and EAP-SIM header, return SIM type - */ -static sim_subtype_t read_header(chunk_t *message) -{ - sim_subtype_t type; - - if (message->len < 8) - { - *message = chunk_empty; - return 0; - } - type = *(message->ptr + 5); - *message = chunk_skip(*message, 8); - return type; -} - -/** - * read the next attribute from the chunk data - */ -static sim_attribute_t read_attribute(chunk_t *message, chunk_t *data) -{ - sim_attribute_t attribute; - size_t length; - - DBG3(DBG_IKE, "reading attribute from %B", message); - - if (message->len < 2) - { - return AT_END; - } - attribute = *message->ptr++; - length = *message->ptr++ * 4 - 2; - message->len -= 2; - DBG3(DBG_IKE, "found attribute %N with length %d", - sim_attribute_names, attribute, length); - - if (length > message->len) - { - return AT_END; - } - data->len = length; - data->ptr = message->ptr; - *message = chunk_skip(*message, length); - return attribute; -} - -/** - * Build an EAP-SIM payload using a variable length attribute list. - * The variable argument takes a sim_attribute_t followed by its data in a chunk. - */ -static eap_payload_t *build_payload(private_eap_sim_t *this, u_int8_t identifier, - sim_subtype_t type, ...) -{ - chunk_t message = chunk_alloca(512); - chunk_t pos = message; - eap_payload_t *payload; - va_list args; - sim_attribute_t attr; - u_int8_t *mac_pos = NULL; - chunk_t mac_data = chunk_empty; - - /* write EAP header, skip length bytes */ - *pos.ptr++ = this->type; - *pos.ptr++ = identifier; - pos.ptr += 2; - pos.len -= 4; - /* write SIM header with type and subtype, zero reserved bytes */ - *pos.ptr++ = EAP_SIM; - *pos.ptr++ = type; - *pos.ptr++ = 0; - *pos.ptr++ = 0; - pos.len -= 4; - - va_start(args, type); - while ((attr = va_arg(args, sim_attribute_t)) != AT_END) - { - chunk_t data = va_arg(args, chunk_t); - - DBG3(DBG_IKE, "building %N %B", sim_attribute_names, attr, &data); - - /* write attribute header */ - *pos.ptr++ = attr; - pos.len--; - - switch (attr) - { - case AT_CLIENT_ERROR_CODE: - case AT_SELECTED_VERSION: - { - *pos.ptr = data.len/4 + 1; - pos = chunk_skip(pos, 1); - memcpy(pos.ptr, data.ptr, data.len); - pos = chunk_skip(pos, data.len); - break; - } - case AT_IDENTITY: - case AT_VERSION_LIST: - { - u_int16_t act_len = data.len; - /* align up to four byte */ - if (data.len % 4) - { - chunk_t tmp = chunk_alloca((data.len/4)*4 + 4); - memset(tmp.ptr, 0, tmp.len); - memcpy(tmp.ptr, data.ptr, data.len); - data = tmp; - } - *pos.ptr = data.len/4 + 1; - pos = chunk_skip(pos, 1); - /* actual length in bytes */ - *(u_int16_t*)pos.ptr = htons(act_len); - pos = chunk_skip(pos, sizeof(u_int16_t)); - memcpy(pos.ptr, data.ptr, data.len); - pos = chunk_skip(pos, data.len); - break; - } - case AT_NONCE_MT: - { - *pos.ptr = data.len/4 + 1; - pos = chunk_skip(pos, 1); - memset(pos.ptr, 0, 2); - pos = chunk_skip(pos, 2); - memcpy(pos.ptr, data.ptr, data.len); - pos = chunk_skip(pos, data.len); - break; - } - case AT_MAC: - { - *pos.ptr++ = 5; pos.len--; - *pos.ptr++ = 0; pos.len--; - *pos.ptr++ = 0; pos.len--; - mac_pos = pos.ptr; - memset(mac_pos, 0, MAC_LEN); - pos = chunk_skip(pos, MAC_LEN); - mac_data = data; - break; - } - case AT_RAND: - { - *pos.ptr++ = data.len/4 + 1; pos.len--; - *pos.ptr++ = 0; pos.len--; - *pos.ptr++ = 0; pos.len--; - memcpy(pos.ptr, data.ptr, data.len); - pos = chunk_skip(pos, data.len); - break; - } - default: - DBG1(DBG_IKE, "no rule to build EAP_SIM attribute %N, skipped", - sim_attribute_names, attr); - break; - } - } - va_end(args); - - /* calculate message length, write into header */ - message.len = pos.ptr - message.ptr; - *(u_int16_t*)(message.ptr + 2) = htons(message.len); - - /* create MAC if AT_MAC attribte was included. Append supplied va_arg - * chunk mac_data to "to-sign" chunk */ - if (mac_pos) - { - signer_t *signer = signer_create(AUTH_HMAC_SHA1_128); - signer->set_key(signer, this->k_auth); - mac_data = chunk_cata("cc", message, mac_data); - signer->get_signature(signer, mac_data, mac_pos); - DBG3(DBG_IKE, "AT_MAC signature of %B\n is %b", - &mac_data, mac_pos, MAC_LEN); - signer->destroy(signer); - } - - payload = eap_payload_create_data(message); - - DBG3(DBG_IKE, "created EAP message %B", &message); - return payload; -} - -/** - * process an EAP-SIM/Request/Start message - */ -static status_t peer_process_start(private_eap_sim_t *this, eap_payload_t *in, - eap_payload_t **out) -{ - chunk_t message, data; - sim_attribute_t attribute, include_id = AT_END; - u_int8_t identifier; - - identifier = in->get_identifier(in); - message = in->get_data(in); - read_header(&message); - - while ((attribute = read_attribute(&message, &data)) != AT_END) - { - switch (attribute) - { - case AT_VERSION_LIST: - { - /* check if server supports our implementation */ - bool found = FALSE; - if (data.len > 2) - { - /* read actual length first */ - data.len = min(data.len, ntohs(*(u_int16_t*)data.ptr) + 2); - data = chunk_skip(data, 2); - chunk_free(&this->version_list); - this->version_list = chunk_clone(data); - while (data.len >= this->version.len) - { - if (memeq(data.ptr, this->version.ptr, this->version.len)) - { - found = TRUE; - break; - } - data = chunk_skip(data, this->version.len); - } - } - if (!found) - { - DBG1(DBG_IKE, "server does not support EAP_SIM " - "version number %#B", &this->version); - *out = build_payload(this, identifier, SIM_CLIENT_ERROR, - AT_CLIENT_ERROR_CODE, client_error_unsupported, - AT_END); - return NEED_MORE; - } - break; - } - case AT_PERMANENT_ID_REQ: - case AT_FULLAUTH_ID_REQ: - case AT_ANY_ID_REQ: - /* only include AT_IDENTITY if requested */ - include_id = AT_IDENTITY; - break; - case AT_NOTIFICATION: - { - u_int16_t code = 0; - if (data.len == 2) - { - code = ntohs(*(u_int16_t*)data.ptr); - } - if (code <= 32767) /* no success bit */ - { - DBG1(DBG_IKE, "received %N error %d", - sim_attribute_names, attribute, code); - *out = build_payload(this, - in->get_identifier(in), SIM_CLIENT_ERROR, - AT_CLIENT_ERROR_CODE, client_error_general, - AT_END); - return NEED_MORE; - } - else - { - DBG1(DBG_IKE, "received %N code %d", - sim_attribute_names, attribute, code); - } - break; - } - default: - DBG1(DBG_IKE, "ignoring EAP_SIM attribute %N", - sim_attribute_names, attribute); - break; - } - } - - /* build payload. If "include_id" is AT_END, AT_IDENTITY is ommited */ - *out = build_payload(this, identifier, SIM_START, - AT_SELECTED_VERSION, this->version, - AT_NONCE_MT, this->nonce, - include_id, this->peer->get_encoding(this->peer), - AT_END); - return NEED_MORE; -} - -/** - * derive EAP keys from kc - */ -static void derive_keys(private_eap_sim_t *this, chunk_t kcs) -{ - chunk_t tmp, mk; - hasher_t *hasher; - prf_t *prf; - int i; - - /* build MK = SHA1(Identity|n*Kc|NONCE_MT|Version List|Selected Version) */ - tmp = chunk_cata("ccccc", this->peer->get_encoding(this->peer), kcs, - this->nonce, this->version_list, this->version); - hasher = hasher_create(HASH_SHA1); - mk = chunk_alloca(hasher->get_hash_size(hasher)); - hasher->get_hash(hasher, tmp, mk.ptr); - hasher->destroy(hasher); - DBG3(DBG_IKE, "MK = SHA1(%B\n) = %B", &tmp, &mk); - - /* K_encr | K_auth | MSK | EMSK = prf() | prf() | prf() | prf() - * FIPS PRF has 320 bit block size, we need 160 byte for keys - * => run prf four times */ - prf = prf_create(PRF_FIPS_SHA1_160); - prf->set_key(prf, mk); - tmp = chunk_alloca(prf->get_block_size(prf) * 4); - for (i = 0; i < 4; i++) - { - prf->get_bytes(prf, chunk_empty, tmp.ptr + tmp.len / 4 * i); - } - prf->destroy(prf); - chunk_free(&this->k_encr); - chunk_free(&this->k_auth); - chunk_free(&this->msk); - chunk_free(&this->emsk); - chunk_split(tmp, "aaaa", KENCR_LEN, &this->k_encr, KAUTH_LEN, &this->k_auth, - MSK_LEN, &this->msk, EMSK_LEN, &this->emsk); - DBG3(DBG_IKE, "K_encr %B\nK_auth %B\nMSK %B\nEMSK %B", - &this->k_encr, &this->k_auth, &this->msk, &this->emsk); -} - -/** - * process an EAP-SIM/Request/Challenge message - */ -static status_t peer_process_challenge(private_eap_sim_t *this, - eap_payload_t *in, eap_payload_t **out) -{ - chunk_t message, data, tmp, kcs, kc, sreses, sres; - sim_attribute_t attribute; - u_int8_t identifier; - chunk_t mac = chunk_empty, rands = chunk_empty; - signer_t *signer; - - if (this->tries-- <= 0) - { - /* give up without notification. This hack is required as some buggy - * server implementations won't respect our client-error. */ - return FAILED; - } - - identifier = in->get_identifier(in); - message = in->get_data(in); - read_header(&message); - - while ((attribute = read_attribute(&message, &data)) != AT_END) - { - switch (attribute) - { - case AT_RAND: - { - rands = chunk_skip(data, 2); - break; - } - case AT_MAC: - { - /* backup MAC, zero it inline for later verification */ - data = chunk_skip(data, 2); - mac = chunk_clonea(data); - memset(data.ptr, 0, data.len); - break; - } - case AT_NOTIFICATION: - { - u_int16_t code = 0; - if (data.len == 2) - { - code = ntohs(*(u_int16_t*)data.ptr); - } - if (code <= 32767) /* no success bit */ - { - DBG1(DBG_IKE, "received %N error %d", - sim_attribute_names, attribute, code); - *out = build_payload(this, - in->get_identifier(in), SIM_CLIENT_ERROR, - AT_CLIENT_ERROR_CODE, client_error_general, - AT_END); - return NEED_MORE; - } - else - { - DBG1(DBG_IKE, "received %N code %d", - sim_attribute_names, attribute, code); - } - break; - } - default: - DBG1(DBG_IKE, "ignoring EAP_SIM attribute %N", - sim_attribute_names, attribute); - break; - } - } - - /* excepting two or three RAND, each 16 bytes. We require two valid - * and different RANDs */ - if ((rands.len != 2 * RAND_LEN && rands.len != 3 * RAND_LEN) || - memeq(rands.ptr, rands.ptr + RAND_LEN, RAND_LEN)) - { - DBG1(DBG_IKE, "no valid AT_RAND received"); - *out = build_payload(this, identifier, SIM_CLIENT_ERROR, - AT_CLIENT_ERROR_CODE, client_error_insufficient, - AT_END); - return NEED_MORE; - } - if (mac.len != MAC_LEN) - { - DBG1(DBG_IKE, "no valid AT_MAC received"); - *out = build_payload(this, identifier, SIM_CLIENT_ERROR, - AT_CLIENT_ERROR_CODE, client_error_general, - AT_END); - return NEED_MORE; - } - - /* get two or three KCs/SRESes from SIM using RANDs */ - kcs = kc = chunk_alloca(rands.len / 2); - sreses = sres = chunk_alloca(rands.len / 4); - while (rands.len > 0) - { - int kc_len = kc.len, sres_len = sres.len; - - if (this->alg(rands.ptr, RAND_LEN, sres.ptr, &sres_len, kc.ptr, &kc_len)) - { - DBG1(DBG_IKE, "unable to get EAP-SIM triplet"); - *out = build_payload(this, identifier, SIM_CLIENT_ERROR, - AT_CLIENT_ERROR_CODE, client_error_general, - AT_END); - return NEED_MORE; - } - DBG3(DBG_IKE, "got triplet for RAND %b\n Kc %b\n SRES %b", - rands.ptr, RAND_LEN, sres.ptr, sres_len, kc.ptr, kc_len); - kc = chunk_skip(kc, kc_len); - sres = chunk_skip(sres, sres_len); - rands = chunk_skip(rands, RAND_LEN); - } - - derive_keys(this, kcs); - - /* verify AT_MAC attribute, signature is over "EAP packet | NONCE_MT" */ - signer = signer_create(AUTH_HMAC_SHA1_128); - signer->set_key(signer, this->k_auth); - tmp = chunk_cata("cc", in->get_data(in), this->nonce); - if (!signer->verify_signature(signer, tmp, mac)) - { - DBG1(DBG_IKE, "AT_MAC verification failed"); - signer->destroy(signer); - *out = build_payload(this, identifier, SIM_CLIENT_ERROR, - AT_CLIENT_ERROR_CODE, client_error_general, - AT_END); - return NEED_MORE; - } - signer->destroy(signer); - - /* build response, AT_MAC is built over "EAP packet | n*SRES" */ - *out = build_payload(this, identifier, SIM_CHALLENGE, - AT_MAC, sreses, - AT_END); - return NEED_MORE; -} - -/** - * process an EAP-SIM/Response/Challenge message - */ -static status_t server_process_challenge(private_eap_sim_t *this, - eap_payload_t *in, eap_payload_t **out) -{ - chunk_t message, data; - sim_attribute_t attribute; - chunk_t mac = chunk_empty, tmp; - signer_t *signer; - - message = in->get_data(in); - read_header(&message); - - while ((attribute = read_attribute(&message, &data)) != AT_END) - { - switch (attribute) - { - case AT_MAC: - /* MAC has two reserved bytes */ - if (data.len == MAC_LEN + 2) - { /* clone and zero MAC for verification */ - mac = chunk_clonea(chunk_skip(data, 2)); - memset(data.ptr, 0, data.len); - } - break; - default: - DBG1(DBG_IKE, "ignoring EAP_SIM attribute %N", - sim_attribute_names, attribute); - break; - } - } - if (!mac.ptr) - { - DBG1(DBG_IKE, "no valid AT_MAC attribute received"); - return FAILED; - } - /* verify AT_MAC attribute, signature is over "EAP packet | n*SRES" */ - signer = signer_create(AUTH_HMAC_SHA1_128); - signer->set_key(signer, this->k_auth); - tmp = chunk_cata("cc", in->get_data(in), this->sreses); - if (!signer->verify_signature(signer, tmp, mac)) - { - DBG1(DBG_IKE, "AT_MAC verification failed"); - signer->destroy(signer); - return FAILED; - } - signer->destroy(signer); - return SUCCESS; -} - -/** - * process an EAP-SIM/Response/Start message - */ -static status_t server_process_start(private_eap_sim_t *this, - eap_payload_t *in, eap_payload_t **out) -{ - chunk_t message, data; - sim_attribute_t attribute; - bool supported = FALSE; - chunk_t rands, rand, kcs, kc, sreses, sres; - char id[64]; - int len, i, rand_len, kc_len, sres_len; - - message = in->get_data(in); - read_header(&message); - - while ((attribute = read_attribute(&message, &data)) != AT_END) - { - switch (attribute) - { - case AT_NONCE_MT: - if (data.len == NONCE_LEN + 2) - { - this->nonce = chunk_clone(chunk_skip(data, 2)); - } - break; - case AT_SELECTED_VERSION: - if (chunk_equals(data, this->version)) - { - supported = TRUE; - } - break; - default: - DBG1(DBG_IKE, "ignoring EAP_SIM attribute %N", - sim_attribute_names, attribute); - break; - } - } - if (!supported || !this->nonce.ptr) - { - DBG1(DBG_IKE, "received incomplete EAP-SIM/Response/Start"); - return FAILED; - } - len = snprintf(id, sizeof(id), "%D", this->peer); - if (len > sizeof(id) || len < 0) - { - return FAILED; - } - - /* read triplets from provider */ - rand = rands = chunk_alloca(RAND_LEN * TRIPLET_COUNT); - kc = kcs = chunk_alloca(KC_LEN * TRIPLET_COUNT); - sres = sreses = chunk_alloca(SRES_LEN * TRIPLET_COUNT); - rands.len = 0; - kcs.len = 0; - sreses.len = 0; - for (i = 0; i < TRIPLET_COUNT; i++) - { - rand_len = RAND_LEN; - kc_len = KC_LEN; - sres_len = SRES_LEN; - if (this->get_triplet(id, rand.ptr, &rand_len, sres.ptr, &sres_len, - kc.ptr, &kc_len)) - { - DBG1(DBG_IKE, "getting EAP-SIM triplet %d failed", i); - return FAILED; - } - rands.len += rand_len; - kcs.len += kc_len; - sreses.len += sres_len; - rand = chunk_skip(rand, rand_len); - kc = chunk_skip(kc, kc_len); - sres = chunk_skip(sres, sres_len); - } - derive_keys(this, kcs); - - /* build MAC over "EAP packet | NONCE_MT" */ - *out = build_payload(this, this->identifier++, SIM_CHALLENGE, AT_RAND, - rands, AT_MAC, this->nonce, AT_END); - this->sreses = chunk_clone(sreses); - return NEED_MORE; -} - -/** - * process an EAP-SIM/Request/Notification message - */ -static status_t peer_process_notification(private_eap_sim_t *this, - eap_payload_t *in, eap_payload_t **out) -{ - chunk_t message, data; - sim_attribute_t attribute; - - message = in->get_data(in); - read_header(&message); - - while ((attribute = read_attribute(&message, &data)) != AT_END) - { - switch (attribute) - { - case AT_NOTIFICATION: - { - u_int16_t code = 0; - if (data.len == 2) - { - code = ntohs(*(u_int16_t*)data.ptr); - } - if (code <= 32767) /* no success bit */ - { - DBG1(DBG_IKE, "received %N error %d", - sim_attribute_names, attribute, code); - *out = build_payload(this, - in->get_identifier(in), SIM_CLIENT_ERROR, - AT_CLIENT_ERROR_CODE, client_error_general, - AT_END); - return NEED_MORE; - } - else - { - DBG1(DBG_IKE, "received %N code %d", - sim_attribute_names, attribute, code); - } - break; - } - default: - DBG1(DBG_IKE, "ignoring EAP_SIM attribute %N", - sim_attribute_names, attribute); - break; - } - } - /* reply with empty notification */ - *out = build_payload(this, in->get_identifier(in), SIM_NOTIFICATION, AT_END); - return NEED_MORE; -} - -/** - * Process a client error - */ -static status_t server_process_client_error(private_eap_sim_t *this, - eap_payload_t *in, eap_payload_t **out) -{ - chunk_t message, data; - sim_attribute_t attribute; - - message = in->get_data(in); - read_header(&message); - - while ((attribute = read_attribute(&message, &data)) != AT_END) - { - if (attribute == AT_CLIENT_ERROR_CODE) - { - u_int16_t code = 0; - if (data.len == 2) - { - code = ntohs(*(u_int16_t*)data.ptr); - } - DBG1(DBG_IKE, "received %N error %d", - sim_attribute_names, attribute, code); - } - else - { - DBG1(DBG_IKE, "ignoring EAP_SIM attribute %N", - sim_attribute_names, attribute); - } - } - return FAILED; -} - -/** - * Implementation of eap_method_t.process for the peer - */ -static status_t peer_process(private_eap_sim_t *this, - eap_payload_t *in, eap_payload_t **out) -{ - sim_subtype_t type; - chunk_t message; - - message = in->get_data(in); - type = read_header(&message); - - switch (type) - { - case SIM_START: - return peer_process_start(this, in, out); - case SIM_CHALLENGE: - return peer_process_challenge(this, in, out); - case SIM_NOTIFICATION: - return peer_process_notification(this, in, out); - default: - DBG1(DBG_IKE, "unable to process EAP_SIM subtype %N", - sim_subtype_names, type); - *out = build_payload(this, in->get_identifier(in), SIM_CLIENT_ERROR, - AT_CLIENT_ERROR_CODE, client_error_general, AT_END); - return NEED_MORE; - } -} - -/** - * Implementation of eap_method_t.process for the server - */ -static status_t server_process(private_eap_sim_t *this, - eap_payload_t *in, eap_payload_t **out) -{ - sim_subtype_t type; - chunk_t message; - - message = in->get_data(in); - type = read_header(&message); - - switch (type) - { - case SIM_START: - return server_process_start(this, in, out); - case SIM_CHALLENGE: - return server_process_challenge(this, in, out); - case SIM_CLIENT_ERROR: - return server_process_client_error(this, in, out); - default: - DBG1(DBG_IKE, "unable to process EAP_SIM subtype %N", - sim_subtype_names, type); - return FAILED; - } -} - -/** - * Implementation of eap_method_t.initiate for the peer - */ -static status_t peer_initiate(private_eap_sim_t *this, eap_payload_t **out) -{ - /* peer never initiates */ - return FAILED; -} - -/** - * Implementation of eap_method_t.initiate for the server - */ -static status_t server_initiate(private_eap_sim_t *this, eap_payload_t **out) -{ - /* version_list to derive MK, no padding */ - this->version_list = chunk_clone(this->version); - /* build_payloads adds padding itself */ - *out = build_payload(this, this->identifier++, SIM_START, - AT_VERSION_LIST, this->version, AT_END); - return NEED_MORE; -} - -/** - * Implementation of eap_method_t.get_type. - */ -static eap_type_t get_type(private_eap_sim_t *this, u_int32_t *vendor) -{ - *vendor = 0; - return EAP_SIM; -} - -/** - * Implementation of eap_method_t.get_msk. - */ -static status_t get_msk(private_eap_sim_t *this, chunk_t *msk) -{ - if (this->msk.ptr) - { - *msk = this->msk; - return SUCCESS; - } - return FAILED; -} - -/** - * Implementation of eap_method_t.is_mutual. - */ -static bool is_mutual(private_eap_sim_t *this) -{ - return TRUE; -} - -/** - * Implementation of eap_method_t.destroy. - */ -static void destroy(private_eap_sim_t *this) -{ - dlclose(this->handle); - chunk_free(&this->nonce); - chunk_free(&this->sreses); - chunk_free(&this->version_list); - chunk_free(&this->k_auth); - chunk_free(&this->k_encr); - chunk_free(&this->msk); - chunk_free(&this->emsk); - free(this); -} - -/* - * Described in header. - */ -eap_sim_t *eap_create(eap_role_t role, - identification_t *server, identification_t *peer) -{ - private_eap_sim_t *this; - randomizer_t *randomizer; - void *symbol; - char *name; - - this = malloc_thing(private_eap_sim_t); - this->alg = NULL; - this->get_triplet = NULL; - this->nonce = chunk_empty; - this->sreses = chunk_empty; - this->peer = peer; - this->tries = MAX_TRIES; - this->version.ptr = version; - this->version.len = sizeof(version); - this->version_list = chunk_empty; - this->k_auth = chunk_empty; - this->k_encr = chunk_empty; - this->msk = chunk_empty; - this->emsk = chunk_empty; - this->identifier = random(); - - this->handle = dlopen(SIM_READER_LIB, RTLD_LAZY); - if (this->handle == NULL) - { - DBG1(DBG_IKE, "unable to open SIM reader '%s'", SIM_READER_LIB); - free(this); - return NULL; - } - switch (role) - { - case EAP_PEER: - name = SIM_READER_ALG; - break; - case EAP_SERVER: - name = SIM_READER_GET_TRIPLET; - break; - default: - free(this); - return NULL; - } - symbol = dlsym(this->handle, name); - if (symbol == NULL) - { - DBG1(DBG_IKE, "unable to open SIM function '%s' in '%s'", - name, SIM_READER_LIB); - dlclose(this->handle); - free(this); - return NULL; - } - switch (role) - { - case EAP_SERVER: - this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))server_initiate; - this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))server_process; - this->get_triplet = symbol; - this->type = EAP_REQUEST; - break; - case EAP_PEER: - this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))peer_initiate; - this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))peer_process; - this->alg = symbol; - this->type = EAP_RESPONSE; - randomizer = randomizer_create(); - if (randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_LEN, - &this->nonce)) - { - DBG1(DBG_IKE, "unable to generate NONCE for EAP_SIM"); - randomizer->destroy(randomizer); - free(this); - return NULL; - } - randomizer->destroy(randomizer); - break; - default: - free(this); - return NULL; - } - this->public.eap_method_interface.get_type = (eap_type_t(*)(eap_method_t*,u_int32_t*))get_type; - this->public.eap_method_interface.is_mutual = (bool(*)(eap_method_t*))is_mutual; - this->public.eap_method_interface.get_msk = (status_t(*)(eap_method_t*,chunk_t*))get_msk; - this->public.eap_method_interface.destroy = (void(*)(eap_method_t*))destroy; - - return &this->public; -} diff --git a/src/charon/sa/authenticators/eap/eap_sim.h b/src/charon/sa/authenticators/eap/eap_sim.h deleted file mode 100644 index d50cf7397..000000000 --- a/src/charon/sa/authenticators/eap/eap_sim.h +++ /dev/null @@ -1,114 +0,0 @@ -/** - * @file eap_sim.h - * - * @brief Interface of eap_sim_t. - * - */ - -/* - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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 EAP_SIM_H_ -#define EAP_SIM_H_ - -typedef struct eap_sim_t eap_sim_t; - -#include - -/** the library containing with the triplet functions */ -#ifndef SIM_READER_LIB -#error SIM_READER_LIB not specified, use --with-sim-reader option -#endif /* SIM_READER_LIB */ - -/** - * @brief Cardreaders SIM function. - * - * @param rand RAND to run algo with - * @param rand_length length of value in rand - * @param sres buffer to get SRES - * @param sres_length size of buffer in sres, returns bytes written to SRES - * @param kc buffer to get Kc - * @param kc_length size of buffer in Kc, returns bytes written to Kc - * @return zero on success - */ -typedef int (*sim_algo_t)(const unsigned char *rand, int rand_length, - unsigned char *sres, int *sres_length, - unsigned char *kc, int *kc_length); - -#ifndef SIM_READER_ALG -/** the SIM_READER_LIB's algorithm, uses sim_algo_t signature */ -#define SIM_READER_ALG "sim_run_alg" -#endif /* SIM_READER_ALG */ - -/** - * @brief Function to get a SIM triplet. - * - * @param identity identity (imsi) to get a triplet for - * @param rand buffer to get RAND - * @param rand_length size of buffer in rand, returns bytes written to RAND - * @param sres buffer to get SRES - * @param sres_length size of buffer in sres, returns bytes written to SRES - * @param kc buffer to get Kc - * @param kc_length size of buffer in Kc, returns bytes written to Kc - * @return zero on success - */ -typedef int (*sim_get_triplet_t)(char *identity, - unsigned char *rand, int *rand_length, - unsigned char *sres, int *sres_length, - unsigned char *kc, int *kc_length); - -#ifndef SIM_READER_GET_TRIPLET -/** the SIM_READER_LIB's get-triplet function, uses sim_get_triplet_t signature */ -#define SIM_READER_GET_TRIPLET "sim_get_triplet" -#endif /* SIM_READER_GET_TRIPLET */ - -/** - * @brief Implementation of the eap_method_t interface using EAP-SIM. - * - * This EAP-SIM client implementation uses another pluggable library to - * access the SIM card/triplet provider. This module is specified using the - * SIM_READER_LIB definition. It has to privde a sim_run_alg() function to - * calculate a triplet (client), and/or a sim_get_triplet() function to get - * a triplet (server). These functions are named to the SIM_READER_ALG and - * the SIM_READER_GET_TRIPLET definitions. - * - * @b Constructors: - * - eap_create() of this module - * - eap_client_create() using eap_method EAP_SIM - * - * @ingroup eap - */ -struct eap_sim_t { - - /** - * Implemented eap_method_t interface. - */ - eap_method_t eap_method_interface; -}; - -/** - * @brief Creates the EAP method EAP-SIM. - * - * @param role role of the module, client/server - * @param server ID of the EAP server - * @param peer ID of the EAP client - * @return eap_sim_t object - * - * @ingroup eap - */ -eap_sim_t *eap_create(eap_role_t role, - identification_t *server, identification_t *peer); - -#endif /* EAP_SIM_H_ */ diff --git a/src/charon/sa/authenticators/eap/sim/eap_sim_file.c b/src/charon/sa/authenticators/eap/sim/eap_sim_file.c deleted file mode 100644 index 2ab45a578..000000000 --- a/src/charon/sa/authenticators/eap/sim/eap_sim_file.c +++ /dev/null @@ -1,288 +0,0 @@ -/** - * @file eap_sim.h - * - * @brief Interface of eap_sim_t. - * - */ - -/* - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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 -#include -#include - -#include - -#define IMSI_LEN 64 -#define RAND_LEN 16 -#define SRES_LEN 4 -#define KC_LEN 8 - -typedef struct triplet_t triplet_t; - -struct triplet_t { - unsigned char imsi[IMSI_LEN]; - unsigned char rand[RAND_LEN]; - unsigned char sres[SRES_LEN]; - unsigned char kc[KC_LEN]; -}; - -static triplet_t *triplets = NULL; -static int triplet_count = 0; - -#define TRIPLET_FILE IPSEC_CONFDIR "/ipsec.d/triplets.dat" - -/** - * convert a single HEX char to its integer value - */ -static int hexchr(char chr) -{ - switch (chr) - { - case '0'...'9': - return chr - '0'; - case 'A'...'F': - return 10 + chr - 'A'; - case 'a'...'f': - return 10 + chr - 'a'; - } - return 0; -} - -/** - * convert a HEX string into a char array bin, limited by array length len - */ -static void hex2bin(char *hex, unsigned char *bin, size_t len) -{ - char *pos; - int i, even = 1; - - pos = hex - 1; - /* find the end, as we convert bottom up */ - while (TRUE) - { - switch (*(pos+1)) - { - case '0'...'9': - case 'A'...'F': - case 'a'...'f': - pos++; - continue; - } - break; - } - /* convert two hex chars into a single bin byte */ - for (i = 0; pos >= hex && i < len; pos--) - { - if (even) - { - bin[len - 1 - i] = hexchr(*pos); - } - else - { - bin[len - 1 - i] |= 16 * hexchr(*pos); - i++; - } - even = !even; - } -} - -/** - * free up allocated triplets - */ -static void __attribute__ ((destructor)) free_triplets() -{ - free(triplets); -} - -/** - * read the triplets from the file, using freeradius triplet file syntax: - * http://www.freeradius.org/radiusd/doc/rlm_sim_triplets - */ -static void __attribute__ ((constructor)) read_triplets() -{ - char line[512], *data[4], *pos; - FILE *file; - int i, nr = 0; - triplet_t *triplet; - - file = fopen(TRIPLET_FILE, "r"); - if (file == NULL) - { - DBG1(DBG_CFG, "opening triplet file %s failed: %s", - TRIPLET_FILE, strerror(errno)); - return; - } - - if (triplets) - { - free(triplets); - triplets = NULL; - triplet_count = 0; - } - - /* read line by line */ - while (fgets(line, sizeof(line), file)) - { - nr++; - /* skip comments, empty lines */ - switch (line[0]) - { - case '\n': - case '\r': - case '#': - case '\0': - continue; - default: - break; - } - /* read comma separated values */ - pos = line; - for (i = 0; i < 4; i++) - { - data[i] = pos; - pos = strchr(pos, ','); - if (pos) - { - *pos = '\0'; - pos++; - } - else if (i != 3) - { - DBG1(DBG_CFG, "error in triplet file, line %d", nr); - fclose(file); - return; - } - } - /* allocate new triplet */ - triplet_count++; - triplets = realloc(triplets, triplet_count * sizeof(triplet_t)); - triplet = &triplets[triplet_count - 1]; - memset(triplet, 0, sizeof(triplet_t)); - - /* convert/copy triplet data */ - for (i = 0; i < IMSI_LEN - 1; i++) - { - switch (data[0][i]) - { - case '\n': - case '\r': - case '\0': - break; - default: - triplet->imsi[i] = data[0][i]; - continue; - } - break; - } - hex2bin(data[1], triplet->rand, RAND_LEN); - hex2bin(data[2], triplet->sres, SRES_LEN); - hex2bin(data[3], triplet->kc, KC_LEN); - - DBG4(DBG_CFG, "triplet: imsi %b\nrand %b\nsres %b\nkc %b", - triplet->imsi, IMSI_LEN, triplet->rand, RAND_LEN, - triplet->sres, SRES_LEN, triplet->kc, KC_LEN); - } - fclose(file); - DBG2(DBG_CFG, "read %d triplets from %s", triplet_count, TRIPLET_FILE); -} - -/** - * Run the sim algorithm, see eap_sim.h - */ -int sim_run_alg(const unsigned char *rand, int rand_length, - unsigned char *sres, int *sres_length, - unsigned char *kc, int *kc_length) -{ - int current; - - if (rand_length != RAND_LEN || - *sres_length < SRES_LEN || - *kc_length < KC_LEN) - { - return 1; - } - - for (current = 0; current < triplet_count; current++) - { - if (memcmp(triplets[current].rand, rand, RAND_LEN) == 0) - { - memcpy(sres, triplets[current].sres, SRES_LEN); - memcpy(kc, triplets[current].kc, KC_LEN); - *sres_length = SRES_LEN; - *kc_length = KC_LEN; - return 0; - } - } - return 2; -} - -/** - * Get a single triplet, see_eap_sim.h - */ -int sim_get_triplet(char *imsi, - unsigned char *rand, int *rand_length, - unsigned char *sres, int *sres_length, - unsigned char *kc, int *kc_length) -{ - int current; - triplet_t *triplet; - static int skip = -1; - - DBG2(DBG_CFG, "getting triplet for %s", imsi); - - if (*rand_length < RAND_LEN || - *sres_length < SRES_LEN || - *kc_length < KC_LEN) - { - return 1; - } - if (triplet_count == 0) - { - return 2; - } - for (current = 0; current < triplet_count; current++) - { - triplet = &triplets[current]; - - if (streq(imsi, triplet->imsi)) - { - /* skip triplet if already used */ - if (skip >= current) - { - continue; - } - *rand_length = RAND_LEN; - *sres_length = SRES_LEN; - *kc_length = KC_LEN; - memcpy(rand, triplet->rand, RAND_LEN); - memcpy(sres, triplet->sres, SRES_LEN); - memcpy(kc, triplet->kc, KC_LEN); - /* remember used triplet */ - skip = current; - return 0; - } - } - if (skip > -1) - { - /* no triplet left, reuse triplets */ - skip = -1; - return sim_get_triplet(imsi, rand, rand_length, - sres, sres_length, kc, kc_length); - } - return 2; -} - diff --git a/src/charon/sa/authenticators/eap_authenticator.c b/src/charon/sa/authenticators/eap_authenticator.c index edd75da43..195853626 100644 --- a/src/charon/sa/authenticators/eap_authenticator.c +++ b/src/charon/sa/authenticators/eap_authenticator.c @@ -1,10 +1,3 @@ -/** - * @file eap_authenticator.c - * - * @brief Implementation of eap_authenticator_t. - * - */ - /* * Copyright (C) 2006 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,8 @@ * 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. + * + * $Id$ */ #include @@ -160,9 +155,9 @@ static status_t initiate(private_eap_authenticator_t *this, eap_type_t type, { DBG1(DBG_IKE, "requesting %N authentication", eap_type_names, type); } - this->method = eap_method_create(type, vendor, this->role, - this->ike_sa->get_my_id(this->ike_sa), - this->ike_sa->get_other_id(this->ike_sa)); + this->method = charon->eap->create_instance(charon->eap, type, vendor, + this->role, this->ike_sa->get_my_id(this->ike_sa), + this->ike_sa->get_other_id(this->ike_sa)); if (this->method == NULL) { @@ -195,9 +190,11 @@ static status_t process_peer(private_eap_authenticator_t *this, if (!vendor && type == EAP_IDENTITY) { - eap_method_t *method = eap_method_create(type, 0, EAP_PEER, - this->ike_sa->get_other_id(this->ike_sa), - this->ike_sa->get_my_id(this->ike_sa)); + eap_method_t *method; + + method = charon->eap->create_instance(charon->eap, type, 0, EAP_PEER, + this->ike_sa->get_other_id(this->ike_sa), + this->ike_sa->get_my_id(this->ike_sa)); if (method == NULL || method->process(method, in, out) != SUCCESS) { @@ -227,9 +224,10 @@ static status_t process_peer(private_eap_authenticator_t *this, DBG1(DBG_IKE, "EAP server requested %N authentication", eap_type_names, type); } - this->method = eap_method_create(type, vendor, EAP_PEER, - this->ike_sa->get_other_id(this->ike_sa), - this->ike_sa->get_my_id(this->ike_sa)); + this->method = charon->eap->create_instance(charon->eap, + type, vendor, EAP_PEER, + this->ike_sa->get_other_id(this->ike_sa), + this->ike_sa->get_my_id(this->ike_sa)); if (this->method == NULL) { DBG1(DBG_IKE, "EAP server requested unsupported " diff --git a/src/charon/sa/authenticators/eap_authenticator.h b/src/charon/sa/authenticators/eap_authenticator.h index cf2180ee3..717ee9f4c 100644 --- a/src/charon/sa/authenticators/eap_authenticator.h +++ b/src/charon/sa/authenticators/eap_authenticator.h @@ -1,10 +1,3 @@ -/** - * @file eap_authenticator.h - * - * @brief Interface of eap_authenticator_t. - * - */ - /* * Copyright (C) 2006 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup eap_authenticator eap_authenticator + * @{ @ingroup authenticators */ #ifndef EAP_AUTHENTICATOR_H_ @@ -29,7 +29,7 @@ typedef struct eap_authenticator_t eap_authenticator_t; #include /** - * @brief Implementation of the authenticator_t interface using AUTH_EAP. + * Implementation of the authenticator_t interface using AUTH_EAP. * * Authentication using EAP involves the most complex authenticator. It stays * alive over multiple ike_auth transactions and handles multiple EAP @@ -68,11 +68,6 @@ typedef struct eap_authenticator_t eap_authenticator_t; +--------+ +--------+ @endverbatim - * @b Constructors: - * - eap_authenticator_create() - * - authenticator_create() using auth_method AUTH_EAP - * - * @ingroup authenticators */ struct eap_authenticator_t { @@ -82,7 +77,7 @@ struct eap_authenticator_t { authenticator_t authenticator_interface; /** - * @brief Check if the EAP method was/is mutual and secure. + * Check if the EAP method was/is mutual and secure. * * RFC4306 proposes to authenticate the EAP responder (server) by standard * IKEv2 methods (RSA, psk). Not all, but some EAP methods @@ -93,19 +88,17 @@ struct eap_authenticator_t { * AUTH payload, the client must verify that the server initiated mutual * EAP authentication before it can trust the server. * - * @param this calling object * @return TRUE, if no AUTH payload required, FALSE otherwise */ bool (*is_mutual) (eap_authenticator_t* this); /** - * @brief Initiate the EAP exchange. + * Initiate the EAP exchange. * * The server initiates EAP exchanges, so the client never calls * this method. If initiate() returns NEED_MORE, the EAP authentication * process started. In any case, a payload is created in "out". * - * @param this calling object * @param type EAP method to use to authenticate client * @param vendor EAP vendor identifier, if type is vendor specific, or 0 * @param out created initiaal EAP message to send @@ -117,7 +110,7 @@ struct eap_authenticator_t { u_int32_t vendor, eap_payload_t **out); /** - * @brief Process an EAP message. + * Process an EAP message. * * After receiving an EAP message "in", the peer/server processes * the payload and creates a reply/subsequent request. @@ -132,7 +125,6 @@ struct eap_authenticator_t { * If a SUCCESS is returned (on any side), the EAP authentication was * successful and the AUTH payload can be exchanged. * - * @param this calling object * @param in received EAP message * @param out created EAP message to send * @return @@ -145,13 +137,11 @@ struct eap_authenticator_t { }; /** - * @brief Creates an authenticator for AUTH_EAP. + * Creates an authenticator for AUTH_EAP. * * @param ike_sa associated ike_sa * @return eap_authenticator_t object - * - * @ingroup authenticators */ eap_authenticator_t *eap_authenticator_create(ike_sa_t *ike_sa); -#endif /* EAP_AUTHENTICATOR_H_ */ +#endif /* EAP_AUTHENTICATOR_H_ @} */ diff --git a/src/charon/sa/authenticators/psk_authenticator.c b/src/charon/sa/authenticators/psk_authenticator.c index 6b76088bb..9094077e4 100644 --- a/src/charon/sa/authenticators/psk_authenticator.c +++ b/src/charon/sa/authenticators/psk_authenticator.c @@ -1,10 +1,3 @@ -/** - * @file psk_authenticator.c - * - * @brief Implementation of psk_authenticator_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,8 @@ * 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. + * + * $Id$ */ #include @@ -26,6 +21,7 @@ #include "psk_authenticator.h" #include +#include /** * Key pad for the AUTH method SHARED_KEY_MESSAGE_INTEGRITY_CODE. @@ -105,39 +101,49 @@ chunk_t build_shared_key_signature(chunk_t ike_sa_init, chunk_t nonce, * Implementation of authenticator_t.verify. */ static status_t verify(private_psk_authenticator_t *this, chunk_t ike_sa_init, - chunk_t my_nonce, auth_payload_t *auth_payload) + chunk_t my_nonce, auth_payload_t *auth_payload) { - status_t status; - chunk_t auth_data, recv_auth_data, shared_key; + chunk_t auth_data, recv_auth_data; identification_t *my_id, *other_id; + shared_key_t *shared_key; + enumerator_t *enumerator; + bool authenticated = FALSE; + int keys_found = 0; my_id = this->ike_sa->get_my_id(this->ike_sa); other_id = this->ike_sa->get_other_id(this->ike_sa); - status = charon->credentials->get_shared_key(charon->credentials, my_id, - other_id, &shared_key); - if (status != SUCCESS) + enumerator = charon->credentials->create_shared_enumerator( + charon->credentials, SHARED_IKE, my_id, other_id); + while (!authenticated && enumerator->enumerate(enumerator, &shared_key, NULL, NULL)) { - DBG1(DBG_IKE, "no shared key found for '%D' - '%D'", my_id, other_id); - return status; + keys_found++; + auth_data = build_shared_key_signature(ike_sa_init, my_nonce, + shared_key->get_key(shared_key), other_id, + this->ike_sa->get_skp_verify(this->ike_sa), + this->ike_sa->get_prf(this->ike_sa)); + recv_auth_data = auth_payload->get_data(auth_payload); + if (auth_data.len == recv_auth_data.len && + memeq(auth_data.ptr, recv_auth_data.ptr, auth_data.len)) + { + DBG1(DBG_IKE, "authentication of '%D' with %N successful", + other_id, auth_method_names, AUTH_PSK); + authenticated = TRUE; + } + chunk_free(&auth_data); } + enumerator->destroy(enumerator); - auth_data = build_shared_key_signature(ike_sa_init, my_nonce, shared_key, - other_id, this->ike_sa->get_skp_verify(this->ike_sa), - this->ike_sa->get_prf(this->ike_sa)); - chunk_free_randomized(&shared_key); - - recv_auth_data = auth_payload->get_data(auth_payload); - if (auth_data.len != recv_auth_data.len || - !memeq(auth_data.ptr, recv_auth_data.ptr, auth_data.len)) + if (!authenticated) { - DBG1(DBG_IKE, "PSK MAC verification failed"); - chunk_free(&auth_data); + if (keys_found == 0) + { + DBG1(DBG_IKE, "no shared key found for '%D' - '%D'", my_id, other_id); + return NOT_FOUND; + } + DBG1(DBG_IKE, "tried %d shared key%s for '%D' - '%D', but MAC mismatched", + keys_found, keys_found == 1 ? "" : "s", my_id, other_id); return FAILED; } - chunk_free(&auth_data); - - DBG1(DBG_IKE, "authentication of '%D' with %N successful", - other_id, auth_method_names, AUTH_PSK); return SUCCESS; } @@ -147,28 +153,27 @@ static status_t verify(private_psk_authenticator_t *this, chunk_t ike_sa_init, static status_t build(private_psk_authenticator_t *this, chunk_t ike_sa_init, chunk_t other_nonce, auth_payload_t **auth_payload) { - chunk_t shared_key; + shared_key_t *shared_key; chunk_t auth_data; - status_t status; identification_t *my_id, *other_id; my_id = this->ike_sa->get_my_id(this->ike_sa); other_id = this->ike_sa->get_other_id(this->ike_sa); DBG1(DBG_IKE, "authentication of '%D' (myself) with %N", my_id, auth_method_names, AUTH_PSK); - status = charon->credentials->get_shared_key(charon->credentials, my_id, - other_id, &shared_key); - if (status != SUCCESS) + shared_key = charon->credentials->get_shared(charon->credentials, SHARED_IKE, + my_id, other_id); + if (shared_key == NULL) { DBG1(DBG_IKE, "no shared key found for '%D' - '%D'", my_id, other_id); - return status; + return NOT_FOUND; } - - auth_data = build_shared_key_signature(ike_sa_init, other_nonce, shared_key, - my_id, this->ike_sa->get_skp_build(this->ike_sa), - this->ike_sa->get_prf(this->ike_sa)); + auth_data = build_shared_key_signature(ike_sa_init, other_nonce, + shared_key->get_key(shared_key), my_id, + this->ike_sa->get_skp_build(this->ike_sa), + this->ike_sa->get_prf(this->ike_sa)); + shared_key->destroy(shared_key); DBG2(DBG_IKE, "successfully created shared key MAC"); - chunk_free_randomized(&shared_key); *auth_payload = auth_payload_create(); (*auth_payload)->set_auth_method(*auth_payload, AUTH_PSK); (*auth_payload)->set_data(*auth_payload, auth_data); diff --git a/src/charon/sa/authenticators/psk_authenticator.h b/src/charon/sa/authenticators/psk_authenticator.h index c1c5bcaac..366678f5d 100644 --- a/src/charon/sa/authenticators/psk_authenticator.h +++ b/src/charon/sa/authenticators/psk_authenticator.h @@ -1,10 +1,3 @@ -/** - * @file psk_authenticator.h - * - * @brief Interface of psk_authenticator_t. - * - */ - /* * Copyright (C) 2006 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup psk_authenticator psk_authenticator + * @{ @ingroup authenticators */ #ifndef PSK_AUTHENTICATOR_H_ @@ -28,13 +28,7 @@ typedef struct psk_authenticator_t psk_authenticator_t; #include /** - * @brief Implementation of the authenticator_t interface using AUTH_PSK. - * - * @b Constructors: - * - psk_authenticator_create() - * - authenticator_create() using auth_method AUTH_PSK - * - * @ingroup authenticators + * Implementation of the authenticator_t interface using AUTH_PSK. */ struct psk_authenticator_t { @@ -45,13 +39,11 @@ struct psk_authenticator_t { }; /** - * @brief Creates an authenticator for AUTH_PSK. + * Creates an authenticator for AUTH_PSK. * * @param ike_sa associated ike_sa * @return psk_authenticator_t object - * - * @ingroup authenticators */ psk_authenticator_t *psk_authenticator_create(ike_sa_t *ike_sa); -#endif /* PSK_AUTHENTICATOR_H_ */ +#endif /* PSK_AUTHENTICATOR_H_ @} */ diff --git a/src/charon/sa/authenticators/rsa_authenticator.c b/src/charon/sa/authenticators/rsa_authenticator.c index ba0fad1e3..becef1841 100644 --- a/src/charon/sa/authenticators/rsa_authenticator.c +++ b/src/charon/sa/authenticators/rsa_authenticator.c @@ -1,10 +1,3 @@ -/** - * @file rsa_authenticator.c - * - * @brief Implementation of rsa_authenticator_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,8 @@ * 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. + * + * $Id$ */ #include @@ -26,6 +21,7 @@ #include "rsa_authenticator.h" #include +#include typedef struct private_rsa_authenticator_t private_rsa_authenticator_t; @@ -58,11 +54,12 @@ extern chunk_t build_tbs_octets(chunk_t ike_sa_init, chunk_t nonce, static status_t verify(private_rsa_authenticator_t *this, chunk_t ike_sa_init, chunk_t my_nonce, auth_payload_t *auth_payload) { - status_t status; + public_key_t *public; chunk_t auth_data, octets; identification_t *other_id; - ca_info_t *issuer; prf_t *prf; + auth_info_t *auth; + status_t status = FAILED; other_id = this->ike_sa->get_other_id(this->ike_sa); @@ -74,16 +71,27 @@ static status_t verify(private_rsa_authenticator_t *this, chunk_t ike_sa_init, prf = this->ike_sa->get_prf(this->ike_sa); prf->set_key(prf, this->ike_sa->get_skp_verify(this->ike_sa)); octets = build_tbs_octets(ike_sa_init, my_nonce, other_id, prf); - status = charon->credentials->verify_signature(charon->credentials, - octets, auth_data, other_id, &issuer); - chunk_free(&octets); - if (status == SUCCESS) + auth = this->ike_sa->get_other_auth(this->ike_sa); + public = charon->credentials->get_public(charon->credentials, KEY_RSA, + other_id, auth); + if (public) { - this->ike_sa->set_other_ca(this->ike_sa, issuer); - DBG1(DBG_IKE, "authentication of '%D' with %N successful", - other_id, auth_method_names, AUTH_RSA); + /* We are currently fixed to SHA1 hashes. + * TODO: allow other hash algorithms and note it in "auth" */ + if (public->verify(public, SIGN_RSA_EMSA_PKCS1_SHA1, octets, auth_data)) + { + DBG1(DBG_IKE, "authentication of %D with %N successful", + other_id, auth_method_names, AUTH_RSA); + status = SUCCESS; + } + public->destroy(public); } + else + { + DBG1(DBG_IKE, "no trusted public key found for %D", other_id); + } + chunk_free(&octets); return status; } @@ -94,43 +102,47 @@ static status_t build(private_rsa_authenticator_t *this, chunk_t ike_sa_init, chunk_t other_nonce, auth_payload_t **auth_payload) { chunk_t octets, auth_data; - status_t status; - rsa_public_key_t *my_pubkey; + status_t status = FAILED; + private_key_t *private; identification_t *my_id; prf_t *prf; + auth_info_t *auth; my_id = this->ike_sa->get_my_id(this->ike_sa); - DBG1(DBG_IKE, "authentication of '%D' (myself) with %N", + DBG1(DBG_IKE, "authentication of %D (myself) with %N", my_id, auth_method_names, AUTH_RSA); - DBG2(DBG_IKE, "looking for RSA public key belonging to '%D'...", my_id); - - my_pubkey = charon->credentials->get_rsa_public_key(charon->credentials, my_id); - if (my_pubkey == NULL) + + auth = this->ike_sa->get_my_auth(this->ike_sa); + private = charon->credentials->get_private(charon->credentials, KEY_RSA, + my_id, auth); + if (private == NULL) { - DBG1(DBG_IKE, "no RSA public key found for '%D'", my_id); + DBG1(DBG_IKE, "no RSA private key found for %D", my_id); return NOT_FOUND; } - DBG2(DBG_IKE, " matching RSA public key found"); - prf = this->ike_sa->get_prf(this->ike_sa); prf->set_key(prf, this->ike_sa->get_skp_build(this->ike_sa)); octets = build_tbs_octets(ike_sa_init, other_nonce, my_id, prf); - status = charon->credentials->rsa_signature(charon->credentials, - my_pubkey, HASH_SHA1, octets, &auth_data); - chunk_free(&octets); - - if (status != SUCCESS) + /* we currently use always SHA1 for signatures, + * TODO: support other hashes depending on configuration/auth */ + if (private->sign(private, SIGN_RSA_EMSA_PKCS1_SHA1, octets, &auth_data)) { - DBG1(DBG_IKE, "building RSA signature with SHA-1 hash failed"); - return status; + auth_payload_t *payload = auth_payload_create(); + payload->set_auth_method(payload, AUTH_RSA); + payload->set_data(payload, auth_data); + *auth_payload = payload; + chunk_free(&auth_data); + status = SUCCESS; + DBG2(DBG_IKE, "successfully signed with RSA private key"); } - DBG2(DBG_IKE, "successfully signed with RSA private key"); + else + { + DBG1(DBG_IKE, "building RSA signature failed"); + } + chunk_free(&octets); + private->destroy(private); - *auth_payload = auth_payload_create(); - (*auth_payload)->set_auth_method(*auth_payload, AUTH_RSA); - (*auth_payload)->set_data(*auth_payload, auth_data); - chunk_free(&auth_data); - return SUCCESS; + return status; } /** diff --git a/src/charon/sa/authenticators/rsa_authenticator.h b/src/charon/sa/authenticators/rsa_authenticator.h index cc5cc0150..f5e41a917 100644 --- a/src/charon/sa/authenticators/rsa_authenticator.h +++ b/src/charon/sa/authenticators/rsa_authenticator.h @@ -1,10 +1,3 @@ -/** - * @file rsa_authenticator.h - * - * @brief Interface of rsa_authenticator_t. - * - */ - /* * Copyright (C) 2006 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup rsa_authenticator rsa_authenticator + * @{ @ingroup authenticators */ #ifndef RSA_AUTHENTICATOR_H_ @@ -28,13 +28,7 @@ typedef struct rsa_authenticator_t rsa_authenticator_t; #include /** - * @brief Implementation of the authenticator_t interface using AUTH_RSA. - * - * @b Constructors: - * - rsa_authenticator_create() - * - authenticator_create() using auth_method AUTH_RSA - * - * @ingroup authenticators + * Implementation of the authenticator_t interface using AUTH_RSA. */ struct rsa_authenticator_t { @@ -45,13 +39,11 @@ struct rsa_authenticator_t { }; /** - * @brief Creates an authenticator for AUTH_RSA. + * Creates an authenticator for AUTH_RSA. * * @param ike_sa associated ike_sa * @return rsa_authenticator_t object - * - * @ingroup authenticators */ rsa_authenticator_t *rsa_authenticator_create(ike_sa_t *ike_sa); -#endif /* RSA_AUTHENTICATOR_H_ */ +#endif /* RSA_AUTHENTICATOR_H_ @} */ diff --git a/src/charon/sa/child_sa.c b/src/charon/sa/child_sa.c index b6c71a8b5..225b8902d 100644 --- a/src/charon/sa/child_sa.c +++ b/src/charon/sa/child_sa.c @@ -1,10 +1,3 @@ -/** - * @file child_sa.c - * - * @brief Implementation of child_sa_t. - * - */ - /* * Copyright (C) 2005-2007 Martin Willi * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger @@ -20,6 +13,8 @@ * 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. + * + * $Id$ */ #define _GNU_SOURCE diff --git a/src/charon/sa/child_sa.h b/src/charon/sa/child_sa.h index b801dd012..b8186ef51 100644 --- a/src/charon/sa/child_sa.h +++ b/src/charon/sa/child_sa.h @@ -1,10 +1,3 @@ -/** - * @file child_sa.h - * - * @brief Interface of child_sa_t. - * - */ - /* * Copyright (C) 2006-2007 Martin Willi * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger @@ -19,8 +12,14 @@ * 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. + * + * $Id$ */ +/** + * @defgroup child_sa child_sa + * @{ @ingroup sa + */ #ifndef CHILD_SA_H_ #define CHILD_SA_H_ @@ -35,7 +34,7 @@ typedef struct child_sa_t child_sa_t; #include /** - * @brief States of a CHILD_SA + * States of a CHILD_SA */ enum child_sa_state_t { @@ -71,7 +70,7 @@ enum child_sa_state_t { extern enum_name_t *child_sa_state_names; /** - * @brief Represents an IPsec SAs between two hosts. + * Represents an IPsec SAs between two hosts. * * A child_sa_t contains two SAs. SAs for both * directions are managed in one child_sa_t object. Both @@ -86,57 +85,47 @@ extern enum_name_t *child_sa_state_names; * - A calls child_sa_t.update to update the already allocated SPIs with the chosen proposal * * Once SAs are set up, policies can be added using add_policies. - * - * - * @b Constructors: - * - child_sa_create() - * - * @ingroup sa */ struct child_sa_t { /** - * @brief Get the name of the config this CHILD_SA uses. + * Get the name of the config this CHILD_SA uses. * - * @param this calling object - * @return name + * @return name */ char* (*get_name) (child_sa_t *this); /** - * @brief Get the reqid of the CHILD SA. + * Get the reqid of the CHILD SA. * * Every CHILD_SA has a reqid. The kernel uses this ID to * identify it. * - * @param this calling object * @return reqid of the CHILD SA */ u_int32_t (*get_reqid)(child_sa_t *this); /** - * @brief Get the SPI of this CHILD_SA. + * Get the SPI of this CHILD_SA. * * Set the boolean parameter inbound to TRUE to * get the SPI for which we receive packets, use * FALSE to get those we use for sending packets. * - * @param this calling object * @param inbound TRUE to get inbound SPI, FALSE for outbound. * @return spi of the CHILD SA */ u_int32_t (*get_spi) (child_sa_t *this, bool inbound); /** - * @brief Get the protocol which this CHILD_SA uses to protect traffic. + * Get the protocol which this CHILD_SA uses to protect traffic. * - * @param this calling object * @return AH | ESP */ protocol_id_t (*get_protocol) (child_sa_t *this); /** - * @brief Get info and statistics about this CHILD_SA. + * Get info and statistics about this CHILD_SA. * * @param mode mode this IKE_SA uses * @param encr_algo encryption algorithm used by this CHILD_SA. @@ -155,7 +144,7 @@ struct child_sa_t { u_int32_t *use_fwd); /** - * @brief Allocate SPIs for given proposals. + * Allocate SPIs for given proposals. * * Since the kernel manages SPIs for us, we need * to allocate them. If a proposal contains more @@ -163,15 +152,13 @@ struct child_sa_t { * allocated. SPIs are stored internally and written * back to the proposal. * - * @param this calling object * @param proposals list of proposals for which SPIs are allocated */ status_t (*alloc)(child_sa_t *this, linked_list_t* proposals); /** - * @brief Install the kernel SAs for a proposal, without previous SPI allocation. + * Install the kernel SAs for a proposal, without previous SPI allocation. * - * @param this calling object * @param proposal proposal for which SPIs are allocated * @param mode mode for the CHILD_SA * @param prf_plus key material to use for key derivation @@ -181,11 +168,10 @@ struct child_sa_t { prf_plus_t *prf_plus); /** - * @brief Install the kernel SAs for a proposal, after SPIs have been allocated. + * Install the kernel SAs for a proposal, after SPIs have been allocated. * * Updates an SA, for which SPIs are already allocated via alloc(). * - * @param this calling object * @param proposal proposal for which SPIs are allocated * @param mode mode for the CHILD_SA * @param prf_plus key material to use for key derivation @@ -195,11 +181,10 @@ struct child_sa_t { prf_plus_t *prf_plus); /** - * @brief Update the hosts in the kernel SAs and policies. + * Update the hosts in the kernel SAs and policies. * * The CHILD must be INSTALLED to do this update. * - * @param this calling object * @param me the new local host * @param other the new remote host * @param TRUE to use UDP encapsulation for NAT traversal @@ -209,12 +194,11 @@ struct child_sa_t { bool encap); /** - * @brief Install the policies using some traffic selectors. + * Install the policies using some traffic selectors. * * Supplied lists of traffic_selector_t's specify the policies * to use for this child sa. * - * @param this calling object * @param my_ts traffic selectors for local site * @param other_ts traffic selectors for remote site * @param mode mode for the SA: tunnel/transport @@ -224,18 +208,16 @@ struct child_sa_t { linked_list_t *other_ts_list, mode_t mode); /** - * @brief Get the traffic selectors of added policies of local host. + * Get the traffic selectors of added policies of local host. * - * @param this calling object * @param local TRUE for own traffic selectors, FALSE for remote * @return list of traffic selectors */ linked_list_t* (*get_traffic_selectors) (child_sa_t *this, bool local); /** - * @brief Get the time of this child_sa_t's last use (i.e. last use of any of its policies) + * Get the time of this child_sa_t's last use (i.e. last use of any of its policies) * - * @param this calling object * @param inbound query for in- or outbound usage * @param use_time the time * @return SUCCESS or FAILED @@ -243,48 +225,42 @@ struct child_sa_t { status_t (*get_use_time) (child_sa_t *this, bool inbound, time_t *use_time); /** - * @brief Get the state of the CHILD_SA. - * - * @param this calling object + * Get the state of the CHILD_SA. */ child_sa_state_t (*get_state) (child_sa_t *this); /** - * @brief Set the state of the CHILD_SA. + * Set the state of the CHILD_SA. * - * @param this calling object + * @param state state to set on CHILD_SA */ void (*set_state) (child_sa_t *this, child_sa_state_t state); /** - * @brief Get the config used to set up this child sa. + * Get the config used to set up this child sa. * - * @param this calling object * @return child_cfg */ child_cfg_t* (*get_config) (child_sa_t *this); /** - * @brief Set the virtual IP used received from IRAS. + * Set the virtual IP used received from IRAS. * * To allow proper setup of firewall rules, the virtual IP is required * for filtering. * - * @param this calling object * @param ip own virtual IP */ void (*set_virtual_ip) (child_sa_t *this, host_t *ip); /** - * @brief Destroys a child_sa. - * - * @param this calling object + * Destroys a child_sa. */ void (*destroy) (child_sa_t *this); }; /** - * @brief Constructor to create a new child_sa_t. + * Constructor to create a new child_sa_t. * * @param me own address * @param other remote address @@ -294,11 +270,9 @@ struct child_sa_t { * @param reqid reqid of old CHILD_SA when rekeying, 0 otherwise * @param encap TRUE to enable UDP encapsulation (NAT traversal) * @return child_sa_t object - * - * @ingroup sa */ child_sa_t * child_sa_create(host_t *me, host_t *other, identification_t *my_id, identification_t* other_id, child_cfg_t *config, u_int32_t reqid, bool encap); -#endif /*CHILD_SA_H_*/ +#endif /*CHILD_SA_H_ @} */ diff --git a/src/charon/sa/connect_manager.c b/src/charon/sa/connect_manager.c index f40af4eed..a913a0735 100644 --- a/src/charon/sa/connect_manager.c +++ b/src/charon/sa/connect_manager.c @@ -1,10 +1,3 @@ -/** - * @file connect_manager.c - * - * @brief Implementation of connect_manager_t. - * - */ - /* * Copyright (C) 2007 Tobias Brunner * Hochschule fuer Technik Rapperswil @@ -18,6 +11,8 @@ * 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. + * + * $Id$ */ #include "connect_manager.h" @@ -1516,7 +1511,14 @@ connect_manager_t *connect_manager_create() this->public.set_responder_data = (status_t(*)(connect_manager_t*,chunk_t,chunk_t,linked_list_t*))set_responder_data; this->public.process_check = (void(*)(connect_manager_t*,message_t*))process_check; - this->hasher = hasher_create(HASH_SHA1); + this->hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); + if (hasher == NULL) + { + DBG1(DBG_IKE, "unable to create connect manager, SHA1 not supported"); + free(this); + return NULL; + } + this->checklists = linked_list_create(); this->initiated = linked_list_create(); diff --git a/src/charon/sa/connect_manager.h b/src/charon/sa/connect_manager.h index 2f3e9109b..c1a443557 100644 --- a/src/charon/sa/connect_manager.h +++ b/src/charon/sa/connect_manager.h @@ -1,10 +1,3 @@ -/** - * @file connect_manager.h - * - * @brief Interface of connect_manager_t. - * - */ - /* * Copyright (C) 2007 Tobias Brunner * Hochschule fuer Technik Rapperswil @@ -18,6 +11,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup connect_manager connect_manager + * @{ @ingroup sa */ #ifndef CONNECT_MANAGER_H_ @@ -31,21 +31,15 @@ typedef struct connect_manager_t connect_manager_t; #include /** - * @brief The connection manager is responsible for establishing a direct + * The connection manager is responsible for establishing a direct * connection with another peer. - * - * @b Constructors: - * - connect_manager_create() - * - * @ingroup sa */ struct connect_manager_t { /** - * @brief Checks if a there is already a mediated connection registered + * Checks if a there is already a mediated connection registered * between two peers. * - * @param this the manager object * @param id my id * @param peer_id the other peer's id * @param mediated_sa the IKE_SA ID of the mediated connection @@ -59,10 +53,9 @@ struct connect_manager_t { ike_sa_id_t *mediated_sa, child_cfg_t *child); /** - * @brief Checks if there are waiting connections with a specific peer. + * Checks if there are waiting connections with a specific peer. * If so, reinitiate them. * - * @param this the manager object * @param id my id * @param peer_id the other peer's id */ @@ -70,9 +63,8 @@ struct connect_manager_t { identification_t *id, identification_t *peer_id); /** - * @brief Creates a checklist and sets the initiator's data. + * Creates a checklist and sets the initiator's data. * - * @param this the manager object * @param initiator ID of the initiator * @param responder ID of the responder * @param session_id the session ID provided by the initiator @@ -80,18 +72,16 @@ struct connect_manager_t { * @param endpoints the initiator's endpoints * @param is_initiator TRUE, if the caller of this method is the initiator * FALSE, otherwise - * @returns - * SUCCESS + * @returns SUCCESS */ status_t (*set_initiator_data) (connect_manager_t *this, identification_t *initiator, identification_t *responder, chunk_t session_id, chunk_t key, linked_list_t *endpoints, bool is_initiator); /** - * @brief Updates a checklist and sets the responder's data. The checklist's + * Updates a checklist and sets the responder's data. The checklist's * state is advanced to WAITING which means that checks will be sent. * - * @param this the manager object * @param session_id the session ID * @param chunk_t the responder's key * @param endpoints the responder's endpoints @@ -104,28 +94,23 @@ struct connect_manager_t { /** - * @brief Processes a connectivity check + * Processes a connectivity check * - * @param this the manager object * @param message the received message */ void (*process_check) (connect_manager_t *this, message_t *message); /** - * @brief Destroys the manager with all data. - * - * @param this the manager object + * Destroys the manager with all data. */ void (*destroy) (connect_manager_t *this); }; /** - * @brief Create a manager. + * Create a manager. * * @returns connect_manager_t object - * - * @ingroup sa */ connect_manager_t *connect_manager_create(void); -#endif /*CONNECT_MANAGER_H_*/ +#endif /*CONNECT_MANAGER_H_ @} */ diff --git a/src/charon/sa/ike_sa.c b/src/charon/sa/ike_sa.c index 93aa08965..4e28b27dc 100644 --- a/src/charon/sa/ike_sa.c +++ b/src/charon/sa/ike_sa.c @@ -1,10 +1,3 @@ -/** - * @file ike_sa.c - * - * @brief Implementation of ike_sa_t. - * - */ - /* * Copyright (C) 2006-2007 Tobias Brunner * Copyright (C) 2006 Daniel Roethlisberger @@ -21,6 +14,8 @@ * 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. + * + * $Id$ */ #include @@ -53,7 +48,8 @@ #include #include #include -#include +#include +#include #include #include #include @@ -121,6 +117,16 @@ struct private_ike_sa_t { */ peer_cfg_t *peer_cfg; + /** + * associated authentication/authorization info for local peer + */ + auth_info_t *my_auth; + + /** + * associated authentication/authorization info for remote peer + */ + auth_info_t *other_auth; + /** * Juggles tasks to process messages */ @@ -153,11 +159,6 @@ struct private_ike_sa_t { */ identification_t *other_id; - /** - * CA that issued the certificate of other - */ - ca_info_t *other_ca; - /** * set of extensions the peer supports */ @@ -425,6 +426,22 @@ static void set_peer_cfg(private_ike_sa_t *this, peer_cfg_t *peer_cfg) } } +/** + * Implementation of ike_sa_t.get_my_auth. + */ +static auth_info_t* get_my_auth(private_ike_sa_t *this) +{ + return this->my_auth; +} + +/** + * Implementation of ike_sa_t.get_other_auth. + */ +static auth_info_t* get_other_auth(private_ike_sa_t *this) +{ + return this->other_auth; +} + /** * Implementation of ike_sa_t.send_keepalive */ @@ -1020,10 +1037,12 @@ static status_t initiate(private_ike_sa_t *this, child_cfg_t *child_cfg) this->task_manager->queue_task(this->task_manager, task); task = (task_t*)ike_natd_create(&this->public, TRUE); this->task_manager->queue_task(this->task_manager, task); - task = (task_t*)ike_cert_create(&this->public, TRUE); + task = (task_t*)ike_cert_pre_create(&this->public, TRUE); this->task_manager->queue_task(this->task_manager, task); task = (task_t*)ike_auth_create(&this->public, TRUE); this->task_manager->queue_task(this->task_manager, task); + task = (task_t*)ike_cert_post_create(&this->public, TRUE); + this->task_manager->queue_task(this->task_manager, task); task = (task_t*)ike_config_create(&this->public, TRUE); this->task_manager->queue_task(this->task_manager, task); task = (task_t*)ike_auth_lifetime_create(&this->public, TRUE); @@ -1112,10 +1131,12 @@ static status_t acquire(private_ike_sa_t *this, u_int32_t reqid) this->task_manager->queue_task(this->task_manager, task); task = (task_t*)ike_natd_create(&this->public, TRUE); this->task_manager->queue_task(this->task_manager, task); - task = (task_t*)ike_cert_create(&this->public, TRUE); + task = (task_t*)ike_cert_pre_create(&this->public, TRUE); this->task_manager->queue_task(this->task_manager, task); task = (task_t*)ike_auth_create(&this->public, TRUE); this->task_manager->queue_task(this->task_manager, task); + task = (task_t*)ike_cert_post_create(&this->public, TRUE); + this->task_manager->queue_task(this->task_manager, task); task = (task_t*)ike_config_create(&this->public, TRUE); this->task_manager->queue_task(this->task_manager, task); task = (task_t*)ike_auth_lifetime_create(&this->public, TRUE); @@ -1502,12 +1523,14 @@ static status_t retransmit(private_ike_sa_t *this, u_int32_t message_id) new->task_manager->queue_task(new->task_manager, task); task = (task_t*)ike_natd_create(&new->public, TRUE); new->task_manager->queue_task(new->task_manager, task); - task = (task_t*)ike_cert_create(&new->public, TRUE); + task = (task_t*)ike_cert_pre_create(&new->public, TRUE); new->task_manager->queue_task(new->task_manager, task); task = (task_t*)ike_config_create(&new->public, TRUE); new->task_manager->queue_task(new->task_manager, task); task = (task_t*)ike_auth_create(&new->public, TRUE); new->task_manager->queue_task(new->task_manager, task); + task = (task_t*)ike_cert_post_create(&new->public, TRUE); + new->task_manager->queue_task(new->task_manager, task); while (to_restart->remove_last(to_restart, (void**)&child_cfg) == SUCCESS) { @@ -1606,22 +1629,6 @@ static void set_other_id(private_ike_sa_t *this, identification_t *other) this->other_id = other; } -/** - * Implementation of ike_sa_t.get_other_ca. - */ -static ca_info_t* get_other_ca(private_ike_sa_t *this) -{ - return this->other_ca; -} - -/** - * Implementation of ike_sa_t.set_other_ca. - */ -static void set_other_ca(private_ike_sa_t *this, ca_info_t *other_ca) -{ - this->other_ca = other_ca; -} - /** * Implementation of ike_sa_t.derive_keys. */ @@ -1643,14 +1650,16 @@ static status_t derive_keys(private_ike_sa_t *this, /* Create SAs general purpose PRF first, we may use it here */ if (!proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, &algo)) { - DBG1(DBG_IKE, "key derivation failed: no PSEUDO_RANDOM_FUNCTION");; + DBG1(DBG_IKE, "no %N selected", + transform_type_names, PSEUDO_RANDOM_FUNCTION); return FAILED; } - this->prf = prf_create(algo->algorithm); + this->prf = lib->crypto->create_prf(lib->crypto, algo->algorithm); if (this->prf == NULL) { - DBG1(DBG_IKE, "key derivation failed: PSEUDO_RANDOM_FUNCTION " - "%N not supported!", pseudo_random_function_names, algo->algorithm); + DBG1(DBG_IKE, "%N %N not supported!", + transform_type_names, PSEUDO_RANDOM_FUNCTION, + pseudo_random_function_names, algo->algorithm); return FAILED; } @@ -1694,7 +1703,7 @@ static status_t derive_keys(private_ike_sa_t *this, /* SK_d is used for generating CHILD_SA key mat => child_prf */ proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, &algo); - this->child_prf = prf_create(algo->algorithm); + this->child_prf = lib->crypto->create_prf(lib->crypto, algo->algorithm); key_size = this->child_prf->get_key_size(this->child_prf); prf_plus->allocate_bytes(prf_plus, key_size, &key); DBG4(DBG_IKE, "Sk_d secret %B", &key); @@ -1704,15 +1713,18 @@ static status_t derive_keys(private_ike_sa_t *this, /* SK_ai/SK_ar used for integrity protection => signer_in/signer_out */ if (!proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &algo)) { - DBG1(DBG_IKE, "key derivation failed: no INTEGRITY_ALGORITHM"); + DBG1(DBG_IKE, "no %N selected", + transform_type_names, INTEGRITY_ALGORITHM); return FAILED; } - signer_i = signer_create(algo->algorithm); - signer_r = signer_create(algo->algorithm); + signer_i = lib->crypto->create_signer(lib->crypto, algo->algorithm); + signer_r = lib->crypto->create_signer(lib->crypto, algo->algorithm); if (signer_i == NULL || signer_r == NULL) { - DBG1(DBG_IKE, "key derivation failed: INTEGRITY_ALGORITHM " - "%N not supported!", integrity_algorithm_names ,algo->algorithm); + DBG1(DBG_IKE, "%N %N not supported!", + transform_type_names, INTEGRITY_ALGORITHM, + integrity_algorithm_names ,algo->algorithm); + prf_plus->destroy(prf_plus); return FAILED; } key_size = signer_i->get_key_size(signer_i); @@ -1741,16 +1753,21 @@ static status_t derive_keys(private_ike_sa_t *this, /* SK_ei/SK_er used for encryption => crypter_in/crypter_out */ if (!proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &algo)) { - DBG1(DBG_IKE, "key derivation failed: no ENCRYPTION_ALGORITHM"); + DBG1(DBG_IKE, "no %N selected", + transform_type_names, ENCRYPTION_ALGORITHM); + prf_plus->destroy(prf_plus); return FAILED; } - crypter_i = crypter_create(algo->algorithm, algo->key_size / 8); - crypter_r = crypter_create(algo->algorithm, algo->key_size / 8); + crypter_i = lib->crypto->create_crypter(lib->crypto, algo->algorithm, + algo->key_size / 8); + crypter_r = lib->crypto->create_crypter(lib->crypto, algo->algorithm, + algo->key_size / 8); if (crypter_i == NULL || crypter_r == NULL) { - DBG1(DBG_IKE, "key derivation failed: ENCRYPTION_ALGORITHM " - "%N (key size %d) not supported!", - encryption_algorithm_names, algo->algorithm, algo->key_size); + DBG1(DBG_IKE, "%N %N (key size %d) not supported!", + transform_type_names, ENCRYPTION_ALGORITHM, + encryption_algorithm_names, algo->algorithm, algo->key_size); + prf_plus->destroy(prf_plus); return FAILED; } key_size = crypter_i->get_key_size(crypter_i); @@ -2309,6 +2326,8 @@ static void destroy(private_ike_sa_t *this) DESTROY_IF(this->ike_cfg); DESTROY_IF(this->peer_cfg); + DESTROY_IF(this->my_auth); + DESTROY_IF(this->other_auth); this->ike_sa_id->destroy(this->ike_sa_id); this->task_manager->destroy(this->task_manager); @@ -2337,6 +2356,8 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) this->public.set_ike_cfg = (void (*)(ike_sa_t*,ike_cfg_t*))set_ike_cfg; this->public.get_peer_cfg = (peer_cfg_t* (*)(ike_sa_t*))get_peer_cfg; this->public.set_peer_cfg = (void (*)(ike_sa_t*,peer_cfg_t*))set_peer_cfg; + this->public.get_my_auth = (auth_info_t*(*)(ike_sa_t*))get_my_auth; + this->public.get_other_auth = (auth_info_t*(*)(ike_sa_t*))get_other_auth; this->public.get_id = (ike_sa_id_t* (*)(ike_sa_t*)) get_id; this->public.get_my_host = (host_t* (*)(ike_sa_t*)) get_my_host; this->public.set_my_host = (void (*)(ike_sa_t*,host_t*)) set_my_host; @@ -2347,8 +2368,6 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) this->public.set_my_id = (void (*)(ike_sa_t*,identification_t*)) set_my_id; this->public.get_other_id = (identification_t* (*)(ike_sa_t*)) get_other_id; this->public.set_other_id = (void (*)(ike_sa_t*,identification_t*)) set_other_id; - this->public.get_other_ca = (ca_info_t* (*)(ike_sa_t*)) get_other_ca; - this->public.set_other_ca = (void (*)(ike_sa_t*,ca_info_t*)) set_other_ca; this->public.enable_extension = (void(*)(ike_sa_t*, ike_extension_t extension))enable_extension; this->public.supports_extension = (bool(*)(ike_sa_t*, ike_extension_t extension))supports_extension; this->public.set_condition = (void (*)(ike_sa_t*, ike_condition_t,bool)) set_condition; @@ -2401,7 +2420,6 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) this->other_host = host_create_any(AF_INET); this->my_id = identification_create_from_encoding(ID_ANY, chunk_empty); this->other_id = identification_create_from_encoding(ID_ANY, chunk_empty); - this->other_ca = NULL; this->extensions = 0; this->conditions = 0; this->crypter_in = NULL; @@ -2420,6 +2438,8 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) this->time.delete = 0; this->ike_cfg = NULL; this->peer_cfg = NULL; + this->my_auth = auth_info_create(); + this->other_auth = auth_info_create(); this->task_manager = task_manager_create(&this->public); this->unique_id = ++unique_id; this->my_virtual_ip = NULL; diff --git a/src/charon/sa/ike_sa.h b/src/charon/sa/ike_sa.h index 975447d9c..f3d96f9de 100644 --- a/src/charon/sa/ike_sa.h +++ b/src/charon/sa/ike_sa.h @@ -1,10 +1,3 @@ -/** - * @file ike_sa.h - * - * @brief Interface of ike_sa_t. - * - */ - /* * Copyright (C) 2006-2007 Tobias Brunner * Copyright (C) 2006 Daniel Roethlisberger @@ -21,6 +14,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup ike_sa ike_sa + * @{ @ingroup sa */ #ifndef IKE_SA_H_ @@ -42,40 +42,32 @@ typedef struct ike_sa_t ike_sa_t; #include #include #include -#include #include #include +#include /** * Timeout in milliseconds after that a half open IKE_SA gets deleted. - * - * @ingroup sa */ #define HALF_OPEN_IKE_SA_TIMEOUT 30000 /** * Interval to send keepalives when NATed, in seconds. - * - * @ingroup sa */ #define KEEPALIVE_INTERVAL 20 /** * After which time rekeying should be retried if it failed, in seconds. - * - * @ingroup sa */ #define RETRY_INTERVAL 30 /** * Jitter to subtract from RETRY_INTERVAL to randomize rekey retry. - * - * @ingroup sa */ #define RETRY_JITTER 20 /** - * @brief Extensions (or optional features) the peer supports + * Extensions (or optional features) the peer supports */ enum ike_extension_t { @@ -91,7 +83,7 @@ enum ike_extension_t { }; /** - * @brief Conditions of an IKE_SA, change during its lifetime + * Conditions of an IKE_SA, change during its lifetime */ enum ike_condition_t { @@ -119,6 +111,11 @@ enum ike_condition_t { * peer has ben authenticated using EAP */ COND_EAP_AUTHENTICATED = (1<<4), + + /** + * received a certificate request from the peer + */ + COND_CERTREQ_SEEN = (1<<4), }; /** @@ -138,7 +135,7 @@ enum statistic_t { }; /** - * @brief State of an IKE_SA. + * State of an IKE_SA. * * An IKE_SA passes various states in its lifetime. A newly created * SA is in the state CREATED. @@ -173,8 +170,6 @@ enum statistic_t { X / \ @endverbatim - * - * @ingroup sa */ enum ike_sa_state_t { @@ -210,365 +205,323 @@ enum ike_sa_state_t { extern enum_name_t *ike_sa_state_names; /** - * @brief Class ike_sa_t representing an IKE_SA. + * Class ike_sa_t representing an IKE_SA. * * An IKE_SA contains crypto information related to a connection * with a peer. It contains multiple IPsec CHILD_SA, for which * it is responsible. All traffic is handled by an IKE_SA, using * the task manager and its tasks. - * - * @b Constructors: - * - ike_sa_create() - * - * @ingroup sa */ struct ike_sa_t { /** - * @brief Get the id of the SA. + * Get the id of the SA. * * Returned ike_sa_id_t object is not getting cloned! * - * @param this calling object * @return ike_sa's ike_sa_id_t */ ike_sa_id_t* (*get_id) (ike_sa_t *this); /** - * @brief Get the numerical ID uniquely defining this IKE_SA. + * Get the numerical ID uniquely defining this IKE_SA. * - * @param this calling object * @return unique ID */ u_int32_t (*get_unique_id) (ike_sa_t *this); /** - * @brief Get the state of the IKE_SA. + * Get the state of the IKE_SA. * - * @param this calling object * @return state of the IKE_SA */ ike_sa_state_t (*get_state) (ike_sa_t *this); /** - * @brief Set the state of the IKE_SA. + * Set the state of the IKE_SA. * - * @param this calling object * @param state state to set for the IKE_SA */ void (*set_state) (ike_sa_t *this, ike_sa_state_t ike_sa); /** - * @brief Get the name of the connection this IKE_SA uses. + * Get the name of the connection this IKE_SA uses. * - * @param this calling object * @return name */ char* (*get_name) (ike_sa_t *this); /** - * @brief Get statistic values from the IKE_SA. + * Get statistic values from the IKE_SA. * - * @param this calling object * @param kind kind of requested value * @return value as integer */ u_int32_t (*get_statistic)(ike_sa_t *this, statistic_t kind); /** - * @brief Get the own host address. + * Get the own host address. * - * @param this calling object * @return host address */ host_t* (*get_my_host) (ike_sa_t *this); /** - * @brief Set the own host address. + * Set the own host address. * - * @param this calling object * @param me host address */ void (*set_my_host) (ike_sa_t *this, host_t *me); /** - * @brief Get the other peers host address. + * Get the other peers host address. * - * @param this calling object * @return host address */ host_t* (*get_other_host) (ike_sa_t *this); /** - * @brief Set the others host address. + * Set the others host address. * - * @param this calling object * @param other host address */ void (*set_other_host) (ike_sa_t *this, host_t *other); /** - * @brief Update the IKE_SAs host. + * Update the IKE_SAs host. * * Hosts may be NULL to use current host. * - * @param this calling object * @param me new local host address, or NULL * @param other new remote host address, or NULL */ void (*update_hosts)(ike_sa_t *this, host_t *me, host_t *other); /** - * @brief Get the own identification. + * Get the own identification. * - * @param this calling object * @return identification */ identification_t* (*get_my_id) (ike_sa_t *this); /** - * @brief Set the own identification. + * Set the own identification. * - * @param this calling object * @param me identification */ void (*set_my_id) (ike_sa_t *this, identification_t *me); /** - * @brief Get the other peer's identification. + * Get the other peer's identification. * - * @param this calling object * @return identification */ identification_t* (*get_other_id) (ike_sa_t *this); /** - * @brief Set the other peer's identification. + * Set the other peer's identification. * - * @param this calling object * @param other identification */ void (*set_other_id) (ike_sa_t *this, identification_t *other); /** - * @brief Get the other peer's certification authority + * Get the config used to setup this IKE_SA. * - * @param this calling object - * @return ca_info_t record of other ca - */ - ca_info_t* (*get_other_ca) (ike_sa_t *this); - - /** - * @brief Set the other peer's certification authority - * - * @param this calling object - * @param other_ca ca_info_t record of other ca - */ - void (*set_other_ca) (ike_sa_t *this, ca_info_t *other_ca); - - /** - * @brief Get the config used to setup this IKE_SA. - * - * @param this calling object * @return ike_config */ ike_cfg_t* (*get_ike_cfg) (ike_sa_t *this); /** - * @brief Set the config to setup this IKE_SA. + * Set the config to setup this IKE_SA. * - * @param this calling object * @param config ike_config to use */ void (*set_ike_cfg) (ike_sa_t *this, ike_cfg_t* config); /** - * @brief Get the peer config used by this IKE_SA. + * Get the peer config used by this IKE_SA. * - * @param this calling object * @return peer_config */ peer_cfg_t* (*get_peer_cfg) (ike_sa_t *this); /** - * @brief Set the peer config to use with this IKE_SA. + * Set the peer config to use with this IKE_SA. * - * @param this calling object * @param config peer_config to use */ void (*set_peer_cfg) (ike_sa_t *this, peer_cfg_t *config); /** - * @brief Add an additional address for the peer. + * Get authentication/authorization info for local peer. + * + * @return auth_info for me + */ + auth_info_t* (*get_my_auth)(ike_sa_t *this); + + /** + * Get authentication/authorization info for remote peer. + * + * @return auth_info for me + */ + auth_info_t* (*get_other_auth)(ike_sa_t *this); + + /** + * Add an additional address for the peer. * * In MOBIKE, a peer may transmit additional addresses where it is * reachable. These are stored in the IKE_SA. * The own list of addresses is not stored, they are queried from * the kernel when required. * - * @param this calling object * @param host host to add to list */ void (*add_additional_address)(ike_sa_t *this, host_t *host); /** - * @brief Create an iterator over all additional addresses of the peer. + * Create an iterator over all additional addresses of the peer. * - * @param this calling object * @return iterator over addresses */ iterator_t* (*create_additional_address_iterator)(ike_sa_t *this); /** - * @brief Enable an extension the peer supports. + * Enable an extension the peer supports. * * If support for an IKE extension is detected, this method is called * to enable that extension and behave accordingly. * - * @param this calling object * @param extension extension to enable */ void (*enable_extension)(ike_sa_t *this, ike_extension_t extension); /** - * @brief Check if the peer supports an extension. + * Check if the peer supports an extension. * - * @param this calling object * @param extension extension to check for support * @return TRUE if peer supports it, FALSE otherwise */ bool (*supports_extension)(ike_sa_t *this, ike_extension_t extension); /** - * @brief Enable/disable a condition flag for this IKE_SA. + * Enable/disable a condition flag for this IKE_SA. * - * @param this calling object * @param condition condition to enable/disable * @param enable TRUE to enable condition, FALSE to disable */ void (*set_condition) (ike_sa_t *this, ike_condition_t condition, bool enable); /** - * @brief Check if a condition flag is set. + * Check if a condition flag is set. * - * @param this calling object * @param condition condition to check * @return TRUE if condition flag set, FALSE otherwise */ bool (*has_condition) (ike_sa_t *this, ike_condition_t condition); /** - * @brief Get the number of queued MOBIKE address updates. + * Get the number of queued MOBIKE address updates. * - * @param this calling object * @return number of pending updates */ u_int32_t (*get_pending_updates)(ike_sa_t *this); /** - * @brief Set the number of queued MOBIKE address updates. + * Set the number of queued MOBIKE address updates. * - * @param this calling object * @param updates number of pending updates */ void (*set_pending_updates)(ike_sa_t *this, u_int32_t updates); #ifdef P2P /** - * @brief Get the server reflexive host. + * Get the server reflexive host. * - * @param this calling object * @return server reflexive host */ host_t* (*get_server_reflexive_host) (ike_sa_t *this); /** - * @brief Set the server reflexive host. + * Set the server reflexive host. * - * @param this calling object * @param host server reflexive host */ void (*set_server_reflexive_host) (ike_sa_t *this, host_t *host); /** - * @brief Initiate the mediation of a mediated connection (i.e. initiate a + * Initiate the mediation of a mediated connection (i.e. initiate a * P2P_CONNECT exchange). * - * @param this calling object * @param mediated_cfg peer_cfg of the mediated connection * @return - * - SUCCESS if initialization started - * - DESTROY_ME if initialization failed + * - SUCCESS if initialization started + * - DESTROY_ME if initialization failed */ status_t (*initiate_mediation) (ike_sa_t *this, peer_cfg_t *mediated_cfg); /** - * @brief Initiate the mediated connection + * Initiate the mediated connection * - * @param this calling object * @param me local endpoint (gets cloned) * @param other remote endpoint (gets cloned) * @param childs linked list of child_cfg_t of CHILD_SAs (gets cloned) * @return - * - SUCCESS if initialization started - * - DESTROY_ME if initialization failed + * - SUCCESS if initialization started + * - DESTROY_ME if initialization failed */ status_t (*initiate_mediated) (ike_sa_t *this, host_t *me, host_t *other, linked_list_t *childs); /** - * @brief Relay data from one peer to another (i.e. initiate a + * Relay data from one peer to another (i.e. initiate a * P2P_CONNECT exchange). * * Data is cloned. * - * @param this calling object * @param requester ID of the requesting peer * @param session_id data of the P2P_SESSIONID payload * @param session_key data of the P2P_SESSIONKEY payload * @param endpoints endpoints * @param response TRUE if this is a response * @return - * - SUCCESS if relay started - * - DESTROY_ME if relay failed + * - SUCCESS if relay started + * - DESTROY_ME if relay failed */ status_t (*relay) (ike_sa_t *this, identification_t *requester, chunk_t session_id, chunk_t session_key, linked_list_t *endpoints, bool response); /** - * @brief Send a callback to a peer. + * Send a callback to a peer. * * Data is cloned. * - * @param this calling object * @param peer_id ID of the other peer * @return - * - SUCCESS if response started - * - DESTROY_ME if response failed + * - SUCCESS if response started + * - DESTROY_ME if response failed */ status_t (*callback) (ike_sa_t *this, identification_t *peer_id); /** - * @brief Respond to a P2P_CONNECT request. + * Respond to a P2P_CONNECT request. * * Data is cloned. * - * @param this calling object * @param peer_id ID of the other peer * @param session_id the session ID supplied by the initiator * @return - * - SUCCESS if response started - * - DESTROY_ME if response failed + * - SUCCESS if response started + * - DESTROY_ME if response failed */ status_t (*respond) (ike_sa_t *this, identification_t *peer_id, chunk_t session_id); #endif /* P2P */ /** - * @brief Initiate a new connection. + * Initiate a new connection. * * The configs are owned by the IKE_SA after the call. * - * @param this calling object * @param child_cfg child config to create CHILD from * @return * - SUCCESS if initialization started @@ -577,12 +530,11 @@ struct ike_sa_t { status_t (*initiate) (ike_sa_t *this, child_cfg_t *child_cfg); /** - * @brief Route a policy in the kernel. + * Route a policy in the kernel. * * Installs the policies in the kernel. If traffic matches, * the kernel requests connection setup from the IKE_SA via acquire(). * - * @param this calling object * @param child_cfg child config to route * @return * - SUCCESS if routed successfully @@ -591,9 +543,8 @@ struct ike_sa_t { status_t (*route) (ike_sa_t *this, child_cfg_t *child_cfg); /** - * @brief Unroute a policy in the kernel previously routed. + * Unroute a policy in the kernel previously routed. * - * @param this calling object * @param reqid reqid of CHILD_SA to unroute * @return * - SUCCESS if route removed @@ -603,12 +554,11 @@ struct ike_sa_t { status_t (*unroute) (ike_sa_t *this, u_int32_t reqid); /** - * @brief Acquire connection setup for an installed kernel policy. + * Acquire connection setup for an installed kernel policy. * * If an installed policy raises an acquire, the kernel calls * this function to establish the CHILD_SA (and maybe the IKE_SA). * - * @param this calling object * @param reqid reqid of the CHILD_SA the policy belongs to. * @return * - SUCCESS if initialization started @@ -617,13 +567,12 @@ struct ike_sa_t { status_t (*acquire) (ike_sa_t *this, u_int32_t reqid); /** - * @brief Initiates the deletion of an IKE_SA. + * Initiates the deletion of an IKE_SA. * * Sends a delete message to the remote peer and waits for * its response. If the response comes in, or a timeout occurs, * the IKE SA gets deleted. * - * @param this calling object * @return * - SUCCESS if deletion is initialized * - INVALID_STATE, if the IKE_SA is not in @@ -633,7 +582,7 @@ struct ike_sa_t { status_t (*delete) (ike_sa_t *this); /** - * @brief Update IKE_SAs after network interfaces have changed. + * Update IKE_SAs after network interfaces have changed. * * Whenever the network interface configuration changes, the kernel * interface calls roam() on each IKE_SA. The IKE_SA then checks if @@ -641,21 +590,19 @@ struct ike_sa_t { * If MOBIKE is supported, addresses are updated; If not, the tunnel is * restarted. * - * @param this calling object * @param address TRUE if address list changed, FALSE otherwise * @return SUCCESS, FAILED, DESTROY_ME */ status_t (*roam)(ike_sa_t *this, bool address); /** - * @brief Processes a incoming IKEv2-Message. + * Processes a incoming IKEv2-Message. * * Message processing may fail. If a critical failure occurs, * process_message() return DESTROY_ME. Then the caller must * destroy the IKE_SA immediatly, as it is unusable. * - * @param this calling object - * @param message message to process + * @param message message to process * @return * - SUCCESS * - FAILED @@ -664,12 +611,11 @@ struct ike_sa_t { status_t (*process_message) (ike_sa_t *this, message_t *message); /** - * @brief Generate a IKE message to send it to the peer. + * Generate a IKE message to send it to the peer. * * This method generates all payloads in the message and encrypts/signs * the packet. * - * @param this calling object * @param message message to generate * @param packet generated output packet * @return @@ -681,9 +627,8 @@ struct ike_sa_t { packet_t **packet); /** - * @brief Retransmits a request. + * Retransmits a request. * - * @param this calling object * @param message_id ID of the request to retransmit * @return * - SUCCESS @@ -692,13 +637,12 @@ struct ike_sa_t { status_t (*retransmit) (ike_sa_t *this, u_int32_t message_id); /** - * @brief Sends a DPD request to the peer. + * Sends a DPD request to the peer. * * To check if a peer is still alive, periodic * empty INFORMATIONAL messages are sent if no * other traffic was received. * - * @param this calling object * @return * - SUCCESS * - DESTROY_ME, if peer did not respond @@ -706,19 +650,17 @@ struct ike_sa_t { status_t (*send_dpd) (ike_sa_t *this); /** - * @brief Sends a keep alive packet. + * Sends a keep alive packet. * * To refresh NAT tables in a NAT router * between the peers, periodic empty * UDP packets are sent if no other traffic * was sent. - * - * @param this calling object */ void (*send_keepalive) (ike_sa_t *this); /** - * @brief Derive all keys and create the transforms for IKE communication. + * Derive all keys and create the transforms for IKE communication. * * Keys are derived using the diffie hellman secret, nonces and internal * stored SPIs. @@ -726,7 +668,6 @@ struct ike_sa_t { * existing IKE_SA (rekeying). The SK_d key from the old IKE_SA * is included in the derivation process. * - * @param this calling object * @param proposal proposal which contains algorithms to use * @param secret secret derived from DH exchange, gets freed * @param nonce_i initiators nonce @@ -740,49 +681,43 @@ struct ike_sa_t { bool initiator, prf_t *child_prf, prf_t *old_prf); /** - * @brief Get a multi purpose prf for the negotiated PRF function. + * Get a multi purpose prf for the negotiated PRF function. * - * @param this calling object * @return pointer to prf_t object */ prf_t *(*get_prf) (ike_sa_t *this); /** - * @brief Get the prf-object, which is used to derive keys for child SAs. + * Get the prf-object, which is used to derive keys for child SAs. * - * @param this calling object * @return pointer to prf_t object */ prf_t *(*get_child_prf) (ike_sa_t *this); /** - * @brief Get the key to build outgoing authentication data. + * Get the key to build outgoing authentication data. * - * @param this calling object * @return pointer to prf_t object */ chunk_t (*get_skp_build) (ike_sa_t *this); /** - * @brief Get the key to verify incoming authentication data. + * Get the key to verify incoming authentication data. * - * @param this calling object * @return pointer to prf_t object */ chunk_t (*get_skp_verify) (ike_sa_t *this); /** - * @brief Associates a child SA to this IKE SA + * Associates a child SA to this IKE SA * - * @param this calling object * @param child_sa child_sa to add */ void (*add_child_sa) (ike_sa_t *this, child_sa_t *child_sa); /** - * @brief Get a CHILD_SA identified by protocol and SPI. + * Get a CHILD_SA identified by protocol and SPI. * - * @param this calling object * @param protocol protocol of the SA * @param spi SPI of the CHILD_SA * @param inbound TRUE if SPI is inbound, FALSE if outbound @@ -792,19 +727,17 @@ struct ike_sa_t { u_int32_t spi, bool inbound); /** - * @brief Create an iterator over all CHILD_SAs. + * Create an iterator over all CHILD_SAs. * - * @param this calling object * @return iterator */ iterator_t* (*create_child_sa_iterator) (ike_sa_t *this); /** - * @brief Rekey the CHILD SA with the specified reqid. + * Rekey the CHILD SA with the specified reqid. * * Looks for a CHILD SA owned by this IKE_SA, and start the rekeing. * - * @param this calling object * @param protocol protocol of the SA * @param spi inbound SPI of the CHILD_SA * @return @@ -814,13 +747,12 @@ struct ike_sa_t { status_t (*rekey_child_sa) (ike_sa_t *this, protocol_id_t protocol, u_int32_t spi); /** - * @brief Close the CHILD SA with the specified protocol/SPI. + * Close the CHILD SA with the specified protocol/SPI. * * Looks for a CHILD SA owned by this IKE_SA, deletes it and * notify's the remote peer about the delete. The associated * states and policies in the kernel get deleted, if they exist. * - * @param this calling object * @param protocol protocol of the SA * @param spi inbound SPI of the CHILD_SA * @return @@ -830,11 +762,10 @@ struct ike_sa_t { status_t (*delete_child_sa) (ike_sa_t *this, protocol_id_t protocol, u_int32_t spi); /** - * @brief Destroy a CHILD SA with the specified protocol/SPI. + * Destroy a CHILD SA with the specified protocol/SPI. * * Looks for a CHILD SA owned by this IKE_SA and destroys it. * - * @param this calling object * @param protocol protocol of the SA * @param spi inbound SPI of the CHILD_SA * @return @@ -844,99 +775,89 @@ struct ike_sa_t { status_t (*destroy_child_sa) (ike_sa_t *this, protocol_id_t protocol, u_int32_t spi); /** - * @brief Rekey the IKE_SA. + * Rekey the IKE_SA. * * Sets up a new IKE_SA, moves all CHILDs to it and deletes this IKE_SA. * - * @param this calling object * @return - SUCCESS, if IKE_SA rekeying initiated */ status_t (*rekey) (ike_sa_t *this); /** - * @brief Restablish the IKE_SA. + * Restablish the IKE_SA. * * Create a completely new IKE_SA with authentication, recreates all children * within the IKE_SA, closes this IKE_SA. * - * @param this calling object * @return DESTROY_ME to destroy the IKE_SA */ status_t (*reestablish) (ike_sa_t *this); /** - * @brief Set the lifetime limit received from a AUTH_LIFETIME notify. + * Set the lifetime limit received from a AUTH_LIFETIME notify. * - * @param this calling object * @param lifetime lifetime in seconds */ void (*set_auth_lifetime)(ike_sa_t *this, u_int32_t lifetime); /** - * @brief Set the virtual IP to use for this IKE_SA and its children. + * Set the virtual IP to use for this IKE_SA and its children. * * The virtual IP is assigned per IKE_SA, not per CHILD_SA. It has the same * lifetime as the IKE_SA. * - * @param this calling object + * @param local TRUE to set local address, FALSE for remote + * @param ip IP to set as virtual IP */ void (*set_virtual_ip) (ike_sa_t *this, bool local, host_t *ip); /** - * @brief Get the virtual IP configured. + * Get the virtual IP configured. * - * @param this calling object * @param local TRUE to get local virtual IP, FALSE for remote + * @return host_t *virtual IP */ host_t* (*get_virtual_ip) (ike_sa_t *this, bool local); /** - * @brief Add a DNS server to the system. + * Add a DNS server to the system. * * An IRAS may send a DNS server. To use it, it is installed on the * system. The DNS entry has a lifetime until the IKE_SA gets closed. * - * @param this calling object * @param dns DNS server to install on the system */ void (*add_dns_server) (ike_sa_t *this, host_t *dns); /** - * @brief Inherit all attributes of other to this after rekeying. + * Inherit all attributes of other to this after rekeying. * * When rekeying is completed, all CHILD_SAs, the virtual IP and all * outstanding tasks are moved from other to this. * As this call may initiate inherited tasks, a status is returned. * - * @param this calling object * @param other other task to inherit from * @return DESTROY_ME if initiation of inherited task failed */ status_t (*inherit) (ike_sa_t *this, ike_sa_t *other); /** - * @brief Reset the IKE_SA, useable when initiating fails - * - * @param this calling object + * Reset the IKE_SA, useable when initiating fails */ void (*reset) (ike_sa_t *this); /** - * @brief Destroys a ike_sa_t object. - * - * @param this calling object + * Destroys a ike_sa_t object. */ void (*destroy) (ike_sa_t *this); }; /** - * @brief Creates an ike_sa_t object with a specific ID. + * Creates an ike_sa_t object with a specific ID. * * @param ike_sa_id ike_sa_id_t object to associate with new IKE_SA * @return ike_sa_t object - * - * @ingroup sa */ ike_sa_t *ike_sa_create(ike_sa_id_t *ike_sa_id); -#endif /* IKE_SA_H_ */ +#endif /* IKE_SA_H_ @} */ diff --git a/src/charon/sa/ike_sa_id.c b/src/charon/sa/ike_sa_id.c index a838c0b8a..741051040 100644 --- a/src/charon/sa/ike_sa_id.c +++ b/src/charon/sa/ike_sa_id.c @@ -1,10 +1,3 @@ -/** - * @file ike_sa_id.c - * - * @brief Implementation of ike_sa_id_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,9 +12,10 @@ * 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. + * + * $Id$ */ - #include "ike_sa_id.h" #include diff --git a/src/charon/sa/ike_sa_id.h b/src/charon/sa/ike_sa_id.h index 0606b7222..3d7923539 100644 --- a/src/charon/sa/ike_sa_id.h +++ b/src/charon/sa/ike_sa_id.h @@ -1,10 +1,3 @@ -/** - * @file ike_sa_id.h - * - * @brief Interface of ike_sa_id_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,8 +12,14 @@ * 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. + * + * $Id$ */ +/** + * @defgroup ike_sa_id ike_sa_id + * @{ @ingroup sa + */ #ifndef IKE_SA_ID_H_ #define IKE_SA_ID_H_ @@ -29,119 +28,101 @@ typedef struct ike_sa_id_t ike_sa_id_t; #include - /** - * @brief An object of type ike_sa_id_t is used to identify an IKE_SA. + * An object of type ike_sa_id_t is used to identify an IKE_SA. * * An IKE_SA is identified by its initiator and responder spi's. * Additionaly it contains the role of the actual running IKEv2-Daemon * for the specific IKE_SA (original initiator or responder). - * - * @b Constructors: - * - ike_sa_id_create() - * - * @ingroup sa */ struct ike_sa_id_t { /** - * @brief Set the SPI of the responder. + * Set the SPI of the responder. * * This function is called when a request or reply of a IKE_SA_INIT is received. * - * @param this calling object * @param responder_spi SPI of responder to set */ void (*set_responder_spi) (ike_sa_id_t *this, u_int64_t responder_spi); /** - * @brief Set the SPI of the initiator. + * Set the SPI of the initiator. * - * @param this calling object * @param initiator_spi SPI to set */ void (*set_initiator_spi) (ike_sa_id_t *this, u_int64_t initiator_spi); /** - * @brief Get the initiator SPI. + * Get the initiator SPI. * - * @param this calling object * @return SPI of the initiator */ u_int64_t (*get_initiator_spi) (ike_sa_id_t *this); /** - * @brief Get the responder SPI. + * Get the responder SPI. * - * @param this calling object * @return SPI of the responder */ u_int64_t (*get_responder_spi) (ike_sa_id_t *this); /** - * @brief Check if two ike_sa_id_t objects are equal. + * Check if two ike_sa_id_t objects are equal. * * Two ike_sa_id_t objects are equal if both SPI values and the role matches. * - * @param this calling object * @param other ike_sa_id_t object to check if equal * @return TRUE if given ike_sa_id_t are equal, FALSE otherwise */ bool (*equals) (ike_sa_id_t *this, ike_sa_id_t *other); /** - * @brief Replace all values of a given ike_sa_id_t object with values. + * Replace all values of a given ike_sa_id_t object with values. * from another ike_sa_id_t object. * * After calling this function, both objects are equal. * - * @param this calling object * @param other ike_sa_id_t object from which values will be taken */ void (*replace_values) (ike_sa_id_t *this, ike_sa_id_t *other); /** - * @brief Get the initiator flag. + * Get the initiator flag. * - * @param this calling object * @return TRUE if we are the original initator */ bool (*is_initiator) (ike_sa_id_t *this); /** - * @brief Switche the original initiator flag. + * Switche the original initiator flag. * - * @param this calling object * @return TRUE if we are the original initator after switch, FALSE otherwise */ bool (*switch_initiator) (ike_sa_id_t *this); /** - * @brief Clones a given ike_sa_id_t object. + * Clones a given ike_sa_id_t object. * - * @param this calling object * @return cloned ike_sa_id_t object */ ike_sa_id_t *(*clone) (ike_sa_id_t *this); /** - * @brief Destroys an ike_sa_id_t object. - * - * @param this calling object + * Destroys an ike_sa_id_t object. */ void (*destroy) (ike_sa_id_t *this); }; /** - * @brief Creates an ike_sa_id_t object with specific SPI's and defined role. + * Creates an ike_sa_id_t object with specific SPI's and defined role. * * @param initiator_spi initiators SPI * @param responder_spi responders SPI * @param is_initiaor TRUE if we are the original initiator * @return ike_sa_id_t object - * - * @ingroup sa */ -ike_sa_id_t * ike_sa_id_create(u_int64_t initiator_spi, u_int64_t responder_spi, bool is_initiaor); +ike_sa_id_t * ike_sa_id_create(u_int64_t initiator_spi, u_int64_t responder_spi, + bool is_initiaor); -#endif /*IKE_SA_ID_H_*/ +#endif /*IKE_SA_ID_H_ @} */ diff --git a/src/charon/sa/ike_sa_manager.c b/src/charon/sa/ike_sa_manager.c index 5e7f78af0..f004f0701 100644 --- a/src/charon/sa/ike_sa_manager.c +++ b/src/charon/sa/ike_sa_manager.c @@ -1,10 +1,3 @@ -/** - * @file ike_sa_manager.c - * - * @brief Implementation of ike_sa_mananger_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,8 @@ * 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. + * + * $Id$ */ #include @@ -30,6 +25,7 @@ #include #include #include +#include typedef struct entry_t entry_t; @@ -508,7 +504,6 @@ static ike_sa_t* checkout_by_config(private_ike_sa_manager_t *this, { identification_t *found_my_id, *found_other_id; host_t *found_my_host, *found_other_host; - int wc; if (!wait_for_entry(this, entry)) { @@ -541,8 +536,8 @@ static ike_sa_t* checkout_by_config(private_ike_sa_manager_t *this, my_host->ip_equals(my_host, found_my_host)) && (other_host->is_anyaddr(other_host) || other_host->ip_equals(other_host, found_other_host)) && - found_my_id->matches(found_my_id, my_id, &wc) && - found_other_id->matches(found_other_id, other_id, &wc) && + found_my_id->matches(found_my_id, my_id) && + found_other_id->matches(found_other_id, other_id) && streq(peer_cfg->get_name(peer_cfg), entry->ike_sa->get_name(entry->ike_sa))) { @@ -920,10 +915,15 @@ ike_sa_manager_t *ike_sa_manager_create() this->public.get_half_open_count = (int(*)(ike_sa_manager_t*,host_t*))get_half_open_count; /* initialize private variables */ + this->hasher = lib->crypto->create_hasher(lib->crypto, HASH_PREFERRED); + if (this->hasher == NULL) + { + DBG1(DBG_MGR, "manager initialization failed, no hasher supported"); + free(this); + return NULL; + } this->ike_sa_list = linked_list_create(); pthread_mutex_init(&this->mutex, NULL); this->randomizer = randomizer_create(); - this->hasher = hasher_create(HASH_SHA1); - return &this->public; } diff --git a/src/charon/sa/ike_sa_manager.h b/src/charon/sa/ike_sa_manager.h index a73a106ba..cb25940c5 100644 --- a/src/charon/sa/ike_sa_manager.h +++ b/src/charon/sa/ike_sa_manager.h @@ -1,10 +1,3 @@ -/** - * @file ike_sa_manager.h - * - * @brief Interface of ike_sa_manager_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup ike_sa_manager ike_sa_manager + * @{ @ingroup sa */ #ifndef IKE_SA_MANAGER_H_ @@ -32,7 +32,7 @@ typedef struct ike_sa_manager_t ike_sa_manager_t; #include /** - * @brief The IKE_SA-Manager is responsible for managing all initiated and responded IKE_SA's. + * The IKE_SA-Manager is responsible for managing all initiated and responded IKE_SA's. * * To avoid access from multiple threads, IKE_SAs must be checked out from * the manager, and checked in after usage. @@ -42,18 +42,12 @@ typedef struct ike_sa_manager_t ike_sa_manager_t; * This could be done by comparing thread-ids via pthread_self()... * * @todo Managing of ike_sa_t objects in a hash table instead of linked list. - * - * @b Constructors: - * - ike_sa_manager_create() - * - * @ingroup sa */ struct ike_sa_manager_t { /** - * @brief Checkout an existing IKE_SA. + * Checkout an existing IKE_SA. * - * @param this the manager object * @param ike_sa_id the SA identifier, will be updated * @returns * - checked out IKE_SA if found @@ -62,16 +56,15 @@ struct ike_sa_manager_t { ike_sa_t* (*checkout) (ike_sa_manager_t* this, ike_sa_id_t *sa_id); /** - * @brief Create and check out a new IKE_SA. + * Create and check out a new IKE_SA. * - * @param this the manager object * @param initiator TRUE for initiator, FALSE otherwise * @returns created andchecked out IKE_SA */ ike_sa_t* (*checkout_new) (ike_sa_manager_t* this, bool initiator); /** - * @brief Checkout an IKE_SA by a message. + * Checkout an IKE_SA by a message. * * In some situations, it is necessary that the manager knows the * message to use for the checkout. This has the folloing reasons: @@ -86,7 +79,6 @@ struct ike_sa_manager_t { * If processing the message does not make sense (for the reasons above), * NULL is returned. * - * @param this the manager object * @param ike_sa_id the SA identifier, will be updated * @returns * - checked out/created IKE_SA @@ -95,7 +87,7 @@ struct ike_sa_manager_t { ike_sa_t* (*checkout_by_message) (ike_sa_manager_t* this, message_t *message); /** - * @brief Checkout an IKE_SA for initiation by a peer_config. + * Checkout an IKE_SA for initiation by a peer_config. * * To initiate, a CHILD_SA may be established within an existing IKE_SA. * This call checks for an existing IKE_SA by comparing the configuration. @@ -104,7 +96,6 @@ struct ike_sa_manager_t { * If no IKE_SA is found, a new one is created. This is also the case when * the found IKE_SA is in the DELETING state. * - * @param this the manager object * @param peer_cfg configuration used to find an existing IKE_SA * @return checked out/created IKE_SA */ @@ -112,14 +103,13 @@ struct ike_sa_manager_t { peer_cfg_t *peer_cfg); /** - * @brief Check out an IKE_SA a unique ID. + * Check out an IKE_SA a unique ID. * * Every IKE_SA and every CHILD_SA is uniquely identified by an ID. * These checkout function uses, depending * on the child parameter, the unique ID of the IKE_SA or the reqid * of one of a IKE_SAs CHILD_SA. * - * @param this the manager object * @param id unique ID of the object * @param child TRUE to use CHILD, FALSE to use IKE_SA * @return @@ -130,12 +120,11 @@ struct ike_sa_manager_t { bool child); /** - * @brief Check out an IKE_SA by the policy/connection name. + * Check out an IKE_SA by the policy/connection name. * * Check out the IKE_SA by the connections name or by a CHILD_SAs policy * name. * - * @param this the manager object * @param name name of the connection/policy * @param child TRUE to use policy name, FALSE to use conn name * @return @@ -146,24 +135,22 @@ struct ike_sa_manager_t { bool child); /** - * @brief Create an iterator over all stored IKE_SAs. + * Create an iterator over all stored IKE_SAs. * * The avoid synchronization issues, the iterator locks access * to the manager exclusively, until it gets destroyed. * This iterator is for reading only! Writing will corrupt the manager. * - * @param this the manager object * @return iterator over all IKE_SAs. */ iterator_t *(*create_iterator) (ike_sa_manager_t* this); /** - * @brief Checkin the SA after usage. + * Checkin the SA after usage. * * @warning the SA pointer MUST NOT be used after checkin! * The SA must be checked out again! * - * @param this the manager object * @param ike_sa_id the SA identifier, will be updated * @param ike_sa checked out SA * @returns @@ -173,7 +160,7 @@ struct ike_sa_manager_t { status_t (*checkin) (ike_sa_manager_t* this, ike_sa_t *ike_sa); /** - * @brief Destroy a checked out SA. + * Destroy a checked out SA. * * The IKE SA is destroyed without notification of the remote peer. * Use this only if the other peer doesn't respond or behaves not @@ -182,7 +169,6 @@ struct ike_sa_manager_t { * so this can be called if the SA is in a "unclean" state, without the * risk that another thread can get the SA. * - * @param this the manager object * @param ike_sa SA to delete * @returns * - SUCCESS if found @@ -191,7 +177,7 @@ struct ike_sa_manager_t { status_t (*checkin_and_destroy) (ike_sa_manager_t* this, ike_sa_t *ike_sa); /** - * @brief Get the number of IKE_SAs which are in the connecting state. + * Get the number of IKE_SAs which are in the connecting state. * * To prevent the server from resource exhaustion, cookies and other * mechanisms are used. The number of half open IKE_SAs is a good @@ -200,29 +186,24 @@ struct ike_sa_manager_t { * from this IP are counted. * Only SAs for which we are the responder are counted. * - * @param this the manager object * @param ip NULL for all, IP for half open IKE_SAs with IP * @return number of half open IKE_SAs */ int (*get_half_open_count) (ike_sa_manager_t *this, host_t *ip); /** - * @brief Destroys the manager with all associated SAs. + * Destroys the manager with all associated SAs. * * Threads will be driven out, so all SAs can be deleted cleanly. - * - * @param this the manager object */ void (*destroy) (ike_sa_manager_t *this); }; /** - * @brief Create a manager. - * - * @returns ike_sa_manager_t object + * Create a manager. * - * @ingroup sa + * @returns ike_sa_manager_t object, NULL if initialization fails */ ike_sa_manager_t *ike_sa_manager_create(void); -#endif /*IKE_SA_MANAGER_H_*/ +#endif /*IKE_SA_MANAGER_H_ @} */ diff --git a/src/charon/sa/mediation_manager.c b/src/charon/sa/mediation_manager.c index f6137304d..eac62a878 100644 --- a/src/charon/sa/mediation_manager.c +++ b/src/charon/sa/mediation_manager.c @@ -1,10 +1,3 @@ -/** - * @file mediation_manager.c - * - * @brief Implementation of mediation_manager_t. - * - */ - /* * Copyright (C) 2007 Tobias Brunner * Hochschule fuer Technik Rapperswil @@ -18,6 +11,8 @@ * 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. + * + * $Id$ */ #include "mediation_manager.h" diff --git a/src/charon/sa/mediation_manager.h b/src/charon/sa/mediation_manager.h index 74acc4d41..7b6074170 100644 --- a/src/charon/sa/mediation_manager.h +++ b/src/charon/sa/mediation_manager.h @@ -1,10 +1,3 @@ -/** - * @file mediation_manager.h - * - * @brief Interface of mediation_manager_t. - * - */ - /* * Copyright (C) 2007 Tobias Brunner * Hochschule fuer Technik Rapperswil @@ -18,6 +11,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup mediation_manager mediation_manager + * @{ @ingroup sa */ #ifndef MEDIATION_MANAGER_H_ @@ -29,29 +29,22 @@ typedef struct mediation_manager_t mediation_manager_t; #include /** - * @brief The mediation manager is responsible for managing currently online + * The mediation manager is responsible for managing currently online * peers and registered requests for offline peers on the mediation server. - * - * @b Constructors: - * - mediation_manager_create() - * - * @ingroup sa */ struct mediation_manager_t { /** - * @brief Remove the IKE_SA of a peer. + * Remove the IKE_SA of a peer. * - * @param this the manager object * @param ike_sa_id the IKE_SA ID of the peer's SA */ void (*remove) (mediation_manager_t* this, ike_sa_id_t *ike_sa_id); /** - * @brief Update the ike_sa_id that is assigned to a peer's ID. If the peer + * Update the ike_sa_id that is assigned to a peer's ID. If the peer * is new, it gets a new record assigned. * - * @param this the manager object * @param peer_id the peer's ID * @param ike_sa_id the IKE_SA ID of the peer's SA */ @@ -59,9 +52,8 @@ struct mediation_manager_t { ike_sa_id_t *ike_sa_id); /** - * @brief Checks if a specific peer is online. + * Checks if a specific peer is online. * - * @param this the manager object * @param peer_id the peer's ID * @returns * - IKE_SA ID of the peer's SA. @@ -71,10 +63,9 @@ struct mediation_manager_t { identification_t *peer_id); /** - * @brief Checks if a specific peer is online and registers the requesting + * Checks if a specific peer is online and registers the requesting * peer if it is not. * - * @param this the manager object * @param peer_id the peer's ID * @param requester the requesters ID * @returns @@ -85,20 +76,16 @@ struct mediation_manager_t { identification_t *peer_id, identification_t *requester); /** - * @brief Destroys the manager with all data. - * - * @param this the manager object + * Destroys the manager with all data. */ void (*destroy) (mediation_manager_t *this); }; /** - * @brief Create a manager. + * Create a manager. * * @returns mediation_manager_t object - * - * @ingroup sa */ mediation_manager_t *mediation_manager_create(void); -#endif /*MEDIATION_MANAGER_H_*/ +#endif /*MEDIATION_MANAGER_H_ @} */ diff --git a/src/charon/sa/task_manager.c b/src/charon/sa/task_manager.c index 89f527aba..df0697055 100644 --- a/src/charon/sa/task_manager.c +++ b/src/charon/sa/task_manager.c @@ -1,10 +1,3 @@ -/** - * @file task_manager.c - * - * @brief Implementation of task_manager_t. - * - */ - /* * Copyright (C) 2007 Tobias Brunner * Copyright (C) 2007 Martin Willi @@ -19,6 +12,8 @@ * 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. + * + * $Id$ */ #include "task_manager.h" @@ -31,7 +26,8 @@ #include #include #include -#include +#include +#include #include #include #include @@ -328,7 +324,7 @@ static status_t build_request(private_task_manager_t *this) this->initiating.mid = 0; exchange = IKE_SA_INIT; activate_task(this, IKE_NATD); - activate_task(this, IKE_CERT); + activate_task(this, IKE_CERT_PRE); #ifdef P2P /* this task has to be activated before the IKE_AUTHENTICATE * task, because that task pregenerates the packet after @@ -337,6 +333,7 @@ static status_t build_request(private_task_manager_t *this) activate_task(this, IKE_P2P); #endif /* P2P */ activate_task(this, IKE_AUTHENTICATE); + activate_task(this, IKE_CERT_POST); activate_task(this, IKE_CONFIG); activate_task(this, CHILD_CREATE); activate_task(this, IKE_AUTH_LIFETIME); @@ -687,7 +684,7 @@ static status_t process_request(private_task_manager_t *this, this->passive_tasks->insert_last(this->passive_tasks, task); task = (task_t*)ike_natd_create(this->ike_sa, FALSE); this->passive_tasks->insert_last(this->passive_tasks, task); - task = (task_t*)ike_cert_create(this->ike_sa, FALSE); + task = (task_t*)ike_cert_pre_create(this->ike_sa, FALSE); this->passive_tasks->insert_last(this->passive_tasks, task); #ifdef P2P task = (task_t*)ike_p2p_create(this->ike_sa, FALSE); @@ -695,6 +692,8 @@ static status_t process_request(private_task_manager_t *this, #endif /* P2P */ task = (task_t*)ike_auth_create(this->ike_sa, FALSE); this->passive_tasks->insert_last(this->passive_tasks, task); + task = (task_t*)ike_cert_post_create(this->ike_sa, FALSE); + this->passive_tasks->insert_last(this->passive_tasks, task); task = (task_t*)ike_config_create(this->ike_sa, FALSE); this->passive_tasks->insert_last(this->passive_tasks, task); task = (task_t*)child_create_create(this->ike_sa, NULL); diff --git a/src/charon/sa/task_manager.h b/src/charon/sa/task_manager.h index 38c63c1a9..07cd8f557 100644 --- a/src/charon/sa/task_manager.h +++ b/src/charon/sa/task_manager.h @@ -1,10 +1,3 @@ -/** - * @file task_manager.h - * - * @brief Interface of task_manager_t. - * - */ - /* * Copyright (C) 2006 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup task_manager task_manager + * @{ @ingroup sa */ #ifndef TASK_MANAGER_H_ @@ -32,42 +32,32 @@ typedef struct task_manager_t task_manager_t; /** * First retransmit timeout in milliseconds. - * - * @ingroup sa */ #define RETRANSMIT_TIMEOUT 4000 /** * Base which is raised to the power of the retransmission try. - * - * @ingroup sa */ #define RETRANSMIT_BASE 1.8 /** * Number of retransmits done before giving up. - * - * @ingroup sa */ #define RETRANSMIT_TRIES 5 /** * Interval for mobike routability checks in ms. - * - * @ingroup sa */ #define ROUTEABILITY_CHECK_INTERVAL 2500 /** * Number of routability checks before giving up - * - * @ingroup sa */ #define ROUTEABILITY_CHECK_TRIES 10 /** - * @brief The task manager, juggles task and handles message exchanges. + * The task manager, juggles task and handles message exchanges. * * On incoming requests, the task manager creates new tasks on demand and * juggles the request through all available tasks. Each task inspects the @@ -97,18 +87,12 @@ typedef struct task_manager_t task_manager_t; @endberbatim * The peer is considered dead after 2min 45s when no reply comes in. - * - * @b Constructors: - * - task_manager_create() - * - * @ingroup sa */ struct task_manager_t { /** - * @brief Process an incoming message. + * Process an incoming message. * - * @param this calling object * @param message message to add payloads to * @return * - DESTROY_ME if IKE_SA must be closed @@ -117,28 +101,24 @@ struct task_manager_t { status_t (*process_message) (task_manager_t *this, message_t *message); /** - * @brief Initiate an exchange with the currently queued tasks. - * - * @param this calling object + * Initiate an exchange with the currently queued tasks. */ status_t (*initiate) (task_manager_t *this); /** - * @brief Queue a task in the manager. + * Queue a task in the manager. * - * @param this calling object * @param task task to queue */ void (*queue_task) (task_manager_t *this, task_t *task); /** - * @brief Retransmit a request if it hasn't been acknowledged yet. + * Retransmit a request if it hasn't been acknowledged yet. * * A return value of INVALID_STATE means that the message was already * acknowledged and has not to be retransmitted. A return value of SUCCESS * means retransmission was required and the message has been resent. * - * @param this calling object * @param message_id ID of the message to retransmit * @return * - INVALID_STATE if retransmission not required @@ -147,52 +127,45 @@ struct task_manager_t { status_t (*retransmit) (task_manager_t *this, u_int32_t message_id); /** - * @brief Migrate all tasks from other to this. + * Migrate all tasks from other to this. * * To rekey or reestablish an IKE_SA completely, all queued or active * tasks should get migrated to the new IKE_SA. * - * @param this manager which gets all tasks * @param other manager which gives away its tasks */ void (*adopt_tasks) (task_manager_t *this, task_manager_t *other); /** - * @brief Reset message ID counters of the task manager. + * Reset message ID counters of the task manager. * * The IKEv2 protocol requires to restart exchanges with message IDs * reset to zero (INVALID_KE_PAYLOAD, COOKIES, ...). The reset() method * resets the message IDs and resets all active tasks using the migrate() * method. * - * @param this calling object * @param other manager which gives away its tasks */ void (*reset) (task_manager_t *this); /** - * @brief Check if we are currently waiting for a reply. + * Check if we are currently waiting for a reply. * - * @param this calling object * @return TRUE if we are waiting, FALSE otherwise */ bool (*busy) (task_manager_t *this); /** - * @brief Destroy the task_manager_t. - * - * @param this calling object + * Destroy the task_manager_t. */ void (*destroy) (task_manager_t *this); }; /** - * @brief Create an instance of the task manager. + * Create an instance of the task manager. * * @param ike_sa IKE_SA to manage. - * - * @ingroup sa */ task_manager_t *task_manager_create(ike_sa_t *ike_sa); -#endif /* TASK_MANAGER_H_ */ +#endif /* TASK_MANAGER_H_ @} */ diff --git a/src/charon/sa/tasks/child_create.c b/src/charon/sa/tasks/child_create.c index 3947a84d1..d933d6267 100644 --- a/src/charon/sa/tasks/child_create.c +++ b/src/charon/sa/tasks/child_create.c @@ -1,10 +1,3 @@ -/** - * @file child_create.c - * - * @brief Implementation of the child_create task. - * - */ - /* * Copyright (C) 2005-2007 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,8 @@ * 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. + * + * $Id$ */ #include "child_create.h" @@ -450,7 +445,7 @@ static void process_payloads(private_child_create_t *this, message_t *message) if (!this->initiator) { this->dh_group = ke_payload->get_dh_group_number(ke_payload); - this->dh = diffie_hellman_create(this->dh_group); + this->dh = lib->crypto->create_dh(lib->crypto, this->dh_group); } if (this->dh) { @@ -580,7 +575,7 @@ static status_t build_i(private_child_create_t *this, message_t *message) if (this->dh_group != MODP_NONE) { - this->dh = diffie_hellman_create(this->dh_group); + this->dh = lib->crypto->create_dh(lib->crypto, this->dh_group); } build_payloads(this, message); diff --git a/src/charon/sa/tasks/child_create.h b/src/charon/sa/tasks/child_create.h index 9f4815215..1a14cd5f9 100644 --- a/src/charon/sa/tasks/child_create.h +++ b/src/charon/sa/tasks/child_create.h @@ -1,10 +1,3 @@ -/** - * @file child_create.h - * - * @brief Interface child_create_t. - * - */ - /* * Copyright (C) 2007 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup child_create child_create + * @{ @ingroup tasks */ #ifndef CHILD_CREATE_H_ @@ -31,15 +31,10 @@ typedef struct child_create_t child_create_t; #include /** - * @brief Task of type CHILD_CREATE, established a new CHILD_SA. + * Task of type CHILD_CREATE, established a new CHILD_SA. * * This task may be included in the IKE_AUTH message or in a separate * CREATE_CHILD_SA exchange. - * - * @b Constructors: - * - child_create_create() - * - * @ingroup tasks */ struct child_create_t { @@ -49,35 +44,32 @@ struct child_create_t { task_t task; /** - * @brief Use a specific reqid for the CHILD_SA. + * Use a specific reqid for the CHILD_SA. * * When this task is used for rekeying, the same reqid is used * for the new CHILD_SA. * - * @param this calling object * @param reqid reqid to use */ void (*use_reqid) (child_create_t *this, u_int32_t reqid); /** - * @brief Get the lower of the two nonces, used for rekey collisions. + * Get the lower of the two nonces, used for rekey collisions. * - * @param this calling object * @return lower nonce */ chunk_t (*get_lower_nonce) (child_create_t *this); /** - * @brief Get the CHILD_SA established/establishing by this task. + * Get the CHILD_SA established/establishing by this task. * - * @param this calling object * @return child_sa */ child_sa_t* (*get_child) (child_create_t *this); }; /** - * @brief Create a new child_create task. + * Create a new child_create task. * * @param ike_sa IKE_SA this task works for * @param config child_cfg if task initiator, NULL if responder @@ -85,4 +77,4 @@ struct child_create_t { */ child_create_t *child_create_create(ike_sa_t *ike_sa, child_cfg_t *config); -#endif /* CHILD_CREATE_H_ */ +#endif /* CHILD_CREATE_H_ @} */ diff --git a/src/charon/sa/tasks/child_delete.c b/src/charon/sa/tasks/child_delete.c index d0b34a276..2c1db2ad0 100644 --- a/src/charon/sa/tasks/child_delete.c +++ b/src/charon/sa/tasks/child_delete.c @@ -1,10 +1,3 @@ -/** - * @file child_delete.c - * - * @brief Implementation of the child_delete task. - * - */ - /* * Copyright (C) 2006-2007 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,8 @@ * 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. + * + * $Id$ */ #include "child_delete.h" diff --git a/src/charon/sa/tasks/child_delete.h b/src/charon/sa/tasks/child_delete.h index a7e676a50..1aa60993e 100644 --- a/src/charon/sa/tasks/child_delete.h +++ b/src/charon/sa/tasks/child_delete.h @@ -1,10 +1,3 @@ -/** - * @file child_delete.h - * - * @brief Interface child_delete_t. - * - */ - /* * Copyright (C) 2007 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup child_delete child_delete + * @{ @ingroup tasks */ #ifndef CHILD_DELETE_H_ @@ -31,12 +31,7 @@ typedef struct child_delete_t child_delete_t; #include /** - * @brief Task of type child_delete, delete a CHILD_SA. - * - * @b Constructors: - * - child_delete_create() - * - * @ingroup tasks + * Task of type child_delete, delete a CHILD_SA. */ struct child_delete_t { @@ -46,16 +41,15 @@ struct child_delete_t { task_t task; /** - * @brief Get the CHILD_SA to delete by this task. + * Get the CHILD_SA to delete by this task. * - * @param this calling object * @return child_sa */ child_sa_t* (*get_child) (child_delete_t *this); }; /** - * @brief Create a new child_delete task. + * Create a new child_delete task. * * @param ike_sa IKE_SA this task works for * @param child_sa CHILD_SA to delete, or NULL as responder @@ -63,4 +57,4 @@ struct child_delete_t { */ child_delete_t *child_delete_create(ike_sa_t *ike_sa, child_sa_t *child_sa); -#endif /* CHILD_DELETE_H_ */ +#endif /* CHILD_DELETE_H_ @} */ diff --git a/src/charon/sa/tasks/child_rekey.c b/src/charon/sa/tasks/child_rekey.c index 3667d8fad..6d741b760 100644 --- a/src/charon/sa/tasks/child_rekey.c +++ b/src/charon/sa/tasks/child_rekey.c @@ -1,10 +1,3 @@ -/** - * @file child_rekey.c - * - * @brief Implementation of the child_rekey task. - * - */ - /* * Copyright (C) 2005-2007 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,8 @@ * 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. + * + * $Id$ */ #include "child_rekey.h" diff --git a/src/charon/sa/tasks/child_rekey.h b/src/charon/sa/tasks/child_rekey.h index 3515f0c3f..382cf4a31 100644 --- a/src/charon/sa/tasks/child_rekey.h +++ b/src/charon/sa/tasks/child_rekey.h @@ -1,10 +1,3 @@ -/** - * @file child_rekey.h - * - * @brief Interface child_rekey_t. - * - */ - /* * Copyright (C) 2007 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup child_rekey child_rekey + * @{ @ingroup tasks */ #ifndef CHILD_REKEY_H_ @@ -31,12 +31,7 @@ typedef struct child_rekey_t child_rekey_t; #include /** - * @brief Task of type CHILD_REKEY, rekey an established CHILD_SA. - * - * @b Constructors: - * - child_rekey_create() - * - * @ingroup tasks + * Task of type CHILD_REKEY, rekey an established CHILD_SA. */ struct child_rekey_t { @@ -46,20 +41,19 @@ struct child_rekey_t { task_t task; /** - * @brief Register a rekeying task which collides with this one + * Register a rekeying task which collides with this one * * If two peers initiate rekeying at the same time, the collision must * be handled gracefully. The task manager is aware of what exchanges * are going on and notifies the outgoing task by passing the incoming. * - * @param this task initated by us * @param other incoming task */ void (*collide)(child_rekey_t* this, task_t *other); }; /** - * @brief Create a new CHILD_REKEY task. + * Create a new CHILD_REKEY task. * * @param ike_sa IKE_SA this task works for * @param child_sa child_sa to rekey, NULL if responder @@ -67,4 +61,4 @@ struct child_rekey_t { */ child_rekey_t *child_rekey_create(ike_sa_t *ike_sa, child_sa_t *child_sa); -#endif /* CHILD_REKEY_H_ */ +#endif /* CHILD_REKEY_H_ @} */ diff --git a/src/charon/sa/tasks/ike_auth.c b/src/charon/sa/tasks/ike_auth.c index de88a0abe..11382047a 100644 --- a/src/charon/sa/tasks/ike_auth.c +++ b/src/charon/sa/tasks/ike_auth.c @@ -1,10 +1,3 @@ -/** - * @file ike_auth.c - * - * @brief Implementation of the ike_auth task. - * - */ - /* * Copyright (C) 2005-2007 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -18,7 +11,9 @@ * 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. + * for more details + * + * $Id$ */ #include "ike_auth.h" @@ -231,7 +226,7 @@ static status_t process_id(private_ike_auth_t *this, message_t *message) { id = idr->get_identification(idr); req = this->ike_sa->get_other_id(this->ike_sa); - if (!id->matches(id, req, NULL)) + if (!id->matches(id, req)) { SIG(IKE_UP_FAILED, "peer ID %D unacceptable, %D required", id, req); id->destroy(id); @@ -525,13 +520,13 @@ static status_t process_r(private_ike_auth_t *this, message_t *message) this->eap_auth = eap_authenticator_create(this->ike_sa); break; default: - break; + return NEED_MORE; } config = charon->backends->get_peer_cfg(charon->backends, this->ike_sa->get_my_id(this->ike_sa), this->ike_sa->get_other_id(this->ike_sa), - this->ike_sa->get_other_ca(this->ike_sa)); + this->ike_sa->get_other_auth(this->ike_sa)); if (config) { this->ike_sa->set_peer_cfg(this->ike_sa, config); @@ -557,6 +552,13 @@ static status_t build_r(private_ike_auth_t *this, message_t *message) return collect_my_init_data(this, message); } + if (!this->peer_authenticated && this->eap_auth == NULL) + { + /* peer not authenticated, nor does it want to use EAP */ + message->add_notify(message, TRUE, AUTHENTICATION_FAILED, chunk_empty); + return FAILED; + } + config = this->ike_sa->get_peer_cfg(this->ike_sa); if (config == NULL) { @@ -587,13 +589,6 @@ static status_t build_r(private_ike_auth_t *this, message_t *message) return SUCCESS; } - if (this->eap_auth == NULL) - { - /* peer not authenticated, nor does it want to use EAP */ - message->add_notify(message, TRUE, AUTHENTICATION_FAILED, chunk_empty); - return FAILED; - } - /* initiate EAP authenitcation */ eap_type = config->get_eap_type(config, &eap_vendor); status = this->eap_auth->initiate(this->eap_auth, eap_type, @@ -618,6 +613,8 @@ static status_t process_i(private_ike_auth_t *this, message_t *message) { iterator_t *iterator; payload_t *payload; + peer_cfg_t *config; + auth_info_t *auth; if (message->get_exchange_type(message) == IKE_SA_INIT) { @@ -687,10 +684,18 @@ static status_t process_i(private_ike_auth_t *this, message_t *message) return process_eap_i(this, message); } + config = this->ike_sa->get_peer_cfg(this->ike_sa); + auth = this->ike_sa->get_other_auth(this->ike_sa); + if (!auth->complies(auth, config->get_auth(config))) + { + SIG(IKE_UP_FAILED, "authorization of %D for config %s failed", + this->ike_sa->get_other_id(this->ike_sa), config->get_name(config)); + return FAILED; + } this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); SIG(IKE_UP_SUCCESS, "IKE_SA '%s' established between %D[%H]...[%H]%D", this->ike_sa->get_name(this->ike_sa), - this->ike_sa->get_my_id(this->ike_sa), + this->ike_sa->get_my_id(this->ike_sa), this->ike_sa->get_my_host(this->ike_sa), this->ike_sa->get_other_host(this->ike_sa), this->ike_sa->get_other_id(this->ike_sa)); diff --git a/src/charon/sa/tasks/ike_auth.h b/src/charon/sa/tasks/ike_auth.h index d7326c988..f44aa7ce6 100644 --- a/src/charon/sa/tasks/ike_auth.h +++ b/src/charon/sa/tasks/ike_auth.h @@ -1,10 +1,3 @@ -/** - * @file ike_auth.h - * - * @brief Interface ike_auth_t. - * - */ - /* * Copyright (C) 2007 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup ike_auth ike_auth + * @{ @ingroup tasks */ #ifndef IKE_AUTH_H_ @@ -30,7 +30,7 @@ typedef struct ike_auth_t ike_auth_t; #include /** - * @brief Task of type ike_auth, authenticates an IKE_SA using authenticators. + * Task of type ike_auth, authenticates an IKE_SA using authenticators. * * The ike_auth task authenticates the IKE_SA using the IKE_AUTH * exchange. It processes and build IDi and IDr payloads and also @@ -38,11 +38,6 @@ typedef struct ike_auth_t ike_auth_t; * which do the actual authentication process. If the ike_auth task is used * with EAP authentication, it stays alive over multiple exchanges until * EAP has completed. - * - * @b Constructors: - * - ike_auth_create() - * - * @ingroup tasks */ struct ike_auth_t { @@ -53,7 +48,7 @@ struct ike_auth_t { }; /** - * @brief Create a new task of type IKE_AUTHENTICATE. + * Create a new task of type IKE_AUTHENTICATE. * * @param ike_sa IKE_SA this task works for * @param initiator TRUE if thask is the initator of an exchange @@ -61,4 +56,4 @@ struct ike_auth_t { */ ike_auth_t *ike_auth_create(ike_sa_t *ike_sa, bool initiator); -#endif /* IKE_AUTH_H_ */ +#endif /* IKE_AUTH_H_ @} */ diff --git a/src/charon/sa/tasks/ike_auth_lifetime.c b/src/charon/sa/tasks/ike_auth_lifetime.c index 9d37ec608..969e21c2b 100644 --- a/src/charon/sa/tasks/ike_auth_lifetime.c +++ b/src/charon/sa/tasks/ike_auth_lifetime.c @@ -1,10 +1,3 @@ -/** - * @file ike_auth_lifetime.c - * - * @brief Implementation of the ike_auth_lifetime task. - * - */ - /* * Copyright (C) 2007 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,8 @@ * 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. + * + * $Id$ */ #include "ike_auth_lifetime.h" diff --git a/src/charon/sa/tasks/ike_auth_lifetime.h b/src/charon/sa/tasks/ike_auth_lifetime.h index 500b89d39..df69ce29c 100644 --- a/src/charon/sa/tasks/ike_auth_lifetime.h +++ b/src/charon/sa/tasks/ike_auth_lifetime.h @@ -1,10 +1,3 @@ -/** - * @file ike_auth_lifetime.h - * - * @brief Interface ike_auth_lifetime_t. - * - */ - /* * Copyright (C) 2007 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup ike_auth_lifetime ike_auth_lifetime + * @{ @ingroup tasks */ #ifndef IKE_AUTH_LIFETIME_H_ @@ -30,15 +30,10 @@ typedef struct ike_auth_lifetime_t ike_auth_lifetime_t; #include /** - * @brief Task of type IKE_AUTH_LIFETIME, implements RFC4478. + * Task of type IKE_AUTH_LIFETIME, implements RFC4478. * * This task exchanges lifetimes for IKE_AUTH to force a client to * reauthenticate before the responders lifetime reaches the limit. - * - * @b Constructors: - * - ike_auth_lifetime_create() - * - * @ingroup tasks */ struct ike_auth_lifetime_t { @@ -49,7 +44,7 @@ struct ike_auth_lifetime_t { }; /** - * @brief Create a new IKE_AUTH_LIFETIME task. + * Create a new IKE_AUTH_LIFETIME task. * * @param ike_sa IKE_SA this task works for * @param initiator TRUE if taks is initiated by us @@ -57,5 +52,4 @@ struct ike_auth_lifetime_t { */ ike_auth_lifetime_t *ike_auth_lifetime_create(ike_sa_t *ike_sa, bool initiator); -#endif /* IKE_MOBIKE_H_ */ - +#endif /* IKE_MOBIKE_H_ @} */ diff --git a/src/charon/sa/tasks/ike_cert.c b/src/charon/sa/tasks/ike_cert.c deleted file mode 100644 index 880ed9c42..000000000 --- a/src/charon/sa/tasks/ike_cert.c +++ /dev/null @@ -1,366 +0,0 @@ -/** - * @file ike_cert.c - * - * @brief Implementation of the ike_cert task. - * - */ - -/* - * Copyright (C) 2006-2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "ike_cert.h" - -#include -#include -#include -#include -#include - - -typedef struct private_ike_cert_t private_ike_cert_t; - -/** - * Private members of a ike_cert_t task. - */ -struct private_ike_cert_t { - - /** - * Public methods and task_t interface. - */ - ike_cert_t public; - - /** - * Assigned IKE_SA. - */ - ike_sa_t *ike_sa; - - /** - * Are we the initiator? - */ - bool initiator; - - /** - * list of CA cert hashes requested, items point to 20 byte chunk - */ - linked_list_t *cas; - - /** - * have we seen a certificate request? - */ - bool certreq_seen; -}; - -/** - * read certificate requests - */ -static void process_certreqs(private_ike_cert_t *this, message_t *message) -{ - iterator_t *iterator; - payload_t *payload; - - iterator = message->get_payload_iterator(message); - while (iterator->iterate(iterator, (void**)&payload)) - { - if (payload->get_type(payload) == CERTIFICATE_REQUEST) - { - certreq_payload_t *certreq = (certreq_payload_t*)payload; - cert_encoding_t encoding; - chunk_t keyids, keyid; - - this->certreq_seen = TRUE; - - encoding = certreq->get_cert_encoding(certreq); - if (encoding != CERT_X509_SIGNATURE) - { - DBG1(DBG_IKE, "certreq payload %N not supported - ignored", - cert_encoding_names, encoding); - continue; - } - - keyids = certreq->get_data(certreq); - - while (keyids.len >= HASH_SIZE_SHA1) - { - keyid = chunk_create(keyids.ptr, HASH_SIZE_SHA1); - keyid = chunk_clone(keyid); - this->cas->insert_last(this->cas, keyid.ptr); - keyids = chunk_skip(keyids, HASH_SIZE_SHA1); - } - } - } - iterator->destroy(iterator); -} - -/** - * import certificates - */ -static void process_certs(private_ike_cert_t *this, message_t *message) -{ - iterator_t *iterator; - payload_t *payload; - - iterator = message->get_payload_iterator(message); - while (iterator->iterate(iterator, (void**)&payload)) - { - if (payload->get_type(payload) == CERTIFICATE) - { - cert_encoding_t encoding; - x509_t *cert; - chunk_t cert_data; - bool found; - cert_payload_t *cert_payload = (cert_payload_t*)payload; - - encoding = cert_payload->get_cert_encoding(cert_payload); - if (encoding != CERT_X509_SIGNATURE) - { - DBG1(DBG_IKE, "certificate payload %N not supported - ignored", - cert_encoding_names, encoding); - continue; - } - - cert_data = cert_payload->get_data_clone(cert_payload); - cert = x509_create_from_chunk(cert_data, 0); - if (cert) - { - if (charon->credentials->verify(charon->credentials, cert, &found)) - { - DBG2(DBG_IKE, "received end entity certificate is trusted - " - "added to store"); - if (found) - { - cert->destroy(cert); - } - else - { - charon->credentials->add_end_certificate(charon->credentials, cert); - } - } - else - { - DBG1(DBG_IKE, "received end entity certificate is not trusted - " - "discarded"); - cert->destroy(cert); - } - } - else - { - DBG1(DBG_IKE, "parsing of received certificate failed - discarded"); - chunk_free(&cert_data); - } - } - } - iterator->destroy(iterator); -} - -/** - * build certificate requests - */ -static void build_certreqs(private_ike_cert_t *this, message_t *message) -{ - ike_cfg_t *ike_cfg; - peer_cfg_t *peer_cfg; - identification_t *ca; - certreq_payload_t *certreq; - - ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa); - - if (ike_cfg->send_certreq(ike_cfg) != CERT_NEVER_SEND) - { - peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); - - if (peer_cfg) - { - ca = peer_cfg->get_other_ca(peer_cfg); - - if (ca && ca->get_type(ca) != ID_ANY) - { - certreq = certreq_payload_create_from_cacert(ca); - } - else - { - certreq = certreq_payload_create_from_cacerts(); - } - } - else - { - certreq = certreq_payload_create_from_cacerts(); - } - - if (certreq) - { - message->add_payload(message, (payload_t*)certreq); - } - } -} - -/** - * add certificates to message - */ -static void build_certs(private_ike_cert_t *this, message_t *message) -{ - peer_cfg_t *peer_cfg; - x509_t *cert; - cert_payload_t *payload; - - peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); - - if (peer_cfg && peer_cfg->get_auth_method(peer_cfg) == AUTH_RSA) - { - switch (peer_cfg->get_cert_policy(peer_cfg)) - { - case CERT_NEVER_SEND: - break; - case CERT_SEND_IF_ASKED: - if (!this->certreq_seen) - { - break; - } - /* FALL */ - case CERT_ALWAYS_SEND: - { - /* TODO: respect CA cert request */ - cert = charon->credentials->get_certificate(charon->credentials, - peer_cfg->get_my_id(peer_cfg)); - if (cert) - { - payload = cert_payload_create_from_x509(cert); - message->add_payload(message, (payload_t*)payload); - } - } - } - } -} - -/** - * Implementation of task_t.process for initiator - */ -static status_t build_i(private_ike_cert_t *this, message_t *message) -{ - if (message->get_exchange_type(message) == IKE_SA_INIT) - { - return NEED_MORE; - } - - build_certreqs(this, message); - build_certs(this, message); - - return NEED_MORE; -} - -/** - * Implementation of task_t.process for responder - */ -static status_t process_r(private_ike_cert_t *this, message_t *message) -{ - if (message->get_exchange_type(message) == IKE_SA_INIT) - { - return NEED_MORE; - } - - process_certreqs(this, message); - process_certs(this, message); - - return NEED_MORE; -} - -/** - * Implementation of task_t.build for responder - */ -static status_t build_r(private_ike_cert_t *this, message_t *message) -{ - if (message->get_exchange_type(message) == IKE_SA_INIT) - { - build_certreqs(this, message); - return NEED_MORE; - } - - build_certs(this, message); - - return SUCCESS; -} - -/** - * Implementation of task_t.process for initiator - */ -static status_t process_i(private_ike_cert_t *this, message_t *message) -{ - if (message->get_exchange_type(message) == IKE_SA_INIT) - { - process_certreqs(this, message); - return NEED_MORE; - } - - process_certs(this, message); - return SUCCESS; -} - -/** - * Implementation of task_t.get_type - */ -static task_type_t get_type(private_ike_cert_t *this) -{ - return IKE_CERT; -} - -/** - * Implementation of task_t.migrate - */ -static void migrate(private_ike_cert_t *this, ike_sa_t *ike_sa) -{ - this->ike_sa = ike_sa; - - this->cas->destroy_function(this->cas, free); - this->cas = linked_list_create(); - this->certreq_seen = FALSE; -} - -/** - * Implementation of task_t.destroy - */ -static void destroy(private_ike_cert_t *this) -{ - this->cas->destroy_function(this->cas, free); - free(this); -} - -/* - * Described in header. - */ -ike_cert_t *ike_cert_create(ike_sa_t *ike_sa, bool initiator) -{ - private_ike_cert_t *this = malloc_thing(private_ike_cert_t); - - this->public.task.get_type = (task_type_t(*)(task_t*))get_type; - this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate; - this->public.task.destroy = (void(*)(task_t*))destroy; - - if (initiator) - { - this->public.task.build = (status_t(*)(task_t*,message_t*))build_i; - this->public.task.process = (status_t(*)(task_t*,message_t*))process_i; - } - else - { - this->public.task.build = (status_t(*)(task_t*,message_t*))build_r; - this->public.task.process = (status_t(*)(task_t*,message_t*))process_r; - } - - this->ike_sa = ike_sa; - this->initiator = initiator; - this->cas = linked_list_create(); - this->certreq_seen = FALSE; - - return &this->public; -} diff --git a/src/charon/sa/tasks/ike_cert.h b/src/charon/sa/tasks/ike_cert.h deleted file mode 100644 index ba0283953..000000000 --- a/src/charon/sa/tasks/ike_cert.h +++ /dev/null @@ -1,61 +0,0 @@ -/** - * @file ike_cert.h - * - * @brief Interface ike_cert_t. - * - */ - -/* - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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 IKE_CERT_H_ -#define IKE_CERT_H_ - -typedef struct ike_cert_t ike_cert_t; - -#include -#include -#include - -/** - * @brief Task of type ike_cert, exchanges certificates and - * certificate requests. - * - * @b Constructors: - * - ike_cert_create() - * - * @ingroup tasks - */ -struct ike_cert_t { - - /** - * Implements the task_t interface - */ - task_t task; -}; - -/** - * @brief Create a new ike_cert task. - * - * The initiator parameter means the original initiator, not the initiator - * of the certificate request. - * - * @param ike_sa IKE_SA this task works for - * @param initiator TRUE if thask is the original initator - * @return ike_cert task to handle by the task_manager - */ -ike_cert_t *ike_cert_create(ike_sa_t *ike_sa, bool initiator); - -#endif /* IKE_CERT_H_ */ diff --git a/src/charon/sa/tasks/ike_cert_post.c b/src/charon/sa/tasks/ike_cert_post.c new file mode 100644 index 000000000..a3cad0b40 --- /dev/null +++ b/src/charon/sa/tasks/ike_cert_post.c @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2006-2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "ike_cert_post.h" + +#include +#include +#include +#include +#include + + +typedef struct private_ike_cert_post_t private_ike_cert_post_t; + +/** + * Private members of a ike_cert_post_t task. + */ +struct private_ike_cert_post_t { + + /** + * Public methods and task_t interface. + */ + ike_cert_post_t public; + + /** + * Assigned IKE_SA. + */ + ike_sa_t *ike_sa; + + /** + * Are we the initiator? + */ + bool initiator; +}; + +/** + * add certificates to message + */ +static void build_certs(private_ike_cert_post_t *this, message_t *message) +{ + peer_cfg_t *peer_cfg; + + peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + if (peer_cfg && peer_cfg->get_auth_method(peer_cfg) == AUTH_RSA) + { + switch (peer_cfg->get_cert_policy(peer_cfg)) + { + case CERT_NEVER_SEND: + break; + case CERT_SEND_IF_ASKED: + if (!this->ike_sa->has_condition(this->ike_sa, COND_CERTREQ_SEEN)) + { + break; + } + /* FALL */ + case CERT_ALWAYS_SEND: + { + cert_payload_t *payload; + enumerator_t *enumerator; + certificate_t *cert; + auth_info_t *auth; + auth_item_t item; + + auth = this->ike_sa->get_my_auth(this->ike_sa); + /* get subject cert first, then issuing certificates */ + if (!auth->get_item(auth, AUTHZ_SUBJECT_CERT, (void**)&cert)) + { + break; + } + payload = cert_payload_create_from_cert(cert); + if (!payload) + { + break; + } + DBG1(DBG_IKE, "sending end entity cert %D", + cert->get_subject(cert)); + message->add_payload(message, (payload_t*)payload); + + enumerator = auth->create_item_enumerator(auth); + while (enumerator->enumerate(enumerator, &item, &cert)) + { + if (item == AUTHZ_IM_CERT) + { + payload = cert_payload_create_from_cert(cert); + if (payload) + { + DBG1(DBG_IKE, "sending issuer cert %D", + cert->get_subject(cert)); + message->add_payload(message, (payload_t*)payload); + } + } + } + enumerator->destroy(enumerator); + } + } + } +} + +/** + * Implementation of task_t.process for initiator + */ +static status_t build_i(private_ike_cert_post_t *this, message_t *message) +{ + if (message->get_exchange_type(message) == IKE_SA_INIT) + { + return NEED_MORE; + } + build_certs(this, message); + return SUCCESS; +} + +/** + * Implementation of task_t.process for responder + */ +static status_t process_r(private_ike_cert_post_t *this, message_t *message) +{ + return NEED_MORE; +} + +/** + * Implementation of task_t.build for responder + */ +static status_t build_r(private_ike_cert_post_t *this, message_t *message) +{ + if (message->get_exchange_type(message) == IKE_SA_INIT) + { + return NEED_MORE; + } + build_certs(this, message); + return SUCCESS; +} + +/** + * Implementation of task_t.process for initiator + */ +static status_t process_i(private_ike_cert_post_t *this, message_t *message) +{ + if (message->get_exchange_type(message) == IKE_SA_INIT) + { + return NEED_MORE; + } + return SUCCESS; +} + +/** + * Implementation of task_t.get_type + */ +static task_type_t get_type(private_ike_cert_post_t *this) +{ + return IKE_CERT_POST; +} + +/** + * Implementation of task_t.migrate + */ +static void migrate(private_ike_cert_post_t *this, ike_sa_t *ike_sa) +{ + this->ike_sa = ike_sa; +} + +/** + * Implementation of task_t.destroy + */ +static void destroy(private_ike_cert_post_t *this) +{ + free(this); +} + +/* + * Described in header. + */ +ike_cert_post_t *ike_cert_post_create(ike_sa_t *ike_sa, bool initiator) +{ + private_ike_cert_post_t *this = malloc_thing(private_ike_cert_post_t); + + this->public.task.get_type = (task_type_t(*)(task_t*))get_type; + this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate; + this->public.task.destroy = (void(*)(task_t*))destroy; + + if (initiator) + { + this->public.task.build = (status_t(*)(task_t*,message_t*))build_i; + this->public.task.process = (status_t(*)(task_t*,message_t*))process_i; + } + else + { + this->public.task.build = (status_t(*)(task_t*,message_t*))build_r; + this->public.task.process = (status_t(*)(task_t*,message_t*))process_r; + } + + this->ike_sa = ike_sa; + this->initiator = initiator; + + return &this->public; +} + diff --git a/src/charon/sa/tasks/ike_cert_post.h b/src/charon/sa/tasks/ike_cert_post.h new file mode 100644 index 000000000..3291d9ab3 --- /dev/null +++ b/src/charon/sa/tasks/ike_cert_post.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2007-2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +/** + * @defgroup ike_cert_post ike_cert_post + * @{ @ingroup tasks + */ + +#ifndef IKE_CERT_POST_H_ +#define IKE_CERT_POST_H_ + +typedef struct ike_cert_post_t ike_cert_post_t; + +#include +#include +#include + +/** + * Task of type ike_cert_post, certificate processing after authentication. + */ +struct ike_cert_post_t { + + /** + * Implements the task_t interface + */ + task_t task; +}; + +/** + * Create a new ike_cert_post task. + * + * The initiator parameter means the original initiator, not the initiator + * of the certificate request. + * + * @param ike_sa IKE_SA this task works for + * @param initiator TRUE if thask is the original initator + * @return ike_cert_post task to handle by the task_manager + */ +ike_cert_post_t *ike_cert_post_create(ike_sa_t *ike_sa, bool initiator); + +#endif /* IKE_CERT_POST_H_ @} */ diff --git a/src/charon/sa/tasks/ike_cert_pre.c b/src/charon/sa/tasks/ike_cert_pre.c new file mode 100644 index 000000000..aa1cfb18a --- /dev/null +++ b/src/charon/sa/tasks/ike_cert_pre.c @@ -0,0 +1,346 @@ +/* + * Copyright (C) 2006-2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "ike_cert_pre.h" + +#include +#include +#include +#include +#include + + +typedef struct private_ike_cert_pre_t private_ike_cert_pre_t; + +/** + * Private members of a ike_cert_pre_t task. + */ +struct private_ike_cert_pre_t { + + /** + * Public methods and task_t interface. + */ + ike_cert_pre_t public; + + /** + * Assigned IKE_SA. + */ + ike_sa_t *ike_sa; + + /** + * Are we the initiator? + */ + bool initiator; +}; + +/** + * read certificate requests + */ +static void process_certreqs(private_ike_cert_pre_t *this, message_t *message) +{ + iterator_t *iterator; + payload_t *payload; + auth_info_t *auth; + bool ca_found = FALSE; + + auth = this->ike_sa->get_my_auth(this->ike_sa); + + iterator = message->get_payload_iterator(message); + while (iterator->iterate(iterator, (void**)&payload)) + { + if (payload->get_type(payload) == CERTIFICATE_REQUEST) + { + certreq_payload_t *certreq = (certreq_payload_t*)payload; + chunk_t keyid; + enumerator_t *enumerator; + + this->ike_sa->set_condition(this->ike_sa, COND_CERTREQ_SEEN, TRUE); + + if (certreq->get_cert_type(certreq) != CERT_X509) + { + DBG1(DBG_IKE, "cert payload %N not supported - ignored", + certificate_type_names, certreq->get_cert_type(certreq)); + continue; + } + enumerator = certreq->create_keyid_enumerator(certreq); + while (enumerator->enumerate(enumerator, &keyid)) + { + identification_t *id; + certificate_t *cert; + + id = identification_create_from_encoding( + ID_PUBKEY_INFO_SHA1, keyid); + cert = charon->credentials->get_cert(charon->credentials, + CERT_X509, KEY_ANY, id, TRUE); + if (cert) + { + DBG1(DBG_IKE, "received cert request for %D", + cert->get_subject(cert)); + auth->add_item(auth, AUTHN_CA_CERT, cert); + cert->destroy(cert); + ca_found = TRUE; + } + id->destroy(id); + } + enumerator->destroy(enumerator); + } + } + iterator->destroy(iterator); + + if (this->ike_sa->has_condition(this->ike_sa, COND_CERTREQ_SEEN) && !ca_found) + { + DBG1(DBG_IKE, "received cert request, but no such CA cert found"); + } +} + +/** + * import certificates + */ +static void process_certs(private_ike_cert_pre_t *this, message_t *message) +{ + iterator_t *iterator; + payload_t *payload; + auth_info_t *auth; + bool first = TRUE; + + auth = this->ike_sa->get_other_auth(this->ike_sa); + + iterator = message->get_payload_iterator(message); + while (iterator->iterate(iterator, (void**)&payload)) + { + if (payload->get_type(payload) == CERTIFICATE) + { + certificate_t *cert; + cert_payload_t *cert_payload = (cert_payload_t*)payload; + + cert = cert_payload->get_cert(cert_payload); + if (cert) + { + if (first) + { /* the first certificate MUST be an end entity one */ + + DBG1(DBG_IKE, "received end entity cert %D", + cert->get_subject(cert)); + auth->add_item(auth, AUTHN_SUBJECT_CERT, cert); + first = FALSE; + } + else + { + DBG1(DBG_IKE, "received issuer cert %D", + cert->get_subject(cert)); + auth->add_item(auth, AUTHN_IM_CERT, cert); + } + } + cert->destroy(cert); + } + } + iterator->destroy(iterator); +} + +/** + * add a certificate request to the message, building request payload if required. + */ +static void add_certreq_payload(message_t *message, certreq_payload_t **reqp, + certificate_t *cert) +{ + public_key_t *public; + certreq_payload_t *req; + + public = cert->get_public_key(cert); + if (!public) + { + return; + } + switch (cert->get_type(cert)) + { + case CERT_X509: + { + identification_t *keyid; + x509_t *x509 = (x509_t*)cert; + + if (!(x509->get_flags(x509) & X509_CA)) + { /* no CA cert, skip */ + break; + } + if (*reqp == NULL) + { + *reqp = certreq_payload_create_type(CERT_X509); + message->add_payload(message, (payload_t*)*reqp); + } + req = *reqp; + keyid = public->get_id(public, ID_PUBKEY_INFO_SHA1); + req->add_keyid(req, keyid->get_encoding(keyid)); + DBG1(DBG_IKE, "sending cert request for %D", + cert->get_subject(cert)); + break; + } + default: + break; + } + public->destroy(public); +} + +/** + * build certificate requests + */ +static void build_certreqs(private_ike_cert_pre_t *this, message_t *message) +{ + ike_cfg_t *ike_cfg; + enumerator_t *enumerator; + certificate_t *cert; + auth_info_t *auth; + bool restricted = FALSE; + auth_item_t item; + certreq_payload_t *x509_req = NULL; + + ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa); + if (ike_cfg->send_certreq(ike_cfg) == CERT_NEVER_SEND) + { + return; + } + auth = this->ike_sa->get_other_auth(this->ike_sa); + + /* check if we require a specific CA for that peer */ + enumerator = auth->create_item_enumerator(auth); + while (enumerator->enumerate(enumerator, &item, &cert)) + { + if (item == AUTHN_CA_CERT) + { + restricted = TRUE; + add_certreq_payload(message, &x509_req, cert); + } + } + enumerator->destroy(enumerator); + + if (!restricted) + { + /* otherwise include all trusted CA certificates */ + enumerator = charon->credentials->create_cert_enumerator( + charon->credentials, CERT_ANY, KEY_ANY, NULL, TRUE); + while (enumerator->enumerate(enumerator, &cert, TRUE)) + { + add_certreq_payload(message, &x509_req, cert); + } + enumerator->destroy(enumerator); + } +} + +/** + * Implementation of task_t.process for initiator + */ +static status_t build_i(private_ike_cert_pre_t *this, message_t *message) +{ + if (message->get_exchange_type(message) == IKE_SA_INIT) + { + return NEED_MORE; + } + build_certreqs(this, message); + return NEED_MORE; +} + +/** + * Implementation of task_t.process for responder + */ +static status_t process_r(private_ike_cert_pre_t *this, message_t *message) +{ + if (message->get_exchange_type(message) == IKE_SA_INIT) + { + return NEED_MORE; + } + process_certreqs(this, message); + process_certs(this, message); + return NEED_MORE; +} + +/** + * Implementation of task_t.build for responder + */ +static status_t build_r(private_ike_cert_pre_t *this, message_t *message) +{ + if (message->get_exchange_type(message) == IKE_SA_INIT) + { + build_certreqs(this, message); + return NEED_MORE; + } + return SUCCESS; +} + +/** + * Implementation of task_t.process for initiator + */ +static status_t process_i(private_ike_cert_pre_t *this, message_t *message) +{ + if (message->get_exchange_type(message) == IKE_SA_INIT) + { + process_certreqs(this, message); + return NEED_MORE; + } + process_certs(this, message); + return SUCCESS; +} + +/** + * Implementation of task_t.get_type + */ +static task_type_t get_type(private_ike_cert_pre_t *this) +{ + return IKE_CERT_PRE; +} + +/** + * Implementation of task_t.migrate + */ +static void migrate(private_ike_cert_pre_t *this, ike_sa_t *ike_sa) +{ + this->ike_sa = ike_sa; +} + +/** + * Implementation of task_t.destroy + */ +static void destroy(private_ike_cert_pre_t *this) +{ + free(this); +} + +/* + * Described in header. + */ +ike_cert_pre_t *ike_cert_pre_create(ike_sa_t *ike_sa, bool initiator) +{ + private_ike_cert_pre_t *this = malloc_thing(private_ike_cert_pre_t); + + this->public.task.get_type = (task_type_t(*)(task_t*))get_type; + this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate; + this->public.task.destroy = (void(*)(task_t*))destroy; + + if (initiator) + { + this->public.task.build = (status_t(*)(task_t*,message_t*))build_i; + this->public.task.process = (status_t(*)(task_t*,message_t*))process_i; + } + else + { + this->public.task.build = (status_t(*)(task_t*,message_t*))build_r; + this->public.task.process = (status_t(*)(task_t*,message_t*))process_r; + } + + this->ike_sa = ike_sa; + this->initiator = initiator; + + return &this->public; +} diff --git a/src/charon/sa/tasks/ike_cert_pre.h b/src/charon/sa/tasks/ike_cert_pre.h new file mode 100644 index 000000000..c7422e629 --- /dev/null +++ b/src/charon/sa/tasks/ike_cert_pre.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2007-2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +/** + * @defgroup ike_cert_pre ike_cert_pre + * @{ @ingroup tasks + */ + +#ifndef IKE_CERT_PRE_H_ +#define IKE_CERT_PRE_H_ + +typedef struct ike_cert_pre_t ike_cert_pre_t; + +#include +#include +#include + +/** + * Task of type ike_cert_post, certificate processing before authentication. + */ +struct ike_cert_pre_t { + + /** + * Implements the task_t interface + */ + task_t task; +}; + +/** + * Create a new ike_cert_pre task. + * + * The initiator parameter means the original initiator, not the initiator + * of the certificate request. + * + * @param ike_sa IKE_SA this task works for + * @param initiator TRUE if thask is the original initator + * @return ike_cert_pre task to handle by the task_manager + */ +ike_cert_pre_t *ike_cert_pre_create(ike_sa_t *ike_sa, bool initiator); + +#endif /* IKE_CERT_PRE_H_ @} */ diff --git a/src/charon/sa/tasks/ike_config.c b/src/charon/sa/tasks/ike_config.c index 3c73395a5..2af0aed96 100644 --- a/src/charon/sa/tasks/ike_config.c +++ b/src/charon/sa/tasks/ike_config.c @@ -1,10 +1,3 @@ -/** - * @file ike_config.c - * - * @brief Implementation of the ike_config task. - * - */ - /* * Copyright (C) 2007 Martin Willi * Copyright (C) 2006-2007 Fabian Hartmann, Noah Heusser @@ -19,6 +12,8 @@ * 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. + * + * $Id$ */ #include "ike_config.h" diff --git a/src/charon/sa/tasks/ike_config.h b/src/charon/sa/tasks/ike_config.h index a7cfddff0..9ee2f59be 100644 --- a/src/charon/sa/tasks/ike_config.h +++ b/src/charon/sa/tasks/ike_config.h @@ -1,10 +1,3 @@ -/** - * @file ike_config.h - * - * @brief Interface ike_config_t. - * - */ - /* * Copyright (C) 2007 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup ike_config ike_config + * @{ @ingroup tasks */ #ifndef IKE_CONFIG_H_ @@ -30,13 +30,8 @@ typedef struct ike_config_t ike_config_t; #include /** - * @brief Task of type IKE_CONFIG, sets up a virtual IP and other + * Task of type IKE_CONFIG, sets up a virtual IP and other * configurations for an IKE_SA. - * - * @b Constructors: - * - ike_config_create() - * - * @ingroup tasks */ struct ike_config_t { @@ -47,7 +42,7 @@ struct ike_config_t { }; /** - * @brief Create a new ike_config task. + * Create a new ike_config task. * * @param ike_sa IKE_SA this task works for * @param initiator TRUE for initiator @@ -55,4 +50,4 @@ struct ike_config_t { */ ike_config_t *ike_config_create(ike_sa_t *ike_sa, bool initiator); -#endif /* IKE_CONFIG_H_ */ +#endif /* IKE_CONFIG_H_ @} */ diff --git a/src/charon/sa/tasks/ike_delete.c b/src/charon/sa/tasks/ike_delete.c index 1a3656ca6..6e1ee8b10 100644 --- a/src/charon/sa/tasks/ike_delete.c +++ b/src/charon/sa/tasks/ike_delete.c @@ -1,10 +1,3 @@ -/** - * @file ike_delete.c - * - * @brief Implementation of the ike_delete task. - * - */ - /* * Copyright (C) 2006-2007 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,8 @@ * 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. + * + * $Id$ */ #include "ike_delete.h" diff --git a/src/charon/sa/tasks/ike_delete.h b/src/charon/sa/tasks/ike_delete.h index e8ec5ebbe..f9cb4dc64 100644 --- a/src/charon/sa/tasks/ike_delete.h +++ b/src/charon/sa/tasks/ike_delete.h @@ -1,10 +1,3 @@ -/** - * @file ike_delete.h - * - * @brief Interface ike_delete_t. - * - */ - /* * Copyright (C) 2007 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup ike_delete ike_delete + * @{ @ingroup tasks */ #ifndef IKE_DELETE_H_ @@ -30,12 +30,7 @@ typedef struct ike_delete_t ike_delete_t; #include /** - * @brief Task of type ike_delete, delete an IKE_SA. - * - * @b Constructors: - * - ike_delete_create() - * - * @ingroup tasks + * Task of type ike_delete, delete an IKE_SA. */ struct ike_delete_t { @@ -46,7 +41,7 @@ struct ike_delete_t { }; /** - * @brief Create a new ike_delete task. + * Create a new ike_delete task. * * @param ike_sa IKE_SA this task works for * @param initiator TRUE if we initiate the delete @@ -54,4 +49,4 @@ struct ike_delete_t { */ ike_delete_t *ike_delete_create(ike_sa_t *ike_sa, bool initiator); -#endif /* IKE_DELETE_H_ */ +#endif /* IKE_DELETE_H_ @} */ diff --git a/src/charon/sa/tasks/ike_dpd.c b/src/charon/sa/tasks/ike_dpd.c index be751766e..04c5a66d1 100644 --- a/src/charon/sa/tasks/ike_dpd.c +++ b/src/charon/sa/tasks/ike_dpd.c @@ -1,10 +1,3 @@ -/** - * @file ike_dpd.c - * - * @brief Implementation of the ike_dpd task. - * - */ - /* * Copyright (C) 2007 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,8 @@ * 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. + * + * $Id$ */ #include "ike_dpd.h" diff --git a/src/charon/sa/tasks/ike_dpd.h b/src/charon/sa/tasks/ike_dpd.h index 531b0502d..56bbee399 100644 --- a/src/charon/sa/tasks/ike_dpd.h +++ b/src/charon/sa/tasks/ike_dpd.h @@ -1,10 +1,3 @@ -/** - * @file ike_dpd.h - * - * @brief Interface ike_dpd_t. - * - */ - /* * Copyright (C) 2007 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup ike_dpd ike_dpd + * @{ @ingroup tasks */ #ifndef IKE_DPD_H_ @@ -30,14 +30,9 @@ typedef struct ike_dpd_t ike_dpd_t; #include /** - * @brief Task of type ike_dpd, detects dead peers. + * Task of type ike_dpd, detects dead peers. * * The DPD task actually does nothing, as a DPD has no associated payloads. - * - * @b Constructors: - * - ike_dpd_create() - * - * @ingroup tasks */ struct ike_dpd_t { @@ -48,11 +43,11 @@ struct ike_dpd_t { }; /** - * @brief Create a new ike_dpd task. + * Create a new ike_dpd task. * * @param initiator TRUE if thask is the original initator * @return ike_dpd task to handle by the task_manager */ ike_dpd_t *ike_dpd_create(bool initiator); -#endif /* IKE_DPD_H_ */ +#endif /* IKE_DPD_H_ @} */ diff --git a/src/charon/sa/tasks/ike_init.c b/src/charon/sa/tasks/ike_init.c index 42b47a82f..6bb3688ea 100644 --- a/src/charon/sa/tasks/ike_init.c +++ b/src/charon/sa/tasks/ike_init.c @@ -1,10 +1,3 @@ -/** - * @file ike_init.c - * - * @brief Implementation of the ike_init task. - * - */ - /* * Copyright (C) 2005-2007 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,8 @@ * 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. + * + * $Id$ */ #include "ike_init.h" @@ -195,7 +190,7 @@ static void process_payloads(private_ike_init_t *this, message_t *message) this->dh_group = ke_payload->get_dh_group_number(ke_payload); if (!this->initiator) { - this->dh = diffie_hellman_create(this->dh_group); + this->dh = lib->crypto->create_dh(lib->crypto, this->dh_group); } if (this->dh) { @@ -241,7 +236,7 @@ static status_t build_i(private_ike_init_t *this, message_t *message) if (!this->dh) { this->dh_group = this->config->get_dh_group(this->config); - this->dh = diffie_hellman_create(this->dh_group); + this->dh = lib->crypto->create_dh(lib->crypto, this->dh_group); if (this->dh == NULL) { SIG(IKE_UP_FAILED, "configured DH group %N not supported", @@ -532,7 +527,7 @@ static void migrate(private_ike_init_t *this, ike_sa_t *ike_sa) this->ike_sa = ike_sa; this->proposal = NULL; - this->dh = diffie_hellman_create(this->dh_group); + this->dh = lib->crypto->create_dh(lib->crypto, this->dh_group); } /** diff --git a/src/charon/sa/tasks/ike_init.h b/src/charon/sa/tasks/ike_init.h index f60c096e8..67afd2b8d 100644 --- a/src/charon/sa/tasks/ike_init.h +++ b/src/charon/sa/tasks/ike_init.h @@ -1,10 +1,3 @@ -/** - * @file ike_init.h - * - * @brief Interface ike_init_t. - * - */ - /* * Copyright (C) 2007 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup ike_init ike_init + * @{ @ingroup tasks */ #ifndef IKE_INIT_H_ @@ -30,14 +30,9 @@ typedef struct ike_init_t ike_init_t; #include /** - * @brief Task of type IKE_INIT, creates an IKE_SA without authentication. + * Task of type IKE_INIT, creates an IKE_SA without authentication. * * The authentication of is handle in the ike_auth task. - * - * @b Constructors: - * - ike_init_create() - * - * @ingroup tasks */ struct ike_init_t { @@ -47,16 +42,15 @@ struct ike_init_t { task_t task; /** - * @brief Get the lower of the two nonces, used for rekey collisions. + * Get the lower of the two nonces, used for rekey collisions. * - * @param this calling object * @return lower nonce */ chunk_t (*get_lower_nonce) (ike_init_t *this); }; /** - * @brief Create a new IKE_INIT task. + * Create a new IKE_INIT task. * * @param ike_sa IKE_SA this task works for (new one when rekeying) * @param initiator TRUE if thask is the original initator @@ -65,4 +59,4 @@ struct ike_init_t { */ ike_init_t *ike_init_create(ike_sa_t *ike_sa, bool initiator, ike_sa_t *old_sa); -#endif /* IKE_INIT_H_ */ +#endif /* IKE_INIT_H_ @} */ diff --git a/src/charon/sa/tasks/ike_mobike.c b/src/charon/sa/tasks/ike_mobike.c index a53c243f0..62a1ad3cd 100644 --- a/src/charon/sa/tasks/ike_mobike.c +++ b/src/charon/sa/tasks/ike_mobike.c @@ -1,10 +1,3 @@ -/** - * @file ike_mobike.c - * - * @brief Implementation of the ike_mobike task. - * - */ - /* * Copyright (C) 2007 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,8 @@ * 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. + * + * $Id$ */ #include "ike_mobike.h" diff --git a/src/charon/sa/tasks/ike_mobike.h b/src/charon/sa/tasks/ike_mobike.h index bb5150723..7325f5a6f 100644 --- a/src/charon/sa/tasks/ike_mobike.h +++ b/src/charon/sa/tasks/ike_mobike.h @@ -1,10 +1,3 @@ -/** - * @file ike_mobike.h - * - * @brief Interface ike_mobike_t. - * - */ - /* * Copyright (C) 2007 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup ike_mobike ike_mobike + * @{ @ingroup tasks */ #ifndef IKE_MOBIKE_H_ @@ -31,7 +31,7 @@ typedef struct ike_mobike_t ike_mobike_t; #include /** - * @brief Task of type ike_mobike, detects and handles MOBIKE extension. + * Task of type ike_mobike, detects and handles MOBIKE extension. * * The MOBIKE extension is defined in RFC4555. It allows to update IKE * and IPsec tunnel addresses. @@ -39,11 +39,6 @@ typedef struct ike_mobike_t ike_mobike_t; * support, allows the exchange of ADDITIONAL_*_ADDRESS to exchange additional * endpoints and handles the UPDATE_SA_ADDRESS notify to finally update * endpoints. - * - * @b Constructors: - * - ike_mobike_create() - * - * @ingroup tasks */ struct ike_mobike_t { @@ -53,36 +48,33 @@ struct ike_mobike_t { task_t task; /** - * @brief Use the task to roam to other addresses. + * Use the task to roam to other addresses. * - * @param this calling object * @param address TRUE to include address list update */ void (*roam)(ike_mobike_t *this, bool address); /** - * @brief Transmision hook, called by task manager. + * Transmision hook, called by task manager. * * The task manager calls this hook whenever it transmits a packet. It * allows the mobike task to send the packet on multiple paths to do path * probing. * - * @param this calling object * @param packet the packet to transmit */ void (*transmit)(ike_mobike_t *this, packet_t *packet); /** - * @brief Check if this task is probing for routability. + * Check if this task is probing for routability. * - * @param this calling object * @return TRUE if task is probing */ bool (*is_probing)(ike_mobike_t *this); }; /** - * @brief Create a new ike_mobike task. + * Create a new ike_mobike task. * * @param ike_sa IKE_SA this task works for * @param initiator TRUE if taks is initiated by us @@ -90,5 +82,4 @@ struct ike_mobike_t { */ ike_mobike_t *ike_mobike_create(ike_sa_t *ike_sa, bool initiator); -#endif /* IKE_MOBIKE_H_ */ - +#endif /* IKE_MOBIKE_H_ @} */ diff --git a/src/charon/sa/tasks/ike_natd.c b/src/charon/sa/tasks/ike_natd.c index 4c64ff8ba..1662a3268 100644 --- a/src/charon/sa/tasks/ike_natd.c +++ b/src/charon/sa/tasks/ike_natd.c @@ -1,10 +1,3 @@ -/** - * @file ike_natd.c - * - * @brief Implementation of the ike_natd task. - * - */ - /* * Copyright (C) 2006-2007 Martin Willi * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger @@ -19,6 +12,8 @@ * 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. + * + * $Id$ */ #include "ike_natd.h" @@ -308,6 +303,12 @@ static status_t build_i(private_ike_natd_t *this, message_t *message) iterator_t *iterator; host_t *host; + if (this->hasher == NULL) + { + DBG1(DBG_IKE, "unable to build NATD payloads, SHA1 not supported"); + return NEED_MORE; + } + /* destination is always set */ host = message->get_destination(message); notify = build_natd_payload(this, NAT_DETECTION_DESTINATION_IP, host); @@ -368,6 +369,12 @@ static status_t build_r(private_ike_natd_t *this, message_t *message) if (this->src_seen && this->dst_seen) { + if (this->hasher == NULL) + { + DBG1(DBG_IKE, "unable to build NATD payloads, SHA1 not supported"); + return SUCCESS; + } + /* initiator seems to support NAT detection, add response */ me = message->get_source(message); notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, me); @@ -415,7 +422,7 @@ static void migrate(private_ike_natd_t *this, ike_sa_t *ike_sa) */ static void destroy(private_ike_natd_t *this) { - this->hasher->destroy(this->hasher); + DESTROY_IF(this->hasher); free(this); } @@ -443,7 +450,7 @@ ike_natd_t *ike_natd_create(ike_sa_t *ike_sa, bool initiator) this->ike_sa = ike_sa; this->initiator = initiator; - this->hasher = hasher_create(HASH_SHA1); + this->hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); this->src_seen = FALSE; this->dst_seen = FALSE; this->src_matched = FALSE; diff --git a/src/charon/sa/tasks/ike_natd.h b/src/charon/sa/tasks/ike_natd.h index 8d0cb58b4..793408797 100644 --- a/src/charon/sa/tasks/ike_natd.h +++ b/src/charon/sa/tasks/ike_natd.h @@ -1,10 +1,3 @@ -/** - * @file ike_natd.h - * - * @brief Interface ike_natd_t. - * - */ - /* * Copyright (C) 2007 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup ike_natd ike_natd + * @{ @ingroup tasks */ #ifndef IKE_NATD_H_ @@ -30,12 +30,7 @@ typedef struct ike_natd_t ike_natd_t; #include /** - * @brief Task of type ike_natd, detects NAT situation in IKE_SA_INIT exchange. - * - * @b Constructors: - * - ike_natd_create() - * - * @ingroup tasks + * Task of type ike_natd, detects NAT situation in IKE_SA_INIT exchange. */ struct ike_natd_t { @@ -46,7 +41,7 @@ struct ike_natd_t { }; /** - * @brief Create a new ike_natd task. + * Create a new ike_natd task. * * @param ike_sa IKE_SA this task works for * @param initiator TRUE if thask is the original initator @@ -54,4 +49,4 @@ struct ike_natd_t { */ ike_natd_t *ike_natd_create(ike_sa_t *ike_sa, bool initiator); -#endif /* IKE_NATD_H_ */ +#endif /* IKE_NATD_H_ @} */ diff --git a/src/charon/sa/tasks/ike_p2p.c b/src/charon/sa/tasks/ike_p2p.c index 6f632733a..ce3a3fd00 100644 --- a/src/charon/sa/tasks/ike_p2p.c +++ b/src/charon/sa/tasks/ike_p2p.c @@ -1,10 +1,3 @@ -/** - * @file ike_p2p.c - * - * @brief Implementation of the ike_p2p task. - * - */ - /* * Copyright (C) 2007 Tobias Brunner * Hochschule fuer Technik Rapperswil @@ -18,8 +11,10 @@ * 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. + * + * $Id$ */ - + #include "ike_p2p.h" #include diff --git a/src/charon/sa/tasks/ike_p2p.h b/src/charon/sa/tasks/ike_p2p.h index 327ac49d8..fe6bbd1a2 100644 --- a/src/charon/sa/tasks/ike_p2p.h +++ b/src/charon/sa/tasks/ike_p2p.h @@ -1,10 +1,3 @@ -/** - * @file ike_p2p.h - * - * @brief Interface ike_p2p_t. - * - */ - /* * Copyright (C) 2007 Tobias Brunner * Hochschule fuer Technik Rapperswil @@ -18,6 +11,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup ike_p2p ike_p2p + * @{ @ingroup tasks */ #ifndef IKE_P2P_H_ @@ -30,7 +30,7 @@ typedef struct ike_p2p_t ike_p2p_t; #include /** - * @brief Task of type IKE_P2P, detects and handles P2P-NAT-T extensions. + * Task of type IKE_P2P, detects and handles P2P-NAT-T extensions. * * This tasks handles the P2P_MEDIATION notify exchange to setup a mediation * connection, allows to initiate mediated connections using P2P_CONNECT @@ -40,11 +40,6 @@ typedef struct ike_p2p_t ike_p2p_t; * @note This task has to be activated before the IKE_AUTH task, because that * task generates the IKE_SA_INIT message so that no more payloads can be added * to it afterwards. - * - * @b Constructors: - * - ike_p2p_create() - * - * @ingroup tasks */ struct ike_p2p_t { @@ -54,38 +49,34 @@ struct ike_p2p_t { task_t task; /** - * @brief Initiates a connection with another peer (i.e. sends a P2P_CONNECT + * Initiates a connection with another peer (i.e. sends a P2P_CONNECT * to the mediation server) * - * @param this object * @param peer_id ID of the other peer (gets cloned) */ void (*connect)(ike_p2p_t *this, identification_t *peer_id); /** - * @brief Responds to a P2P_CONNECT from another peer (i.e. sends a P2P_CONNECT + * Responds to a P2P_CONNECT from another peer (i.e. sends a P2P_CONNECT * to the mediation server) * - * @param this object * @param peer_id ID of the other peer (gets cloned) * @param session_id the session ID as provided by the initiator (gets cloned) */ void (*respond)(ike_p2p_t *this, identification_t *peer_id, chunk_t session_id); /** - * @brief Sends a P2P_CALLBACK to a peer that previously requested another peer. + * Sends a P2P_CALLBACK to a peer that previously requested another peer. * - * @param this object * @param peer_id ID of the other peer (gets cloned) */ void (*callback)(ike_p2p_t *this, identification_t *peer_id); /** - * @brief Relays data to another peer (i.e. sends a P2P_CONNECT to the peer) + * Relays data to another peer (i.e. sends a P2P_CONNECT to the peer) * * Data gets cloned. * - * @param this object * @param requester ID of the requesting peer * @param session_id content of the P2P_SESSIONID notify * @param session_key content of the P2P_SESSIONKEY notify @@ -98,7 +89,7 @@ struct ike_p2p_t { }; /** - * @brief Create a new ike_p2p task. + * Create a new ike_p2p task. * * @param ike_sa IKE_SA this task works for * @param initiator TRUE if taks is initiated by us @@ -106,5 +97,4 @@ struct ike_p2p_t { */ ike_p2p_t *ike_p2p_create(ike_sa_t *ike_sa, bool initiator); - -#endif /*IKE_P2P_H_*/ +#endif /*IKE_P2P_H_ @} */ diff --git a/src/charon/sa/tasks/ike_reauth.c b/src/charon/sa/tasks/ike_reauth.c index 0e98382a8..7b69a938f 100644 --- a/src/charon/sa/tasks/ike_reauth.c +++ b/src/charon/sa/tasks/ike_reauth.c @@ -1,10 +1,3 @@ -/** - * @file ike_reauth.c - * - * @brief Implementation of the ike_reauth task. - * - */ - /* * Copyright (C) 2006-2007 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,8 @@ * 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. + * + * $Id$ */ #include "ike_reauth.h" diff --git a/src/charon/sa/tasks/ike_reauth.h b/src/charon/sa/tasks/ike_reauth.h index 3c872e1e1..f5599fd76 100644 --- a/src/charon/sa/tasks/ike_reauth.h +++ b/src/charon/sa/tasks/ike_reauth.h @@ -1,10 +1,3 @@ -/** - * @file ike_reauth.h - * - * @brief Interface ike_reauth_t. - * - */ - /* * Copyright (C) 2007 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup ike_reauth ike_reauth + * @{ @ingroup tasks */ #ifndef IKE_REAUTH_H_ @@ -30,12 +30,7 @@ typedef struct ike_reauth_t ike_reauth_t; #include /** - * @brief Task of type ike_reauth, reestablishes an IKE_SA. - * - * @b Constructors: - * - ike_reauth_create() - * - * @ingroup tasks + * Task of type ike_reauth, reestablishes an IKE_SA. */ struct ike_reauth_t { @@ -46,7 +41,7 @@ struct ike_reauth_t { }; /** - * @brief Create a new ike_reauth task. + * Create a new ike_reauth task. * * This task is initiator only. * @@ -55,5 +50,4 @@ struct ike_reauth_t { */ ike_reauth_t *ike_reauth_create(ike_sa_t *ike_sa); -#endif /* IKE_REAUTH_H_ */ - +#endif /* IKE_REAUTH_H_ @} */ diff --git a/src/charon/sa/tasks/ike_rekey.c b/src/charon/sa/tasks/ike_rekey.c index 827f95156..1428d5699 100644 --- a/src/charon/sa/tasks/ike_rekey.c +++ b/src/charon/sa/tasks/ike_rekey.c @@ -1,10 +1,3 @@ -/** - * @file ike_rekey.c - * - * @brief Implementation of the ike_rekey task. - * - */ - /* * Copyright (C) 2005-2007 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,8 @@ * 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. + * + * $Id$ */ #include "ike_rekey.h" diff --git a/src/charon/sa/tasks/ike_rekey.h b/src/charon/sa/tasks/ike_rekey.h index 125422efd..06889cb39 100644 --- a/src/charon/sa/tasks/ike_rekey.h +++ b/src/charon/sa/tasks/ike_rekey.h @@ -1,10 +1,3 @@ -/** - * @file ike_rekey.h - * - * @brief Interface ike_rekey_t. - * - */ - /* * Copyright (C) 2007 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup ike_rekey ike_rekey + * @{ @ingroup tasks */ #ifndef IKE_REKEY_H_ @@ -30,12 +30,7 @@ typedef struct ike_rekey_t ike_rekey_t; #include /** - * @brief Task of type IKE_REKEY, rekey an established IKE_SA. - * - * @b Constructors: - * - ike_rekey_create() - * - * @ingroup tasks + * Task of type IKE_REKEY, rekey an established IKE_SA. */ struct ike_rekey_t { @@ -45,20 +40,19 @@ struct ike_rekey_t { task_t task; /** - * @brief Register a rekeying task which collides with this one. + * Register a rekeying task which collides with this one. * * If two peers initiate rekeying at the same time, the collision must * be handled gracefully. The task manager is aware of what exchanges * are going on and notifies the outgoing task by passing the incoming. * - * @param this task initated by us * @param other incoming task */ void (*collide)(ike_rekey_t* this, task_t *other); }; /** - * @brief Create a new IKE_REKEY task. + * Create a new IKE_REKEY task. * * @param ike_sa IKE_SA this task works for * @param initiator TRUE for initiator, FALSE for responder @@ -66,4 +60,4 @@ struct ike_rekey_t { */ ike_rekey_t *ike_rekey_create(ike_sa_t *ike_sa, bool initiator); -#endif /* IKE_REKEY_H_ */ +#endif /* IKE_REKEY_H_ @} */ diff --git a/src/charon/sa/tasks/task.c b/src/charon/sa/tasks/task.c index cc20a8861..0ff2afd77 100644 --- a/src/charon/sa/tasks/task.c +++ b/src/charon/sa/tasks/task.c @@ -1,10 +1,3 @@ -/** - * @file task.c - * - * @brief Enum values for task types - * - */ - /* * Copyright (C) 2007 Tobias Brunner * Copyright (C) 2007 Martin Willi @@ -19,6 +12,8 @@ * 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. + * + * $Id$ */ #include "task.h" @@ -29,7 +24,8 @@ ENUM(task_type_names, IKE_INIT, CHILD_REKEY, "IKE_MOBIKE", "IKE_AUTHENTICATE", "IKE_AUTH_LIFETIME", - "IKE_CERT", + "IKE_CERT_PRE", + "IKE_CERT_POST", "IKE_CONFIG", "IKE_REKEY", "IKE_REAUTH", diff --git a/src/charon/sa/tasks/task.h b/src/charon/sa/tasks/task.h index a59207711..773bc60c6 100644 --- a/src/charon/sa/tasks/task.h +++ b/src/charon/sa/tasks/task.h @@ -1,10 +1,3 @@ -/** - * @file task.h - * - * @brief Interface task_t. - * - */ - /* * Copyright (C) 2007 Tobias Brunner * Copyright (C) 2006 Martin Willi @@ -19,6 +12,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup task task + * @{ @ingroup tasks */ #ifndef TASK_H_ @@ -32,9 +32,7 @@ typedef struct task_t task_t; #include /** - * @brief Different kinds of tasks. - * - * @ingroup tasks + * Different kinds of tasks. */ enum task_type_t { /** establish an unauthenticated IKE_SA */ @@ -47,8 +45,10 @@ enum task_type_t { IKE_AUTHENTICATE, /** AUTH_LIFETIME negotiation, RFC4478 */ IKE_AUTH_LIFETIME, - /** exchange certificates and requests */ - IKE_CERT, + /** certificate processing before authentication (certreqs, cert parsing) */ + IKE_CERT_PRE, + /** certificate processing after authentication (certs payload generation) */ + IKE_CERT_POST, /** Configuration payloads, virtual IP and such */ IKE_CONFIG, /** rekey an IKE_SA */ @@ -77,7 +77,7 @@ enum task_type_t { extern enum_name_t *task_type_names; /** - * @brief Interface for a task, an operation handled within exchanges. + * Interface for a task, an operation handled within exchanges. * * A task is an elemantary operation. It may be handled by a single or by * multiple exchanges. An exchange may even complete multiple tasks. @@ -94,18 +94,12 @@ extern enum_name_t *task_type_names; * the task needs further build()/process() calls to complete, the manager * leaves the taks in the queue. A returned FAILED indicates a critical failure. * The manager closes the IKE_SA whenever a task returns FAILED. - * - * @b Constructors: - * - None, use implementations specific constructors - * - * @ingroup tasks */ struct task_t { /** - * @brief Build a request or response message for this task. + * Build a request or response message for this task. * - * @param this calling object * @param message message to add payloads to * @return * - FAILED if a critical error occured @@ -115,9 +109,8 @@ struct task_t { status_t (*build) (task_t *this, message_t *message); /** - * @brief Process a request or response message for this task. + * Process a request or response message for this task. * - * @param this calling object * @param message message to read payloads from * @return * - FAILED if a critical error occured @@ -127,14 +120,12 @@ struct task_t { status_t (*process) (task_t *this, message_t *message); /** - * @brief Get the type of the task implementation. - * - * @param this calling object + * Get the type of the task implementation. */ task_type_t (*get_type) (task_t *this); /** - * @brief Migrate a task to a new IKE_SA. + * Migrate a task to a new IKE_SA. * * After migrating a task, it goes back to a state where it can be * used again to initate an exchange. This is useful when a task @@ -144,17 +135,14 @@ struct task_t { * try. * The ike_sa is the new IKE_SA this task belongs to and operates on. * - * @param this calling object * @param ike_sa new IKE_SA this task works for */ void (*migrate) (task_t *this, ike_sa_t *ike_sa); /** - * @brief Destroys a task_t object. - * - * @param this calling object + * Destroys a task_t object. */ void (*destroy) (task_t *this); }; -#endif /* TASK_H_ */ +#endif /* TASK_H_ @} */ diff --git a/src/libfast/Makefile.am b/src/libfast/Makefile.am new file mode 100644 index 000000000..6104f335d --- /dev/null +++ b/src/libfast/Makefile.am @@ -0,0 +1,8 @@ +lib_LTLIBRARIES = libfast.la + +libfast_la_SOURCES = context.h dispatcher.c request.h session.h \ + controller.h dispatcher.h request.c session.c filter.h +libfast_la_LIBADD = $(top_builddir)/src/libstrongswan/libstrongswan.la \ + -lfcgi -lpthread -lneo_cgi -lneo_cs -lneo_utl -lz +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I/usr/include/ClearSilver +AM_CFLAGS = -rdynamic diff --git a/src/libfast/context.h b/src/libfast/context.h new file mode 100644 index 000000000..6b9e83310 --- /dev/null +++ b/src/libfast/context.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +/** + * @defgroup context context + * @{ @ingroup libfast + */ + +#ifndef CONTEXT_H_ +#define CONTEXT_H_ + +typedef struct context_t context_t; + +/** + * Constructor function for a user specific context. + */ +typedef context_t *(*context_constructor_t)(void *param); + +/** + * User specific session context, to extend. + */ +struct context_t { + + /** + * Destroy the context_t. + */ + void (*destroy) (context_t *this); +}; + +#endif /* CONTEXT_H_ @}*/ diff --git a/src/libfast/controller.h b/src/libfast/controller.h new file mode 100644 index 000000000..9ac641fef --- /dev/null +++ b/src/libfast/controller.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +/** + * @defgroup controller_i controller + * @{ @ingroup libfast + */ + +#ifndef CONTROLLER_H_ +#define CONTROLLER_H_ + +#include "request.h" +#include "context.h" + +typedef struct controller_t controller_t; + +/** + * Constructor function for a controller. + * + * @param context session specific context, implements context_t + * @param param user supplied param, as registered to the dispatcher + */ +typedef controller_t *(*controller_constructor_t)(context_t* context, void *param); + +/** + * Controller interface, to be implemented by users controllers. + * + * Controller instances get created per session, so each session has an + * associated set of private controller instances. + * The controller handle function is called for each incoming request. + */ +struct controller_t { + + /** + * Get the name of the controller. + * + * @return name of the controller + */ + char* (*get_name)(controller_t *this); + + /** + * Handle a HTTP request for that controller. + * + * Request URLs are parsed in the form + * controller_name/p1/p2/p3/p4/p5 with a maximum of 5 parameters. Each + * parameter not found in the request URL is set to NULL. + * + * @param request HTTP request + * @param p1 first parameter + * @param p2 second parameter + * @param p3 third parameter + * @param p4 forth parameter + * @param p5 fifth parameter + * @return + */ + void (*handle)(controller_t *this, request_t *request, + char *p1, char *p2, char *p3, char *p4, char *p5); + + /** + * Destroy the controller instance. + */ + void (*destroy) (controller_t *this); +}; + +#endif /* CONTROLLER_H_ @} */ diff --git a/src/libfast/dispatcher.c b/src/libfast/dispatcher.c new file mode 100644 index 000000000..d5708d0ac --- /dev/null +++ b/src/libfast/dispatcher.c @@ -0,0 +1,383 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "dispatcher.h" + +#include "request.h" +#include "session.h" + +#include +#include +#include +#include + +#include +#include + +typedef struct private_dispatcher_t private_dispatcher_t; + +/** + * private data of the task manager + */ +struct private_dispatcher_t { + + /** + * public functions + */ + dispatcher_t public; + + /** + * fcgi socket fd + */ + int fd; + + /** + * thread list + */ + pthread_t *threads; + + /** + * number of threads in "threads" + */ + int thread_count; + + /** + * session locking mutex + */ + pthread_mutex_t mutex; + + /** + * List of sessions + */ + linked_list_t *sessions; + + /** + * session timeout + */ + time_t timeout; + + /** + * running in debug mode? + */ + bool debug; + + /** + * List of controllers controller_constructor_t + */ + linked_list_t *controllers; + + /** + * List of filters filter_constructor_t + */ + linked_list_t *filters; + + /** + * constructor function to create session context (in controller_entry_t) + */ + context_constructor_t context_constructor; + + /** + * user param to context constructor + */ + void *param; +}; + +typedef struct { + /** constructor function */ + controller_constructor_t constructor; + /** parameter to constructor */ + void *param; +} controller_entry_t; + +typedef struct { + /** constructor function */ + filter_constructor_t constructor; + /** parameter to constructor */ + void *param; +} filter_entry_t; + +typedef struct { + /** session instance */ + session_t *session; + /** condvar to wait for session */ + pthread_cond_t cond; + /** client host address, to prevent session hijacking */ + char *host; + /** TRUE if session is in use */ + bool in_use; + /** last use of the session */ + time_t used; + /** has the session been closed by the handler? */ + bool closed; +} session_entry_t; + +/** + * create a session and instanciate controllers + */ +static session_t* load_session(private_dispatcher_t *this) +{ + iterator_t *iterator; + controller_entry_t *centry; + filter_entry_t *fentry; + session_t *session; + context_t *context = NULL; + controller_t *controller; + filter_t *filter; + + if (this->context_constructor) + { + context = this->context_constructor(this->param); + } + session = session_create(context); + + iterator = this->controllers->create_iterator(this->controllers, TRUE); + while (iterator->iterate(iterator, (void**)¢ry)) + { + controller = centry->constructor(context, centry->param); + session->add_controller(session, controller); + } + iterator->destroy(iterator); + + iterator = this->filters->create_iterator(this->filters, TRUE); + while (iterator->iterate(iterator, (void**)&fentry)) + { + filter = fentry->constructor(context, fentry->param); + session->add_filter(session, filter); + } + iterator->destroy(iterator); + + return session; +} + +/** + * create a new session entry + */ +static session_entry_t *session_entry_create(private_dispatcher_t *this, + char *host) +{ + session_entry_t *entry; + + entry = malloc_thing(session_entry_t); + entry->in_use = FALSE; + entry->closed = FALSE; + pthread_cond_init(&entry->cond, NULL); + entry->session = load_session(this); + entry->used = time(NULL); + entry->host = strdup(host); + + return entry; +} + +static void session_entry_destroy(session_entry_t *entry) +{ + entry->session->destroy(entry->session); + free(entry->host); + free(entry); +} + +/** + * Implementation of dispatcher_t.add_controller. + */ +static void add_controller(private_dispatcher_t *this, + controller_constructor_t constructor, void *param) +{ + controller_entry_t *entry = malloc_thing(controller_entry_t); + + entry->constructor = constructor; + entry->param = param; + this->controllers->insert_last(this->controllers, entry); +} + +/** + * Implementation of dispatcher_t.add_filter. + */ +static void add_filter(private_dispatcher_t *this, + filter_constructor_t constructor, void *param) +{ + filter_entry_t *entry = malloc_thing(filter_entry_t); + + entry->constructor = constructor; + entry->param = param; + this->filters->insert_last(this->filters, entry); +} + +/** + * Actual dispatching code + */ +static void dispatch(private_dispatcher_t *this) +{ + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); + + while (TRUE) + { + request_t *request; + session_entry_t *current, *found = NULL; + iterator_t *iterator; + time_t now; + char *sid; + + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + request = request_create(this->fd, this->debug); + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); + + if (request == NULL) + { + continue; + } + sid = request->get_cookie(request, "SID"); + now = time(NULL); + + /* find session */ + pthread_mutex_lock(&this->mutex); + iterator = this->sessions->create_iterator(this->sessions, TRUE); + while (iterator->iterate(iterator, (void**)¤t)) + { + /* check all sessions for timeout or close flag + * TODO: use a seperate cleanup thread */ + if (!current->in_use && + (current->used < now - this->timeout || current->closed)) + { + iterator->remove(iterator); + session_entry_destroy(current); + continue; + } + /* find by session ID. Prevent session hijacking by host check */ + if (!found && sid && + streq(current->session->get_sid(current->session), sid) && + streq(current->host, request->get_host(request))) + { + found = current; + } + } + iterator->destroy(iterator); + + if (found) + { + /* wait until session is unused */ + while (found->in_use) + { + pthread_cond_wait(&found->cond, &this->mutex); + } + } + else + { /* create a new session if not found */ + found = session_entry_create(this, request->get_host(request)); + this->sessions->insert_first(this->sessions, found); + } + found->in_use = TRUE; + pthread_mutex_unlock(&this->mutex); + + /* start processing */ + found->session->process(found->session, request); + found->used = time(NULL); + + /* release session */ + pthread_mutex_lock(&this->mutex); + found->in_use = FALSE; + found->closed = request->session_closed(request); + pthread_cond_signal(&found->cond); + pthread_mutex_unlock(&this->mutex); + + /* cleanup */ + request->destroy(request); + } +} + +/** + * Implementation of dispatcher_t.run. + */ +static void run(private_dispatcher_t *this, int threads) +{ + this->thread_count = threads; + this->threads = malloc(sizeof(pthread_t) * threads); + while (threads) + { + if (pthread_create(&this->threads[threads - 1], + NULL, (void*)dispatch, this) == 0) + { + threads--; + } + } +} + +/** + * Implementation of dispatcher_t.waitsignal. + */ +static void waitsignal(private_dispatcher_t *this) +{ + sigset_t set; + int sig; + + sigemptyset(&set); + sigaddset(&set, SIGINT); + sigaddset(&set, SIGTERM); + sigaddset(&set, SIGHUP); + sigprocmask(SIG_BLOCK, &set, NULL); + sigwait(&set, &sig); +} + +/** + * Implementation of dispatcher_t.destroy + */ +static void destroy(private_dispatcher_t *this) +{ + FCGX_ShutdownPending(); + while (this->thread_count--) + { + pthread_cancel(this->threads[this->thread_count]); + pthread_join(this->threads[this->thread_count], NULL); + } + this->sessions->destroy_function(this->sessions, (void*)session_entry_destroy); + this->controllers->destroy_function(this->controllers, free); + this->filters->destroy_function(this->filters, free); + free(this); +} + +/* + * see header file + */ +dispatcher_t *dispatcher_create(char *socket, bool debug, int timeout, + context_constructor_t constructor, void *param) +{ + private_dispatcher_t *this = malloc_thing(private_dispatcher_t); + + this->public.add_controller = (void(*)(dispatcher_t*, controller_constructor_t, void*))add_controller; + this->public.add_filter = (void(*)(dispatcher_t*,filter_constructor_t constructor, void *param))add_filter; + this->public.run = (void(*)(dispatcher_t*, int threads))run; + this->public.waitsignal = (void(*)(dispatcher_t*))waitsignal; + this->public.destroy = (void(*)(dispatcher_t*))destroy; + + this->sessions = linked_list_create(); + this->controllers = linked_list_create(); + this->filters = linked_list_create(); + this->context_constructor = constructor; + pthread_mutex_init(&this->mutex, NULL); + this->param = param; + this->fd = 0; + this->timeout = timeout; + this->debug = debug; + + FCGX_Init(); + + if (socket) + { + unlink(socket); + this->fd = FCGX_OpenSocket(socket, 10); + } + return &this->public; +} + diff --git a/src/libfast/dispatcher.h b/src/libfast/dispatcher.h new file mode 100644 index 000000000..b792fb647 --- /dev/null +++ b/src/libfast/dispatcher.h @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +/** + * @defgroup libfast libfast + * @{ + * FastCGI Application Server w/ templates. + * + * Libfast is a framework to write web applications in an MVC fashion. It uses + * the ClearSilver template engine and communicates through FastCGI with + * the webserver. It is multithreaded and really fast. + * + * The application has a global context and a session context. The global + * context is accessed from all sessions simultaneously and therefore + * needs to be threadsave. Often a database wrapper is the global context. + * The session context is instanciated per session. Sessions are managed + * automatically through session cookies. The session context is kept alive + * until the session times out. It must implement the context_t interface and + * a #context_constructor_t is needed to create instances. To each session, + * a set of controllers gets instanciated. The controller instances are per + * session, so you can hold private data for each user. + * Controllers need to implement the controller_t interface and need a + * #controller_constructor_t function to create instances. + * + * A small example shows how to set up libfast: + * @code + dispatcher_t *dispatcher; + your_global_context_implementation_t *global; + + global = initialize_your_global_context(); + + dispatcher = dispatcher_create(NULL, FALSE, 180, + (context_constructor_t)your_session_context_create, global); + dispatcher->add_controller(dispatcher, your_controller1_create, param1); + dispatcher->add_controller(dispatcher, your_controller2_create, param2); + + dispatcher->run(dispatcher, 20); + + dispatcher->waitsignal(dispatcher); + + dispatcher->destroy(dispatcher); + global->destroy(); + @endcode + * @} + * + * @defgroup dispatcher dispatcher + * @{ @ingroup libfast + */ + +#ifndef DISPATCHER_H_ +#define DISPATCHER_H_ + +#include "controller.h" +#include "filter.h" + +typedef struct dispatcher_t dispatcher_t; + +/** + * Dispatcher, accepts connections using multiple threads. + * + * The dispatcher creates a session for each client (using SID cookies). In + * each session, a session context is created using the context constructor. + * Each controller is instanciated in the session using the controller + * constructor added with add_controller. + */ +struct dispatcher_t { + + /** + * Register a controller to the dispatcher. + * + * The first controller added serves as default controller. Client's + * get redirected to it if no other controller matches. + * + * @param constructor constructor function to the conntroller + * @param param param to pass to constructor + */ + void (*add_controller)(dispatcher_t *this, + controller_constructor_t constructor, void *param); + + /** + * @brief Add a filter to the dispatcher. + * + * @param constructor constructor to create filter in session + * @param param param to pass to constructor + */ + void (*add_filter)(dispatcher_t *this, + filter_constructor_t constructor, void *param); + + /** + * Start with dispatching. + * + * Instanciate a constant thread pool and start dispatching requests. + * + * @param threads number of dispatching threads + */ + void (*run)(dispatcher_t *this, int threads); + + /** + * Wait for a relevant signal action. + * + */ + void (*waitsignal)(dispatcher_t *this); + + /** + * Destroy the dispatcher_t. + */ + void (*destroy) (dispatcher_t *this); +}; + +/** + * Create a dispatcher. + * + * The context constructor is invoked to create a session context for + * each session. + * + * @param socket FastCGI socket path, NULL for dynamic + * @param debug no stripping, no compression, timing information + * @param timeout session timeout + * @param constructor construction function for session context + * @param param parameter to supply to context constructor + */ +dispatcher_t *dispatcher_create(char *socket, bool debug, int timeout, + context_constructor_t constructor, void *param); + +#endif /* DISPATCHER_H_ @} */ diff --git a/src/libfast/filter.h b/src/libfast/filter.h new file mode 100644 index 000000000..d2fb8dd5f --- /dev/null +++ b/src/libfast/filter.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +/* + * @defgroup filter filter + * @{ @ingroup libfast + */ + +#ifndef FILTER_H_ +#define FILTER_H_ + +#include "request.h" +#include "context.h" +#include "controller.h" + +typedef struct filter_t filter_t; + +/** + * Constructor function for a filter + * + * @param context session specific context + * @param param user supplied param + */ +typedef filter_t *(*filter_constructor_t)(context_t* context, void *param); + +/** + * Filter interface, to be implemented by users filters. + */ +struct filter_t { + + /** + * Called before the controller handles the request + * + * @param request HTTP request + * @param controller selected controller, before execution + * @return TRUE to continue request handling + */ + bool (*run)(filter_t *this, request_t *request, controller_t *controller); + + /** + * Destroy the filter instance. + */ + void (*destroy) (filter_t *this); +}; + +#endif /* FILTER_H_ @} */ diff --git a/src/libfast/request.c b/src/libfast/request.c new file mode 100644 index 000000000..ef9f66122 --- /dev/null +++ b/src/libfast/request.c @@ -0,0 +1,447 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#define _GNU_SOURCE + +#include "request.h" + +#include +#include +#include +#include +#include +#include + +typedef struct private_request_t private_request_t; + +/** + * private data of the task manager + */ +struct private_request_t { + + /** + * public functions + */ + request_t public; + + /** + * FastCGI request object + */ + FCGX_Request req; + + /** + * length of the req.envp array + */ + int req_env_len; + + /** + * ClearSilver CGI Kit context + */ + CGI *cgi; + + /** + * ClearSilver HDF dataset for this request + */ + HDF *hdf; + + /** + * close the session? + */ + bool closed; + + /** + * reference count + */ + refcount_t ref; +}; + +/** + * key to a the threads "this" request, used for ClearSilver cgiwrap callbacks. + * ClearSilver cgiwrap is not threadsave, so we use a private + * context for each thread. + */ +static pthread_key_t this_key; + +/** + * control variable for pthread_once + */ +pthread_once_t once = PTHREAD_ONCE_INIT; + +/** + * fcgiwrap read callback + */ +static int read_cb(void *null, char *buf, int size) +{ + private_request_t *this = (private_request_t*)pthread_getspecific(this_key); + + return FCGX_GetStr(buf, size, this->req.in); +} + +/** + * fcgiwrap writef callback + */ +static int writef_cb(void *null, const char *format, va_list args) +{ + private_request_t *this = (private_request_t*)pthread_getspecific(this_key); + + FCGX_VFPrintF(this->req.out, format, args); + return 0; +} +/** + * fcgiwrap write callback + */ +static int write_cb(void *null, const char *buf, int size) +{ + private_request_t *this = (private_request_t*)pthread_getspecific(this_key); + + return FCGX_PutStr(buf, size, this->req.out); +} + +/** + * fcgiwrap getenv callback + */ +static char *getenv_cb(void *null, const char *key) +{ + char *value; + private_request_t *this = (private_request_t*)pthread_getspecific(this_key); + + value = FCGX_GetParam(key, this->req.envp); + return value ? strdup(value) : NULL; +} + +/** + * fcgiwrap getenv callback + */ +static int putenv_cb(void *null, const char *key, const char *value) +{ + /* not supported */ + return 1; +} + +/** + * fcgiwrap iterenv callback + */ +static int iterenv_cb(void *null, int num, char **key, char **value) +{ + *key = NULL; + *value = NULL; + private_request_t *this = (private_request_t*)pthread_getspecific(this_key); + if (num < this->req_env_len) + { + char *eq; + + eq = strchr(this->req.envp[num], '='); + if (eq) + { + *key = strndup(this->req.envp[num], eq - this->req.envp[num]); + *value = strdup(eq + 1); + } + if (*key == NULL || *value == NULL) + { + free(*key); + free(*value); + return 1; + } + } + return 0; +} + +/** + * Implementation of request_t.get_cookie. + */ +static char* get_cookie(private_request_t *this, char *name) +{ + return hdf_get_valuef(this->hdf, "Cookie.%s", name); +} + +/** + * Implementation of request_t.get_path. + */ +static char* get_path(private_request_t *this) +{ + char * path = FCGX_GetParam("PATH_INFO", this->req.envp); + return path ? path : ""; +} + +/** + * Implementation of request_t.get_host. + */ +static char* get_host(private_request_t *this) +{ + char *addr = FCGX_GetParam("REMOTE_ADDR", this->req.envp); + return addr ? addr : ""; +} + +/** + * Implementation of request_t.get_user_agent. + */ +static char* get_user_agent(private_request_t *this) +{ + char *agent = FCGX_GetParam("HTTP_USER_AGENT", this->req.envp); + return agent ? agent : ""; +} + +/** + * Implementation of request_t.get_post_data. + */ +static char* get_query_data(private_request_t *this, char *name) +{ + return hdf_get_valuef(this->hdf, "Query.%s", name); +} + +/** + * Implementation of request_t.add_cookie. + */ +static void add_cookie(private_request_t *this, char *name, char *value) +{ + pthread_setspecific(this_key, this); + cgi_cookie_set (this->cgi, name, value, + FCGX_GetParam("SCRIPT_NAME", this->req.envp), + NULL, NULL, 0, 0); +} + +/** + * Implementation of request_t.redirect. + */ +static void redirect(private_request_t *this, char *fmt, ...) +{ + va_list args; + + FCGX_FPrintF(this->req.out, "Status: 303 See Other\n"); + FCGX_FPrintF(this->req.out, "Location: %s%s", + FCGX_GetParam("SCRIPT_NAME", this->req.envp), + *fmt == '/' ? "" : "/"); + va_start(args, fmt); + FCGX_VFPrintF(this->req.out, fmt, args); + va_end(args); + FCGX_FPrintF(this->req.out, "\n\n"); +} + +/** + * Implementation of request_t.to_referer. + */ +static void to_referer(private_request_t *this) +{ + FCGX_FPrintF(this->req.out, "Status: 303 See Other\n"); + FCGX_FPrintF(this->req.out, "Location: %s\n\n", + FCGX_GetParam("HTTP_REFERER", this->req.envp)); +} + +/** + * Implementation of request_t.get_base. + */ +static char* get_base(private_request_t *this) +{ + return FCGX_GetParam("SCRIPT_NAME", this->req.envp); +} + +/** + * Implementation of request_t.session_closed. + */ +static bool session_closed(private_request_t *this) +{ + return this->closed; +} + +/** + * Implementation of request_t.close_session. + */ +static void close_session(private_request_t *this) +{ + this->closed = TRUE; +} + +/** + * Implementation of request_t.serve. + */ +static void serve(private_request_t *this, char *headers, chunk_t chunk) +{ + FCGX_FPrintF(this->req.out, "%s\n\n", headers); + + FCGX_PutStr(chunk.ptr, chunk.len, this->req.out); +} + +/** + * Implementation of request_t.render. + */ +static void render(private_request_t *this, char *template) +{ + NEOERR* err; + + pthread_setspecific(this_key, this); + err = cgi_display(this->cgi, template); + if (err) + { + cgi_neo_error(this->cgi, err); + nerr_log_error(err); + } + return; +} + +/** + * Implementation of request_t.streamf. + */ +static int streamf(private_request_t *this, char *format, ...) +{ + va_list args; + int written; + + va_start(args, format); + written = FCGX_VFPrintF(this->req.out, format, args); + va_end(args); + if (written >= 0 && + FCGX_FFlush(this->req.out) == -1) + { + return -1; + } + return written; +} + +/** + * Implementation of request_t.set. + */ +static void set(private_request_t *this, char *key, char *value) +{ + hdf_set_value(this->hdf, key, value); +} + +/** + * Implementation of request_t.setf. + */ +static void setf(private_request_t *this, char *format, ...) +{ + va_list args; + + va_start(args, format); + hdf_set_valuevf(this->hdf, format, args); + va_end(args); +} + +/** + * Implementation of request_t.get_ref. + */ +static request_t* get_ref(private_request_t *this) +{ + ref_get(&this->ref); + return &this->public; +} + +/** + * Implementation of request_t.destroy + */ +static void destroy(private_request_t *this) +{ + if (ref_put(&this->ref)) + { + pthread_setspecific(this_key, this); + cgi_destroy(&this->cgi); + FCGX_Finish_r(&this->req); + free(this); + } +} + +/** + * This initialization method is guaranteed to run only once + * for all threads. + */ +static void init(void) +{ + cgiwrap_init_emu(NULL, read_cb, writef_cb, write_cb, + getenv_cb, putenv_cb, iterenv_cb); + pthread_key_create(&this_key, NULL); +} + +/* + * see header file + */ +request_t *request_create(int fd, bool debug) +{ + NEOERR* err; + private_request_t *this = malloc_thing(private_request_t); + bool failed = FALSE; + + pthread_cleanup_push(free, this); + if (FCGX_InitRequest(&this->req, fd, 0) != 0 || + FCGX_Accept_r(&this->req) != 0) + { + failed = TRUE; + } + pthread_cleanup_pop(failed); + if (failed) + { + return NULL; + } + + this->public.get_path = (char*(*)(request_t*))get_path; + this->public.get_base = (char*(*)(request_t*))get_base; + this->public.get_host = (char*(*)(request_t*))get_host; + this->public.get_user_agent = (char*(*)(request_t*))get_user_agent; + this->public.add_cookie = (void(*)(request_t*, char *name, char *value))add_cookie; + this->public.get_cookie = (char*(*)(request_t*,char*))get_cookie; + this->public.get_query_data = (char*(*)(request_t*, char *name))get_query_data; + this->public.session_closed = (bool(*)(request_t*))session_closed; + this->public.close_session = (void(*)(request_t*))close_session; + this->public.redirect = (void(*)(request_t*, char *fmt,...))redirect; + this->public.to_referer = (void(*)(request_t*))to_referer; + this->public.render = (void(*)(request_t*,char*))render; + this->public.streamf = (int(*)(request_t*, char *format, ...))streamf; + this->public.serve = (void(*)(request_t*,char*,chunk_t))serve; + this->public.set = (void(*)(request_t*, char *, char*))set; + this->public.setf = (void(*)(request_t*, char *format, ...))setf; + this->public.get_ref = (request_t*(*)(request_t*))get_ref; + this->public.destroy = (void(*)(request_t*))destroy; + + pthread_once(&once, init); + pthread_setspecific(this_key, this); + + this->ref = 1; + this->closed = FALSE; + this->req_env_len = 0; + while (this->req.envp[this->req_env_len] != NULL) + { + this->req_env_len++; + } + + err = hdf_init(&this->hdf); + if (!err) + { + hdf_set_value(this->hdf, "base", get_base(this)); + hdf_set_value(this->hdf, "Config.NoCache", "true"); + if (!debug) + { + hdf_set_value(this->hdf, "Config.TimeFooter", "0"); + hdf_set_value(this->hdf, "Config.CompressionEnabled", "1"); + hdf_set_value(this->hdf, "Config.WhiteSpaceStrip", "2"); + } + + err = cgi_init(&this->cgi, this->hdf); + if (!err) + { + err = cgi_parse(this->cgi); + if (!err) + { + return &this->public; + } + cgi_destroy(&this->cgi); + } + } + nerr_log_error(err); + FCGX_Finish_r(&this->req); + free(this); + return NULL; +} + diff --git a/src/libfast/request.h b/src/libfast/request.h new file mode 100644 index 000000000..d73477a5a --- /dev/null +++ b/src/libfast/request.h @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +/** + * @defgroup request request + * @{ @ingroup libfast + */ + +#ifndef REQUEST_H_ +#define REQUEST_H_ + +#include +#include + +typedef struct request_t request_t; + +/** + * A HTTP request, encapsulates FCGX_Request. + * + * The response is also handled through the request object. + */ +struct request_t { + + /** + * Add a cookie to the reply (Set-Cookie header). + * + * @param name name of the cookie to set + * @param value value of the cookie + */ + void (*add_cookie)(request_t *this, char *name, char *value); + + /** + * Get a cookie the client sent in the request. + * + * @param name name of the cookie + * @return cookie value, NULL if no such cookie found + */ + char* (*get_cookie)(request_t *this, char *name); + + /** + * Get the request path relative to the application. + * + * @return path + */ + char* (*get_path)(request_t *this); + + /** + * Get the base path of the application. + * + * @return base path + */ + char* (*get_base)(request_t *this); + + /** + * Get the remote host address of this request. + * + * @return host address as string + */ + char* (*get_host)(request_t *this); + + /** + * Get the user agent string. + * + * @return user agent string + */ + char* (*get_user_agent)(request_t *this); + + /** + * Get a post/get variable included in the request. + * + * @param name name of the POST/GET variable + * @return value, NULL if not found + */ + char* (*get_query_data)(request_t *this, char *name); + + /** + * Close the session and it's context after handling. + */ + void (*close_session)(request_t *this); + + /** + * Has the session been closed by close_session()? + * + * @return TRUE if session has been closed + */ + bool (*session_closed)(request_t *this); + + /** + * Redirect the client to another location. + * + * @param fmt location format string + * @param ... variable argument for fmt + */ + void (*redirect)(request_t *this, char *fmt, ...); + + /** + * Redirect the client to the referer. + */ + void (*to_referer)(request_t *this); + + /** + * Set a template value. + * + * @param key key to set + * @param value value to set key to + */ + void (*set)(request_t *this, char *key, char *value); + + /** + * Set a template value using format strings. + * + * Format string is in the form "key=value", where printf like format + * substitution occurs over the whole string. + * + * @param format printf like format string + * @param ... variable argument list + */ + void (*setf)(request_t *this, char *format, ...); + + /** + * Render a template. + * + * The render() function additionally sets a HDF variable "base" + * which points to the root of the web application and allows to point to + * other targets without to worry about path location. + * + * @param template clearsilver template file location + */ + void (*render)(request_t *this, char *template); + + /** + * Stream a format string to the client. + * + * Stream is not closed and may be called multiple times to allow + * server-push functionality. + * + * @param format printf like format string + * @param ... argmuent list to format string + * @return number of streamed bytes, < 0 if stream closed + */ + int (*streamf)(request_t *this, char *format, ...); + + /** + * Serve a request with headers and a body. + * + * @param headers HTTP headers, \n separated + * @param chunk body to write to output + */ + void (*serve)(request_t *this, char *headers, chunk_t chunk); + + /** + * Increase the reference count to the stream. + * + * @return this with increased refcount + */ + request_t* (*get_ref)(request_t *this); + + /** + * Destroy the request_t. + */ + void (*destroy) (request_t *this); +}; + +/** + * Create a request from the fastcgi struct. + * + * @param fd file descripter opened with FCGX_OpenSocket + * @param debug no stripping, no compression, timing information + */ +request_t *request_create(int fd, bool debug); + +#endif /* REQUEST_H_ @} */ diff --git a/src/libfast/session.c b/src/libfast/session.c new file mode 100644 index 000000000..519187efa --- /dev/null +++ b/src/libfast/session.c @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#define _GNU_SOURCE + +#include "session.h" + +#include +#include +#include + +#include +#include + +typedef struct private_session_t private_session_t; + +/** + * private data of the task manager + */ +struct private_session_t { + + /** + * public functions + */ + session_t public; + + /** + * session ID + */ + char *sid; + + /** + * list of controller instances controller_t + */ + linked_list_t *controllers; + + /** + * list of filter instances filter_t + */ + linked_list_t *filters; + + /** + * user defined session context + */ + context_t *context; +}; + +/** + * Implementation of session_t.add_controller. + */ +static void add_controller(private_session_t *this, controller_t *controller) +{ + this->controllers->insert_last(this->controllers, controller); +} + +/** + * Implementation of session_t.add_filter. + */ +static void add_filter(private_session_t *this, filter_t *filter) +{ + this->filters->insert_last(this->filters, filter); +} + +/** + * Create a session ID and a cookie + */ +static void create_sid(private_session_t *this, request_t *request) +{ + char buf[16]; + chunk_t chunk = chunk_from_buf(buf); + randomizer_t *randomizer = randomizer_create(); + + randomizer->get_pseudo_random_bytes(randomizer, sizeof(buf), buf); + this->sid = chunk_to_hex(chunk, FALSE); + request->add_cookie(request, "SID", this->sid); + randomizer->destroy(randomizer); +} + +/** + * run all registered filters + */ +static bool run_filter(private_session_t *this, request_t *request, + controller_t *controller) +{ + iterator_t *iterator; + filter_t *filter; + + iterator = this->filters->create_iterator(this->filters, TRUE); + while (iterator->iterate(iterator, (void**)&filter)) + { + if (!filter->run(filter, request, controller)) + { + iterator->destroy(iterator); + return FALSE; + } + } + iterator->destroy(iterator); + return TRUE; +} + +/** + * Implementation of session_t.process. + */ +static void process(private_session_t *this, request_t *request) +{ + char *pos, *start, *param[6] = {NULL, NULL, NULL, NULL, NULL, NULL}; + iterator_t *iterator; + bool handled = FALSE; + controller_t *current; + int i = 0; + + if (this->sid == NULL) + { + create_sid(this, request); + } + + start = request->get_path(request); + if (start) + { + if (*start == '/') start++; + while ((pos = strchr(start, '/')) != NULL && i < 5) + { + param[i++] = strndup(start, pos - start); + start = pos + 1; + } + param[i] = strdup(start); + iterator = this->controllers->create_iterator(this->controllers, TRUE); + while (iterator->iterate(iterator, (void**)¤t)) + { + if (streq(current->get_name(current), param[0])) + { + if (run_filter(this, request, current)) + { + current->handle(current, request, param[1], param[2], + param[3], param[4], param[5]); + handled = TRUE; + } + break; + } + } + iterator->destroy(iterator); + for (i = 0; i < 6; i++) + { + free(param[i]); + } + } + if (!handled) + { + if (this->controllers->get_first(this->controllers, + (void**)¤t) == SUCCESS) + { + request->redirect(request, current->get_name(current)); + } + } +} + +/** + * Implementation of session_t.get_sid. + */ +static char* get_sid(private_session_t *this) +{ + return this->sid; +} + +/** + * Implementation of session_t.destroy + */ +static void destroy(private_session_t *this) +{ + this->controllers->destroy_offset(this->controllers, offsetof(controller_t, destroy)); + this->filters->destroy_offset(this->filters, offsetof(filter_t, destroy)); + if (this->context) this->context->destroy(this->context); + free(this->sid); + free(this); +} + +/* + * see header file + */ +session_t *session_create(context_t *context) +{ + private_session_t *this = malloc_thing(private_session_t); + + this->public.add_controller = (void(*)(session_t*, controller_t*))add_controller; + this->public.add_filter = (void(*)(session_t*, filter_t*))add_filter; + this->public.process = (void(*)(session_t*,request_t*))process; + this->public.get_sid = (char*(*)(session_t*))get_sid; + this->public.destroy = (void(*)(session_t*))destroy; + + this->sid = NULL; + this->controllers = linked_list_create(); + this->filters = linked_list_create(); + this->context = context; + + return &this->public; +} + diff --git a/src/libfast/session.h b/src/libfast/session.h new file mode 100644 index 000000000..98d7ee3ce --- /dev/null +++ b/src/libfast/session.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +/** + * @defgroup session session + * @{ @ingroup libfast + */ + +#ifndef SESSION_H_ +#define SESSION_H_ + +#include "request.h" +#include "controller.h" +#include "filter.h" + +typedef struct session_t session_t; + +/** + * Session handling class, instanciated for each user session. + */ +struct session_t { + + /** + * Get the session ID of the session. + * + * @return session ID + */ + char* (*get_sid)(session_t *this); + + /** + * Add a controller instance to the session. + * + * @param controller controller to add + */ + void (*add_controller)(session_t *this, controller_t *controller); + + /** + * @brief Add a filter instance to the session. + * + * @param filter filter to add + */ + void (*add_filter)(session_t *this, filter_t *filter); + + /** + * Process a request in this session. + * + * @param request request to process + */ + void (*process)(session_t *this, request_t *request); + + /** + * Destroy the session_t. + * + * @param this calling object + */ + void (*destroy) (session_t *this); +}; + +/** + * Create a session new session. + * + * @param context user defined session context instance + */ +session_t *session_create(context_t *context); + +#endif /* SESSION_H_ @} */ diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am index fc642c615..b858e2585 100644 --- a/src/libstrongswan/Makefile.am +++ b/src/libstrongswan/Makefile.am @@ -9,43 +9,37 @@ else endif libstrongswan_la_SOURCES += \ -credential_store.h \ library.c library.h \ chunk.c chunk.h \ debug.c debug.h \ enum.c enum.h \ +settings.h settings.c \ printf_hook.c printf_hook.h \ asn1/asn1.c asn1/asn1.h \ asn1/oid.c asn1/oid.h \ asn1/pem.c asn1/pem.h \ asn1/ttodata.c asn1/ttodata.h \ -crypto/ac.c crypto/ac.h \ -crypto/ca.c crypto/ca.h \ -crypto/certinfo.c crypto/certinfo.h \ -crypto/crl.c crypto/crl.h \ crypto/crypters/crypter.c crypto/crypters/crypter.h \ -crypto/crypters/aes_cbc_crypter.c crypto/crypters/aes_cbc_crypter.h \ -crypto/crypters/des_crypter.c crypto/crypters/des_crypter.h \ -crypto/diffie_hellman.c crypto/diffie_hellman.h \ crypto/hashers/hasher.h crypto/hashers/hasher.c \ -crypto/hashers/sha1_hasher.c crypto/hashers/sha1_hasher.h \ -crypto/hashers/sha2_hasher.c crypto/hashers/sha2_hasher.h \ -crypto/hashers/md5_hasher.c crypto/hashers/md5_hasher.h \ -crypto/hmac.c crypto/hmac.h \ -crypto/ietf_attr_list.c crypto/ietf_attr_list.h \ -crypto/ocsp.c crypto/ocsp.h \ -crypto/pkcs7.c crypto/pkcs7.h \ crypto/pkcs9.c crypto/pkcs9.h \ -crypto/prfs/fips_prf.c crypto/prfs/fips_prf.h \ -crypto/prfs/hmac_prf.c crypto/prfs/hmac_prf.h \ crypto/prfs/prf.c crypto/prfs/prf.h \ crypto/prf_plus.h crypto/prf_plus.c \ -crypto/rsa/rsa_private_key.c crypto/rsa/rsa_private_key.h \ -crypto/rsa/rsa_public_key.h crypto/rsa/rsa_public_key.c \ -crypto/signers/hmac_signer.c crypto/signers/hmac_signer.h \ crypto/signers/signer.c crypto/signers/signer.h \ -crypto/x509.c crypto/x509.h \ -utils/fetcher.c utils/fetcher.h \ +crypto/diffie_hellman.c crypto/diffie_hellman.h \ +crypto/crypto_factory.c crypto/crypto_factory.h \ +credentials/credential_factory.c credentials/credential_factory.h \ +credentials/builder.c credentials/builder.h \ +credentials/keys/private_key.c credentials/keys/private_key.h \ +credentials/keys/public_key.c credentials/keys/public_key.h \ +credentials/keys/shared_key.c credentials/keys/shared_key.h \ +credentials/certificates/certificate.c credentials/certificates/certificate.h \ +credentials/certificates/x509.h credentials/certificates/x509.c \ +credentials/certificates/crl.h credentials/certificates/crl.c \ +credentials/certificates/ocsp_request.h credentials/certificates/ocsp_request.c \ +credentials/certificates/ocsp_response.h credentials/certificates/ocsp_response.c \ +fetcher/fetcher.h fetcher/fetcher_manager.h fetcher/fetcher_manager.c \ +database/database.h database/database_factory.h database/database_factory.c \ +utils.h utils.c \ utils/host.c utils/host.h \ utils/identification.c utils/identification.h \ utils/iterator.h \ @@ -54,28 +48,22 @@ utils/lexparser.c utils/lexparser.h \ utils/linked_list.c utils/linked_list.h \ utils/enumerator.c utils/enumerator.h \ utils/optionsfrom.c utils/optionsfrom.h \ -utils/randomizer.c utils/randomizer.h +utils/randomizer.c utils/randomizer.h \ +utils/mutex.c utils/mutex.h \ +plugins/plugin_loader.c plugins/plugin_loader.h plugins/plugin.h if USE_INTEGRITY_TEST libstrongswan_la_SOURCES += \ fips/fips_canister_end.c endif -libstrongswan_la_LIBADD = -lgmp -lpthread +libstrongswan_la_LIBADD = -lpthread -ldl INCLUDES = -I$(top_srcdir)/src/libstrongswan +AM_CFLAGS = if USE_LEAK_DETECTIVE - libstrongswan_la_LIBADD += -ldl - AM_CFLAGS = -DLEAK_DETECTIVE -endif - -if USE_LIBCURL - libstrongswan_la_LIBADD += -lcurl -endif - -if USE_LIBLDAP - libstrongswan_la_LIBADD += -lldap -llber + AM_CFLAGS += -DLEAK_DETECTIVE endif EXTRA_DIST = asn1/oid.txt asn1/oid.pl @@ -88,6 +76,65 @@ asn1/oid.c : asn1/oid.txt asn1/oid.pl asn1/oid.h : asn1/oid.txt asn1/oid.pl cd asn1 && $(PERL) oid.pl + +# build plugins with their own Makefile +####################################### + +SUBDIRS = + +if USE_AES + SUBDIRS += plugins/aes +endif + +if USE_DES + SUBDIRS += plugins/des +endif + +if USE_MD5 + SUBDIRS += plugins/md5 +endif + +if USE_SHA1 + SUBDIRS += plugins/sha1 +endif + +if USE_SHA2 + SUBDIRS += plugins/sha2 +endif + +if USE_FIPS_PRF + SUBDIRS += plugins/fips_prf +endif + +if USE_GMP + SUBDIRS += plugins/gmp +endif + +if USE_HMAC + SUBDIRS += plugins/hmac +endif + +if USE_X509 + SUBDIRS += plugins/x509 +endif + +if USE_CURL + SUBDIRS += plugins/curl +endif + +if USE_LDAP + SUBDIRS += plugins/ldap +endif + +if USE_MYSQL + SUBDIRS += plugins/mysql +endif + +if USE_SQLITE + SUBDIRS += plugins/sqlite +endif + + if USE_INTEGRITY_TEST # build fips_signer which in turn builds fips_signature.h ######################################################### diff --git a/src/libstrongswan/asn1/asn1.c b/src/libstrongswan/asn1/asn1.c index b53f5a766..cd204c698 100644 --- a/src/libstrongswan/asn1/asn1.c +++ b/src/libstrongswan/asn1/asn1.c @@ -1,14 +1,6 @@ -/** - * @file asn1.c - * - * @brief Simple ASN.1 parser - * - */ - /* * Copyright (C) 2006 Martin Will * Copyright (C) 2000-2008 Andreas Steffen - * * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -21,7 +13,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id$ + * $Id$ */ #include @@ -833,20 +825,6 @@ chunk_t asn1_wrap(asn1_t type, const char *mode, ...) return construct; } -/** - * convert a MP integer into a DER coded ASN.1 object - */ -chunk_t asn1_integer_from_mpz(const mpz_t value) -{ - size_t bits = mpz_sizeinbase(value, 2); /* size in bits */ - chunk_t n; - - n.len = 1 + bits / 8; /* size in bytes */ - n.ptr = mpz_export(NULL, NULL, 1, n.len, 1, 0, value); - - return asn1_wrap(ASN1_INTEGER, "m", n); -} - /** * ASN.1 definition of time */ diff --git a/src/libstrongswan/asn1/asn1.h b/src/libstrongswan/asn1/asn1.h index 4eaf1a78d..432214766 100644 --- a/src/libstrongswan/asn1/asn1.h +++ b/src/libstrongswan/asn1/asn1.h @@ -1,10 +1,3 @@ -/** - * @file asn1.h - * - * @brief Simple ASN.1 parser - * - */ - /* * Copyright (C) 2006 Martin Will * Copyright (C) 2000-2008 Andreas Steffen @@ -21,11 +14,16 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id$ + * $Id$ + */ + +/** + * @defgroup asn1 asn1 + * @{ @ingroup asn1 */ -#ifndef _ASN1_H -#define _ASN1_H +#ifndef ASN1_H_ +#define ASN1_H_ #include #include @@ -35,9 +33,7 @@ /** - * @brief Definition of some primitive ASN1 types - * - * @ingroup asn1 + * Definition of some primitive ASN1 types */ typedef enum { ASN1_EOC = 0x00, @@ -87,7 +83,6 @@ typedef enum { } asn1_t; /* Definition of ASN1 flags */ - #define ASN1_NONE 0x00 #define ASN1_DEF 0x01 #define ASN1_OPT 0x02 @@ -100,7 +95,6 @@ typedef enum { #define ASN1_INVALID_LENGTH 0xffffffff /* definition of an ASN.1 object */ - typedef struct { u_int level; const u_char *name; @@ -141,9 +135,8 @@ extern bool is_asn1(chunk_t blob); extern void code_asn1_length(size_t length, chunk_t *code); extern u_char* build_asn1_object(chunk_t *object, asn1_t type, size_t datalen); -extern chunk_t asn1_integer_from_mpz(const mpz_t value); extern chunk_t asn1_simple_object(asn1_t tag, chunk_t content); extern chunk_t asn1_bitstring(const char *mode, chunk_t content); extern chunk_t asn1_wrap(asn1_t type, const char *mode, ...); -#endif /* _ASN1_H */ +#endif /* ASN1_H_ @}*/ diff --git a/src/libstrongswan/asn1/pem.c b/src/libstrongswan/asn1/pem.c index 4ab70dbdc..f545d7a07 100755 --- a/src/libstrongswan/asn1/pem.c +++ b/src/libstrongswan/asn1/pem.c @@ -11,7 +11,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id$ + * $Id$ */ #include @@ -95,10 +95,16 @@ static err_t pem_decrypt(chunk_t *blob, encryption_algorithm_t alg, size_t key_s u_int8_t padding, *last_padding_pos, *first_padding_pos; if (passphrase == NULL || passphrase->len == 0) + { return "missing passphrase"; + } /* build key from passphrase and IV */ - hasher = hasher_create(HASH_MD5); + hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5); + if (hasher == NULL) + { + return "MD5 hasher not supported"; + } hash.len = hasher->get_hash_size(hasher); hash.ptr = alloca(hash.len); hasher->get_hash(hasher, *passphrase, NULL); @@ -115,7 +121,7 @@ static err_t pem_decrypt(chunk_t *blob, encryption_algorithm_t alg, size_t key_s hasher->destroy(hasher); /* decrypt blob */ - crypter = crypter_create(alg, key_size); + crypter = lib->crypto->create_crypter(lib->crypto, alg, key_size); crypter->set_key(crypter, key); if (crypter->decrypt(crypter, *blob, *iv, &decrypted) != SUCCESS) { @@ -310,8 +316,8 @@ err_t pem_to_bin(chunk_t *blob, chunk_t *passphrase, bool *pgp) /* load a coded key or certificate file with autodetection * of binary DER or base64 PEM ASN.1 formats and armored PGP format */ -bool pem_asn1_load_file(const char *filename, chunk_t *passphrase, - const char *type, chunk_t *blob, bool *pgp) +bool pem_asn1_load_file(char *filename, chunk_t *passphrase, + chunk_t *blob, bool *pgp) { err_t ugh = NULL; @@ -326,7 +332,7 @@ bool pem_asn1_load_file(const char *filename, chunk_t *passphrase, blob->ptr = malloc(blob->len); bytes = fread(blob->ptr, 1, blob->len, fd); fclose(fd); - DBG1(" loading %s file '%s' (%d bytes)", type, filename, bytes); + DBG2(" loading '%s' (%d bytes)", filename, bytes); *pgp = FALSE; @@ -364,7 +370,7 @@ bool pem_asn1_load_file(const char *filename, chunk_t *passphrase, } else { - DBG1(" could not open %s file '%s'", type, filename); + DBG1(" reading file '%s' failed", filename); } return FALSE; } diff --git a/src/libstrongswan/asn1/pem.h b/src/libstrongswan/asn1/pem.h index 0f4b7202c..956623c0d 100755 --- a/src/libstrongswan/asn1/pem.h +++ b/src/libstrongswan/asn1/pem.h @@ -21,7 +21,7 @@ err_t pem_to_bin(chunk_t *blob, chunk_t *passphrase, bool *pgp); -bool pem_asn1_load_file(const char *filename, chunk_t *passphrase, - const char *type, chunk_t *blob, bool *pgp); +bool pem_asn1_load_file(char *filename, chunk_t *passphrase, + chunk_t *blob, bool *pgp); -#endif /*PEM_H_*/ +#endif /*PEM_H_ @} */ diff --git a/src/libstrongswan/asn1/ttodata.c b/src/libstrongswan/asn1/ttodata.c index 125313c2a..6cffecd40 100644 --- a/src/libstrongswan/asn1/ttodata.c +++ b/src/libstrongswan/asn1/ttodata.c @@ -11,6 +11,8 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public * License for more details. + * + * $Id$ */ #include "ttodata.h" @@ -34,7 +36,7 @@ static const char *badch(const char *, int, char *, size_t); #define BADOFF(code) (BADCH0-(code)) /** - * @brief convert text to data, with verbose error reports + * convert text to data, with verbose error reports * * If some of this looks slightly odd, it's because it has changed * repeatedly (from the original atodata()) without a major rewrite. @@ -197,7 +199,7 @@ const char *ttodatav(const char *src, size_t srclen, int base, char *dst, size_t } /** - * @brief ttodata - convert text to data + * ttodata - convert text to data * * @param src * @param srclen 0 means apply strlen() @@ -214,7 +216,7 @@ const char *ttodata(const char *src, size_t srclen, int base, char *dst, size_t } /** - * @brief atodata - convert ASCII to data + * atodata - convert ASCII to data * * backward-compatibility interface * @@ -234,7 +236,7 @@ size_t atodata(const char *src, size_t srclen, char *dst, size_t dstlen) } /** - * @brief atobytes - convert ASCII to data bytes + * atobytes - convert ASCII to data bytes * * another backward-compatibility interface */ @@ -244,7 +246,7 @@ const char *atobytes(const char *src, size_t srclen, char *dst, size_t dstlen, s } /** - * @brief unhex - convert two ASCII hex digits to byte + * unhex - convert two ASCII hex digits to byte * * @param src known to be full length * @param dstnumber of result bytes, or error code @@ -290,7 +292,7 @@ static int unhex(const char *src, char *dst, size_t dstlen) } /** - * @brief unb64 - convert four ASCII base64 digits to three bytes + * unb64 - convert four ASCII base64 digits to three bytes * * Note that a base64 digit group is padded out with '=' if it represents * less than three bytes: one byte is dd==, two is ddd=, three is dddd. @@ -368,7 +370,7 @@ static int unb64(const char *src, char *dst, size_t dstlen) } /** - * @brief untext - convert one ASCII character to byte + * untext - convert one ASCII character to byte * * @param src known to be full length * @param dst @@ -386,7 +388,7 @@ static int untext(const char *src, char *dst, size_t dstlen) } /** - * @brief badch - produce a nice complaint about an unknown character + * badch - produce a nice complaint about an unknown character * * If the compiler complains that the array bigenough[] has a negative * size, that means the TTODATAV_BUF constant has been set too small. diff --git a/src/libstrongswan/asn1/ttodata.h b/src/libstrongswan/asn1/ttodata.h index 6125c6b82..89ce53b84 100644 --- a/src/libstrongswan/asn1/ttodata.h +++ b/src/libstrongswan/asn1/ttodata.h @@ -25,4 +25,4 @@ err_t ttodata(const char *src, size_t srclen, int base, char *buf, size_t buflen, size_t *needed); -#endif /* TTODATA_H_ */ +#endif /* TTODATA_H_ @} */ diff --git a/src/libstrongswan/chunk.c b/src/libstrongswan/chunk.c index 0d7841641..6f12c9b51 100644 --- a/src/libstrongswan/chunk.c +++ b/src/libstrongswan/chunk.c @@ -1,10 +1,3 @@ -/** - * @file chunk.c - * - * @brief Pointer/lenght abstraction and its functions. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,8 @@ * 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. + * + * $Id$ */ #include @@ -356,82 +351,22 @@ bool chunk_equals_or_null(chunk_t a, chunk_t b) return a.len == b.len && memeq(a.ptr, b.ptr, a.len); } -/** - * Number of bytes per line to dump raw data - */ -#define BYTES_PER_LINE 16 - -/** - * output handler in printf() for byte ranges - */ -static int print_bytes(FILE *stream, const struct printf_info *info, - const void *const *args) -{ - char *bytes = *((void**)(args[0])); - int len = *((size_t*)(args[1])); - - char buffer[BYTES_PER_LINE * 3]; - char ascii_buffer[BYTES_PER_LINE + 1]; - char *buffer_pos = buffer; - char *bytes_pos = bytes; - char *bytes_roof = bytes + len; - int line_start = 0; - int i = 0; - int written = 0; - - written += fprintf(stream, "=> %d bytes @ %p", len, bytes); - - while (bytes_pos < bytes_roof) - { - *buffer_pos++ = hexdig_upper[(*bytes_pos >> 4) & 0xF]; - *buffer_pos++ = hexdig_upper[ *bytes_pos & 0xF]; - - ascii_buffer[i++] = - (*bytes_pos > 31 && *bytes_pos < 127) ? *bytes_pos : '.'; - - if (++bytes_pos == bytes_roof || i == BYTES_PER_LINE) - { - int padding = 3 * (BYTES_PER_LINE - i); - int written; - - while (padding--) - { - *buffer_pos++ = ' '; - } - *buffer_pos++ = '\0'; - ascii_buffer[i] = '\0'; - - written += fprintf(stream, "\n%4d: %s %s", - line_start, buffer, ascii_buffer); - - - buffer_pos = buffer; - line_start += BYTES_PER_LINE; - i = 0; - } - else - { - *buffer_pos++ = ' '; - } - } - return written; -} - /** * output handler in printf() for chunks */ -static int print_chunk(FILE *stream, const struct printf_info *info, +static int chunk_print(FILE *stream, const struct printf_info *info, const void *const *args) { chunk_t *chunk = *((chunk_t**)(args[0])); bool first = TRUE; chunk_t copy = *chunk; int written = 0; + printf_hook_functions_t mem = mem_get_printf_hooks(); if (!info->alt) { const void *new_args[] = {&chunk->ptr, &chunk->len}; - return print_bytes(stream, info, new_args); + return mem.print(stream, info, new_args); } while (copy.len > 0) @@ -451,10 +386,24 @@ static int print_chunk(FILE *stream, const struct printf_info *info, } /** - * register printf() handlers + * arginfo handler for printf() mem ranges + */ +static int chunk_arginfo(const struct printf_info *info, size_t n, int *argtypes) +{ + if (n > 0) + { + argtypes[0] = PA_POINTER; + } + return 1; +} + +/** + * return printf hook functions for a chunk */ -static void __attribute__ ((constructor))print_register() +printf_hook_functions_t chunk_get_printf_hooks() { - register_printf_function(PRINTF_CHUNK, print_chunk, arginfo_ptr); - register_printf_function(PRINTF_BYTES, print_bytes, arginfo_ptr_int); + printf_hook_functions_t hooks = {chunk_print, chunk_arginfo}; + + return hooks; } + diff --git a/src/libstrongswan/chunk.h b/src/libstrongswan/chunk.h index 9c0aabba1..76acfde34 100644 --- a/src/libstrongswan/chunk.h +++ b/src/libstrongswan/chunk.h @@ -1,12 +1,5 @@ -/** - * @file chunk.h - * - * @brief Pointer/length abstraction and its functions. - * - */ - /* - * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005-2008 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil * @@ -19,6 +12,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup chunk chunk + * @{ @ingroup libstrongswan */ #ifndef CHUNK_H_ @@ -26,8 +26,7 @@ #include #include - -#include +#include typedef struct chunk_t chunk_t; @@ -41,6 +40,8 @@ struct chunk_t { size_t len; }; +#include + /** * A { NULL, 0 }-chunk handy for initialization. */ @@ -161,4 +162,12 @@ bool chunk_equals(chunk_t a, chunk_t b); */ bool chunk_equals_or_null(chunk_t a, chunk_t b); -#endif /* CHUNK_H_ */ +/** + * Get printf hooks for a chunk. + * + * Arguments are: + * chunk_t *chunk + */ +printf_hook_functions_t chunk_get_printf_hooks(); + +#endif /* CHUNK_H_ @}*/ diff --git a/src/libstrongswan/credential_store.h b/src/libstrongswan/credential_store.h deleted file mode 100755 index 62b6ad2d5..000000000 --- a/src/libstrongswan/credential_store.h +++ /dev/null @@ -1,330 +0,0 @@ -/** - * @file credential_store.h - * - * @brief Interface credential_store_t. - * - */ - -/* - * Copyright (C) 2005-2006 Martin Willi - * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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 CREDENTIAL_STORE_H_ -#define CREDENTIAL_STORE_H_ - -typedef struct credential_store_t credential_store_t; - -#include -#include -#include -#include -#include -#include - - -/** - * @brief The interface for a credential_store backend. - * - * @b Constructors: - * - stroke_create() - * - * @ingroup config - */ -struct credential_store_t { - - /** - * @brief Returns the secret shared by two specific IDs. - * - * The returned chunk must be destroyed by the caller after usage. - * - * @param this calling object - * @param my_id my ID identifiying the secret. - * @param other_id peer ID identifying the secret. - * @param[out] secret the pre-shared secret will be written there. - * @return - * - NOT_FOUND if no preshared secrets for specific ID could be found - * - SUCCESS - * - */ - status_t (*get_shared_key) (credential_store_t *this, identification_t *my_id, - identification_t *other_id, chunk_t *shared_key); - - /** - * @brief Returns the EAP secret for two specified IDs. - * - * The returned chunk must be destroyed by the caller after usage. - * - * @param this calling object - * @param my_id my ID identifiying the secret. - * @param other_id peer ID identifying the secret. - * @param[out] eap_key the EAP secret will be written here - * @return - * - NOT_FOUND if no preshared secrets for specific ID could be found - * - SUCCESS - * - */ - status_t (*get_eap_key) (credential_store_t *this, identification_t *my_id, - identification_t *other_id, chunk_t *eap_key); - - /** - * @brief Returns the RSA public key of a specific ID. - * - * @param this calling object - * @param id identification_t object identifiying the key. - * @return public key, or NULL if not found - */ - rsa_public_key_t* (*get_rsa_public_key) (credential_store_t *this, identification_t *id); - - /** - * @brief Is there a matching RSA private key belonging to an RSA public key? - * - * @param this calling object - * @param pubkey public key - * @return TRUE if matching private key was found - */ - bool (*has_rsa_private_key) (credential_store_t *this, rsa_public_key_t *pubkey); - - /** - * @brief Returns the certificate of a specific ID. - * - * @param this calling object - * @param id identification_t object identifiying the cert. - * @return certificate, or NULL if not found - */ - x509_t* (*get_certificate) (credential_store_t *this, identification_t *id); - - /** - * @brief Returns the auth certificate of a specific subject distinguished name. - * - * @param this calling object - * @param auth_flags set of allowed authority types - * @param id identification_t object identifiying the cacert. - * @return certificate, or NULL if not found - */ - x509_t* (*get_auth_certificate) (credential_store_t *this, u_int auth_flags, identification_t *id); - - /** - * @brief Returns the ca certificate of a specific keyID. - * - * @param this calling object - * @param keyid identification_t object identifiying the cacert. - * @return certificate, or NULL if not found - */ - x509_t* (*get_ca_certificate_by_keyid) (credential_store_t *this, chunk_t keyid); - - /** - * @brief Returns the issuing ca of a given certificate. - * - * @param this calling object - * @param cert certificate for which issuer ca info is required - * @return ca info, or NULL if not found - */ - ca_info_t* (*get_issuer) (credential_store_t *this, x509_t* cert); - - /** - * @brief RSA private key belonging to an RSA public key - * - * - * @param this calling object - * @param pubkey public key used to find the matching private key - * @param hash_algorithm hash algorithm to be used for signature - * @param data data block to be signed - * @param signature signature to be returned - * @return status of the signature process - SUCCESS if successful - */ - status_t (*rsa_signature) (credential_store_t *this, rsa_public_key_t *pubkey, hash_algorithm_t hash_algorithm, - chunk_t data, chunk_t *signature); - - /** - * @brief Verify an RSA signature given the ID of the signer - * - * @param this calling object - * @param hash hash value to be verified. - * @param sig signature to be verified. - * @param id identification_t object identifiying the signer. - * @param issuer_p issuer of the signer's certificate (if not self-signed). - * @return status of the verification - SUCCESS if successful - */ - status_t (*verify_signature) (credential_store_t *this, chunk_t hash, chunk_t sig, identification_t *id, - ca_info_t **issuer_p); - - /** - * @brief Verify an X.509 certificate up to trust anchor without any status checks - * - * @param this calling object - * @param label label characterizing the certificate to be verified - * @param cert certificate to be verified - * @return TRUE if trusted - */ - bool (*is_trusted) (credential_store_t *this, const char *label, x509_t *cert); - - /** - * @brief Verify an X.509 certificate up to trust anchor including status checks - * - * @param this calling object - * @param cert certificate to be verified - * @param found found a certificate copy in the credential store - * @return TRUE if valid, trusted, and current status is good - */ - bool (*verify) (credential_store_t *this, x509_t *cert, bool *found); - - /** - * @brief If an end certificate does not already exists in the credential store then add it. - * - * @param this calling object - * @param cert certificate to be added - * @return pointer to the added or already existing certificate - */ - x509_t* (*add_end_certificate) (credential_store_t *this, x509_t *cert); - - /** - * @brief If an authority certificate does not already exists in the credential store then add it. - * - * @param this calling object - * @param cert authority certificate to be added - * @param auth_flag authority flags to add to the certificate - * @return pointer to the added or already existing certificate - */ - x509_t* (*add_auth_certificate) (credential_store_t *this, x509_t *cert, u_int auth_flag); - - /** - * @brief If a ca info record does not already exists in the credential store then add it. - * - * @param this calling object - * @param ca_info ca info record to be added - * @return pointer to the added or already existing ca_info_t record - */ - ca_info_t* (*add_ca_info) (credential_store_t *this, ca_info_t *ca_info); - - /** - * @brief Release a ca info record with a given name. - * - * @param this calling object - * @param name name of the ca info record to be released - * @return - * - SUCCESS, or - * - NOT_FOUND - */ - status_t (*release_ca_info) (credential_store_t *this, const char *name); - - /** - * @brief Create an iterator over all end certificates. - * - * @param this calling object - * @return iterator - */ - iterator_t* (*create_cert_iterator) (credential_store_t *this); - - /** - * @brief Create an iterator over all authority certificates. - * - * @param this calling object - * @return iterator - */ - iterator_t* (*create_auth_cert_iterator) (credential_store_t *this); - - /** - * @brief Create an iterator over all CA info records - * - * @param this calling object - * @return iterator - */ - iterator_t* (*create_cainfo_iterator) (credential_store_t *this); - - /** - * @brief Create an iterator over all attribute certificates. - * - * @param this calling object - * @return iterator - */ - iterator_t* (*create_acert_iterator) (credential_store_t *this); - - /** - * @brief Loads ca certificates from a default directory. - * - * Certificates in both DER and PEM format are accepted - * - * @param this calling object - */ - void (*load_ca_certificates) (credential_store_t *this); - - /** - * @brief Loads authorization authority certificates from a default directory. - * - * Certificates in both DER and PEM format are accepted - * - * @param this calling object - */ - void (*load_aa_certificates) (credential_store_t *this); - - /** - * @brief Loads attribute certificates from a default directory. - * - * Certificates in both DER and PEM format are accepted - * - * @param this calling object - */ - void (*load_attr_certificates) (credential_store_t *this); - - /** - * @brief Loads ocsp certificates from a default directory. - * - * Certificates in both DER and PEM format are accepted - * - * @param this calling object - */ - void (*load_ocsp_certificates) (credential_store_t *this); - - /** - * @brief Loads CRLs from a default directory. - * - * Certificates in both DER and PEM format are accepted - * - * @param this calling object - * @param path directory to load crls from - */ - void (*load_crls) (credential_store_t *this); - - /** - * @brief Loads secrets in ipsec.secrets - * - * RSA private key files can be either in DER or PEM format - * Optional encryption with a passphrase supported - * - * @param this calling object - * @param reload are the secrets to be reloaded - */ - void (*load_secrets) (credential_store_t *this, bool reload); - - /** - * @brief Destroys a credential_store_t object. - * - * @param this calling object - */ - void (*destroy) (credential_store_t *this); -}; - -/** - * @brief Creates a credential_store_t instance. - * - * @param strict enforce a strict crl policy - * @return credential store instance. - * - * @ingroup config - */ -credential_store_t *credential_store_create(bool strict); - - -#endif /*CREDENTIAL_STORE_H_*/ diff --git a/src/libstrongswan/credentials/builder.c b/src/libstrongswan/credentials/builder.c new file mode 100644 index 000000000..c4c3ba176 --- /dev/null +++ b/src/libstrongswan/credentials/builder.c @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 "builder.h" + +ENUM(builder_part_names, BUILD_BLOB_ASN1_DER, BUILD_END, + "BUILD_BLOB_ASN1_DER", + "BUILD_KEY_SIZE", + "BUILD_SIGNING_KEY", + "BUILD_SIGNING_CERT", + "BUILD_PUBLIC_KEY", + "BUILD_SUBJECT", + "BUILD_SUBJECT_ALTNAME", + "BUILD_ISSUER", + "BUILD_ISSUER_ALTNAME", + "BUILD_CA_CERT", + "BUILD_CERT", + "BUILD_END", +); diff --git a/src/libstrongswan/credentials/builder.h b/src/libstrongswan/credentials/builder.h new file mode 100644 index 000000000..14c3d2496 --- /dev/null +++ b/src/libstrongswan/credentials/builder.h @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 builder builder + * @{ @ingroup credentials + */ + +#ifndef BUILDER_H_ +#define BUILDER_H_ + +typedef struct builder_t builder_t; +typedef enum builder_part_t builder_part_t; + +/** + * Constructor function which creates a new builder instance. + * + * @param subtype constructor specific subtype, e.g. certificate_type_t + * @return builder to construct a instance of type + */ +typedef builder_t* (*builder_constructor_t)(int subtype); + +#include + +/** + * Parts to build credentials from. + */ +enum builder_part_t { + /** DER encoded ASN1 blob, argument is a chunk_t */ + BUILD_BLOB_ASN1_DER, + /** key size in bits, as used for key generation, as u_int */ + BUILD_KEY_SIZE, + /** private key to use for signing, private_key_t* */ + BUILD_SIGNING_KEY, + /** certificate used for signing, certificate_t* */ + BUILD_SIGNING_CERT, + /** public key to include, public_key_t* */ + BUILD_PUBLIC_KEY, + /** subject for e.g. certificates, identification_t* */ + BUILD_SUBJECT, + /** additional subject name, identification_t* */ + BUILD_SUBJECT_ALTNAME, + /** issuer for e.g. certificates, identification_t* */ + BUILD_ISSUER, + /** additional issuer name, identification_t* */ + BUILD_ISSUER_ALTNAME, + /** a CA certificate, certificate_t* */ + BUILD_CA_CERT, + /** a certificcate, certificate_t* */ + BUILD_CERT, + /** end of variable argument builder list */ + BUILD_END, +}; + +/** + * enum names for build_part_t + */ +extern enum_name_t *builder_part_names; + +/** + * Credential construction API. + * + * The builder allows the construction of credentials in a generic and + * flexible way. + */ +struct builder_t { + + /** + * Add a part to the construct. + * + * Any added parts get owned by the builder/construct, so clone/refcount + * them if needed. + * + * @param part kind of part + * @param ... part specific variable argument + */ + void (*add)(builder_t *this, builder_part_t part, ...); + + /** + * Build the construct with all supplied parts. + * + * Once build() is called, the builder gets destroyed. + * + * @return specific interface, as requested with constructor. + */ + void* (*build)(builder_t *this); +}; + +#endif /* BUILDER_H_ @}*/ diff --git a/src/libstrongswan/credentials/certificates/certificate.c b/src/libstrongswan/credentials/certificates/certificate.c new file mode 100644 index 000000000..649ab3069 --- /dev/null +++ b/src/libstrongswan/credentials/certificates/certificate.c @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "certificate.h" + +#include + +ENUM(certificate_type_names, CERT_ANY, CERT_PGP, + "ANY", + "X509", + "X509_CRL", + "X509_OCSP_REQUEST", + "X509_OCSP_RESPONSE", + "X509_AC", + "X509_CHAIN", + "TRUSTED_PUBKEY", + "PGP", +); + +ENUM(cert_validation_names, VALIDATION_GOOD, VALIDATION_SKIPPED, + "GOOD", + "REVOKED", + "FAILED", + "SKIPPED", +); + diff --git a/src/libstrongswan/credentials/certificates/certificate.h b/src/libstrongswan/credentials/certificates/certificate.h new file mode 100644 index 000000000..94f19a068 --- /dev/null +++ b/src/libstrongswan/credentials/certificates/certificate.h @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2007-2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 certificate certificate + * @{ @ingroup certificates + */ + +#ifndef CERTIFICATE_H_ +#define CERTIFICATE_H_ + +typedef struct certificate_t certificate_t; +typedef enum certificate_type_t certificate_type_t; +typedef enum cert_validation_t cert_validation_t; + +#include +#include +#include + +/** + * Kind of a certificate_t + */ +enum certificate_type_t { + /** just any certificate */ + CERT_ANY, + /** X.509 certificate */ + CERT_X509, + /** X.509 certificate revocation list */ + CERT_X509_CRL, + /** X.509 online certificate status protocol request */ + CERT_X509_OCSP_REQUEST, + /** X.509 online certificate status protocol response */ + CERT_X509_OCSP_RESPONSE, + /** X.509 attribute certificate */ + CERT_X509_AC, + /** trusted, preinstalled public key */ + CERT_TRUSTED_PUBKEY, + /** PGP certificate */ + CERT_PGP, +}; + +/** + * Enum names for certificate_type_t + */ +extern enum_name_t *certificate_type_names; + +/** + * Result of a certificate validation. + */ +enum cert_validation_t { + /** certificate has been validated successfully */ + VALIDATION_GOOD, + /** validation failed, certificate is revoked */ + VALIDATION_REVOKED, + /* ocsp status is unknown or crl is stale */ + VALIDATION_UNKNOWN, + /** validation process failed due to an error */ + VALIDATION_FAILED, + /** validation has been skipped (no cdps available) */ + VALIDATION_SKIPPED, +}; + +/** + * Enum names for cert_validation_t + */ +extern enum_name_t *cert_validation_names; + +/** + * An abstract certificate. + * + * A certificate designs a subject-issuer relationship. It may have an + * associated public key. + */ +struct certificate_t { + + /** + * Get the type of the certificate. + * + * @return certifcate type + */ + certificate_type_t (*get_type)(certificate_t *this); + + /** + * Get the primary subject to which this certificate belongs. + * + * @return subject identity + */ + identification_t* (*get_subject)(certificate_t *this); + + /** + * Check if certificate contains a subject ID. + * + * A certificate may contain additional subject identifiers, which are + * not returned by get_subject (e.g. subjectAltNames) + * + * @param subject subject identity + * @return matching value of best match + */ + id_match_t (*has_subject)(certificate_t *this, identification_t *subject); + + /** + * Get the issuer which signed this certificate. + * + * @return issuer identity + */ + identification_t* (*get_issuer)(certificate_t *this); + + /** + * Check if certificate contains an issuer ID. + * + * A certificate may contain additional issuer identifiers, which are + * not returned by get_issuer (e.g. issuerAltNames) + * + * @param subject isser identity + * @return matching value of best match + */ + id_match_t (*has_issuer)(certificate_t *this, identification_t *issuer); + + /** + * Check if this certificate is issued by a specific issuer. + * + * As signature verification is computional expensive, it is optional + * and may be skipped. While this is not sufficient for verification + * purposes, it is to e.g. find matching certificates. + * + * @param issuer issuer's certificate + * @param checksig TRUE to verify signature, FALSE to compare issuer only + * @return TRUE if certificate issued by issuer and trusted + */ + bool (*issued_by)(certificate_t *this, certificate_t *issuer, bool checksig); + + /** + * Get the public key associated to this certificate. + * + * @return newly referenced public_key, NULL if none available + */ + public_key_t* (*get_public_key)(certificate_t *this); + + /** + * Check the lifetime of the certificate. + * + * @param when check validity at a certain time (NULL for now) + * @param not_before receives certificates start of lifetime + * @param not_after receives certificates end of lifetime + * @return TRUE if when between not_after and not_before + */ + bool (*get_validity)(certificate_t *this, time_t *when, + time_t *not_before, time_t *not_after); + + /** + * Get the certificate in an encoded form. + * + * @return allocated chunk of encoded cert + */ + chunk_t (*get_encoding)(certificate_t *this); + + /** + * Check if two certificates are equal. + * + * @param other certificate to compair against this + * @return TRUE if certificates are equal + */ + bool (*equals)(certificate_t *this, certificate_t *other); + + /** + * Get a new reference to the certificate. + * + * @return this, with an increased refcount + */ + certificate_t* (*get_ref)(certificate_t *this); + + /** + * Destroy a certificate. + */ + void (*destroy)(certificate_t *this); +}; + +#endif /* CERTIFICATE_H_ @}*/ diff --git a/src/libstrongswan/credentials/certificates/crl.c b/src/libstrongswan/credentials/certificates/crl.c new file mode 100644 index 000000000..48fb24a5d --- /dev/null +++ b/src/libstrongswan/credentials/certificates/crl.c @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2008 Martin Willi + * Copyright (C) 2006 Andreas Steffen + * 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 . + * + * 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. + * + * $Id$ + */ + +#include "crl.h" + +ENUM(crl_reason_names, CRL_UNSPECIFIED, CRL_REMOVE_FROM_CRL, + "unspecified", + "key compromise", + "ca compromise", + "affiliation changed", + "superseded", + "cessation of operation", + "certificate hold", + "reason #7", + "remove from crl", +); + diff --git a/src/libstrongswan/credentials/certificates/crl.h b/src/libstrongswan/credentials/certificates/crl.h new file mode 100644 index 000000000..752293ffb --- /dev/null +++ b/src/libstrongswan/credentials/certificates/crl.h @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2008 Martin Willi + * Copyright (C) 2006 Andreas Steffen + * 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 . + * + * 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 crl crl + * @{ @ingroup certificates + */ + +#ifndef CRL_H_ +#define CRL_H_ + +typedef struct crl_t crl_t; +typedef enum crl_reason_t crl_reason_t; + +#include +#include + +/** + * RFC 2459 CRL reason codes + */ +enum crl_reason_t { + CRL_UNSPECIFIED = 0, + CRL_KEY_COMPROMISE = 1, + CRL_CA_COMPROMISE = 2, + CRL_AFFILIATION_CHANGED = 3, + CRL_SUPERSEDED = 4, + CRL_CESSATION_OF_OPERATON = 5, + CRL_CERTIFICATE_HOLD = 6, + CRL_REMOVE_FROM_CRL = 8, +}; + +/** + * enum names for crl_reason_t + */ +extern enum_name_t *crl_reason_names; + +/** + * X509 certificate revocation list (CRL) interface definition. + */ +struct crl_t { + + /** + * Implements (parts of) the certificate_t interface + */ + certificate_t certificate; + + /** + * Is that newer than this? + * + * @return TRUE if newer, FALSE otherwise + */ + bool (*is_newer)(crl_t *this, crl_t *that); + + /** + * Get the CRL serial number. + * + * @return chunk pointing to internal crlNumber + */ + chunk_t (*get_serial)(crl_t *this); + + /** + * Get the the authorityKeyIdentifier. + * + * @return authKeyIdentifier as identification_t* + */ + identification_t* (*get_authKeyIdentifier)(crl_t *this); + + /** + * Create an enumerator over all revoked certificates. + * + * The enumerator takes 3 pointer arguments: + * chunk_t serial, time_t revocation_date, crl_reason_t reason + * + * @return enumerator over revoked certificates. + */ + enumerator_t* (*create_enumerator)(crl_t *this); + +}; + +#endif /* CRL_H_ @}*/ diff --git a/src/libstrongswan/credentials/certificates/ocsp_request.c b/src/libstrongswan/credentials/certificates/ocsp_request.c new file mode 100644 index 000000000..0958be4a0 --- /dev/null +++ b/src/libstrongswan/credentials/certificates/ocsp_request.c @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "ocsp_request.h" + diff --git a/src/libstrongswan/credentials/certificates/ocsp_request.h b/src/libstrongswan/credentials/certificates/ocsp_request.h new file mode 100644 index 000000000..377eabd23 --- /dev/null +++ b/src/libstrongswan/credentials/certificates/ocsp_request.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +/** + * @defgroup ocsp_request ocsp_request + * @{ @ingroup certificates + */ + +#ifndef OCSP_REQUEST_H_ +#define OCSP_REQUEST_H_ + +#include + +typedef struct ocsp_request_t ocsp_request_t; + +/** + * OCSP request message. + */ +struct ocsp_request_t { + + /** + * Implements certificiate_t interface + */ + certificate_t interface; +}; + +#endif /* OCSP_REQUEST_H_ @}*/ diff --git a/src/libstrongswan/credentials/certificates/ocsp_response.c b/src/libstrongswan/credentials/certificates/ocsp_response.c new file mode 100644 index 000000000..02e12f761 --- /dev/null +++ b/src/libstrongswan/credentials/certificates/ocsp_response.c @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "ocsp_response.h" + +ENUM(ocsp_status_names, OCSP_SUCCESSFUL, OCSP_UNAUTHORIZED, + "successful", + "malformed request", + "internal error", + "try later", + "status #4", + "signature required", + "unauthorized" +); + diff --git a/src/libstrongswan/credentials/certificates/ocsp_response.h b/src/libstrongswan/credentials/certificates/ocsp_response.h new file mode 100644 index 000000000..416f712f3 --- /dev/null +++ b/src/libstrongswan/credentials/certificates/ocsp_response.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +/** + * @defgroup ocsp_response ocsp_response + * @{ @ingroup certificates + */ + +#ifndef OCSP_RESPONSE_H_ +#define OCSP_RESPONSE_H_ + +#include +#include + +typedef struct ocsp_response_t ocsp_response_t; +typedef enum ocsp_status_t ocsp_status_t; + +/** + * OCSP response status + */ +enum ocsp_status_t { + OCSP_SUCCESSFUL = 0, + OCSP_MALFORMEDREQUEST = 1, + OCSP_INTERNALERROR = 2, + OCSP_TRYLATER = 3, + OCSP_SIGREQUIRED = 5, + OCSP_UNAUTHORIZED = 6, +}; + +/** + * enum names for ocsp_status_t + */ +extern enum_name_t *ocsp_status_names; + +/** + * OCSP response message. + */ +struct ocsp_response_t { + + /** + * Implements certificiate_t interface + */ + certificate_t certificate; + + /** + * Check the status of a certificate by this OCSP response. + * + * @param subject certificate to check status + * @param issuer issuer certificate of subject + * @param revocation_time receives time of revocation, if revoked + * @param revocation_reason receives reason of revocation, if revoked + * @param this_update creation time of revocation list + * @param next_update exptected time of next revocation list + * @return certificate revocation status + */ + cert_validation_t (*get_status)(ocsp_response_t *this, + x509_t *subject, x509_t *issuer, + time_t *revocation_time, + crl_reason_t *revocation_reason, + time_t *this_update, time_t *next_update); + + /** + * Create an enumerator over the contained certificates. + * + * @return enumerator over certificate_t* + */ + enumerator_t* (*create_cert_enumerator)(ocsp_response_t *this); +}; + +#endif /* OCSP_RESPONSE_H_ @}*/ diff --git a/src/libstrongswan/credentials/certificates/x509.c b/src/libstrongswan/credentials/certificates/x509.c new file mode 100644 index 000000000..a5f4fc1d0 --- /dev/null +++ b/src/libstrongswan/credentials/certificates/x509.c @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "x509.h" + +ENUM(x509_flag_names, X509_CA, X509_SELF_SIGNED, + "X509_CA", + "X509_AA", + "X509_OCSP_SIGNER", + "X509_SELF_SIGNED", +); diff --git a/src/libstrongswan/credentials/certificates/x509.h b/src/libstrongswan/credentials/certificates/x509.h new file mode 100644 index 000000000..a4f9d1ff3 --- /dev/null +++ b/src/libstrongswan/credentials/certificates/x509.h @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2007-2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 x509 x509 + * @{ @ingroup certificates + */ + +#ifndef X509_H_ +#define X509_H_ + +#include +#include + +typedef struct x509_t x509_t; +typedef enum x509_flag_t x509_flag_t; + +/** + * X.509 certificate flags. + */ +enum x509_flag_t { + /** cert has CA constraint */ + X509_CA = (1<<0), + /** cert has AA constraint */ + X509_AA = (1<<1), + /** cert has OCSP signer constraint */ + X509_OCSP_SIGNER = (1<<2), + /** cert belongs to an end entity */ + X509_PEER = (1<<3), + /** cert is self-signed */ + X509_SELF_SIGNED = (1<<4), +}; + +/** + * enum names for x509 flags + */ +extern enum_name_t *x509_flag_names; + +/** + * X.509 certificate interface. + * + * This interface adds additional methods to the certificate_t type to + * allow further operations on these certificates. + */ +struct x509_t { + + /** + * Implements certificate_t. + */ + certificate_t interface; + + /** + * Get the flags set for this certificate. + * + * @return set of flags + */ + x509_flag_t (*get_flags)(x509_t *this); + + /** + * Set the flags for this certificate. + * + * @param flags set of flags + */ + void (*set_flags)(x509_t *this, x509_flag_t flags); + + /** + * Get the certificate serial number. + * + * @return chunk pointing to internal serial number + */ + chunk_t (*get_serial)(x509_t *this); + + /** + * Get the the authorityKeyIdentifier. + * + * @return authKeyIdentifier as identification_t* + */ + identification_t* (*get_authKeyIdentifier)(x509_t *this); + + /** + * Create an enumerator over all subjectAltNames. + * + * @return enumerator over subjectAltNames as identification_t* + */ + enumerator_t* (*create_subjectAltName_enumerator)(x509_t *this); + + /** + * Create an enumerator over all CRL URIs. + * + * @return enumerator over URIs as char* + */ + enumerator_t* (*create_crl_uri_enumerator)(x509_t *this); + + /** + * Create an enumerator over all OCSP URIs. + * + * @return enumerator over URIs as char* + */ + enumerator_t* (*create_ocsp_uri_enumerator)(x509_t *this); +}; + +#endif /* X509_H_ @}*/ diff --git a/src/libstrongswan/credentials/credential_factory.c b/src/libstrongswan/credentials/credential_factory.c new file mode 100644 index 000000000..ab99a4211 --- /dev/null +++ b/src/libstrongswan/credentials/credential_factory.c @@ -0,0 +1,263 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "credential_factory.h" + +#include +#include +#include + +typedef struct private_credential_factory_t private_credential_factory_t; + +/** + * private data of credential_factory + */ +struct private_credential_factory_t { + + /** + * public functions + */ + credential_factory_t public; + + /** + * list with entry_t + */ + linked_list_t *constructors; + + /** + * mutex to lock access to modules + */ + mutex_t *mutex; +}; + +typedef struct entry_t entry_t; +struct entry_t { + /** kind of credential builder */ + credential_type_t type; + /** subtype of credential, e.g. certificate_type_t */ + int subtype; + /** builder construction function */ + builder_constructor_t constructor; +}; + +/** + * Implementation of credential_factory_t.create_builder. + */ +static builder_t* create_builder(private_credential_factory_t *this, + credential_type_t type, int subtype) +{ + enumerator_t *enumerator; + entry_t *entry; + builder_t *builder = NULL; + + this->mutex->lock(this->mutex); + enumerator = this->constructors->create_enumerator(this->constructors); + while (enumerator->enumerate(enumerator, &entry)) + { + if (entry->type == type && entry->subtype == subtype) + { + builder = entry->constructor(subtype); + if (builder) + { + break; + } + } + } + enumerator->destroy(enumerator); + this->mutex->unlock(this->mutex); + return builder; +} + +/** + * Implementation of credential_factory_t.add_builder_constructor. + */ +static void add_builder(private_credential_factory_t *this, + credential_type_t type, int subtype, + builder_constructor_t constructor) +{ + entry_t *entry = malloc_thing(entry_t); + + entry->type = type; + entry->subtype = subtype; + entry->constructor = constructor; + this->mutex->lock(this->mutex); + this->constructors->insert_last(this->constructors, entry); + this->mutex->unlock(this->mutex); +} + +/** + * Implementation of credential_factory_t.remove_builder. + */ +static void remove_builder(private_credential_factory_t *this, + builder_constructor_t constructor) +{ + enumerator_t *enumerator; + entry_t *entry; + + this->mutex->lock(this->mutex); + enumerator = this->constructors->create_enumerator(this->constructors); + while (enumerator->enumerate(enumerator, &entry)) + { + if (entry->constructor == constructor) + { + this->constructors->remove_at(this->constructors, enumerator); + free(entry); + } + } + enumerator->destroy(enumerator); + this->mutex->unlock(this->mutex); +} + +/** + * Implementation of credential_factory_t.create. + */ +static void* create(private_credential_factory_t *this, credential_type_t type, + int subtype, ...) +{ + builder_t *builder; + builder_part_t part; + va_list args; + + builder = create_builder(this, type, subtype); + if (builder) + { + va_start(args, subtype); + while (TRUE) + { + part = va_arg(args, builder_part_t); + + switch (part) + { + case BUILD_END: + break; + case BUILD_BLOB_ASN1_DER: + builder->add(builder, part, va_arg(args, chunk_t)); + continue; + case BUILD_KEY_SIZE: + builder->add(builder, part, va_arg(args, u_int)); + continue; + case BUILD_SIGNING_KEY: + case BUILD_PUBLIC_KEY: + case BUILD_SUBJECT: + case BUILD_SUBJECT_ALTNAME: + case BUILD_ISSUER: + case BUILD_ISSUER_ALTNAME: + case BUILD_SIGNING_CERT: + case BUILD_CA_CERT: + case BUILD_CERT: + builder->add(builder, part, va_arg(args, void*)); + continue; + default: + DBG1("builder part %N not supported by factory", + builder_part_names, part); + continue; + } + break; + } + va_end(args); + + return builder->build(builder); + } + + /** shredder all data on failure */ + va_start(args, subtype); + while (TRUE) + { + part = va_arg(args, builder_part_t); + + switch (part) + { + case BUILD_END: + break; + case BUILD_BLOB_ASN1_DER: + { + chunk_t chunk = va_arg(args, chunk_t); + free(chunk.ptr); + continue; + } + case BUILD_SIGNING_KEY: + { + private_key_t *private = va_arg(args, private_key_t*); + private->destroy(private); + continue; + } + case BUILD_PUBLIC_KEY: + { + public_key_t *public = va_arg(args, public_key_t*); + public->destroy(public); + continue; + } + case BUILD_SUBJECT: + case BUILD_SUBJECT_ALTNAME: + case BUILD_ISSUER: + case BUILD_ISSUER_ALTNAME: + { + identification_t *id = va_arg(args, identification_t*); + id->destroy(id); + continue; + } + case BUILD_SIGNING_CERT: + case BUILD_CA_CERT: + case BUILD_CERT: + { + certificate_t *cert = va_arg(args, certificate_t*); + cert->destroy(cert); + continue; + } + case BUILD_KEY_SIZE: + continue; + default: + DBG1("builder part %N not supported by factory", + builder_part_names, part); + continue; + } + break; + } + va_end(args); + return NULL; +} + +/** + * Implementation of credential_factory_t.destroy + */ +static void destroy(private_credential_factory_t *this) +{ + this->constructors->destroy_function(this->constructors, free); + this->mutex->destroy(this->mutex); + free(this); +} + +/* + * see header file + */ +credential_factory_t *credential_factory_create() +{ + private_credential_factory_t *this = malloc_thing(private_credential_factory_t); + + this->public.create = (void*(*)(credential_factory_t*, credential_type_t type, int subtype, ...))create; + this->public.create_builder = (builder_t*(*)(credential_factory_t*, credential_type_t type, int subtype))create_builder; + this->public.add_builder = (void(*)(credential_factory_t*,credential_type_t type, int subtype, builder_constructor_t constructor))add_builder; + this->public.remove_builder = (void(*)(credential_factory_t*,builder_constructor_t constructor))remove_builder; + this->public.destroy = (void(*)(credential_factory_t*))destroy; + + this->constructors = linked_list_create(); + + this->mutex = mutex_create(MUTEX_RECURSIVE); + + return &this->public; +} + diff --git a/src/libstrongswan/credentials/credential_factory.h b/src/libstrongswan/credentials/credential_factory.h new file mode 100644 index 000000000..394d0b075 --- /dev/null +++ b/src/libstrongswan/credentials/credential_factory.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup credential_factory credential_factory + * @{ @ingroup credentials + */ + +#ifndef CREDENTIAL_FACTORY_H_ +#define CREDENTIAL_FACTORY_H_ + +typedef struct credential_factory_t credential_factory_t; +typedef enum credential_type_t credential_type_t; + +#include +#include +#include +#include + +/** + * Kind of credential. + */ +enum credential_type_t { + /** private key, implemented in private_key_t */ + CRED_PRIVATE_KEY, + /** public key, implemented in public_key_t */ + CRED_PUBLIC_KEY, + /** certificates, implemented in certificate_t */ + CRED_CERTIFICATE, +}; + +/** + * Manages credential construction functions and creates instances. + */ +struct credential_factory_t { + + /** + * Create a credential using a list of builder_part_t's. + * + * The variable argument list takes builder_part_t types followed + * by the type specific value. The list must be terminated using BUILD_END. + * + * @param type credential type to build + * @param subtype subtype specific for type of the credential + * @param ... build_part_t arguments, BUILD_END terminated. + * @return type specific credential, NULL if failed + */ + void* (*create)(credential_factory_t *this, credential_type_t type, + int subtype, ...); + + /** + * Create a builder instance to build credentials. + * + * @param type type of credentials the builder creates + * @param subtype type specific subtype, such as certificate_type_t + * @return builder instance + */ + builder_t* (*create_builder)(credential_factory_t *this, + credential_type_t type, int subtype); + /** + * Register a builder_t constructor function. + * + * @param type type of credential the builder creates + * @param constructor builder constructor function to register + */ + void (*add_builder)(credential_factory_t *this, + credential_type_t type, int subtype, + builder_constructor_t constructor); + /** + * Unregister a builder_t constructor function. + * + * @param constructor constructor function to unregister. + */ + void (*remove_builder)(credential_factory_t *this, + builder_constructor_t constructor); + + /** + * Destroy a credential_factory instance. + */ + void (*destroy)(credential_factory_t *this); +}; + +/** + * Create a credential_factory instance. + */ +credential_factory_t *credential_factory_create(); + +#endif /* CREDENTIAL_FACTORY_H_ @}*/ diff --git a/src/libstrongswan/credentials/keys/private_key.c b/src/libstrongswan/credentials/keys/private_key.c new file mode 100644 index 000000000..9853bda10 --- /dev/null +++ b/src/libstrongswan/credentials/keys/private_key.c @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "private_key.h" + diff --git a/src/libstrongswan/credentials/keys/private_key.h b/src/libstrongswan/credentials/keys/private_key.h new file mode 100644 index 000000000..fbb5abf02 --- /dev/null +++ b/src/libstrongswan/credentials/keys/private_key.h @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +/** + * @defgroup private_key private_key + * @{ @ingroup keys + */ + +#ifndef PRIVATE_KEY_H_ +#define PRIVATE_KEY_H_ + +typedef struct private_key_t private_key_t; + +#include +#include + +/** + * Abstract private key interface. + */ +struct private_key_t { + + /** + * Get the key type. + * + * @return type of the key + */ + key_type_t (*get_type)(private_key_t *this); + + /** + * Create a signature over a chunk of data. + * + * @param scheme signature scheme to use + * @param data chunk of data to sign + * @param signature where to allocate created signature + * @return TRUE if signature created + */ + bool (*sign)(private_key_t *this, signature_scheme_t scheme, + chunk_t data, chunk_t *signature); + /** + * Decrypt a chunk of data. + * + * @param crypto chunk containing encrypted data + * @param plain where to allocate decrypted data + * @return TRUE if data decrypted and plaintext allocated + */ + bool (*decrypt)(private_key_t *this, chunk_t crypto, chunk_t *plain); + + /** + * Get the strength of the key in bytes. + * + * @return strength of the key in bytes + */ + size_t (*get_keysize) (private_key_t *this); + + /** + * Get a unique key identifier, such as a hash over the public key. + * + * @param type type of the key ID to get + * @return unique ID of the key as identification_t, or NULL + */ + identification_t* (*get_id) (private_key_t *this, id_type_t type); + + /** + * Get the public part from the private key. + * + * @return public key + */ + public_key_t* (*get_public_key)(private_key_t *this); + + /** + * Check if a private key belongs to a public key. + * + * @param public public key + * @return TRUE, if keys belong together + */ + bool (*belongs_to) (private_key_t *this, public_key_t *public); + + /** + * Get an encoded form of the private key. + * + * @todo Do we need a encoding type specification? + * + * @return allocated chunk containing encoded private key + */ + chunk_t (*get_encoding)(private_key_t *this); + + /** + * Increase the refcount to this private key. + * + * @return this, with an increased refcount + */ + private_key_t* (*get_ref)(private_key_t *this); + + /** + * Decrease refcount, destroy private_key if no more references. + */ + void (*destroy)(private_key_t *this); +}; + +/** + * Read a private key from a file. + * + * @param type type of the key + * @param filename filename to read key from + * @param passphrase passphrase to decrypt an encrypted key + * @return loaded private key, NULL if failed + */ +private_key_t *private_key_create_from_file(key_type_t type, char *filename, + chunk_t passphrase); + +/** + * Create a private key from a chunk. + * + * @param type type of the key + * @param chunk chunk to create key from + * @return loaded private key, NULL if failed + */ +private_key_t *private_key_create_from_chunk(key_type_t type, chunk_t chunk); + +/** + * Generate a new private key. + * + * @param type type of the key + * @param size key size in bytes + * @return generated private key, NULL if failed + */ +private_key_t *private_key_create_generated(key_type_t type, size_t size); + +#endif /* PRIVATE_KEY_H_ @} */ diff --git a/src/libstrongswan/credentials/keys/public_key.c b/src/libstrongswan/credentials/keys/public_key.c new file mode 100644 index 000000000..654b53c16 --- /dev/null +++ b/src/libstrongswan/credentials/keys/public_key.c @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "public_key.h" + +ENUM(key_type_names, KEY_RSA, KEY_RSA, + "RSA" +); + +ENUM(signature_scheme_names, SIGN_DEFAULT, SIGN_RSA_EMSA_PKCS1_SHA512, + "DEFAULT", + "RSA_EMSA_PKCS1_MD5", + "RSA_EMSA_PKCS1_SHA1", + "RSA_EMSA_PKCS1_SHA256", + "RSA_EMSA_PKCS1_SHA384", + "RSA_EMSA_PKCS1_SHA512", +); + diff --git a/src/libstrongswan/credentials/keys/public_key.h b/src/libstrongswan/credentials/keys/public_key.h new file mode 100644 index 000000000..2083db5a1 --- /dev/null +++ b/src/libstrongswan/credentials/keys/public_key.h @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +/** + * @defgroup public_key public_key + * @{ @ingroup keys + */ + +#ifndef PUBLIC_KEY_H_ +#define PUBLIC_KEY_H_ + +typedef struct public_key_t public_key_t; +typedef enum key_type_t key_type_t; +typedef enum key_id_type_t key_id_type_t; +typedef enum signature_scheme_t signature_scheme_t; + +#include +#include + +/** + * Type of a key pair, the used crypto system + */ +enum key_type_t { + /** key type wildcard */ + KEY_ANY, + /** RSA crypto system as in PKCS#1 */ + KEY_RSA, + /** DSS, ElGamal, ECDSA, ... */ +}; + +/** + * Enum names for key_type_t + */ +extern enum_name_t *key_type_names; + +/** + * Signature scheme for signature creation + * + * EMSA-PKCS1 signatures are from the PKCS#1 standard. They include + * the ASN1-OID of the used hash algorithm. + */ +enum signature_scheme_t { + /** default scheme of that underlying crypto system */ + SIGN_DEFAULT, + /** EMSA-PKCS1 with MD5 */ + SIGN_RSA_EMSA_PKCS1_MD5, + /** EMSA-PKCS1 signature as in PKCS#1 standard using SHA1 as hash. */ + SIGN_RSA_EMSA_PKCS1_SHA1, + /** EMSA-PKCS1 signature as in PKCS#1 standard using SHA256 as hash. */ + SIGN_RSA_EMSA_PKCS1_SHA256, + /** EMSA-PKCS1 signature as in PKCS#1 standard using SHA384 as hash. */ + SIGN_RSA_EMSA_PKCS1_SHA384, + /** EMSA-PKCS1 signature as in PKCS#1 standard using SHA512 as hash. */ + SIGN_RSA_EMSA_PKCS1_SHA512, +}; + +/** + * Enum names for signature_scheme_t + */ +extern enum_name_t *signature_scheme_names; + +/** + * Abstract interface of a public key. + */ +struct public_key_t { + + /** + * Get the key type. + * + * @return type of the key + */ + key_type_t (*get_type)(public_key_t *this); + + /** + * Verifies a signature against a chunk of data. + * + * @param scheme signature scheme to use for verification, may be default + * @param data data to check signature against + * @param signature signature to check + * @return TRUE if signature matches + */ + bool (*verify)(public_key_t *this, signature_scheme_t scheme, + chunk_t data, chunk_t signature); + + /** + * Encrypt a chunk of data. + * + * @param crypto chunk containing plaintext data + * @param plain where to allocate encrypted data + * @return TRUE if data successfully encrypted + */ + bool (*encrypt)(public_key_t *this, chunk_t crypto, chunk_t *plain); + + /** + * Get the strength of the key in bytes. + * + * @return strength of the key in bytes + */ + size_t (*get_keysize) (public_key_t *this); + + /** + * Get a unique key identifier, such as a hash over the key. + * + * @param type type of the key ID to get + * @return unique ID of the key as identification_t, or NULL + */ + identification_t* (*get_id) (public_key_t *this, id_type_t type); + + /** + * Get an encoded form of the key. + * + * @todo Do we need a encoding type specification? + * + * @return allocated chunk containing encoded key + */ + chunk_t (*get_encoding)(public_key_t *this); + + /** + * Increase the refcount of the key. + * + * @return this with an increased refcount + */ + public_key_t* (*get_ref)(public_key_t *this); + + /** + * Destroy a public_key instance. + */ + void (*destroy)(public_key_t *this); +}; + +/** + * Read a public key from a file. + * + * @param type type of the key + * @param filename filename to read key from + * @return loaded public key, NULL if failed + */ +public_key_t *public_key_create_from_file(key_type_t type, char *filename); + +/** + * Create a public key from a chunk. + * + * @param type type of the key + * @param chunk chunk to create key from + * @return loaded public key, NULL if failed + */ +public_key_t *public_key_create_from_chunk(key_type_t type, chunk_t chunk); + +#endif /* PUBLIC_KEY_H_ @} */ diff --git a/src/libstrongswan/credentials/keys/shared_key.c b/src/libstrongswan/credentials/keys/shared_key.c new file mode 100644 index 000000000..66b45a003 --- /dev/null +++ b/src/libstrongswan/credentials/keys/shared_key.c @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "shared_key.h" + +ENUM(shared_key_type_names, SHARED_ANY, SHARED_PIN, + "ANY", + "IKE", + "EAP", + "PRIVATE_KEY_PASS", + "PIN", +); + diff --git a/src/libstrongswan/credentials/keys/shared_key.h b/src/libstrongswan/credentials/keys/shared_key.h new file mode 100644 index 000000000..86586a7c7 --- /dev/null +++ b/src/libstrongswan/credentials/keys/shared_key.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 shared_key shared_key + * @{ @ingroup keys + */ + +#ifndef SHARED_KEY_H_ +#define SHARED_KEY_H_ + +#include +#include + +typedef struct shared_key_t shared_key_t; +typedef enum shared_key_type_t shared_key_type_t; + +/** + * Type of a shared key. + */ +enum shared_key_type_t { + /** wildcard for all keys */ + SHARED_ANY, + /** PSK for IKE authentication */ + SHARED_IKE, + /** key for a EAP authentication method */ + SHARED_EAP, + /** key to decrypt encrypted private keys */ + SHARED_PRIVATE_KEY_PASS, + /** PIN to unlock a smartcard */ + SHARED_PIN, +}; + +/** + * enum names for shared_key_type_t + */ +extern enum_name_t *shared_key_type_names; + +/** + * A symmetric key shared between multiple owners. + * + * This class is not thread save, do not add owners while others might be + * reading. + */ +struct shared_key_t { + + /** + * Get the kind of this key. + * + * @return type of the key + */ + shared_key_type_t (*get_type)(shared_key_t *this); + + /** + * Get the shared key data. + * + * @return chunk pointing to the internal key + */ + chunk_t (*get_key)(shared_key_t *this); + + /** + * Increase refcount of the key. + * + * @return this with an increased refcount + */ + shared_key_t* (*get_ref)(shared_key_t *this); + + /** + * Destroy a shared_key instance if all references are gone. + */ + void (*destroy)(shared_key_t *this); +}; + +#endif /** SHARED_KEY_H_ @} */ diff --git a/src/libstrongswan/crypto/ac.c b/src/libstrongswan/crypto/ac.c deleted file mode 100644 index 30282124c..000000000 --- a/src/libstrongswan/crypto/ac.c +++ /dev/null @@ -1,636 +0,0 @@ -/** - * @file ac.c - * - * @brief Implementation of x509ac_t. - * - */ - -/* - * Copyright (C) 2002 Ueli Galizzi, Ariane Seiler - * Copyright (C) 2003 Martin Berner, Lukas Suter - * Copyright (C) 2007 Andreas Steffen, 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 . - * - * 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. - * - * RCSID $Id$ - */ - -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "ac.h" - -#define ACERT_WARNING_INTERVAL 1 /* day */ - -typedef struct private_x509ac_t private_x509ac_t; - -/** - * Private data of a x509ac_t object. - */ -struct private_x509ac_t { - /** - * Public interface for this attribute certificate. - */ - x509ac_t public; - - /** - * Time when attribute certificate was installed - */ - time_t installed; - - /** - * X.509 attribute certificate in DER format - */ - chunk_t certificate; - - /** - * X.509 attribute certificate body over which signature is computed - */ - chunk_t certificateInfo; - - /** - * Version of the X.509 attribute certificate - */ - u_int version; - - /** - * Serial number of the X.509 attribute certificate - */ - chunk_t serialNumber; - - /** - * ID representing the issuer of the holder certificate - */ - identification_t *holderIssuer; - - /** - * Serial number of the holder certificate - */ - chunk_t holderSerial; - - /** - * ID representing the holder - */ - identification_t *entityName; - - /** - * ID representing the attribute certificate issuer - */ - identification_t *issuerName; - - /** - * Signature algorithm - */ - int sigAlg; - - /** - * Start time of certificate validity - */ - time_t notBefore; - - /** - * End time of certificate validity - */ - time_t notAfter; - - /** - * List of charging attributes - */ - linked_list_t *charging; - - /** - * List of groub attributes - */ - linked_list_t *groups; - - /** - * Authority Key Identifier - */ - chunk_t authKeyID; - - /** - * Authority Key Serial Number - */ - chunk_t authKeySerialNumber; - - /** - * No revocation information available - */ - bool noRevAvail; - - /** - * Signature algorithm (must be identical to sigAlg) - */ - int algorithm; - - /** - * Signature - */ - chunk_t signature; -}; - -/** - * ASN.1 definition of roleSyntax - */ -static const asn1Object_t roleSyntaxObjects[] = -{ - { 0, "roleSyntax", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ - { 1, "roleAuthority", ASN1_CONTEXT_C_0, ASN1_OPT | - ASN1_OBJ }, /* 1 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 2 */ - { 1, "roleName", ASN1_CONTEXT_C_1, ASN1_OBJ } /* 3 */ -}; - -#define ROLE_ROOF 4 - -/** - * ASN.1 definition of an X509 attribute certificate - */ -static const asn1Object_t acObjects[] = -{ - { 0, "AttributeCertificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */ - { 1, "AttributeCertificateInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */ - { 2, "version", ASN1_INTEGER, ASN1_DEF | - ASN1_BODY }, /* 2 */ - { 2, "holder", ASN1_SEQUENCE, ASN1_NONE }, /* 3 */ - { 3, "baseCertificateID", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 4 */ - { 4, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */ - { 4, "serial", ASN1_INTEGER, ASN1_BODY }, /* 6 */ - { 4, "issuerUID", ASN1_BIT_STRING, ASN1_OPT | - ASN1_BODY }, /* 7 */ - { 4, "end opt", ASN1_EOC, ASN1_END }, /* 8 */ - { 3, "end opt", ASN1_EOC, ASN1_END }, /* 9 */ - { 3, "entityName", ASN1_CONTEXT_C_1, ASN1_OPT | - ASN1_OBJ }, /* 10 */ - { 3, "end opt", ASN1_EOC, ASN1_END }, /* 11 */ - { 3, "objectDigestInfo", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 12 */ - { 4, "digestedObjectType", ASN1_ENUMERATED, ASN1_BODY }, /* 13*/ - { 4, "otherObjectTypeID", ASN1_OID, ASN1_OPT | - ASN1_BODY }, /* 14 */ - { 4, "end opt", ASN1_EOC, ASN1_END }, /* 15*/ - { 4, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 16 */ - { 3, "end opt", ASN1_EOC, ASN1_END }, /* 17 */ - { 2, "v2Form", ASN1_CONTEXT_C_0, ASN1_NONE }, /* 18 */ - { 3, "issuerName", ASN1_SEQUENCE, ASN1_OPT | - ASN1_OBJ }, /* 19 */ - { 3, "end opt", ASN1_EOC, ASN1_END }, /* 20 */ - { 3, "baseCertificateID", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 21 */ - { 4, "issuerSerial", ASN1_SEQUENCE, ASN1_NONE }, /* 22 */ - { 5, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 23 */ - { 5, "serial", ASN1_INTEGER, ASN1_BODY }, /* 24 */ - { 5, "issuerUID", ASN1_BIT_STRING, ASN1_OPT | - ASN1_BODY }, /* 25 */ - { 5, "end opt", ASN1_EOC, ASN1_END }, /* 26 */ - { 3, "end opt", ASN1_EOC, ASN1_END }, /* 27 */ - { 3, "objectDigestInfo", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 28 */ - { 4, "digestInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 29 */ - { 5, "digestedObjectType", ASN1_ENUMERATED, ASN1_BODY }, /* 30 */ - { 5, "otherObjectTypeID", ASN1_OID, ASN1_OPT | - ASN1_BODY }, /* 31 */ - { 5, "end opt", ASN1_EOC, ASN1_END }, /* 32 */ - { 5, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 33 */ - { 3, "end opt", ASN1_EOC, ASN1_END }, /* 34 */ - { 2, "signature", ASN1_EOC, ASN1_RAW }, /* 35 */ - { 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 36 */ - { 2, "attrCertValidityPeriod", ASN1_SEQUENCE, ASN1_NONE }, /* 37 */ - { 3, "notBeforeTime", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 38 */ - { 3, "notAfterTime", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 39 */ - { 2, "attributes", ASN1_SEQUENCE, ASN1_LOOP }, /* 40 */ - { 3, "attribute", ASN1_SEQUENCE, ASN1_NONE }, /* 41 */ - { 4, "type", ASN1_OID, ASN1_BODY }, /* 42 */ - { 4, "values", ASN1_SET, ASN1_LOOP }, /* 43 */ - { 5, "value", ASN1_EOC, ASN1_RAW }, /* 44 */ - { 4, "end loop", ASN1_EOC, ASN1_END }, /* 45 */ - { 2, "end loop", ASN1_EOC, ASN1_END }, /* 46 */ - { 2, "extensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 47 */ - { 3, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 48 */ - { 4, "extnID", ASN1_OID, ASN1_BODY }, /* 49 */ - { 4, "critical", ASN1_BOOLEAN, ASN1_DEF | - ASN1_BODY }, /* 50 */ - { 4, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 51 */ - { 2, "end loop", ASN1_EOC, ASN1_END }, /* 52 */ - { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 53 */ - { 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY } /* 54 */ -}; - -#define AC_OBJ_CERTIFICATE 0 -#define AC_OBJ_CERTIFICATE_INFO 1 -#define AC_OBJ_VERSION 2 -#define AC_OBJ_HOLDER_ISSUER 5 -#define AC_OBJ_HOLDER_SERIAL 6 -#define AC_OBJ_ENTITY_NAME 10 -#define AC_OBJ_ISSUER_NAME 19 -#define AC_OBJ_ISSUER 23 -#define AC_OBJ_SIG_ALG 35 -#define AC_OBJ_SERIAL_NUMBER 36 -#define AC_OBJ_NOT_BEFORE 38 -#define AC_OBJ_NOT_AFTER 39 -#define AC_OBJ_ATTRIBUTE_TYPE 42 -#define AC_OBJ_ATTRIBUTE_VALUE 44 -#define AC_OBJ_EXTN_ID 49 -#define AC_OBJ_CRITICAL 50 -#define AC_OBJ_EXTN_VALUE 51 -#define AC_OBJ_ALGORITHM 53 -#define AC_OBJ_SIGNATURE 54 -#define AC_OBJ_ROOF 55 - -/** - * Implements x509ac_t.is_valid - */ -static err_t is_valid(const private_x509ac_t *this, time_t *until) -{ - time_t current_time = time(NULL); - - DBG2(" not before : %T", &this->notBefore); - DBG2(" current time: %T", ¤t_time); - DBG2(" not after : %T", &this->notAfter); - - if (until != NULL && - (*until == UNDEFINED_TIME || this->notAfter < *until)) - { - *until = this->notAfter; - } - if (current_time < this->notBefore) - { - return "is not valid yet"; - } - if (current_time > this->notAfter) - { - return "has expired"; - } - DBG2(" attribute certificate is valid"); - return NULL; -} - -/** - * Implements x509ac_t.is_newer - */ -static bool is_newer(const private_x509ac_t *this, const private_x509ac_t *other) -{ - return this->notBefore > other->notBefore; -} - -/** - * Implements x509ac_t.equals_holder. - */ -static bool equals_holder(const private_x509ac_t *this, const private_x509ac_t *other) -{ - return this->holderIssuer->equals(this->holderIssuer, other->holderIssuer) - && chunk_equals(this->holderSerial, other->holderSerial); -} - -/** - * parses a directoryName - */ -static bool parse_directoryName(chunk_t blob, int level, bool implicit, identification_t **name) -{ - bool has_directoryName; - linked_list_t *list = linked_list_create(); - - x509_parse_generalNames(blob, level, implicit, list); - has_directoryName = list->get_count(list) > 0; - - if (has_directoryName) - { - iterator_t *iterator = list->create_iterator(list, TRUE); - identification_t *directoryName; - bool first = TRUE; - - while (iterator->iterate(iterator, (void**)&directoryName)) - { - if (first) - { - *name = directoryName; - first = FALSE; - } - else - { - DBG1("more than one directory name - first selected"); - directoryName->destroy(directoryName); - } - } - iterator->destroy(iterator); - } - else - { - DBG1("no directoryName found"); - } - - list->destroy(list); - return has_directoryName; -} - -/** - * parses roleSyntax - */ -static void parse_roleSyntax(chunk_t blob, int level0) -{ - asn1_ctx_t ctx; - chunk_t object; - u_int level; - int objectID = 0; - - asn1_init(&ctx, blob, level0, FALSE, FALSE); - while (objectID < ROLE_ROOF) - { - if (!extract_object(roleSyntaxObjects, &objectID, &object, &level, &ctx)) - { - return; - } - - switch (objectID) - { - default: - break; - } - objectID++; - } -} - -/** - * Parses an X.509 attribute certificate - */ -static bool parse_certificate(chunk_t blob, private_x509ac_t *this) -{ - asn1_ctx_t ctx; - bool critical; - chunk_t object; - u_int level; - int objectID = 0; - int type = OID_UNKNOWN; - int extn_oid = OID_UNKNOWN; - - asn1_init(&ctx, blob, 0, FALSE, FALSE); - while (objectID < AC_OBJ_ROOF) - { - if (!extract_object(acObjects, &objectID, &object, &level, &ctx)) - { - return FALSE; - } - - /* those objects which will parsed further need the next higher level */ - level++; - - switch (objectID) - { - case AC_OBJ_CERTIFICATE: - this->certificate = object; - break; - case AC_OBJ_CERTIFICATE_INFO: - this->certificateInfo = object; - break; - case AC_OBJ_VERSION: - this->version = (object.len) ? (1 + (u_int)*object.ptr) : 1; - DBG2(" v%d", this->version); - if (this->version != 2) - { - DBG1("v%d attribute certificates are not supported", this->version); - return FALSE; - } - break; - case AC_OBJ_HOLDER_ISSUER: - if (!parse_directoryName(object, level, FALSE, &this->holderIssuer)) - { - return FALSE; - } - break; - case AC_OBJ_HOLDER_SERIAL: - this->holderSerial = object; - break; - case AC_OBJ_ENTITY_NAME: - if (!parse_directoryName(object, level, TRUE, &this->entityName)) - { - return FALSE; - } - break; - case AC_OBJ_ISSUER_NAME: - if (!parse_directoryName(object, level, FALSE, &this->issuerName)) - { - return FALSE; - } - break; - case AC_OBJ_SIG_ALG: - this->sigAlg = parse_algorithmIdentifier(object, level, NULL); - break; - case AC_OBJ_SERIAL_NUMBER: - this->serialNumber = object; - break; - case AC_OBJ_NOT_BEFORE: - this->notBefore = asn1totime(&object, ASN1_GENERALIZEDTIME); - break; - case AC_OBJ_NOT_AFTER: - this->notAfter = asn1totime(&object, ASN1_GENERALIZEDTIME); - break; - case AC_OBJ_ATTRIBUTE_TYPE: - type = known_oid(object); - break; - case AC_OBJ_ATTRIBUTE_VALUE: - { - switch (type) - { - case OID_AUTHENTICATION_INFO: - DBG2(" need to parse authenticationInfo"); - break; - case OID_ACCESS_IDENTITY: - DBG2(" need to parse accessIdentity"); - break; - case OID_CHARGING_IDENTITY: - ietfAttr_list_create_from_chunk(object, this->charging, level); - break; - case OID_GROUP: - ietfAttr_list_create_from_chunk(object, this->groups, level); - break; - case OID_ROLE: - parse_roleSyntax(object, level); - break; - default: - break; - } - } - break; - case AC_OBJ_EXTN_ID: - extn_oid = known_oid(object); - break; - case AC_OBJ_CRITICAL: - critical = object.len && *object.ptr; - DBG2(" %s",(critical)?"TRUE":"FALSE"); - break; - case AC_OBJ_EXTN_VALUE: - { - switch (extn_oid) - { - case OID_CRL_DISTRIBUTION_POINTS: - DBG2(" need to parse crlDistributionPoints"); - break; - case OID_AUTHORITY_KEY_ID: - x509_parse_authorityKeyIdentifier(object, level, - &this->authKeyID, &this->authKeySerialNumber); - break; - case OID_TARGET_INFORMATION: - DBG2(" need to parse targetInformation"); - break; - case OID_NO_REV_AVAIL: - this->noRevAvail = TRUE; - break; - default: - break; - } - } - break; - case AC_OBJ_ALGORITHM: - this->algorithm = parse_algorithmIdentifier(object, level, NULL); - break; - case AC_OBJ_SIGNATURE: - this->signature = object; - break; - default: - break; - } - objectID++; - } - this->installed = time(NULL); - return TRUE; -} - -/** - * Implementation of x509ac_t.list. - */ -static void list(const private_x509ac_t *this, FILE *out, bool utc) -{ - time_t now = time(NULL); - - fprintf(out, "%#T\n", &this->installed, utc); - - if (this->entityName) - { - fprintf(out, " holder: '%D'\n", this->entityName); - } - if (this->holderIssuer) - { - fprintf(out, " hissuer: '%D'\n", this->holderIssuer); - } - if (this->holderSerial.ptr) - { - fprintf(out, " hserial: %#B\n", &this->holderSerial); - } - - /* list all group attributes on a single line */ - fprintf(out, " groups: "); - ietfAttr_list_list(this->groups, out); - fprintf(out, "\n"); - - fprintf(out, " issuer: '%D'\n", this->issuerName); - fprintf(out, " serial: %#B\n", &this->serialNumber); - - fprintf(out, " validity: not before %#T, ", &this->notBefore, utc); - if (now < this->notBefore) - { - fprintf(out, "not valid yet (valid in %#V)\n", &now, &this->notBefore); - } - else - { - fprintf(out, "ok\n"); - } - - fprintf(out, " not after %#T, ", &this->notAfter, utc); - if (now > this->notAfter) - { - fprintf(out, "expired (%#V ago)\n", &now, &this->notAfter); - } - else - { - fprintf(out, "ok"); - if (now > this->notAfter - ACERT_WARNING_INTERVAL * 60 * 60 * 24) - { - fprintf(out, " (expires in %#V)", &now, &this->notAfter); - } - fprintf(out, " \n"); - } - - if (this->authKeyID.ptr) - { - fprintf(out, " authkey: %#B\n", &this->authKeyID); - } - if (this->authKeySerialNumber.ptr) - { - fprintf(out, " aserial: %#B\n", &this->authKeySerialNumber); - } -} - -/** - * Implements x509ac_t.destroy - */ -static void destroy(private_x509ac_t *this) -{ - DESTROY_IF(this->holderIssuer); - DESTROY_IF(this->entityName); - DESTROY_IF(this->issuerName); - ietfAttr_list_destroy(this->charging); - ietfAttr_list_destroy(this->groups); - free(this->certificate.ptr); - free(this); -} - -/** - * Described in header. - */ -x509ac_t *x509ac_create_from_chunk(chunk_t chunk) -{ - private_x509ac_t *this = malloc_thing(private_x509ac_t); - - /* initialize */ - this->holderIssuer = NULL; - this->entityName = NULL; - this->issuerName = NULL; - this->charging = linked_list_create(); - this->groups = linked_list_create(); - - /* public functions */ - this->public.is_valid = (err_t (*) (const x509ac_t*,time_t*))is_valid; - this->public.is_newer = (bool (*) (const x509ac_t*,const x509ac_t*))is_newer; - this->public.equals_holder = (bool (*) (const x509ac_t*,const x509ac_t*))equals_holder; - this->public.list = (void (*) (const x509ac_t*,FILE*,bool))list; - this->public.destroy = (void (*) (x509ac_t*))destroy; - - if (!parse_certificate(chunk, this)) - { - destroy(this); - return NULL; - } - return &this->public; -} - -/** - * Described in header. - */ -x509ac_t *x509ac_create_from_file(const char *filename) -{ - bool pgp = FALSE; - chunk_t chunk = chunk_empty; - - if (!pem_asn1_load_file(filename, NULL, "attribute certificate", &chunk, &pgp)) - { - return NULL; - } - return x509ac_create_from_chunk(chunk); -} - diff --git a/src/libstrongswan/crypto/ac.h b/src/libstrongswan/crypto/ac.h deleted file mode 100644 index 045c458fb..000000000 --- a/src/libstrongswan/crypto/ac.h +++ /dev/null @@ -1,110 +0,0 @@ -/** - * @file ac.h - * - * @brief Interface of x509ac_t. - * - */ - -/* - * Copyright (C) 2002 Ueli Galizzi, Ariane Seiler - * Copyright (C) 2003 Martin Berner, Lukas Suter - * Copyright (C) 2007 Andreas Steffen - * - * 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 . - * - * 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. - * - * RCSID $Id$ - */ - -#ifndef AC_H_ -#define AC_H_ - -#include - -typedef struct x509ac_t x509ac_t; - -/** - * @brief X.509 attribute certificate. - * - * @b Constructors: - * - x509ac_create_from_chunk() - * - x509ac_create_from_file() - * - * @ingroup crypto - */ -struct x509ac_t { - - /** - * @brief Checks the validity interval of the attribute certificate - * - * @param this certificate being examined - * @param until until = min(until, notAfter) - * @return NULL if the certificate is valid - */ - err_t (*is_valid) (const x509ac_t *this, time_t *until); - - /** @brief Checks if this attr cert is newer than the other attr cert - * - * @param this calling object - * @param other other attr cert object - * @return TRUE if this was issued more recently than other - */ - bool (*is_newer) (const x509ac_t *this, const x509ac_t *other); - - /** - * @brief Checks if two attribute certificates belong to the same holder - * - * @param this calling attribute certificate - * @param that other attribute certificate - * @return TRUE if same holder - */ - bool (*equals_holder) (const x509ac_t *this, const x509ac_t *other); - - /** - * @brief Log the attribute certificate info to out. - * - * @param this calling object - * @param out stream to write to - * @param utc TRUE for UTC times, FALSE for local time - */ - void (*list)(const x509ac_t *this, FILE *out, bool utc); - - /** - * @brief Destroys the attribute certificate. - * - * @param this certificate to destroy - */ - void (*destroy) (x509ac_t *this); -}; - -/** - * @brief Read a x509 attribute certificate from a DER encoded blob. - * - * @param chunk chunk containing DER encoded data - * @return created x509ac_t certificate, or NULL if invalid. - * - * @ingroup crypto - */ -x509ac_t *x509ac_create_from_chunk(chunk_t chunk); - -/** - * @brief Read a x509 attribute certificate from a DER encoded file. - * - * @param filename file containing DER encoded data - * @return created x509ac_t certificate, or NULL if invalid. - * - * @ingroup crypto - */ -x509ac_t *x509ac_create_from_file(const char *filename); - -#endif /* AC_H_ */ - diff --git a/src/libstrongswan/crypto/ca.c b/src/libstrongswan/crypto/ca.c deleted file mode 100644 index 510e3528e..000000000 --- a/src/libstrongswan/crypto/ca.c +++ /dev/null @@ -1,813 +0,0 @@ -/** - * @file ca.c - * - * @brief Implementation of ca_info_t. - * - */ - -/* - * Copyright (C) 2007 Andreas Steffen - * 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 . - * - * 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 -#include -#include -#include -#include - -#include "x509.h" -#include "crl.h" -#include "ca.h" -#include "ac.h" -#include "certinfo.h" -#include "ocsp.h" - -#include -#include -#include -#include -#include - -typedef struct private_ca_info_t private_ca_info_t; - -/** - * Private data of a ca_info_t object. - */ -struct private_ca_info_t { - /** - * Public interface for this ca info record - */ - ca_info_t public; - - /** - * Name of the ca info record - */ - char *name; - - /** - * Time when ca info record was installed - */ - time_t installed; - - /** - * Distinguished Name of the CA - */ - x509_t *cacert; - - /** - * List of attribute certificates - */ - linked_list_t *attrcerts; - - /** - * List of crl URIs - */ - linked_list_t *crluris; - - /** - * List of ocsp URIs - */ - linked_list_t *ocspuris; - - /** - * CRL issued by this ca - */ - crl_t *crl; - - /** - * List of certificate info records - */ - linked_list_t *certinfos; - - /** - * mutex controls access to the elements: - * name, crluris, ocspuris, crl, and certinfos - */ - pthread_mutex_t mutex; -}; - -/** - * static options set by ca_info_set_options() - */ -static strict_t strict_crl_policy = STRICT_NO; -static bool cache_crls = FALSE; -static u_int crl_check_interval = 0; - -/** - * Implements ca_info_t.equals - */ -static bool equals(const private_ca_info_t *this, const private_ca_info_t *that) -{ - return chunk_equals(this->cacert->get_keyid(this->cacert), - that->cacert->get_keyid(that->cacert)); -} - -/** - * Implements ca_info_t.equals_name_release_info - */ -static bool equals_name_release_info(private_ca_info_t *this, const char *name) -{ - bool found; - - pthread_mutex_lock(&(this->mutex)); - found = this->name != NULL && streq(this->name, name); - - if (found) - { - this->crluris->destroy_offset(this->crluris, - offsetof(identification_t, destroy)); - this->crluris = linked_list_create(); - - this->ocspuris->destroy_offset(this->ocspuris, - offsetof(identification_t, destroy)); - this->ocspuris = linked_list_create(); - - free(this->name); - this->name = NULL; - } - - pthread_mutex_unlock(&(this->mutex)); - return found; -} - -/** - * Implements ca_info_t.is_crl_issuer - */ -static bool is_cert_issuer(private_ca_info_t *this, const x509_t *cert) -{ - return cert->is_issuer(cert, this->cacert); -} - -/** - * Implements ca_info_t.is_crl_issuer - */ -static bool is_crl_issuer(private_ca_info_t *this, const crl_t *crl) -{ - return crl->is_issuer(crl, this->cacert); -} - -/** - * Implements ca_info_t.is_ca - */ -static bool is_ca(private_ca_info_t *this) -{ - return this->cacert->is_ca(this->cacert); -} - -/** - * Implements ca_info_t.is_strict - */ -static bool is_strict(private_ca_info_t *this) -{ - bool strict = strict_crl_policy != STRICT_NO; - - if (strict_crl_policy == STRICT_IFURI) - { - pthread_mutex_lock(&(this->mutex)); - strict = this->crluris->get_count(this->crluris) > 0 || - this->ocspuris->get_count(this->ocspuris) > 0; - pthread_mutex_unlock(&(this->mutex)); - } - return strict; -} - -/** - * Implements ca_info_t.has_crl - */ -static bool has_crl(private_ca_info_t *this) -{ - bool found; - - pthread_mutex_lock(&(this->mutex)); - found = this->crl != NULL; - pthread_mutex_unlock(&(this->mutex)); - - return found; -} - -/** - * Implements ca_info_t.has_certinfos - */ -static bool has_certinfos(private_ca_info_t *this) -{ - bool found; - - pthread_mutex_lock(&(this->mutex)); - found = this->certinfos->get_count(this->certinfos) > 0; - pthread_mutex_unlock(&(this->mutex)); - - return found; -} - -/** - * Implements ca_info_t.add_crl - */ -static void add_crl(private_ca_info_t *this, crl_t *crl) -{ - pthread_mutex_lock(&(this->mutex)); - - if (this->crl) - { - if (crl->is_newer(crl, this->crl)) - { - this->crl->destroy(this->crl); - this->crl = crl; - DBG1(" this crl is newer - existing crl replaced"); - } - else - { - crl->destroy(crl); - DBG1(" this crl is not newer - existing crl retained"); - } - } - else - { - this->crl = crl; - DBG2(" crl added"); - } - - pthread_mutex_unlock(&(this->mutex)); -} - -/** - * Implements ca_info_t.list_crl - */ -static void list_crl(private_ca_info_t *this, FILE *out, bool utc) -{ - pthread_mutex_lock(&this->mutex); - this->crl->list(this->crl, out, utc); - pthread_mutex_unlock(&this->mutex); -} - -/** - * Implements ca_info_t.list_certinfos - */ -static void list_certinfos(private_ca_info_t *this, FILE *out, bool utc) -{ - iterator_t *iterator; - certinfo_t *certinfo; - chunk_t authkey; - - pthread_mutex_lock(&this->mutex); - - authkey = this->cacert->get_subjectKeyID(this->cacert); - fprintf(out," authname: '%D'\n", this->cacert->get_subject(this->cacert)); - fprintf(out," authkey: %#B\n", &authkey); - - iterator = this->certinfos->create_iterator(this->certinfos, TRUE); - while (iterator->iterate(iterator, (void**)&certinfo)) - { - time_t nextUpdate, thisUpdate, now; - chunk_t serial; - - now = time(NULL); - nextUpdate = certinfo->get_nextUpdate(certinfo); - thisUpdate = certinfo->get_thisUpdate(certinfo); - serial = certinfo->get_serialNumber(certinfo); - - fprintf(out, "%#T, until %#T, ", &thisUpdate, utc, &nextUpdate, utc); - if (now > nextUpdate) - { - fprintf(out, "expired (%#V ago)\n", &now, &nextUpdate); - } - else - { - fprintf(out, "ok (expires in %#V)\n", &now, &nextUpdate); - } - fprintf(out, " serial: %#B, %N\n", &serial, - cert_status_names, certinfo->get_status(certinfo)); - } - iterator->destroy(iterator); - - pthread_mutex_unlock(&this->mutex); -} - -/** - * Find an exact copy of an identification in a linked list - */ -static identification_t* find_identification(linked_list_t *list, identification_t *id) -{ - identification_t *found_id = NULL, *current_id; - - iterator_t *iterator = list->create_iterator(list, TRUE); - - while (iterator->iterate(iterator, (void**)¤t_id)) - { - if (id->equals(id, current_id)) - { - found_id = current_id; - break; - } - } - iterator->destroy(iterator); - - return found_id; -} - -/** - * Add a unique identification to a linked list - */ -static identification_t *add_identification(linked_list_t *list, identification_t *id) -{ - identification_t *found_id = find_identification(list, id); - - if (found_id) - { - id->destroy(id); - return found_id; - } - else - { - list->insert_last(list, (void*)id); - return id; - } -} - -/** - * Implements ca_info_t.add_crluri - */ -static void add_crluri(private_ca_info_t *this, chunk_t uri) -{ - if (uri.len < 6 || - (strncasecmp(uri.ptr, "http", 4) != 0 && - strncasecmp(uri.ptr, "ldap", 4) != 0 && - strncasecmp(uri.ptr, "file", 4) != 0 && - strncasecmp(uri.ptr, "ftp", 3) != 0)) - { - DBG1(" invalid crl uri '%.*s'", uri.len, uri.ptr); - return; - } - else - { - identification_t *crluri = identification_create_from_encoding(ID_DER_ASN1_GN_URI, uri); - - pthread_mutex_lock(&(this->mutex)); - add_identification(this->crluris, crluri); - pthread_mutex_unlock(&(this->mutex)); - } -} - -/** - * Implements ca_info_t.add_ocspuri - */ -static void add_ocspuri(private_ca_info_t *this, chunk_t uri) -{ - if (uri.len < 7 || strncasecmp(uri.ptr, "http", 4) != 0) - { - DBG1(" invalid ocsp uri '%.*s'", uri.len, uri.ptr); - return; - } - else - { - identification_t *ocspuri = identification_create_from_encoding(ID_DER_ASN1_GN_URI, uri); - - pthread_mutex_lock(&(this->mutex)); - add_identification(this->ocspuris, ocspuri); - pthread_mutex_unlock(&(this->mutex)); - } -} - -/** - * Implements ca_info_t.add_info. - */ -void add_info (private_ca_info_t *this, const private_ca_info_t *that) -{ - pthread_mutex_lock(&(this->mutex)); - - if (this->name == NULL && that->name != NULL) - { - this->name = strdup(that->name); - } - - pthread_mutex_unlock(&(this->mutex)); - - { - identification_t *uri; - - iterator_t *iterator = that->crluris->create_iterator(that->crluris, TRUE); - - while (iterator->iterate(iterator, (void**)&uri)) - { - if (uri->get_type(uri) == ID_DER_ASN1_GN_URI) - { - add_crluri(this, uri->get_encoding(uri)); - } - } - iterator->destroy(iterator); - } - - { - identification_t *uri; - - iterator_t *iterator = that->ocspuris->create_iterator(that->ocspuris, TRUE); - - while (iterator->iterate(iterator, (void**)&uri)) - { - if (uri->get_type(uri) == ID_DER_ASN1_GN_URI) - { - add_ocspuri(this, uri->get_encoding(uri)); - } - } - iterator->destroy(iterator); - } -} - -/** - * Implements ca_info_t.get_certificate. - */ -static x509_t* get_certificate(private_ca_info_t* this) -{ - return this->cacert; -} - -/** - * caches a crl by saving it to a given crl directory - */ -void cache_crl(private_ca_info_t* this, const char *crl_dir, crl_t *crl) -{ - char buffer[BUF_LEN]; - char *path; - char *pos = buffer; - int len = BUF_LEN; - int n; - - chunk_t authKeyID = this->cacert->get_subjectKeyID(this->cacert); - chunk_t uri; - - uri.ptr = buffer; - uri.len = 7 + strlen(crl_dir) + 1 + 2*authKeyID.len + 4; - - if (uri.len >= BUF_LEN) - { - DBG1("file uri exceeds buffer length of %d bytes - crl not saved", BUF_LEN); - return; - } - - /* print the file uri prefix */ - n = snprintf(pos, len, "file://"); - pos += n; len -= n; - - /* remember the start of the path string */ - path = pos; - - /* print the default crl directory path */ - n = snprintf(pos, len, "%s/", crl_dir); - pos += n; len -= n; - - /* create and print a unique crl filename derived from the authKeyID */ - while (authKeyID.len-- > 0) - { - n = snprintf(pos, len, "%02x", *authKeyID.ptr++); - pos += n; len -= n; - } - - /* add the file suffix */ - n = snprintf(pos, len, ".crl"); - - if (crl->write_to_file(crl, path, 0022, TRUE)) - { - identification_t *crluri = identification_create_from_encoding(ID_DER_ASN1_GN_URI, uri); - - add_identification(this->crluris, crluri); - } -} - -/** - * Implements ca_info_t.verify_by_crl. - */ -static cert_status_t verify_by_crl(private_ca_info_t* this, certinfo_t *certinfo, - const char *crl_dir) -{ - rsa_public_key_t *issuer_public_key = this->cacert->get_public_key(this->cacert); - bool stale; - - pthread_mutex_lock(&(this->mutex)); - if (this->crl == NULL) - { - stale = TRUE; - DBG1("no crl is locally available"); - } - else - { - stale = !this->crl->is_valid(this->crl); - DBG1("crl is %s", stale? "stale":"valid"); - } - - if (stale && crl_check_interval > 0) - { - iterator_t *iterator = this->crluris->create_iterator(this->crluris, TRUE); - identification_t *uri; - - while (iterator->iterate(iterator, (void**)&uri)) - { - fetcher_t *fetcher; - char uri_string[BUF_LEN]; - chunk_t uri_chunk = uri->get_encoding(uri); - chunk_t response_chunk; - - snprintf(uri_string, BUF_LEN, "%.*s", uri_chunk.len, uri_chunk.ptr); - fetcher = fetcher_create(uri_string); - - response_chunk = fetcher->get(fetcher); - fetcher->destroy(fetcher); - if (response_chunk.ptr != NULL) - { - crl_t *crl = crl_create_from_chunk(response_chunk); - - if (crl == NULL) - { - free(response_chunk.ptr); - continue; - } - if (!is_crl_issuer(this, crl)) - { - DBG1(" fetched crl has wrong issuer"); - crl->destroy(crl); - continue; - } - if (!crl->verify(crl, issuer_public_key)) - { - DBG1("fetched crl signature is invalid"); - crl->destroy(crl); - continue; - } - DBG2("fetched crl signature is valid"); - - if (this->crl == NULL) - { - this->crl = crl; - } - else if (crl->is_newer(crl, this->crl)) - { - this->crl->destroy(this->crl); - this->crl = crl; - DBG1("this crl is newer - existing crl replaced"); - } - else - { - crl->destroy(crl); - DBG1("this crl is not newer - existing crl retained"); - continue; - } - if (crl->is_valid(crl)) - { - if (cache_crls && strncasecmp(uri_string, "file", 4) != 0) - { - cache_crl(this, crl_dir, crl); - } - /* we found a valid crl and therefore exit the fetch loop */ - break; - } - else - { - DBG1("fetched crl is stale"); - } - } - } - iterator->destroy(iterator); - } - - if (this->crl) - { - if (!this->crl->verify(this->crl, issuer_public_key)) - { - DBG1("crl signature is invalid"); - goto ret; - } - DBG2("crl signature is valid"); - - this->crl->get_status(this->crl, certinfo); - } - -ret: - pthread_mutex_unlock(&(this->mutex)); - return certinfo->get_status(certinfo); -} - -/** - * Implements ca_info_t.verify_by_ocsp. - */ -static cert_status_t verify_by_ocsp(private_ca_info_t* this, - certinfo_t *certinfo, - credential_store_t *credentials) -{ - bool stale; - iterator_t *iterator; - certinfo_t *cached_certinfo = NULL; - int comparison = 1; - - pthread_mutex_lock(&(this->mutex)); - - /* do we support OCSP at all? */ - if (this->ocspuris->get_count(this->ocspuris) == 0) - { - goto ret; - } - - iterator = this->certinfos->create_iterator(this->certinfos, TRUE); - - /* find the list insertion point in alphabetical order */ - while(iterator->iterate(iterator, (void**)&cached_certinfo)) - { - comparison = certinfo->compare_serialNumber(certinfo, cached_certinfo); - - if (comparison <= 0) - { - break; - } - } - - /* do we have a valid certinfo_t for this serial number in our cache? */ - if (comparison == 0) - { - stale = cached_certinfo->get_nextUpdate(cached_certinfo) < time(NULL); - DBG1("ocsp status in cache is %s", stale ? "stale":"fresh"); - } - else - { - stale = TRUE; - DBG1("ocsp status is not in cache"); - } - - if (stale) - { - ocsp_t *ocsp; - - ocsp = ocsp_create(this->cacert, this->ocspuris); - ocsp->fetch(ocsp, certinfo, credentials); - if (certinfo->get_status(certinfo) != CERT_UNDEFINED) - { - if (comparison != 0) - { - cached_certinfo = certinfo_create(certinfo->get_serialNumber(certinfo)); - - if (comparison > 0) - { - this->certinfos->insert_last(this->certinfos, (void *)cached_certinfo); - } - else - { - iterator->insert_before(iterator, (void *)cached_certinfo); - } - } - cached_certinfo->update(cached_certinfo, certinfo); - } - ocsp->destroy(ocsp); - } - else - { - certinfo->update(certinfo, cached_certinfo); - } - - iterator->destroy(iterator); - -ret: - pthread_mutex_unlock(&(this->mutex)); - return certinfo->get_status(certinfo); -} - -/** - * Implements ca_info_t.purge_ocsp - */ -static void purge_ocsp(private_ca_info_t *this) -{ - pthread_mutex_lock(&(this->mutex)); - - this->certinfos->destroy_offset(this->certinfos, - offsetof(certinfo_t, destroy)); - this->certinfos = linked_list_create(); - - pthread_mutex_unlock(&(this->mutex)); -} - -/** - * Implements ca_info_t.destroy - */ -static void destroy(private_ca_info_t *this) -{ - this->attrcerts->destroy_offset(this->attrcerts, - offsetof(x509ac_t, destroy)); - this->crluris->destroy_offset(this->crluris, - offsetof(identification_t, destroy)); - this->ocspuris->destroy_offset(this->ocspuris, - offsetof(identification_t, destroy)); - this->certinfos->destroy_offset(this->certinfos, - offsetof(certinfo_t, destroy)); - DESTROY_IF(this->crl); - free(this->name); - free(this); -} - -/** - * list the info of this CA - */ -static void list(private_ca_info_t* this, FILE* out, bool utc) -{ - chunk_t chunk; - identification_t *uri; - iterator_t *iterator; - bool first; - - pthread_mutex_lock(&(this->mutex)); - fprintf(out, "%#T", &this->installed, utc); - - if (this->name) - { - fprintf(out, ", \"%s\"\n", this->name); - } - else - { - fprintf(out, "\n"); - } - - fprintf(out, " authname: '%D'\n", this->cacert->get_subject(this->cacert)); - chunk = this->cacert->get_subjectKeyID(this->cacert); - fprintf(out, " authkey: %#B\n", &chunk); - chunk = this->cacert->get_keyid(this->cacert); - fprintf(out, " keyid: %#B\n", &chunk); - - first = TRUE; - iterator = this->crluris->create_iterator(this->crluris, TRUE); - while (iterator->iterate(iterator, (void**)&uri)) - { - fprintf(out, " %s '%D'\n", first ? "crluris:":" ", uri); - first = FALSE; - } - iterator->destroy(iterator); - - first = TRUE; - iterator = this->ocspuris->create_iterator(this->ocspuris, TRUE); - while (iterator->iterate(iterator, (void**)&uri)) - { - fprintf(out, " %s '%D'\n", first ? "ocspuris:":" ", uri); - first = FALSE; - } - iterator->destroy(iterator); - pthread_mutex_unlock(&(this->mutex)); -} - -/* - * Described in header. - */ -void ca_info_set_options(strict_t strict, bool cache, u_int interval) -{ - strict_crl_policy = strict; - cache_crls = cache; - crl_check_interval = interval; -} - -/* - * Described in header. - */ -ca_info_t *ca_info_create(const char *name, x509_t *cacert) -{ - private_ca_info_t *this = malloc_thing(private_ca_info_t); - - /* initialize */ - this->installed = time(NULL); - this->name = (name == NULL)? NULL:strdup(name); - this->cacert = cacert; - this->attrcerts = linked_list_create(); - this->crluris = linked_list_create(); - this->ocspuris = linked_list_create(); - this->certinfos = linked_list_create(); - this->crl = NULL; - - /* initialize the mutex */ - pthread_mutex_init(&(this->mutex), NULL); - - /* public functions */ - this->public.equals = (bool (*) (const ca_info_t*,const ca_info_t*))equals; - this->public.equals_name_release_info = (bool (*) (ca_info_t*,const char*))equals_name_release_info; - this->public.is_cert_issuer = (bool (*) (ca_info_t*,const x509_t*))is_cert_issuer; - this->public.is_crl_issuer = (bool (*) (ca_info_t*,const crl_t*))is_crl_issuer; - this->public.is_ca = (bool (*) (ca_info_t*))is_ca; - this->public.is_strict = (bool (*) (ca_info_t*))is_strict; - this->public.add_info = (void (*) (ca_info_t*,const ca_info_t*))add_info; - this->public.add_crl = (void (*) (ca_info_t*,crl_t*))add_crl; - this->public.has_crl = (bool (*) (ca_info_t*))has_crl; - this->public.has_certinfos = (bool (*) (ca_info_t*))has_certinfos; - this->public.list = (void (*) (ca_info_t*,FILE*,bool))list; - this->public.list_crl = (void (*) (ca_info_t*,FILE*,bool))list_crl; - this->public.list_certinfos = (void (*) (ca_info_t*,FILE*,bool))list_certinfos; - this->public.add_crluri = (void (*) (ca_info_t*,chunk_t))add_crluri; - this->public.add_ocspuri = (void (*) (ca_info_t*,chunk_t))add_ocspuri; - this->public.get_certificate = (x509_t* (*) (ca_info_t*))get_certificate; - this->public.verify_by_crl = (cert_status_t (*) (ca_info_t*,certinfo_t*, const char*))verify_by_crl; - this->public.verify_by_ocsp = (cert_status_t (*) (ca_info_t*,certinfo_t*,credential_store_t*))verify_by_ocsp; - this->public.purge_ocsp = (void (*) (ca_info_t*))purge_ocsp; - this->public.destroy = (void (*) (ca_info_t*))destroy; - - return &this->public; -} diff --git a/src/libstrongswan/crypto/ca.h b/src/libstrongswan/crypto/ca.h deleted file mode 100644 index ff6271b15..000000000 --- a/src/libstrongswan/crypto/ca.h +++ /dev/null @@ -1,243 +0,0 @@ -/** - * @file ca.h - * - * @brief Interface of ca_info_t. - * - */ - -/* - * Copyright (C) 2007 Andreas Steffen - * 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 . - * - * 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 CA_H_ -#define CA_H_ - -typedef struct ca_info_t ca_info_t; - -#include - -#include "x509.h" -#include "crl.h" - -#define MAX_CA_PATH_LEN 7 - -/*forward declaration */ -struct credential_store_t; - -/** - * @brief X.509 certification authority information record - * - * @b Constructors: - * - ca_info_create() - * - * @ingroup transforms - */ -struct ca_info_t { - - /** - * @brief Compare two ca info records - * - * Comparison is done via the keyid of the ca certificate - * - * @param this first ca info object - * @param that second ca info objct - * @return TRUE if a match is found - */ - bool (*equals) (const ca_info_t *this, const ca_info_t* that); - - /** - * @brief If the ca info record has the same name then release the name and URIs - * - * @param this ca info object - * @return TRUE if a match is found - */ - bool (*equals_name_release_info) (ca_info_t *this, const char *name); - - /** - * @brief Checks if a certificate was issued by this ca - * - * @param this ca info object - * @param cert certificate to be checked - * @return TRUE if the issuing ca has been found - */ - bool (*is_cert_issuer) (ca_info_t *this, const x509_t *cert); - - /** - * @brief Checks if a crl was issued by this ca - * - * @param this ca info object - * @param crl crl to be checked - * @return TRUE if the issuing ca has been found - */ - bool (*is_crl_issuer) (ca_info_t *this, const crl_t *crl); - - /** - * @brief Checks if the ca certificate has the isCA flag set - * - * @param this ca info object - * @return TRUE if the isCA flag is set - */ - bool (*is_ca) (ca_info_t *this); - - /** - * @brief Checks if the ca enforces a strict crl policy - * - * @param this ca info object - * @return TRUE if the crl policy is strict - */ - bool (*is_strict) (ca_info_t *this); - - /** - * @brief Merges info from a secondary ca info object - * - * @param this primary ca info object - * @param that secondary ca info object - */ - void (*add_info) (ca_info_t *this, const ca_info_t *that); - - /** - * @brief Adds a new or replaces an obsoleted CRL - * - * @param this ca info object - * @param crl crl to be added - */ - void (*add_crl) (ca_info_t *this, crl_t *crl); - - /** - * @brief Does the CA have a CRL? - * - * @param this ca info object - * @return TRUE if crl is available - */ - bool (*has_crl) (ca_info_t *this); - - /** - * @brief Does the CA have OCSP certinfos? - * - * @param this ca info object - * @return TRUE if there are any certinfos - */ - bool (*has_certinfos) (ca_info_t *this); - - /** - * @brief Print the CA info onto the console - * - * @param this ca info object - * @param out output stream - * @param utc TRUE - utc - FALSE - local time - */ - void (*list) (ca_info_t *this, FILE *out, bool utc); - - /** - * @brief List the CRL onto the console - * - * @param this ca info object - * @param out output stream - * @param utc TRUE - utc - FALSE - local time - */ - void (*list_crl) (ca_info_t *this, FILE *out, bool utc); - - /** - * @brief List the OCSP certinfos onto the console - * - * @param this ca info object - * @param out output stream - * @param utc TRUE - utc - FALSE - local time - */ - void (*list_certinfos) (ca_info_t *this, FILE *out, bool utc); - - /** - * @brief Adds a CRL URI to a list - * - * @param this ca info object - * @param uri crl uri to be added - */ - void (*add_crluri) (ca_info_t *this, chunk_t uri); - - /** - * @brief Adds a OCSP URI to a list - * - * @param this ca info object - * @param uri ocsp uri to be added - */ - void (*add_ocspuri) (ca_info_t *this, chunk_t uri); - - /** - * @brief Get the ca certificate - * - * @param this ca info object - * @return ca certificate - */ - x509_t* (*get_certificate) (ca_info_t *this); - - /** - * @brief Verify the status of a certificate by CRL - * - * @param this ca info object - * @param certinfo detailed certificate status information - * @param crl_dir directory where fetched crls should be stored - * @return certificate status - */ - cert_status_t (*verify_by_crl) (ca_info_t *this, certinfo_t *certinfo, const char *crl_dir); - - /** - * @brief Verify the status of a certificate by OCSP - * - * @param this ca info object - * @param certinfo detailed certificate status information - * @param credentials credential store needed for trust path verification - * @return certificate status - */ - cert_status_t (*verify_by_ocsp) (ca_info_t* this, certinfo_t* certinfo, struct credential_store_t* credentials); - - /** - * @brief Purge the OCSP certinfos of a ca info record - * - * @param this ca info object - */ - void (*purge_ocsp) (ca_info_t *this); - - /** - * @brief Destroys a ca info record - * - * @param this ca info to destroy - */ - void (*destroy) (ca_info_t *this); -}; - -/** - * @brief Set ca info options - * - * @param cache TRUE if crls shall be cached by storing them - * @param interval crl_check_interval to be set in seconds - * - * @ingroup crypto - */ -void ca_info_set_options(strict_t strict, bool cache, u_int interval); - -/** - * @brief Create a ca info record - * - * @param name name of the ca info record - * @param cacert path to the ca certificate - * @return created ca_info_t, or NULL if invalid. - * - * @ingroup crypto - */ -ca_info_t *ca_info_create(const char *name, x509_t *cacert); - -#endif /* CA_H_ */ diff --git a/src/libstrongswan/crypto/certinfo.c b/src/libstrongswan/crypto/certinfo.c deleted file mode 100644 index 8a125e247..000000000 --- a/src/libstrongswan/crypto/certinfo.c +++ /dev/null @@ -1,257 +0,0 @@ -/** - * @file certinfo.c - * - * @brief Implementation of certinfo_t. - * - */ - -/* - * Copyright (C) 2006 Andreas Steffen - * 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 . - * - * 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 -#include - -#include - -#include "certinfo.h" - -typedef struct private_certinfo_t private_certinfo_t; - -/** - * Private data of a certinfo_t object. - */ -struct private_certinfo_t { - /** - * Public interface for this certificate status information object. - */ - certinfo_t public; - - /** - * Serial number of the certificate - */ - chunk_t serialNumber; - - /** - * Certificate status - */ - cert_status_t status; - - /** - * Certificate status is for one-time use only - */ - bool once; - - /** - * Time when the certificate status info was generated - */ - time_t thisUpdate; - - /** - * Time when an updated certifcate status info will be available - */ - time_t nextUpdate; - - /** - * Time of certificate revocation - */ - time_t revocationTime; - - /** - * Reason of certificate revocation - */ - crl_reason_t revocationReason; -}; - -ENUM(cert_status_names, CERT_GOOD, CERT_UNTRUSTED, - "good", - "revoked", - "unknown", - "unknown", - "untrusted", -); - -ENUM(crl_reason_names, REASON_UNSPECIFIED, REASON_REMOVE_FROM_CRL, - "unspecified", - "key compromise", - "ca compromise", - "affiliation changed", - "superseded", - "cessation of operation", - "certificate hold", - "reason #7", - "remove from crl", -); - -/** - * Implements certinfo_t.compare_serialNumber - */ -static int compare_serialNumber(const private_certinfo_t *this, const private_certinfo_t *that) -{ - return chunk_compare(this->serialNumber, that->serialNumber); -} - -/** - * Implements certinfo_t.equals_serialNumber - */ -static bool equals_serialNumber(const private_certinfo_t *this, const private_certinfo_t *that) -{ - return chunk_equals(this->serialNumber, that->serialNumber); -} - -/** - * Implements certinfo_t.get_serialNumber - */ -static chunk_t get_serialNumber(const private_certinfo_t *this) -{ - return this->serialNumber; -} - -/** - * Implements certinfo_t.set_status - */ -static void set_status(private_certinfo_t *this, cert_status_t status) -{ - this->status = status; -} - -/** - * Implements certinfo_t.get_status - */ -static cert_status_t get_status(const private_certinfo_t *this) -{ - return this->status; -} - -/** - * Implements certinfo_t.set_thisUpdate - */ -static void set_thisUpdate(private_certinfo_t *this, time_t thisUpdate) -{ - this->thisUpdate = thisUpdate; -} - -/** - * Implements certinfo_t.get_thisUpdate - */ -static time_t get_thisUpdate(const private_certinfo_t *this) -{ - return this->thisUpdate; -} - -/** - * Implements certinfo_t.set_nextUpdate - */ -static void set_nextUpdate(private_certinfo_t *this, time_t nextUpdate) -{ - this->nextUpdate = nextUpdate; -} - -/** - * Implements certinfo_t.get_nextUpdate - */ -static time_t get_nextUpdate(const private_certinfo_t *this) -{ - return this->nextUpdate; -} - -/** - * Implements certinfo_t.set_revocationTime - */ -static void set_revocationTime(private_certinfo_t *this, time_t revocationTime) -{ - this->revocationTime = revocationTime; -} - -/** - * Implements certinfo_t.get_revocationTime - */ -static time_t get_revocationTime(const private_certinfo_t *this) -{ - return this->revocationTime; -} - -/** - * Implements certinfo_t.set_revocationReason - */ -static void set_revocationReason(private_certinfo_t *this, crl_reason_t reason) -{ - this->revocationReason = reason; -} - -/** - * Implements certinfo_t.get_revocationReason - */ -static crl_reason_t get_revocationReason(const private_certinfo_t *this) -{ - return this->revocationReason; -} - -/** - * Implements certinfo_t.update - */ -static void update(private_certinfo_t *this, const private_certinfo_t *that) -{ - if (equals_serialNumber(this, that)) - { - chunk_t this_serialNumber = this->serialNumber; - - *this = *that; - this->serialNumber = this_serialNumber; - } -} - -/** - * Implements certinfo_t.destroy - */ -static void destroy(private_certinfo_t *this) -{ - free(this->serialNumber.ptr); - free(this); -} - -/* - * Described in header. - */ -certinfo_t *certinfo_create(chunk_t serial) -{ - private_certinfo_t *this = malloc_thing(private_certinfo_t); - - /* initialize */ - this->serialNumber = chunk_clone(serial); - this->status = CERT_UNDEFINED; - this->thisUpdate = UNDEFINED_TIME; - this->nextUpdate = UNDEFINED_TIME; - this->revocationTime = UNDEFINED_TIME; - this->revocationReason = REASON_UNSPECIFIED; - - /* public functions */ - this->public.compare_serialNumber = (int (*) (const certinfo_t*,const certinfo_t*))compare_serialNumber; - this->public.equals_serialNumber = (bool (*) (const certinfo_t*,const certinfo_t*))equals_serialNumber; - this->public.get_serialNumber = (chunk_t (*) (const certinfo_t*))get_serialNumber; - this->public.set_status = (void (*) (certinfo_t*,cert_status_t))set_status; - this->public.get_status = (cert_status_t (*) (const certinfo_t*))get_status; - this->public.set_thisUpdate = (void (*) (certinfo_t*,time_t))set_thisUpdate; - this->public.get_thisUpdate = (time_t (*) (const certinfo_t*))get_thisUpdate; - this->public.set_nextUpdate = (void (*) (certinfo_t*,time_t))set_nextUpdate; - this->public.get_nextUpdate = (time_t (*) (const certinfo_t*))get_nextUpdate; - this->public.set_revocationTime = (void (*) (certinfo_t*,time_t))set_revocationTime; - this->public.get_revocationTime = (time_t (*) (const certinfo_t*))get_revocationTime; - this->public.set_revocationReason = (void (*) (certinfo_t*, crl_reason_t))set_revocationReason; - this->public.get_revocationReason = (crl_reason_t(*) (const certinfo_t*))get_revocationReason; - this->public.update = (void (*) (certinfo_t*, const certinfo_t*))update; - this->public.destroy = (void (*) (certinfo_t*))destroy; - - return &this->public; -} diff --git a/src/libstrongswan/crypto/certinfo.h b/src/libstrongswan/crypto/certinfo.h deleted file mode 100644 index 476befda8..000000000 --- a/src/libstrongswan/crypto/certinfo.h +++ /dev/null @@ -1,203 +0,0 @@ -/** - * @file certinfo.h - * - * @brief Interface of certinfo_t. - * - */ - -/* - * Copyright (C) 2006 Andreas Steffen - * 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 . - * - * 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 CERTINFO_H_ -#define CERTINFO_H_ - -typedef enum cert_status_t cert_status_t; -typedef enum crl_reason_t crl_reason_t; -typedef struct certinfo_t certinfo_t; - -#include - -/** - * RFC 2560 OCSP - certificate status - */ -enum cert_status_t { - CERT_GOOD = 0, - CERT_REVOKED = 1, - CERT_UNKNOWN = 2, - CERT_UNDEFINED = 3, - CERT_UNTRUSTED = 4 /* private use */ -}; - -extern enum_name_t *cert_status_names; - -/** - * RFC 2459 CRL reason codes - */ -enum crl_reason_t { - REASON_UNSPECIFIED = 0, - REASON_KEY_COMPROMISE = 1, - REASON_CA_COMPROMISE = 2, - REASON_AFFILIATION_CHANGED = 3, - REASON_SUPERSEDED = 4, - REASON_CESSATION_OF_OPERATON = 5, - REASON_CERTIFICATE_HOLD = 6, - REASON_REMOVE_FROM_CRL = 8 -}; - -extern enum_name_t *crl_reason_names; - -/** - * @brief X.509 certificate status information - * - * @ingroup transforms - */ -struct certinfo_t { - - /** - * @brief Check if both certinfo objects have the same serialNumber. - * - * @param this calling object - * @param that second certinfo_t object - * @return TRUE if the same serialNumber - */ - bool (*equals_serialNumber) (const certinfo_t *this, const certinfo_t *that); - - /** - * @brief Compares two serial numbers. - * - * @param this calling object - * @param that second certinfo_t object - * @return negative if this is smaller than that - * zero if this equals that - * positive if this is greater than that - */ - int (*compare_serialNumber) (const certinfo_t *this, const certinfo_t *that); - - /** - * @brief Get serial number. - * - * @param this calling object - * @return serialNumber - */ - chunk_t (*get_serialNumber) (const certinfo_t *this); - - /** - * @brief Set certificate status. - * - * @param this calling object - * @param status status - */ - void (*set_status) (certinfo_t *this, cert_status_t status); - - /** - * @brief Get certificate status. - * - * @param this calling object - * @return status - */ - cert_status_t (*get_status) (const certinfo_t *this); - - /** - * @brief Set thisUpdate. - * - * @param this calling object - * @param thisUpdate thisUpdate - */ - void (*set_thisUpdate) (certinfo_t *this, time_t thisUpdate); - - /** - * @brief Get thisUpdate. - * - * @param this calling object - * @return thisUpdate - */ - time_t (*get_thisUpdate) (const certinfo_t *this); - - /** - * @brief Set nextUpdate. - * - * @param this calling object - * @param nextUpdate - */ - void (*set_nextUpdate) (certinfo_t *this, time_t nextUpdate); - - /** - * @brief Get nextUpdate. - * - * @param this calling object - * @return nextUpdate - */ - time_t (*get_nextUpdate) (const certinfo_t *this); - - /** - * @brief Set revocationTime. - * - * @param this calling object - * @param revocationTime revocationTime - */ - void (*set_revocationTime) (certinfo_t *this, time_t revocationTime); - - /** - * @brief Get revocationTime. - * - * @param this calling object - * @return revocationTime - */ - time_t (*get_revocationTime) (const certinfo_t *this); - - /** - * @brief Set revocationReason. - * - * @param this calling object - * @param reason revocationReason - */ - void (*set_revocationReason) (certinfo_t *this, crl_reason_t reason); - - /** - * @brief Get revocationReason. - * - * @param this calling object - * @return revocationReason - */ - crl_reason_t (*get_revocationReason) (const certinfo_t *this); - - /** - * @brief Set revocationReason. - * - * @param this calling object to be updated - * @param that object containing updated information - */ - void (*update) (certinfo_t *this, const certinfo_t *that); - - /** - * @brief Destroys the certinfo_t object. - * - * @param this certinfo_t to destroy - */ - void (*destroy) (certinfo_t *this); - -}; - -/** - * @brief Create a certinfo_t object. - * - * @param serial chunk serial number of the certificate - * @return created certinfo_t object - * - * @ingroup transforms - */ -certinfo_t *certinfo_create(chunk_t serial); - -#endif /* CERTINFO_H_ */ diff --git a/src/libstrongswan/crypto/crl.c b/src/libstrongswan/crypto/crl.c deleted file mode 100755 index 024d96239..000000000 --- a/src/libstrongswan/crypto/crl.c +++ /dev/null @@ -1,536 +0,0 @@ -/** - * @file crl.c - * - * @brief Implementation of crl_t. - * - */ - -/* - * Copyright (C) 2006 Andreas Steffen - * 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 . - * - * 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. - * - * RCSID $Id$ - */ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "certinfo.h" -#include "x509.h" -#include "crl.h" - -#define CRL_WARNING_INTERVAL 7 /* days */ - -/* access structure for a revoked certificate */ - -typedef struct revokedCert_t revokedCert_t; - -struct revokedCert_t { - chunk_t userCertificate; - time_t revocationDate; - crl_reason_t revocationReason; -}; - -typedef struct private_crl_t private_crl_t; - -/** - * Private data of a crl_t object. - */ -struct private_crl_t { - /** - * Public interface for this crl. - */ - crl_t public; - - /** - * Time when crl was installed - */ - time_t installed; - - /** - * List of crlDistributionPoints - */ - linked_list_t *crlDistributionPoints; - - /** - * X.509 crl in DER format - */ - chunk_t certificateList; - - /** - * X.509 crl body over which signature is computed - */ - chunk_t tbsCertList; - - /** - * Version of the X.509 crl - */ - u_int version; - - /** - * Signature algorithm - */ - int sigAlg; - - /** - * ID representing the crl issuer - */ - identification_t *issuer; - - /** - * CRL number - */ - chunk_t crlNumber; - - /** - * Time when the crl was generated - */ - time_t thisUpdate; - - /** - * Time when an update crl will be available - */ - time_t nextUpdate; - - /** - * List of identification_t's representing subjectAltNames - */ - linked_list_t *revokedCertificates; - - /** - * Authority Key Identifier - */ - chunk_t authKeyID; - - /** - * Authority Key Serial Number - */ - chunk_t authKeySerialNumber; - - /** - * Signature algorithm (must be identical to sigAlg) - */ - int algorithm; - - /** - * Signature - */ - chunk_t signature; -}; - -/** - * ASN.1 definition of an X.509 certificate revocation list - */ -static const asn1Object_t crlObjects[] = { - { 0, "certificateList", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */ - { 1, "tbsCertList", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */ - { 2, "version", ASN1_INTEGER, ASN1_OPT | - ASN1_BODY }, /* 2 */ - { 2, "end opt", ASN1_EOC, ASN1_END }, /* 3 */ - { 2, "signature", ASN1_EOC, ASN1_RAW }, /* 4 */ - { 2, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */ - { 2, "thisUpdate", ASN1_EOC, ASN1_RAW }, /* 6 */ - { 2, "nextUpdate", ASN1_EOC, ASN1_RAW }, /* 7 */ - { 2, "revokedCertificates", ASN1_SEQUENCE, ASN1_OPT | - ASN1_LOOP }, /* 8 */ - { 3, "certList", ASN1_SEQUENCE, ASN1_NONE }, /* 9 */ - { 4, "userCertificate", ASN1_INTEGER, ASN1_BODY }, /* 10 */ - { 4, "revocationDate", ASN1_EOC, ASN1_RAW }, /* 11 */ - { 4, "crlEntryExtensions", ASN1_SEQUENCE, ASN1_OPT | - ASN1_LOOP }, /* 12 */ - { 5, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 13 */ - { 6, "extnID", ASN1_OID, ASN1_BODY }, /* 14 */ - { 6, "critical", ASN1_BOOLEAN, ASN1_DEF | - ASN1_BODY }, /* 15 */ - { 6, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 16 */ - { 4, "end opt or loop", ASN1_EOC, ASN1_END }, /* 17 */ - { 2, "end opt or loop", ASN1_EOC, ASN1_END }, /* 18 */ - { 2, "optional extensions", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 19 */ - { 3, "crlExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 20 */ - { 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 21 */ - { 5, "extnID", ASN1_OID, ASN1_BODY }, /* 22 */ - { 5, "critical", ASN1_BOOLEAN, ASN1_DEF | - ASN1_BODY }, /* 23 */ - { 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 24 */ - { 3, "end loop", ASN1_EOC, ASN1_END }, /* 25 */ - { 2, "end opt", ASN1_EOC, ASN1_END }, /* 26 */ - { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 27 */ - { 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY } /* 28 */ - }; - -#define CRL_OBJ_CERTIFICATE_LIST 0 -#define CRL_OBJ_TBS_CERT_LIST 1 -#define CRL_OBJ_VERSION 2 -#define CRL_OBJ_SIG_ALG 4 -#define CRL_OBJ_ISSUER 5 -#define CRL_OBJ_THIS_UPDATE 6 -#define CRL_OBJ_NEXT_UPDATE 7 -#define CRL_OBJ_USER_CERTIFICATE 10 -#define CRL_OBJ_REVOCATION_DATE 11 -#define CRL_OBJ_CRL_ENTRY_EXTN_ID 14 -#define CRL_OBJ_CRL_ENTRY_CRITICAL 15 -#define CRL_OBJ_CRL_ENTRY_EXTN_VALUE 16 -#define CRL_OBJ_EXTN_ID 22 -#define CRL_OBJ_CRITICAL 23 -#define CRL_OBJ_EXTN_VALUE 24 -#define CRL_OBJ_ALGORITHM 27 -#define CRL_OBJ_SIGNATURE 28 -#define CRL_OBJ_ROOF 29 - -/** - * Parses a CRL revocation reason code - */ -static crl_reason_t parse_crl_reasonCode(chunk_t object) -{ - crl_reason_t reason = REASON_UNSPECIFIED; - - if (*object.ptr == ASN1_ENUMERATED && asn1_length(&object) == 1) - { - reason = *object.ptr; - } - DBG2(" '%N'", crl_reason_names, reason); - - return reason; -} - -/** - * Parses an X.509 Certificate Revocation List (CRL) - */ -bool parse_x509crl(chunk_t blob, u_int level0, private_crl_t *crl) -{ - asn1_ctx_t ctx; - bool critical; - chunk_t extnID; - chunk_t userCertificate = chunk_empty; - revokedCert_t *revokedCert = NULL; - chunk_t object; - u_int level; - int objectID = 0; - - asn1_init(&ctx, blob, level0, FALSE, FALSE); - - while (objectID < CRL_OBJ_ROOF) - { - if (!extract_object(crlObjects, &objectID, &object, &level, &ctx)) - return FALSE; - - /* those objects which will parsed further need the next higher level */ - level++; - - switch (objectID) - { - case CRL_OBJ_CERTIFICATE_LIST: - crl->certificateList = object; - break; - case CRL_OBJ_TBS_CERT_LIST: - crl->tbsCertList = object; - break; - case CRL_OBJ_VERSION: - crl->version = (object.len) ? (1+(u_int)*object.ptr) : 1; - DBG2(" v%d", crl->version); - break; - case CRL_OBJ_SIG_ALG: - crl->sigAlg = parse_algorithmIdentifier(object, level, NULL); - break; - case CRL_OBJ_ISSUER: - crl->issuer = identification_create_from_encoding(ID_DER_ASN1_DN, object); - DBG2(" '%D'", crl->issuer); - break; - case CRL_OBJ_THIS_UPDATE: - crl->thisUpdate = parse_time(object, level); - break; - case CRL_OBJ_NEXT_UPDATE: - crl->nextUpdate = parse_time(object, level); - break; - case CRL_OBJ_USER_CERTIFICATE: - userCertificate = object; - break; - case CRL_OBJ_REVOCATION_DATE: - revokedCert = malloc_thing(revokedCert_t); - revokedCert->userCertificate = userCertificate; - revokedCert->revocationDate = parse_time(object, level); - revokedCert->revocationReason = REASON_UNSPECIFIED; - crl->revokedCertificates->insert_last(crl->revokedCertificates, (void *)revokedCert); - break; - case CRL_OBJ_CRL_ENTRY_EXTN_ID: - case CRL_OBJ_EXTN_ID: - extnID = object; - break; - case CRL_OBJ_CRL_ENTRY_CRITICAL: - case CRL_OBJ_CRITICAL: - critical = object.len && *object.ptr; - DBG2(" %s",(critical)?"TRUE":"FALSE"); - break; - case CRL_OBJ_CRL_ENTRY_EXTN_VALUE: - case CRL_OBJ_EXTN_VALUE: - { - int extn_oid = known_oid(extnID); - - if (revokedCert && extn_oid == OID_CRL_REASON_CODE) - { - revokedCert->revocationReason = parse_crl_reasonCode(object); - } - else if (extn_oid == OID_AUTHORITY_KEY_ID) - { - x509_parse_authorityKeyIdentifier(object, level, - &crl->authKeyID, &crl->authKeySerialNumber); - } - else if (extn_oid == OID_CRL_NUMBER) - { - if (!parse_asn1_simple_object(&object, ASN1_INTEGER, level, "crlNumber")) - { - return FALSE; - } - crl->crlNumber = object; - } - } - break; - case CRL_OBJ_ALGORITHM: - crl->algorithm = parse_algorithmIdentifier(object, level, NULL); - if (crl->algorithm != crl->sigAlg) - { - DBG1(" signature algorithms do not agree"); - return FALSE; - } - break; - case CRL_OBJ_SIGNATURE: - crl->signature = object; - break; - default: - break; - } - objectID++; - } - time(&crl->installed); - return TRUE; -} - -/** - * Implements crl_t.is_valid - */ -static bool is_valid(const private_crl_t *this) -{ - time_t current_time = time(NULL); - - DBG2(" this update : %T", &this->thisUpdate); - DBG2(" current time: %T", ¤t_time); - DBG2(" next update: %T", &this->nextUpdate); - - return current_time < this->nextUpdate; -} - -/** - * Implements crl_t.get_issuer - */ -static identification_t *get_issuer(const private_crl_t *this) -{ - return this->issuer; -} - -/** - * Implements crl_t.equals_issuer - */ -static bool equals_issuer(const private_crl_t *this, const private_crl_t *other) -{ - return (this->authKeyID.ptr) - ? chunk_equals(this->authKeyID, other->authKeyID) - : (this->issuer->equals(this->issuer, other->issuer) - && chunk_equals_or_null(this->authKeySerialNumber, other->authKeySerialNumber)); -} - -/** - * Implements crl_t.is_issuer - */ -static bool is_issuer(const private_crl_t *this, const x509_t *issuer) -{ - return (this->authKeyID.ptr) - ? chunk_equals(this->authKeyID, issuer->get_subjectKeyID(issuer)) - : (this->issuer->equals(this->issuer, issuer->get_subject(issuer)) - && chunk_equals_or_null(this->authKeySerialNumber, issuer->get_serialNumber(issuer))); -} - -/** - * Implements crl_t.is_newer - */ -static bool is_newer(const private_crl_t *this, const private_crl_t *other) -{ - return (this->nextUpdate > other->nextUpdate); -} - -/** - * Implements crl_t.verify - */ -static bool verify(const private_crl_t *this, const rsa_public_key_t *signer) -{ - hash_algorithm_t algorithm = hasher_algorithm_from_oid(this->algorithm); - - if (algorithm == HASH_UNKNOWN) - { - DBG1(" unknown signature algorithm"); - return FALSE; - } - return signer->verify_emsa_pkcs1_signature(signer, algorithm, this->tbsCertList, this->signature) == SUCCESS; -} - -/** - * Implements crl_t.get_status - */ -static void get_status(const private_crl_t *this, certinfo_t *certinfo) -{ - chunk_t serialNumber = certinfo->get_serialNumber(certinfo); - iterator_t *iterator; - revokedCert_t *revokedCert; - - certinfo->set_nextUpdate(certinfo, this->nextUpdate); - certinfo->set_status(certinfo, CERT_GOOD); - - iterator = this->revokedCertificates->create_iterator(this->revokedCertificates, TRUE); - while (iterator->iterate(iterator, (void**)&revokedCert)) - { - if (chunk_equals(serialNumber, revokedCert->userCertificate)) - { - certinfo->set_status(certinfo, CERT_REVOKED); - certinfo->set_revocationTime(certinfo, revokedCert->revocationDate); - certinfo->set_revocationReason(certinfo, revokedCert->revocationReason); - break; - } - } - iterator->destroy(iterator); -} - -/** - * Implements crl_t.write_to_file. - */ -static bool write_to_file(private_crl_t *this, const char *path, mode_t mask, bool force) -{ - return chunk_write(this->certificateList, path, "crl", mask, force); -} - -/** - * Implements crl_t.destroy - */ -static void destroy(private_crl_t *this) -{ - this->revokedCertificates->destroy_function(this->revokedCertificates, free); - this->crlDistributionPoints->destroy_offset(this->crlDistributionPoints, - offsetof(identification_t, destroy)); - DESTROY_IF(this->issuer); - free(this->certificateList.ptr); - free(this); -} - -/** - * Implementation of crl_t.list. - */ -static void list(private_crl_t *this, FILE* out, bool utc) -{ - time_t now; - - now = time(NULL); - - fprintf(out, "%#T, revoked certs: %d\n", &this->installed, utc, - this->revokedCertificates->get_count(this->revokedCertificates)); - fprintf(out, " issuer: '%D'\n", this->issuer); - if (this->crlNumber.ptr) - { - fprintf(out, " crlnumber: %#B\n", &this->crlNumber); - } - fprintf(out, " updates: this %#T\n", &this->thisUpdate, utc); - fprintf(out, " next %#T ", &this->nextUpdate, utc); - if (this->nextUpdate == UNDEFINED_TIME) - { - fprintf(out, "ok (expires never)\n"); - } - else if (now > this->nextUpdate) - { - fprintf(out, "expired (%#V ago)\n", &now, &this->nextUpdate); - } - else if (now > this->nextUpdate - CRL_WARNING_INTERVAL * 60 * 60 * 24) - { - fprintf(out, "ok (expires in %#V)\n", &now, &this->nextUpdate); - } - else - { - fprintf(out, "ok\n"); - } - if (this->authKeyID.ptr) - { - fprintf(out, " authkey: %#B\n", &this->authKeyID); - } - if (this->authKeySerialNumber.ptr) - { - fprintf(out, " aserial: %#B\n", &this->authKeySerialNumber); - } -} - -/* - * Described in header. - */ -crl_t *crl_create_from_chunk(chunk_t chunk) -{ - private_crl_t *this = malloc_thing(private_crl_t); - - /* initialize */ - this->crlDistributionPoints = linked_list_create(); - this->tbsCertList = chunk_empty; - this->issuer = NULL; - this->crlNumber = chunk_empty; - this->revokedCertificates = linked_list_create(); - this->authKeyID = chunk_empty; - this->authKeySerialNumber = chunk_empty; - - /* public functions */ - this->public.get_issuer = (identification_t* (*) (const crl_t*))get_issuer; - this->public.equals_issuer = (bool (*) (const crl_t*,const crl_t*))equals_issuer; - this->public.is_issuer = (bool (*) (const crl_t*,const x509_t*))is_issuer; - this->public.is_valid = (bool (*) (const crl_t*))is_valid; - this->public.is_newer = (bool (*) (const crl_t*,const crl_t*))is_newer; - this->public.verify = (bool (*) (const crl_t*,const rsa_public_key_t*))verify; - this->public.get_status = (void (*) (const crl_t*,certinfo_t*))get_status; - this->public.write_to_file = (bool (*) (const crl_t*,const char*,mode_t,bool))write_to_file; - this->public.list = (void(*)(crl_t*, FILE* out, bool utc))list; - this->public.destroy = (void (*) (crl_t*))destroy; - - if (!parse_x509crl(chunk, 0, this)) - { - destroy(this); - return NULL; - } - - return &this->public; -} - -/* - * Described in header. - */ -crl_t *crl_create_from_file(const char *filename) -{ - bool pgp = FALSE; - chunk_t chunk = chunk_empty; - - if (!pem_asn1_load_file(filename, NULL, "crl", &chunk, &pgp)) - { - return NULL; - } - return crl_create_from_chunk(chunk); -} diff --git a/src/libstrongswan/crypto/crl.h b/src/libstrongswan/crypto/crl.h deleted file mode 100755 index 68cc04911..000000000 --- a/src/libstrongswan/crypto/crl.h +++ /dev/null @@ -1,158 +0,0 @@ -/** - * @file crl.h - * - * @brief Interface of crl_t. - * - */ - -/* - * Copyright (C) 2006 Andreas Steffen - * 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 . - * - * 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. - * - * RCSID $Id$ - */ - -#ifndef CRL_H_ -#define CRL_H_ - -typedef struct crl_t crl_t; - -#include -#include -#include -#include -#include - -/** - * @brief X.509 certificate revocation list - * - * @b Constructors: - * - crl_create_from_chunk() - * - crl_create_from_file() - * - * @ingroup transforms - */ -struct crl_t { - - /** - * @brief Get the crl's issuer ID. - * - * The resulting ID is always a identification_t - * of type ID_DER_ASN1_DN. - * - * @param this calling object - * @return issuers ID - */ - identification_t *(*get_issuer) (const crl_t *this); - - /** - * @brief Check if both crls have the same issuer. - * - * @param this calling object - * @param other other crl - * @return TRUE if the same issuer - */ - bool (*equals_issuer) (const crl_t *this, const crl_t *other); - - /** - * @brief Check if ia candidate cert is the issuer of the crl - * - * @param this calling object - * @param issuer candidate issuer of the crl - * @return TRUE if issuer - */ - bool (*is_issuer) (const crl_t *this, const x509_t *issuer); - - /** - * @brief Checks the validity interval of the crl - * - * @param this calling object - * @return TRUE if the crl is valid - */ - bool (*is_valid) (const crl_t *this); - - /** - * @brief Checks if this crl is newer (thisUpdate) than the other crl - * - * @param this calling object - * @param other other crl object - * @return TRUE if this was issued more recently than other - */ - bool (*is_newer) (const crl_t *this, const crl_t *other); - - /** - * @brief Check if a crl is trustworthy. - * - * @param this calling object - * @param signer signer's RSA public key - * @return TRUE if crl is trustworthy - */ - bool (*verify) (const crl_t *this, const rsa_public_key_t *signer); - - /** - * @brief Get the certificate status - * - * @param this calling object - * @param certinfo certinfo is updated - */ - void (*get_status) (const crl_t *this, certinfo_t *certinfo); - - /** - * @brief Log the info of this CRL to out. - * - * @param this calling object - * @param out stream to write to - * @param utc TRUE for UTC, FALSE for local time - */ - void (*list)(crl_t *this, FILE* out, bool utc); - - /** - * @brief Write a der-encoded crl to a file - * - * @param this calling object - * @param path path where the file is to be stored - * @param mask file access control rights - * @param force overwrite the file if it already exists - * @return TRUE if successfully written - */ - bool (*write_to_file) (const crl_t *this, const char *path, mode_t mask, bool force); - - /** - * @brief Destroys the crl. - * - * @param this crl to destroy - */ - void (*destroy) (crl_t *this); -}; - -/** - * @brief Read a x509 crl from a DER encoded blob. - * - * @param chunk chunk containing DER encoded data - * @return created crl_t, or NULL if invalid. - * - * @ingroup transforms - */ -crl_t *crl_create_from_chunk(chunk_t chunk); - -/** - * @brief Read a x509 crl from a DER encoded file. - * - * @param filename file containing DER encoded data - * @return created crl_t, or NULL if invalid. - * - * @ingroup transforms - */ -crl_t *crl_create_from_file(const char *filename); - -#endif /* CRL_H_ */ diff --git a/src/libstrongswan/crypto/crypters/aes_cbc_crypter.c b/src/libstrongswan/crypto/crypters/aes_cbc_crypter.c deleted file mode 100644 index 947188af3..000000000 --- a/src/libstrongswan/crypto/crypters/aes_cbc_crypter.c +++ /dev/null @@ -1,1620 +0,0 @@ -/** - * @file aes_cbc_crypter.c - * - * @brief Implementation of aes_cbc_crypter_t - * - */ - - /* - * Copyright (C) 2001 Dr B. R. Gladman - * Copyright (C) 2005-2006 Martin Willi - * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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 "aes_cbc_crypter.h" - - - -/* - * The number of key schedule words for different block and key lengths - * allowing for method of computation which requires the length to be a - * multiple of the key length. This version of AES implementation supports - * all three keylengths 16, 24 and 32 bytes! - * - * Nk = 4 6 8 - * ------------- - * Nb = 4 | 60 60 64 - * 6 | 96 90 96 - * 8 | 120 120 120 - */ -#define AES_KS_LENGTH 120 -#define AES_RC_LENGTH 29 - -#define AES_BLOCK_SIZE 16 - -typedef struct private_aes_cbc_crypter_t private_aes_cbc_crypter_t; - -/** - * @brief Class implementing the AES symmetric encryption algorithm. - * - * @ingroup crypters - */ -struct private_aes_cbc_crypter_t { - - /** - * Public part of this class. - */ - aes_cbc_crypter_t public; - - /** - * Number of words in the key input block. - */ - u_int32_t aes_Nkey; - - /** - * The number of cipher rounds. - */ - u_int32_t aes_Nrnd; - - /** - * The encryption key schedule. - */ - u_int32_t aes_e_key[AES_KS_LENGTH]; - - /** - * The decryption key schedule. - */ - u_int32_t aes_d_key[AES_KS_LENGTH]; - - /** - * Key size of this AES cypher object. - */ - u_int32_t key_size; - - /** - * Decrypts a block. - * - * No memory gets allocated. - * - * @param this calling object - * @param[in] in_blk block to decrypt - * @param[out] out_blk decrypted data are written to this location - */ - void (*decrypt_block) (const private_aes_cbc_crypter_t *this, const unsigned char in_blk[], unsigned char out_blk[]); - - /** - * Encrypts a block. - * - * No memory gets allocated. - * - * @param this calling object - * @param[in] in_blk block to encrypt - * @param[out] out_blk encrypted data are written to this location - */ - void (*encrypt_block) (const private_aes_cbc_crypter_t *this, const unsigned char in_blk[], unsigned char out_blk[]); -}; - - -/* ugly macro stuff */ - -/* 1. Define UNROLL for full loop unrolling in encryption and decryption. - * 2. Define PARTIAL_UNROLL to unroll two loops in encryption and decryption. - * 3. Define FIXED_TABLES for compiled rather than dynamic tables. - * 4. Define FF_TABLES to use tables for field multiplies and inverses. - * Do not enable this without understanding stack space requirements. - * 5. Define ARRAYS to use arrays to hold the local state block. If this - * is not defined, individually declared 32-bit words are used. - * 6. Define FAST_VARIABLE if a high speed variable block implementation - * is needed (essentially three separate fixed block size code sequences) - * 7. Define either ONE_TABLE or FOUR_TABLES for a fast table driven - * version using 1 table (2 kbytes of table space) or 4 tables (8 - * kbytes of table space) for higher speed. - * 8. Define either ONE_LR_TABLE or FOUR_LR_TABLES for a further speed - * increase by using tables for the last rounds but with more table - * space (2 or 8 kbytes extra). - * 9. If neither ONE_TABLE nor FOUR_TABLES is defined, a compact but - * slower version is provided. - * 10. If fast decryption key scheduling is needed define ONE_IM_TABLE - * or FOUR_IM_TABLES for higher speed (2 or 8 kbytes extra). - */ - -#define UNROLL -//#define PARTIAL_UNROLL - -#define FIXED_TABLES -//#define FF_TABLES -//#define ARRAYS -#define FAST_VARIABLE - -//#define ONE_TABLE -#define FOUR_TABLES - -//#define ONE_LR_TABLE -#define FOUR_LR_TABLES - -//#define ONE_IM_TABLE -#define FOUR_IM_TABLES - -#if defined(UNROLL) && defined (PARTIAL_UNROLL) -#error both UNROLL and PARTIAL_UNROLL are defined -#endif - -#if defined(ONE_TABLE) && defined (FOUR_TABLES) -#error both ONE_TABLE and FOUR_TABLES are defined -#endif - -#if defined(ONE_LR_TABLE) && defined (FOUR_LR_TABLES) -#error both ONE_LR_TABLE and FOUR_LR_TABLES are defined -#endif - -#if defined(ONE_IM_TABLE) && defined (FOUR_IM_TABLES) -#error both ONE_IM_TABLE and FOUR_IM_TABLES are defined -#endif - -#if defined(AES_BLOCK_SIZE) && AES_BLOCK_SIZE != 16 && AES_BLOCK_SIZE != 24 && AES_BLOCK_SIZE != 32 -#error an illegal block size has been specified -#endif - -/** - * Rotates bytes within words by n positions, moving bytes - * to higher index positions with wrap around into low positions. - */ -#define upr(x,n) (((x) << 8 * (n)) | ((x) >> (32 - 8 * (n)))) -/** - * Moves bytes by n positions to higher index positions in - * words but without wrap around. - */ -#define ups(x,n) ((x) << 8 * (n)) - -/** - * Extracts a byte from a word. - */ -#define bval(x,n) ((unsigned char)((x) >> 8 * (n))) -#define bytes2word(b0, b1, b2, b3) \ - ((u_int32_t)(b3) << 24 | (u_int32_t)(b2) << 16 | (u_int32_t)(b1) << 8 | (b0)) - - -/* little endian processor without data alignment restrictions: AES_LE_OK */ -/* original code: i386 */ -#if defined(i386) || defined(_I386) || defined(__i386__) || defined(__i386) -#define AES_LE_OK 1 -/* added (tested): alpha --jjo */ -#elif defined(__alpha__)|| defined (__alpha) -#define AES_LE_OK 1 -/* added (tested): ia64 --jjo */ -#elif defined(__ia64__)|| defined (__ia64) -#define AES_LE_OK 1 -#endif - -#ifdef AES_LE_OK -/* little endian processor without data alignment restrictions */ -#define word_in(x) *(u_int32_t*)(x) -#define const_word_in(x) *(const u_int32_t*)(x) -#define word_out(x,v) *(u_int32_t*)(x) = (v) -#define const_word_out(x,v) *(const u_int32_t*)(x) = (v) -#else -/* slower but generic big endian or with data alignment restrictions */ -/* some additional "const" touches to stop "gcc -Wcast-qual" complains --jjo */ -#define word_in(x) ((u_int32_t)(((unsigned char *)(x))[0])|((u_int32_t)(((unsigned char *)(x))[1])<<8)|((u_int32_t)(((unsigned char *)(x))[2])<<16)|((u_int32_t)(((unsigned char *)(x))[3])<<24)) -#define const_word_in(x) ((const u_int32_t)(((const unsigned char *)(x))[0])|((const u_int32_t)(((const unsigned char *)(x))[1])<<8)|((const u_int32_t)(((const unsigned char *)(x))[2])<<16)|((const u_int32_t)(((const unsigned char *)(x))[3])<<24)) -#define word_out(x,v) ((unsigned char *)(x))[0]=(v),((unsigned char *)(x))[1]=((v)>>8),((unsigned char *)(x))[2]=((v)>>16),((unsigned char *)(x))[3]=((v)>>24) -#define const_word_out(x,v) ((const unsigned char *)(x))[0]=(v),((const unsigned char *)(x))[1]=((v)>>8),((const unsigned char *)(x))[2]=((v)>>16),((const unsigned char *)(x))[3]=((v)>>24) -#endif - -// Disable at least some poor combinations of options - -#if !defined(ONE_TABLE) && !defined(FOUR_TABLES) -#define FIXED_TABLES -#undef UNROLL -#undef ONE_LR_TABLE -#undef FOUR_LR_TABLES -#undef ONE_IM_TABLE -#undef FOUR_IM_TABLES -#elif !defined(FOUR_TABLES) -#ifdef FOUR_LR_TABLES -#undef FOUR_LR_TABLES -#define ONE_LR_TABLE -#endif -#ifdef FOUR_IM_TABLES -#undef FOUR_IM_TABLES -#define ONE_IM_TABLE -#endif -#elif !defined(AES_BLOCK_SIZE) -#if defined(UNROLL) -#define PARTIAL_UNROLL -#undef UNROLL -#endif -#endif - -// the finite field modular polynomial and elements - -#define ff_poly 0x011b -#define ff_hi 0x80 - -// multiply four bytes in GF(2^8) by 'x' {02} in parallel - -#define m1 0x80808080 -#define m2 0x7f7f7f7f -#define m3 0x0000001b -#define FFmulX(x) ((((x) & m2) << 1) ^ ((((x) & m1) >> 7) * m3)) - -// The following defines provide alternative definitions of FFmulX that might -// give improved performance if a fast 32-bit multiply is not available. Note -// that a temporary variable u needs to be defined where FFmulX is used. - -// #define FFmulX(x) (u = (x) & m1, u |= (u >> 1), ((x) & m2) << 1) ^ ((u >> 3) | (u >> 6)) -// #define m4 0x1b1b1b1b -// #define FFmulX(x) (u = (x) & m1, ((x) & m2) << 1) ^ ((u - (u >> 7)) & m4) - -// perform column mix operation on four bytes in parallel - -#define fwd_mcol(x) (f2 = FFmulX(x), f2 ^ upr(x ^ f2,3) ^ upr(x,2) ^ upr(x,1)) - -#if defined(FIXED_TABLES) - -// the S-Box table - -static const unsigned char s_box[256] = -{ - 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, - 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, - 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, - 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, - 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, - 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, - 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, - 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, - 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, - 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, - 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, - 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, - 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, - 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, - 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, - 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, - 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, - 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, - 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, - 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, - 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, - 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, - 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, - 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, - 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, - 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, - 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, - 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, - 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, - 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, - 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, - 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 -}; - -// the inverse S-Box table - -static const unsigned char inv_s_box[256] = -{ - 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, - 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, - 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, - 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, - 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, - 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, - 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, - 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, - 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, - 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, - 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, - 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, - 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, - 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, - 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, - 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, - 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, - 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, - 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, - 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, - 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, - 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, - 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, - 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, - 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, - 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, - 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, - 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, - 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, - 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, - 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, - 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d -}; - -#define w0(p) 0x000000##p - -// Number of elements required in this table for different -// block and key lengths is: -// -// Nk = 4 6 8 -// ---------- -// Nb = 4 | 10 8 7 -// 6 | 19 12 11 -// 8 | 29 19 14 -// -// this table can be a table of bytes if the key schedule -// code is adjusted accordingly - -static const u_int32_t rcon_tab[29] = -{ - w0(01), w0(02), w0(04), w0(08), - w0(10), w0(20), w0(40), w0(80), - w0(1b), w0(36), w0(6c), w0(d8), - w0(ab), w0(4d), w0(9a), w0(2f), - w0(5e), w0(bc), w0(63), w0(c6), - w0(97), w0(35), w0(6a), w0(d4), - w0(b3), w0(7d), w0(fa), w0(ef), - w0(c5) -}; - -#undef w0 - -#define r0(p,q,r,s) 0x##p##q##r##s -#define r1(p,q,r,s) 0x##q##r##s##p -#define r2(p,q,r,s) 0x##r##s##p##q -#define r3(p,q,r,s) 0x##s##p##q##r -#define w0(p) 0x000000##p -#define w1(p) 0x0000##p##00 -#define w2(p) 0x00##p##0000 -#define w3(p) 0x##p##000000 - -#if defined(FIXED_TABLES) && (defined(ONE_TABLE) || defined(FOUR_TABLES)) - -// data for forward tables (other than last round) - -#define f_table \ - r(a5,63,63,c6), r(84,7c,7c,f8), r(99,77,77,ee), r(8d,7b,7b,f6),\ - r(0d,f2,f2,ff), r(bd,6b,6b,d6), r(b1,6f,6f,de), r(54,c5,c5,91),\ - r(50,30,30,60), r(03,01,01,02), r(a9,67,67,ce), r(7d,2b,2b,56),\ - r(19,fe,fe,e7), r(62,d7,d7,b5), r(e6,ab,ab,4d), r(9a,76,76,ec),\ - r(45,ca,ca,8f), r(9d,82,82,1f), r(40,c9,c9,89), r(87,7d,7d,fa),\ - r(15,fa,fa,ef), r(eb,59,59,b2), r(c9,47,47,8e), r(0b,f0,f0,fb),\ - r(ec,ad,ad,41), r(67,d4,d4,b3), r(fd,a2,a2,5f), r(ea,af,af,45),\ - r(bf,9c,9c,23), r(f7,a4,a4,53), r(96,72,72,e4), r(5b,c0,c0,9b),\ - r(c2,b7,b7,75), r(1c,fd,fd,e1), r(ae,93,93,3d), r(6a,26,26,4c),\ - r(5a,36,36,6c), r(41,3f,3f,7e), r(02,f7,f7,f5), r(4f,cc,cc,83),\ - r(5c,34,34,68), r(f4,a5,a5,51), r(34,e5,e5,d1), r(08,f1,f1,f9),\ - r(93,71,71,e2), r(73,d8,d8,ab), r(53,31,31,62), r(3f,15,15,2a),\ - r(0c,04,04,08), r(52,c7,c7,95), r(65,23,23,46), r(5e,c3,c3,9d),\ - r(28,18,18,30), r(a1,96,96,37), r(0f,05,05,0a), r(b5,9a,9a,2f),\ - r(09,07,07,0e), r(36,12,12,24), r(9b,80,80,1b), r(3d,e2,e2,df),\ - r(26,eb,eb,cd), r(69,27,27,4e), r(cd,b2,b2,7f), r(9f,75,75,ea),\ - r(1b,09,09,12), r(9e,83,83,1d), r(74,2c,2c,58), r(2e,1a,1a,34),\ - r(2d,1b,1b,36), r(b2,6e,6e,dc), r(ee,5a,5a,b4), r(fb,a0,a0,5b),\ - r(f6,52,52,a4), r(4d,3b,3b,76), r(61,d6,d6,b7), r(ce,b3,b3,7d),\ - r(7b,29,29,52), r(3e,e3,e3,dd), r(71,2f,2f,5e), r(97,84,84,13),\ - r(f5,53,53,a6), r(68,d1,d1,b9), r(00,00,00,00), r(2c,ed,ed,c1),\ - r(60,20,20,40), r(1f,fc,fc,e3), r(c8,b1,b1,79), r(ed,5b,5b,b6),\ - r(be,6a,6a,d4), r(46,cb,cb,8d), r(d9,be,be,67), r(4b,39,39,72),\ - r(de,4a,4a,94), r(d4,4c,4c,98), r(e8,58,58,b0), r(4a,cf,cf,85),\ - r(6b,d0,d0,bb), r(2a,ef,ef,c5), r(e5,aa,aa,4f), r(16,fb,fb,ed),\ - r(c5,43,43,86), r(d7,4d,4d,9a), r(55,33,33,66), r(94,85,85,11),\ - r(cf,45,45,8a), r(10,f9,f9,e9), r(06,02,02,04), r(81,7f,7f,fe),\ - r(f0,50,50,a0), r(44,3c,3c,78), r(ba,9f,9f,25), r(e3,a8,a8,4b),\ - r(f3,51,51,a2), r(fe,a3,a3,5d), r(c0,40,40,80), r(8a,8f,8f,05),\ - r(ad,92,92,3f), r(bc,9d,9d,21), r(48,38,38,70), r(04,f5,f5,f1),\ - r(df,bc,bc,63), r(c1,b6,b6,77), r(75,da,da,af), r(63,21,21,42),\ - r(30,10,10,20), r(1a,ff,ff,e5), r(0e,f3,f3,fd), r(6d,d2,d2,bf),\ - r(4c,cd,cd,81), r(14,0c,0c,18), r(35,13,13,26), r(2f,ec,ec,c3),\ - r(e1,5f,5f,be), r(a2,97,97,35), r(cc,44,44,88), r(39,17,17,2e),\ - r(57,c4,c4,93), r(f2,a7,a7,55), r(82,7e,7e,fc), r(47,3d,3d,7a),\ - r(ac,64,64,c8), r(e7,5d,5d,ba), r(2b,19,19,32), r(95,73,73,e6),\ - r(a0,60,60,c0), r(98,81,81,19), r(d1,4f,4f,9e), r(7f,dc,dc,a3),\ - r(66,22,22,44), r(7e,2a,2a,54), r(ab,90,90,3b), r(83,88,88,0b),\ - r(ca,46,46,8c), r(29,ee,ee,c7), r(d3,b8,b8,6b), r(3c,14,14,28),\ - r(79,de,de,a7), r(e2,5e,5e,bc), r(1d,0b,0b,16), r(76,db,db,ad),\ - r(3b,e0,e0,db), r(56,32,32,64), r(4e,3a,3a,74), r(1e,0a,0a,14),\ - r(db,49,49,92), r(0a,06,06,0c), r(6c,24,24,48), r(e4,5c,5c,b8),\ - r(5d,c2,c2,9f), r(6e,d3,d3,bd), r(ef,ac,ac,43), r(a6,62,62,c4),\ - r(a8,91,91,39), r(a4,95,95,31), r(37,e4,e4,d3), r(8b,79,79,f2),\ - r(32,e7,e7,d5), r(43,c8,c8,8b), r(59,37,37,6e), r(b7,6d,6d,da),\ - r(8c,8d,8d,01), r(64,d5,d5,b1), r(d2,4e,4e,9c), r(e0,a9,a9,49),\ - r(b4,6c,6c,d8), r(fa,56,56,ac), r(07,f4,f4,f3), r(25,ea,ea,cf),\ - r(af,65,65,ca), r(8e,7a,7a,f4), r(e9,ae,ae,47), r(18,08,08,10),\ - r(d5,ba,ba,6f), r(88,78,78,f0), r(6f,25,25,4a), r(72,2e,2e,5c),\ - r(24,1c,1c,38), r(f1,a6,a6,57), r(c7,b4,b4,73), r(51,c6,c6,97),\ - r(23,e8,e8,cb), r(7c,dd,dd,a1), r(9c,74,74,e8), r(21,1f,1f,3e),\ - r(dd,4b,4b,96), r(dc,bd,bd,61), r(86,8b,8b,0d), r(85,8a,8a,0f),\ - r(90,70,70,e0), r(42,3e,3e,7c), r(c4,b5,b5,71), r(aa,66,66,cc),\ - r(d8,48,48,90), r(05,03,03,06), r(01,f6,f6,f7), r(12,0e,0e,1c),\ - r(a3,61,61,c2), r(5f,35,35,6a), r(f9,57,57,ae), r(d0,b9,b9,69),\ - r(91,86,86,17), r(58,c1,c1,99), r(27,1d,1d,3a), r(b9,9e,9e,27),\ - r(38,e1,e1,d9), r(13,f8,f8,eb), r(b3,98,98,2b), r(33,11,11,22),\ - r(bb,69,69,d2), r(70,d9,d9,a9), r(89,8e,8e,07), r(a7,94,94,33),\ - r(b6,9b,9b,2d), r(22,1e,1e,3c), r(92,87,87,15), r(20,e9,e9,c9),\ - r(49,ce,ce,87), r(ff,55,55,aa), r(78,28,28,50), r(7a,df,df,a5),\ - r(8f,8c,8c,03), r(f8,a1,a1,59), r(80,89,89,09), r(17,0d,0d,1a),\ - r(da,bf,bf,65), r(31,e6,e6,d7), r(c6,42,42,84), r(b8,68,68,d0),\ - r(c3,41,41,82), r(b0,99,99,29), r(77,2d,2d,5a), r(11,0f,0f,1e),\ - r(cb,b0,b0,7b), r(fc,54,54,a8), r(d6,bb,bb,6d), r(3a,16,16,2c) - -// data for inverse tables (other than last round) - -#define i_table \ - r(50,a7,f4,51), r(53,65,41,7e), r(c3,a4,17,1a), r(96,5e,27,3a),\ - r(cb,6b,ab,3b), r(f1,45,9d,1f), r(ab,58,fa,ac), r(93,03,e3,4b),\ - r(55,fa,30,20), r(f6,6d,76,ad), r(91,76,cc,88), r(25,4c,02,f5),\ - r(fc,d7,e5,4f), r(d7,cb,2a,c5), r(80,44,35,26), r(8f,a3,62,b5),\ - r(49,5a,b1,de), r(67,1b,ba,25), r(98,0e,ea,45), r(e1,c0,fe,5d),\ - r(02,75,2f,c3), r(12,f0,4c,81), r(a3,97,46,8d), r(c6,f9,d3,6b),\ - r(e7,5f,8f,03), r(95,9c,92,15), r(eb,7a,6d,bf), r(da,59,52,95),\ - r(2d,83,be,d4), r(d3,21,74,58), r(29,69,e0,49), r(44,c8,c9,8e),\ - r(6a,89,c2,75), r(78,79,8e,f4), r(6b,3e,58,99), r(dd,71,b9,27),\ - r(b6,4f,e1,be), r(17,ad,88,f0), r(66,ac,20,c9), r(b4,3a,ce,7d),\ - r(18,4a,df,63), r(82,31,1a,e5), r(60,33,51,97), r(45,7f,53,62),\ - r(e0,77,64,b1), r(84,ae,6b,bb), r(1c,a0,81,fe), r(94,2b,08,f9),\ - r(58,68,48,70), r(19,fd,45,8f), r(87,6c,de,94), r(b7,f8,7b,52),\ - r(23,d3,73,ab), r(e2,02,4b,72), r(57,8f,1f,e3), r(2a,ab,55,66),\ - r(07,28,eb,b2), r(03,c2,b5,2f), r(9a,7b,c5,86), r(a5,08,37,d3),\ - r(f2,87,28,30), r(b2,a5,bf,23), r(ba,6a,03,02), r(5c,82,16,ed),\ - r(2b,1c,cf,8a), r(92,b4,79,a7), r(f0,f2,07,f3), r(a1,e2,69,4e),\ - r(cd,f4,da,65), r(d5,be,05,06), r(1f,62,34,d1), r(8a,fe,a6,c4),\ - r(9d,53,2e,34), r(a0,55,f3,a2), r(32,e1,8a,05), r(75,eb,f6,a4),\ - r(39,ec,83,0b), r(aa,ef,60,40), r(06,9f,71,5e), r(51,10,6e,bd),\ - r(f9,8a,21,3e), r(3d,06,dd,96), r(ae,05,3e,dd), r(46,bd,e6,4d),\ - r(b5,8d,54,91), r(05,5d,c4,71), r(6f,d4,06,04), r(ff,15,50,60),\ - r(24,fb,98,19), r(97,e9,bd,d6), r(cc,43,40,89), r(77,9e,d9,67),\ - r(bd,42,e8,b0), r(88,8b,89,07), r(38,5b,19,e7), r(db,ee,c8,79),\ - r(47,0a,7c,a1), r(e9,0f,42,7c), r(c9,1e,84,f8), r(00,00,00,00),\ - r(83,86,80,09), r(48,ed,2b,32), r(ac,70,11,1e), r(4e,72,5a,6c),\ - r(fb,ff,0e,fd), r(56,38,85,0f), r(1e,d5,ae,3d), r(27,39,2d,36),\ - r(64,d9,0f,0a), r(21,a6,5c,68), r(d1,54,5b,9b), r(3a,2e,36,24),\ - r(b1,67,0a,0c), r(0f,e7,57,93), r(d2,96,ee,b4), r(9e,91,9b,1b),\ - r(4f,c5,c0,80), r(a2,20,dc,61), r(69,4b,77,5a), r(16,1a,12,1c),\ - r(0a,ba,93,e2), r(e5,2a,a0,c0), r(43,e0,22,3c), r(1d,17,1b,12),\ - r(0b,0d,09,0e), r(ad,c7,8b,f2), r(b9,a8,b6,2d), r(c8,a9,1e,14),\ - r(85,19,f1,57), r(4c,07,75,af), r(bb,dd,99,ee), r(fd,60,7f,a3),\ - r(9f,26,01,f7), r(bc,f5,72,5c), r(c5,3b,66,44), r(34,7e,fb,5b),\ - r(76,29,43,8b), r(dc,c6,23,cb), r(68,fc,ed,b6), r(63,f1,e4,b8),\ - r(ca,dc,31,d7), r(10,85,63,42), r(40,22,97,13), r(20,11,c6,84),\ - r(7d,24,4a,85), r(f8,3d,bb,d2), r(11,32,f9,ae), r(6d,a1,29,c7),\ - r(4b,2f,9e,1d), r(f3,30,b2,dc), r(ec,52,86,0d), r(d0,e3,c1,77),\ - r(6c,16,b3,2b), r(99,b9,70,a9), r(fa,48,94,11), r(22,64,e9,47),\ - r(c4,8c,fc,a8), r(1a,3f,f0,a0), r(d8,2c,7d,56), r(ef,90,33,22),\ - r(c7,4e,49,87), r(c1,d1,38,d9), r(fe,a2,ca,8c), r(36,0b,d4,98),\ - r(cf,81,f5,a6), r(28,de,7a,a5), r(26,8e,b7,da), r(a4,bf,ad,3f),\ - r(e4,9d,3a,2c), r(0d,92,78,50), r(9b,cc,5f,6a), r(62,46,7e,54),\ - r(c2,13,8d,f6), r(e8,b8,d8,90), r(5e,f7,39,2e), r(f5,af,c3,82),\ - r(be,80,5d,9f), r(7c,93,d0,69), r(a9,2d,d5,6f), r(b3,12,25,cf),\ - r(3b,99,ac,c8), r(a7,7d,18,10), r(6e,63,9c,e8), r(7b,bb,3b,db),\ - r(09,78,26,cd), r(f4,18,59,6e), r(01,b7,9a,ec), r(a8,9a,4f,83),\ - r(65,6e,95,e6), r(7e,e6,ff,aa), r(08,cf,bc,21), r(e6,e8,15,ef),\ - r(d9,9b,e7,ba), r(ce,36,6f,4a), r(d4,09,9f,ea), r(d6,7c,b0,29),\ - r(af,b2,a4,31), r(31,23,3f,2a), r(30,94,a5,c6), r(c0,66,a2,35),\ - r(37,bc,4e,74), r(a6,ca,82,fc), r(b0,d0,90,e0), r(15,d8,a7,33),\ - r(4a,98,04,f1), r(f7,da,ec,41), r(0e,50,cd,7f), r(2f,f6,91,17),\ - r(8d,d6,4d,76), r(4d,b0,ef,43), r(54,4d,aa,cc), r(df,04,96,e4),\ - r(e3,b5,d1,9e), r(1b,88,6a,4c), r(b8,1f,2c,c1), r(7f,51,65,46),\ - r(04,ea,5e,9d), r(5d,35,8c,01), r(73,74,87,fa), r(2e,41,0b,fb),\ - r(5a,1d,67,b3), r(52,d2,db,92), r(33,56,10,e9), r(13,47,d6,6d),\ - r(8c,61,d7,9a), r(7a,0c,a1,37), r(8e,14,f8,59), r(89,3c,13,eb),\ - r(ee,27,a9,ce), r(35,c9,61,b7), r(ed,e5,1c,e1), r(3c,b1,47,7a),\ - r(59,df,d2,9c), r(3f,73,f2,55), r(79,ce,14,18), r(bf,37,c7,73),\ - r(ea,cd,f7,53), r(5b,aa,fd,5f), r(14,6f,3d,df), r(86,db,44,78),\ - r(81,f3,af,ca), r(3e,c4,68,b9), r(2c,34,24,38), r(5f,40,a3,c2),\ - r(72,c3,1d,16), r(0c,25,e2,bc), r(8b,49,3c,28), r(41,95,0d,ff),\ - r(71,01,a8,39), r(de,b3,0c,08), r(9c,e4,b4,d8), r(90,c1,56,64),\ - r(61,84,cb,7b), r(70,b6,32,d5), r(74,5c,6c,48), r(42,57,b8,d0) - -// generate the required tables in the desired endian format - -#undef r -#define r r0 - -#if defined(ONE_TABLE) -static const u_int32_t ft_tab[256] = - { f_table }; -#elif defined(FOUR_TABLES) -static const u_int32_t ft_tab[4][256] = -{ { f_table }, -#undef r -#define r r1 - { f_table }, -#undef r -#define r r2 - { f_table }, -#undef r -#define r r3 - { f_table } -}; -#endif - -#undef r -#define r r0 -#if defined(ONE_TABLE) -static const u_int32_t it_tab[256] = - { i_table }; -#elif defined(FOUR_TABLES) -static const u_int32_t it_tab[4][256] = -{ { i_table }, -#undef r -#define r r1 - { i_table }, -#undef r -#define r r2 - { i_table }, -#undef r -#define r r3 - { i_table } -}; -#endif - -#endif - -#if defined(FIXED_TABLES) && (defined(ONE_LR_TABLE) || defined(FOUR_LR_TABLES)) - -// data for inverse tables (last round) - -#define li_table \ - w(52), w(09), w(6a), w(d5), w(30), w(36), w(a5), w(38),\ - w(bf), w(40), w(a3), w(9e), w(81), w(f3), w(d7), w(fb),\ - w(7c), w(e3), w(39), w(82), w(9b), w(2f), w(ff), w(87),\ - w(34), w(8e), w(43), w(44), w(c4), w(de), w(e9), w(cb),\ - w(54), w(7b), w(94), w(32), w(a6), w(c2), w(23), w(3d),\ - w(ee), w(4c), w(95), w(0b), w(42), w(fa), w(c3), w(4e),\ - w(08), w(2e), w(a1), w(66), w(28), w(d9), w(24), w(b2),\ - w(76), w(5b), w(a2), w(49), w(6d), w(8b), w(d1), w(25),\ - w(72), w(f8), w(f6), w(64), w(86), w(68), w(98), w(16),\ - w(d4), w(a4), w(5c), w(cc), w(5d), w(65), w(b6), w(92),\ - w(6c), w(70), w(48), w(50), w(fd), w(ed), w(b9), w(da),\ - w(5e), w(15), w(46), w(57), w(a7), w(8d), w(9d), w(84),\ - w(90), w(d8), w(ab), w(00), w(8c), w(bc), w(d3), w(0a),\ - w(f7), w(e4), w(58), w(05), w(b8), w(b3), w(45), w(06),\ - w(d0), w(2c), w(1e), w(8f), w(ca), w(3f), w(0f), w(02),\ - w(c1), w(af), w(bd), w(03), w(01), w(13), w(8a), w(6b),\ - w(3a), w(91), w(11), w(41), w(4f), w(67), w(dc), w(ea),\ - w(97), w(f2), w(cf), w(ce), w(f0), w(b4), w(e6), w(73),\ - w(96), w(ac), w(74), w(22), w(e7), w(ad), w(35), w(85),\ - w(e2), w(f9), w(37), w(e8), w(1c), w(75), w(df), w(6e),\ - w(47), w(f1), w(1a), w(71), w(1d), w(29), w(c5), w(89),\ - w(6f), w(b7), w(62), w(0e), w(aa), w(18), w(be), w(1b),\ - w(fc), w(56), w(3e), w(4b), w(c6), w(d2), w(79), w(20),\ - w(9a), w(db), w(c0), w(fe), w(78), w(cd), w(5a), w(f4),\ - w(1f), w(dd), w(a8), w(33), w(88), w(07), w(c7), w(31),\ - w(b1), w(12), w(10), w(59), w(27), w(80), w(ec), w(5f),\ - w(60), w(51), w(7f), w(a9), w(19), w(b5), w(4a), w(0d),\ - w(2d), w(e5), w(7a), w(9f), w(93), w(c9), w(9c), w(ef),\ - w(a0), w(e0), w(3b), w(4d), w(ae), w(2a), w(f5), w(b0),\ - w(c8), w(eb), w(bb), w(3c), w(83), w(53), w(99), w(61),\ - w(17), w(2b), w(04), w(7e), w(ba), w(77), w(d6), w(26),\ - w(e1), w(69), w(14), w(63), w(55), w(21), w(0c), w(7d), - -// generate the required tables in the desired endian format - -#undef r -#define r(p,q,r,s) w0(q) -#if defined(ONE_LR_TABLE) -static const u_int32_t fl_tab[256] = - { f_table }; -#elif defined(FOUR_LR_TABLES) -static const u_int32_t fl_tab[4][256] = -{ { f_table }, -#undef r -#define r(p,q,r,s) w1(q) - { f_table }, -#undef r -#define r(p,q,r,s) w2(q) - { f_table }, -#undef r -#define r(p,q,r,s) w3(q) - { f_table } -}; -#endif - -#undef w -#define w w0 -#if defined(ONE_LR_TABLE) -static const u_int32_t il_tab[256] = - { li_table }; -#elif defined(FOUR_LR_TABLES) -static const u_int32_t il_tab[4][256] = -{ { li_table }, -#undef w -#define w w1 - { li_table }, -#undef w -#define w w2 - { li_table }, -#undef w -#define w w3 - { li_table } -}; -#endif - -#endif - -#if defined(FIXED_TABLES) && (defined(ONE_IM_TABLE) || defined(FOUR_IM_TABLES)) - -#define m_table \ - r(00,00,00,00), r(0b,0d,09,0e), r(16,1a,12,1c), r(1d,17,1b,12),\ - r(2c,34,24,38), r(27,39,2d,36), r(3a,2e,36,24), r(31,23,3f,2a),\ - r(58,68,48,70), r(53,65,41,7e), r(4e,72,5a,6c), r(45,7f,53,62),\ - r(74,5c,6c,48), r(7f,51,65,46), r(62,46,7e,54), r(69,4b,77,5a),\ - r(b0,d0,90,e0), r(bb,dd,99,ee), r(a6,ca,82,fc), r(ad,c7,8b,f2),\ - r(9c,e4,b4,d8), r(97,e9,bd,d6), r(8a,fe,a6,c4), r(81,f3,af,ca),\ - r(e8,b8,d8,90), r(e3,b5,d1,9e), r(fe,a2,ca,8c), r(f5,af,c3,82),\ - r(c4,8c,fc,a8), r(cf,81,f5,a6), r(d2,96,ee,b4), r(d9,9b,e7,ba),\ - r(7b,bb,3b,db), r(70,b6,32,d5), r(6d,a1,29,c7), r(66,ac,20,c9),\ - r(57,8f,1f,e3), r(5c,82,16,ed), r(41,95,0d,ff), r(4a,98,04,f1),\ - r(23,d3,73,ab), r(28,de,7a,a5), r(35,c9,61,b7), r(3e,c4,68,b9),\ - r(0f,e7,57,93), r(04,ea,5e,9d), r(19,fd,45,8f), r(12,f0,4c,81),\ - r(cb,6b,ab,3b), r(c0,66,a2,35), r(dd,71,b9,27), r(d6,7c,b0,29),\ - r(e7,5f,8f,03), r(ec,52,86,0d), r(f1,45,9d,1f), r(fa,48,94,11),\ - r(93,03,e3,4b), r(98,0e,ea,45), r(85,19,f1,57), r(8e,14,f8,59),\ - r(bf,37,c7,73), r(b4,3a,ce,7d), r(a9,2d,d5,6f), r(a2,20,dc,61),\ - r(f6,6d,76,ad), r(fd,60,7f,a3), r(e0,77,64,b1), r(eb,7a,6d,bf),\ - r(da,59,52,95), r(d1,54,5b,9b), r(cc,43,40,89), r(c7,4e,49,87),\ - r(ae,05,3e,dd), r(a5,08,37,d3), r(b8,1f,2c,c1), r(b3,12,25,cf),\ - r(82,31,1a,e5), r(89,3c,13,eb), r(94,2b,08,f9), r(9f,26,01,f7),\ - r(46,bd,e6,4d), r(4d,b0,ef,43), r(50,a7,f4,51), r(5b,aa,fd,5f),\ - r(6a,89,c2,75), r(61,84,cb,7b), r(7c,93,d0,69), r(77,9e,d9,67),\ - r(1e,d5,ae,3d), r(15,d8,a7,33), r(08,cf,bc,21), r(03,c2,b5,2f),\ - r(32,e1,8a,05), r(39,ec,83,0b), r(24,fb,98,19), r(2f,f6,91,17),\ - r(8d,d6,4d,76), r(86,db,44,78), r(9b,cc,5f,6a), r(90,c1,56,64),\ - r(a1,e2,69,4e), r(aa,ef,60,40), r(b7,f8,7b,52), r(bc,f5,72,5c),\ - r(d5,be,05,06), r(de,b3,0c,08), r(c3,a4,17,1a), r(c8,a9,1e,14),\ - r(f9,8a,21,3e), r(f2,87,28,30), r(ef,90,33,22), r(e4,9d,3a,2c),\ - r(3d,06,dd,96), r(36,0b,d4,98), r(2b,1c,cf,8a), r(20,11,c6,84),\ - r(11,32,f9,ae), r(1a,3f,f0,a0), r(07,28,eb,b2), r(0c,25,e2,bc),\ - r(65,6e,95,e6), r(6e,63,9c,e8), r(73,74,87,fa), r(78,79,8e,f4),\ - r(49,5a,b1,de), r(42,57,b8,d0), r(5f,40,a3,c2), r(54,4d,aa,cc),\ - r(f7,da,ec,41), r(fc,d7,e5,4f), r(e1,c0,fe,5d), r(ea,cd,f7,53),\ - r(db,ee,c8,79), r(d0,e3,c1,77), r(cd,f4,da,65), r(c6,f9,d3,6b),\ - r(af,b2,a4,31), r(a4,bf,ad,3f), r(b9,a8,b6,2d), r(b2,a5,bf,23),\ - r(83,86,80,09), r(88,8b,89,07), r(95,9c,92,15), r(9e,91,9b,1b),\ - r(47,0a,7c,a1), r(4c,07,75,af), r(51,10,6e,bd), r(5a,1d,67,b3),\ - r(6b,3e,58,99), r(60,33,51,97), r(7d,24,4a,85), r(76,29,43,8b),\ - r(1f,62,34,d1), r(14,6f,3d,df), r(09,78,26,cd), r(02,75,2f,c3),\ - r(33,56,10,e9), r(38,5b,19,e7), r(25,4c,02,f5), r(2e,41,0b,fb),\ - r(8c,61,d7,9a), r(87,6c,de,94), r(9a,7b,c5,86), r(91,76,cc,88),\ - r(a0,55,f3,a2), r(ab,58,fa,ac), r(b6,4f,e1,be), r(bd,42,e8,b0),\ - r(d4,09,9f,ea), r(df,04,96,e4), r(c2,13,8d,f6), r(c9,1e,84,f8),\ - r(f8,3d,bb,d2), r(f3,30,b2,dc), r(ee,27,a9,ce), r(e5,2a,a0,c0),\ - r(3c,b1,47,7a), r(37,bc,4e,74), r(2a,ab,55,66), r(21,a6,5c,68),\ - r(10,85,63,42), r(1b,88,6a,4c), r(06,9f,71,5e), r(0d,92,78,50),\ - r(64,d9,0f,0a), r(6f,d4,06,04), r(72,c3,1d,16), r(79,ce,14,18),\ - r(48,ed,2b,32), r(43,e0,22,3c), r(5e,f7,39,2e), r(55,fa,30,20),\ - r(01,b7,9a,ec), r(0a,ba,93,e2), r(17,ad,88,f0), r(1c,a0,81,fe),\ - r(2d,83,be,d4), r(26,8e,b7,da), r(3b,99,ac,c8), r(30,94,a5,c6),\ - r(59,df,d2,9c), r(52,d2,db,92), r(4f,c5,c0,80), r(44,c8,c9,8e),\ - r(75,eb,f6,a4), r(7e,e6,ff,aa), r(63,f1,e4,b8), r(68,fc,ed,b6),\ - r(b1,67,0a,0c), r(ba,6a,03,02), r(a7,7d,18,10), r(ac,70,11,1e),\ - r(9d,53,2e,34), r(96,5e,27,3a), r(8b,49,3c,28), r(80,44,35,26),\ - r(e9,0f,42,7c), r(e2,02,4b,72), r(ff,15,50,60), r(f4,18,59,6e),\ - r(c5,3b,66,44), r(ce,36,6f,4a), r(d3,21,74,58), r(d8,2c,7d,56),\ - r(7a,0c,a1,37), r(71,01,a8,39), r(6c,16,b3,2b), r(67,1b,ba,25),\ - r(56,38,85,0f), r(5d,35,8c,01), r(40,22,97,13), r(4b,2f,9e,1d),\ - r(22,64,e9,47), r(29,69,e0,49), r(34,7e,fb,5b), r(3f,73,f2,55),\ - r(0e,50,cd,7f), r(05,5d,c4,71), r(18,4a,df,63), r(13,47,d6,6d),\ - r(ca,dc,31,d7), r(c1,d1,38,d9), r(dc,c6,23,cb), r(d7,cb,2a,c5),\ - r(e6,e8,15,ef), r(ed,e5,1c,e1), r(f0,f2,07,f3), r(fb,ff,0e,fd),\ - r(92,b4,79,a7), r(99,b9,70,a9), r(84,ae,6b,bb), r(8f,a3,62,b5),\ - r(be,80,5d,9f), r(b5,8d,54,91), r(a8,9a,4f,83), r(a3,97,46,8d) - -#undef r -#define r r0 - -#if defined(ONE_IM_TABLE) -static const u_int32_t im_tab[256] = - { m_table }; -#elif defined(FOUR_IM_TABLES) -static const u_int32_t im_tab[4][256] = -{ { m_table }, -#undef r -#define r r1 - { m_table }, -#undef r -#define r r2 - { m_table }, -#undef r -#define r r3 - { m_table } -}; -#endif - -#endif - -#else - -static int tab_gen = 0; - -static unsigned char s_box[256]; // the S box -static unsigned char inv_s_box[256]; // the inverse S box -static u_int32_t rcon_tab[AES_RC_LENGTH]; // table of round constants - -#if defined(ONE_TABLE) -static u_int32_t ft_tab[256]; -static u_int32_t it_tab[256]; -#elif defined(FOUR_TABLES) -static u_int32_t ft_tab[4][256]; -static u_int32_t it_tab[4][256]; -#endif - -#if defined(ONE_LR_TABLE) -static u_int32_t fl_tab[256]; -static u_int32_t il_tab[256]; -#elif defined(FOUR_LR_TABLES) -static u_int32_t fl_tab[4][256]; -static u_int32_t il_tab[4][256]; -#endif - -#if defined(ONE_IM_TABLE) -static u_int32_t im_tab[256]; -#elif defined(FOUR_IM_TABLES) -static u_int32_t im_tab[4][256]; -#endif - -// Generate the tables for the dynamic table option - -#if !defined(FF_TABLES) - -// It will generally be sensible to use tables to compute finite -// field multiplies and inverses but where memory is scarse this -// code might sometimes be better. - -// return 2 ^ (n - 1) where n is the bit number of the highest bit -// set in x with x in the range 1 < x < 0x00000200. This form is -// used so that locals within FFinv can be bytes rather than words - -static unsigned char hibit(const u_int32_t x) -{ unsigned char r = (unsigned char)((x >> 1) | (x >> 2)); - - r |= (r >> 2); - r |= (r >> 4); - return (r + 1) >> 1; -} - -// return the inverse of the finite field element x - -static unsigned char FFinv(const unsigned char x) -{ unsigned char p1 = x, p2 = 0x1b, n1 = hibit(x), n2 = 0x80, v1 = 1, v2 = 0; - - if(x < 2) return x; - - for(;;) - { - if(!n1) return v1; - - while(n2 >= n1) - { - n2 /= n1; p2 ^= p1 * n2; v2 ^= v1 * n2; n2 = hibit(p2); - } - - if(!n2) return v2; - - while(n1 >= n2) - { - n1 /= n2; p1 ^= p2 * n1; v1 ^= v2 * n1; n1 = hibit(p1); - } - } -} - -// define the finite field multiplies required for Rijndael - -#define FFmul02(x) ((((x) & 0x7f) << 1) ^ ((x) & 0x80 ? 0x1b : 0)) -#define FFmul03(x) ((x) ^ FFmul02(x)) -#define FFmul09(x) ((x) ^ FFmul02(FFmul02(FFmul02(x)))) -#define FFmul0b(x) ((x) ^ FFmul02((x) ^ FFmul02(FFmul02(x)))) -#define FFmul0d(x) ((x) ^ FFmul02(FFmul02((x) ^ FFmul02(x)))) -#define FFmul0e(x) FFmul02((x) ^ FFmul02((x) ^ FFmul02(x))) - -#else - -#define FFinv(x) ((x) ? pow[255 - log[x]]: 0) - -#define FFmul02(x) (x ? pow[log[x] + 0x19] : 0) -#define FFmul03(x) (x ? pow[log[x] + 0x01] : 0) -#define FFmul09(x) (x ? pow[log[x] + 0xc7] : 0) -#define FFmul0b(x) (x ? pow[log[x] + 0x68] : 0) -#define FFmul0d(x) (x ? pow[log[x] + 0xee] : 0) -#define FFmul0e(x) (x ? pow[log[x] + 0xdf] : 0) - -#endif - -// The forward and inverse affine transformations used in the S-box - -#define fwd_affine(x) \ - (w = (u_int32_t)x, w ^= (w<<1)^(w<<2)^(w<<3)^(w<<4), 0x63^(unsigned char)(w^(w>>8))) - -#define inv_affine(x) \ - (w = (u_int32_t)x, w = (w<<1)^(w<<3)^(w<<6), 0x05^(unsigned char)(w^(w>>8))) - -static void gen_tabs(void) -{ u_int32_t i, w; - -#if defined(FF_TABLES) - - unsigned char pow[512], log[256]; - - // log and power tables for GF(2^8) finite field with - // 0x011b as modular polynomial - the simplest primitive - // root is 0x03, used here to generate the tables - - i = 0; w = 1; - do - { - pow[i] = (unsigned char)w; - pow[i + 255] = (unsigned char)w; - log[w] = (unsigned char)i++; - w ^= (w << 1) ^ (w & ff_hi ? ff_poly : 0); - } - while (w != 1); - -#endif - - for(i = 0, w = 1; i < AES_RC_LENGTH; ++i) - { - rcon_tab[i] = bytes2word(w, 0, 0, 0); - w = (w << 1) ^ (w & ff_hi ? ff_poly : 0); - } - - for(i = 0; i < 256; ++i) - { unsigned char b; - - s_box[i] = b = fwd_affine(FFinv((unsigned char)i)); - - w = bytes2word(b, 0, 0, 0); -#if defined(ONE_LR_TABLE) - fl_tab[i] = w; -#elif defined(FOUR_LR_TABLES) - fl_tab[0][i] = w; - fl_tab[1][i] = upr(w,1); - fl_tab[2][i] = upr(w,2); - fl_tab[3][i] = upr(w,3); -#endif - w = bytes2word(FFmul02(b), b, b, FFmul03(b)); -#if defined(ONE_TABLE) - ft_tab[i] = w; -#elif defined(FOUR_TABLES) - ft_tab[0][i] = w; - ft_tab[1][i] = upr(w,1); - ft_tab[2][i] = upr(w,2); - ft_tab[3][i] = upr(w,3); -#endif - inv_s_box[i] = b = FFinv(inv_affine((unsigned char)i)); - - w = bytes2word(b, 0, 0, 0); -#if defined(ONE_LR_TABLE) - il_tab[i] = w; -#elif defined(FOUR_LR_TABLES) - il_tab[0][i] = w; - il_tab[1][i] = upr(w,1); - il_tab[2][i] = upr(w,2); - il_tab[3][i] = upr(w,3); -#endif - w = bytes2word(FFmul0e(b), FFmul09(b), FFmul0d(b), FFmul0b(b)); -#if defined(ONE_TABLE) - it_tab[i] = w; -#elif defined(FOUR_TABLES) - it_tab[0][i] = w; - it_tab[1][i] = upr(w,1); - it_tab[2][i] = upr(w,2); - it_tab[3][i] = upr(w,3); -#endif -#if defined(ONE_IM_TABLE) - im_tab[b] = w; -#elif defined(FOUR_IM_TABLES) - im_tab[0][b] = w; - im_tab[1][b] = upr(w,1); - im_tab[2][b] = upr(w,2); - im_tab[3][b] = upr(w,3); -#endif - - } -} - -#endif - -#define no_table(x,box,vf,rf,c) bytes2word( \ - box[bval(vf(x,0,c),rf(0,c))], \ - box[bval(vf(x,1,c),rf(1,c))], \ - box[bval(vf(x,2,c),rf(2,c))], \ - box[bval(vf(x,3,c),rf(3,c))]) - -#define one_table(x,op,tab,vf,rf,c) \ - ( tab[bval(vf(x,0,c),rf(0,c))] \ - ^ op(tab[bval(vf(x,1,c),rf(1,c))],1) \ - ^ op(tab[bval(vf(x,2,c),rf(2,c))],2) \ - ^ op(tab[bval(vf(x,3,c),rf(3,c))],3)) - -#define four_tables(x,tab,vf,rf,c) \ - ( tab[0][bval(vf(x,0,c),rf(0,c))] \ - ^ tab[1][bval(vf(x,1,c),rf(1,c))] \ - ^ tab[2][bval(vf(x,2,c),rf(2,c))] \ - ^ tab[3][bval(vf(x,3,c),rf(3,c))]) - -#define vf1(x,r,c) (x) -#define rf1(r,c) (r) -#define rf2(r,c) ((r-c)&3) - -#if defined(FOUR_LR_TABLES) -#define ls_box(x,c) four_tables(x,fl_tab,vf1,rf2,c) -#elif defined(ONE_LR_TABLE) -#define ls_box(x,c) one_table(x,upr,fl_tab,vf1,rf2,c) -#else -#define ls_box(x,c) no_table(x,s_box,vf1,rf2,c) -#endif - -#if defined(FOUR_IM_TABLES) -#define inv_mcol(x) four_tables(x,im_tab,vf1,rf1,0) -#elif defined(ONE_IM_TABLE) -#define inv_mcol(x) one_table(x,upr,im_tab,vf1,rf1,0) -#else -#define inv_mcol(x) \ - (f9 = (x),f2 = FFmulX(f9), f4 = FFmulX(f2), f8 = FFmulX(f4), f9 ^= f8, \ - f2 ^= f4 ^ f8 ^ upr(f2 ^ f9,3) ^ upr(f4 ^ f9,2) ^ upr(f9,1)) -#endif - -#define nc (AES_BLOCK_SIZE/4) - -// Initialise the key schedule from the user supplied key. The key -// length is now specified in bytes - 16, 24 or 32 as appropriate. -// This corresponds to bit lengths of 128, 192 and 256 bits, and -// to Nk values of 4, 6 and 8 respectively. - -#define mx(t,f) (*t++ = inv_mcol(*f),f++) -#define cp(t,f) *t++ = *f++ - -#if AES_BLOCK_SIZE == 16 -#define cpy(d,s) cp(d,s); cp(d,s); cp(d,s); cp(d,s) -#define mix(d,s) mx(d,s); mx(d,s); mx(d,s); mx(d,s) -#elif AES_BLOCK_SIZE == 24 -#define cpy(d,s) cp(d,s); cp(d,s); cp(d,s); cp(d,s); \ - cp(d,s); cp(d,s) -#define mix(d,s) mx(d,s); mx(d,s); mx(d,s); mx(d,s); \ - mx(d,s); mx(d,s) -#elif AES_BLOCK_SIZE == 32 -#define cpy(d,s) cp(d,s); cp(d,s); cp(d,s); cp(d,s); \ - cp(d,s); cp(d,s); cp(d,s); cp(d,s) -#define mix(d,s) mx(d,s); mx(d,s); mx(d,s); mx(d,s); \ - mx(d,s); mx(d,s); mx(d,s); mx(d,s) -#else - -#define cpy(d,s) \ -switch(nc) \ -{ case 8: cp(d,s); cp(d,s); \ - case 6: cp(d,s); cp(d,s); \ - case 4: cp(d,s); cp(d,s); \ - cp(d,s); cp(d,s); \ -} - -#define mix(d,s) \ -switch(nc) \ -{ case 8: mx(d,s); mx(d,s); \ - case 6: mx(d,s); mx(d,s); \ - case 4: mx(d,s); mx(d,s); \ - mx(d,s); mx(d,s); \ -} - -#endif - -// y = output word, x = input word, r = row, c = column -// for r = 0, 1, 2 and 3 = column accessed for row r - -#if defined(ARRAYS) -#define s(x,c) x[c] -#else -#define s(x,c) x##c -#endif - -// I am grateful to Frank Yellin for the following constructions -// which, given the column (c) of the output state variable that -// is being computed, return the input state variables which are -// needed for each row (r) of the state - -// For the fixed block size options, compilers reduce these two -// expressions to fixed variable references. For variable block -// size code conditional clauses will sometimes be returned - -#define unused 77 // Sunset Strip - -#define fwd_var(x,r,c) \ - ( r==0 ? \ - ( c==0 ? s(x,0) \ - : c==1 ? s(x,1) \ - : c==2 ? s(x,2) \ - : c==3 ? s(x,3) \ - : c==4 ? s(x,4) \ - : c==5 ? s(x,5) \ - : c==6 ? s(x,6) \ - : s(x,7)) \ - : r==1 ? \ - ( c==0 ? s(x,1) \ - : c==1 ? s(x,2) \ - : c==2 ? s(x,3) \ - : c==3 ? nc==4 ? s(x,0) : s(x,4) \ - : c==4 ? s(x,5) \ - : c==5 ? nc==8 ? s(x,6) : s(x,0) \ - : c==6 ? s(x,7) \ - : s(x,0)) \ - : r==2 ? \ - ( c==0 ? nc==8 ? s(x,3) : s(x,2) \ - : c==1 ? nc==8 ? s(x,4) : s(x,3) \ - : c==2 ? nc==4 ? s(x,0) : nc==8 ? s(x,5) : s(x,4) \ - : c==3 ? nc==4 ? s(x,1) : nc==8 ? s(x,6) : s(x,5) \ - : c==4 ? nc==8 ? s(x,7) : s(x,0) \ - : c==5 ? nc==8 ? s(x,0) : s(x,1) \ - : c==6 ? s(x,1) \ - : s(x,2)) \ - : \ - ( c==0 ? nc==8 ? s(x,4) : s(x,3) \ - : c==1 ? nc==4 ? s(x,0) : nc==8 ? s(x,5) : s(x,4) \ - : c==2 ? nc==4 ? s(x,1) : nc==8 ? s(x,6) : s(x,5) \ - : c==3 ? nc==4 ? s(x,2) : nc==8 ? s(x,7) : s(x,0) \ - : c==4 ? nc==8 ? s(x,0) : s(x,1) \ - : c==5 ? nc==8 ? s(x,1) : s(x,2) \ - : c==6 ? s(x,2) \ - : s(x,3))) - -#define inv_var(x,r,c) \ - ( r==0 ? \ - ( c==0 ? s(x,0) \ - : c==1 ? s(x,1) \ - : c==2 ? s(x,2) \ - : c==3 ? s(x,3) \ - : c==4 ? s(x,4) \ - : c==5 ? s(x,5) \ - : c==6 ? s(x,6) \ - : s(x,7)) \ - : r==1 ? \ - ( c==0 ? nc==4 ? s(x,3) : nc==8 ? s(x,7) : s(x,5) \ - : c==1 ? s(x,0) \ - : c==2 ? s(x,1) \ - : c==3 ? s(x,2) \ - : c==4 ? s(x,3) \ - : c==5 ? s(x,4) \ - : c==6 ? s(x,5) \ - : s(x,6)) \ - : r==2 ? \ - ( c==0 ? nc==4 ? s(x,2) : nc==8 ? s(x,5) : s(x,4) \ - : c==1 ? nc==4 ? s(x,3) : nc==8 ? s(x,6) : s(x,5) \ - : c==2 ? nc==8 ? s(x,7) : s(x,0) \ - : c==3 ? nc==8 ? s(x,0) : s(x,1) \ - : c==4 ? nc==8 ? s(x,1) : s(x,2) \ - : c==5 ? nc==8 ? s(x,2) : s(x,3) \ - : c==6 ? s(x,3) \ - : s(x,4)) \ - : \ - ( c==0 ? nc==4 ? s(x,1) : nc==8 ? s(x,4) : s(x,3) \ - : c==1 ? nc==4 ? s(x,2) : nc==8 ? s(x,5) : s(x,4) \ - : c==2 ? nc==4 ? s(x,3) : nc==8 ? s(x,6) : s(x,5) \ - : c==3 ? nc==8 ? s(x,7) : s(x,0) \ - : c==4 ? nc==8 ? s(x,0) : s(x,1) \ - : c==5 ? nc==8 ? s(x,1) : s(x,2) \ - : c==6 ? s(x,2) \ - : s(x,3))) - -#define si(y,x,k,c) s(y,c) = const_word_in(x + 4 * c) ^ k[c] -#define so(y,x,c) word_out(y + 4 * c, s(x,c)) - -#if defined(FOUR_TABLES) -#define fwd_rnd(y,x,k,c) s(y,c)= (k)[c] ^ four_tables(x,ft_tab,fwd_var,rf1,c) -#define inv_rnd(y,x,k,c) s(y,c)= (k)[c] ^ four_tables(x,it_tab,inv_var,rf1,c) -#elif defined(ONE_TABLE) -#define fwd_rnd(y,x,k,c) s(y,c)= (k)[c] ^ one_table(x,upr,ft_tab,fwd_var,rf1,c) -#define inv_rnd(y,x,k,c) s(y,c)= (k)[c] ^ one_table(x,upr,it_tab,inv_var,rf1,c) -#else -#define fwd_rnd(y,x,k,c) s(y,c) = fwd_mcol(no_table(x,s_box,fwd_var,rf1,c)) ^ (k)[c] -#define inv_rnd(y,x,k,c) s(y,c) = inv_mcol(no_table(x,inv_s_box,inv_var,rf1,c) ^ (k)[c]) -#endif - -#if defined(FOUR_LR_TABLES) -#define fwd_lrnd(y,x,k,c) s(y,c)= (k)[c] ^ four_tables(x,fl_tab,fwd_var,rf1,c) -#define inv_lrnd(y,x,k,c) s(y,c)= (k)[c] ^ four_tables(x,il_tab,inv_var,rf1,c) -#elif defined(ONE_LR_TABLE) -#define fwd_lrnd(y,x,k,c) s(y,c)= (k)[c] ^ one_table(x,ups,fl_tab,fwd_var,rf1,c) -#define inv_lrnd(y,x,k,c) s(y,c)= (k)[c] ^ one_table(x,ups,il_tab,inv_var,rf1,c) -#else -#define fwd_lrnd(y,x,k,c) s(y,c) = no_table(x,s_box,fwd_var,rf1,c) ^ (k)[c] -#define inv_lrnd(y,x,k,c) s(y,c) = no_table(x,inv_s_box,inv_var,rf1,c) ^ (k)[c] -#endif - -#if AES_BLOCK_SIZE == 16 - -#if defined(ARRAYS) -#define locals(y,x) x[4],y[4] -#else -#define locals(y,x) x##0,x##1,x##2,x##3,y##0,y##1,y##2,y##3 -// the following defines prevent the compiler requiring the declaration -// of generated but unused variables in the fwd_var and inv_var macros -#define b04 unused -#define b05 unused -#define b06 unused -#define b07 unused -#define b14 unused -#define b15 unused -#define b16 unused -#define b17 unused -#endif -#define l_copy(y, x) s(y,0) = s(x,0); s(y,1) = s(x,1); \ - s(y,2) = s(x,2); s(y,3) = s(x,3); -#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); si(y,x,k,3) -#define state_out(y,x) so(y,x,0); so(y,x,1); so(y,x,2); so(y,x,3) -#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); rm(y,x,k,3) - -#elif AES_BLOCK_SIZE == 24 - -#if defined(ARRAYS) -#define locals(y,x) x[6],y[6] -#else -#define locals(y,x) x##0,x##1,x##2,x##3,x##4,x##5, \ - y##0,y##1,y##2,y##3,y##4,y##5 -#define b06 unused -#define b07 unused -#define b16 unused -#define b17 unused -#endif -#define l_copy(y, x) s(y,0) = s(x,0); s(y,1) = s(x,1); \ - s(y,2) = s(x,2); s(y,3) = s(x,3); \ - s(y,4) = s(x,4); s(y,5) = s(x,5); -#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); \ - si(y,x,k,3); si(y,x,k,4); si(y,x,k,5) -#define state_out(y,x) so(y,x,0); so(y,x,1); so(y,x,2); \ - so(y,x,3); so(y,x,4); so(y,x,5) -#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); \ - rm(y,x,k,3); rm(y,x,k,4); rm(y,x,k,5) -#else - -#if defined(ARRAYS) -#define locals(y,x) x[8],y[8] -#else -#define locals(y,x) x##0,x##1,x##2,x##3,x##4,x##5,x##6,x##7, \ - y##0,y##1,y##2,y##3,y##4,y##5,y##6,y##7 -#endif -#define l_copy(y, x) s(y,0) = s(x,0); s(y,1) = s(x,1); \ - s(y,2) = s(x,2); s(y,3) = s(x,3); \ - s(y,4) = s(x,4); s(y,5) = s(x,5); \ - s(y,6) = s(x,6); s(y,7) = s(x,7); - -#if AES_BLOCK_SIZE == 32 - -#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); si(y,x,k,3); \ - si(y,x,k,4); si(y,x,k,5); si(y,x,k,6); si(y,x,k,7) -#define state_out(y,x) so(y,x,0); so(y,x,1); so(y,x,2); so(y,x,3); \ - so(y,x,4); so(y,x,5); so(y,x,6); so(y,x,7) -#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); rm(y,x,k,3); \ - rm(y,x,k,4); rm(y,x,k,5); rm(y,x,k,6); rm(y,x,k,7) -#else - -#define state_in(y,x,k) \ -switch(nc) \ -{ case 8: si(y,x,k,7); si(y,x,k,6); \ - case 6: si(y,x,k,5); si(y,x,k,4); \ - case 4: si(y,x,k,3); si(y,x,k,2); \ - si(y,x,k,1); si(y,x,k,0); \ -} - -#define state_out(y,x) \ -switch(nc) \ -{ case 8: so(y,x,7); so(y,x,6); \ - case 6: so(y,x,5); so(y,x,4); \ - case 4: so(y,x,3); so(y,x,2); \ - so(y,x,1); so(y,x,0); \ -} - -#if defined(FAST_VARIABLE) - -#define round(rm,y,x,k) \ -switch(nc) \ -{ case 8: rm(y,x,k,7); rm(y,x,k,6); \ - rm(y,x,k,5); rm(y,x,k,4); \ - rm(y,x,k,3); rm(y,x,k,2); \ - rm(y,x,k,1); rm(y,x,k,0); \ - break; \ - case 6: rm(y,x,k,5); rm(y,x,k,4); \ - rm(y,x,k,3); rm(y,x,k,2); \ - rm(y,x,k,1); rm(y,x,k,0); \ - break; \ - case 4: rm(y,x,k,3); rm(y,x,k,2); \ - rm(y,x,k,1); rm(y,x,k,0); \ - break; \ -} -#else - -#define round(rm,y,x,k) \ -switch(nc) \ -{ case 8: rm(y,x,k,7); rm(y,x,k,6); \ - case 6: rm(y,x,k,5); rm(y,x,k,4); \ - case 4: rm(y,x,k,3); rm(y,x,k,2); \ - rm(y,x,k,1); rm(y,x,k,0); \ -} - -#endif - -#endif -#endif - -/** - * Implementation of private_aes_cbc_crypter_t.encrypt_block. - */ -static void encrypt_block(const private_aes_cbc_crypter_t *this, const unsigned char in_blk[], unsigned char out_blk[]) -{ u_int32_t locals(b0, b1); - const u_int32_t *kp = this->aes_e_key; - -#if !defined(ONE_TABLE) && !defined(FOUR_TABLES) - u_int32_t f2; -#endif - - state_in(b0, in_blk, kp); kp += nc; - -#if defined(UNROLL) - - switch(this->aes_Nrnd) - { - case 14: round(fwd_rnd, b1, b0, kp ); - round(fwd_rnd, b0, b1, kp + nc ); kp += 2 * nc; - case 12: round(fwd_rnd, b1, b0, kp ); - round(fwd_rnd, b0, b1, kp + nc ); kp += 2 * nc; - case 10: round(fwd_rnd, b1, b0, kp ); - round(fwd_rnd, b0, b1, kp + nc); - round(fwd_rnd, b1, b0, kp + 2 * nc); - round(fwd_rnd, b0, b1, kp + 3 * nc); - round(fwd_rnd, b1, b0, kp + 4 * nc); - round(fwd_rnd, b0, b1, kp + 5 * nc); - round(fwd_rnd, b1, b0, kp + 6 * nc); - round(fwd_rnd, b0, b1, kp + 7 * nc); - round(fwd_rnd, b1, b0, kp + 8 * nc); - round(fwd_lrnd, b0, b1, kp + 9 * nc); - } - -#elif defined(PARTIAL_UNROLL) - { u_int32_t rnd; - - for(rnd = 0; rnd < (this->aes_Nrnd >> 1) - 1; ++rnd) - { - round(fwd_rnd, b1, b0, kp); - round(fwd_rnd, b0, b1, kp + nc); kp += 2 * nc; - } - - round(fwd_rnd, b1, b0, kp); - round(fwd_lrnd, b0, b1, kp + nc); - } -#else - { u_int32_t rnd; - - for(rnd = 0; rnd < this->aes_Nrnd - 1; ++rnd) - { - round(fwd_rnd, b1, b0, kp); - l_copy(b0, b1); kp += nc; - } - - round(fwd_lrnd, b0, b1, kp); - } -#endif - - state_out(out_blk, b0); -} - -/** - * Implementation of private_aes_cbc_crypter_t.decrypt_block. - */ -static void decrypt_block(const private_aes_cbc_crypter_t *this, const unsigned char in_blk[], unsigned char out_blk[]) -{ u_int32_t locals(b0, b1); - const u_int32_t *kp = this->aes_d_key; - -#if !defined(ONE_TABLE) && !defined(FOUR_TABLES) - u_int32_t f2, f4, f8, f9; -#endif - - state_in(b0, in_blk, kp); kp += nc; - -#if defined(UNROLL) - - switch(this->aes_Nrnd) - { - case 14: round(inv_rnd, b1, b0, kp ); - round(inv_rnd, b0, b1, kp + nc ); kp += 2 * nc; - case 12: round(inv_rnd, b1, b0, kp ); - round(inv_rnd, b0, b1, kp + nc ); kp += 2 * nc; - case 10: round(inv_rnd, b1, b0, kp ); - round(inv_rnd, b0, b1, kp + nc); - round(inv_rnd, b1, b0, kp + 2 * nc); - round(inv_rnd, b0, b1, kp + 3 * nc); - round(inv_rnd, b1, b0, kp + 4 * nc); - round(inv_rnd, b0, b1, kp + 5 * nc); - round(inv_rnd, b1, b0, kp + 6 * nc); - round(inv_rnd, b0, b1, kp + 7 * nc); - round(inv_rnd, b1, b0, kp + 8 * nc); - round(inv_lrnd, b0, b1, kp + 9 * nc); - } - -#elif defined(PARTIAL_UNROLL) - { u_int32_t rnd; - - for(rnd = 0; rnd < (this->aes_Nrnd >> 1) - 1; ++rnd) - { - round(inv_rnd, b1, b0, kp); - round(inv_rnd, b0, b1, kp + nc); kp += 2 * nc; - } - - round(inv_rnd, b1, b0, kp); - round(inv_lrnd, b0, b1, kp + nc); - } -#else - { u_int32_t rnd; - - for(rnd = 0; rnd < this->aes_Nrnd - 1; ++rnd) - { - round(inv_rnd, b1, b0, kp); - l_copy(b0, b1); kp += nc; - } - - round(inv_lrnd, b0, b1, kp); - } -#endif - - state_out(out_blk, b0); -} - -/** - * Implementation of crypter_t.decrypt. - */ -static status_t decrypt (private_aes_cbc_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *decrypted) -{ - int ret, pos; - const u_int32_t *iv_i; - u_int8_t *in, *out; - - ret = data.len; - if (((data.len) % 16) != 0) - { - /* data length must be padded to a multiple of blocksize */ - return INVALID_ARG; - } - - decrypted->ptr = malloc(data.len); - if (decrypted->ptr == NULL) - { - return OUT_OF_RES; - } - decrypted->len = data.len; - - in = data.ptr; - out = decrypted->ptr; - - pos=data.len-16; - in+=pos; - out+=pos; - while(pos>=0) { - this->decrypt_block(this,in,out); - if (pos==0) - iv_i=(const u_int32_t*) (iv.ptr); - else - iv_i=(const u_int32_t*) (in-16); - *((u_int32_t *)(&out[ 0])) ^= iv_i[0]; - *((u_int32_t *)(&out[ 4])) ^= iv_i[1]; - *((u_int32_t *)(&out[ 8])) ^= iv_i[2]; - *((u_int32_t *)(&out[12])) ^= iv_i[3]; - in-=16; - out-=16; - pos-=16; - } - - return SUCCESS; -} - - -/** - * Implementation of crypter_t.decrypt. - */ -static status_t encrypt (private_aes_cbc_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *encrypted) -{ - int ret, pos; - const u_int32_t *iv_i; - u_int8_t *in, *out; - - ret = data.len; - if (((data.len) % 16) != 0) - { - /* data length must be padded to a multiple of blocksize */ - return INVALID_ARG; - } - - encrypted->ptr = malloc(data.len); - if (encrypted->ptr == NULL) - { - return OUT_OF_RES; - } - encrypted->len = data.len; - - in = data.ptr; - out = encrypted->ptr; - - pos=0; - while(posencrypt_block(this,out,out); - in+=16; - out+=16; - pos+=16; - } - return SUCCESS; -} - -/** - * Implementation of crypter_t.get_block_size. - */ -static size_t get_block_size (private_aes_cbc_crypter_t *this) -{ - return AES_BLOCK_SIZE; -} - -/** - * Implementation of crypter_t.get_key_size. - */ -static size_t get_key_size (private_aes_cbc_crypter_t *this) -{ - return this->key_size; -} - -/** - * Implementation of crypter_t.set_key. - */ -static status_t set_key (private_aes_cbc_crypter_t *this, chunk_t key) -{ - u_int32_t *kf, *kt, rci, f = 0; - u_int8_t *in_key = key.ptr; - - if (key.len != this->key_size) - { - return INVALID_ARG; - } - - this->aes_Nrnd = (this->aes_Nkey > (nc) ? this->aes_Nkey : (nc)) + 6; - - this->aes_e_key[0] = const_word_in(in_key ); - this->aes_e_key[1] = const_word_in(in_key + 4); - this->aes_e_key[2] = const_word_in(in_key + 8); - this->aes_e_key[3] = const_word_in(in_key + 12); - - kf = this->aes_e_key; - kt = kf + nc * (this->aes_Nrnd + 1) - this->aes_Nkey; - rci = 0; - - switch(this->aes_Nkey) - { - case 4: do - { kf[4] = kf[0] ^ ls_box(kf[3],3) ^ rcon_tab[rci++]; - kf[5] = kf[1] ^ kf[4]; - kf[6] = kf[2] ^ kf[5]; - kf[7] = kf[3] ^ kf[6]; - kf += 4; - } - while(kf < kt); - break; - - case 6: this->aes_e_key[4] = const_word_in(in_key + 16); - this->aes_e_key[5] = const_word_in(in_key + 20); - do - { kf[ 6] = kf[0] ^ ls_box(kf[5],3) ^ rcon_tab[rci++]; - kf[ 7] = kf[1] ^ kf[ 6]; - kf[ 8] = kf[2] ^ kf[ 7]; - kf[ 9] = kf[3] ^ kf[ 8]; - kf[10] = kf[4] ^ kf[ 9]; - kf[11] = kf[5] ^ kf[10]; - kf += 6; - } - while(kf < kt); - break; - - case 8: this->aes_e_key[4] = const_word_in(in_key + 16); - this->aes_e_key[5] = const_word_in(in_key + 20); - this->aes_e_key[6] = const_word_in(in_key + 24); - this->aes_e_key[7] = const_word_in(in_key + 28); - do - { kf[ 8] = kf[0] ^ ls_box(kf[7],3) ^ rcon_tab[rci++]; - kf[ 9] = kf[1] ^ kf[ 8]; - kf[10] = kf[2] ^ kf[ 9]; - kf[11] = kf[3] ^ kf[10]; - kf[12] = kf[4] ^ ls_box(kf[11],0); - kf[13] = kf[5] ^ kf[12]; - kf[14] = kf[6] ^ kf[13]; - kf[15] = kf[7] ^ kf[14]; - kf += 8; - } - while (kf < kt); - break; - } - - if(!f) - { - u_int32_t i; - - kt = this->aes_d_key + nc * this->aes_Nrnd; - kf = this->aes_e_key; - - cpy(kt, kf); kt -= 2 * nc; - - for(i = 1; i < this->aes_Nrnd; ++i) - { -#if defined(ONE_TABLE) || defined(FOUR_TABLES) -#if !defined(ONE_IM_TABLE) && !defined(FOUR_IM_TABLES) - u_int32_t f2, f4, f8, f9; -#endif - mix(kt, kf); -#else - cpy(kt, kf); -#endif - kt -= 2 * nc; - } - cpy(kt, kf); - } - - return SUCCESS; -} - -/** - * Implementation of crypter_t.destroy and aes_cbc_crypter_t.destroy. - */ -static void destroy (private_aes_cbc_crypter_t *this) -{ - free(this); -} - -/* - * Described in header - */ -aes_cbc_crypter_t *aes_cbc_crypter_create(size_t key_size) -{ - private_aes_cbc_crypter_t *this = malloc_thing(private_aes_cbc_crypter_t); - - #if !defined(FIXED_TABLES) - if(!tab_gen) { gen_tabs(); tab_gen = 1; } - #endif - - this->key_size = key_size; - switch(key_size) { - case 32: /* bytes */ - this->aes_Nkey = 8; - break; - case 24: /* bytes */ - this->aes_Nkey = 6; - break; - case 16: /* bytes */ - this->aes_Nkey = 4; - break; - default: - free(this); - return NULL; - } - - /* functions of crypter_t interface */ - this->public.crypter_interface.encrypt = (status_t (*) (crypter_t *, chunk_t,chunk_t, chunk_t *)) encrypt; - this->public.crypter_interface.decrypt = (status_t (*) (crypter_t *, chunk_t , chunk_t, chunk_t *)) decrypt; - this->public.crypter_interface.get_block_size = (size_t (*) (crypter_t *)) get_block_size; - this->public.crypter_interface.get_key_size = (size_t (*) (crypter_t *)) get_key_size; - this->public.crypter_interface.set_key = (status_t (*) (crypter_t *,chunk_t)) set_key; - this->public.crypter_interface.destroy = (void (*) (crypter_t *)) destroy; - - /* private functions */ - this->decrypt_block = decrypt_block; - this->encrypt_block = encrypt_block; - - return &(this->public); -} diff --git a/src/libstrongswan/crypto/crypters/aes_cbc_crypter.h b/src/libstrongswan/crypto/crypters/aes_cbc_crypter.h deleted file mode 100644 index 5da248b8c..000000000 --- a/src/libstrongswan/crypto/crypters/aes_cbc_crypter.h +++ /dev/null @@ -1,61 +0,0 @@ -/** - * @file aes_cbc_crypter.h - * - * @brief Interface of aes_cbc_crypter_t - * - */ - -/* - * Copyright (C) 2001 Dr B. R. Gladman - * Copyright (C) 2005-2006 Martin Willi - * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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 AES_CBC_CRYPTER_H_ -#define AES_CBC_CRYPTER_H_ - -typedef struct aes_cbc_crypter_t aes_cbc_crypter_t; - -#include - -/** - * @brief Class implementing the AES symmetric encryption algorithm. - * - * @b Constructors: - * - aes_cbc_crypter_create() - * - * @ingroup crypters - */ -struct aes_cbc_crypter_t { - - /** - * The crypter_t interface. - */ - crypter_t crypter_interface; -}; - -/** - * @brief Constructor to create aes_cbc_crypter_t objects. - * - * Supported key sizes are: 16, 24 or 32. - * - * @param key_size key size in bytes - * @return - * - aes_cbc_crypter_t object - * - NULL if key size not supported - */ -aes_cbc_crypter_t *aes_cbc_crypter_create(size_t key_size); - - -#endif /* AES_CBC_CRYPTER_H_ */ diff --git a/src/libstrongswan/crypto/crypters/crypter.c b/src/libstrongswan/crypto/crypters/crypter.c index 7f62741a7..69bab02fb 100644 --- a/src/libstrongswan/crypto/crypters/crypter.c +++ b/src/libstrongswan/crypto/crypters/crypter.c @@ -1,10 +1,3 @@ -/** - * @file crypter.c - * - * @brief Generic constructor for crypter_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,15 +12,12 @@ * 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. + * + * $Id$ */ - #include "crypter.h" -#include -#include - - ENUM_BEGIN(encryption_algorithm_names, ENCR_UNDEFINED, ENCR_UNDEFINED, "UNDEFINED"); ENUM_NEXT(encryption_algorithm_names, ENCR_DES_IV64, ENCR_DES_IV32, ENCR_UNDEFINED, @@ -46,23 +36,3 @@ ENUM_NEXT(encryption_algorithm_names, ENCR_NULL, ENCR_AES_CTR, ENCR_DES_IV32, "AES_CTR"); ENUM_END(encryption_algorithm_names, ENCR_AES_CTR); -/* - * Described in header. - */ -crypter_t *crypter_create(encryption_algorithm_t encryption_algorithm, size_t key_size) -{ - switch (encryption_algorithm) - { - case ENCR_AES_CBC: - { - return (crypter_t*)aes_cbc_crypter_create(key_size); - } - case ENCR_DES: - case ENCR_3DES: - { - return (crypter_t*)des_crypter_create(encryption_algorithm); - } - default: - return NULL; - } -} diff --git a/src/libstrongswan/crypto/crypters/crypter.h b/src/libstrongswan/crypto/crypters/crypter.h index 46d94ce93..c8b38f8fa 100644 --- a/src/libstrongswan/crypto/crypters/crypter.h +++ b/src/libstrongswan/crypto/crypters/crypter.h @@ -1,10 +1,3 @@ -/** - * @file crypter.h - * - * @brief Interface crypter_t - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup crypter crypter + * @{ @ingroup crypto */ #ifndef CRYPTER_H_ @@ -30,21 +30,12 @@ typedef struct crypter_t crypter_t; #include /** - * @brief Encryption algorithm, as in IKEv2 RFC 3.3.2. - * - * Currently only the following algorithms are implemented: - * - ENCR_AES_CBC - * - ENCR_DES - * - ENCR_3DES - * - * @ingroup crypters + * Encryption algorithm, as in IKEv2 RFC 3.3.2. */ enum encryption_algorithm_t { ENCR_UNDEFINED = 1024, ENCR_DES_IV64 = 1, - /** Implemented in class des_crypter_t */ ENCR_DES = 2, - /** Implemented in class des_crypter_t */ ENCR_3DES = 3, ENCR_RC5 = 4, ENCR_IDEA = 5, @@ -53,7 +44,6 @@ enum encryption_algorithm_t { ENCR_3IDEA = 8, ENCR_DES_IV32 = 9, ENCR_NULL = 11, - /** Implemented in class aes_cbc_crypter_t */ ENCR_AES_CBC = 12, ENCR_AES_CTR = 13 }; @@ -64,92 +54,58 @@ enum encryption_algorithm_t { extern enum_name_t *encryption_algorithm_names; /** - * @brief Generic interface for symmetric encryption algorithms. - * - * @b Constructors: - * - crypter_create() - * - * @ingroup crypters + * Generic interface for symmetric encryption algorithms. */ struct crypter_t { /** - * @brief Encrypt a chunk of data and allocate space for the encrypted value. + * Encrypt a chunk of data and allocate space for the encrypted value. * - * @param this calling object - * @param data data to encrypt - * @param iv initializing vector - * @param[out] encrypted pointer where the encrypted bytes will be written - * @return - * - SUCCESS - * - INVALID_ARG if data size not a multiple of block size + * @param data data to encrypt + * @param iv initializing vector + * @param encrypted pointer where the encrypted bytes will be written + * @return SUCCESS, or INVALID_ARG if size invalid */ - status_t (*encrypt) (crypter_t *this, chunk_t data, chunk_t iv, chunk_t *encrypted); + status_t (*encrypt) (crypter_t *this, chunk_t data, chunk_t iv, + chunk_t *encrypted); /** - * @brief Decrypt a chunk of data and allocate space for the decrypted value. + * Decrypt a chunk of data and allocate space for the decrypted value. * - * @param this calling object - * @param data data to decrypt - * @param iv initializing vector - * @param[out] encrypted pointer where the decrypted bytes will be written - * @return - * - SUCCESS - * - INVALID_ARG if data size not a multiple of block size + * @param data data to decrypt + * @param iv initializing vector + * @param encrypted pointer where the decrypted bytes will be written + * @return SUCCESS, or INVALID_ARG if invalid */ - status_t (*decrypt) (crypter_t *this, chunk_t data, chunk_t iv, chunk_t *decrypted); + status_t (*decrypt) (crypter_t *this, chunk_t data, chunk_t iv, + chunk_t *decrypted); /** - * @brief Get the block size of this crypter_t object. + * Get the block size of the crypto algorithm. * - * @param this calling object * @return block size in bytes */ size_t (*get_block_size) (crypter_t *this); /** - * @brief Get the key size of this crypter_t object. + * Get the key size of the crypto algorithm. * - * @param this calling object * @return key size in bytes */ size_t (*get_key_size) (crypter_t *this); /** - * @brief Set the key for this crypter_t object. + * Set the key. * - * @param this calling object * @param key key to set - * @return - * - SUCCESS - * - INVALID_ARG if key length invalid + * @return SUCCESS, or INVALID_ARG if key length invalid */ status_t (*set_key) (crypter_t *this, chunk_t key); /** - * @brief Destroys a crypter_t object. - * - * @param this calling object + * Destroys a crypter_t object. */ void (*destroy) (crypter_t *this); }; -/** - * @brief Generic constructor for crypter_t objects. - * - * Currently only the following algorithms are implemented: - * - ENCR_AES_CBC - * - ENCR_DES - * - ENCR_3DES - * - * The key_size is ignored for algorithms with fixed key size. - * - * @param encryption_algorithm Algorithm to use for crypter - * @param key_size size of the key in bytes - * @return - * - crypter_t object - * - NULL if encryption algorithm/key_size is not supported - */ -crypter_t *crypter_create(encryption_algorithm_t encryption_algorithm, size_t key_size); - -#endif /*CRYPTER_H_*/ +#endif /*CRYPTER_H_ @} */ diff --git a/src/libstrongswan/crypto/crypters/des_crypter.c b/src/libstrongswan/crypto/crypters/des_crypter.c deleted file mode 100644 index 655cc03ce..000000000 --- a/src/libstrongswan/crypto/crypters/des_crypter.c +++ /dev/null @@ -1,1536 +0,0 @@ -/** - * @file des_crypter.c - * - * @brief Implementation of des_crypter_t - * - */ - -/* Copyright (C) 2006 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * Derived from Plutos DES library by Eric Young. - * - * Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com) - * All rights reserved. - * - * This package is an SSL implementation written - * by Eric Young (eay@cryptsoft.com). - * The implementation was written so as to conform with Netscapes SSL. - * - * This library is free for commercial and non-commercial use as long as - * the following conditions are aheared to. - * - * Copyright remains Eric Young's, and as such any Copyright notices in - * the code are not to be removed. - * If this package is used in a product, Eric Young should be given attribution - * as the author of the parts of the library used. - * This can be in the form of a textual message at program startup or - * in documentation (online or textual) provided with the package. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * "This product includes cryptographic software written by - * Eric Young (eay@cryptsoft.com)" - * The word 'cryptographic' can be left out if the rouines from the library - * being used are not cryptographic related :-). - * 4. If you include any Windows specific code (or a derivative thereof) from - * the apps directory (application code) you must include an acknowledgement: - * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" - * - * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * The licence and distribution terms for any publically available version or - * derivative of this code cannot be changed. i.e. this code cannot simply be - * copied and put under another distribution licence - * [including the GNU Public Licence.] - */ - -#include "des_crypter.h" - -typedef u_char des_cblock[8]; - -typedef struct des_ks_struct { - des_cblock _; -} des_key_schedule[16]; - - -typedef struct private_des_crypter_t private_des_crypter_t; - -/** - * Private data for des_crypter_t - */ -struct private_des_crypter_t { - - /** - * Public part of this class. - */ - des_crypter_t public; - - /** - * Key size, depends on algoritm... - */ - size_t key_size; - - union { - /** key schedule for single des */ - des_key_schedule ks; - /** key schedule for 3des */ - des_key_schedule ks3[3]; - }; -}; - - -#define DES_ENCRYPT 1 -#define DES_DECRYPT 0 - -#define DES_LONG u_int32_t - -#if defined(WIN32) || defined(WIN16) -#ifndef MSDOS -#define MSDOS -#endif -#endif - -#ifndef DES_DEFAULT_OPTIONS -/* the following is tweaked from a config script, that is why it is a - * protected undef/define */ -#ifndef DES_PTR -#define DES_PTR -#endif - -/* This helps C compiler generate the correct code for multiple functional - * units. It reduces register dependancies at the expense of 2 more - * registers */ -#ifndef DES_RISC1 -#define DES_RISC1 -#endif - -#ifndef DES_RISC2 -#undef DES_RISC2 -#endif - -#if defined(DES_RISC1) && defined(DES_RISC2) -YOU SHOULD NOT HAVE BOTH DES_RISC1 AND DES_RISC2 DEFINED!!!!! -#endif - -/* Unroll the inner loop, this sometimes helps, sometimes hinders. - * Very mucy CPU dependant */ -#ifndef DES_UNROLL -#define DES_UNROLL -#endif - -/* These default values were supplied by - * Peter Gutman - * They are only used if nothing else has been defined */ -#if !defined(DES_PTR) && !defined(DES_RISC1) && !defined(DES_RISC2) && !defined(DES_UNROLL) -/* Special defines which change the way the code is built depending on the - CPU and OS. For SGI machines you can use _MIPS_SZLONG (32 or 64) to find - even newer MIPS CPU's, but at the moment one size fits all for - optimization options. Older Sparc's work better with only UNROLL, but - there's no way to tell at compile time what it is you're running on */ - -#if defined( sun ) /* Newer Sparc's */ -#define DES_PTR -#define DES_RISC1 -#define DES_UNROLL -#elif defined( __ultrix ) /* Older MIPS */ -#define DES_PTR -#define DES_RISC2 -#define DES_UNROLL -#elif defined( __osf1__ ) /* Alpha */ -#define DES_PTR -#define DES_RISC2 -#elif defined ( _AIX ) /* RS6000 */ - /* Unknown */ -#elif defined( __hpux ) /* HP-PA */ - /* Unknown */ -#elif defined( __aux ) /* 68K */ - /* Unknown */ -#elif defined( __dgux ) /* 88K (but P6 in latest boxes) */ -#define DES_UNROLL -#elif defined( __sgi ) /* Newer MIPS */ -#define DES_PTR -#define DES_RISC2 -#define DES_UNROLL -#elif defined( i386 ) /* x86 boxes, should be gcc */ -#define DES_PTR -#define DES_RISC1 -#define DES_UNROLL -#endif /* Systems-specific speed defines */ -#endif - -#endif /* DES_DEFAULT_OPTIONS */ - -#ifdef MSDOS /* Visual C++ 2.1 (Windows NT/95) */ -#include -#include -#include -#include -#ifndef RAND -#define RAND -#endif -#undef NOPROTO -#endif - -#if defined(__STDC__) || defined(VMS) || defined(M_XENIX) || defined(MSDOS) -#ifndef __KERNEL__ -#include -#else -#include -#endif -#endif - -#ifndef RAND -#define RAND -#endif - -#ifdef linux -#undef RAND -#endif - -#ifdef MSDOS -#define getpid() 2 -#define RAND -#undef NOPROTO -#endif - -#if defined(NOCONST) -#define const -#endif - -#ifdef __STDC__ -#undef NOPROTO -#endif - -#ifdef RAND -#define srandom(s) srand(s) -#define random rand -#endif - -#define ITERATIONS 16 -#define HALF_ITERATIONS 8 - -/* used in des_read and des_write */ -#define MAXWRITE (1024*16) -#define BSIZE (MAXWRITE+4) - -#define c2l(c,l) (l =((DES_LONG)(*((c)++))) , \ - l|=((DES_LONG)(*((c)++)))<< 8L, \ - l|=((DES_LONG)(*((c)++)))<<16L, \ - l|=((DES_LONG)(*((c)++)))<<24L) - -/* NOTE - c is not incremented as per c2l */ -#define c2ln(c,l1,l2,n) { \ - c+=n; \ - l1=l2=0; \ - switch (n) { \ - case 8: l2 =((DES_LONG)(*(--(c))))<<24L; \ - case 7: l2|=((DES_LONG)(*(--(c))))<<16L; \ - case 6: l2|=((DES_LONG)(*(--(c))))<< 8L; \ - case 5: l2|=((DES_LONG)(*(--(c)))); \ - case 4: l1 =((DES_LONG)(*(--(c))))<<24L; \ - case 3: l1|=((DES_LONG)(*(--(c))))<<16L; \ - case 2: l1|=((DES_LONG)(*(--(c))))<< 8L; \ - case 1: l1|=((DES_LONG)(*(--(c)))); \ -} \ -} - -#define l2c(l,c) (*((c)++)=(unsigned char)(((l) )&0xff), \ - *((c)++)=(unsigned char)(((l)>> 8L)&0xff), \ - *((c)++)=(unsigned char)(((l)>>16L)&0xff), \ - *((c)++)=(unsigned char)(((l)>>24L)&0xff)) - -/* replacements for htonl and ntohl since I have no idea what to do - * when faced with machines with 8 byte longs. */ -#define HDRSIZE 4 - -#define n2l(c,l) (l =((DES_LONG)(*((c)++)))<<24L, \ - l|=((DES_LONG)(*((c)++)))<<16L, \ - l|=((DES_LONG)(*((c)++)))<< 8L, \ - l|=((DES_LONG)(*((c)++)))) - -#define l2n(l,c) (*((c)++)=(unsigned char)(((l)>>24L)&0xff), \ - *((c)++)=(unsigned char)(((l)>>16L)&0xff), \ - *((c)++)=(unsigned char)(((l)>> 8L)&0xff), \ - *((c)++)=(unsigned char)(((l) )&0xff)) - -/* NOTE - c is not incremented as per l2c */ -#define l2cn(l1,l2,c,n) { \ - c+=n; \ - switch (n) { \ - case 8: *(--(c))=(unsigned char)(((l2)>>24L)&0xff); \ - case 7: *(--(c))=(unsigned char)(((l2)>>16L)&0xff); \ - case 6: *(--(c))=(unsigned char)(((l2)>> 8L)&0xff); \ - case 5: *(--(c))=(unsigned char)(((l2) )&0xff); \ - case 4: *(--(c))=(unsigned char)(((l1)>>24L)&0xff); \ - case 3: *(--(c))=(unsigned char)(((l1)>>16L)&0xff); \ - case 2: *(--(c))=(unsigned char)(((l1)>> 8L)&0xff); \ - case 1: *(--(c))=(unsigned char)(((l1) )&0xff); \ -} \ -} - -#if defined(WIN32) -#define ROTATE(a,n) (_lrotr(a,n)) -#else -#define ROTATE(a,n) (((a)>>(n))+((a)<<(32-(n)))) -#endif - -/* Don't worry about the LOAD_DATA() stuff, that is used by - * fcrypt() to add it's little bit to the front */ - -#ifdef DES_FCRYPT - -#define LOAD_DATA_tmp(R,S,u,t,E0,E1) \ -{ DES_LONG tmp; LOAD_DATA(R,S,u,t,E0,E1,tmp); } - -#define LOAD_DATA(R,S,u,t,E0,E1,tmp) \ - t=R^(R>>16L); \ - u=t&E0; t&=E1; \ - tmp=(u<<16); u^=R^s[S ]; u^=tmp; \ - tmp=(t<<16); t^=R^s[S+1]; t^=tmp -#else -#define LOAD_DATA_tmp(a,b,c,d,e,f) LOAD_DATA(a,b,c,d,e,f,g) -#define LOAD_DATA(R,S,u,t,E0,E1,tmp) \ - u=R^s[S ]; \ - t=R^s[S+1] -#endif - -/* The changes to this macro may help or hinder, depending on the - * compiler and the achitecture. gcc2 always seems to do well :-). - * Inspired by Dana How - * DO NOT use the alternative version on machines with 8 byte longs. - * It does not seem to work on the Alpha, even when DES_LONG is 4 - * bytes, probably an issue of accessing non-word aligned objects :-( */ -#ifdef DES_PTR - -/* It recently occured to me that 0^0^0^0^0^0^0 == 0, so there - * is no reason to not xor all the sub items together. This potentially - * saves a register since things can be xored directly into L */ - -#if defined(DES_RISC1) || defined(DES_RISC2) -#ifdef DES_RISC1 -#define D_ENCRYPT(LL,R,S) { \ - unsigned int u1,u2,u3; \ - LOAD_DATA(R,S,u,t,E0,E1,u1); \ - u2=(int)u>>8L; \ - u1=(int)u&0xfc; \ - u2&=0xfc; \ - t=ROTATE(t,4); \ - u>>=16L; \ - LL^= *(DES_LONG *)((unsigned char *)des_SP +u1); \ - LL^= *(DES_LONG *)((unsigned char *)des_SP+0x200+u2); \ - u3=(int)(u>>8L); \ - u1=(int)u&0xfc; \ - u3&=0xfc; \ - LL^= *(DES_LONG *)((unsigned char *)des_SP+0x400+u1); \ - LL^= *(DES_LONG *)((unsigned char *)des_SP+0x600+u3); \ - u2=(int)t>>8L; \ - u1=(int)t&0xfc; \ - u2&=0xfc; \ - t>>=16L; \ - LL^= *(DES_LONG *)((unsigned char *)des_SP+0x100+u1); \ - LL^= *(DES_LONG *)((unsigned char *)des_SP+0x300+u2); \ - u3=(int)t>>8L; \ - u1=(int)t&0xfc; \ - u3&=0xfc; \ - LL^= *(DES_LONG *)((unsigned char *)des_SP+0x500+u1); \ - LL^= *(DES_LONG *)((unsigned char *)des_SP+0x700+u3); } -#endif -#ifdef DES_RISC2 -#define D_ENCRYPT(LL,R,S) { \ - unsigned int u1,u2,s1,s2; \ - LOAD_DATA(R,S,u,t,E0,E1,u1); \ - u2=(int)u>>8L; \ - u1=(int)u&0xfc; \ - u2&=0xfc; \ - t=ROTATE(t,4); \ - LL^= *(DES_LONG *)((unsigned char *)des_SP +u1); \ - LL^= *(DES_LONG *)((unsigned char *)des_SP+0x200+u2); \ - s1=(int)(u>>16L); \ - s2=(int)(u>>24L); \ - s1&=0xfc; \ - s2&=0xfc; \ - LL^= *(DES_LONG *)((unsigned char *)des_SP+0x400+s1); \ - LL^= *(DES_LONG *)((unsigned char *)des_SP+0x600+s2); \ - u2=(int)t>>8L; \ - u1=(int)t&0xfc; \ - u2&=0xfc; \ - LL^= *(DES_LONG *)((unsigned char *)des_SP+0x100+u1); \ - LL^= *(DES_LONG *)((unsigned char *)des_SP+0x300+u2); \ - s1=(int)(t>>16L); \ - s2=(int)(t>>24L); \ - s1&=0xfc; \ - s2&=0xfc; \ - LL^= *(DES_LONG *)((unsigned char *)des_SP+0x500+s1); \ - LL^= *(DES_LONG *)((unsigned char *)des_SP+0x700+s2); } -#endif -#else -#define D_ENCRYPT(LL,R,S) { \ - LOAD_DATA_tmp(R,S,u,t,E0,E1); \ - t=ROTATE(t,4); \ - LL^= \ - *(DES_LONG *)((unsigned char *)des_SP +((u )&0xfc))^ \ - *(DES_LONG *)((unsigned char *)des_SP+0x200+((u>> 8L)&0xfc))^ \ - *(DES_LONG *)((unsigned char *)des_SP+0x400+((u>>16L)&0xfc))^ \ - *(DES_LONG *)((unsigned char *)des_SP+0x600+((u>>24L)&0xfc))^ \ - *(DES_LONG *)((unsigned char *)des_SP+0x100+((t )&0xfc))^ \ - *(DES_LONG *)((unsigned char *)des_SP+0x300+((t>> 8L)&0xfc))^ \ - *(DES_LONG *)((unsigned char *)des_SP+0x500+((t>>16L)&0xfc))^ \ - *(DES_LONG *)((unsigned char *)des_SP+0x700+((t>>24L)&0xfc)); } -#endif - -#else /* original version */ - -#if defined(DES_RISC1) || defined(DES_RISC2) -#ifdef DES_RISC1 -#define D_ENCRYPT(LL,R,S) {\ - unsigned int u1,u2,u3; \ - LOAD_DATA(R,S,u,t,E0,E1,u1); \ - u>>=2L; \ - t=ROTATE(t,6); \ - u2=(int)u>>8L; \ - u1=(int)u&0x3f; \ - u2&=0x3f; \ - u>>=16L; \ - LL^=des_SPtrans[0][u1]; \ - LL^=des_SPtrans[2][u2]; \ - u3=(int)u>>8L; \ - u1=(int)u&0x3f; \ - u3&=0x3f; \ - LL^=des_SPtrans[4][u1]; \ - LL^=des_SPtrans[6][u3]; \ - u2=(int)t>>8L; \ - u1=(int)t&0x3f; \ - u2&=0x3f; \ - t>>=16L; \ - LL^=des_SPtrans[1][u1]; \ - LL^=des_SPtrans[3][u2]; \ - u3=(int)t>>8L; \ - u1=(int)t&0x3f; \ - u3&=0x3f; \ - LL^=des_SPtrans[5][u1]; \ - LL^=des_SPtrans[7][u3]; } -#endif -#ifdef DES_RISC2 -#define D_ENCRYPT(LL,R,S) {\ - unsigned int u1,u2,s1,s2; \ - LOAD_DATA(R,S,u,t,E0,E1,u1); \ - u>>=2L; \ - t=ROTATE(t,6); \ - u2=(int)u>>8L; \ - u1=(int)u&0x3f; \ - u2&=0x3f; \ - LL^=des_SPtrans[0][u1]; \ - LL^=des_SPtrans[2][u2]; \ - s1=(int)u>>16L; \ - s2=(int)u>>24L; \ - s1&=0x3f; \ - s2&=0x3f; \ - LL^=des_SPtrans[4][s1]; \ - LL^=des_SPtrans[6][s2]; \ - u2=(int)t>>8L; \ - u1=(int)t&0x3f; \ - u2&=0x3f; \ - LL^=des_SPtrans[1][u1]; \ - LL^=des_SPtrans[3][u2]; \ - s1=(int)t>>16; \ - s2=(int)t>>24L; \ - s1&=0x3f; \ - s2&=0x3f; \ - LL^=des_SPtrans[5][s1]; \ - LL^=des_SPtrans[7][s2]; } -#endif - -#else - -#define D_ENCRYPT(LL,R,S) {\ - LOAD_DATA_tmp(R,S,u,t,E0,E1); \ - t=ROTATE(t,4); \ - LL^=\ - des_SPtrans[0][(u>> 2L)&0x3f]^ \ - des_SPtrans[2][(u>>10L)&0x3f]^ \ - des_SPtrans[4][(u>>18L)&0x3f]^ \ - des_SPtrans[6][(u>>26L)&0x3f]^ \ - des_SPtrans[1][(t>> 2L)&0x3f]^ \ - des_SPtrans[3][(t>>10L)&0x3f]^ \ - des_SPtrans[5][(t>>18L)&0x3f]^ \ - des_SPtrans[7][(t>>26L)&0x3f]; } -#endif -#endif - - /* IP and FP - * The problem is more of a geometric problem that random bit fiddling. - 0 1 2 3 4 5 6 7 62 54 46 38 30 22 14 6 - 8 9 10 11 12 13 14 15 60 52 44 36 28 20 12 4 - 16 17 18 19 20 21 22 23 58 50 42 34 26 18 10 2 - 24 25 26 27 28 29 30 31 to 56 48 40 32 24 16 8 0 - - 32 33 34 35 36 37 38 39 63 55 47 39 31 23 15 7 - 40 41 42 43 44 45 46 47 61 53 45 37 29 21 13 5 - 48 49 50 51 52 53 54 55 59 51 43 35 27 19 11 3 - 56 57 58 59 60 61 62 63 57 49 41 33 25 17 9 1 - - The output has been subject to swaps of the form - 0 1 -> 3 1 but the odd and even bits have been put into - 2 3 2 0 - different words. The main trick is to remember that - t=((l>>size)^r)&(mask); - r^=t; - l^=(t<>(n))^(b))&(m)),\ - (b)^=(t),\ - (a)^=((t)<<(n))) - -#define IP(l,r) \ -{ \ - register DES_LONG tt; \ - PERM_OP(r,l,tt, 4,0x0f0f0f0fL); \ - PERM_OP(l,r,tt,16,0x0000ffffL); \ - PERM_OP(r,l,tt, 2,0x33333333L); \ - PERM_OP(l,r,tt, 8,0x00ff00ffL); \ - PERM_OP(r,l,tt, 1,0x55555555L); \ -} - -#define FP(l,r) \ -{ \ - register DES_LONG tt; \ - PERM_OP(l,r,tt, 1,0x55555555L); \ - PERM_OP(r,l,tt, 8,0x00ff00ffL); \ - PERM_OP(l,r,tt, 2,0x33333333L); \ - PERM_OP(r,l,tt,16,0x0000ffffL); \ - PERM_OP(l,r,tt, 4,0x0f0f0f0fL); \ -} - -#ifndef NOPROTO -void fcrypt_body(DES_LONG *out,des_key_schedule ks, - DES_LONG Eswap0, DES_LONG Eswap1); -#else -void fcrypt_body(); -#endif - -static const DES_LONG des_skb[8][64]={ - { /* for C bits (numbered as per FIPS 46) 1 2 3 4 5 6 */ - 0x00000000L,0x00000010L,0x20000000L,0x20000010L, - 0x00010000L,0x00010010L,0x20010000L,0x20010010L, - 0x00000800L,0x00000810L,0x20000800L,0x20000810L, - 0x00010800L,0x00010810L,0x20010800L,0x20010810L, - 0x00000020L,0x00000030L,0x20000020L,0x20000030L, - 0x00010020L,0x00010030L,0x20010020L,0x20010030L, - 0x00000820L,0x00000830L,0x20000820L,0x20000830L, - 0x00010820L,0x00010830L,0x20010820L,0x20010830L, - 0x00080000L,0x00080010L,0x20080000L,0x20080010L, - 0x00090000L,0x00090010L,0x20090000L,0x20090010L, - 0x00080800L,0x00080810L,0x20080800L,0x20080810L, - 0x00090800L,0x00090810L,0x20090800L,0x20090810L, - 0x00080020L,0x00080030L,0x20080020L,0x20080030L, - 0x00090020L,0x00090030L,0x20090020L,0x20090030L, - 0x00080820L,0x00080830L,0x20080820L,0x20080830L, - 0x00090820L,0x00090830L,0x20090820L,0x20090830L, - }, - { /* for C bits (numbered as per FIPS 46) 7 8 10 11 12 13 */ - 0x00000000L,0x02000000L,0x00002000L,0x02002000L, - 0x00200000L,0x02200000L,0x00202000L,0x02202000L, - 0x00000004L,0x02000004L,0x00002004L,0x02002004L, - 0x00200004L,0x02200004L,0x00202004L,0x02202004L, - 0x00000400L,0x02000400L,0x00002400L,0x02002400L, - 0x00200400L,0x02200400L,0x00202400L,0x02202400L, - 0x00000404L,0x02000404L,0x00002404L,0x02002404L, - 0x00200404L,0x02200404L,0x00202404L,0x02202404L, - 0x10000000L,0x12000000L,0x10002000L,0x12002000L, - 0x10200000L,0x12200000L,0x10202000L,0x12202000L, - 0x10000004L,0x12000004L,0x10002004L,0x12002004L, - 0x10200004L,0x12200004L,0x10202004L,0x12202004L, - 0x10000400L,0x12000400L,0x10002400L,0x12002400L, - 0x10200400L,0x12200400L,0x10202400L,0x12202400L, - 0x10000404L,0x12000404L,0x10002404L,0x12002404L, - 0x10200404L,0x12200404L,0x10202404L,0x12202404L, - }, - { /* for C bits (numbered as per FIPS 46) 14 15 16 17 19 20 */ - 0x00000000L,0x00000001L,0x00040000L,0x00040001L, - 0x01000000L,0x01000001L,0x01040000L,0x01040001L, - 0x00000002L,0x00000003L,0x00040002L,0x00040003L, - 0x01000002L,0x01000003L,0x01040002L,0x01040003L, - 0x00000200L,0x00000201L,0x00040200L,0x00040201L, - 0x01000200L,0x01000201L,0x01040200L,0x01040201L, - 0x00000202L,0x00000203L,0x00040202L,0x00040203L, - 0x01000202L,0x01000203L,0x01040202L,0x01040203L, - 0x08000000L,0x08000001L,0x08040000L,0x08040001L, - 0x09000000L,0x09000001L,0x09040000L,0x09040001L, - 0x08000002L,0x08000003L,0x08040002L,0x08040003L, - 0x09000002L,0x09000003L,0x09040002L,0x09040003L, - 0x08000200L,0x08000201L,0x08040200L,0x08040201L, - 0x09000200L,0x09000201L,0x09040200L,0x09040201L, - 0x08000202L,0x08000203L,0x08040202L,0x08040203L, - 0x09000202L,0x09000203L,0x09040202L,0x09040203L, - }, - { /* for C bits (numbered as per FIPS 46) 21 23 24 26 27 28 */ - 0x00000000L,0x00100000L,0x00000100L,0x00100100L, - 0x00000008L,0x00100008L,0x00000108L,0x00100108L, - 0x00001000L,0x00101000L,0x00001100L,0x00101100L, - 0x00001008L,0x00101008L,0x00001108L,0x00101108L, - 0x04000000L,0x04100000L,0x04000100L,0x04100100L, - 0x04000008L,0x04100008L,0x04000108L,0x04100108L, - 0x04001000L,0x04101000L,0x04001100L,0x04101100L, - 0x04001008L,0x04101008L,0x04001108L,0x04101108L, - 0x00020000L,0x00120000L,0x00020100L,0x00120100L, - 0x00020008L,0x00120008L,0x00020108L,0x00120108L, - 0x00021000L,0x00121000L,0x00021100L,0x00121100L, - 0x00021008L,0x00121008L,0x00021108L,0x00121108L, - 0x04020000L,0x04120000L,0x04020100L,0x04120100L, - 0x04020008L,0x04120008L,0x04020108L,0x04120108L, - 0x04021000L,0x04121000L,0x04021100L,0x04121100L, - 0x04021008L,0x04121008L,0x04021108L,0x04121108L, - }, - { /* for D bits (numbered as per FIPS 46) 1 2 3 4 5 6 */ - 0x00000000L,0x10000000L,0x00010000L,0x10010000L, - 0x00000004L,0x10000004L,0x00010004L,0x10010004L, - 0x20000000L,0x30000000L,0x20010000L,0x30010000L, - 0x20000004L,0x30000004L,0x20010004L,0x30010004L, - 0x00100000L,0x10100000L,0x00110000L,0x10110000L, - 0x00100004L,0x10100004L,0x00110004L,0x10110004L, - 0x20100000L,0x30100000L,0x20110000L,0x30110000L, - 0x20100004L,0x30100004L,0x20110004L,0x30110004L, - 0x00001000L,0x10001000L,0x00011000L,0x10011000L, - 0x00001004L,0x10001004L,0x00011004L,0x10011004L, - 0x20001000L,0x30001000L,0x20011000L,0x30011000L, - 0x20001004L,0x30001004L,0x20011004L,0x30011004L, - 0x00101000L,0x10101000L,0x00111000L,0x10111000L, - 0x00101004L,0x10101004L,0x00111004L,0x10111004L, - 0x20101000L,0x30101000L,0x20111000L,0x30111000L, - 0x20101004L,0x30101004L,0x20111004L,0x30111004L, - }, - { /* for D bits (numbered as per FIPS 46) 8 9 11 12 13 14 */ - 0x00000000L,0x08000000L,0x00000008L,0x08000008L, - 0x00000400L,0x08000400L,0x00000408L,0x08000408L, - 0x00020000L,0x08020000L,0x00020008L,0x08020008L, - 0x00020400L,0x08020400L,0x00020408L,0x08020408L, - 0x00000001L,0x08000001L,0x00000009L,0x08000009L, - 0x00000401L,0x08000401L,0x00000409L,0x08000409L, - 0x00020001L,0x08020001L,0x00020009L,0x08020009L, - 0x00020401L,0x08020401L,0x00020409L,0x08020409L, - 0x02000000L,0x0A000000L,0x02000008L,0x0A000008L, - 0x02000400L,0x0A000400L,0x02000408L,0x0A000408L, - 0x02020000L,0x0A020000L,0x02020008L,0x0A020008L, - 0x02020400L,0x0A020400L,0x02020408L,0x0A020408L, - 0x02000001L,0x0A000001L,0x02000009L,0x0A000009L, - 0x02000401L,0x0A000401L,0x02000409L,0x0A000409L, - 0x02020001L,0x0A020001L,0x02020009L,0x0A020009L, - 0x02020401L,0x0A020401L,0x02020409L,0x0A020409L, - }, - { /* for D bits (numbered as per FIPS 46) 16 17 18 19 20 21 */ - 0x00000000L,0x00000100L,0x00080000L,0x00080100L, - 0x01000000L,0x01000100L,0x01080000L,0x01080100L, - 0x00000010L,0x00000110L,0x00080010L,0x00080110L, - 0x01000010L,0x01000110L,0x01080010L,0x01080110L, - 0x00200000L,0x00200100L,0x00280000L,0x00280100L, - 0x01200000L,0x01200100L,0x01280000L,0x01280100L, - 0x00200010L,0x00200110L,0x00280010L,0x00280110L, - 0x01200010L,0x01200110L,0x01280010L,0x01280110L, - 0x00000200L,0x00000300L,0x00080200L,0x00080300L, - 0x01000200L,0x01000300L,0x01080200L,0x01080300L, - 0x00000210L,0x00000310L,0x00080210L,0x00080310L, - 0x01000210L,0x01000310L,0x01080210L,0x01080310L, - 0x00200200L,0x00200300L,0x00280200L,0x00280300L, - 0x01200200L,0x01200300L,0x01280200L,0x01280300L, - 0x00200210L,0x00200310L,0x00280210L,0x00280310L, - 0x01200210L,0x01200310L,0x01280210L,0x01280310L, - }, - { /* for D bits (numbered as per FIPS 46) 22 23 24 25 27 28 */ - 0x00000000L,0x04000000L,0x00040000L,0x04040000L, - 0x00000002L,0x04000002L,0x00040002L,0x04040002L, - 0x00002000L,0x04002000L,0x00042000L,0x04042000L, - 0x00002002L,0x04002002L,0x00042002L,0x04042002L, - 0x00000020L,0x04000020L,0x00040020L,0x04040020L, - 0x00000022L,0x04000022L,0x00040022L,0x04040022L, - 0x00002020L,0x04002020L,0x00042020L,0x04042020L, - 0x00002022L,0x04002022L,0x00042022L,0x04042022L, - 0x00000800L,0x04000800L,0x00040800L,0x04040800L, - 0x00000802L,0x04000802L,0x00040802L,0x04040802L, - 0x00002800L,0x04002800L,0x00042800L,0x04042800L, - 0x00002802L,0x04002802L,0x00042802L,0x04042802L, - 0x00000820L,0x04000820L,0x00040820L,0x04040820L, - 0x00000822L,0x04000822L,0x00040822L,0x04040822L, - 0x00002820L,0x04002820L,0x00042820L,0x04042820L, - 0x00002822L,0x04002822L,0x00042822L,0x04042822L, - } -}; - -const DES_LONG des_SPtrans[8][64]={ - { - /* nibble 0 */ - 0x02080800L, 0x00080000L, 0x02000002L, 0x02080802L, - 0x02000000L, 0x00080802L, 0x00080002L, 0x02000002L, - 0x00080802L, 0x02080800L, 0x02080000L, 0x00000802L, - 0x02000802L, 0x02000000L, 0x00000000L, 0x00080002L, - 0x00080000L, 0x00000002L, 0x02000800L, 0x00080800L, - 0x02080802L, 0x02080000L, 0x00000802L, 0x02000800L, - 0x00000002L, 0x00000800L, 0x00080800L, 0x02080002L, - 0x00000800L, 0x02000802L, 0x02080002L, 0x00000000L, - 0x00000000L, 0x02080802L, 0x02000800L, 0x00080002L, - 0x02080800L, 0x00080000L, 0x00000802L, 0x02000800L, - 0x02080002L, 0x00000800L, 0x00080800L, 0x02000002L, - 0x00080802L, 0x00000002L, 0x02000002L, 0x02080000L, - 0x02080802L, 0x00080800L, 0x02080000L, 0x02000802L, - 0x02000000L, 0x00000802L, 0x00080002L, 0x00000000L, - 0x00080000L, 0x02000000L, 0x02000802L, 0x02080800L, - 0x00000002L, 0x02080002L, 0x00000800L, 0x00080802L, - }, - { /* nibble 1 */ - 0x40108010L, 0x00000000L, 0x00108000L, 0x40100000L, - 0x40000010L, 0x00008010L, 0x40008000L, 0x00108000L, - 0x00008000L, 0x40100010L, 0x00000010L, 0x40008000L, - 0x00100010L, 0x40108000L, 0x40100000L, 0x00000010L, - 0x00100000L, 0x40008010L, 0x40100010L, 0x00008000L, - 0x00108010L, 0x40000000L, 0x00000000L, 0x00100010L, - 0x40008010L, 0x00108010L, 0x40108000L, 0x40000010L, - 0x40000000L, 0x00100000L, 0x00008010L, 0x40108010L, - 0x00100010L, 0x40108000L, 0x40008000L, 0x00108010L, - 0x40108010L, 0x00100010L, 0x40000010L, 0x00000000L, - 0x40000000L, 0x00008010L, 0x00100000L, 0x40100010L, - 0x00008000L, 0x40000000L, 0x00108010L, 0x40008010L, - 0x40108000L, 0x00008000L, 0x00000000L, 0x40000010L, - 0x00000010L, 0x40108010L, 0x00108000L, 0x40100000L, - 0x40100010L, 0x00100000L, 0x00008010L, 0x40008000L, - 0x40008010L, 0x00000010L, 0x40100000L, 0x00108000L, - }, - { /* nibble 2 */ - 0x04000001L, 0x04040100L, 0x00000100L, 0x04000101L, - 0x00040001L, 0x04000000L, 0x04000101L, 0x00040100L, - 0x04000100L, 0x00040000L, 0x04040000L, 0x00000001L, - 0x04040101L, 0x00000101L, 0x00000001L, 0x04040001L, - 0x00000000L, 0x00040001L, 0x04040100L, 0x00000100L, - 0x00000101L, 0x04040101L, 0x00040000L, 0x04000001L, - 0x04040001L, 0x04000100L, 0x00040101L, 0x04040000L, - 0x00040100L, 0x00000000L, 0x04000000L, 0x00040101L, - 0x04040100L, 0x00000100L, 0x00000001L, 0x00040000L, - 0x00000101L, 0x00040001L, 0x04040000L, 0x04000101L, - 0x00000000L, 0x04040100L, 0x00040100L, 0x04040001L, - 0x00040001L, 0x04000000L, 0x04040101L, 0x00000001L, - 0x00040101L, 0x04000001L, 0x04000000L, 0x04040101L, - 0x00040000L, 0x04000100L, 0x04000101L, 0x00040100L, - 0x04000100L, 0x00000000L, 0x04040001L, 0x00000101L, - 0x04000001L, 0x00040101L, 0x00000100L, 0x04040000L, - }, - { /* nibble 3 */ - 0x00401008L, 0x10001000L, 0x00000008L, 0x10401008L, - 0x00000000L, 0x10400000L, 0x10001008L, 0x00400008L, - 0x10401000L, 0x10000008L, 0x10000000L, 0x00001008L, - 0x10000008L, 0x00401008L, 0x00400000L, 0x10000000L, - 0x10400008L, 0x00401000L, 0x00001000L, 0x00000008L, - 0x00401000L, 0x10001008L, 0x10400000L, 0x00001000L, - 0x00001008L, 0x00000000L, 0x00400008L, 0x10401000L, - 0x10001000L, 0x10400008L, 0x10401008L, 0x00400000L, - 0x10400008L, 0x00001008L, 0x00400000L, 0x10000008L, - 0x00401000L, 0x10001000L, 0x00000008L, 0x10400000L, - 0x10001008L, 0x00000000L, 0x00001000L, 0x00400008L, - 0x00000000L, 0x10400008L, 0x10401000L, 0x00001000L, - 0x10000000L, 0x10401008L, 0x00401008L, 0x00400000L, - 0x10401008L, 0x00000008L, 0x10001000L, 0x00401008L, - 0x00400008L, 0x00401000L, 0x10400000L, 0x10001008L, - 0x00001008L, 0x10000000L, 0x10000008L, 0x10401000L, - }, - { /* nibble 4 */ - 0x08000000L, 0x00010000L, 0x00000400L, 0x08010420L, - 0x08010020L, 0x08000400L, 0x00010420L, 0x08010000L, - 0x00010000L, 0x00000020L, 0x08000020L, 0x00010400L, - 0x08000420L, 0x08010020L, 0x08010400L, 0x00000000L, - 0x00010400L, 0x08000000L, 0x00010020L, 0x00000420L, - 0x08000400L, 0x00010420L, 0x00000000L, 0x08000020L, - 0x00000020L, 0x08000420L, 0x08010420L, 0x00010020L, - 0x08010000L, 0x00000400L, 0x00000420L, 0x08010400L, - 0x08010400L, 0x08000420L, 0x00010020L, 0x08010000L, - 0x00010000L, 0x00000020L, 0x08000020L, 0x08000400L, - 0x08000000L, 0x00010400L, 0x08010420L, 0x00000000L, - 0x00010420L, 0x08000000L, 0x00000400L, 0x00010020L, - 0x08000420L, 0x00000400L, 0x00000000L, 0x08010420L, - 0x08010020L, 0x08010400L, 0x00000420L, 0x00010000L, - 0x00010400L, 0x08010020L, 0x08000400L, 0x00000420L, - 0x00000020L, 0x00010420L, 0x08010000L, 0x08000020L, - }, - { /* nibble 5 */ - 0x80000040L, 0x00200040L, 0x00000000L, 0x80202000L, - 0x00200040L, 0x00002000L, 0x80002040L, 0x00200000L, - 0x00002040L, 0x80202040L, 0x00202000L, 0x80000000L, - 0x80002000L, 0x80000040L, 0x80200000L, 0x00202040L, - 0x00200000L, 0x80002040L, 0x80200040L, 0x00000000L, - 0x00002000L, 0x00000040L, 0x80202000L, 0x80200040L, - 0x80202040L, 0x80200000L, 0x80000000L, 0x00002040L, - 0x00000040L, 0x00202000L, 0x00202040L, 0x80002000L, - 0x00002040L, 0x80000000L, 0x80002000L, 0x00202040L, - 0x80202000L, 0x00200040L, 0x00000000L, 0x80002000L, - 0x80000000L, 0x00002000L, 0x80200040L, 0x00200000L, - 0x00200040L, 0x80202040L, 0x00202000L, 0x00000040L, - 0x80202040L, 0x00202000L, 0x00200000L, 0x80002040L, - 0x80000040L, 0x80200000L, 0x00202040L, 0x00000000L, - 0x00002000L, 0x80000040L, 0x80002040L, 0x80202000L, - 0x80200000L, 0x00002040L, 0x00000040L, 0x80200040L, - }, - { /* nibble 6 */ - 0x00004000L, 0x00000200L, 0x01000200L, 0x01000004L, - 0x01004204L, 0x00004004L, 0x00004200L, 0x00000000L, - 0x01000000L, 0x01000204L, 0x00000204L, 0x01004000L, - 0x00000004L, 0x01004200L, 0x01004000L, 0x00000204L, - 0x01000204L, 0x00004000L, 0x00004004L, 0x01004204L, - 0x00000000L, 0x01000200L, 0x01000004L, 0x00004200L, - 0x01004004L, 0x00004204L, 0x01004200L, 0x00000004L, - 0x00004204L, 0x01004004L, 0x00000200L, 0x01000000L, - 0x00004204L, 0x01004000L, 0x01004004L, 0x00000204L, - 0x00004000L, 0x00000200L, 0x01000000L, 0x01004004L, - 0x01000204L, 0x00004204L, 0x00004200L, 0x00000000L, - 0x00000200L, 0x01000004L, 0x00000004L, 0x01000200L, - 0x00000000L, 0x01000204L, 0x01000200L, 0x00004200L, - 0x00000204L, 0x00004000L, 0x01004204L, 0x01000000L, - 0x01004200L, 0x00000004L, 0x00004004L, 0x01004204L, - 0x01000004L, 0x01004200L, 0x01004000L, 0x00004004L, - }, - { /* nibble 7 */ - 0x20800080L, 0x20820000L, 0x00020080L, 0x00000000L, - 0x20020000L, 0x00800080L, 0x20800000L, 0x20820080L, - 0x00000080L, 0x20000000L, 0x00820000L, 0x00020080L, - 0x00820080L, 0x20020080L, 0x20000080L, 0x20800000L, - 0x00020000L, 0x00820080L, 0x00800080L, 0x20020000L, - 0x20820080L, 0x20000080L, 0x00000000L, 0x00820000L, - 0x20000000L, 0x00800000L, 0x20020080L, 0x20800080L, - 0x00800000L, 0x00020000L, 0x20820000L, 0x00000080L, - 0x00800000L, 0x00020000L, 0x20000080L, 0x20820080L, - 0x00020080L, 0x20000000L, 0x00000000L, 0x00820000L, - 0x20800080L, 0x20020080L, 0x20020000L, 0x00800080L, - 0x20820000L, 0x00000080L, 0x00800080L, 0x20020000L, - 0x20820080L, 0x00800000L, 0x20800000L, 0x20000080L, - 0x00820000L, 0x00020080L, 0x20020080L, 0x20800000L, - 0x00000080L, 0x20820000L, 0x00820080L, 0x00000000L, - 0x20000000L, 0x20800080L, 0x00020000L, 0x00820080L, - } -}; - -#define HPERM_OP(a,t,n,m) ((t)=((((a)<<(16-(n)))^(a))&(m)),\ - (a)=(a)^(t)^(t>>(16-(n)))) - -static const unsigned char odd_parity[256]={ - 1, 1, 2, 2, 4, 4, 7, 7, 8, 8, 11, 11, 13, 13, 14, 14, - 16, 16, 19, 19, 21, 21, 22, 22, 25, 25, 26, 26, 28, 28, 31, 31, - 32, 32, 35, 35, 37, 37, 38, 38, 41, 41, 42, 42, 44, 44, 47, 47, - 49, 49, 50, 50, 52, 52, 55, 55, 56, 56, 59, 59, 61, 61, 62, 62, - 64, 64, 67, 67, 69, 69, 70, 70, 73, 73, 74, 74, 76, 76, 79, 79, - 81, 81, 82, 82, 84, 84, 87, 87, 88, 88, 91, 91, 93, 93, 94, 94, - 97, 97, 98, 98,100,100,103,103,104,104,107,107,109,109,110,110, - 112,112,115,115,117,117,118,118,121,121,122,122,124,124,127,127, - 128,128,131,131,133,133,134,134,137,137,138,138,140,140,143,143, - 145,145,146,146,148,148,151,151,152,152,155,155,157,157,158,158, - 161,161,162,162,164,164,167,167,168,168,171,171,173,173,174,174, - 176,176,179,179,181,181,182,182,185,185,186,186,188,188,191,191, - 193,193,194,194,196,196,199,199,200,200,203,203,205,205,206,206, - 208,208,211,211,213,213,214,214,217,217,218,218,220,220,223,223, - 224,224,227,227,229,229,230,230,233,233,234,234,236,236,239,239, - 241,241,242,242,244,244,247,247,248,248,251,251,253,253,254,254 -}; - -/** - * Create key schedule for a single DES 64Bit key - */ -static int des_set_key(des_cblock *key, des_key_schedule *schedule) -{ - static int shifts2[16] = {0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,0}; - register DES_LONG c,d,t,s,t2; - register unsigned char *in; - register DES_LONG *k; - register int i; - des_cblock odd; - - for (i = 0; i < sizeof(des_cblock); i++) - { - odd[i] = odd_parity[(*key)[i]]; - } - - k=(DES_LONG *)schedule; - in=(unsigned char *)&odd; - - c2l(in,c); - c2l(in,d); - - /* do PC1 in 60 simple operations */ -/* PERM_OP(d,c,t,4,0x0f0f0f0fL); - HPERM_OP(c,t,-2, 0xcccc0000L); - HPERM_OP(c,t,-1, 0xaaaa0000L); - HPERM_OP(c,t, 8, 0x00ff0000L); - HPERM_OP(c,t,-1, 0xaaaa0000L); - HPERM_OP(d,t,-8, 0xff000000L); - HPERM_OP(d,t, 8, 0x00ff0000L); - HPERM_OP(d,t, 2, 0x33330000L); - d=((d&0x00aa00aaL)<<7L)|((d&0x55005500L)>>7L)|(d&0xaa55aa55L); - d=(d>>8)|((c&0xf0000000L)>>4); - c&=0x0fffffffL; */ - - /* I now do it in 47 simple operations :-) - * Thanks to John Fletcher (john_fletcher@lccmail.ocf.llnl.gov) - * for the inspiration. :-) */ - PERM_OP (d,c,t,4,0x0f0f0f0fL); - HPERM_OP(c,t,-2,0xcccc0000L); - HPERM_OP(d,t,-2,0xcccc0000L); - PERM_OP (d,c,t,1,0x55555555L); - PERM_OP (c,d,t,8,0x00ff00ffL); - PERM_OP (d,c,t,1,0x55555555L); - d= (((d&0x000000ffL)<<16L)| (d&0x0000ff00L) | - ((d&0x00ff0000L)>>16L)|((c&0xf0000000L)>>4L)); - c&=0x0fffffffL; - - for (i=0; i>2L)|(c<<26L)); d=((d>>2L)|(d<<26L)); } - else - { c=((c>>1L)|(c<<27L)); d=((d>>1L)|(d<<27L)); } - c&=0x0fffffffL; - d&=0x0fffffffL; - /* could be a few less shifts but I am to lazy at this - * point in time to investigate */ - s= des_skb[0][ (c )&0x3f ]| - des_skb[1][((c>> 6)&0x03)|((c>> 7L)&0x3c)]| - des_skb[2][((c>>13)&0x0f)|((c>>14L)&0x30)]| - des_skb[3][((c>>20)&0x01)|((c>>21L)&0x06) | - ((c>>22L)&0x38)]; - t= des_skb[4][ (d )&0x3f ]| - des_skb[5][((d>> 7L)&0x03)|((d>> 8L)&0x3c)]| - des_skb[6][ (d>>15L)&0x3f ]| - des_skb[7][((d>>21L)&0x0f)|((d>>22L)&0x30)]; - - /* table contained 0213 4657 */ - t2=((t<<16L)|(s&0x0000ffffL))&0xffffffffL; - *(k++)=ROTATE(t2,30)&0xffffffffL; - - t2=((s>>16L)|(t&0xffff0000L)); - *(k++)=ROTATE(t2,26)&0xffffffffL; - } - return(0); -} - - -static void des_encrypt(DES_LONG *data, des_key_schedule ks, int enc) -{ - register DES_LONG l,r,t,u; -#ifdef DES_PTR - register unsigned char *des_SP=(unsigned char *)des_SPtrans; -#endif -#ifndef DES_UNROLL - register int i; -#endif - register DES_LONG *s; - - r=data[0]; - l=data[1]; - - IP(r,l); - /* Things have been modified so that the initial rotate is - * done outside the loop. This required the - * des_SPtrans values in sp.h to be rotated 1 bit to the right. - * One perl script later and things have a 5% speed up on a sparc2. - * Thanks to Richard Outerbridge <71755.204@CompuServe.COM> - * for pointing this out. */ - /* clear the top bits on machines with 8byte longs */ - /* shift left by 2 */ - r=ROTATE(r,29)&0xffffffffL; - l=ROTATE(l,29)&0xffffffffL; - - s=(DES_LONG *)ks; - /* I don't know if it is worth the effort of loop unrolling the - * inner loop */ - if (enc) - { -#ifdef DES_UNROLL - D_ENCRYPT(l,r, 0); /* 1 */ - D_ENCRYPT(r,l, 2); /* 2 */ - D_ENCRYPT(l,r, 4); /* 3 */ - D_ENCRYPT(r,l, 6); /* 4 */ - D_ENCRYPT(l,r, 8); /* 5 */ - D_ENCRYPT(r,l,10); /* 6 */ - D_ENCRYPT(l,r,12); /* 7 */ - D_ENCRYPT(r,l,14); /* 8 */ - D_ENCRYPT(l,r,16); /* 9 */ - D_ENCRYPT(r,l,18); /* 10 */ - D_ENCRYPT(l,r,20); /* 11 */ - D_ENCRYPT(r,l,22); /* 12 */ - D_ENCRYPT(l,r,24); /* 13 */ - D_ENCRYPT(r,l,26); /* 14 */ - D_ENCRYPT(l,r,28); /* 15 */ - D_ENCRYPT(r,l,30); /* 16 */ -#else - for (i=0; i<32; i+=8) -{ - D_ENCRYPT(l,r,i+0); /* 1 */ - D_ENCRYPT(r,l,i+2); /* 2 */ - D_ENCRYPT(l,r,i+4); /* 3 */ - D_ENCRYPT(r,l,i+6); /* 4 */ -} -#endif - } - else -{ -#ifdef DES_UNROLL - D_ENCRYPT(l,r,30); /* 16 */ - D_ENCRYPT(r,l,28); /* 15 */ - D_ENCRYPT(l,r,26); /* 14 */ - D_ENCRYPT(r,l,24); /* 13 */ - D_ENCRYPT(l,r,22); /* 12 */ - D_ENCRYPT(r,l,20); /* 11 */ - D_ENCRYPT(l,r,18); /* 10 */ - D_ENCRYPT(r,l,16); /* 9 */ - D_ENCRYPT(l,r,14); /* 8 */ - D_ENCRYPT(r,l,12); /* 7 */ - D_ENCRYPT(l,r,10); /* 6 */ - D_ENCRYPT(r,l, 8); /* 5 */ - D_ENCRYPT(l,r, 6); /* 4 */ - D_ENCRYPT(r,l, 4); /* 3 */ - D_ENCRYPT(l,r, 2); /* 2 */ - D_ENCRYPT(r,l, 0); /* 1 */ -#else - for (i=30; i>0; i-=8) -{ - D_ENCRYPT(l,r,i-0); /* 16 */ - D_ENCRYPT(r,l,i-2); /* 15 */ - D_ENCRYPT(l,r,i-4); /* 14 */ - D_ENCRYPT(r,l,i-6); /* 13 */ -} -#endif -} - - /* rotate and clear the top bits on machines with 8byte longs */ - l=ROTATE(l,3)&0xffffffffL; - r=ROTATE(r,3)&0xffffffffL; - - FP(r,l); - data[0]=l; - data[1]=r; - l=r=t=u=0; -} - -/** - * DES CBC encrypt decrypt routine - */ -static void des_cbc_encrypt(des_cblock *input, des_cblock *output, long length, - des_key_schedule schedule, des_cblock *ivec, int enc) -{ - register DES_LONG tin0,tin1; - register DES_LONG tout0,tout1,xor0,xor1; - register unsigned char *in,*out; - register long l=length; - DES_LONG tin[2]; - unsigned char *iv; - - in=(unsigned char *)input; - out=(unsigned char *)output; - iv=(unsigned char *)ivec; - - if (enc) - { - c2l(iv,tout0); - c2l(iv,tout1); - for (l-=8; l>=0; l-=8) - { - c2l(in,tin0); - c2l(in,tin1); - tin0^=tout0; tin[0]=tin0; - tin1^=tout1; tin[1]=tin1; - des_encrypt((DES_LONG *)tin,schedule,DES_ENCRYPT); - tout0=tin[0]; l2c(tout0,out); - tout1=tin[1]; l2c(tout1,out); - } - if (l != -8) - { - c2ln(in,tin0,tin1,l+8); - tin0^=tout0; tin[0]=tin0; - tin1^=tout1; tin[1]=tin1; - des_encrypt((DES_LONG *)tin,schedule,DES_ENCRYPT); - tout0=tin[0]; l2c(tout0,out); - tout1=tin[1]; l2c(tout1,out); - } - } - else - { - c2l(iv,xor0); - c2l(iv,xor1); - for (l-=8; l>=0; l-=8) - { - c2l(in,tin0); tin[0]=tin0; - c2l(in,tin1); tin[1]=tin1; - des_encrypt((DES_LONG *)tin,schedule,DES_DECRYPT); - tout0=tin[0]^xor0; - tout1=tin[1]^xor1; - l2c(tout0,out); - l2c(tout1,out); - xor0=tin0; - xor1=tin1; - } - if (l != -8) - { - c2l(in,tin0); tin[0]=tin0; - c2l(in,tin1); tin[1]=tin1; - des_encrypt((DES_LONG *)tin,schedule,DES_DECRYPT); - tout0=tin[0]^xor0; - tout1=tin[1]^xor1; - l2cn(tout0,tout1,out,l+8); - /* xor0=tin0; - xor1=tin1; */ - } - } - tin0=tin1=tout0=tout1=xor0=xor1=0; - tin[0]=tin[1]=0; -} - -static void des_encrypt2(DES_LONG *data, des_key_schedule ks, int enc) -{ - register DES_LONG l,r,t,u; -#ifdef DES_PTR - register unsigned char *des_SP=(unsigned char *)des_SPtrans; -#endif -#ifndef DES_UNROLL - register int i; -#endif - register DES_LONG *s; - - r=data[0]; - l=data[1]; - - /* Things have been modified so that the initial rotate is - * done outside the loop. This required the - * des_SPtrans values in sp.h to be rotated 1 bit to the right. - * One perl script later and things have a 5% speed up on a sparc2. - * Thanks to Richard Outerbridge <71755.204@CompuServe.COM> - * for pointing this out. - * clear the top bits on machines with 8byte longs */ - r=ROTATE(r,29)&0xffffffffL; - l=ROTATE(l,29)&0xffffffffL; - - s=(DES_LONG *)ks; - /* I don't know if it is worth the effort of loop unrolling the - * inner loop */ - if (enc) - { -#ifdef DES_UNROLL - D_ENCRYPT(l,r, 0); /* 1 */ - D_ENCRYPT(r,l, 2); /* 2 */ - D_ENCRYPT(l,r, 4); /* 3 */ - D_ENCRYPT(r,l, 6); /* 4 */ - D_ENCRYPT(l,r, 8); /* 5 */ - D_ENCRYPT(r,l,10); /* 6 */ - D_ENCRYPT(l,r,12); /* 7 */ - D_ENCRYPT(r,l,14); /* 8 */ - D_ENCRYPT(l,r,16); /* 9 */ - D_ENCRYPT(r,l,18); /* 10 */ - D_ENCRYPT(l,r,20); /* 11 */ - D_ENCRYPT(r,l,22); /* 12 */ - D_ENCRYPT(l,r,24); /* 13 */ - D_ENCRYPT(r,l,26); /* 14 */ - D_ENCRYPT(l,r,28); /* 15 */ - D_ENCRYPT(r,l,30); /* 16 */ -#else - for (i=0; i<32; i+=8) -{ - D_ENCRYPT(l,r,i+0); /* 1 */ - D_ENCRYPT(r,l,i+2); /* 2 */ - D_ENCRYPT(l,r,i+4); /* 3 */ - D_ENCRYPT(r,l,i+6); /* 4 */ -} -#endif - } - else -{ -#ifdef DES_UNROLL - D_ENCRYPT(l,r,30); /* 16 */ - D_ENCRYPT(r,l,28); /* 15 */ - D_ENCRYPT(l,r,26); /* 14 */ - D_ENCRYPT(r,l,24); /* 13 */ - D_ENCRYPT(l,r,22); /* 12 */ - D_ENCRYPT(r,l,20); /* 11 */ - D_ENCRYPT(l,r,18); /* 10 */ - D_ENCRYPT(r,l,16); /* 9 */ - D_ENCRYPT(l,r,14); /* 8 */ - D_ENCRYPT(r,l,12); /* 7 */ - D_ENCRYPT(l,r,10); /* 6 */ - D_ENCRYPT(r,l, 8); /* 5 */ - D_ENCRYPT(l,r, 6); /* 4 */ - D_ENCRYPT(r,l, 4); /* 3 */ - D_ENCRYPT(l,r, 2); /* 2 */ - D_ENCRYPT(r,l, 0); /* 1 */ -#else - for (i=30; i>0; i-=8) -{ - D_ENCRYPT(l,r,i-0); /* 16 */ - D_ENCRYPT(r,l,i-2); /* 15 */ - D_ENCRYPT(l,r,i-4); /* 14 */ - D_ENCRYPT(r,l,i-6); /* 13 */ -} -#endif -} - /* rotate and clear the top bits on machines with 8byte longs */ - data[0]=ROTATE(l,3)&0xffffffffL; - data[1]=ROTATE(r,3)&0xffffffffL; - l=r=t=u=0; -} - -/** - * Single block 3DES EDE encrypt routine - */ -static void des_encrypt3(DES_LONG *data, des_key_schedule ks1, - des_key_schedule ks2, des_key_schedule ks3) -{ - register DES_LONG l,r; - - l=data[0]; - r=data[1]; - IP(l,r); - data[0]=l; - data[1]=r; - des_encrypt2((DES_LONG *)data,ks1,DES_ENCRYPT); - des_encrypt2((DES_LONG *)data,ks2,DES_DECRYPT); - des_encrypt2((DES_LONG *)data,ks3,DES_ENCRYPT); - l=data[0]; - r=data[1]; - FP(r,l); - data[0]=l; - data[1]=r; -} - -/** - * Single block 3DES EDE decrypt routine - */ -static void des_decrypt3(DES_LONG *data, des_key_schedule ks1, - des_key_schedule ks2, des_key_schedule ks3) -{ - register DES_LONG l,r; - - l=data[0]; - r=data[1]; - IP(l,r); - data[0]=l; - data[1]=r; - des_encrypt2((DES_LONG *)data,ks3,DES_DECRYPT); - des_encrypt2((DES_LONG *)data,ks2,DES_ENCRYPT); - des_encrypt2((DES_LONG *)data,ks1,DES_DECRYPT); - l=data[0]; - r=data[1]; - FP(r,l); - data[0]=l; - data[1]=r; -} - -/** - * 3DES EDE CBC encrypt/decrypt routine - */ -static void des_ede3_cbc_encrypt(des_cblock *input, des_cblock *output, long length, - des_key_schedule ks1, des_key_schedule ks2, - des_key_schedule ks3, des_cblock *ivec, int enc) -{ - register DES_LONG tin0,tin1; - register DES_LONG tout0,tout1,xor0,xor1; - register unsigned char *in,*out; - register long l=length; - DES_LONG tin[2]; - unsigned char *iv; - - in=(unsigned char *)input; - out=(unsigned char *)output; - iv=(unsigned char *)ivec; - - if (enc) - { - c2l(iv,tout0); - c2l(iv,tout1); - for (l-=8; l>=0; l-=8) - { - c2l(in,tin0); - c2l(in,tin1); - tin0^=tout0; - tin1^=tout1; - - tin[0]=tin0; - tin[1]=tin1; - des_encrypt3((DES_LONG *)tin,ks1,ks2,ks3); - tout0=tin[0]; - tout1=tin[1]; - - l2c(tout0,out); - l2c(tout1,out); - } - if (l != -8) - { - c2ln(in,tin0,tin1,l+8); - tin0^=tout0; - tin1^=tout1; - - tin[0]=tin0; - tin[1]=tin1; - des_encrypt3((DES_LONG *)tin,ks1,ks2,ks3); - tout0=tin[0]; - tout1=tin[1]; - - l2c(tout0,out); - l2c(tout1,out); - } - iv=(unsigned char *)ivec; - l2c(tout0,iv); - l2c(tout1,iv); - } - else - { - register DES_LONG t0,t1; - - c2l(iv,xor0); - c2l(iv,xor1); - for (l-=8; l>=0; l-=8) - { - c2l(in,tin0); - c2l(in,tin1); - - t0=tin0; - t1=tin1; - - tin[0]=tin0; - tin[1]=tin1; - des_decrypt3((DES_LONG *)tin,ks1,ks2,ks3); - tout0=tin[0]; - tout1=tin[1]; - - tout0^=xor0; - tout1^=xor1; - l2c(tout0,out); - l2c(tout1,out); - xor0=t0; - xor1=t1; - } - if (l != -8) - { - c2l(in,tin0); - c2l(in,tin1); - - t0=tin0; - t1=tin1; - - tin[0]=tin0; - tin[1]=tin1; - des_decrypt3((DES_LONG *)tin,ks1,ks2,ks3); - tout0=tin[0]; - tout1=tin[1]; - - tout0^=xor0; - tout1^=xor1; - l2cn(tout0,tout1,out,l+8); - xor0=t0; - xor1=t1; - } - - iv=(unsigned char *)ivec; - l2c(xor0,iv); - l2c(xor1,iv); - } - tin0=tin1=tout0=tout1=xor0=xor1=0; - tin[0]=tin[1]=0; -} - -/** - * Implementation of crypter_t.decrypt for DES. - */ -static status_t decrypt(private_des_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *decrypted) -{ - des_cblock ivb; - - if (data.len % sizeof(des_cblock) != 0 || - iv.len != sizeof(des_cblock)) - { - return INVALID_ARG; - } - - *decrypted = chunk_alloc(data.len); - memcpy(&ivb, iv.ptr, sizeof(des_cblock)); - des_cbc_encrypt((des_cblock*)(data.ptr), (des_cblock*)(decrypted->ptr), - data.len, this->ks, &ivb, DES_DECRYPT); - return SUCCESS; -} - - -/** - * Implementation of crypter_t.decrypt for DES. - */ -static status_t encrypt(private_des_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *encrypted) -{ - des_cblock ivb; - - if (data.len % sizeof(des_cblock) != 0 || - iv.len != sizeof(des_cblock)) - { - return INVALID_ARG; - } - - *encrypted = chunk_alloc(data.len); - memcpy(&ivb, iv.ptr, sizeof(des_cblock)); - des_cbc_encrypt((des_cblock*)(data.ptr), (des_cblock*)(encrypted->ptr), - data.len, this->ks, &ivb, DES_ENCRYPT); - return SUCCESS; -} - -/** - * Implementation of crypter_t.decrypt for 3DES. - */ -static status_t decrypt3(private_des_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *decrypted) -{ - des_cblock ivb; - - if (data.len % sizeof(des_cblock) != 0 || - iv.len != sizeof(des_cblock)) - { - return INVALID_ARG; - } - - *decrypted = chunk_alloc(data.len); - memcpy(&ivb, iv.ptr, sizeof(des_cblock)); - des_ede3_cbc_encrypt((des_cblock*)(data.ptr), (des_cblock*)(decrypted->ptr), - data.len, this->ks3[0], this->ks3[1], this->ks3[2], - &ivb, DES_DECRYPT); - return SUCCESS; -} - -/** - * Implementation of crypter_t.decrypt for 3DES. - */ -static status_t encrypt3(private_des_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *encrypted) -{ - des_cblock ivb; - - if (data.len % sizeof(des_cblock) != 0 || - iv.len != sizeof(des_cblock)) - { - return INVALID_ARG; - } - - *encrypted = chunk_alloc(data.len); - memcpy(&ivb, iv.ptr, sizeof(des_cblock)); - des_ede3_cbc_encrypt((des_cblock*)(data.ptr), (des_cblock*)(encrypted->ptr), - data.len, this->ks3[0], this->ks3[1], this->ks3[2], - &ivb, DES_ENCRYPT); - return SUCCESS; -} - -/** - * Implementation of crypter_t.get_block_size. - */ -static size_t get_block_size (private_des_crypter_t *this) -{ - return sizeof(des_cblock); -} - -/** - * Implementation of crypter_t.get_key_size. - */ -static size_t get_key_size (private_des_crypter_t *this) -{ - return this->key_size; -} - -/** - * Implementation of crypter_t.set_key for DES. - */ -static status_t set_key(private_des_crypter_t *this, chunk_t key) -{ - if (key.len != sizeof(des_cblock)) - { - return INVALID_ARG; - } - - des_set_key((des_cblock*)(key.ptr), &this->ks); - - return SUCCESS; -} - -/** - * Implementation of crypter_t.set_key for 3DES. - */ -static status_t set_key3(private_des_crypter_t *this, chunk_t key) -{ - if (key.len != 3 * sizeof(des_cblock)) - { - return INVALID_ARG; - } - - des_set_key((des_cblock*)(key.ptr) + 0, &this->ks3[0]); - des_set_key((des_cblock*)(key.ptr) + 1, &this->ks3[1]); - des_set_key((des_cblock*)(key.ptr) + 2, &this->ks3[2]); - - return SUCCESS; -} - -/** - * Implementation of crypter_t.destroy and des_crypter_t.destroy. - */ -static void destroy(private_des_crypter_t *this) -{ - free(this); -} - -/* - * Described in header - */ -des_crypter_t *des_crypter_create(encryption_algorithm_t algo) -{ - private_des_crypter_t *this = malloc_thing(private_des_crypter_t); - - /* functions of crypter_t interface */ - this->public.crypter_interface.get_block_size = (size_t (*) (crypter_t *)) get_block_size; - this->public.crypter_interface.get_key_size = (size_t (*) (crypter_t *)) get_key_size; - this->public.crypter_interface.destroy = (void (*) (crypter_t *)) destroy; - - /* use functions depending on algorithm */ - switch (algo) - { - case ENCR_DES: - this->key_size = sizeof(des_cblock); - this->public.crypter_interface.set_key = (status_t (*) (crypter_t *,chunk_t)) set_key; - this->public.crypter_interface.encrypt = (status_t (*) (crypter_t *, chunk_t,chunk_t, chunk_t *)) encrypt; - this->public.crypter_interface.decrypt = (status_t (*) (crypter_t *, chunk_t , chunk_t, chunk_t *)) decrypt; - break; - case ENCR_3DES: - this->key_size = 3 * sizeof(des_cblock); - this->public.crypter_interface.set_key = (status_t (*) (crypter_t *,chunk_t)) set_key3; - this->public.crypter_interface.encrypt = (status_t (*) (crypter_t *, chunk_t,chunk_t, chunk_t *)) encrypt3; - this->public.crypter_interface.decrypt = (status_t (*) (crypter_t *, chunk_t , chunk_t, chunk_t *)) decrypt3; - break; - default: - free(this); - return NULL; - } - return &(this->public); -} diff --git a/src/libstrongswan/crypto/crypters/des_crypter.h b/src/libstrongswan/crypto/crypters/des_crypter.h deleted file mode 100644 index 0c87b0a9c..000000000 --- a/src/libstrongswan/crypto/crypters/des_crypter.h +++ /dev/null @@ -1,58 +0,0 @@ -/** - * @file des_crypter.h - * - * @brief Interface of des_crypter_t - * - */ - -/* - * Copyright (C) 2006 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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 DES_CRYPTER_H_ -#define DES_CRYPTER_H_ - -typedef struct des_crypter_t des_crypter_t; - -#include - - -/** - * @brief Class implementing the DES and 3DES encryption algorithms. - * - * @b Constructors: - * - des_crypter_create() - * - * @ingroup crypters - */ -struct des_crypter_t { - - /** - * The crypter_t interface. - */ - crypter_t crypter_interface; -}; - -/** - * @brief Constructor to create des_crypter_t objects. - * - * @param algo ENCR_DES for single DES, ENCR_3DES for triple DES - * @return - * - des_crypter_t object - * - NULL if algo not supported - */ -des_crypter_t *des_crypter_create(encryption_algorithm_t algo); - - -#endif /* DES_CRYPTER_H_ */ diff --git a/src/libstrongswan/crypto/crypto_factory.c b/src/libstrongswan/crypto/crypto_factory.c new file mode 100644 index 000000000..1bca84f2a --- /dev/null +++ b/src/libstrongswan/crypto/crypto_factory.c @@ -0,0 +1,483 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "crypto_factory.h" + +#include +#include + +typedef struct crypter_entry_t crypter_entry_t; +struct crypter_entry_t { + /** encryption algorithm */ + encryption_algorithm_t algo; + /** associated constructor */ + crypter_constructor_t create; +}; + +typedef struct signer_entry_t signer_entry_t; +struct signer_entry_t { + /** integrity algorithm */ + integrity_algorithm_t algo; + /** associated constructor */ + signer_constructor_t create; +}; + +typedef struct hasher_entry_t hasher_entry_t; +struct hasher_entry_t { + /** hash algorithm */ + hash_algorithm_t algo; + /** associated constructor */ + hasher_constructor_t create; +}; + +typedef struct prf_entry_t prf_entry_t; +struct prf_entry_t { + /** hash algorithm */ + pseudo_random_function_t algo; + /** associated constructor */ + prf_constructor_t create; +}; + +typedef struct dh_entry_t dh_entry_t; +struct dh_entry_t { + /** hash algorithm */ + diffie_hellman_group_t group; + /** associated constructor */ + dh_constructor_t create; +}; + +typedef struct private_crypto_factory_t private_crypto_factory_t; + +/** + * private data of crypto_factory + */ +struct private_crypto_factory_t { + + /** + * public functions + */ + crypto_factory_t public; + + /** + * registered crypters, as crypter_entry_t + */ + linked_list_t *crypters; + + /** + * registered signers, as signer_entry_t + */ + linked_list_t *signers; + + /** + * registered hashers, as hasher_entry_t + */ + linked_list_t *hashers; + + /** + * registered perfs, as prf_entry_t + */ + linked_list_t *prfs; + + /** + * registered diffie hellman, as dh_entry_t + */ + linked_list_t *dhs; + + /** + * mutex to lock access to modules + */ + mutex_t *mutex; +}; + +/** + * Implementation of crypto_factory_t.create_crypter. + */ +static crypter_t* create_crypter(private_crypto_factory_t *this, + encryption_algorithm_t algo, size_t key_size) +{ + enumerator_t *enumerator; + crypter_entry_t *entry; + crypter_t *crypter = NULL; + + this->mutex->lock(this->mutex); + enumerator = this->crypters->create_enumerator(this->crypters); + while (enumerator->enumerate(enumerator, &entry)) + { + if (entry->algo == algo) + { + crypter = entry->create(algo, key_size); + if (crypter) + { + break; + } + } + } + enumerator->destroy(enumerator); + this->mutex->unlock(this->mutex); + return crypter; +} + +/** + * Implementation of crypto_factory_t.create_signer. + */ +static signer_t* create_signer(private_crypto_factory_t *this, + integrity_algorithm_t algo) +{ + enumerator_t *enumerator; + signer_entry_t *entry; + signer_t *signer = NULL; + + this->mutex->lock(this->mutex); + enumerator = this->signers->create_enumerator(this->signers); + while (enumerator->enumerate(enumerator, &entry)) + { + if (entry->algo == algo) + { + signer = entry->create(algo); + if (signer) + { + break; + } + } + } + enumerator->destroy(enumerator); + this->mutex->unlock(this->mutex); + + return signer; +} + +/** + * Implementation of crypto_factory_t.create_hasher. + */ +static hasher_t* create_hasher(private_crypto_factory_t *this, + hash_algorithm_t algo) +{ + enumerator_t *enumerator; + hasher_entry_t *entry; + hasher_t *hasher = NULL; + + this->mutex->lock(this->mutex); + enumerator = this->hashers->create_enumerator(this->hashers); + while (enumerator->enumerate(enumerator, &entry)) + { + if (algo == HASH_PREFERRED || entry->algo == algo) + { + hasher = entry->create(entry->algo); + if (hasher) + { + break; + } + } + } + enumerator->destroy(enumerator); + this->mutex->unlock(this->mutex); + return hasher; +} + +/** + * Implementation of crypto_factory_t.create_prf. + */ +static prf_t* create_prf(private_crypto_factory_t *this, + pseudo_random_function_t algo) +{ + enumerator_t *enumerator; + prf_entry_t *entry; + prf_t *prf = NULL; + + this->mutex->lock(this->mutex); + enumerator = this->prfs->create_enumerator(this->prfs); + while (enumerator->enumerate(enumerator, &entry)) + { + if (entry->algo == algo) + { + prf = entry->create(algo); + if (prf) + { + break; + } + } + } + enumerator->destroy(enumerator); + this->mutex->unlock(this->mutex); + return prf; +} + +/** + * Implementation of crypto_factory_t.create_dh. + */ +static diffie_hellman_t* create_dh(private_crypto_factory_t *this, + diffie_hellman_group_t group) +{ + enumerator_t *enumerator; + dh_entry_t *entry; + diffie_hellman_t *diffie_hellman = NULL; + + this->mutex->lock(this->mutex); + enumerator = this->dhs->create_enumerator(this->dhs); + while (enumerator->enumerate(enumerator, &entry)) + { + if (entry->group == group) + { + diffie_hellman = entry->create(group); + if (diffie_hellman) + { + break; + } + } + } + enumerator->destroy(enumerator); + this->mutex->unlock(this->mutex); + return diffie_hellman; +} + +/** + * Implementation of crypto_factory_t.add_crypter. + */ +static void add_crypter(private_crypto_factory_t *this, + encryption_algorithm_t algo, + crypter_constructor_t create) +{ + crypter_entry_t *entry = malloc_thing(crypter_entry_t); + + entry->algo = algo; + entry->create = create; + this->mutex->lock(this->mutex); + this->crypters->insert_last(this->crypters, entry); + this->mutex->unlock(this->mutex); +} + +/** + * Implementation of crypto_factory_t.remove_crypter. + */ +static void remove_crypter(private_crypto_factory_t *this, + crypter_constructor_t create) +{ + crypter_entry_t *entry; + enumerator_t *enumerator; + + this->mutex->lock(this->mutex); + enumerator = this->crypters->create_enumerator(this->crypters); + while (enumerator->enumerate(enumerator, &entry)) + { + if (entry->create == create) + { + this->crypters->remove_at(this->crypters, enumerator); + free(entry); + } + } + enumerator->destroy(enumerator); + this->mutex->unlock(this->mutex); +} + +/** + * Implementation of crypto_factory_t.add_signer. + */ +static void add_signer(private_crypto_factory_t *this, + integrity_algorithm_t algo, signer_constructor_t create) +{ + signer_entry_t *entry = malloc_thing(signer_entry_t); + + entry->algo = algo; + entry->create = create; + this->mutex->lock(this->mutex); + this->signers->insert_last(this->signers, entry); + this->mutex->unlock(this->mutex); +} + +/** + * Implementation of crypto_factory_t.remove_signer. + */ +static void remove_signer(private_crypto_factory_t *this, + signer_constructor_t create) +{ + signer_entry_t *entry; + enumerator_t *enumerator; + + this->mutex->lock(this->mutex); + enumerator = this->signers->create_enumerator(this->signers); + while (enumerator->enumerate(enumerator, &entry)) + { + if (entry->create == create) + { + this->signers->remove_at(this->signers, enumerator); + free(entry); + } + } + enumerator->destroy(enumerator); + this->mutex->unlock(this->mutex); +} + +/** + * Implementation of crypto_factory_t.add_hasher. + */ +static void add_hasher(private_crypto_factory_t *this, hash_algorithm_t algo, + hasher_constructor_t create) +{ + hasher_entry_t *entry = malloc_thing(hasher_entry_t); + + entry->algo = algo; + entry->create = create; + this->mutex->lock(this->mutex); + this->hashers->insert_last(this->hashers, entry); + this->mutex->unlock(this->mutex); +} + +/** + * Implementation of crypto_factory_t.remove_hasher. + */ +static void remove_hasher(private_crypto_factory_t *this, + hasher_constructor_t create) +{ + hasher_entry_t *entry; + enumerator_t *enumerator; + + this->mutex->lock(this->mutex); + enumerator = this->hashers->create_enumerator(this->hashers); + while (enumerator->enumerate(enumerator, &entry)) + { + if (entry->create == create) + { + this->hashers->remove_at(this->hashers, enumerator); + free(entry); + } + } + enumerator->destroy(enumerator); + this->mutex->unlock(this->mutex); +} + +/** + * Implementation of crypto_factory_t.add_prf. + */ +static void add_prf(private_crypto_factory_t *this, + pseudo_random_function_t algo, prf_constructor_t create) +{ + prf_entry_t *entry = malloc_thing(prf_entry_t); + + entry->algo = algo; + entry->create = create; + this->mutex->lock(this->mutex); + this->prfs->insert_last(this->prfs, entry); + this->mutex->unlock(this->mutex); +} + +/** + * Implementation of crypto_factory_t.remove_prf. + */ +static void remove_prf(private_crypto_factory_t *this, prf_constructor_t create) +{ + prf_entry_t *entry; + enumerator_t *enumerator; + + this->mutex->lock(this->mutex); + enumerator = this->prfs->create_enumerator(this->prfs); + while (enumerator->enumerate(enumerator, &entry)) + { + if (entry->create == create) + { + this->prfs->remove_at(this->prfs, enumerator); + free(entry); + } + } + enumerator->destroy(enumerator); + this->mutex->unlock(this->mutex); +} + +/** + * Implementation of crypto_factory_t.add_dh. + */ +static void add_dh(private_crypto_factory_t *this, diffie_hellman_group_t group, + dh_constructor_t create) +{ + dh_entry_t *entry = malloc_thing(dh_entry_t); + + entry->group = group; + entry->create = create; + this->mutex->lock(this->mutex); + this->dhs->insert_last(this->dhs, entry); + this->mutex->unlock(this->mutex); +} + +/** + * Implementation of crypto_factory_t.remove_dh. + */ +static void remove_dh(private_crypto_factory_t *this, dh_constructor_t create) +{ + dh_entry_t *entry; + enumerator_t *enumerator; + + this->mutex->lock(this->mutex); + enumerator = this->dhs->create_enumerator(this->dhs); + while (enumerator->enumerate(enumerator, &entry)) + { + if (entry->create == create) + { + this->dhs->remove_at(this->dhs, enumerator); + free(entry); + } + } + enumerator->destroy(enumerator); + this->mutex->unlock(this->mutex); +} + +/** + * Implementation of crypto_factory_t.destroy + */ +static void destroy(private_crypto_factory_t *this) +{ + this->crypters->destroy_function(this->crypters, free); + this->signers->destroy_function(this->signers, free); + this->hashers->destroy_function(this->hashers, free); + this->prfs->destroy_function(this->prfs, free); + this->dhs->destroy_function(this->dhs, free); + this->mutex->destroy(this->mutex); + free(this); +} + +/* + * see header file + */ +crypto_factory_t *crypto_factory_create() +{ + private_crypto_factory_t *this = malloc_thing(private_crypto_factory_t); + + this->public.create_crypter = (crypter_t*(*)(crypto_factory_t*, encryption_algorithm_t, size_t))create_crypter; + this->public.create_signer = (signer_t*(*)(crypto_factory_t*, integrity_algorithm_t))create_signer; + this->public.create_hasher = (hasher_t*(*)(crypto_factory_t*, hash_algorithm_t))create_hasher; + this->public.create_prf = (prf_t*(*)(crypto_factory_t*, pseudo_random_function_t))create_prf; + this->public.create_dh = (diffie_hellman_t*(*)(crypto_factory_t*, diffie_hellman_group_t group))create_dh; + this->public.add_crypter = (void(*)(crypto_factory_t*, encryption_algorithm_t algo, crypter_constructor_t create))add_crypter; + this->public.remove_crypter = (void(*)(crypto_factory_t*, crypter_constructor_t create))remove_crypter; + this->public.add_signer = (void(*)(crypto_factory_t*, integrity_algorithm_t algo, signer_constructor_t create))add_signer; + this->public.remove_signer = (void(*)(crypto_factory_t*, signer_constructor_t create))remove_signer; + this->public.add_hasher = (void(*)(crypto_factory_t*, hash_algorithm_t algo, hasher_constructor_t create))add_hasher; + this->public.remove_hasher = (void(*)(crypto_factory_t*, hasher_constructor_t create))remove_hasher; + this->public.add_prf = (void(*)(crypto_factory_t*, pseudo_random_function_t algo, prf_constructor_t create))add_prf; + this->public.remove_prf = (void(*)(crypto_factory_t*, prf_constructor_t create))remove_prf; + this->public.add_dh = (void(*)(crypto_factory_t*, diffie_hellman_group_t algo, dh_constructor_t create))add_dh; + this->public.remove_dh = (void(*)(crypto_factory_t*, dh_constructor_t create))remove_dh; + this->public.destroy = (void(*)(crypto_factory_t*))destroy; + + this->crypters = linked_list_create(); + this->signers = linked_list_create(); + this->hashers = linked_list_create(); + this->prfs = linked_list_create(); + this->dhs = linked_list_create(); + this->mutex = mutex_create(MUTEX_RECURSIVE); + + return &this->public; +} + diff --git a/src/libstrongswan/crypto/crypto_factory.h b/src/libstrongswan/crypto/crypto_factory.h new file mode 100644 index 000000000..c8c2bccc9 --- /dev/null +++ b/src/libstrongswan/crypto/crypto_factory.h @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 crypto_factory crypto_factory + * @{ @ingroup crypto + */ + +#ifndef CRYPTO_FACTORY_H_ +#define CRYPTO_FACTORY_H_ + +typedef struct crypto_factory_t crypto_factory_t; + +#include +#include +#include +#include +#include +#include + +/** + * Constructor function for crypters + */ +typedef crypter_t* (*crypter_constructor_t)(encryption_algorithm_t algo, + size_t key_size); +/** + * Constructor function for signers + */ +typedef signer_t* (*signer_constructor_t)(integrity_algorithm_t algo); + +/** + * Constructor function for hashers + */ +typedef hasher_t* (*hasher_constructor_t)(hash_algorithm_t algo); + +/** + * Constructor function for pseudo random fucntions + */ +typedef prf_t* (*prf_constructor_t)(pseudo_random_function_t algo); + +/** + * Constructor function for diffie hellman + */ +typedef diffie_hellman_t* (*dh_constructor_t)(diffie_hellman_group_t group); + +/** + * Handles crypto modules and creates instances. + */ +struct crypto_factory_t { + + /** + * Create a crypter instance. + * + * @param algo encryption algorithm + * @param key_size length of the key in bytes + * @return crypter_t instance, NULL if not supported + */ + crypter_t* (*create_crypter)(crypto_factory_t *this, + encryption_algorithm_t algo, size_t key_size); + + /** + * Create a symmetric signer instance. + * + * @param algo MAC algorithm to use + * @return signer_t instance, NULL if not supported + */ + signer_t* (*create_signer)(crypto_factory_t *this, + integrity_algorithm_t algo); + + /** + * Create a hasher instance. + * + * @param algo hash algorithm + * @return hasher_t instance, NULL if not supported + */ + hasher_t* (*create_hasher)(crypto_factory_t *this, hash_algorithm_t algo); + + /** + * Create a pseudo random function instance. + * + * @param algo PRF algorithm to use + * @return prf_t instance, NULL if not supported + */ + prf_t* (*create_prf)(crypto_factory_t *this, pseudo_random_function_t algo); + + /** + * Create a diffie hellman instance. + * + * @param group diffie hellman group + * @return diffie_hellman_t instance, NULL if not supported + */ + diffie_hellman_t* (*create_dh)(crypto_factory_t *this, + diffie_hellman_group_t group); + + /** + * Register a crypter constructor. + * + * @param algo algorithm to constructor + * @param create constructor function for that algorithm + * @return + */ + void (*add_crypter)(crypto_factory_t *this, encryption_algorithm_t algo, + crypter_constructor_t create); + + /** + * Unregister a crypter constructor. + * + * @param create constructor function to unregister + */ + void (*remove_crypter)(crypto_factory_t *this, crypter_constructor_t create); + + /** + * Register a signer constructor. + * + * @param algo algorithm to constructor + * @param create constructor function for that algorithm + * @return + */ + void (*add_signer)(crypto_factory_t *this, integrity_algorithm_t algo, + signer_constructor_t create); + + /** + * Unregister a signer constructor. + * + * @param create constructor function to unregister + */ + void (*remove_signer)(crypto_factory_t *this, signer_constructor_t create); + + /** + * Register a hasher constructor. + * + * The first added hasher is the preferred hasher returned on + * create_hasher(HASH_PREFERRED). + * + * @param algo algorithm to constructor + * @param create constructor function for that algorithm + * @return + */ + void (*add_hasher)(crypto_factory_t *this, hash_algorithm_t algo, + hasher_constructor_t create); + + /** + * Unregister a hasher constructor. + * + * @param create constructor function to unregister + */ + void (*remove_hasher)(crypto_factory_t *this, hasher_constructor_t create); + + /** + * Register a prf constructor. + * + * @param algo algorithm to constructor + * @param create constructor function for that algorithm + * @return + */ + void (*add_prf)(crypto_factory_t *this, pseudo_random_function_t algo, + prf_constructor_t create); + + /** + * Unregister a prf constructor. + * + * @param create constructor function to unregister + */ + void (*remove_prf)(crypto_factory_t *this, prf_constructor_t create); + + /** + * Register a diffie hellman constructor. + * + * @param group dh group to constructor + * @param create constructor function for that algorithm + * @return + */ + void (*add_dh)(crypto_factory_t *this, diffie_hellman_group_t group, + dh_constructor_t create); + + /** + * Unregister a diffie hellman constructor. + * + * @param create constructor function to unregister + */ + void (*remove_dh)(crypto_factory_t *this, dh_constructor_t create); + + /** + * Destroy a crypto_factory instance. + */ + void (*destroy)(crypto_factory_t *this); +}; + +/** + * Create a crypto_factory instance. + */ +crypto_factory_t *crypto_factory_create(); + +#endif /* CRYPTO_FACTORY_H_ @}*/ diff --git a/src/libstrongswan/crypto/diffie_hellman.c b/src/libstrongswan/crypto/diffie_hellman.c index 605892e87..922708720 100644 --- a/src/libstrongswan/crypto/diffie_hellman.c +++ b/src/libstrongswan/crypto/diffie_hellman.c @@ -1,14 +1,5 @@ -/** - * @file diffie_hellman.c - * - * @brief Implementation of diffie_hellman_t. - * - */ - /* - * Copyright (C) 1998-2002 D. Hugh Redelmeier. - * Copyright (C) 1999, 2000, 2001 Henry Spencer. - * Copyright (C) 2005-2007 Martin Willi + * Copyright (C) 2005-2008 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil * @@ -21,15 +12,12 @@ * 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. + * + * $Id$ */ -#include - #include "diffie_hellman.h" -#include -#include - ENUM_BEGIN(diffie_hellman_group_names, MODP_NONE, MODP_1024_BIT, "MODP_NONE", "MODP_768_BIT", @@ -44,546 +32,3 @@ ENUM_NEXT(diffie_hellman_group_names, MODP_2048_BIT, MODP_8192_BIT, MODP_1536_BI "MODP_8192_BIT"); ENUM_END(diffie_hellman_group_names, MODP_8192_BIT); - -/** - * Modulus of Group 1 (MODP_768_BIT). - */ -static u_int8_t group1_modulus[] = { - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x34, - 0xC4,0xC6,0x62,0x8B,0x80 ,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74, - 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 -}; - -/** - * Modulus of Group 2 (MODP_1024_BIT). - */ -static u_int8_t group2_modulus[] = { - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x34, - 0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74, - 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,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 -}; - -/** - * Modulus of Group 5 (MODP_1536_BIT). - */ -static u_int8_t group5_modulus[] = { - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x34, - 0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74, - 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,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,0xE4,0x5B,0x3D,0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05, - 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 -}; -/** - * Modulus of Group 14 (MODP_2048_BIT). - */ -static u_int8_t group14_modulus[] = { - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x34, - 0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74, - 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,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,0xE4,0x5B,0x3D,0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05, - 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,0x18,0x21,0x7C,0x32,0x90,0x5E,0x46,0x2E,0x36,0xCE,0x3B, - 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 -}; - -/** - * Modulus of Group 15 (MODP_3072_BIT). - */ -static u_int8_t group15_modulus[] = { - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x34, - 0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74, - 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,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,0xE4,0x5B,0x3D,0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05, - 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,0x18,0x21,0x7C,0x32,0x90,0x5E,0x46,0x2E,0x36,0xCE,0x3B, - 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,0xAA,0xC4,0x2D,0xAD,0x33,0x17,0x0D,0x04,0x50,0x7A,0x33, - 0xA8,0x55,0x21,0xAB,0xDF,0x1C,0xBA,0x64,0xEC,0xFB,0x85,0x04,0x58,0xDB,0xEF,0x0A, - 0x8A,0xEA,0x71,0x57,0x5D,0x06,0x0C,0x7D,0xB3,0x97,0x0F,0x85,0xA6,0xE1,0xE4,0xC7, - 0xAB,0xF5,0xAE,0x8C,0xDB,0x09,0x33,0xD7,0x1E,0x8C,0x94,0xE0,0x4A,0x25,0x61,0x9D, - 0xCE,0xE3,0xD2,0x26,0x1A,0xD2,0xEE,0x6B,0xF1,0x2F,0xFA,0x06,0xD9,0x8A,0x08,0x64, - 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 -}; - -/** - * Modulus of Group 16 (MODP_4096_BIT). - */ -static u_int8_t group16_modulus[] = { - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x34, - 0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74, - 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,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,0xE4,0x5B,0x3D,0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05, - 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,0x18,0x21,0x7C,0x32,0x90,0x5E,0x46,0x2E,0x36,0xCE,0x3B, - 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,0xAA,0xC4,0x2D,0xAD,0x33,0x17,0x0D,0x04,0x50,0x7A,0x33, - 0xA8,0x55,0x21,0xAB,0xDF,0x1C,0xBA,0x64,0xEC,0xFB,0x85,0x04,0x58,0xDB,0xEF,0x0A, - 0x8A,0xEA,0x71,0x57,0x5D,0x06,0x0C,0x7D,0xB3,0x97,0x0F,0x85,0xA6,0xE1,0xE4,0xC7, - 0xAB,0xF5,0xAE,0x8C,0xDB,0x09,0x33,0xD7,0x1E,0x8C,0x94,0xE0,0x4A,0x25,0x61,0x9D, - 0xCE,0xE3,0xD2,0x26,0x1A,0xD2,0xEE,0x6B,0xF1,0x2F,0xFA,0x06,0xD9,0x8A,0x08,0x64, - 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,0x21,0x08,0x01,0x1A,0x72,0x3C,0x12,0xA7,0x87,0xE6,0xD7, - 0x88,0x71,0x9A,0x10,0xBD,0xBA,0x5B,0x26,0x99,0xC3,0x27,0x18,0x6A,0xF4,0xE2,0x3C, - 0x1A,0x94,0x68,0x34,0xB6,0x15,0x0B,0xDA,0x25,0x83,0xE9,0xCA,0x2A,0xD4,0x4C,0xE8, - 0xDB,0xBB,0xC2,0xDB,0x04,0xDE,0x8E,0xF9,0x2E,0x8E,0xFC,0x14,0x1F,0xBE,0xCA,0xA6, - 0x28,0x7C,0x59,0x47,0x4E,0x6B,0xC0,0x5D,0x99,0xB2,0x96,0x4F,0xA0,0x90,0xC3,0xA2, - 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 -}; - -/** - * Modulus of Group 17 (MODP_6144_BIT). - */ -static u_int8_t group17_modulus[] = { - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x34, - 0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74, - 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,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,0xE4,0x5B,0x3D,0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05, - 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,0x18,0x21,0x7C,0x32,0x90,0x5E,0x46,0x2E,0x36,0xCE,0x3B, - 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,0xAA,0xC4,0x2D,0xAD,0x33,0x17,0x0D,0x04,0x50,0x7A,0x33, - 0xA8,0x55,0x21,0xAB,0xDF,0x1C,0xBA,0x64,0xEC,0xFB,0x85,0x04,0x58,0xDB,0xEF,0x0A, - 0x8A,0xEA,0x71,0x57,0x5D,0x06,0x0C,0x7D,0xB3,0x97,0x0F,0x85,0xA6,0xE1,0xE4,0xC7, - 0xAB,0xF5,0xAE,0x8C,0xDB,0x09,0x33,0xD7,0x1E,0x8C,0x94,0xE0,0x4A,0x25,0x61,0x9D, - 0xCE,0xE3,0xD2,0x26,0x1A,0xD2,0xEE,0x6B,0xF1,0x2F,0xFA,0x06,0xD9,0x8A,0x08,0x64, - 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,0x21,0x08,0x01,0x1A,0x72,0x3C,0x12,0xA7,0x87,0xE6,0xD7, - 0x88,0x71,0x9A,0x10,0xBD,0xBA,0x5B,0x26,0x99,0xC3,0x27,0x18,0x6A,0xF4,0xE2,0x3C, - 0x1A,0x94,0x68,0x34,0xB6,0x15,0x0B,0xDA,0x25,0x83,0xE9,0xCA,0x2A,0xD4,0x4C,0xE8, - 0xDB,0xBB,0xC2,0xDB,0x04,0xDE,0x8E,0xF9,0x2E,0x8E,0xFC,0x14,0x1F,0xBE,0xCA,0xA6, - 0x28,0x7C,0x59,0x47,0x4E,0x6B,0xC0,0x5D,0x99,0xB2,0x96,0x4F,0xA0,0x90,0xC3,0xA2, - 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,0x02,0x84,0x92,0x36,0xC3,0xFA,0xB4,0xD2,0x7C,0x70,0x26, - 0xC1,0xD4,0xDC,0xB2,0x60,0x26,0x46,0xDE,0xC9,0x75,0x1E,0x76,0x3D,0xBA,0x37,0xBD, - 0xF8,0xFF,0x94,0x06,0xAD,0x9E,0x53,0x0E,0xE5,0xDB,0x38,0x2F,0x41,0x30,0x01,0xAE, - 0xB0,0x6A,0x53,0xED,0x90,0x27,0xD8,0x31,0x17,0x97,0x27,0xB0,0x86,0x5A,0x89,0x18, - 0xDA,0x3E,0xDB,0xEB,0xCF,0x9B,0x14,0xED,0x44,0xCE,0x6C,0xBA,0xCE,0xD4,0xBB,0x1B, - 0xDB,0x7F,0x14,0x47,0xE6,0xCC,0x25,0x4B,0x33,0x20,0x51,0x51,0x2B,0xD7,0xAF,0x42, - 0x6F,0xB8,0xF4,0x01,0x37,0x8C,0xD2,0xBF,0x59,0x83,0xCA,0x01,0xC6,0x4B,0x92,0xEC, - 0xF0,0x32,0xEA,0x15,0xD1,0x72,0x1D,0x03,0xF4,0x82,0xD7,0xCE,0x6E,0x74,0xFE,0xF6, - 0xD5,0x5E,0x70,0x2F,0x46,0x98,0x0C,0x82,0xB5,0xA8,0x40,0x31,0x90,0x0B,0x1C,0x9E, - 0x59,0xE7,0xC9,0x7F,0xBE,0xC7,0xE8,0xF3,0x23,0xA9,0x7A,0x7E,0x36,0xCC,0x88,0xBE, - 0x0F,0x1D,0x45,0xB7,0xFF,0x58,0x5A,0xC5,0x4B,0xD4,0x07,0xB2,0x2B,0x41,0x54,0xAA, - 0xCC,0x8F,0x6D,0x7E,0xBF,0x48,0xE1,0xD8,0x14,0xCC,0x5E,0xD2,0x0F,0x80,0x37,0xE0, - 0xA7,0x97,0x15,0xEE,0xF2,0x9B,0xE3,0x28,0x06,0xA1,0xD5,0x8B,0xB7,0xC5,0xDA,0x76, - 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 -}; - -/** - * Modulus of Group 18 (MODP_8192_BIT). - */ -static u_int8_t group18_modulus[] = { - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x34, - 0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74, - 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,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,0xE4,0x5B,0x3D,0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05, - 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,0x18,0x21,0x7C,0x32,0x90,0x5E,0x46,0x2E,0x36,0xCE,0x3B, - 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,0xAA,0xC4,0x2D,0xAD,0x33,0x17,0x0D,0x04,0x50,0x7A,0x33, - 0xA8,0x55,0x21,0xAB,0xDF,0x1C,0xBA,0x64,0xEC,0xFB,0x85,0x04,0x58,0xDB,0xEF,0x0A, - 0x8A,0xEA,0x71,0x57,0x5D,0x06,0x0C,0x7D,0xB3,0x97,0x0F,0x85,0xA6,0xE1,0xE4,0xC7, - 0xAB,0xF5,0xAE,0x8C,0xDB,0x09,0x33,0xD7,0x1E,0x8C,0x94,0xE0,0x4A,0x25,0x61,0x9D, - 0xCE,0xE3,0xD2,0x26,0x1A,0xD2,0xEE,0x6B,0xF1,0x2F,0xFA,0x06,0xD9,0x8A,0x08,0x64, - 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,0x21,0x08,0x01,0x1A,0x72,0x3C,0x12,0xA7,0x87,0xE6,0xD7, - 0x88,0x71,0x9A,0x10,0xBD,0xBA,0x5B,0x26,0x99,0xC3,0x27,0x18,0x6A,0xF4,0xE2,0x3C, - 0x1A,0x94,0x68,0x34,0xB6,0x15,0x0B,0xDA,0x25,0x83,0xE9,0xCA,0x2A,0xD4,0x4C,0xE8, - 0xDB,0xBB,0xC2,0xDB,0x04,0xDE,0x8E,0xF9,0x2E,0x8E,0xFC,0x14,0x1F,0xBE,0xCA,0xA6, - 0x28,0x7C,0x59,0x47,0x4E,0x6B,0xC0,0x5D,0x99,0xB2,0x96,0x4F,0xA0,0x90,0xC3,0xA2, - 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,0x02,0x84,0x92,0x36,0xC3,0xFA,0xB4,0xD2,0x7C,0x70,0x26, - 0xC1,0xD4,0xDC,0xB2,0x60,0x26,0x46,0xDE,0xC9,0x75,0x1E,0x76,0x3D,0xBA,0x37,0xBD, - 0xF8,0xFF,0x94,0x06,0xAD,0x9E,0x53,0x0E,0xE5,0xDB,0x38,0x2F,0x41,0x30,0x01,0xAE, - 0xB0,0x6A,0x53,0xED,0x90,0x27,0xD8,0x31,0x17,0x97,0x27,0xB0,0x86,0x5A,0x89,0x18, - 0xDA,0x3E,0xDB,0xEB,0xCF,0x9B,0x14,0xED,0x44,0xCE,0x6C,0xBA,0xCE,0xD4,0xBB,0x1B, - 0xDB,0x7F,0x14,0x47,0xE6,0xCC,0x25,0x4B,0x33,0x20,0x51,0x51,0x2B,0xD7,0xAF,0x42, - 0x6F,0xB8,0xF4,0x01,0x37,0x8C,0xD2,0xBF,0x59,0x83,0xCA,0x01,0xC6,0x4B,0x92,0xEC, - 0xF0,0x32,0xEA,0x15,0xD1,0x72,0x1D,0x03,0xF4,0x82,0xD7,0xCE,0x6E,0x74,0xFE,0xF6, - 0xD5,0x5E,0x70,0x2F,0x46,0x98,0x0C,0x82,0xB5,0xA8,0x40,0x31,0x90,0x0B,0x1C,0x9E, - 0x59,0xE7,0xC9,0x7F,0xBE,0xC7,0xE8,0xF3,0x23,0xA9,0x7A,0x7E,0x36,0xCC,0x88,0xBE, - 0x0F,0x1D,0x45,0xB7,0xFF,0x58,0x5A,0xC5,0x4B,0xD4,0x07,0xB2,0x2B,0x41,0x54,0xAA, - 0xCC,0x8F,0x6D,0x7E,0xBF,0x48,0xE1,0xD8,0x14,0xCC,0x5E,0xD2,0x0F,0x80,0x37,0xE0, - 0xA7,0x97,0x15,0xEE,0xF2,0x9B,0xE3,0x28,0x06,0xA1,0xD5,0x8B,0xB7,0xC5,0xDA,0x76, - 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,0xBE,0x11,0x59,0x74,0xA3,0x92,0x6F,0x12,0xFE,0xE5,0xE4, - 0x38,0x77,0x7C,0xB6,0xA9,0x32,0xDF,0x8C,0xD8,0xBE,0xC4,0xD0,0x73,0xB9,0x31,0xBA, - 0x3B,0xC8,0x32,0xB6,0x8D,0x9D,0xD3,0x00,0x74,0x1F,0xA7,0xBF,0x8A,0xFC,0x47,0xED, - 0x25,0x76,0xF6,0x93,0x6B,0xA4,0x24,0x66,0x3A,0xAB,0x63,0x9C,0x5A,0xE4,0xF5,0x68, - 0x34,0x23,0xB4,0x74,0x2B,0xF1,0xC9,0x78,0x23,0x8F,0x16,0xCB,0xE3,0x9D,0x65,0x2D, - 0xE3,0xFD,0xB8,0xBE,0xFC,0x84,0x8A,0xD9,0x22,0x22,0x2E,0x04,0xA4,0x03,0x7C,0x07, - 0x13,0xEB,0x57,0xA8,0x1A,0x23,0xF0,0xC7,0x34,0x73,0xFC,0x64,0x6C,0xEA,0x30,0x6B, - 0x4B,0xCB,0xC8,0x86,0x2F,0x83,0x85,0xDD,0xFA,0x9D,0x4B,0x7F,0xA2,0xC0,0x87,0xE8, - 0x79,0x68,0x33,0x03,0xED,0x5B,0xDD,0x3A,0x06,0x2B,0x3C,0xF5,0xB3,0xA2,0x78,0xA6, - 0x6D,0x2A,0x13,0xF8,0x3F,0x44,0xF8,0x2D,0xDF,0x31,0x0E,0xE0,0x74,0xAB,0x6A,0x36, - 0x45,0x97,0xE8,0x99,0xA0,0x25,0x5D,0xC1,0x64,0xF3,0x1C,0xC5,0x08,0x46,0x85,0x1D, - 0xF9,0xAB,0x48,0x19,0x5D,0xED,0x7E,0xA1,0xB1,0xD5,0x10,0xBD,0x7E,0xE7,0x4D,0x73, - 0xFA,0xF3,0x6B,0xC3,0x1E,0xCF,0xA2,0x68,0x35,0x90,0x46,0xF4,0xEB,0x87,0x9F,0x92, - 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, -}; - -typedef struct modulus_entry_t modulus_entry_t; - -/** - * Entry of the modulus list. - */ -struct modulus_entry_t { - /** - * Group number as it is defined in file transform_substructure.h. - */ - diffie_hellman_group_t group; - - /** - * Pointer to first byte of modulus (network order). - */ - u_int8_t *modulus; - - /* - * Length of modulus in bytes. - */ - size_t modulus_len; - - /* - * Generator value. - */ - u_int16_t generator; -}; - -/** - * All supported modulus values. - */ -static modulus_entry_t modulus_entries[] = { - {MODP_768_BIT, group1_modulus, sizeof(group1_modulus), 2}, - {MODP_1024_BIT, group2_modulus, sizeof(group2_modulus), 2}, - {MODP_1536_BIT, group5_modulus, sizeof(group5_modulus), 2}, - {MODP_2048_BIT, group14_modulus, sizeof(group14_modulus), 2}, - {MODP_3072_BIT, group15_modulus, sizeof(group15_modulus), 2}, - {MODP_4096_BIT, group16_modulus, sizeof(group16_modulus), 2}, - {MODP_6144_BIT, group17_modulus, sizeof(group17_modulus), 2}, - {MODP_8192_BIT, group18_modulus, sizeof(group18_modulus), 2}, -}; - -typedef struct private_diffie_hellman_t private_diffie_hellman_t; - -/** - * Private data of an diffie_hellman_t object. - * - */ -struct private_diffie_hellman_t { - /** - * Public diffie_hellman_t interface. - */ - diffie_hellman_t public; - - /** - * Diffie Hellman group number. - */ - u_int16_t group; - - /* - * Generator value. - */ - mpz_t g; - - /** - * My private value. - */ - mpz_t xa; - - /** - * My public value. - */ - mpz_t ya; - - /** - * Other public value. - */ - mpz_t yb; - - /** - * Shared secret. - */ - mpz_t zz; - - /** - * Modulus. - */ - mpz_t p; - - /** - * Modulus length. - */ - size_t p_len; - - /** - * True if shared secret is computed and stored in my_public_value. - */ - bool computed; -}; - -/** - * Implementation of diffie_hellman_t.set_other_public_value. - */ -static void set_other_public_value(private_diffie_hellman_t *this, chunk_t value) -{ - mpz_t p_min_1; - - mpz_init(p_min_1); - mpz_sub_ui(p_min_1, this->p, 1); - - mpz_import(this->yb, value.len, 1, 1, 1, 0, value.ptr); - - /* check public value: - * 1. 0 or 1 is invalid as 0^a = 0 and 1^a = 1 - * 2. a public value larger or equal the modulus is invalid */ - if (mpz_cmp_ui(this->yb, 1) > 0 || - mpz_cmp(this->yb, p_min_1) < 0) - { -#ifdef EXTENDED_DH_TEST - /* 3. test if y ^ q mod p = 1, where q = (p - 1)/2. */ - mpz_t q, one; - - mpz_init(q); - mpz_init(one); - mpz_fdiv_q_2exp(q, p_min_1, 1); - mpz_powm(one, this->yb, q, this->p); - mpz_clear(q); - if (mpz_cmp_ui(one, 1) == 0) - { - mpz_powm(this->zz, this->yb, this->xa, this->p); - this->computed = TRUE; - } - else - { - DBG1("public DH value verification failed: y ^ q mod p != 1"); - } - mpz_clear(one); -#else - mpz_powm(this->zz, this->yb, this->xa, this->p); - this->computed = TRUE; -#endif - } - else - { - DBG1("public DH value verification failed: y < 2 || y > p - 1 "); - } - mpz_clear(p_min_1); -} - -/** - * Implementation of diffie_hellman_t.get_other_public_value. - */ -static status_t get_other_public_value(private_diffie_hellman_t *this, - chunk_t *value) -{ - if (!this->computed) - { - return FAILED; - } - value->len = this->p_len; - value->ptr = mpz_export(NULL, NULL, 1, value->len, 1, 0, this->yb); - return SUCCESS; -} - -/** - * Implementation of diffie_hellman_t.get_my_public_value. - */ -static void get_my_public_value(private_diffie_hellman_t *this,chunk_t *value) -{ - value->len = this->p_len; - value->ptr = mpz_export(NULL, NULL, 1, value->len, 1, 0, this->ya); -} - -/** - * Implementation of diffie_hellman_t.get_shared_secret. - */ -static status_t get_shared_secret(private_diffie_hellman_t *this, chunk_t *secret) -{ - if (!this->computed) - { - return FAILED; - } - secret->len = this->p_len; - secret->ptr = mpz_export(NULL, NULL, 1, secret->len, 1, 0, this->zz); - return SUCCESS; -} - -/** - * Implementation of diffie_hellman_t.get_dh_group. - */ -static diffie_hellman_group_t get_dh_group(private_diffie_hellman_t *this) -{ - return this->group; -} - -/** - * Lookup the modulus in modulo table - */ -static status_t set_modulus(private_diffie_hellman_t *this) -{ - int i; - status_t status = NOT_FOUND; - - for (i = 0; i < (sizeof(modulus_entries) / sizeof(modulus_entry_t)); i++) - { - if (modulus_entries[i].group == this->group) - { - chunk_t chunk; - chunk.ptr = modulus_entries[i].modulus; - chunk.len = modulus_entries[i].modulus_len; - mpz_import(this->p, chunk.len, 1, 1, 1, 0, chunk.ptr); - this->p_len = chunk.len; - mpz_set_ui(this->g, modulus_entries[i].generator); - status = SUCCESS; - break; - } - } - return status; -} - -/** - * Implementation of diffie_hellman_t.destroy. - */ -static void destroy(private_diffie_hellman_t *this) -{ - mpz_clear(this->p); - mpz_clear(this->xa); - mpz_clear(this->ya); - mpz_clear(this->yb); - mpz_clear(this->zz); - mpz_clear(this->g); - free(this); -} - -/* - * Described in header. - */ -diffie_hellman_t *diffie_hellman_create(diffie_hellman_group_t group) -{ - private_diffie_hellman_t *this = malloc_thing(private_diffie_hellman_t); - randomizer_t *randomizer; - chunk_t random; - status_t status; - - /* public functions */ - this->public.get_shared_secret = (status_t (*)(diffie_hellman_t *, chunk_t *)) get_shared_secret; - this->public.set_other_public_value = (void (*)(diffie_hellman_t *, chunk_t )) set_other_public_value; - this->public.get_other_public_value = (status_t (*)(diffie_hellman_t *, chunk_t *)) get_other_public_value; - this->public.get_my_public_value = (void (*)(diffie_hellman_t *, chunk_t *)) get_my_public_value; - this->public.get_dh_group = (diffie_hellman_group_t (*)(diffie_hellman_t *)) get_dh_group; - this->public.destroy = (void (*)(diffie_hellman_t *)) destroy; - - /* private variables */ - this->group = group; - mpz_init(this->p); - mpz_init(this->yb); - mpz_init(this->ya); - mpz_init(this->xa); - mpz_init(this->zz); - mpz_init(this->g); - - this->computed = FALSE; - - /* find a modulus according to group */ - if (set_modulus(this) != SUCCESS) - { - destroy(this); - return NULL; - } - randomizer = randomizer_create(); - status = randomizer->allocate_pseudo_random_bytes( - randomizer, this->p_len, &random); - randomizer->destroy(randomizer); - if (status != SUCCESS) - { - destroy(this); - return NULL; - } - mpz_import(this->xa, random.len, 1, 1, 1, 0, random.ptr); - chunk_free(&random); - - mpz_powm(this->ya, this->g, this->xa, this->p); - - return &this->public; -} - diff --git a/src/libstrongswan/crypto/diffie_hellman.h b/src/libstrongswan/crypto/diffie_hellman.h index 8cd06d60e..07e475b47 100644 --- a/src/libstrongswan/crypto/diffie_hellman.h +++ b/src/libstrongswan/crypto/diffie_hellman.h @@ -1,10 +1,3 @@ -/** - * @file diffie_hellman.h - * - * @brief Interface of diffie_hellman_t. - * - */ - /* * Copyright (C) 2005-2007 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup diffie_hellman diffie_hellman + * @{ @ingroup crypto */ #ifndef DIFFIE_HELLMAN_H_ @@ -30,13 +30,10 @@ typedef struct diffie_hellman_t diffie_hellman_t; #include /** - * @brief Diffie-Hellman group. + * Diffie-Hellman group. * * The modulus (or group) to use for a Diffie-Hellman calculation. - * * See IKEv2 RFC 3.3.2 and RFC 3526. - * - * @ingroup crypto */ enum diffie_hellman_group_t { MODP_NONE = 0, @@ -56,89 +53,60 @@ enum diffie_hellman_group_t { extern enum_name_t *diffie_hellman_group_names; /** - * @brief Implementation of the Diffie-Hellman algorithm, as in RFC2631. - * - * @b Constructors: - * - diffie_hellman_create() - * - * @ingroup crypto + * Implementation of the Diffie-Hellman algorithm, as in RFC2631. */ struct diffie_hellman_t { /** - * @brief Returns the shared secret of this diffie hellman exchange. + * Returns the shared secret of this diffie hellman exchange. * * Space for returned secret is allocated and must be * freed by the caller. * - * @param this calling object * @param secret shared secret will be written into this chunk - * @return - * - SUCCESS - * - FAILED if not both DH values are set + * @return SUCCESS, FAILED if not both DH values are set */ status_t (*get_shared_secret) (diffie_hellman_t *this, chunk_t *secret); /** - * @brief Sets the public value of partner. + * Sets the public value of partner. * * Chunk gets cloned and can be destroyed afterwards. * - * @param this calling object * @param value public value of partner */ void (*set_other_public_value) (diffie_hellman_t *this, chunk_t value); /** - * @brief Gets the public value of partner. + * Gets the public value of partner. * * Space for returned chunk is allocated and must be freed by the caller. * - * @param this calling object * @param value public value of partner is stored at this location - * @return - * - SUCCESS - * - FAILED if other public value not set + * @return SUCCESS, FAILED if other public value not set */ status_t (*get_other_public_value) (diffie_hellman_t *this, chunk_t *value); /** - * @brief Gets the own public value to transmit. + * Gets the own public value to transmit. * * Space for returned chunk is allocated and must be freed by the caller. * - * @param this calling object * @param value public value of caller is stored at this location */ void (*get_my_public_value) (diffie_hellman_t *this, chunk_t *value); /** - * @brief Get the DH group used. + * Get the DH group used. * - * @param this calling object * @return DH group set in construction */ diffie_hellman_group_t (*get_dh_group) (diffie_hellman_t *this); /** - * @brief Destroys an diffie_hellman_t object. - * - * @param this diffie_hellman_t object to destroy + * Destroys an diffie_hellman_t object. */ void (*destroy) (diffie_hellman_t *this); }; -/** - * @brief Creates a new diffie_hellman_t object. - * - * @param group Diffie Hellman group number to use - * @return - * - diffie_hellman_t object - * - NULL if dh group not supported - * - * @ingroup crypto - */ -diffie_hellman_t *diffie_hellman_create(diffie_hellman_group_t group); - -#endif /*DIFFIE_HELLMAN_H_*/ - +#endif /*DIFFIE_HELLMAN_H_ @} */ diff --git a/src/libstrongswan/crypto/hashers/hasher.c b/src/libstrongswan/crypto/hashers/hasher.c index d8c6ff94c..ea4b4b08b 100644 --- a/src/libstrongswan/crypto/hashers/hasher.c +++ b/src/libstrongswan/crypto/hashers/hasher.c @@ -1,10 +1,3 @@ -/** - * @file hasher.c - * - * @brief Generic constructor for hasher_t. - * - */ - /* * Copyright (C) 2005 Jan Hutter * Copyright (C) 2005-2006 Martin Willi @@ -21,91 +14,53 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id$ + * $Id$ */ - #include "hasher.h" #include -#include -#include -#include - ENUM(hash_algorithm_names, HASH_UNKNOWN, HASH_SHA512, "HASH_UNKNOWN", + "HASH_PREFERRED", "HASH_MD2", "HASH_MD5", "HASH_SHA1", + "HASH_SHA1_NOFINAL", "HASH_SHA256", "HASH_SHA384", "HASH_SHA512" ); -/* - * Described in header. - */ -hasher_t *hasher_create(hash_algorithm_t hash_algorithm) -{ - switch (hash_algorithm) - { - case HASH_SHA1: - { - return (hasher_t*)sha1_hasher_create(); - } - case HASH_SHA256: - case HASH_SHA384: - case HASH_SHA512: - { - return (hasher_t*)sha2_hasher_create(hash_algorithm); - } - case HASH_MD5: - { - return (hasher_t*)md5_hasher_create(); - } - default: - return NULL; - } -} - /* * Described in header. */ hash_algorithm_t hasher_algorithm_from_oid(int oid) { - hash_algorithm_t algorithm; - switch (oid) { case OID_MD2: case OID_MD2_WITH_RSA: - algorithm = HASH_MD2; - break; + return HASH_MD2; case OID_MD5: case OID_MD5_WITH_RSA: - algorithm = HASH_MD5; - break; + return HASH_MD5; case OID_SHA1: case OID_SHA1_WITH_RSA: - algorithm = HASH_SHA1; - break; + return HASH_SHA1; case OID_SHA256: case OID_SHA256_WITH_RSA: - algorithm = HASH_SHA256; - break; + return HASH_SHA256; case OID_SHA384: case OID_SHA384_WITH_RSA: - algorithm = HASH_SHA384; - break; + return HASH_SHA384; case OID_SHA512: case OID_SHA512_WITH_RSA: - algorithm = HASH_SHA512; - break; + return HASH_SHA512; default: - algorithm = HASH_UNKNOWN; + return HASH_UNKNOWN; } - return algorithm; } /* diff --git a/src/libstrongswan/crypto/hashers/hasher.h b/src/libstrongswan/crypto/hashers/hasher.h index d6604b883..4aa4ba357 100644 --- a/src/libstrongswan/crypto/hashers/hasher.h +++ b/src/libstrongswan/crypto/hashers/hasher.h @@ -1,10 +1,3 @@ -/** - * @file hasher.h - * - * @brief Interface hasher_t. - * - */ - /* * Copyright (C) 2005 Jan Hutter * Copyright (C) 2005-2006 Martin Willi @@ -21,7 +14,12 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id$ + * $Id$ + */ + +/** + * @defgroup traffic_selector traffic_selector + * @{ @ingroup config */ #ifndef HASHER_H_ @@ -33,30 +31,21 @@ typedef struct hasher_t hasher_t; #include /** - * @brief Algorithms to use for hashing. - * - * Currently only the following algorithms are implemented: - * - HASH_MD5 - * - HASH_SHA1 - * - HASH_SHA256 - * - HASH_SHA384 - * - HASH_SHA512 - * - * @ingroup hashers + * Algorithms to use for hashing. */ enum hash_algorithm_t { - HASH_UNKNOWN = 0, - HASH_MD2 = 1, - /** Implemented in class md5_hasher_t */ - HASH_MD5 = 2, - /** Implemented in class sha1_hasher_t */ - HASH_SHA1 = 3, - /** Implemented in class sha2_hasher_t */ - HASH_SHA256 = 4, - /** Implemented in class sha2_hasher_t */ - HASH_SHA384 = 5, - /** Implemented in class sha2_hasher_t */ - HASH_SHA512 = 6, + /** not specified hash function */ + HASH_UNKNOWN = 0, + /** preferred hash function, general purpose */ + HASH_PREFERRED = 1, + HASH_MD2 = 2, + HASH_MD5 = 3, + HASH_SHA1 = 4, + /** special SHA1 which does not run SHA1Final, but copies the state */ + HASH_SHA1_NOFINAL = 5, + HASH_SHA256 = 6, + HASH_SHA384 = 7, + HASH_SHA512 = 8, }; #define HASH_SIZE_MD2 16 @@ -65,7 +54,6 @@ enum hash_algorithm_t { #define HASH_SIZE_SHA256 32 #define HASH_SIZE_SHA384 48 #define HASH_SIZE_SHA512 64 -#define HASH_SIZE_MAX 64 /** * enum names for hash_algorithm_t. @@ -73,16 +61,11 @@ enum hash_algorithm_t { extern enum_name_t *hash_algorithm_names; /** - * @brief Generic interface for all hash functions. - * - * @b Constructors: - * - hasher_create() - * - * @ingroup hashers + * Generic interface for all hash functions. */ struct hasher_t { /** - * @brief Hash data and write it in the buffer. + * Hash data and write it in the buffer. * * If the parameter hash is NULL, no result is written back * and more data can be appended to already hashed data. @@ -91,108 +74,63 @@ struct hasher_t { * The hash output parameter must hold at least * hash_t.get_block_size() bytes. * - * @param this calling object - * @param data data to hash - * @param[out] hash pointer where the hash will be written + * @param data data to hash + * @param hash pointer where the hash will be written */ void (*get_hash) (hasher_t *this, chunk_t data, u_int8_t *hash); /** - * @brief Hash data and allocate space for the hash. + * Hash data and allocate space for the hash. * * If the parameter hash is NULL, no result is written back * and more data can be appended to already hashed data. * If not, the result is written back and the hasher is reset. * - * @param this calling object - * @param data chunk with data to hash - * @param[out] hash chunk which will hold allocated hash + * @param data chunk with data to hash + * @param hash chunk which will hold allocated hash */ void (*allocate_hash) (hasher_t *this, chunk_t data, chunk_t *hash); /** - * @brief Get the size of the resulting hash. + * Get the size of the resulting hash. * - * @param this calling object - * @return hash size in bytes + * @return hash size in bytes */ size_t (*get_hash_size) (hasher_t *this); /** - * @brief Resets the hashers state. - * - * @param this calling object + * Resets the hashers state. */ void (*reset) (hasher_t *this); /** - * @brief Get the state of the hasher. - * - * A hasher stores internal state information. This state may be - * manipulated to include a "seed" into the hashing operation. It used by - * some exotic protocols (such as AKA). - * The data pointed by chunk may be manipulated, but not replaced nor freed. - * This is more a hack than a feature. The hasher's state may be byte - * order dependant; use with care. - * - * @param this calling object - */ - chunk_t (*get_state) (hasher_t *this); - - /** - * @brief Destroys a hasher object. - * - * @param this calling object + * Destroys a hasher object. */ void (*destroy) (hasher_t *this); }; /** - * @brief Generic interface to create a hasher_t. + * Conversion of ASN.1 OID to hash algorithm. * - * @param hash_algorithm Algorithm to use for hashing - * @return - * - hasher_t object - * - NULL if algorithm not supported - * - * @ingroup hashers - */ -hasher_t *hasher_create(hash_algorithm_t hash_algorithm); - -/** - * @brief Conversion of ASN.1 OID to hash algorithm. - * - * @param oid ASN.1 OID - * @return - * - hash algorithm - * - HASH_UNKNOWN if OID unsuported - * - * @ingroup hashers + * @param oid ASN.1 OID + * @return hash algorithm, HASH_UNKNOWN if OID unsuported */ hash_algorithm_t hasher_algorithm_from_oid(int oid); /** - * @brief Conversion of hash algorithm into ASN.1 OID. + * Conversion of hash algorithm into ASN.1 OID. * - * @param alg hash algorithm - * @return - * - ASN.1 hash OID if known hash algorithm - * - OID_UNKNOW - * - * @ingroup hashers + * @param alg hash algorithm + * @return ASN.1 OID, or OID_UNKNOW */ int hasher_algorithm_to_oid(hash_algorithm_t alg); /** - * @brief Conversion of hash signature algorithm into ASN.1 OID. - * - * @param alg hash algorithm - * @return - * - ASN.1 signature OID if known hash algorithm - * - OID_UNKNOW + * Conversion of hash signature algorithm into ASN.1 OID. * - * @ingroup hashers + * @param alg hash algorithm + * @return ASN.1 OID if, or OID_UNKNOW */ int hasher_signature_algorithm_to_oid(hash_algorithm_t alg); -#endif /* HASHER_H_ */ +#endif /* HASHER_H_ @} */ diff --git a/src/libstrongswan/crypto/hashers/md5_hasher.c b/src/libstrongswan/crypto/hashers/md5_hasher.c deleted file mode 100644 index d4dde3693..000000000 --- a/src/libstrongswan/crypto/hashers/md5_hasher.c +++ /dev/null @@ -1,405 +0,0 @@ -/** - * @file md5_hasher.c - * - * @brief Implementation of md5_hasher_t. - * - */ - -/* - * Copyright (C) 2005-2006 Martin Willi - * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil - * Copyright (C) 1991-1992, RSA Data Security, Inc. Created 1991. - * All rights reserved. - * - * Derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm. - * Ported to fulfill hasher_t interface. - * - * 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 . - * - * 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 - -#include "md5_hasher.h" - - -/* Constants for MD5Transform routine. */ -#define S11 7 -#define S12 12 -#define S13 17 -#define S14 22 -#define S21 5 -#define S22 9 -#define S23 14 -#define S24 20 -#define S31 4 -#define S32 11 -#define S33 16 -#define S34 23 -#define S41 6 -#define S42 10 -#define S43 15 -#define S44 21 - -static u_int8_t PADDING[64] = { - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; - -/* - * ugly macro stuff - */ -/* F, G, H and I are basic MD5 functions. - */ -#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) -#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) -#define H(x, y, z) ((x) ^ (y) ^ (z)) -#define I(x, y, z) ((y) ^ ((x) | (~z))) - -/* ROTATE_LEFT rotates x left n bits. - */ -#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) - -/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. -Rotation is separate from addition to prevent recomputation. - */ -#define FF(a, b, c, d, x, s, ac) { \ - (a) += F ((b), (c), (d)) + (x) + (u_int32_t)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } -#define GG(a, b, c, d, x, s, ac) { \ - (a) += G ((b), (c), (d)) + (x) + (u_int32_t)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } -#define HH(a, b, c, d, x, s, ac) { \ - (a) += H ((b), (c), (d)) + (x) + (u_int32_t)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } -#define II(a, b, c, d, x, s, ac) { \ - (a) += I ((b), (c), (d)) + (x) + (u_int32_t)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } - - - -typedef struct private_md5_hasher_t private_md5_hasher_t; - -/** - * Private data structure with hasing context. - */ -struct private_md5_hasher_t { - /** - * Public interface for this hasher. - */ - md5_hasher_t public; - - /* - * State of the hasher. - */ - u_int32_t state[5]; - u_int32_t count[2]; - u_int8_t buffer[64]; -}; - - -#if BYTE_ORDER != LITTLE_ENDIAN - -/* Encodes input (u_int32_t) into output (u_int8_t). Assumes len is - * a multiple of 4. - */ -static void Encode (u_int8_t *output, u_int32_t *input, size_t len) -{ - size_t i, j; - - for (i = 0, j = 0; j < len; i++, j += 4) - { - output[j] = (u_int8_t)(input[i] & 0xff); - output[j+1] = (u_int8_t)((input[i] >> 8) & 0xff); - output[j+2] = (u_int8_t)((input[i] >> 16) & 0xff); - output[j+3] = (u_int8_t)((input[i] >> 24) & 0xff); - } -} - -/* Decodes input (u_int8_t) into output (u_int32_t). Assumes len is - * a multiple of 4. - */ -static void Decode(u_int32_t *output, u_int8_t *input, size_t len) -{ - size_t i, j; - - for (i = 0, j = 0; j < len; i++, j += 4) - { - output[i] = ((u_int32_t)input[j]) | (((u_int32_t)input[j+1]) << 8) | - (((u_int32_t)input[j+2]) << 16) | (((u_int32_t)input[j+3]) << 24); - } -} - -#elif BYTE_ORDER == LITTLE_ENDIAN - #define Encode memcpy - #define Decode memcpy -#endif - -/* MD5 basic transformation. Transforms state based on block. - */ -static void MD5Transform(u_int32_t state[4], u_int8_t block[64]) -{ - u_int32_t a = state[0], b = state[1], c = state[2], d = state[3], x[16]; - - Decode(x, block, 64); - - /* Round 1 */ - FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ - FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ - FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ - FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ - FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ - FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ - FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ - FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ - FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ - FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ - FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ - FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ - FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ - FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ - FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ - FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ - - /* Round 2 */ - GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ - GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ - GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ - GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ - GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ - GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ - GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ - GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ - GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ - GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ - GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ - GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ - GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ - GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ - GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ - GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ - - /* Round 3 */ - HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ - HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ - HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ - HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ - HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ - HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ - HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ - HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ - HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ - HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ - HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ - HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ - HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ - HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ - HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ - HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ - - /* Round 4 */ - II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ - II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ - II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ - II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ - II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ - II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ - II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ - II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ - II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ - II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ - II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ - II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ - II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ - II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ - II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ - II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ - - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; -} - -/* MD5 block update operation. Continues an MD5 message-digest - * operation, processing another message block, and updating the - * context. - */ -static void MD5Update(private_md5_hasher_t *this, u_int8_t *input, size_t inputLen) -{ - u_int32_t i; - size_t index, partLen; - - /* Compute number of bytes mod 64 */ - index = (u_int8_t)((this->count[0] >> 3) & 0x3F); - - /* Update number of bits */ - if ((this->count[0] += (inputLen << 3)) < (inputLen << 3)) - { - this->count[1]++; - } - this->count[1] += (inputLen >> 29); - - partLen = 64 - index; - - /* Transform as many times as possible. */ - if (inputLen >= partLen) - { - memcpy(&this->buffer[index], input, partLen); - MD5Transform (this->state, this->buffer); - - for (i = partLen; i + 63 < inputLen; i += 64) - { - MD5Transform (this->state, &input[i]); - } - index = 0; - } - else - { - i = 0; - } - - /* Buffer remaining input */ - memcpy(&this->buffer[index], &input[i], inputLen-i); -} - -/* MD5 finalization. Ends an MD5 message-digest operation, writing the - * the message digest and zeroizing the context. - */ -static void MD5Final (private_md5_hasher_t *this, u_int8_t digest[16]) -{ - u_int8_t bits[8]; - size_t index, padLen; - - /* Save number of bits */ - Encode (bits, this->count, 8); - - /* Pad out to 56 mod 64. */ - index = (size_t)((this->count[0] >> 3) & 0x3f); - padLen = (index < 56) ? (56 - index) : (120 - index); - MD5Update (this, PADDING, padLen); - - /* Append length (before padding) */ - MD5Update (this, bits, 8); - - if (digest != NULL) /* Bill Simpson's padding */ - { - /* store state in digest */ - Encode (digest, this->state, 16); - } -} - - - -/** - * Implementation of hasher_t.get_hash. - */ -static void get_hash(private_md5_hasher_t *this, chunk_t chunk, u_int8_t *buffer) -{ - MD5Update(this, chunk.ptr, chunk.len); - if (buffer != NULL) - { - MD5Final(this, buffer); - this->public.hasher_interface.reset(&(this->public.hasher_interface)); - } -} - - -/** - * Implementation of hasher_t.allocate_hash. - */ -static void allocate_hash(private_md5_hasher_t *this, chunk_t chunk, chunk_t *hash) -{ - chunk_t allocated_hash; - - MD5Update(this, chunk.ptr, chunk.len); - if (hash != NULL) - { - allocated_hash.ptr = malloc(HASH_SIZE_MD5); - allocated_hash.len = HASH_SIZE_MD5; - - MD5Final(this, allocated_hash.ptr); - this->public.hasher_interface.reset(&(this->public.hasher_interface)); - - *hash = allocated_hash; - } -} - -/** - * Implementation of hasher_t.get_hash_size. - */ -static size_t get_hash_size(private_md5_hasher_t *this) -{ - return HASH_SIZE_MD5; -} - -/** - * Implementation of hasher_t.reset. - */ -static void reset(private_md5_hasher_t *this) -{ - this->state[0] = 0x67452301; - this->state[1] = 0xefcdab89; - this->state[2] = 0x98badcfe; - this->state[3] = 0x10325476; - this->count[0] = 0; - this->count[1] = 0; -} - -/** - * Implementation of hasher_t.get_state - */ -static chunk_t get_state(private_md5_hasher_t *this) -{ - chunk_t chunk; - - chunk.ptr = (u_char*)&this->state[0]; - chunk.len = sizeof(this->state); - - return chunk; -} - -/** - * Implementation of hasher_t.destroy. - */ -static void destroy(private_md5_hasher_t *this) -{ - free(this); -} - -/* - * Described in header. - */ -md5_hasher_t *md5_hasher_create(void) -{ - private_md5_hasher_t *this = malloc_thing(private_md5_hasher_t); - - this->public.hasher_interface.get_hash = (void (*) (hasher_t*, chunk_t, u_int8_t*))get_hash; - this->public.hasher_interface.allocate_hash = (void (*) (hasher_t*, chunk_t, chunk_t*))allocate_hash; - this->public.hasher_interface.get_hash_size = (size_t (*) (hasher_t*))get_hash_size; - this->public.hasher_interface.reset = (void (*) (hasher_t*))reset; - this->public.hasher_interface.get_state = (chunk_t (*) (hasher_t*))get_state; - this->public.hasher_interface.destroy = (void (*) (hasher_t*))destroy; - - /* initialize */ - reset(this); - - return &(this->public); -} diff --git a/src/libstrongswan/crypto/hashers/md5_hasher.h b/src/libstrongswan/crypto/hashers/md5_hasher.h deleted file mode 100644 index 715f11663..000000000 --- a/src/libstrongswan/crypto/hashers/md5_hasher.h +++ /dev/null @@ -1,60 +0,0 @@ -/** - * @file md5_hasher.h - * - * @brief Interface for md5_hasher_t. - * - */ - -/* - * Copyright (C) 2005-2006 Martin Willi - * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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 MD5_HASHER_H_ -#define MD5_HASHER_H_ - -typedef struct md5_hasher_t md5_hasher_t; - -#include - -/** - * @brief Implementation of hasher_t interface using the - * MD5 algorithm. - * - * @b Constructors: - * - hasher_create() using HASH_MD5 as algorithm - * - md5_hasher_create() - * - * @see hasher_t - * - * @ingroup hashers - */ -struct md5_hasher_t { - - /** - * Generic hasher_t interface for this hasher. - */ - hasher_t hasher_interface; -}; - -/** - * @brief Creates a new md5_hasher_t. - * - * @return md5_hasher_t object - * - * @ingroup hashers - */ -md5_hasher_t *md5_hasher_create(void); - -#endif /*MD5_HASHER_H_*/ diff --git a/src/libstrongswan/crypto/hashers/sha1_hasher.c b/src/libstrongswan/crypto/hashers/sha1_hasher.c deleted file mode 100644 index 6a86937ae..000000000 --- a/src/libstrongswan/crypto/hashers/sha1_hasher.c +++ /dev/null @@ -1,280 +0,0 @@ -/** - * @file sha1_hasher.c - * - * @brief Implementation of hasher_sha_t. - * - */ - -/* - * Copyright (C) 2005-2006 Martin Willi - * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil - * - * Ported from Steve Reid's implementation - * "SHA1 in C" found in strongSwan. - * - * 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 . - * - * 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 - -#include "sha1_hasher.h" - -/* - * ugly macro stuff - */ -#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) - -#if BYTE_ORDER == LITTLE_ENDIAN - #define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) |(rol(block->l[i],8)&0x00FF00FF)) -#elif BYTE_ORDER == BIG_ENDIAN - #define blk0(i) block->l[i] -#else - #error "Endianness not defined!" -#endif -#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] ^block->l[(i+2)&15]^block->l[i&15],1)) - -/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ -#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); -#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); -#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); -#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); -#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); - - -typedef struct private_sha1_hasher_t private_sha1_hasher_t; - -/** - * Private data structure with hasing context. - */ -struct private_sha1_hasher_t { - /** - * Public interface for this hasher. - */ - sha1_hasher_t public; - - /* - * State of the hasher. - */ - u_int32_t state[5]; - u_int32_t count[2]; - u_int8_t buffer[64]; -}; - -/* - * Hash a single 512-bit block. This is the core of the algorithm. * - */ -static void SHA1Transform(u_int32_t state[5], const unsigned char buffer[64]) -{ - u_int32_t a, b, c, d, e; - typedef union { - u_int8_t c[64]; - u_int32_t l[16]; - } CHAR64LONG16; - CHAR64LONG16 block[1]; /* use array to appear as a pointer */ - memcpy(block, buffer, 64); - - /* Copy context->state[] to working vars */ - a = state[0]; - b = state[1]; - c = state[2]; - d = state[3]; - e = state[4]; - /* 4 rounds of 20 operations each. Loop unrolled. */ - R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); - R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); - R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); - R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); - R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); - R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); - R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); - R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); - R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); - R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); - R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); - R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); - R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); - R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); - R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); - R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); - R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); - R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); - R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); - R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); - /* Add the working vars back into context.state[] */ - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; - state[4] += e; - /* Wipe variables */ - a = b = c = d = e = 0; - memset(block, '\0', sizeof(block)); -} - -/* - * Run your data through this. - */ -static void SHA1Update(private_sha1_hasher_t* this, u_int8_t *data, u_int32_t len) -{ - u_int32_t i; - u_int32_t j; - - j = this->count[0]; - if ((this->count[0] += len << 3) < j) - { - this->count[1]++; - } - this->count[1] += (len>>29); - j = (j >> 3) & 63; - if ((j + len) > 63) - { - memcpy(&this->buffer[j], data, (i = 64-j)); - SHA1Transform(this->state, this->buffer); - for ( ; i + 63 < len; i += 64) - { - SHA1Transform(this->state, &data[i]); - } - j = 0; - } - else - { - i = 0; - } - memcpy(&this->buffer[j], &data[i], len - i); -} - - -/* - * Add padding and return the message digest. - */ -static void SHA1Final(private_sha1_hasher_t *this, u_int8_t *digest) -{ - u_int32_t i; - u_int8_t finalcount[8]; - u_int8_t c; - - for (i = 0; i < 8; i++) - { - finalcount[i] = (u_int8_t)((this->count[(i >= 4 ? 0 : 1)] - >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ - } - c = 0200; - SHA1Update(this, &c, 1); - while ((this->count[0] & 504) != 448) - { - c = 0000; - SHA1Update(this, &c, 1); - } - SHA1Update(this, finalcount, 8); /* Should cause a SHA1Transform() */ - for (i = 0; i < 20; i++) - { - digest[i] = (u_int8_t)((this->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); - } -} - - -/** - * Implementation of hasher_t.get_hash. - */ -static void get_hash(private_sha1_hasher_t *this, chunk_t chunk, u_int8_t *buffer) -{ - SHA1Update(this, chunk.ptr, chunk.len); - if (buffer != NULL) - { - SHA1Final(this, buffer); - this->public.hasher_interface.reset(&(this->public.hasher_interface)); - } -} - - -/** - * Implementation of hasher_t.allocate_hash. - */ -static void allocate_hash(private_sha1_hasher_t *this, chunk_t chunk, chunk_t *hash) -{ - chunk_t allocated_hash; - - SHA1Update(this, chunk.ptr, chunk.len); - if (hash != NULL) - { - allocated_hash.ptr = malloc(HASH_SIZE_SHA1); - allocated_hash.len = HASH_SIZE_SHA1; - - SHA1Final(this, allocated_hash.ptr); - this->public.hasher_interface.reset(&(this->public.hasher_interface)); - - *hash = allocated_hash; - } -} - -/** - * Implementation of hasher_t.get_hash_size. - */ -static size_t get_hash_size(private_sha1_hasher_t *this) -{ - return HASH_SIZE_SHA1; -} - -/** - * Implementation of hasher_t.reset. - */ -static void reset(private_sha1_hasher_t *this) -{ - this->state[0] = 0x67452301; - this->state[1] = 0xEFCDAB89; - this->state[2] = 0x98BADCFE; - this->state[3] = 0x10325476; - this->state[4] = 0xC3D2E1F0; - this->count[0] = 0; - this->count[1] = 0; -} - -/** - * Implementation of hasher_t.get_state - */ -static chunk_t get_state(private_sha1_hasher_t *this) -{ - chunk_t chunk; - - chunk.ptr = (u_char*)&this->state[0]; - chunk.len = sizeof(this->state); - - return chunk; -} - -/** - * Implementation of hasher_t.destroy. - */ -static void destroy(private_sha1_hasher_t *this) -{ - free(this); -} - -/* - * Described in header. - */ -sha1_hasher_t *sha1_hasher_create(void) -{ - private_sha1_hasher_t *this = malloc_thing(private_sha1_hasher_t); - - this->public.hasher_interface.get_hash = (void (*) (hasher_t*, chunk_t, u_int8_t*))get_hash; - this->public.hasher_interface.allocate_hash = (void (*) (hasher_t*, chunk_t, chunk_t*))allocate_hash; - this->public.hasher_interface.get_hash_size = (size_t (*) (hasher_t*))get_hash_size; - this->public.hasher_interface.reset = (void (*) (hasher_t*))reset; - this->public.hasher_interface.get_state = (chunk_t (*) (hasher_t*))get_state; - this->public.hasher_interface.destroy = (void (*) (hasher_t*))destroy; - - /* initialize */ - reset(this); - - return &(this->public); -} diff --git a/src/libstrongswan/crypto/hashers/sha1_hasher.h b/src/libstrongswan/crypto/hashers/sha1_hasher.h deleted file mode 100644 index 380fa9845..000000000 --- a/src/libstrongswan/crypto/hashers/sha1_hasher.h +++ /dev/null @@ -1,60 +0,0 @@ -/** - * @file sha1_hasher.h - * - * @brief Interface of sha1_hasher_t - * - */ - -/* - * Copyright (C) 2005-2006 Martin Willi - * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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 SHA1_HASHER_H_ -#define SHA1_HASHER_H_ - -typedef struct sha1_hasher_t sha1_hasher_t; - -#include - -/** - * @brief Implementation of hasher_t interface using the - * SHA1 algorithm. - * - * @b Constructors: - * - hasher_create() using HASH_SHA1 as algorithm - * - sha1_hasher_create() - * - * @see hasher_t - * - * @ingroup hashers - */ -struct sha1_hasher_t { - - /** - * Generic hasher_t interface for this hasher. - */ - hasher_t hasher_interface; -}; - -/** - * @brief Creates a new sha1_hasher_t. - * - * @return sha1_hasher_t object - * - * @ingroup hashers - */ -sha1_hasher_t *sha1_hasher_create(void); - -#endif /*SHA1_HASHER_H_*/ diff --git a/src/libstrongswan/crypto/hashers/sha2_hasher.c b/src/libstrongswan/crypto/hashers/sha2_hasher.c deleted file mode 100644 index b68972cec..000000000 --- a/src/libstrongswan/crypto/hashers/sha2_hasher.c +++ /dev/null @@ -1,672 +0,0 @@ -/** - * @file sha2_hasher.c - * - * @brief Implementation of hasher_sha_t. - * - */ - -/* - * Copyright (C) 2006 Martin Willi - * Hochschule fuer Technik Rapperswil - * Copyright (C) 2001 Jari Ruusu. - * - * Ported from strongSwans implementation written by Jari Ruusu. - * - * 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 . - * - * 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 - -#include "sha2_hasher.h" - - -typedef struct private_sha512_hasher_t private_sha512_hasher_t; - -/** - * Private data structure with hasing context for SHA384 and SHA512 - */ -struct private_sha512_hasher_t { - /** - * Public interface for this hasher. - */ - sha2_hasher_t public; - - unsigned char sha_out[128]; /* results are here, bytes 0..47/0..63 */ - u_int64_t sha_H[8]; - u_int64_t sha_blocks; - u_int64_t sha_blocksMSB; - int sha_bufCnt; -}; - - -typedef struct private_sha256_hasher_t private_sha256_hasher_t; - -/** - * Private data structure with hasing context for SHA256 - */ -struct private_sha256_hasher_t { - /** - * Public interface for this hasher. - */ - sha2_hasher_t public; - - unsigned char sha_out[64]; /* results are here, bytes 0...31 */ - u_int32_t sha_H[8]; - u_int64_t sha_blocks; - int sha_bufCnt; -}; - - -static const u_int32_t sha256_hashInit[8] = { - 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, - 0x1f83d9ab, 0x5be0cd19 -}; - -static const u_int32_t sha256_K[64] = { - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, - 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, - 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, - 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, - 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, - 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, - 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, - 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, - 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 -}; - -static const u_int64_t sha512_hashInit[8] = { - 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, 0x3c6ef372fe94f82bULL, - 0xa54ff53a5f1d36f1ULL, 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, - 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL -}; - -static const u_int64_t sha384_hashInit[8] = { - 0xcbbb9d5dc1059ed8ULL, 0x629a292a367cd507ULL, 0x9159015a3070dd17ULL, - 0x152fecd8f70e5939ULL, 0x67332667ffc00b31ULL, 0x8eb44a8768581511ULL, - 0xdb0c2e0d64f98fa7ULL, 0x47b5481dbefa4fa4ULL -}; - -static const u_int64_t sha512_K[80] = { - 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, - 0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, - 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL, - 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, - 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, - 0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, - 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL, - 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, - 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, - 0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, - 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL, - 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, - 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, - 0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, - 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL, - 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, - 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, - 0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, - 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL, - 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, - 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, - 0xc67178f2e372532bULL, 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, - 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL, - 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, - 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, - 0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, - 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL -}; - - -/* set macros for SHA256 */ -#define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z))) -#define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) -#define R(x,y) ((y) >> (x)) - -#define S(x,y) (((y) >> (x)) | ((y) << (32 - (x)))) -#define uSig0(x) ((S(2,(x))) ^ (S(13,(x))) ^ (S(22,(x)))) -#define uSig1(x) ((S(6,(x))) ^ (S(11,(x))) ^ (S(25,(x)))) -#define lSig0(x) ((S(7,(x))) ^ (S(18,(x))) ^ (R(3,(x)))) -#define lSig1(x) ((S(17,(x))) ^ (S(19,(x))) ^ (R(10,(x)))) - -/** - * Single block SHA256 transformation - */ -static void sha256_transform(private_sha256_hasher_t *ctx, - const unsigned char *datap) -{ - register int j; - u_int32_t a, b, c, d, e, f, g, h; - u_int32_t T1, T2, W[64], Wm2, Wm15; - - /* read the data, big endian byte order */ - j = 0; - do { - W[j] = (((u_int32_t)(datap[0]))<<24) | (((u_int32_t)(datap[1]))<<16) | - (((u_int32_t)(datap[2]))<<8 ) | ((u_int32_t)(datap[3])); - datap += 4; - } while(++j < 16); - - /* initialize variables a...h */ - a = ctx->sha_H[0]; - b = ctx->sha_H[1]; - c = ctx->sha_H[2]; - d = ctx->sha_H[3]; - e = ctx->sha_H[4]; - f = ctx->sha_H[5]; - g = ctx->sha_H[6]; - h = ctx->sha_H[7]; - - /* apply compression function */ - j = 0; - do - { - if(j >= 16) - { - Wm2 = W[j - 2]; - Wm15 = W[j - 15]; - W[j] = lSig1(Wm2) + W[j - 7] + lSig0(Wm15) + W[j - 16]; - } - T1 = h + uSig1(e) + Ch(e,f,g) + sha256_K[j] + W[j]; - T2 = uSig0(a) + Maj(a,b,c); - h = g; g = f; f = e; - e = d + T1; - d = c; c = b; b = a; - a = T1 + T2; - } while(++j < 64); - - /* compute intermediate hash value */ - ctx->sha_H[0] += a; - ctx->sha_H[1] += b; - ctx->sha_H[2] += c; - ctx->sha_H[3] += d; - ctx->sha_H[4] += e; - ctx->sha_H[5] += f; - ctx->sha_H[6] += g; - ctx->sha_H[7] += h; - - ctx->sha_blocks++; -} - -/** - * Update SHA256 hash - */ -static void sha256_write(private_sha256_hasher_t *ctx, - const unsigned char *datap, int length) -{ - while(length > 0) - { - if(!ctx->sha_bufCnt) - { - while(length >= sizeof(ctx->sha_out)) - { - sha256_transform(ctx, datap); - datap += sizeof(ctx->sha_out); - length -= sizeof(ctx->sha_out); - } - if(!length) return; - } - ctx->sha_out[ctx->sha_bufCnt] = *datap++; - length--; - if(++ctx->sha_bufCnt == sizeof(ctx->sha_out)) - { - sha256_transform(ctx, &ctx->sha_out[0]); - ctx->sha_bufCnt = 0; - } - } -} - -/** - * finalize SHA256 hash - */ -static void sha256_final(private_sha256_hasher_t *ctx) -{ - register int j; - u_int64_t bitLength; - u_int32_t i; - unsigned char padByte, *datap; - - bitLength = (ctx->sha_blocks << 9) | (ctx->sha_bufCnt << 3); - padByte = 0x80; - sha256_write(ctx, &padByte, 1); - - /* pad extra space with zeroes */ - padByte = 0; - while(ctx->sha_bufCnt != 56) - { - sha256_write(ctx, &padByte, 1); - } - - /* write bit length, big endian byte order */ - ctx->sha_out[56] = bitLength >> 56; - ctx->sha_out[57] = bitLength >> 48; - ctx->sha_out[58] = bitLength >> 40; - ctx->sha_out[59] = bitLength >> 32; - ctx->sha_out[60] = bitLength >> 24; - ctx->sha_out[61] = bitLength >> 16; - ctx->sha_out[62] = bitLength >> 8; - ctx->sha_out[63] = bitLength; - sha256_transform(ctx, &ctx->sha_out[0]); - - /* return results in ctx->sha_out[0...31] */ - datap = &ctx->sha_out[0]; - j = 0; - do { - i = ctx->sha_H[j]; - datap[0] = i >> 24; - datap[1] = i >> 16; - datap[2] = i >> 8; - datap[3] = i; - datap += 4; - } while(++j < 8); -} - -/* update macros for SHA512 */ -#undef S -#undef uSig0 -#undef uSig1 -#undef lSig0 -#undef lSig1 -#define S(x,y) (((y) >> (x)) | ((y) << (64 - (x)))) -#define uSig0(x) ((S(28,(x))) ^ (S(34,(x))) ^ (S(39,(x)))) -#define uSig1(x) ((S(14,(x))) ^ (S(18,(x))) ^ (S(41,(x)))) -#define lSig0(x) ((S(1,(x))) ^ (S(8,(x))) ^ (R(7,(x)))) -#define lSig1(x) ((S(19,(x))) ^ (S(61,(x))) ^ (R(6,(x)))) - -/** - * Single block SHA384/SHA512 transformation - */ -static void sha512_transform(private_sha512_hasher_t *ctx, - const unsigned char *datap) -{ - register int j; - u_int64_t a, b, c, d, e, f, g, h; - u_int64_t T1, T2, W[80], Wm2, Wm15; - - /* read the data, big endian byte order */ - j = 0; - do { - W[j] = (((u_int64_t)(datap[0]))<<56) | (((u_int64_t)(datap[1]))<<48) | - (((u_int64_t)(datap[2]))<<40) | (((u_int64_t)(datap[3]))<<32) | - (((u_int64_t)(datap[4]))<<24) | (((u_int64_t)(datap[5]))<<16) | - (((u_int64_t)(datap[6]))<<8 ) | ((u_int64_t)(datap[7])); - datap += 8; - } while(++j < 16); - - /* initialize variables a...h */ - a = ctx->sha_H[0]; - b = ctx->sha_H[1]; - c = ctx->sha_H[2]; - d = ctx->sha_H[3]; - e = ctx->sha_H[4]; - f = ctx->sha_H[5]; - g = ctx->sha_H[6]; - h = ctx->sha_H[7]; - - /* apply compression function */ - j = 0; - do { - if(j >= 16) { - Wm2 = W[j - 2]; - Wm15 = W[j - 15]; - W[j] = lSig1(Wm2) + W[j - 7] + lSig0(Wm15) + W[j - 16]; - } - T1 = h + uSig1(e) + Ch(e,f,g) + sha512_K[j] + W[j]; - T2 = uSig0(a) + Maj(a,b,c); - h = g; g = f; f = e; - e = d + T1; - d = c; c = b; b = a; - a = T1 + T2; - } while(++j < 80); - - /* compute intermediate hash value */ - ctx->sha_H[0] += a; - ctx->sha_H[1] += b; - ctx->sha_H[2] += c; - ctx->sha_H[3] += d; - ctx->sha_H[4] += e; - ctx->sha_H[5] += f; - ctx->sha_H[6] += g; - ctx->sha_H[7] += h; - - ctx->sha_blocks++; - if(!ctx->sha_blocks) ctx->sha_blocksMSB++; -} - -/** - * Update a SHA384/SHA512 hash - */ -static void sha512_write(private_sha512_hasher_t *ctx, - const unsigned char *datap, int length) -{ - while(length > 0) - { - if(!ctx->sha_bufCnt) - { - while(length >= sizeof(ctx->sha_out)) - { - sha512_transform(ctx, datap); - datap += sizeof(ctx->sha_out); - length -= sizeof(ctx->sha_out); - } - if(!length) return; - } - ctx->sha_out[ctx->sha_bufCnt] = *datap++; - length--; - if(++ctx->sha_bufCnt == sizeof(ctx->sha_out)) - { - sha512_transform(ctx, &ctx->sha_out[0]); - ctx->sha_bufCnt = 0; - } - } -} - -/** - * Finalize a SHA384/SHA512 hash - */ -static void sha512_final(private_sha512_hasher_t *ctx) -{ - register int j; - u_int64_t bitLength, bitLengthMSB; - u_int64_t i; - unsigned char padByte, *datap; - - bitLength = (ctx->sha_blocks << 10) | (ctx->sha_bufCnt << 3); - bitLengthMSB = (ctx->sha_blocksMSB << 10) | (ctx->sha_blocks >> 54); - padByte = 0x80; - sha512_write(ctx, &padByte, 1); - - /* pad extra space with zeroes */ - padByte = 0; - while(ctx->sha_bufCnt != 112) - { - sha512_write(ctx, &padByte, 1); - } - - /* write bit length, big endian byte order */ - ctx->sha_out[112] = bitLengthMSB >> 56; - ctx->sha_out[113] = bitLengthMSB >> 48; - ctx->sha_out[114] = bitLengthMSB >> 40; - ctx->sha_out[115] = bitLengthMSB >> 32; - ctx->sha_out[116] = bitLengthMSB >> 24; - ctx->sha_out[117] = bitLengthMSB >> 16; - ctx->sha_out[118] = bitLengthMSB >> 8; - ctx->sha_out[119] = bitLengthMSB; - ctx->sha_out[120] = bitLength >> 56; - ctx->sha_out[121] = bitLength >> 48; - ctx->sha_out[122] = bitLength >> 40; - ctx->sha_out[123] = bitLength >> 32; - ctx->sha_out[124] = bitLength >> 24; - ctx->sha_out[125] = bitLength >> 16; - ctx->sha_out[126] = bitLength >> 8; - ctx->sha_out[127] = bitLength; - sha512_transform(ctx, &ctx->sha_out[0]); - - /* return results in ctx->sha_out[0...63] */ - datap = &ctx->sha_out[0]; - j = 0; - do { - i = ctx->sha_H[j]; - datap[0] = i >> 56; - datap[1] = i >> 48; - datap[2] = i >> 40; - datap[3] = i >> 32; - datap[4] = i >> 24; - datap[5] = i >> 16; - datap[6] = i >> 8; - datap[7] = i; - datap += 8; - } while(++j < 8); -} - -/** - * Implementation of hasher_t.get_hash for SHA256. - */ -static void get_hash256(private_sha256_hasher_t *this, - chunk_t chunk, u_int8_t *buffer) -{ - sha256_write(this, chunk.ptr, chunk.len); - if (buffer != NULL) - { - sha256_final(this); - memcpy(buffer, this->sha_out, HASH_SIZE_SHA256); - this->public.hasher_interface.reset(&(this->public.hasher_interface)); - } -} - -/** - * Implementation of hasher_t.get_hash for SHA384. - */ -static void get_hash384(private_sha512_hasher_t *this, - chunk_t chunk, u_int8_t *buffer) -{ - sha512_write(this, chunk.ptr, chunk.len); - if (buffer != NULL) - { - sha512_final(this); - memcpy(buffer, this->sha_out, HASH_SIZE_SHA384); - this->public.hasher_interface.reset(&(this->public.hasher_interface)); - } -} - -/** - * Implementation of hasher_t.get_hash for SHA512. - */ -static void get_hash512(private_sha512_hasher_t *this, - chunk_t chunk, u_int8_t *buffer) -{ - sha512_write(this, chunk.ptr, chunk.len); - if (buffer != NULL) - { - sha512_final(this); - memcpy(buffer, this->sha_out, HASH_SIZE_SHA512); - this->public.hasher_interface.reset(&(this->public.hasher_interface)); - } -} - -/** - * Implementation of hasher_t.allocate_hash for SHA256. - */ -static void allocate_hash256(private_sha256_hasher_t *this, - chunk_t chunk, chunk_t *hash) -{ - chunk_t allocated_hash; - - sha256_write(this, chunk.ptr, chunk.len); - if (hash != NULL) - { - sha256_final(this); - allocated_hash = chunk_alloc(HASH_SIZE_SHA256); - memcpy(allocated_hash.ptr, this->sha_out, HASH_SIZE_SHA256); - this->public.hasher_interface.reset(&(this->public.hasher_interface)); - *hash = allocated_hash; - } -} - -/** - * Implementation of hasher_t.allocate_hash for SHA384. - */ -static void allocate_hash384(private_sha512_hasher_t *this, - chunk_t chunk, chunk_t *hash) -{ - chunk_t allocated_hash; - - sha512_write(this, chunk.ptr, chunk.len); - if (hash != NULL) - { - sha512_final(this); - allocated_hash = chunk_alloc(HASH_SIZE_SHA384); - memcpy(allocated_hash.ptr, this->sha_out, HASH_SIZE_SHA384); - this->public.hasher_interface.reset(&(this->public.hasher_interface)); - *hash = allocated_hash; - } -} - -/** - * Implementation of hasher_t.allocate_hash for SHA512. - */ -static void allocate_hash512(private_sha512_hasher_t *this, - chunk_t chunk, chunk_t *hash) -{ - chunk_t allocated_hash; - - sha512_write(this, chunk.ptr, chunk.len); - if (hash != NULL) - { - sha512_final(this); - allocated_hash = chunk_alloc(HASH_SIZE_SHA512); - memcpy(allocated_hash.ptr, this->sha_out, HASH_SIZE_SHA512); - this->public.hasher_interface.reset(&(this->public.hasher_interface)); - *hash = allocated_hash; - } -} - -/** - * Implementation of hasher_t.get_hash_size for SHA256. - */ -static size_t get_hash_size256(private_sha256_hasher_t *this) -{ - return HASH_SIZE_SHA256; -} - -/** - * Implementation of hasher_t.get_hash_size for SHA384. - */ -static size_t get_hash_size384(private_sha512_hasher_t *this) -{ - return HASH_SIZE_SHA384; -} - -/** - * Implementation of hasher_t.get_hash_size for SHA512. - */ -static size_t get_hash_size512(private_sha512_hasher_t *this) -{ - return HASH_SIZE_SHA512; -} - -/** - * Implementation of hasher_t.reset for SHA256 - */ -static void reset256(private_sha256_hasher_t *ctx) -{ - memcpy(&ctx->sha_H[0], &sha256_hashInit[0], sizeof(ctx->sha_H)); - ctx->sha_blocks = 0; - ctx->sha_bufCnt = 0; -} - -/** - * Implementation of hasher_t.reset for SHA384 - */ -static void reset384(private_sha512_hasher_t *ctx) -{ - memcpy(&ctx->sha_H[0], &sha384_hashInit[0], sizeof(ctx->sha_H)); - ctx->sha_blocks = 0; - ctx->sha_blocksMSB = 0; - ctx->sha_bufCnt = 0; -} - -/** - * Implementation of hasher_t.reset for SHA512 - */ -static void reset512(private_sha512_hasher_t *ctx) -{ - memcpy(&ctx->sha_H[0], &sha512_hashInit[0], sizeof(ctx->sha_H)); - ctx->sha_blocks = 0; - ctx->sha_blocksMSB = 0; - ctx->sha_bufCnt = 0; -} - -/** - * Implementation of hasher_t.get_state for SHA256 - */ -static chunk_t get_state256(private_sha256_hasher_t *ctx) -{ - chunk_t chunk; - chunk.ptr = (u_char*)&ctx->sha_H[0]; - chunk.len = HASH_SIZE_SHA256; - return chunk; -} - -/** - * Implementation of hasher_t.get_state for SHA384 - */ -static chunk_t get_state384(private_sha512_hasher_t *ctx) -{ - chunk_t chunk; - chunk.ptr = (u_char*)&ctx->sha_H[0]; - chunk.len = HASH_SIZE_SHA384; - return chunk; -} -/** - * Implementation of hasher_t.get_state for SHA512 - */ -static chunk_t get_state512(private_sha512_hasher_t *ctx) -{ - chunk_t chunk; - chunk.ptr = (u_char*)&ctx->sha_H[0]; - chunk.len = HASH_SIZE_SHA512; - return chunk; -} - -/** - * Implementation of hasher_t.destroy. - */ -static void destroy(sha2_hasher_t *this) -{ - free(this); -} - -/* - * Described in header. - */ -sha2_hasher_t *sha2_hasher_create(hash_algorithm_t algorithm) -{ - sha2_hasher_t *this; - - switch (algorithm) - { - case HASH_SHA256: - this = (sha2_hasher_t*)malloc_thing(private_sha256_hasher_t); - this->hasher_interface.reset = (void(*)(hasher_t*))reset256; - this->hasher_interface.get_state = (chunk_t(*)(hasher_t*))get_state256; - this->hasher_interface.get_hash_size = (size_t(*)(hasher_t*))get_hash_size256; - this->hasher_interface.get_hash = (void(*)(hasher_t*,chunk_t,u_int8_t*))get_hash256; - this->hasher_interface.allocate_hash = (void(*)(hasher_t*,chunk_t,chunk_t*))allocate_hash256; - break; - case HASH_SHA384: - /* uses SHA512 data structure */ - this = (sha2_hasher_t*)malloc_thing(private_sha512_hasher_t); - this->hasher_interface.reset = (void(*)(hasher_t*))reset384; - this->hasher_interface.get_state = (chunk_t(*)(hasher_t*))get_state384; - this->hasher_interface.get_hash_size = (size_t(*)(hasher_t*))get_hash_size384; - this->hasher_interface.get_hash = (void(*)(hasher_t*,chunk_t,u_int8_t*))get_hash384; - this->hasher_interface.allocate_hash = (void(*)(hasher_t*,chunk_t,chunk_t*))allocate_hash384; - break; - case HASH_SHA512: - this = (sha2_hasher_t*)malloc_thing(private_sha512_hasher_t); - this->hasher_interface.reset = (void(*)(hasher_t*))reset512; - this->hasher_interface.get_state = (chunk_t(*)(hasher_t*))get_state512; - this->hasher_interface.get_hash_size = (size_t(*)(hasher_t*))get_hash_size512; - this->hasher_interface.get_hash = (void(*)(hasher_t*,chunk_t,u_int8_t*))get_hash512; - this->hasher_interface.allocate_hash = (void(*)(hasher_t*,chunk_t,chunk_t*))allocate_hash512; - break; - default: - return NULL; - } - this->hasher_interface.destroy = (void(*)(hasher_t*))destroy; - - /* initialize */ - this->hasher_interface.reset(&this->hasher_interface); - - return this; -} diff --git a/src/libstrongswan/crypto/hashers/sha2_hasher.h b/src/libstrongswan/crypto/hashers/sha2_hasher.h deleted file mode 100644 index 91e82fedb..000000000 --- a/src/libstrongswan/crypto/hashers/sha2_hasher.h +++ /dev/null @@ -1,62 +0,0 @@ -/** - * @file sha2_hasher.h - * - * @brief Interface of sha2_hasher_t - * - */ - -/* - * Copyright (C) 2006 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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 SHA2_HASHER_H_ -#define SHA2_HASHER_H_ - -typedef struct sha2_hasher_t sha2_hasher_t; - -#include - -/** - * @brief Implementation of hasher_t interface using the SHA2 algorithms. - * - * SHA2 is an other name for the SHA-256, SHA-384 and SHA-512 variants of - * the SHA hash algorithm. - * - * @b Constructors: - * - hasher_create() using HASH_SHA256, HASH_SHA384 or HASH_SHA512 as algorithm - * - sha2_hasher_create() - * - * @see hasher_t - * - * @ingroup hashers - */ -struct sha2_hasher_t { - - /** - * Generic hasher_t interface for this hasher. - */ - hasher_t hasher_interface; -}; - -/** - * @brief Creates a new sha2_hasher_t. - * - * @param algorithm HASH_SHA256, HASH_SHA384 or HASH_SHA512 - * @return sha2_hasher_t object - * - * @ingroup hashers - */ -sha2_hasher_t *sha2_hasher_create(hash_algorithm_t algorithm); - -#endif /* SHA2_HASHER_H_ */ diff --git a/src/libstrongswan/crypto/hmac.c b/src/libstrongswan/crypto/hmac.c deleted file mode 100644 index df4f90bc8..000000000 --- a/src/libstrongswan/crypto/hmac.c +++ /dev/null @@ -1,215 +0,0 @@ -/** - * @file hmac.c - * - * @brief Implementation of hmac_t. - */ - -/* - * Copyright (C) 2005-2006 Martin Willi - * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General hmac License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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 hmac License - * for more details. - */ - -#include - -#include "hmac.h" - - -typedef struct private_hmac_t private_hmac_t; - -/** - * Private data of a hmac_t object. - * - * The variable names are the same as in the RFC. - */ -struct private_hmac_t { - /** - * Public hmac_t interface. - */ - hmac_t hmac; - - /** - * Block size, as in RFC. - */ - u_int8_t b; - - /** - * Hash function. - */ - hasher_t *h; - - /** - * Previously xor'ed key using opad. - */ - chunk_t opaded_key; - - /** - * Previously xor'ed key using ipad. - */ - chunk_t ipaded_key; -}; - -/** - * Implementation of hmac_t.get_mac. - */ -static void get_mac(private_hmac_t *this, chunk_t data, u_int8_t *out) -{ - /* H(K XOR opad, H(K XOR ipad, text)) - * - * if out is NULL, we append text to the inner hash. - * else, we complete the inner and do the outer. - * - */ - - u_int8_t buffer[this->h->get_hash_size(this->h)]; - chunk_t inner; - - if (out == NULL) - { - /* append data to inner */ - this->h->get_hash(this->h, data, NULL); - } - else - { - /* append and do outer hash */ - inner.ptr = buffer; - inner.len = this->h->get_hash_size(this->h); - - /* complete inner */ - this->h->get_hash(this->h, data, buffer); - - /* do outer */ - this->h->get_hash(this->h, this->opaded_key, NULL); - this->h->get_hash(this->h, inner, out); - - /* reinit for next call */ - this->h->get_hash(this->h, this->ipaded_key, NULL); - } -} - -/** - * Implementation of hmac_t.allocate_mac. - */ -static void allocate_mac(private_hmac_t *this, chunk_t data, chunk_t *out) -{ - /* allocate space and use get_mac */ - if (out == NULL) - { - /* append mode */ - this->hmac.get_mac(&(this->hmac), data, NULL); - } - else - { - out->len = this->h->get_hash_size(this->h); - out->ptr = malloc(out->len); - this->hmac.get_mac(&(this->hmac), data, out->ptr); - } -} - -/** - * Implementation of hmac_t.get_block_size. - */ -static size_t get_block_size(private_hmac_t *this) -{ - return this->h->get_hash_size(this->h); -} - -/** - * Implementation of hmac_t.set_key. - */ -static void set_key(private_hmac_t *this, chunk_t key) -{ - int i; - u_int8_t buffer[this->b]; - - memset(buffer, 0, this->b); - - if (key.len > this->b) - { - /* if key is too long, it will be hashed */ - this->h->get_hash(this->h, key, buffer); - } - else - { - /* if not, just copy it in our pre-padded k */ - memcpy(buffer, key.ptr, key.len); - } - - /* apply ipad and opad to key */ - for (i = 0; i < this->b; i++) - { - this->ipaded_key.ptr[i] = buffer[i] ^ 0x36; - this->opaded_key.ptr[i] = buffer[i] ^ 0x5C; - } - - /* begin hashing of inner pad */ - this->h->reset(this->h); - this->h->get_hash(this->h, this->ipaded_key, NULL); -} - -/** - * Implementation of hmac_t.destroy. - */ -static void destroy(private_hmac_t *this) -{ - this->h->destroy(this->h); - free(this->opaded_key.ptr); - free(this->ipaded_key.ptr); - free(this); -} - -/* - * Described in header - */ -hmac_t *hmac_create(hash_algorithm_t hash_algorithm) -{ - private_hmac_t *this; - - this = malloc_thing(private_hmac_t); - - /* set hmac_t methods */ - this->hmac.get_mac = (void (*)(hmac_t *,chunk_t,u_int8_t*))get_mac; - this->hmac.allocate_mac = (void (*)(hmac_t *,chunk_t,chunk_t*))allocate_mac; - this->hmac.get_block_size = (size_t (*)(hmac_t *))get_block_size; - this->hmac.set_key = (void (*)(hmac_t *,chunk_t))set_key; - this->hmac.destroy = (void (*)(hmac_t *))destroy; - - /* set b, according to hasher */ - switch (hash_algorithm) - { - case HASH_SHA1: - case HASH_MD5: - case HASH_SHA256: - this->b = 64; - break; - case HASH_SHA384: - case HASH_SHA512: - this->b = 128; - break; - default: - free(this); - return NULL; - } - - /* build the hasher */ - this->h = hasher_create(hash_algorithm); - - /* build ipad and opad */ - this->opaded_key.ptr = malloc(this->b); - this->opaded_key.len = this->b; - - this->ipaded_key.ptr = malloc(this->b); - this->ipaded_key.len = this->b; - - return &(this->hmac); -} diff --git a/src/libstrongswan/crypto/hmac.h b/src/libstrongswan/crypto/hmac.h deleted file mode 100644 index 06b75aaf9..000000000 --- a/src/libstrongswan/crypto/hmac.h +++ /dev/null @@ -1,117 +0,0 @@ -/** - * @file hmac.h - * - * @brief Interface of hmac_t. - */ - -/* - * Copyright (C) 2005-2006 Martin Willi - * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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 HMAC_H_ -#define HMAC_H_ - -typedef struct hmac_t hmac_t; - -#include - -/** - * @brief Message authentication using hash functions. - * - * This class implements the message authenticaion algorithm - * described in RFC2104. It uses a hash function, wich must - * be implemented as a hasher_t class. - * - * See http://www.faqs.org/rfcs/rfc2104.html for RFC. - * @see - * - hasher_t - * - prf_hmac_t - * - * @b Constructors: - * - hmac_create() - * - * @ingroup crypto - */ -struct hmac_t { - /** - * @brief Generate message authentication code. - * - * If buffer is NULL, no result is given back. A next call will - * append the data to already supplied data. If buffer is not NULL, - * the mac of all apended data is calculated, returned and the - * state of the hmac_t is reseted. - * - * @param this calling object - * @param data chunk of data to authenticate - * @param[out] buffer pointer where the generated bytes will be written - */ - void (*get_mac) (hmac_t *this, chunk_t data, u_int8_t *buffer); - - /** - * @brief Generates message authentication code and - * allocate space for them. - * - * If chunk is NULL, no result is given back. A next call will - * append the data to already supplied. If chunk is not NULL, - * the mac of all apended data is calculated, returned and the - * state of the hmac_t reset; - * - * @param this calling object - * @param data chunk of data to authenticate - * @param[out] chunk chunk which will hold generated bytes - */ - void (*allocate_mac) (hmac_t *this, chunk_t data, chunk_t *chunk); - - /** - * @brief Get the block size of this hmac_t object. - * - * @param this calling object - * @return block size in bytes - */ - size_t (*get_block_size) (hmac_t *this); - - /** - * @brief Set the key for this hmac_t object. - * - * Any key length is accepted. - * - * @param this calling object - * @param key key to set - */ - void (*set_key) (hmac_t *this, chunk_t key); - - /** - * @brief Destroys a hmac_t object. - * - * @param this calling object - */ - void (*destroy) (hmac_t *this); -}; - -/** - * @brief Creates a new hmac_t object. - * - * Creates a hasher_t object internally. - * - * @param hash_algorithm hash algorithm to use - * @return - * - hmac_t object - * - NULL if hash algorithm is not supported - * - * @ingroup transforms - */ -hmac_t *hmac_create(hash_algorithm_t hash_algorithm); - -#endif /*HMAC_H_*/ diff --git a/src/libstrongswan/crypto/ietf_attr_list.c b/src/libstrongswan/crypto/ietf_attr_list.c deleted file mode 100644 index 1ecadf679..000000000 --- a/src/libstrongswan/crypto/ietf_attr_list.c +++ /dev/null @@ -1,405 +0,0 @@ -/** - * @file ietf_attr.c - * - * @brief Implementation of ietfAttr_t. - * - */ - -/* - * Copyright (C) 2007 Andreas Steffen, 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 . - * - * 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 -#include - -#include -#include -#include - -#include "ietf_attr_list.h" - -/** - * Private definition of ietfAttribute kinds - */ -typedef enum { - IETF_ATTRIBUTE_OCTETS = 0, - IETF_ATTRIBUTE_OID = 1, - IETF_ATTRIBUTE_STRING = 2 -} ietfAttribute_t; - -typedef struct ietfAttr_t ietfAttr_t; - -/** - * Private definition of an ietfAttribute - */ -struct ietfAttr_t { - /** - * IETF attribute kind - */ - ietfAttribute_t kind; - - /** - * IETF attribute valuse - */ - chunk_t value; - - /** - * Compares two ietfAttributes - * - * return -1 if this is earlier in the alphabet than other - * return 0 if this equals other - * return +1 if this is later in the alphabet than other - * - * @param this calling object - * @param other other object - */ - int (*compare) (const ietfAttr_t *this ,const ietfAttr_t *other); - - /** - * Destroys the ietfAttr_t object. - * - * @param this ietfAttr_t to destroy - */ - void (*destroy) (ietfAttr_t *this); -}; - -/** - * Implements ietfAttr_t.compare. - */ -static int ietfAttr_compare(const ietfAttr_t *this ,const ietfAttr_t *other) -{ - int cmp_len, len, cmp_value; - - /* OID attributes are appended after STRING and OCTETS attributes */ - if (this->kind != IETF_ATTRIBUTE_OID && other->kind == IETF_ATTRIBUTE_OID) - { - return -1; - } - if (this->kind == IETF_ATTRIBUTE_OID && other->kind != IETF_ATTRIBUTE_OID) - { - return 1; - } - - cmp_len = this->value.len - other->value.len; - len = (cmp_len < 0)? this->value.len : other->value.len; - cmp_value = memcmp(this->value.ptr, other->value.ptr, len); - - return (cmp_value == 0)? cmp_len : cmp_value; -} - -/** - * Implements ietfAttr_t.destroy. - */ -static void ietfAttr_destroy(ietfAttr_t *this) -{ - free(this->value.ptr); - free(this); -} - -/** - * Creates an ietfAttr_t object. - */ -static ietfAttr_t *ietfAttr_create(ietfAttribute_t kind, chunk_t value) -{ - ietfAttr_t *this = malloc_thing(ietfAttr_t); - - /* initialize */ - this->kind = kind; - this->value = chunk_clone(value); - - /* function */ - this->compare = ietfAttr_compare; - this->destroy = ietfAttr_destroy; - - return this; -} - -/** - * Adds an ietfAttr_t object to a sorted linked list - */ -static void ietfAttr_add(linked_list_t *list, ietfAttr_t *attr) -{ - iterator_t *iterator = list->create_iterator(list, TRUE); - ietfAttr_t *current_attr; - bool found = FALSE; - - while (iterator->iterate(iterator, (void **)¤t_attr)) - { - int cmp = attr->compare(attr, current_attr); - - if (cmp > 0) - { - continue; - } - if (cmp == 0) - { - attr->destroy(attr); - } - else - { - iterator->insert_before(iterator, attr); - } - found = TRUE; - break; - } - iterator->destroy(iterator); - if (!found) - { - list->insert_last(list, attr); - } -} - -/* - * Described in header. - */ -bool ietfAttr_list_equals(linked_list_t *list_a, linked_list_t *list_b) -{ - bool result = TRUE; - - /* lists must have the same number of attributes */ - if (list_a->get_count(list_a) != list_b->get_count(list_b)) - { - return FALSE; - } - /* empty lists - no attributes */ - if (list_a->get_count(list_a) == 0) - { - return TRUE; - } - - /* compare two alphabetically-sorted lists */ - { - iterator_t *iterator_a = list_a->create_iterator(list_a, TRUE); - iterator_t *iterator_b = list_b->create_iterator(list_b, TRUE); - ietfAttr_t *attr_a, *attr_b; - - while (iterator_a->iterate(iterator_a, (void **)&attr_a) && - iterator_b->iterate(iterator_b, (void **)&attr_b)) - { - if (attr_a->compare(attr_a, attr_b) != 0) - { - /* we have a mismatch */ - result = FALSE; - break; - } - } - iterator_a->destroy(iterator_a); - iterator_b->destroy(iterator_b); - } - return result; -} - -/* - * Described in header. - */ -void ietfAttr_list_list(linked_list_t *list, FILE *out) -{ - iterator_t *iterator = list->create_iterator(list, TRUE); - ietfAttr_t *attr; - bool first = TRUE; - - while (iterator->iterate(iterator, (void **)&attr)) - { - if (first) - { - first = FALSE; - } - else - { - fprintf(out, ", "); - } - - switch (attr->kind) - { - case IETF_ATTRIBUTE_OCTETS: - case IETF_ATTRIBUTE_STRING: - fprintf(out, "%.*s", (int)attr->value.len, attr->value.ptr); - break; - case IETF_ATTRIBUTE_OID: - { - int oid = known_oid(attr->value); - - if (oid == OID_UNKNOWN) - { - fprintf(out, "0x#B", &attr->value); - } - else - { - fprintf(out, "%s", oid_names[oid]); - } - } - break; - default: - break; - } - } - iterator->destroy(iterator); -} - -/* - * Described in header. - */ -void ietfAttr_list_create_from_string(char *msg, linked_list_t *list) -{ - chunk_t line = { msg, strlen(msg) }; - - while (eat_whitespace(&line)) - { - chunk_t group; - - /* extract the next comma-separated group attribute */ - if (!extract_token(&group, ',', &line)) - { - group = line; - line.len = 0; - } - - /* remove any trailing spaces */ - while (group.len > 0 && *(group.ptr + group.len - 1) == ' ') - { - group.len--; - } - - /* add the group attribute to the list */ - if (group.len > 0) - { - ietfAttr_t *attr = ietfAttr_create(IETF_ATTRIBUTE_STRING, group); - - ietfAttr_add(list, attr); - } - } -} - -/** - * ASN.1 definition of ietfAttrSyntax - */ -static const asn1Object_t ietfAttrSyntaxObjects[] = -{ - { 0, "ietfAttrSyntax", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ - { 1, "policyAuthority", ASN1_CONTEXT_C_0, ASN1_OPT | - ASN1_BODY }, /* 1 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 2 */ - { 1, "values", ASN1_SEQUENCE, ASN1_LOOP }, /* 3 */ - { 2, "octets", ASN1_OCTET_STRING, ASN1_OPT | - ASN1_BODY }, /* 4 */ - { 2, "end choice", ASN1_EOC, ASN1_END }, /* 5 */ - { 2, "oid", ASN1_OID, ASN1_OPT | - ASN1_BODY }, /* 6 */ - { 2, "end choice", ASN1_EOC, ASN1_END }, /* 7 */ - { 2, "string", ASN1_UTF8STRING, ASN1_OPT | - ASN1_BODY }, /* 8 */ - { 2, "end choice", ASN1_EOC, ASN1_END }, /* 9 */ - { 1, "end loop", ASN1_EOC, ASN1_END } /* 10 */ -}; - -#define IETF_ATTR_OCTETS 4 -#define IETF_ATTR_OID 6 -#define IETF_ATTR_STRING 8 -#define IETF_ATTR_ROOF 11 - -/* - * Described in header. - */ -void ietfAttr_list_create_from_chunk(chunk_t chunk, linked_list_t *list, int level0) -{ - asn1_ctx_t ctx; - chunk_t object; - u_int level; - int objectID = 0; - - asn1_init(&ctx, chunk, level0, FALSE, FALSE); - - while (objectID < IETF_ATTR_ROOF) - { - if (!extract_object(ietfAttrSyntaxObjects, &objectID, &object, &level, &ctx)) - { - return; - } - - switch (objectID) - { - case IETF_ATTR_OCTETS: - case IETF_ATTR_OID: - case IETF_ATTR_STRING: - { - ietfAttribute_t kind = (objectID - IETF_ATTR_OCTETS) / 2; - ietfAttr_t *attr = ietfAttr_create(kind, object); - ietfAttr_add(list, attr); - } - break; - default: - break; - } - objectID++; - } -} - -/* - * Described in header. - */ -chunk_t ietfAttr_list_encode(linked_list_t *list) -{ - chunk_t ietfAttributes; - size_t size = 0; - u_char *pos; - iterator_t *iterator = list->create_iterator(list, TRUE); - ietfAttr_t *attr; - - /* precalculate the total size of all values */ - while (iterator->iterate(iterator, (void **)&attr)) - { - size_t len = attr->value.len; - - size += 1 + (len > 0) + (len >= 128) + (len >= 256) + (len >= 65536) + len; - } - iterator->destroy(iterator); - - pos = build_asn1_object(&ietfAttributes, ASN1_SEQUENCE, size); - - iterator = list->create_iterator(list, TRUE); - while (iterator->iterate(iterator, (void **)&attr)) - { - chunk_t ietfAttribute; - asn1_t type = ASN1_NULL; - - switch (attr->kind) - { - case IETF_ATTRIBUTE_OCTETS: - type = ASN1_OCTET_STRING; - break; - case IETF_ATTRIBUTE_STRING: - type = ASN1_UTF8STRING; - break; - case IETF_ATTRIBUTE_OID: - type = ASN1_OID; - break; - } - ietfAttribute = asn1_simple_object(type, attr->value); - - /* copy ietfAttribute into ietfAttributes chunk */ - memcpy(pos, ietfAttribute.ptr, ietfAttribute.len); - pos += ietfAttribute.len; - free(ietfAttribute.ptr); - } - iterator->destroy(iterator); - - return asn1_wrap(ASN1_SEQUENCE, "m", ietfAttributes); -} - -/* - * Described in header. - */ -void ietfAttr_list_destroy(linked_list_t *list) -{ - list->destroy_offset(list, offsetof(ietfAttr_t, destroy)); -} diff --git a/src/libstrongswan/crypto/ietf_attr_list.h b/src/libstrongswan/crypto/ietf_attr_list.h deleted file mode 100644 index 75407bbf6..000000000 --- a/src/libstrongswan/crypto/ietf_attr_list.h +++ /dev/null @@ -1,89 +0,0 @@ -/** - * @file ietf_attr_list.h - * - * @brief Handling of ietfAttr_t linked lists - * - */ - -/* - * Copyright (C) 2007 Andreas Steffen - * - * 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 . - * - * 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 IETF_ATTR_LIST_H_ -#define IETF_ATTR_LIST_H_ - -#include -#include - - -/** - * @brief Compare two linked lists of ietfAttr_t objects for equality - * - * @param list_a first alphabetically-sorted list - * @param list_b second alphabetically-sorted list - * @return TRUE if equal - * - * @ingroup crypto - */ -bool ietfAttr_list_equals(linked_list_t *list_a, linked_list_t *list_b); - -/** - * @brief Lists a linked list of ietfAttr_t objects - * - * @param list alphabetically-sorted linked list of attributes - @param out output file - * - * @ingroup crypto - */ -void ietfAttr_list_list(linked_list_t *list, FILE *out); - -/** - * @brief Create a linked list of ietfAttr_t objects from a string - * - * @param msg string with comma-separated group names - * @param list alphabetically-sorted linked list of attributes - * - * @ingroup crypto - */ -void ietfAttr_list_create_from_string(char *msg, linked_list_t *list); - -/** - * @brief Create a linked list of ietfAttr_t objects from an ASN.1-coded chunk - * - * @param chunk chunk containing ASN.1-coded attributes - * @param list alphabetically-sorted linked list of attributes - * @param level0 parsing level - */ -void ietfAttr_list_create_from_chunk(chunk_t chunk, linked_list_t *list, int level0); - -/** - * @brief Encode a linked list of ietfAttr_t objects into an ASN.1-coded chunk - * - * @param list alphabetically-sorted linked list of attributes - * @return chunk containing ASN.1-coded attributes - */ -chunk_t ietfAttr_list_encode(linked_list_t *list); - -/** - * @brief Destroys a linked list of ietfAttr_t objects - * - * @param list list to be destroyed - * - * @ingroup crypto - */ -void ietfAttr_list_destroy(linked_list_t *list); - -#endif /* IETF_ATTR_LIST_H_ */ - diff --git a/src/libstrongswan/crypto/ocsp.c b/src/libstrongswan/crypto/ocsp.c deleted file mode 100644 index 4bbec31de..000000000 --- a/src/libstrongswan/crypto/ocsp.c +++ /dev/null @@ -1,934 +0,0 @@ -/** - * @file ocsp.c - * - * @brief Implementation of ocsp_t. - * - */ - -/* Support of the Online Certificate Status Protocol (OCSP) - * - * Copyright (C) 2003 Christoph Gysin, Simon Zwahlen - * Copyright (C) 2007 Andreas Steffen - * - * Hochschule für 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 . - * - * 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. - * - * RCSID $Id$ - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "hashers/hasher.h" -#include "rsa/rsa_public_key.h" -#include "certinfo.h" -#include "x509.h" -#include "ocsp.h" - -#define NONCE_LENGTH 16 - -typedef struct private_ocsp_t private_ocsp_t; - -/** - * Private data of a ocsp_t object. - */ -struct private_ocsp_t { - /** - * Public interface for this ocsp object. - */ - ocsp_t public; - - /** - * CA certificate. - */ - x509_t *cacert; - - /** - * Requestor certificate - */ - x509_t *requestor_cert; - - /** - * Linked list of ocsp uris - */ - linked_list_t *uris; - - /** - * Linked list of certinfos to be requested - */ - linked_list_t *certinfos; - - /** - * Nonce required for ocsp request and response - */ - chunk_t nonce; - - /** - * SHA-1 hash over issuer distinguished name - */ - chunk_t authNameID; - - /** - * SHA-1 hash over issuer public key - */ - chunk_t authKeyID; -}; - -ENUM(response_status_names, STATUS_SUCCESSFUL, STATUS_UNAUTHORIZED, - "successful", - "malformed request", - "internal error", - "try later", - "signature required", - "unauthorized" -); - -/* response container */ -typedef struct response_t response_t; - -struct response_t { - chunk_t chunk; - chunk_t tbs; - identification_t *responder_id_name; - chunk_t responder_id_key; - time_t produced_at; - chunk_t responses; - chunk_t nonce; - int algorithm; - chunk_t signature; - x509_t *responder_cert; - - /** - * @brief Destroys the response_t object - * - * @param this response_t to destroy - */ - void (*destroy) (response_t *this); -}; - -/** - * Implements response_t.destroy. - */ -static void response_destroy(response_t *this) -{ - DESTROY_IF(this->responder_id_name); - DESTROY_IF(this->responder_cert); - free(this->chunk.ptr); - free(this); -} - -/** - * Creates a response_t object - */ -static response_t* response_create_from_chunk(chunk_t chunk) -{ - response_t *this = malloc_thing(response_t); - - this->chunk = chunk; - this->tbs = chunk_empty; - this->responder_id_name = NULL; - this->responder_id_key = chunk_empty; - this->produced_at = UNDEFINED_TIME; - this->responses = chunk_empty; - this->nonce = chunk_empty; - this->algorithm = OID_UNKNOWN; - this->signature = chunk_empty; - this->responder_cert = NULL; - - this->destroy = (void (*) (response_t*))response_destroy; - - return this; -} - -/* some OCSP specific prefabricated ASN.1 constants */ - -static u_char ASN1_nonce_oid_str[] = { - 0x06, 0x09, - 0x2B, 0x06, - 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x02 -}; - -static u_char ASN1_response_oid_str[] = { - 0x06, 0x09, - 0x2B, 0x06, - 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x04 -}; - -static u_char ASN1_response_content_str[] = { - 0x04, 0x0D, - 0x30, 0x0B, - 0x06, 0x09, - 0x2B, 0x06, - 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x01 -}; - -static const chunk_t ASN1_nonce_oid = chunk_from_buf(ASN1_nonce_oid_str); -static const chunk_t ASN1_response_oid = chunk_from_buf(ASN1_response_oid_str); -static const chunk_t ASN1_response_content = chunk_from_buf(ASN1_response_content_str); - -/* asn.1 definitions for parsing */ - -static const asn1Object_t ocspResponseObjects[] = { - { 0, "OCSPResponse", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ - { 1, "responseStatus", ASN1_ENUMERATED, ASN1_BODY }, /* 1 */ - { 1, "responseBytesContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 2 */ - { 2, "responseBytes", ASN1_SEQUENCE, ASN1_NONE }, /* 3 */ - { 3, "responseType", ASN1_OID, ASN1_BODY }, /* 4 */ - { 3, "response", ASN1_OCTET_STRING, ASN1_BODY }, /* 5 */ - { 1, "end opt", ASN1_EOC, ASN1_END } /* 6 */ -}; - -#define OCSP_RESPONSE_STATUS 1 -#define OCSP_RESPONSE_TYPE 4 -#define OCSP_RESPONSE 5 -#define OCSP_RESPONSE_ROOF 7 - -static const asn1Object_t basicResponseObjects[] = { - { 0, "BasicOCSPResponse", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ - { 1, "tbsResponseData", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */ - { 2, "versionContext", ASN1_CONTEXT_C_0, ASN1_NONE | - ASN1_DEF }, /* 2 */ - { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 3 */ - { 2, "responderIdContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 4 */ - { 3, "responderIdByName", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */ - { 2, "end choice", ASN1_EOC, ASN1_END }, /* 6 */ - { 2, "responderIdContext", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 7 */ - { 3, "responderIdByKey", ASN1_OCTET_STRING, ASN1_BODY }, /* 8 */ - { 2, "end choice", ASN1_EOC, ASN1_END }, /* 9 */ - { 2, "producedAt", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 10 */ - { 2, "responses", ASN1_SEQUENCE, ASN1_OBJ }, /* 11 */ - { 2, "responseExtensionsContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 12 */ - { 3, "responseExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 13 */ - { 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 14 */ - { 5, "extnID", ASN1_OID, ASN1_BODY }, /* 15 */ - { 5, "critical", ASN1_BOOLEAN, ASN1_BODY | - ASN1_DEF }, /* 16 */ - { 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 17 */ - { 4, "end loop", ASN1_EOC, ASN1_END }, /* 18 */ - { 2, "end opt", ASN1_EOC, ASN1_END }, /* 19 */ - { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 20 */ - { 1, "signature", ASN1_BIT_STRING, ASN1_BODY }, /* 21 */ - { 1, "certsContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 22 */ - { 2, "certs", ASN1_SEQUENCE, ASN1_LOOP }, /* 23 */ - { 3, "certificate", ASN1_SEQUENCE, ASN1_RAW }, /* 24 */ - { 2, "end loop", ASN1_EOC, ASN1_END }, /* 25 */ - { 1, "end opt", ASN1_EOC, ASN1_END } /* 26 */ -}; - -#define BASIC_RESPONSE_TBS_DATA 1 -#define BASIC_RESPONSE_VERSION 3 -#define BASIC_RESPONSE_ID_BY_NAME 5 -#define BASIC_RESPONSE_ID_BY_KEY 8 -#define BASIC_RESPONSE_PRODUCED_AT 10 -#define BASIC_RESPONSE_RESPONSES 11 -#define BASIC_RESPONSE_EXT_ID 15 -#define BASIC_RESPONSE_CRITICAL 16 -#define BASIC_RESPONSE_EXT_VALUE 17 -#define BASIC_RESPONSE_ALGORITHM 20 -#define BASIC_RESPONSE_SIGNATURE 21 -#define BASIC_RESPONSE_CERTIFICATE 24 -#define BASIC_RESPONSE_ROOF 27 - -static const asn1Object_t responsesObjects[] = { - { 0, "responses", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ - { 1, "singleResponse", ASN1_EOC, ASN1_RAW }, /* 1 */ - { 0, "end loop", ASN1_EOC, ASN1_END } /* 2 */ -}; - -#define RESPONSES_SINGLE_RESPONSE 1 -#define RESPONSES_ROOF 3 - -static const asn1Object_t singleResponseObjects[] = { - { 0, "singleResponse", ASN1_SEQUENCE, ASN1_BODY }, /* 0 */ - { 1, "certID", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */ - { 2, "algorithm", ASN1_EOC, ASN1_RAW }, /* 2 */ - { 2, "issuerNameHash", ASN1_OCTET_STRING, ASN1_BODY }, /* 3 */ - { 2, "issuerKeyHash", ASN1_OCTET_STRING, ASN1_BODY }, /* 4 */ - { 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 5 */ - { 1, "certStatusGood", ASN1_CONTEXT_S_0, ASN1_OPT }, /* 6 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 7 */ - { 1, "certStatusRevoked", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 8 */ - { 2, "revocationTime", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 9 */ - { 2, "revocationReason", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 10 */ - { 3, "crlReason", ASN1_ENUMERATED, ASN1_BODY }, /* 11 */ - { 2, "end opt", ASN1_EOC, ASN1_END }, /* 12 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 13 */ - { 1, "certStatusUnknown", ASN1_CONTEXT_S_2, ASN1_OPT }, /* 14 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 15 */ - { 1, "thisUpdate", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 16 */ - { 1, "nextUpdateContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 17 */ - { 2, "nextUpdate", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 18 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 19 */ - { 1, "singleExtensionsContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 20 */ - { 2, "singleExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 21 */ - { 3, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 22 */ - { 4, "extnID", ASN1_OID, ASN1_BODY }, /* 23 */ - { 4, "critical", ASN1_BOOLEAN, ASN1_BODY | - ASN1_DEF }, /* 24 */ - { 4, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 25 */ - { 2, "end loop", ASN1_EOC, ASN1_END }, /* 26 */ - { 1, "end opt", ASN1_EOC, ASN1_END } /* 27 */ -}; - -#define SINGLE_RESPONSE_ALGORITHM 2 -#define SINGLE_RESPONSE_ISSUER_NAME_HASH 3 -#define SINGLE_RESPONSE_ISSUER_KEY_HASH 4 -#define SINGLE_RESPONSE_SERIAL_NUMBER 5 -#define SINGLE_RESPONSE_CERT_STATUS_GOOD 6 -#define SINGLE_RESPONSE_CERT_STATUS_REVOKED 8 -#define SINGLE_RESPONSE_CERT_STATUS_REVOCATION_TIME 9 -#define SINGLE_RESPONSE_CERT_STATUS_CRL_REASON 11 -#define SINGLE_RESPONSE_CERT_STATUS_UNKNOWN 14 -#define SINGLE_RESPONSE_THIS_UPDATE 16 -#define SINGLE_RESPONSE_NEXT_UPDATE 18 -#define SINGLE_RESPONSE_EXT_ID 23 -#define SINGLE_RESPONSE_CRITICAL 24 -#define SINGLE_RESPONSE_EXT_VALUE 25 -#define SINGLE_RESPONSE_ROOF 28 - -/** - * build requestorName (into TBSRequest) - */ -static chunk_t build_requestor_name(private_ocsp_t *this) -{ - identification_t *requestor_name = this->requestor_cert->get_subject(this->requestor_cert); - - return asn1_wrap(ASN1_CONTEXT_C_1, "m", - asn1_simple_object(ASN1_CONTEXT_C_4, - requestor_name->get_encoding(requestor_name))); -} - -/** - * build request (into requestList) - * no singleRequestExtensions used - */ -static chunk_t build_request(private_ocsp_t *this, certinfo_t *certinfo) -{ - chunk_t serialNumber = certinfo->get_serialNumber(certinfo); - - chunk_t reqCert = asn1_wrap(ASN1_SEQUENCE, "cmmm", - asn1_algorithmIdentifier(OID_SHA1), - asn1_simple_object(ASN1_OCTET_STRING, this->authNameID), - asn1_simple_object(ASN1_OCTET_STRING, this->authKeyID), - asn1_simple_object(ASN1_INTEGER, serialNumber)); - - return asn1_wrap(ASN1_SEQUENCE, "m", reqCert); -} - -/** - * build requestList (into TBSRequest) - */ -static chunk_t build_request_list(private_ocsp_t *this) -{ - chunk_t requestList; - size_t datalen = 0; - linked_list_t *request_list = linked_list_create(); - - { - iterator_t *iterator = this->certinfos->create_iterator(this->certinfos, TRUE); - certinfo_t *certinfo; - - while (iterator->iterate(iterator, (void**)&certinfo)) - { - chunk_t *request = malloc_thing(chunk_t); - - *request = build_request(this, certinfo); - request_list->insert_last(request_list, (void*)request); - datalen += request->len; - } - iterator->destroy(iterator); - } - { - iterator_t *iterator = request_list->create_iterator(request_list, TRUE); - chunk_t *request; - - u_char *pos = build_asn1_object(&requestList, ASN1_SEQUENCE, datalen); - - while (iterator->iterate(iterator, (void**)&request)) - { - memcpy(pos, request->ptr, request->len); - pos += request->len; - free(request->ptr); - free(request); - } - iterator->destroy(iterator); - request_list->destroy(request_list); - } - return requestList; -} - -/** - * build nonce extension (into requestExtensions) - */ -static chunk_t build_nonce_extension(private_ocsp_t *this) -{ - randomizer_t *randomizer = randomizer_create(); - - /* generate a random nonce */ - randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_LENGTH, &this->nonce); - randomizer->destroy(randomizer); - - return asn1_wrap(ASN1_SEQUENCE, "cm", - ASN1_nonce_oid, - asn1_simple_object(ASN1_OCTET_STRING, this->nonce)); -} - -/** - * build requestExtensions (into TBSRequest) - */ -static chunk_t build_request_ext(private_ocsp_t *this) -{ - return asn1_wrap(ASN1_CONTEXT_C_2, "m", - asn1_wrap(ASN1_SEQUENCE, "mm", - build_nonce_extension(this), - asn1_wrap(ASN1_SEQUENCE, "cc", - ASN1_response_oid, - ASN1_response_content - ) - ) - ); -} - -/** - * build TBSRequest (into OCSPRequest) - */ -static chunk_t build_tbs_request(private_ocsp_t *this, bool has_requestor_cert) -{ - /* version is skipped since the default is ok */ - return asn1_wrap(ASN1_SEQUENCE, "mmm", - (has_requestor_cert)? build_requestor_name(this): chunk_empty, - build_request_list(this), - build_request_ext(this)); -} - -/** - * build signature into ocsp request - * gets built only if a request cert with a corresponding private key is found - */ -static chunk_t build_signature(private_ocsp_t *this, chunk_t tbsRequest) -{ - /* TODO */ - return chunk_empty; -} - -/** - * assembles an ocsp request and sets the nonce field in private_ocsp_t to the sent nonce - */ -static chunk_t ocsp_build_request(private_ocsp_t *this) -{ - bool has_requestor_cert; - chunk_t keyid = this->cacert->get_keyid(this->cacert); - chunk_t tbsRequest, signature; - - DBG2("assembling ocsp request"); - DBG2("issuer: '%D'", this->cacert->get_subject(this->cacert)); - DBG2("keyid: %#B", &keyid); - - /* looks for requestor cert and matching private key */ - has_requestor_cert = FALSE; - - /* TODO has_requestor_cert = get_ocsp_requestor_cert(location); */ - - /* build content */ - tbsRequest = build_tbs_request(this, has_requestor_cert); - - /* sign tbsReuqest */ - signature = (has_requestor_cert)? build_signature(this, tbsRequest): chunk_empty; - - return asn1_wrap(ASN1_SEQUENCE, "mm", - tbsRequest, - signature); - - return signature; -} - -/** - * parse a basic OCSP response - */ -static bool ocsp_parse_basic_response(chunk_t blob, int level0, response_t *res) -{ - u_int level, version; - asn1_ctx_t ctx; - bool critical; - chunk_t object; - int objectID = 0; - int extn_oid = OID_UNKNOWN; - - asn1_init(&ctx, blob, level0, FALSE, FALSE); - - while (objectID < BASIC_RESPONSE_ROOF) - { - if (!extract_object(basicResponseObjects, &objectID, &object, &level, &ctx)) - { - return FALSE; - } - - switch (objectID) - { - case BASIC_RESPONSE_TBS_DATA: - res->tbs = object; - break; - case BASIC_RESPONSE_VERSION: - version = (object.len)? (1 + (u_int)*object.ptr) : 1; - if (version != OCSP_BASIC_RESPONSE_VERSION) - { - DBG1("wrong ocsp basic response version (version= %i)", version); - return FALSE; - } - break; - case BASIC_RESPONSE_ID_BY_NAME: - res->responder_id_name = identification_create_from_encoding(ID_DER_ASN1_DN, object); - DBG2(" '%D'", res->responder_id_name); - break; - case BASIC_RESPONSE_ID_BY_KEY: - res->responder_id_key = object; - break; - case BASIC_RESPONSE_PRODUCED_AT: - res->produced_at = asn1totime(&object, ASN1_GENERALIZEDTIME); - break; - case BASIC_RESPONSE_RESPONSES: - res->responses = object; - break; - case BASIC_RESPONSE_EXT_ID: - extn_oid = known_oid(object); - break; - case BASIC_RESPONSE_CRITICAL: - critical = object.len && *object.ptr; - DBG2(" %s", critical? "TRUE" : "FALSE"); - break; - case BASIC_RESPONSE_EXT_VALUE: - if (extn_oid == OID_NONCE) - res->nonce = object; - break; - case BASIC_RESPONSE_ALGORITHM: - res->algorithm = parse_algorithmIdentifier(object, level+1, NULL); - break; - case BASIC_RESPONSE_SIGNATURE: - res->signature = object; - break; - case BASIC_RESPONSE_CERTIFICATE: - { - chunk_t blob = chunk_clone(object); - - res->responder_cert = x509_create_from_chunk(blob, level+1); - } - break; - } - objectID++; - } - return TRUE; -} - -/** - * parse an ocsp response and return the result as a response_t struct - */ -static response_status ocsp_parse_response(response_t *res) -{ - asn1_ctx_t ctx; - chunk_t object; - u_int level; - int objectID = 0; - int ocspResponseType = OID_UNKNOWN; - response_status rStatus = STATUS_INTERNALERROR; - - asn1_init(&ctx, res->chunk, 0, FALSE, FALSE); - - while (objectID < OCSP_RESPONSE_ROOF) - { - if (!extract_object(ocspResponseObjects, &objectID, &object, &level, &ctx)) - { - return STATUS_INTERNALERROR; - } - - switch (objectID) - { - case OCSP_RESPONSE_STATUS: - rStatus = (response_status) *object.ptr; - DBG2(" '%N'", response_status_names, rStatus); - - switch (rStatus) - { - case STATUS_SUCCESSFUL: - break; - case STATUS_MALFORMEDREQUEST: - case STATUS_INTERNALERROR: - case STATUS_TRYLATER: - case STATUS_SIGREQUIRED: - case STATUS_UNAUTHORIZED: - DBG1("unsuccessful ocsp response: server said '%N'", - response_status_names, rStatus); - return rStatus; - default: - return STATUS_INTERNALERROR; - } - break; - case OCSP_RESPONSE_TYPE: - ocspResponseType = known_oid(object); - break; - case OCSP_RESPONSE: - { - switch (ocspResponseType) - { - case OID_BASIC: - if (!ocsp_parse_basic_response(object, level+1, res)) - { - return STATUS_INTERNALERROR; - } - break; - default: - DBG1("ocsp response is not of type BASIC"); - DBG1("ocsp response OID: %#B", &object); - return STATUS_INTERNALERROR; - } - } - break; - } - objectID++; - } - return rStatus; -} - -/** - * Check if the OCSP response has a valid signature - */ -static bool ocsp_valid_response(response_t *res, x509_t *ocsp_cert) -{ - rsa_public_key_t *public_key; - time_t until = UNDEFINED_TIME; - err_t ugh; - hash_algorithm_t algorithm = hasher_algorithm_from_oid(res->algorithm); - - if (algorithm == HASH_UNKNOWN) - { - DBG1("unknown signature algorithm"); - return FALSE; - } - - DBG2("verifying ocsp response signature:"); - DBG2("signer: '%D'", ocsp_cert->get_subject(ocsp_cert)); - DBG2("issuer: '%D'", ocsp_cert->get_issuer(ocsp_cert)); - - ugh = ocsp_cert->is_valid(ocsp_cert, &until); - if (ugh != NULL) - { - DBG1("ocsp signer certificate %s", ugh); - return FALSE; - } - public_key = ocsp_cert->get_public_key(ocsp_cert); - - return public_key->verify_emsa_pkcs1_signature(public_key, algorithm, res->tbs, res->signature) == SUCCESS; -} - -/** - * parse a single OCSP response - */ -static bool ocsp_parse_single_response(private_ocsp_t *this, chunk_t blob, int level0) -{ - u_int level, extn_oid; - asn1_ctx_t ctx; - bool critical; - chunk_t object; - int objectID = 0; - - certinfo_t *certinfo = NULL; - - asn1_init(&ctx, blob, level0, FALSE, FALSE); - - while (objectID < SINGLE_RESPONSE_ROOF) - { - if (!extract_object(singleResponseObjects, &objectID, &object, &level, &ctx)) - { - return FALSE; - } - - switch (objectID) - { - case SINGLE_RESPONSE_ALGORITHM: - if (parse_algorithmIdentifier(object, level+1, NULL) != OID_SHA1) - { - DBG1("only sha-1 hash supported in ocsp single response"); - return FALSE; - } - break; - case SINGLE_RESPONSE_ISSUER_NAME_HASH: - if (!chunk_equals(object, this->authNameID)) - { - DBG1("ocsp single response has wrong issuer name hash"); - return FALSE; - } - break; - case SINGLE_RESPONSE_ISSUER_KEY_HASH: - if (!chunk_equals(object, this->authKeyID)) - { - DBG1("ocsp single response has wrong issuer key hash"); - return FALSE; - } - break; - case SINGLE_RESPONSE_SERIAL_NUMBER: - { - iterator_t *iterator = this->certinfos->create_iterator(this->certinfos, TRUE); - certinfo_t *current_certinfo; - - while (iterator->iterate(iterator, (void**)¤t_certinfo)) - { - if (chunk_equals(object, current_certinfo->get_serialNumber(current_certinfo))) - { - certinfo = current_certinfo; - } - } - iterator->destroy(iterator); - if (certinfo == NULL) - { - DBG1("unrequested serial number in ocsp single response"); - return FALSE; - } - } - break; - case SINGLE_RESPONSE_CERT_STATUS_GOOD: - certinfo->set_status(certinfo, CERT_GOOD); - break; - case SINGLE_RESPONSE_CERT_STATUS_REVOKED: - certinfo->set_status(certinfo, CERT_REVOKED); - break; - case SINGLE_RESPONSE_CERT_STATUS_REVOCATION_TIME: - certinfo->set_revocationTime(certinfo, - asn1totime(&object, ASN1_GENERALIZEDTIME)); - break; - case SINGLE_RESPONSE_CERT_STATUS_CRL_REASON: - certinfo->set_revocationReason(certinfo, - (object.len == 1) ? *object.ptr : REASON_UNSPECIFIED); - break; - case SINGLE_RESPONSE_CERT_STATUS_UNKNOWN: - certinfo->set_status(certinfo, CERT_UNKNOWN); - break; - case SINGLE_RESPONSE_THIS_UPDATE: - certinfo->set_thisUpdate(certinfo, - asn1totime(&object, ASN1_GENERALIZEDTIME)); - break; - case SINGLE_RESPONSE_NEXT_UPDATE: - certinfo->set_nextUpdate(certinfo, - asn1totime(&object, ASN1_GENERALIZEDTIME)); - break; - case SINGLE_RESPONSE_EXT_ID: - extn_oid = known_oid(object); - break; - case SINGLE_RESPONSE_CRITICAL: - critical = object.len && *object.ptr; - DBG2(" %s", critical ? "TRUE" : "FALSE"); - case SINGLE_RESPONSE_EXT_VALUE: - break; - } - objectID++; - } - return TRUE; -} - -/** - * verify and process ocsp response and update the ocsp cache - */ -static void ocsp_process_response(private_ocsp_t *this, response_t *res, credential_store_t *credentials) -{ - x509_t *ocsp_cert = NULL; - - /* parse the ocsp response without looking at the single responses yet */ - response_status status = ocsp_parse_response(res); - - if (status != STATUS_SUCCESSFUL) - { - DBG1("error in ocsp response"); - return; - } - - /* check if there was a nonce in the request */ - if (this->nonce.ptr != NULL && res->nonce.ptr == NULL) - { - DBG1("ocsp response contains no nonce, replay attack possible"); - } - - /* check if the nonces are identical */ - if (res->nonce.ptr != NULL && !chunk_equals(res->nonce, this->nonce)) - { - DBG1("invalid nonce in ocsp response"); - return; - } - - /* check if we received a trusted responder certificate */ - if (res->responder_cert) - { - if (res->responder_cert->is_ocsp_signer(res->responder_cert)) - { - DBG2("received certificate is ocsp signer"); - if (credentials->is_trusted(credentials, "OCSP signing", res->responder_cert)) - { - DBG1("received ocsp signer certificate is trusted"); - ocsp_cert = credentials->add_auth_certificate(credentials, - res->responder_cert, AUTH_OCSP); - res->responder_cert = NULL; - } - else - { - DBG1("received ocsp signer certificate is not trusted - rejected"); - } - } - else - { - DBG1("received certificate is no ocsp signer - rejected"); - } - } - - /* if we didn't receive a trusted responder cert, search the credential store */ - if (ocsp_cert == NULL) - { - ocsp_cert = credentials->get_auth_certificate(credentials, - AUTH_OCSP|AUTH_CA, res->responder_id_name); - if (ocsp_cert == NULL) - { - DBG1("no ocsp signer certificate found"); - return; - } - } - - /* check the response signature */ - if (!ocsp_valid_response(res, ocsp_cert)) - { - DBG1("ocsp response signature is invalid"); - return; - } - DBG2("ocsp response signature is valid"); - - /* now parse the single responses one at a time */ - { - u_int level; - asn1_ctx_t ctx; - chunk_t object; - int objectID = 0; - - asn1_init(&ctx, res->responses, 0, FALSE, FALSE); - - while (objectID < RESPONSES_ROOF) - { - if (!extract_object(responsesObjects, &objectID, &object, &level, &ctx)) - { - return; - } - if (objectID == RESPONSES_SINGLE_RESPONSE) - { - ocsp_parse_single_response(this, object, level+1); - } - objectID++; - } - } -} - -/** - * Implements ocsp_t.fetch. - */ -static void fetch(private_ocsp_t *this, certinfo_t *certinfo, credential_store_t *credentials) -{ - chunk_t request; - response_t *response = NULL; - - if (this->uris->get_count(this->uris) == 0) - { - return; - } - this->certinfos->insert_last(this->certinfos, (void*)certinfo); - - request = ocsp_build_request(this); - DBG3("ocsp request: %B", &request); - { - iterator_t *iterator = this->uris->create_iterator(this->uris, TRUE); - identification_t *uri; - - while (iterator->iterate(iterator, (void**)&uri)) - { - fetcher_t *fetcher; - char uri_string[BUF_LEN]; - chunk_t uri_chunk = uri->get_encoding(uri); - chunk_t response_chunk; - - snprintf(uri_string, BUF_LEN, "%.*s", uri_chunk.len, uri_chunk.ptr); - fetcher = fetcher_create(uri_string); - - response_chunk = fetcher->post(fetcher, "application/ocsp-request", request); - fetcher->destroy(fetcher); - if (response_chunk.ptr != NULL) - { - response = response_create_from_chunk(response_chunk); - break; - } - } - iterator->destroy(iterator); - } - free(request.ptr); - - if (response == NULL) - { - return; - } - DBG3("ocsp response: %B", &response->chunk); - ocsp_process_response(this, response, credentials); - response->destroy(response); -} - -/** - * Implements ocsp_t.destroy. - */ -static void destroy(private_ocsp_t *this) -{ - this->certinfos->destroy(this->certinfos); - free(this->authNameID.ptr); - free(this->nonce.ptr); - free(this); -} - -/* - * Described in header. - */ -ocsp_t *ocsp_create(x509_t *cacert, linked_list_t *uris) -{ - private_ocsp_t *this = malloc_thing(private_ocsp_t); - - /* initialize */ - this->cacert = cacert; - this->uris = uris; - this->certinfos = linked_list_create(); - this->nonce = chunk_empty; - this->authKeyID = cacert->get_subjectKeyID(cacert); - { - hasher_t *hasher = hasher_create(HASH_SHA1); - identification_t *issuer = cacert->get_subject(cacert); - - hasher->allocate_hash(hasher, issuer->get_encoding(issuer), - &this->authNameID); - hasher->destroy(hasher); - } - - /* public functions */ - this->public.fetch = (void (*) (ocsp_t*,certinfo_t*,credential_store_t*))fetch; - this->public.destroy = (void (*) (ocsp_t*))destroy; - - return &this->public; -} diff --git a/src/libstrongswan/crypto/ocsp.h b/src/libstrongswan/crypto/ocsp.h index e468bb8be..b358d409f 100644 --- a/src/libstrongswan/crypto/ocsp.h +++ b/src/libstrongswan/crypto/ocsp.h @@ -1,12 +1,4 @@ -/** - * @file ocsp.h - * - * @brief Interface of ocsp_t - * - */ - -/* Support of the Online Certificate Status Protocol (OCSP) Support - * +/* * Copyright (C) 2003 Christoph Gysin, Simon Zwahlen * Copyright (C) 2007 Andreas Steffen * @@ -22,7 +14,12 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id$ + * $Id$ + */ + +/** + * @defgroup ocsp ocsp + * @{ @ingroup crypto */ #ifndef OCSP_H_ @@ -51,39 +48,32 @@ typedef enum { } response_status; /** - * @brief Online Certficate Status Protocol (OCSP) - * - * @ingroup transforms + * Online Certficate Status Protocol (OCSP) */ struct ocsp_t { /** - * @brief Fetches the actual certificate status via OCSP + * Fetches the actual certificate status via OCSP * - * @param uris linked list of ocsp uris * @param certinfo certificate status info to be updated * @param credentials credential store needed for trust path verification */ void (*fetch) (ocsp_t *this, certinfo_t *certinfo, credential_store_t *credentials); /** - * @brief Destroys the ocsp_t object. - * - * @param this ocsp object to destroy + * Destroys the ocsp_t object. */ void (*destroy) (ocsp_t *this); }; /** - * @brief Create an ocsp_t object. + * Create an ocsp_t object. * * @param cacert ca certificate * @param uris linked list of ocsp uris * @return created ocsp_t object - * - * @ingroup transforms */ ocsp_t *ocsp_create(x509_t *cacert, linked_list_t *uris); -#endif /* OCSP_H_ */ +#endif /* OCSP_H_ @} */ diff --git a/src/libstrongswan/crypto/pkcs7.c b/src/libstrongswan/crypto/pkcs7.c index 252fc19b2..662e8dd0d 100644 --- a/src/libstrongswan/crypto/pkcs7.c +++ b/src/libstrongswan/crypto/pkcs7.c @@ -1,10 +1,3 @@ -/** - * @file pkcs7.c - * - * @brief Implementation of pkcs7_t. - * - */ - /* * Copyright (C) 2005 Jan Hutter, Martin Willi * Copyright (C) 2002-2008 Andreas Steffen @@ -21,7 +14,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id$ + * $Id$ */ #include @@ -459,10 +452,18 @@ static bool parse_signedData(private_pkcs7_t *this, x509_t *cacert) } else { - hasher_t *hasher = hasher_create(algorithm); + hasher_t *hasher; chunk_t hash; bool valid; + hasher = lib->crypto->create_hasher(lib->crypto, algorithm) + if (hasher == NULL) + { + DBG1("hash algorithm %N not supported", + hash_algorithm_names, algorithm); + free(messageDigest.ptr); + return FALSE; + } hasher->allocate_hash(hasher, this->data, &hash); hasher->destroy(hasher); DBG3("hash: %B", &hash); @@ -873,15 +874,24 @@ bool build_signedData(private_pkcs7_t *this, rsa_private_key_t *private_key, if (this->attributes != NULL) { - if (this->data.ptr != NULL) + if(this->data.ptr != NULL) { + hasher_t *hasher; + + hasher = lib->crypto->create_hasher(lib->crypto, alg); + if (hasher == NULL) + { + DBG1(" hash algorithm %N not support", + hash_algorithm_names, alg); + return FALSE; + } + /* take the current time as signingTime */ time_t now = time(NULL); chunk_t signingTime = timetoasn1(&now, ASN1_UTCTIME); chunk_t messageDigest, attributes; - hasher_t *hasher = hasher_create(alg); - + hasher->allocate_hash(hasher, this->data, &messageDigest); hasher->destroy(hasher); this->attributes->set_attribute(this->attributes, diff --git a/src/libstrongswan/crypto/pkcs7.h b/src/libstrongswan/crypto/pkcs7.h index 1872673e6..77d3ecdbd 100644 --- a/src/libstrongswan/crypto/pkcs7.h +++ b/src/libstrongswan/crypto/pkcs7.h @@ -1,10 +1,3 @@ -/** - * @file pkcs7.h - * - * @brief Interface of pkcs7_t. - * - */ - /* * Copyright (C) 2005 Jan Hutter, Martin Willi * Copyright (C) 2002-2008 Andreas Steffen @@ -21,11 +14,16 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id$ + * $Id$ + */ + +/** + * @defgroup pkcs7 pkcs7 + * @{ @ingroup crypto */ -#ifndef _PKCS7_H -#define _PKCS7_H +#ifndef _PKCS7_H_ +#define _PKCS7_H_ typedef struct pkcs7_t pkcs7_t; @@ -37,60 +35,48 @@ typedef struct pkcs7_t pkcs7_t; #include /** - * @brief PKCS#7 contentInfo object. - * - * @b Constructors: - * -pkcs7_create_from_chunk() - * -pkcs7_create_from_data() - * - * @ingroup crypto + * PKCS#7 contentInfo object. */ struct pkcs7_t { /** - * @brief Check if the PKCS#7 contentType is data + * Check if the PKCS#7 contentType is data * - * @param this calling object * @return TRUE if the contentType is data */ bool (*is_data) (pkcs7_t *this); /** - * @brief Check if the PKCS#7 contentType is signedData + * Check if the PKCS#7 contentType is signedData * - * @param this calling object * @return TRUE if the contentType is signedData */ bool (*is_signedData) (pkcs7_t *this); /** - * @brief Check if the PKCS#7 contentType is envelopedData + * Check if the PKCS#7 contentType is envelopedData * - * @param this calling object * @return TRUE if the contentType is envelopedData */ bool (*is_envelopedData) (pkcs7_t *this); /** - * @brief Parse a PKCS#7 data content. + * Parse a PKCS#7 data content. * - * @param this calling object * @return TRUE if parsing was successful */ bool (*parse_data) (pkcs7_t *this); /** - * @brief Parse a PKCS#7 signedData content. + * Parse a PKCS#7 signedData content. * - * @param this calling object * @param cacert cacert used to verify the signature * @return TRUE if parsing was successful */ bool (*parse_signedData) (pkcs7_t *this, x509_t *cacert); /** - * @brief Parse a PKCS#7 envelopedData content. + * Parse a PKCS#7 envelopedData content. * - * @param this calling object * @param serialNumber serialNumber of the request * @param key RSA private key used to decrypt the symmetric key * @return TRUE if parsing was successful @@ -98,112 +84,97 @@ struct pkcs7_t { bool (*parse_envelopedData) (pkcs7_t *this, chunk_t serialNumber, rsa_private_key_t *key); /** - * @brief Returns the parsed data object + * Returns the parsed data object * - * @param this calling object * @return chunk containing the data object */ chunk_t (*get_data) (pkcs7_t *this); /** - * @brief Returns the a DER-encoded contentInfo object + * Returns the a DER-encoded contentInfo object * - * @param this calling object * @return chunk containing the contentInfo object */ chunk_t (*get_contentInfo) (pkcs7_t *this); /** - * @brief Create an iterator for the certificates. + * Create an iterator for the certificates. * - * @param this calling object * @return iterator for the certificates */ iterator_t *(*create_certificate_iterator) (pkcs7_t *this); /** - * @brief Add a certificate. + * Add a certificate. * - * @param this calling object * @param cert certificate to be included */ void (*set_certificate) (pkcs7_t *this, x509_t *cert); /** - * @brief Add authenticated attributes. + * Add authenticated attributes. * - * @param this calling object * @param attributes attributes to be included */ void (*set_attributes) (pkcs7_t *this, pkcs9_t *attributes); /** - * @brief Build a data object + * Build a data object * - * @param this PKCS#7 data to be built * @return TRUE if build was successful */ bool (*build_data) (pkcs7_t *this); /** - * @brief Build an envelopedData object + * Build an envelopedData object * - * @param this PKCS#7 data object to envelop * @param cert receivers's certificate * @param alg encryption algorithm * @return TRUE if build was successful */ - bool (*build_envelopedData) (pkcs7_t *this, x509_t *cert, encryption_algorithm_t alg); + bool (*build_envelopedData) (pkcs7_t *this, x509_t *cert, + encryption_algorithm_t alg); /** - * @brief Build an signedData object + * Build an signedData object * - * @param this PKCS#7 data object to sign * @param key signer's RSA private key * @param alg digest algorithm used for signature * @return TRUE if build was successful */ - bool (*build_signedData) (pkcs7_t *this, rsa_private_key_t *key, hash_algorithm_t alg); + bool (*build_signedData) (pkcs7_t *this, rsa_private_key_t *key, + hash_algorithm_t alg); /** - * @brief Destroys the contentInfo object. - * - * @param this PKCS#7 contentInfo object to destroy + * Destroys the contentInfo object. */ void (*destroy) (pkcs7_t *this); }; /** - * @brief Read a PKCS#7 contentInfo object from a DER encoded chunk. + * Read a PKCS#7 contentInfo object from a DER encoded chunk. * * @param chunk chunk containing DER encoded data * @param level ASN.1 parsing start level * @return created pkcs7_contentInfo object, or NULL if invalid. - * - * @ingroup crypto */ pkcs7_t *pkcs7_create_from_chunk(chunk_t chunk, u_int level); /** - * @brief Create a PKCS#7 contentInfo object + * Create a PKCS#7 contentInfo object * * @param chunk chunk containing data * @return created pkcs7_contentInfo object. - * - * @ingroup crypto */ pkcs7_t *pkcs7_create_from_data(chunk_t data); /** - * @brief Read a X.509 certificate from a DER encoded file. + * Read a X.509 certificate from a DER encoded file. * * @param filename file containing DER encoded data * @param label label describing kind of PKCS#7 file * @return created pkcs7_t object, or NULL if invalid. - * - * @ingroup crypto */ pkcs7_t *pkcs7_create_from_file(const char *filename, const char *label); - -#endif /* _PKCS7_H */ +#endif /* _PKCS7_H_ @} */ diff --git a/src/libstrongswan/crypto/pkcs9.c b/src/libstrongswan/crypto/pkcs9.c index 1003c9011..ba2724005 100644 --- a/src/libstrongswan/crypto/pkcs9.c +++ b/src/libstrongswan/crypto/pkcs9.c @@ -1,13 +1,5 @@ -/** - * @file pkcs9.c - * - * @brief Implementation of pkcs9_t. - * - */ - /* * Copyright (C)2008 Andreas Steffen - * * Hochschule fuer Technik Rapperswil, Switzerland * * This program is free software; you can redistribute it and/or modify it @@ -20,7 +12,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id: pkcs7.c 3423 2008-01-22 10:32:37Z andreas $ + * $Id$ */ #include diff --git a/src/libstrongswan/crypto/pkcs9.h b/src/libstrongswan/crypto/pkcs9.h index 44915720c..e5e22bf63 100644 --- a/src/libstrongswan/crypto/pkcs9.h +++ b/src/libstrongswan/crypto/pkcs9.h @@ -1,13 +1,5 @@ -/** - * @file pkcs7.h - * - * @brief Interface of pkcs9_t. - * - */ - /* - * Copyright (C) 2008 Andreas Steffen - * + * Copyright (C) 2008 Andreas Steffen * Hochschule fuer Technik Rapperswil, Switzerland * * This program is free software; you can redistribute it and/or modify it @@ -20,102 +12,89 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id: pkcs7.h 3423 2008-01-22 10:32:37Z andreas $ + * $Id$ + */ + +/** + * @defgroup pkcs9 pkcs9 + * @{ @ingroup crypto */ -#ifndef _PKCS9_H -#define _PKCS9_H +#ifndef PKCS9_H_ +#define PKCS9_H_ typedef struct pkcs9_t pkcs9_t; #include /** - * @brief PKCS#9 . - * - * @b Constructors: - * -pkcs9_create_from_chunk() - * -pkcs9_create() - * - * @ingroup crypto + * PKCS#9 attributes. */ struct pkcs9_t { + /** - * @brief generate ASN.1 encoding of attribute list - * - * @param this PKCS#9 attribute list to be encoded + * Generate ASN.1 encoding of attribute list */ void (*build_encoding) (pkcs9_t *this); /** - * @brief gets ASN.1 encoding of PKCS#9 attribute list + * Gets ASN.1 encoding of PKCS#9 attribute list * - * @param this calling object * @return ASN.1 encoded PKCSI#9 list */ chunk_t (*get_encoding) (pkcs9_t *this); /** - * @brief gets a PKCS#9 attribute + * Gets a PKCS#9 attribute * - * @param this calling object * @param oid OID of the attribute * @return ASN.1 encoded value of the attribute */ chunk_t (*get_attribute) (pkcs9_t *this, int oid); /** - * @brief adds a PKCS#9 attribute + * Adds a PKCS#9 attribute * - * @param this calling object * @param oid OID of the attribute * @param value ASN.1 encoded value of the attribute */ void (*set_attribute) (pkcs9_t *this, int oid, chunk_t value); /** - * @brief gets a PKCS#9 messageDigest attribute + * Gets a PKCS#9 messageDigest attribute * - * @param this calling object * @return messageDigest */ chunk_t (*get_messageDigest) (pkcs9_t *this); /** - * @brief add a PKCS#9 messageDigest attribute + * Add a PKCS#9 messageDigest attribute * - * @param this calling object * @param value messageDigest */ void (*set_messageDigest) (pkcs9_t *this, chunk_t value); /** - * @brief Destroys the PKCS#9 attribute list. - * - * @param this PKCS#9 attribute list to destroy + * Destroys the PKCS#9 attribute list. */ void (*destroy) (pkcs9_t *this); }; /** - * @brief Read a PKCS#9 attribute list from a DER encoded chunk. + * Read a PKCS#9 attribute list from a DER encoded chunk. * * @param chunk chunk containing DER encoded data * @param level ASN.1 parsing start level * @return created pkcs9 attribute list, or NULL if invalid. - * - * @ingroup crypto */ pkcs9_t *pkcs9_create_from_chunk(chunk_t chunk, u_int level); /** - * @brief Create an empty PKCS#9 attribute list + * Create an empty PKCS#9 attribute list * * @param chunk chunk containing data * @return created pkcs9 attribute list. - * - * @ingroup crypto */ pkcs9_t *pkcs9_create(void); -#endif /* _PKCS9_H */ +#endif /* PKCS9_H_ @} */ diff --git a/src/libstrongswan/crypto/prf_plus.c b/src/libstrongswan/crypto/prf_plus.c index 6bd444b1f..6b1042036 100644 --- a/src/libstrongswan/crypto/prf_plus.c +++ b/src/libstrongswan/crypto/prf_plus.c @@ -1,10 +1,3 @@ -/** - * @file prf_plus.c - * - * @brief Implementation of prf_plus_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,8 @@ * 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. + * + * $Id$ */ #include diff --git a/src/libstrongswan/crypto/prf_plus.h b/src/libstrongswan/crypto/prf_plus.h index 90f9ce2eb..9e074974c 100644 --- a/src/libstrongswan/crypto/prf_plus.h +++ b/src/libstrongswan/crypto/prf_plus.h @@ -1,10 +1,3 @@ -/** - * @file prf_plus.h - * - * @brief Interface for prf_plus.h. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup prf_plus prf_plus + * @{ @ingroup crypto */ #ifndef PRF_PLUS_H_ @@ -29,53 +29,43 @@ typedef struct prf_plus_t prf_plus_t; #include /** - * @brief Implementation of the prf+ function described in IKEv2 RFC. + * Implementation of the prf+ function described in IKEv2 RFC. * * This class implements the prf+ algorithm. Internally it uses a pseudo random * function, which implements the prf_t interface. - * * See IKEv2 RFC 2.13. - * - * @b Constructors: - * - prf_plus_create() - * - * @ingroup transforms */ struct prf_plus_t { /** - * @brief Get pseudo random bytes. + * Get pseudo random bytes. * * Get the next few bytes of the prf+ output. Space * must be allocated by the caller. * - * @param this calling object - * @param length number of bytes to get - * @param[out] buffer pointer where the generated bytes will be written + * @param length number of bytes to get + * @param buffer pointer where the generated bytes will be written */ void (*get_bytes) (prf_plus_t *this, size_t length, u_int8_t *buffer); /** - * @brief Allocate pseudo random bytes. + * Allocate pseudo random bytes. * * Get the next few bytes of the prf+ output. This function * will allocate the required space. * - * @param this calling object - * @param length number of bytes to get - * @param[out] chunk chunk which will hold generated bytes + * @param length number of bytes to get + * @param chunk chunk which will hold generated bytes */ void (*allocate_bytes) (prf_plus_t *this, size_t length, chunk_t *chunk); /** - * @brief Destroys a prf_plus_t object. - * - * @param this calling object + * Destroys a prf_plus_t object. */ void (*destroy) (prf_plus_t *this); }; /** - * @brief Creates a new prf_plus_t object. + * Creates a new prf_plus_t object. * * Seed will be cloned. prf will * not be cloned, must be destroyed outside after @@ -84,9 +74,7 @@ struct prf_plus_t { * @param prf prf object to use * @param seed input seed for prf * @return prf_plus_t object - * - * @ingroup transforms */ prf_plus_t *prf_plus_create(prf_t *prf, chunk_t seed); -#endif /*PRF_PLUS_H_*/ +#endif /*PRF_PLUS_H_ @} */ diff --git a/src/libstrongswan/crypto/prfs/fips_prf.c b/src/libstrongswan/crypto/prfs/fips_prf.c deleted file mode 100644 index 0ab80b089..000000000 --- a/src/libstrongswan/crypto/prfs/fips_prf.c +++ /dev/null @@ -1,258 +0,0 @@ -/** - * @file fips_prf.c - * - * @brief Implementation for fips_prf_t. - * - */ - -/* - * Copyright (C) 2006 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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 "fips_prf.h" - -#include - -#include - -typedef struct private_fips_prf_t private_fips_prf_t; - -/** - * Private data of a fips_prf_t object. - */ -struct private_fips_prf_t { - /** - * Public fips_prf_t interface. - */ - fips_prf_t public; - - /** - * key of prf function, "b" long - */ - u_int8_t *key; - - /** - * size of "b" in bytes - */ - size_t b; - - /** - * G function, either SHA1 or DES - */ - void (*g)(u_int8_t t[], chunk_t c, u_int8_t res[]); -}; - -/** - * t used in G(), equals to initial SHA1 value - */ -static u_int8_t t[] = { - 0x67,0x45,0x23,0x01,0xEF,0xCD,0xAB,0x89,0x98,0xBA, - 0xDC,0xFE,0x10,0x32,0x54,0x76,0xC3,0xD2,0xE1,0xF0, -}; - -/** - * sum = (a + b) mod 2 ^ (length * 8) - */ -static void add_mod(size_t length, u_int8_t a[], u_int8_t b[], u_int8_t sum[]) -{ - int i, c = 0; - - for(i = length - 1; i >= 0; i--) - { - u_int32_t tmp; - - tmp = a[i] + b[i] + c; - sum[i] = 0xff & tmp; - c = tmp >> 8; - } -} - -/** - * calculate "chunk mod 2^(length*8)" and save it into buffer - */ -static void chunk_mod(size_t length, chunk_t chunk, u_int8_t buffer[]) -{ - if (chunk.len < length) - { - /* apply seed as least significant bits, others are zero */ - memset(buffer, 0, length - chunk.len); - memcpy(buffer + length - chunk.len, chunk.ptr, chunk.len); - } - else - { - /* use least significant bytes from seed, as we use mod 2^b */ - memcpy(buffer, chunk.ptr + chunk.len - length, length); - } -} - -/** - * Implementation of prf_t.get_bytes. - * - * Test vector: - * - * key: - * 0xbd, 0x02, 0x9b, 0xbe, 0x7f, 0x51, 0x96, 0x0b, - * 0xcf, 0x9e, 0xdb, 0x2b, 0x61, 0xf0, 0x6f, 0x0f, - * 0xeb, 0x5a, 0x38, 0xb6 - * - * seed: - * 0x00 - * - * result: - * 0x20, 0x70, 0xb3, 0x22, 0x3d, 0xba, 0x37, 0x2f, - * 0xde, 0x1c, 0x0f, 0xfc, 0x7b, 0x2e, 0x3b, 0x49, - * 0x8b, 0x26, 0x06, 0x14, 0x3c, 0x6c, 0x18, 0xba, - * 0xcb, 0x0f, 0x6c, 0x55, 0xba, 0xbb, 0x13, 0x78, - * 0x8e, 0x20, 0xd7, 0x37, 0xa3, 0x27, 0x51, 0x16 - */ -static void get_bytes(private_fips_prf_t *this, chunk_t seed, u_int8_t w[]) -{ - int i; - u_int8_t xval[this->b]; - u_int8_t xseed[this->b]; - u_int8_t sum[this->b]; - u_int8_t *xkey = this->key; - u_int8_t one[this->b]; - chunk_t xval_chunk = chunk_from_buf(xval); - - memset(one, 0, this->b); - one[this->b - 1] = 0x01; - - /* 3.1 */ - chunk_mod(this->b, seed, xseed); - - /* 3.2 */ - for (i = 0; i < 2; i++) /* twice */ - { - /* a. XVAL = (XKEY + XSEED j) mod 2^b */ - add_mod(this->b, xkey, xseed, xval); - DBG3("XVAL %b", xval, this->b); - /* b. wi = G(t, XVAL ) */ - this->g(t, xval_chunk, &w[i * this->b]); - DBG3("w[%d] %b", i, &w[i * this->b], this->b); - /* c. XKEY = (1 + XKEY + wi) mod 2b */ - add_mod(this->b, xkey, &w[i * this->b], sum); - add_mod(this->b, sum, one, xkey); - DBG3("XKEY %b", xkey, this->b); - } - - /* 3.3 done already, mod q not used */ -} - -/** - * Implementation of prf_t.get_block_size. - */ -static size_t get_block_size(private_fips_prf_t *this) -{ - return 2 * this->b; -} -/** - * Implementation of prf_t.allocate_bytes. - */ -static void allocate_bytes(private_fips_prf_t *this, chunk_t seed, chunk_t *chunk) -{ - *chunk = chunk_alloc(get_block_size(this)); - get_bytes(this, seed, chunk->ptr); -} - -/** - * Implementation of prf_t.get_key_size. - */ -static size_t get_key_size(private_fips_prf_t *this) -{ - return this->b; -} - -/** - * Implementation of prf_t.set_key. - */ -static void set_key(private_fips_prf_t *this, chunk_t key) -{ - /* save key as "key mod 2^b" */ - chunk_mod(this->b, key, this->key); -} - -/** - * Implementation of the G() function based on SHA1 - */ -void g_sha1(u_int8_t t[], chunk_t c, u_int8_t res[]) -{ - hasher_t *hasher; - u_int8_t buf[64]; - chunk_t state_chunk; - u_int32_t *state, *iv, *hash; - - if (c.len < sizeof(buf)) - { - /* pad c with zeros */ - memset(buf, 0, sizeof(buf)); - memcpy(buf, c.ptr, c.len); - c.ptr = buf; - c.len = sizeof(buf); - } - else - { - /* not more than 512 bits can be G()-ed */ - c.len = sizeof(buf); - } - - /* our SHA1 hasher's state is 32-Bit integers in host order. We must - * convert them */ - hasher = hasher_create(HASH_SHA1); - state_chunk = hasher->get_state(hasher); - state = (u_int32_t*)state_chunk.ptr; - iv = (u_int32_t*)t; - hash = (u_int32_t*)res; - state[0] = htonl(iv[0]); - state[1] = htonl(iv[1]); - state[2] = htonl(iv[2]); - state[3] = htonl(iv[3]); - hasher->get_hash(hasher, c, NULL); - hash[0] = htonl(state[0]); - hash[1] = htonl(state[1]); - hash[2] = htonl(state[2]); - hash[3] = htonl(state[3]); - hash[4] = htonl(state[4]); - hasher->destroy(hasher); -} - -/** - * Implementation of prf_t.destroy. - */ -static void destroy(private_fips_prf_t *this) -{ - free(this->key); - free(this); -} - -/* - * Described in header. - */ -fips_prf_t *fips_prf_create(size_t b, void(*g)(u_int8_t[],chunk_t,u_int8_t[])) -{ - private_fips_prf_t *this = malloc_thing(private_fips_prf_t); - - this->public.prf_interface.get_bytes = (void (*) (prf_t *,chunk_t,u_int8_t*))get_bytes; - this->public.prf_interface.allocate_bytes = (void (*) (prf_t*,chunk_t,chunk_t*))allocate_bytes; - this->public.prf_interface.get_block_size = (size_t (*) (prf_t*))get_block_size; - this->public.prf_interface.get_key_size = (size_t (*) (prf_t*))get_key_size; - this->public.prf_interface.set_key = (void (*) (prf_t *,chunk_t))set_key; - this->public.prf_interface.destroy = (void (*) (prf_t *))destroy; - - this->g = g; - this->b = b; - this->key = malloc(b); - - return &(this->public); -} diff --git a/src/libstrongswan/crypto/prfs/fips_prf.h b/src/libstrongswan/crypto/prfs/fips_prf.h deleted file mode 100644 index 283ee1f61..000000000 --- a/src/libstrongswan/crypto/prfs/fips_prf.h +++ /dev/null @@ -1,80 +0,0 @@ -/** - * @file fips_prf.h - * - * @brief Interface of fips_prf_t. - * - */ - -/* - * Copyright (C) 2006 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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 FIPS_PRF_H_ -#define FIPS_PRF_H_ - -typedef struct fips_prf_t fips_prf_t; - -#include -#include -#include - -/** - * @brief Implementation of prf_t using the FIPS 186-2-change1 standard. - * - * FIPS defines a "General Purpose Random Number Generator" (Revised - * Algorithm for Computing m values of x (Appendix 3.1 of FIPS 186-2)). This - * implementation is not intended for private key generation and therefore does - * not include the "mod q" operation (see FIPS 186-2-change1 p74). - * The FIPS PRF is stateful; the key changes every time when bytes are acquired. - * - * @b Constructors: - * - fips_prf_create() - * - prf_create() using one of the FIPS algorithms - * - * @ingroup prfs - */ -struct fips_prf_t { - - /** - * Generic prf_t interface for this fips_prf_t class. - */ - prf_t prf_interface; -}; - -/** - * @brief Creates a new fips_prf_t object. - * - * FIPS 186-2 defines G() functions used in the PRF function. It can - * be implemented either based on SHA1 or DES. - * - * @param b size of b (in bytes, not bits) - * @param g G() function to use (e.g. g_sha1) - * @return - * - fips_prf_t object - * - NULL if b invalid not supported - * - * @ingroup prfs - */ -fips_prf_t *fips_prf_create(size_t b, void(*g)(u_int8_t[],chunk_t,u_int8_t[])); - -/** - * @brief Implementation of the G() function based on SHA1. - * - * @param t initialization vector for SHA1 hasher, 20 bytes long - * @param c value to hash, not longer than 512 bit - * @param res result of G(), requries 20 bytes - */ -void g_sha1(u_int8_t t[], chunk_t c, u_int8_t res[]); - -#endif /* FIPS_PRF_H_ */ diff --git a/src/libstrongswan/crypto/prfs/hmac_prf.c b/src/libstrongswan/crypto/prfs/hmac_prf.c deleted file mode 100644 index f315f880d..000000000 --- a/src/libstrongswan/crypto/prfs/hmac_prf.c +++ /dev/null @@ -1,118 +0,0 @@ -/** - * @file hmac_prf.c - * - * @brief Implementation for hmac_prf_t. - * - */ - -/* - * Copyright (C) 2005-2006 Martin Willi - * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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 "hmac_prf.h" - -#include - - -typedef struct private_hmac_prf_t private_hmac_prf_t; - -/** - * Private data of a hma_prf_t object. - */ -struct private_hmac_prf_t { - /** - * Public hmac_prf_t interface. - */ - hmac_prf_t public; - - /** - * Hmac to use for generation. - */ - hmac_t *hmac; -}; - -/** - * Implementation of prf_t.get_bytes. - */ -static void get_bytes(private_hmac_prf_t *this, chunk_t seed, u_int8_t *buffer) -{ - this->hmac->get_mac(this->hmac, seed, buffer); -} - -/** - * Implementation of prf_t.allocate_bytes. - */ -static void allocate_bytes(private_hmac_prf_t *this, chunk_t seed, chunk_t *chunk) -{ - this->hmac->allocate_mac(this->hmac, seed, chunk); -} - -/** - * Implementation of prf_t.get_block_size. - */ -static size_t get_block_size(private_hmac_prf_t *this) -{ - return this->hmac->get_block_size(this->hmac); -} - -/** - * Implementation of prf_t.get_block_size. - */ -static size_t get_key_size(private_hmac_prf_t *this) -{ - /* for HMAC prfs, IKEv2 uses block size as key size */ - return this->hmac->get_block_size(this->hmac); -} - -/** - * Implementation of prf_t.set_key. - */ -static void set_key(private_hmac_prf_t *this, chunk_t key) -{ - this->hmac->set_key(this->hmac, key); -} - -/** - * Implementation of prf_t.destroy. - */ -static void destroy(private_hmac_prf_t *this) -{ - this->hmac->destroy(this->hmac); - free(this); -} - -/* - * Described in header. - */ -hmac_prf_t *hmac_prf_create(hash_algorithm_t hash_algorithm) -{ - private_hmac_prf_t *this = malloc_thing(private_hmac_prf_t); - - this->public.prf_interface.get_bytes = (void (*) (prf_t *,chunk_t,u_int8_t*))get_bytes; - this->public.prf_interface.allocate_bytes = (void (*) (prf_t*,chunk_t,chunk_t*))allocate_bytes; - this->public.prf_interface.get_block_size = (size_t (*) (prf_t*))get_block_size; - this->public.prf_interface.get_key_size = (size_t (*) (prf_t*))get_key_size; - this->public.prf_interface.set_key = (void (*) (prf_t *,chunk_t))set_key; - this->public.prf_interface.destroy = (void (*) (prf_t *))destroy; - - this->hmac = hmac_create(hash_algorithm); - if (this->hmac == NULL) - { - free(this); - return NULL; - } - - return &(this->public); -} diff --git a/src/libstrongswan/crypto/prfs/hmac_prf.h b/src/libstrongswan/crypto/prfs/hmac_prf.h deleted file mode 100644 index 9b06ee3a2..000000000 --- a/src/libstrongswan/crypto/prfs/hmac_prf.h +++ /dev/null @@ -1,65 +0,0 @@ -/** - * @file hmac_prf.h - * - * @brief Interface of hmac_prf_t. - * - */ - -/* - * Copyright (C) 2005-2006 Martin Willi - * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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 PRF_HMAC_H_ -#define PRF_HMAC_H_ - -typedef struct hmac_prf_t hmac_prf_t; - -#include -#include -#include - -/** - * @brief Implementation of prf_t interface using the - * HMAC algorithm. - * - * This simply wraps a hmac_t in a prf_t. More a question of - * interface matching. - * - * @b Constructors: - * - hmac_prf_create() - * - * @ingroup prfs - */ -struct hmac_prf_t { - - /** - * Generic prf_t interface for this hmac_prf_t class. - */ - prf_t prf_interface; -}; - -/** - * @brief Creates a new hmac_prf_t object. - * - * @param hash_algorithm hmac's hash algorithm - * @return - * - hmac_prf_t object - * - NULL if hash not supported - * - * @ingroup prfs - */ -hmac_prf_t *hmac_prf_create(hash_algorithm_t hash_algorithm); - -#endif /*PRF_HMAC_SHA1_H_*/ diff --git a/src/libstrongswan/crypto/prfs/prf.c b/src/libstrongswan/crypto/prfs/prf.c index f803829af..c1fa1e152 100644 --- a/src/libstrongswan/crypto/prfs/prf.c +++ b/src/libstrongswan/crypto/prfs/prf.c @@ -1,10 +1,3 @@ -/** - * @file prf.c - * - * @brief Generic constructor for all prf_t - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,15 +12,12 @@ * 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. + * + * $Id$ */ - #include "prf.h" -#include -#include -#include - ENUM_BEGIN(pseudo_random_function_names, PRF_UNDEFINED, PRF_FIPS_DES, "PRF_UNDEFINED", "PRF_FIPS_SHA1_160", @@ -42,29 +32,3 @@ ENUM_NEXT(pseudo_random_function_names, PRF_HMAC_MD5, PRF_HMAC_SHA2_512, PRF_FIP "PRF_HMAC_SHA2_512"); ENUM_END(pseudo_random_function_names, PRF_HMAC_SHA2_512); -/* - * Described in header. - */ -prf_t *prf_create(pseudo_random_function_t pseudo_random_function) -{ - switch (pseudo_random_function) - { - case PRF_HMAC_SHA1: - return (prf_t*)hmac_prf_create(HASH_SHA1); - case PRF_HMAC_MD5: - return (prf_t*)hmac_prf_create(HASH_MD5); - case PRF_HMAC_SHA2_256: - return (prf_t*)hmac_prf_create(HASH_SHA256); - case PRF_HMAC_SHA2_384: - return (prf_t*)hmac_prf_create(HASH_SHA384); - case PRF_HMAC_SHA2_512: - return (prf_t*)hmac_prf_create(HASH_SHA512); - case PRF_FIPS_SHA1_160: - return (prf_t*)fips_prf_create(20, g_sha1); - case PRF_FIPS_DES: - case PRF_HMAC_TIGER: - case PRF_AES128_CBC: - default: - return NULL; - } -} diff --git a/src/libstrongswan/crypto/prfs/prf.h b/src/libstrongswan/crypto/prfs/prf.h index 8560a4a9c..662a95938 100644 --- a/src/libstrongswan/crypto/prfs/prf.h +++ b/src/libstrongswan/crypto/prfs/prf.h @@ -1,10 +1,3 @@ -/** - * @file prf.h - * - * @brief Interface prf_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup prf prf + * @{ @ingroup crypto */ #ifndef PRF_H_ @@ -30,12 +30,10 @@ typedef struct prf_t prf_t; #include /** - * @brief Pseudo random function, as in IKEv2 RFC 3.3.2. + * Pseudo random function, as in IKEv2 RFC 3.3.2. * * PRF algorithms not defined in IKEv2 are allocated in "private use" * space. - * - * @ingroup prfs */ enum pseudo_random_function_t { PRF_UNDEFINED = 1024, @@ -63,80 +61,53 @@ enum pseudo_random_function_t { extern enum_name_t *pseudo_random_function_names; /** - * @brief Generic interface for pseudo-random-functions. - * - * @b Constructors: - * - prf_create() - * - hmac_prf_create() - * - * @todo Implement more prf algorithms - * - * @ingroup prfs + * Generic interface for pseudo-random-functions. */ struct prf_t { /** - * @brief Generates pseudo random bytes and writes them in the buffer. + * Generates pseudo random bytes and writes them in the buffer. * - * @param this calling object - * @param seed a chunk containing the seed for the next bytes - * @param[out] buffer pointer where the generated bytes will be written + * @param seed a chunk containing the seed for the next bytes + * @param buffer pointer where the generated bytes will be written */ void (*get_bytes) (prf_t *this, chunk_t seed, u_int8_t *buffer); /** - * @brief Generates pseudo random bytes and allocate space for them. + * Generates pseudo random bytes and allocate space for them. * - * @param this calling object - * @param seed a chunk containing the seed for the next bytes - * @param[out] chunk chunk which will hold generated bytes + * @param seed a chunk containing the seed for the next bytes + * @param chunk chunk which will hold generated bytes */ void (*allocate_bytes) (prf_t *this, chunk_t seed, chunk_t *chunk); /** - * @brief Get the block size of this prf_t object. + * Get the block size of this prf_t object. * - * @param this calling object - * @return block size in bytes + * @return block size in bytes */ size_t (*get_block_size) (prf_t *this); /** - * @brief Get the key size of this prf_t object. + * Get the key size of this prf_t object. * * This is a suggestion only, all implemented PRFs accept variable key * length. * - * @param this calling object - * @return key size in bytes + * @return key size in bytes */ size_t (*get_key_size) (prf_t *this); /** - * @brief Set the key for this prf_t object. + * Set the key for this prf_t object. * - * @param this calling object - * @param key key to set + * @param key key to set */ void (*set_key) (prf_t *this, chunk_t key); /** - * @brief Destroys a prf object. - * - * @param this calling object + * Destroys a prf object. */ void (*destroy) (prf_t *this); }; -/** - * @brief Generic constructor for a prf_t oject. - * - * @param pseudo_random_function Algorithm to use - * @return - * - prf_t object - * - NULL if prf algorithm not supported - * - * @ingroup prfs - */ -prf_t *prf_create(pseudo_random_function_t pseudo_random_function); - -#endif /*PRF_H_*/ +#endif /*PRF_H_ @} */ diff --git a/src/libstrongswan/crypto/rsa/rsa_private_key.c b/src/libstrongswan/crypto/rsa/rsa_private_key.c deleted file mode 100644 index 43f45e461..000000000 --- a/src/libstrongswan/crypto/rsa/rsa_private_key.c +++ /dev/null @@ -1,722 +0,0 @@ -/** - * @file rsa_private_key.c - * - * @brief Implementation of rsa_private_key_t. - * - */ - -/* - * Copyright (C) 2005 Jan Hutter - * Copyright (C) 2005-2006 Martin Willi - * Copyright (C) 2007-2008 Andreas Steffen - * - * 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 . - * - * 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. - * - * RCSID $Id$ - */ - -#include -#include -#include -#include - -#include "rsa_public_key.h" -#include "rsa_private_key.h" - -#include -#include -#include -#include - -/** - * defined in rsa_public_key.c - */ -extern chunk_t rsa_public_key_info_to_asn1(const mpz_t n, const mpz_t e); -extern chunk_t rsa_public_key_id_create(const mpz_t n, const mpz_t e); - -/** - * Public exponent to use for key generation. - */ -#define PUBLIC_EXPONENT 0x10001 - -typedef struct private_rsa_private_key_t private_rsa_private_key_t; - -/** - * Private data of a rsa_private_key_t object. - */ -struct private_rsa_private_key_t { - /** - * Public interface for this signer. - */ - rsa_private_key_t public; - - /** - * Version of key, as encoded in PKCS#1 - */ - u_int version; - - /** - * Public modulus. - */ - mpz_t n; - - /** - * Public exponent. - */ - mpz_t e; - - /** - * Private prime 1. - */ - mpz_t p; - - /** - * Private Prime 2. - */ - mpz_t q; - - /** - * Private exponent. - */ - mpz_t d; - - /** - * Private exponent 1. - */ - mpz_t exp1; - - /** - * Private exponent 2. - */ - mpz_t exp2; - - /** - * Private coefficient. - */ - mpz_t coeff; - - /** - * Keysize in bytes. - */ - size_t k; - - /** - * Keyid formed as a SHA-1 hash of a publicKeyInfo object - */ - chunk_t keyid; - - /** - * @brief Implements the RSADP algorithm specified in PKCS#1. - * - * @param this calling object - * @param data data to process - * @return processed data - */ - chunk_t (*rsadp) (private_rsa_private_key_t *this, chunk_t data); - - /** - * @brief Implements the RSASP1 algorithm specified in PKCS#1. - * @param this calling object - * @param data data to process - * @return processed data - */ - chunk_t (*rsasp1) (private_rsa_private_key_t *this, chunk_t data); -}; - -/* ASN.1 definition of a PKCS#1 RSA private key */ -static const asn1Object_t privkey_objects[] = { - { 0, "RSAPrivateKey", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ - { 1, "version", ASN1_INTEGER, ASN1_BODY }, /* 1 */ - { 1, "modulus", ASN1_INTEGER, ASN1_BODY }, /* 2 */ - { 1, "publicExponent", ASN1_INTEGER, ASN1_BODY }, /* 3 */ - { 1, "privateExponent", ASN1_INTEGER, ASN1_BODY }, /* 4 */ - { 1, "prime1", ASN1_INTEGER, ASN1_BODY }, /* 5 */ - { 1, "prime2", ASN1_INTEGER, ASN1_BODY }, /* 6 */ - { 1, "exponent1", ASN1_INTEGER, ASN1_BODY }, /* 7 */ - { 1, "exponent2", ASN1_INTEGER, ASN1_BODY }, /* 8 */ - { 1, "coefficient", ASN1_INTEGER, ASN1_BODY }, /* 9 */ - { 1, "otherPrimeInfos", ASN1_SEQUENCE, ASN1_OPT | - ASN1_LOOP }, /* 10 */ - { 2, "otherPrimeInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 11 */ - { 3, "prime", ASN1_INTEGER, ASN1_BODY }, /* 12 */ - { 3, "exponent", ASN1_INTEGER, ASN1_BODY }, /* 13 */ - { 3, "coefficient", ASN1_INTEGER, ASN1_BODY }, /* 14 */ - { 1, "end opt or loop", ASN1_EOC, ASN1_END } /* 15 */ -}; - -#define PRIV_KEY_VERSION 1 -#define PRIV_KEY_MODULUS 2 -#define PRIV_KEY_PUB_EXP 3 -#define PRIV_KEY_PRIV_EXP 4 -#define PRIV_KEY_PRIME1 5 -#define PRIV_KEY_PRIME2 6 -#define PRIV_KEY_EXP1 7 -#define PRIV_KEY_EXP2 8 -#define PRIV_KEY_COEFF 9 -#define PRIV_KEY_ROOF 16 - -/** - * Auxiliary function overwriting private key material with - * pseudo-random bytes before releasing it - */ -static void mpz_clear_randomized(mpz_t z) -{ - size_t len = mpz_size(z) * GMP_LIMB_BITS / BITS_PER_BYTE; - u_int8_t *random_bytes = alloca(len); - - randomizer_t *randomizer = randomizer_create(); - - randomizer->get_pseudo_random_bytes(randomizer, len, random_bytes); - - /* overwrite mpz_t with pseudo-random bytes before clearing it */ - mpz_import(z, len, 1, 1, 1, 0, random_bytes); - mpz_clear(z); - - randomizer->destroy(randomizer); -} - -/** - * Generate a random prime number with prime_len bytes - */ -static status_t compute_prime(private_rsa_private_key_t *this, size_t prime_len, mpz_t *prime) -{ - randomizer_t *randomizer; - chunk_t random_bytes; - status_t status; - - randomizer = randomizer_create(); - mpz_init(*prime); - - do - { - DBG1(" generating %d bit prime from %s ...", BITS_PER_BYTE * prime_len, DEV_RANDOM); - status = randomizer->allocate_random_bytes(randomizer, prime_len, &random_bytes); - if (status != SUCCESS) - { - randomizer->destroy(randomizer); - mpz_clear(*prime); - return FAILED; - } - - /* make sure most significant bit is set */ - random_bytes.ptr[0] = random_bytes.ptr[0] | 0x80; - - /* convert chunk to mpz value */ - mpz_import(*prime, random_bytes.len, 1, 1, 1, 0, random_bytes.ptr); - - /* get next prime */ - mpz_nextprime (*prime, *prime); - - /* free the random_bytes after overwriting them with a pseudo-random sequence */ - chunk_free_randomized(&random_bytes); - } - /* check if it isnt too large */ - while (((mpz_sizeinbase(*prime, 2) + 7) / BITS_PER_BYTE) > prime_len); - - randomizer->destroy(randomizer); - return SUCCESS; -} - -/** - * Implementation of private_rsa_private_key_t.rsadp and private_rsa_private_key_t.rsasp1. - */ -static chunk_t rsadp(private_rsa_private_key_t *this, chunk_t data) -{ - mpz_t t1, t2; - chunk_t decrypted; - - mpz_init(t1); - mpz_init(t2); - - mpz_import(t1, data.len, 1, 1, 1, 0, data.ptr); - - mpz_powm(t2, t1, this->exp1, this->p); /* m1 = c^dP mod p */ - mpz_powm(t1, t1, this->exp2, this->q); /* m2 = c^dQ mod Q */ - mpz_sub(t2, t2, t1); /* h = qInv (m1 - m2) mod p */ - mpz_mod(t2, t2, this->p); - mpz_mul(t2, t2, this->coeff); - mpz_mod(t2, t2, this->p); - - mpz_mul(t2, t2, this->q); /* m = m2 + h q */ - mpz_add(t1, t1, t2); - - decrypted.len = this->k; - decrypted.ptr = mpz_export(NULL, NULL, 1, decrypted.len, 1, 0, t1); - - mpz_clear_randomized(t1); - mpz_clear_randomized(t2); - - return decrypted; -} - -/** - * Implementation of rsa_private_key_t.pkcs1_decrypt. - */ -static status_t pkcs1_decrypt(private_rsa_private_key_t *this, - chunk_t in, chunk_t *out) -{ - status_t status = FAILED; - chunk_t em, em_ori; - - /* decrypt the input data */ - em = em_ori = this->rsadp(this, in); - - /* PKCS#1 v1.5 EME encryption formatting - * EM = 00 || 02 || PS || 00 || M - * PS = pseudo-random nonzero octets - */ - - /* check for magic bytes */ - if (*(em.ptr) != 0x00 || *(em.ptr+1) != 0x02) - { - DBG1("incorrect padding - probably wrong RSA key"); - goto end; - } - em.ptr += 2; - em.len -= 2; - - /* the plaintext data starts after first 0x00 byte */ - while (em.len-- > 0 && *em.ptr++ != 0x00); - - if (em.len == 0) - { - DBG1("no plaintext data found"); - goto end; - } - - *out = chunk_clone(em); - status = SUCCESS; - -end: - free(em_ori.ptr); - return status; -} - -/** - * Implementation of rsa_private_key_t.build_emsa_pkcs1_signature. - */ -static status_t build_emsa_pkcs1_signature(private_rsa_private_key_t *this, - hash_algorithm_t hash_algorithm, - chunk_t data, chunk_t *signature) -{ - hasher_t *hasher; - chunk_t em, digestInfo, hash; - int hash_oid = hasher_algorithm_to_oid(hash_algorithm); - - if (hash_oid == OID_UNKNOWN) - { - return NOT_SUPPORTED; - } - - /* get hasher */ - hasher = hasher_create(hash_algorithm); - if (hasher == NULL) - { - return NOT_SUPPORTED; - } - - /* build hash */ - hasher->allocate_hash(hasher, data, &hash); - hasher->destroy(hasher); - - /* build DER-encoded digestInfo */ - digestInfo = asn1_wrap(ASN1_SEQUENCE, "cm", - asn1_algorithmIdentifier(hash_oid), - asn1_simple_object(ASN1_OCTET_STRING, hash) - ); - chunk_free(&hash); - - /* build chunk to rsa-decrypt: - * EM = 0x00 || 0x01 || PS || 0x00 || T. - * PS = 0xFF padding, with length to fill em - * T = encoded_hash - */ - em.len = this->k; - em.ptr = malloc(em.len); - - /* fill em with padding */ - memset(em.ptr, 0xFF, em.len); - /* set magic bytes */ - *(em.ptr) = 0x00; - *(em.ptr+1) = 0x01; - *(em.ptr + em.len - digestInfo.len - 1) = 0x00; - /* set DER-encoded hash */ - memcpy(em.ptr + em.len - digestInfo.len, digestInfo.ptr, digestInfo.len); - - /* build signature */ - *signature = this->rsasp1(this, em); - - free(digestInfo.ptr); - free(em.ptr); - - return SUCCESS; -} - -/** - * Implementation of rsa_private_key_t.pkcs1_write. - */ -static bool pkcs1_write(private_rsa_private_key_t *this, const char *filename, bool force) -{ - bool status; - - chunk_t pkcs1 = asn1_wrap(ASN1_SEQUENCE, "cmmmmmmmm", - ASN1_INTEGER_0, - asn1_integer_from_mpz(this->n), - asn1_integer_from_mpz(this->e), - asn1_integer_from_mpz(this->d), - asn1_integer_from_mpz(this->p), - asn1_integer_from_mpz(this->q), - asn1_integer_from_mpz(this->exp1), - asn1_integer_from_mpz(this->exp2), - asn1_integer_from_mpz(this->coeff)); - - status = chunk_write(pkcs1, filename, "pkcs1", 0066, force); - chunk_free_randomized(&pkcs1); - return status; -} - -/** - * Implementation of rsa_private_key_t.get_public_key. - */ -rsa_public_key_t *get_public_key(private_rsa_private_key_t *this) -{ - return rsa_public_key_create(this->n, this->e); -} - -/** - * Implementation of rsa_private_key.belongs_to. - */ -static bool belongs_to(private_rsa_private_key_t *this, rsa_public_key_t *public) -{ - return chunk_equals(this->keyid, public->get_keyid(public)); -} - -/** - * Check the loaded key if it is valid and usable - * TODO: Log errors - */ -static status_t check(private_rsa_private_key_t *this) -{ - mpz_t t, u, q1; - status_t status = SUCCESS; - - /* PKCS#1 1.5 section 6 requires modulus to have at least 12 octets. - * We actually require more (for security). - */ - if (this->k < 512 / BITS_PER_BYTE) - { - return FAILED; - } - - /* we picked a max modulus size to simplify buffer allocation */ - if (this->k > 8192 / BITS_PER_BYTE) - { - return FAILED; - } - - mpz_init(t); - mpz_init(u); - mpz_init(q1); - - /* check that n == p * q */ - mpz_mul(u, this->p, this->q); - if (mpz_cmp(u, this->n) != 0) - { - status = FAILED; - } - - /* check that e divides neither p-1 nor q-1 */ - mpz_sub_ui(t, this->p, 1); - mpz_mod(t, t, this->e); - if (mpz_cmp_ui(t, 0) == 0) - { - status = FAILED; - } - - mpz_sub_ui(t, this->q, 1); - mpz_mod(t, t, this->e); - if (mpz_cmp_ui(t, 0) == 0) - { - status = FAILED; - } - - /* check that d is e^-1 (mod lcm(p-1, q-1)) */ - /* see PKCS#1v2, aka RFC 2437, for the "lcm" */ - mpz_sub_ui(q1, this->q, 1); - mpz_sub_ui(u, this->p, 1); - mpz_gcd(t, u, q1); /* t := gcd(p-1, q-1) */ - mpz_mul(u, u, q1); /* u := (p-1) * (q-1) */ - mpz_divexact(u, u, t); /* u := lcm(p-1, q-1) */ - - mpz_mul(t, this->d, this->e); - mpz_mod(t, t, u); - if (mpz_cmp_ui(t, 1) != 0) - { - status = FAILED; - } - - /* check that exp1 is d mod (p-1) */ - mpz_sub_ui(u, this->p, 1); - mpz_mod(t, this->d, u); - if (mpz_cmp(t, this->exp1) != 0) - { - status = FAILED; - } - - /* check that exp2 is d mod (q-1) */ - mpz_sub_ui(u, this->q, 1); - mpz_mod(t, this->d, u); - if (mpz_cmp(t, this->exp2) != 0) - { - status = FAILED; - } - - /* check that coeff is (q^-1) mod p */ - mpz_mul(t, this->coeff, this->q); - mpz_mod(t, t, this->p); - if (mpz_cmp_ui(t, 1) != 0) - { - status = FAILED; - } - - mpz_clear_randomized(t); - mpz_clear_randomized(u); - mpz_clear_randomized(q1); - return status; -} - -/** - * Implementation of rsa_private_key.destroy. - */ -static void destroy(private_rsa_private_key_t *this) -{ - mpz_clear_randomized(this->n); - mpz_clear_randomized(this->e); - mpz_clear_randomized(this->p); - mpz_clear_randomized(this->q); - mpz_clear_randomized(this->d); - mpz_clear_randomized(this->exp1); - mpz_clear_randomized(this->exp2); - mpz_clear_randomized(this->coeff); - chunk_free_randomized(&this->keyid); - free(this); -} - -/** - * Internal generic constructor - */ -static private_rsa_private_key_t *rsa_private_key_create_empty(void) -{ - private_rsa_private_key_t *this = malloc_thing(private_rsa_private_key_t); - - /* public functions */ - this->public.pkcs1_decrypt = (status_t (*) (rsa_private_key_t*,chunk_t,chunk_t*))pkcs1_decrypt; - this->public.build_emsa_pkcs1_signature = (status_t (*) (rsa_private_key_t*,hash_algorithm_t,chunk_t,chunk_t*))build_emsa_pkcs1_signature; - this->public.pkcs1_write = (bool (*) (rsa_private_key_t*,const char*,bool))pkcs1_write; - this->public.get_public_key = (rsa_public_key_t* (*) (rsa_private_key_t*))get_public_key; - this->public.belongs_to = (bool (*) (rsa_private_key_t*,rsa_public_key_t*))belongs_to; - this->public.destroy = (void (*) (rsa_private_key_t*))destroy; - - /* private functions */ - this->rsadp = rsadp; - this->rsasp1 = rsadp; /* same algorithm */ - - this->keyid = chunk_empty; - - return this; -} - -/* - * See header - */ -rsa_private_key_t *rsa_private_key_create(size_t key_size) -{ - mpz_t p, q, n, e, d, exp1, exp2, coeff; - mpz_t m, q1, t; - private_rsa_private_key_t *this; - size_t key_len = key_size / BITS_PER_BYTE; - size_t prime_len = key_len / 2; - - /* Get values of primes p and q */ - if (compute_prime(this, prime_len, &p) != SUCCESS) - { - return NULL; - } - if (compute_prime(this, prime_len, &q) != SUCCESS) - { - mpz_clear(p); - return NULL; - } - - mpz_init(t); - mpz_init(n); - mpz_init(d); - mpz_init(exp1); - mpz_init(exp2); - mpz_init(coeff); - - /* Swapping Primes so p is larger then q */ - if (mpz_cmp(p, q) < 0) - { - mpz_swap(p, q); - } - - mpz_mul(n, p, q); /* n = p*q */ - mpz_init_set_ui(e, PUBLIC_EXPONENT); /* assign public exponent */ - mpz_init_set(m, p); /* m = p */ - mpz_sub_ui(m, m, 1); /* m = m -1 */ - mpz_init_set(q1, q); /* q1 = q */ - mpz_sub_ui(q1, q1, 1); /* q1 = q1 -1 */ - mpz_gcd(t, m, q1); /* t = gcd(p-1, q-1) */ - mpz_mul(m, m, q1); /* m = (p-1)*(q-1) */ - mpz_divexact(m, m, t); /* m = m / t */ - mpz_gcd(t, m, e); /* t = gcd(m, e) (greatest common divisor) */ - - mpz_invert(d, e, m); /* e has an inverse mod m */ - if (mpz_cmp_ui(d, 0) < 0) /* make sure d is positive */ - { - mpz_add(d, d, m); - } - mpz_sub_ui(t, p, 1); /* t = p-1 */ - mpz_mod(exp1, d, t); /* exp1 = d mod p-1 */ - mpz_sub_ui(t, q, 1); /* t = q-1 */ - mpz_mod(exp2, d, t); /* exp2 = d mod q-1 */ - - mpz_invert(coeff, q, p); /* coeff = q^-1 mod p */ - if (mpz_cmp_ui(coeff, 0) < 0) /* make coeff d is positive */ - { - mpz_add(coeff, coeff, p); - } - - mpz_clear_randomized(q1); - mpz_clear_randomized(m); - mpz_clear_randomized(t); - - /* determine exact the modulus size in bits */ - key_size = mpz_sizeinbase(n, 2); - - /* create and fill in rsa_private_key_t object */ - this = rsa_private_key_create_empty(); - this->k = (key_size + 7) / BITS_PER_BYTE; - this->keyid = rsa_public_key_id_create(n, e); - *(this->p) = *p; - *(this->q) = *q; - *(this->n) = *n; - *(this->e) = *e; - *(this->d) = *d; - *(this->exp1) = *exp1; - *(this->exp2) = *exp2; - *(this->coeff) = *coeff; - DBG1("generated %d bit RSA key with keyid: %#B", key_size, &this->keyid); - - return &this->public; -} - -/* - * see header - */ -rsa_private_key_t *rsa_private_key_create_from_chunk(chunk_t blob) -{ - asn1_ctx_t ctx; - chunk_t object; - u_int level; - int objectID = 0; - private_rsa_private_key_t *this; - - this = rsa_private_key_create_empty(); - - mpz_init(this->n); - mpz_init(this->e); - mpz_init(this->p); - mpz_init(this->q); - mpz_init(this->d); - mpz_init(this->exp1); - mpz_init(this->exp2); - mpz_init(this->coeff); - - asn1_init(&ctx, blob, 0, FALSE, TRUE); - - while (objectID < PRIV_KEY_ROOF) - { - if (!extract_object(privkey_objects, &objectID, &object, &level, &ctx)) - { - destroy(this); - return FALSE; - } - switch (objectID) - { - case PRIV_KEY_VERSION: - if (object.len > 0 && *object.ptr != 0) - { - destroy(this); - return NULL; - } - break; - case PRIV_KEY_MODULUS: - mpz_import(this->n, object.len, 1, 1, 1, 0, object.ptr); - break; - case PRIV_KEY_PUB_EXP: - mpz_import(this->e, object.len, 1, 1, 1, 0, object.ptr); - break; - case PRIV_KEY_PRIV_EXP: - mpz_import(this->d, object.len, 1, 1, 1, 0, object.ptr); - break; - case PRIV_KEY_PRIME1: - mpz_import(this->p, object.len, 1, 1, 1, 0, object.ptr); - break; - case PRIV_KEY_PRIME2: - mpz_import(this->q, object.len, 1, 1, 1, 0, object.ptr); - break; - case PRIV_KEY_EXP1: - mpz_import(this->exp1, object.len, 1, 1, 1, 0, object.ptr); - break; - case PRIV_KEY_EXP2: - mpz_import(this->exp2, object.len, 1, 1, 1, 0, object.ptr); - break; - case PRIV_KEY_COEFF: - mpz_import(this->coeff, object.len, 1, 1, 1, 0, object.ptr); - break; - } - objectID++; - } - - this->k = (mpz_sizeinbase(this->n, 2) + 7) / BITS_PER_BYTE; - this->keyid = rsa_public_key_id_create(this->n, this->e); - - if (check(this) != SUCCESS) - { - destroy(this); - return NULL; - } - else - { - return &this->public; - } -} - -/* - * see header - */ -rsa_private_key_t *rsa_private_key_create_from_file(char *filename, chunk_t *passphrase) -{ - bool pgp = FALSE; - chunk_t chunk = chunk_empty; - rsa_private_key_t *key = NULL; - - if (!pem_asn1_load_file(filename, passphrase, "private key", &chunk, &pgp)) - return NULL; - - key = rsa_private_key_create_from_chunk(chunk); - chunk_free_randomized(&chunk); - return key; -} diff --git a/src/libstrongswan/crypto/rsa/rsa_private_key.h b/src/libstrongswan/crypto/rsa/rsa_private_key.h deleted file mode 100644 index 5f6645809..000000000 --- a/src/libstrongswan/crypto/rsa/rsa_private_key.h +++ /dev/null @@ -1,163 +0,0 @@ -/** - * @file rsa_private_key.h - * - * @brief Interface of rsa_private_key_t. - * - */ - -/* - * Copyright (C) 2005 Jan Hutter - * Copyright (C) 2005-2006 Martin Willi - * Copyright (C) 2007-2008 Andreas Steffen - * - * 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 . - * - * 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. - * - * RCSID $Id$ - */ - -#ifndef RSA_PRIVATE_KEY_H_ -#define RSA_PRIVATE_KEY_H_ - -typedef struct rsa_private_key_t rsa_private_key_t; - -#include -#include -#include - -/** - * @brief RSA private key with associated functions. - * - * Currently only supports signing using EMSA encoding. - * - * @b Constructors: - * - rsa_private_key_create() - * - rsa_private_key_create_from_chunk() - * - rsa_private_key_create_from_file() - * - * @see rsa_public_key_t - * - * @ingroup rsa - */ -struct rsa_private_key_t { - - /** - * @brief Decrypt a data block based on EME-PKCS1 encoding. - * - * - * @param this calling object - * @param data encrypted input data - * @param out decrypted output data - * @return - * - SUCCESS - * - FAILED if padding is not correct - */ - status_t (*pkcs1_decrypt) (rsa_private_key_t *this, chunk_t in, chunk_t *out); - - /** - * @brief Build a signature over a chunk using EMSA-PKCS1 encoding. - * - * This signature creates a hash using the specified hash algorithm, concatenates - * it with an ASN1-OID of the hash algorithm and runs the RSASP1 function - * on it. - * - * @param this calling object - * @param hash_algorithm hash algorithm to use for hashing - * @param data data to sign - * @param[out] signature allocated signature - * @return - * - SUCCESS - * - INVALID_STATE, if key not set - * - NOT_SUPPORTED, if hash algorithm not supported - */ - status_t (*build_emsa_pkcs1_signature) (rsa_private_key_t *this, hash_algorithm_t hash_algorithm, chunk_t data, chunk_t *signature); - - /** - * @brief Writes an RSA private key to a file in PKCS#1 format. - * - * @param this calling object - * @param filename file to which the key should be written. - * @param force if TRUE overwrite existing file - * @return TRUE if successful - FALSE otherwise - */ - bool (*pkcs1_write) (rsa_private_key_t *this, const char *filename, bool force); - - /** - * @brief Create a rsa_public_key_t with the public part of the key. - * - * @param this calling object - * @return public_key - */ - rsa_public_key_t *(*get_public_key) (rsa_private_key_t *this); - - /** - * @brief Check if a private key belongs to a public key. - * - * Compares the public part of the private key with the - * public key, return TRUE if it equals. - * - * @param this private key - * @param public public key - * @return TRUE, if keys belong together - */ - bool (*belongs_to) (rsa_private_key_t *this, rsa_public_key_t *public); - - /** - * @brief Destroys the private key. - * - * @param this private key to destroy - */ - void (*destroy) (rsa_private_key_t *this); -}; - -/** - * @brief Generate a new RSA key with specified key length. - * - * @param key_size size of the key in bits - * @return generated rsa_private_key_t. - * - * @ingroup rsa - */ -rsa_private_key_t *rsa_private_key_create(size_t key_size); - -/** - * @brief Load an RSA private key from a chunk. - * - * Load a key from a chunk, encoded as described in PKCS#1 - * (ASN1 DER encoded). - * - * @param chunk chunk containing the DER encoded key - * @return loaded rsa_private_key_t, or NULL - * - * @ingroup rsa - */ -rsa_private_key_t *rsa_private_key_create_from_chunk(chunk_t chunk); - -/** - * @brief Load an RSA private key from a file. - * - * Load a key from a file, which is either in a unencrypted binary - * format (DER), or in a (encrypted) PEM format. The supplied - * passphrase is used to decrypt an ecrypted key. - * - * @param filename filename which holds the key - * @param passphrase optional passphase for decryption, can be NULL - * @return loaded rsa_private_key_t, or NULL - * - * @todo Implement PEM file loading - * @todo Implement key decryption - * - * @ingroup rsa - */ -rsa_private_key_t *rsa_private_key_create_from_file(char *filename, chunk_t *passphrase); - -#endif /*RSA_PRIVATE_KEY_H_*/ diff --git a/src/libstrongswan/crypto/rsa/rsa_public_key.c b/src/libstrongswan/crypto/rsa/rsa_public_key.c deleted file mode 100644 index 16ac3bbbd..000000000 --- a/src/libstrongswan/crypto/rsa/rsa_public_key.c +++ /dev/null @@ -1,516 +0,0 @@ -/** - * @file rsa_public_key.c - * - * @brief Implementation of rsa_public_key_t. - * - */ - -/* - * Copyright (C) 2005 Jan Hutter - * Copyright (C) 2005-2006 Martin Willi - * Copyright (C) 2007-2008 Andreas Steffen - * - * 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 . - * - * 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. - * - * RCSID $Id$ - */ - -#include -#include -#include -#include -#include - -#include "rsa_public_key.h" - -#include -#include -#include -#include -#include - -/* ASN.1 definition of RSApublicKey */ -static const asn1Object_t pubkeyObjects[] = { - { 0, "RSAPublicKey", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */ - { 1, "modulus", ASN1_INTEGER, ASN1_BODY }, /* 1 */ - { 1, "publicExponent", ASN1_INTEGER, ASN1_BODY }, /* 2 */ -}; - -#define PUB_KEY_RSA_PUBLIC_KEY 0 -#define PUB_KEY_MODULUS 1 -#define PUB_KEY_EXPONENT 2 -#define PUB_KEY_ROOF 3 - -/* ASN.1 definition of digestInfo */ -static const asn1Object_t digestInfoObjects[] = { - { 0, "digestInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */ - { 1, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 1 */ - { 1, "digest", ASN1_OCTET_STRING, ASN1_BODY }, /* 2 */ -}; - -#define DIGEST_INFO 0 -#define DIGEST_INFO_ALGORITHM 1 -#define DIGEST_INFO_DIGEST 2 -#define DIGEST_INFO_ROOF 3 - -typedef struct private_rsa_public_key_t private_rsa_public_key_t; - -/** - * Private data structure with signing context. - */ -struct private_rsa_public_key_t { - /** - * Public interface for this signer. - */ - rsa_public_key_t public; - - /** - * Public modulus. - */ - mpz_t n; - - /** - * Public exponent. - */ - mpz_t e; - - /** - * Keysize in bytes. - */ - size_t k; - - /** - * Keyid formed as a SHA-1 hash of a publicKeyInfo object - */ - chunk_t keyid; - - /** - * @brief Implements the RSAEP algorithm specified in PKCS#1. - * - * @param this calling object - * @param data data to process - * @return processed data - */ - chunk_t (*rsaep) (const private_rsa_public_key_t *this, chunk_t data); - - /** - * @brief Implements the RSASVP1 algorithm specified in PKCS#1. - * - * @param this calling object - * @param data data to process - * @return processed data - */ - chunk_t (*rsavp1) (const private_rsa_public_key_t *this, chunk_t data); -}; - -/** - * Implementation of private_rsa_public_key_t.rsaep and private_rsa_public_key_t.rsavp1 - */ -static chunk_t rsaep(const private_rsa_public_key_t *this, chunk_t data) -{ - mpz_t m, c; - chunk_t encrypted; - - mpz_init(c); - mpz_init(m); - - mpz_import(m, data.len, 1, 1, 1, 0, data.ptr); - - mpz_powm(c, m, this->e, this->n); - - encrypted.len = this->k; - encrypted.ptr = mpz_export(NULL, NULL, 1, encrypted.len, 1, 0, c); - - mpz_clear(c); - mpz_clear(m); - - return encrypted; -} - -/** - * Implementation of rsa_public_key_t.eme_pkcs1_encrypt. - */ -static status_t pkcs1_encrypt(private_rsa_public_key_t *this, - chunk_t in, chunk_t *out) -{ - chunk_t em; - u_char *pos; - int padding = this->k - in.len - 3; - - if (padding < 8) - { - DBG1("rsa padding of %d bytes is too small", padding); - return FAILED; - } - em.len = this->k; - em.ptr = pos = malloc(em.len); - - /* add padding according to PKCS#1 7.2.1 1.+2. */ - *pos++ = 0x00; - *pos++ = 0x02; - - /* pad with pseudo random bytes unequal to zero */ - { - randomizer_t *randomizer = randomizer_create(); - - /* pad with pseudo random bytes unequal to zero */ - while (padding--) - { - randomizer->get_pseudo_random_bytes(randomizer, 1, pos); - while (!*pos) - { - randomizer->get_pseudo_random_bytes(randomizer, 1, pos); - } - pos++; - } - randomizer->destroy(randomizer); - } - - /* append the padding terminator */ - *pos++ = 0x00; - - /* now add the data */ - memcpy(pos, in.ptr, in.len); - *out = this->rsaep(this, em); - free(em.ptr); - return SUCCESS; -} - -/** - * Implementation of rsa_public_key.verify_emsa_pkcs1_signature. - */ -static status_t verify_emsa_pkcs1_signature(const private_rsa_public_key_t *this, - hash_algorithm_t algorithm, - chunk_t data, chunk_t signature) -{ - chunk_t em_ori, em; - status_t res = FAILED; - - /* remove any preceding 0-bytes from signature */ - while (signature.len && *(signature.ptr) == 0x00) - { - signature.len -= 1; - signature.ptr++; - } - - if (signature.len > this->k) - { - return INVALID_ARG; - } - - /* unpack signature */ - em_ori = em = this->rsavp1(this, signature); - - /* result should look like this: - * EM = 0x00 || 0x01 || PS || 0x00 || T. - * PS = 0xFF padding, with length to fill em - * T = oid || hash - */ - - /* check magic bytes */ - if (*(em.ptr) != 0x00 || *(em.ptr+1) != 0x01) - { - DBG2("incorrect padding - probably wrong RSA key"); - goto end; - } - em.ptr += 2; - em.len -= 2; - - /* find magic 0x00 */ - while (em.len > 0) - { - if (*em.ptr == 0x00) - { - /* found magic byte, stop */ - em.ptr++; - em.len--; - break; - } - else if (*em.ptr != 0xFF) - { - /* bad padding, decryption failed ?!*/ - goto end; - } - em.ptr++; - em.len--; - } - - if (em.len == 0) - { - /* no digestInfo found */ - goto end; - } - - /* parse ASN.1-based digestInfo */ - { - asn1_ctx_t ctx; - chunk_t object; - u_int level; - int objectID = 0; - hash_algorithm_t hash_algorithm = HASH_UNKNOWN; - - asn1_init(&ctx, em, 0, FALSE, FALSE); - - while (objectID < DIGEST_INFO_ROOF) - { - if (!extract_object(digestInfoObjects, &objectID, &object, &level, &ctx)) - { - goto end; - } - switch (objectID) - { - case DIGEST_INFO: - if (em.len > object.len) - { - DBG1("digestInfo field in signature is followed by %u surplus bytes", - em.len - object.len); - goto end; - } - break; - case DIGEST_INFO_ALGORITHM: - { - int hash_oid = parse_algorithmIdentifier(object, level+1, NULL); - - hash_algorithm = hasher_algorithm_from_oid(hash_oid); - if (hash_algorithm == HASH_UNKNOWN - || (algorithm != HASH_UNKNOWN && hash_algorithm != algorithm)) - { - DBG1("wrong hash algorithm used in signature"); - goto end; - } - } - break; - case DIGEST_INFO_DIGEST: - { - chunk_t hash; - hasher_t *hasher = hasher_create(hash_algorithm); - - if (object.len != hasher->get_hash_size(hasher)) - { - DBG1("hash size in signature is %u bytes instead of %u bytes", - object.len, hasher->get_hash_size(hasher)); - hasher->destroy(hasher); - goto end; - } - - /* build our own hash */ - hasher->allocate_hash(hasher, data, &hash); - hasher->destroy(hasher); - - /* compare the hashes */ - res = memeq(object.ptr, hash.ptr, hash.len) ? SUCCESS : FAILED; - free(hash.ptr); - } - break; - default: - break; - } - objectID++; - } - } - -end: - free(em_ori.ptr); - return res; -} - - -/** - * Implementation of rsa_public_key_t.get_modulus. - */ -static mpz_t *get_modulus(const private_rsa_public_key_t *this) -{ - return (mpz_t*)&this->n; -} - -/** - * Implementation of rsa_public_key_t.get_keysize. - */ -static size_t get_keysize(const private_rsa_public_key_t *this) -{ - return this->k; -} - -/** - * Build a DER-encoded publicKeyInfo object from an RSA public key. - * Also used in rsa_private_key.c. - */ -chunk_t rsa_public_key_info_to_asn1(const mpz_t n, const mpz_t e) -{ - chunk_t publicKey = asn1_wrap(ASN1_SEQUENCE, "mm", - asn1_integer_from_mpz(n), - asn1_integer_from_mpz(e)); - - return asn1_wrap(ASN1_SEQUENCE, "cm", - asn1_algorithmIdentifier(OID_RSA_ENCRYPTION), - asn1_bitstring("m", publicKey)); -} - -/** - * Form the RSA keyid as a SHA-1 hash of a publicKeyInfo object - * Also used in rsa_private_key.c. - */ -chunk_t rsa_public_key_id_create(mpz_t n, mpz_t e) -{ - chunk_t keyid; - chunk_t publicKeyInfo = rsa_public_key_info_to_asn1(n, e); - hasher_t *hasher = hasher_create(HASH_SHA1); - - hasher->allocate_hash(hasher, publicKeyInfo, &keyid); - hasher->destroy(hasher); - free(publicKeyInfo.ptr); - - return keyid; -} - -/** - * Implementation of rsa_public_key_t.get_publicKeyInfo. - */ -static chunk_t get_publicKeyInfo(const private_rsa_public_key_t *this) -{ - return rsa_public_key_info_to_asn1(this->n, this->e); -} - -/** - * Implementation of rsa_public_key_t.get_keyid. - */ -static chunk_t get_keyid(const private_rsa_public_key_t *this) -{ - return this->keyid; -} - -/* forward declaration used by rsa_public_key_t.clone */ -private_rsa_public_key_t *rsa_public_key_create_empty(void); - -/** - * Implementation of rsa_public_key_t.clone. - */ -static rsa_public_key_t* _clone(const private_rsa_public_key_t *this) -{ - private_rsa_public_key_t *clone = rsa_public_key_create_empty(); - - mpz_init_set(clone->n, this->n); - mpz_init_set(clone->e, this->e); - clone->keyid = chunk_clone(this->keyid); - clone->k = this->k; - - return &clone->public; -} - -/** - * Implementation of rsa_public_key_t.destroy. - */ -static void destroy(private_rsa_public_key_t *this) -{ - mpz_clear(this->n); - mpz_clear(this->e); - free(this->keyid.ptr); - free(this); -} - -/** - * Generic private constructor - */ -private_rsa_public_key_t *rsa_public_key_create_empty(void) -{ - private_rsa_public_key_t *this = malloc_thing(private_rsa_public_key_t); - - /* public functions */ - this->public.pkcs1_encrypt = (status_t (*) (rsa_public_key_t*,chunk_t,chunk_t*))pkcs1_encrypt; - this->public.verify_emsa_pkcs1_signature = (status_t (*) (const rsa_public_key_t*,hash_algorithm_t,chunk_t,chunk_t))verify_emsa_pkcs1_signature; - this->public.get_modulus = (mpz_t *(*) (const rsa_public_key_t*))get_modulus; - this->public.get_keysize = (size_t (*) (const rsa_public_key_t*))get_keysize; - this->public.get_publicKeyInfo = (chunk_t (*) (const rsa_public_key_t*))get_publicKeyInfo; - this->public.get_keyid = (chunk_t (*) (const rsa_public_key_t*))get_keyid; - this->public.clone = (rsa_public_key_t* (*) (const rsa_public_key_t*))_clone; - this->public.destroy = (void (*) (rsa_public_key_t*))destroy; - - /* private functions */ - this->rsaep = rsaep; - this->rsavp1 = rsaep; /* same algorithm */ - - return this; -} - -/* - * See header - */ -rsa_public_key_t *rsa_public_key_create(mpz_t n, mpz_t e) -{ - private_rsa_public_key_t *this = rsa_public_key_create_empty(); - - mpz_init_set(this->n, n); - mpz_init_set(this->e, e); - - this->k = (mpz_sizeinbase(n, 2) + 7) / BITS_PER_BYTE; - this->keyid = rsa_public_key_id_create(n, e); - return &this->public; -} -/* - * See header - */ -rsa_public_key_t *rsa_public_key_create_from_chunk(chunk_t blob) -{ - asn1_ctx_t ctx; - chunk_t object; - u_int level; - int objectID = 0; - - private_rsa_public_key_t *this = rsa_public_key_create_empty(); - - mpz_init(this->n); - mpz_init(this->e); - - asn1_init(&ctx, blob, 0, FALSE, FALSE); - - while (objectID < PUB_KEY_ROOF) - { - if (!extract_object(pubkeyObjects, &objectID, &object, &level, &ctx)) - { - destroy(this); - return FALSE; - } - switch (objectID) - { - case PUB_KEY_MODULUS: - mpz_import(this->n, object.len, 1, 1, 1, 0, object.ptr); - break; - case PUB_KEY_EXPONENT: - mpz_import(this->e, object.len, 1, 1, 1, 0, object.ptr); - break; - } - objectID++; - } - - this->k = (mpz_sizeinbase(this->n, 2) + 7) / BITS_PER_BYTE; - this->keyid = rsa_public_key_id_create(this->n, this->e); - return &this->public; -} - -/* - * See header - */ -rsa_public_key_t *rsa_public_key_create_from_file(char *filename) -{ - bool pgp = FALSE; - chunk_t chunk = chunk_empty; - rsa_public_key_t *pubkey = NULL; - - if (!pem_asn1_load_file(filename, NULL, "public key", &chunk, &pgp)) - { - return NULL; - } - pubkey = rsa_public_key_create_from_chunk(chunk); - free(chunk.ptr); - return pubkey; -} diff --git a/src/libstrongswan/crypto/rsa/rsa_public_key.h b/src/libstrongswan/crypto/rsa/rsa_public_key.h deleted file mode 100644 index 1c15169fd..000000000 --- a/src/libstrongswan/crypto/rsa/rsa_public_key.h +++ /dev/null @@ -1,173 +0,0 @@ -/** - * @file rsa_public_key.h - * - * @brief Interface of rsa_public_key_t. - * - */ - -/* - * Copyright (C) 2005 Jan Hutter - * Copyright (C) 2005-2006 Martin Willi - * Copyright (C) 2007-2008 Andreas Steffen - * - * 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 . - * - * 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. - * - * RCSID $Id$ - */ - -#ifndef RSA_PUBLIC_KEY_H_ -#define RSA_PUBLIC_KEY_H_ - -typedef struct rsa_public_key_t rsa_public_key_t; - -#include - -#include -#include - -/** - * @brief RSA public key with associated functions. - * - * Currently only supports signature verification using - * the EMSA encoding (see PKCS1) - * - * @b Constructors: - * - rsa_public_key_create() - * - rsa_public_key_create_from_chunk() - * - rsa_public_key_create_from_file() - * - * @ingroup rsa - */ -struct rsa_public_key_t { - - /** - * @brief Encrypt a data block using EME-PKCS1 encoding. - * - * - * @param this calling object - * @param data plaintext input data - * @param out encrypted output data - * @return - * - SUCCESS - * - FAILED if data block is too large - */ - status_t (*pkcs1_encrypt) (rsa_public_key_t *this, chunk_t in, chunk_t *out); - - /** - * @brief Verify an EMSA-PKCS1 encoded signature. - * - * Processes the supplied signature with the RSAVP1 function, - * selects the hash algorithm form the resultign ASN1-OID and - * verifies the hash against the supplied data. - * - * @param this rsa_public_key to use - * @param data data to sign - # @param algorithm hash algorithm the signature is based on - * @param signature signature to verify - * @return - * - SUCCESS, if signature ok - * - INVALID_STATE, if key not set - * - NOT_SUPPORTED, if hash algorithm not supported - * - INVALID_ARG, if signature is not a signature - * - FAILED if signature invalid or unable to verify - */ - status_t (*verify_emsa_pkcs1_signature) (const rsa_public_key_t *this, - hash_algorithm_t algorithm, - chunk_t data, chunk_t signature); - - /** - * @brief Get the modulus of the key. - * - * @param this calling object - * @return modulus (n) of the key - */ - mpz_t *(*get_modulus) (const rsa_public_key_t *this); - - /** - * @brief Get the size of the modulus in bytes. - * - * @param this calling object - * @return size of the modulus (n) in bytes - */ - size_t (*get_keysize) (const rsa_public_key_t *this); - - /** - * @brief Get the DER encoded publicKeyInfo object. - * - * @param this calling object - * @return DER encoded publicKeyInfo object - */ - chunk_t (*get_publicKeyInfo) (const rsa_public_key_t *this); - - /** - * @brief Get the keyid formed as the SHA-1 hash of a publicKeyInfo object. - * - * @param this calling object - * @return keyid in the form of a SHA-1 hash - */ - chunk_t (*get_keyid) (const rsa_public_key_t *this); - - /** - * @brief Clone the public key. - * - * @param this public key to clone - * @return clone of this - */ - rsa_public_key_t *(*clone) (const rsa_public_key_t *this); - - /** - * @brief Destroys the public key. - * - * @param this public key to destroy - */ - void (*destroy) (rsa_public_key_t *this); -}; - -/** - * @brief Create a RSA public key from modulus and public exponent. - * - * @param n modulus - * @param e public exponent - * @return created rsa_public_key_t - * - * @ingroup rsa - */ -rsa_public_key_t *rsa_public_key_create(mpz_t n, mpz_t e); - -/** - * @brief Load an RSA public key from a chunk. - * - * Load a key from a chunk, encoded in the more frequently - * used publicKeyInfo object (ASN1 DER encoded). - * - * @param chunk chunk containing the DER encoded key - * @return loaded rsa_public_key_t, or NULL - * - * @ingroup rsa - */ -rsa_public_key_t *rsa_public_key_create_from_chunk(chunk_t chunk); - -/** - * @brief Load an RSA public key from a file. - * - * Load a key from a file, which is either in binary - * format (DER), or in PEM format. - * - * @param filename filename which holds the key - * @return loaded rsa_public_key_t, or NULL - * - * @ingroup rsa - */ -rsa_public_key_t *rsa_public_key_create_from_file(char *filename); - -#endif /*RSA_PUBLIC_KEY_H_*/ diff --git a/src/libstrongswan/crypto/signers/hmac_signer.c b/src/libstrongswan/crypto/signers/hmac_signer.c deleted file mode 100644 index ad5b882a6..000000000 --- a/src/libstrongswan/crypto/signers/hmac_signer.c +++ /dev/null @@ -1,185 +0,0 @@ -/** - * @file hmac_signer.c - * - * @brief Implementation of hmac_signer_t. - * - */ - -/* - * Copyright (C) 2005-2006 Martin Willi - * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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 - -#include "hmac_signer.h" - -#include - -typedef struct private_hmac_signer_t private_hmac_signer_t; - -/** - * Private data structure with signing context. - */ -struct private_hmac_signer_t { - /** - * Public interface of hmac_signer_t. - */ - hmac_signer_t public; - - /** - * Assigned hmac function. - */ - prf_t *hmac_prf; - - /** - * Block size (truncation of HMAC Hash) - */ - size_t block_size; -}; - -/** - * Implementation of signer_t.get_signature. - */ -static void get_signature(private_hmac_signer_t *this, chunk_t data, u_int8_t *buffer) -{ - if (buffer == NULL) - { /* append mode */ - this->hmac_prf->get_bytes(this->hmac_prf, data, NULL); - } - else - { - u_int8_t full_mac[this->hmac_prf->get_block_size(this->hmac_prf)]; - - this->hmac_prf->get_bytes(this->hmac_prf, data, full_mac); - memcpy(buffer, full_mac, this->block_size); - } -} - -/** - * Implementation of signer_t.allocate_signature. - */ -static void allocate_signature (private_hmac_signer_t *this, chunk_t data, chunk_t *chunk) -{ - if (chunk == NULL) - { /* append mode */ - this->hmac_prf->get_bytes(this->hmac_prf, data, NULL); - } - else - { - chunk_t signature; - u_int8_t full_mac[this->hmac_prf->get_block_size(this->hmac_prf)]; - - this->hmac_prf->get_bytes(this->hmac_prf, data, full_mac); - - signature.ptr = malloc(this->block_size); - signature.len = this->block_size; - - memcpy(signature.ptr, full_mac, this->block_size); - - *chunk = signature; - } -} - -/** - * Implementation of signer_t.verify_signature. - */ -static bool verify_signature(private_hmac_signer_t *this, chunk_t data, chunk_t signature) -{ - u_int8_t full_mac[this->hmac_prf->get_block_size(this->hmac_prf)]; - - this->hmac_prf->get_bytes(this->hmac_prf, data, full_mac); - - if (signature.len != this->block_size) - { - return FALSE; - } - - /* compare mac aka signature :-) */ - if (memcmp(signature.ptr, full_mac, this->block_size) == 0) - { - return TRUE; - } - else - { - return FALSE; - } -} - -/** - * Implementation of signer_t.get_key_size. - */ -static size_t get_key_size(private_hmac_signer_t *this) -{ - /* for HMAC signer, IKEv2 uses block size as key size */ - return this->hmac_prf->get_block_size(this->hmac_prf); -} - -/** - * Implementation of signer_t.get_block_size. - */ -static size_t get_block_size(private_hmac_signer_t *this) -{ - return this->block_size; -} - -/** - * Implementation of signer_t.set_key. - */ -static void set_key(private_hmac_signer_t *this, chunk_t key) -{ - this->hmac_prf->set_key(this->hmac_prf, key); -} - -/** - * Implementation of signer_t.destroy. - */ -static status_t destroy(private_hmac_signer_t *this) -{ - this->hmac_prf->destroy(this->hmac_prf); - free(this); - return SUCCESS; -} - -/* - * Described in header - */ -hmac_signer_t *hmac_signer_create(hash_algorithm_t hash_algoritm, size_t block_size) -{ - size_t hmac_block_size; - private_hmac_signer_t *this = malloc_thing(private_hmac_signer_t); - - this->hmac_prf = (prf_t *) hmac_prf_create(hash_algoritm); - if (this->hmac_prf == NULL) - { - /* algorithm not supported */ - free(this); - return NULL; - } - - /* prevent invalid truncation */ - hmac_block_size = this->hmac_prf->get_block_size(this->hmac_prf); - this->block_size = min(block_size, hmac_block_size); - - /* interface functions */ - this->public.signer_interface.get_signature = (void (*) (signer_t*, chunk_t, u_int8_t*))get_signature; - this->public.signer_interface.allocate_signature = (void (*) (signer_t*, chunk_t, chunk_t*))allocate_signature; - this->public.signer_interface.verify_signature = (bool (*) (signer_t*, chunk_t, chunk_t))verify_signature; - this->public.signer_interface.get_key_size = (size_t (*) (signer_t*))get_key_size; - this->public.signer_interface.get_block_size = (size_t (*) (signer_t*))get_block_size; - this->public.signer_interface.set_key = (void (*) (signer_t*,chunk_t))set_key; - this->public.signer_interface.destroy = (void (*) (signer_t*))destroy; - - return &(this->public); -} diff --git a/src/libstrongswan/crypto/signers/hmac_signer.h b/src/libstrongswan/crypto/signers/hmac_signer.h deleted file mode 100644 index 2449069bd..000000000 --- a/src/libstrongswan/crypto/signers/hmac_signer.h +++ /dev/null @@ -1,68 +0,0 @@ -/** - * @file hmac_signer.h - * - * @brief Interface of hmac_signer_t. - * - */ - -/* - * Copyright (C) 2005-2006 Martin Willi - * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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 HMAC_SIGNER_H_ -#define HMAC_SIGNER_H_ - -typedef struct hmac_signer_t hmac_signer_t; - -#include -#include - -/** - * @brief Implementation of signer_t interface using HMAC. - * - * HMAC uses a standard hash function implemented in a hasher_t to build - * a MAC. - * - * @ingroup signers - */ -struct hmac_signer_t { - - /** - * generic signer_t interface for this signer - */ - signer_t signer_interface; -}; - -/** - * @brief Creates a new hmac_signer_t. - * - * HMAC signatures are often truncated to shorten them to a more usable, but - * still secure enough length. - * Block size must be equal or smaller then the hash algorithms - * hash. - * - * @param hash_algoritm Hash algorithm to use with signer - * @param block_size Size of resulting signature (truncated to block_size) - * @return - * - hmac_signer_t - * - NULL if hash algorithm not supported - * - * @ingroup signers - */ -hmac_signer_t *hmac_signer_create(hash_algorithm_t hash_algoritm, - size_t block_size); - - -#endif /*HMAC_SIGNER_H_*/ diff --git a/src/libstrongswan/crypto/signers/signer.c b/src/libstrongswan/crypto/signers/signer.c index 747bc5efa..377c2b921 100644 --- a/src/libstrongswan/crypto/signers/signer.c +++ b/src/libstrongswan/crypto/signers/signer.c @@ -1,10 +1,3 @@ -/** - * @file signer.c - * - * @brief Implementation of generic signer_t constructor. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,12 +12,12 @@ * 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. + * + * $Id$ */ #include "signer.h" -#include - ENUM_BEGIN(integrity_algorithm_names, AUTH_UNDEFINED, AUTH_HMAC_SHA1_128, "UNDEFINED", "AUTH_HMAC_SHA1_128"); @@ -40,26 +33,3 @@ ENUM_NEXT(integrity_algorithm_names, AUTH_HMAC_SHA2_256_128, AUTH_HMAC_SHA2_512_ "AUTH_HMAC_SHA2_512_256"); ENUM_END(integrity_algorithm_names, AUTH_HMAC_SHA2_512_256); -/* - * Described in header. - */ -signer_t *signer_create(integrity_algorithm_t integrity_algorithm) -{ - switch(integrity_algorithm) - { - case AUTH_HMAC_SHA1_96: - return (signer_t *)hmac_signer_create(HASH_SHA1, 12); - case AUTH_HMAC_SHA1_128: - return (signer_t *)hmac_signer_create(HASH_SHA1, 16); - case AUTH_HMAC_MD5_96: - return (signer_t *)hmac_signer_create(HASH_MD5, 12); - case AUTH_HMAC_SHA2_256_128: - return (signer_t *)hmac_signer_create(HASH_SHA256, 16); - case AUTH_HMAC_SHA2_384_192: - return (signer_t *)hmac_signer_create(HASH_SHA384, 24); - case AUTH_HMAC_SHA2_512_256: - return (signer_t *)hmac_signer_create(HASH_SHA512, 32); - default: - return NULL; - } -} diff --git a/src/libstrongswan/crypto/signers/signer.h b/src/libstrongswan/crypto/signers/signer.h index 4218e4146..cfc6652bc 100644 --- a/src/libstrongswan/crypto/signers/signer.h +++ b/src/libstrongswan/crypto/signers/signer.h @@ -1,10 +1,3 @@ -/** - * @file signer.h - * - * @brief Interface for signer_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup signer signer + * @{ @ingroup crypto */ #ifndef SIGNER_H_ @@ -30,11 +30,9 @@ typedef struct signer_t signer_t; #include /** - * @brief Integrity algorithm, as in IKEv2 RFC 3.3.2. + * Integrity algorithm, as in IKEv2 RFC 3.3.2. * * Algorithms not specified in IKEv2 are allocated in private use space. - * - * @ingroup signers */ enum integrity_algorithm_t { AUTH_UNDEFINED = 1024, @@ -61,93 +59,65 @@ enum integrity_algorithm_t { extern enum_name_t *integrity_algorithm_names; /** - * @brief Generig interface for a symmetric signature algorithm. - * - * @b Constructors: - * - signer_create() - * - hmac_signer_create() - * - * @todo Implement more integrity algorithms - * - * @ingroup signers + * Generig interface for a symmetric signature algorithm. */ struct signer_t { /** - * @brief Generate a signature. + * Generate a signature. * * If buffer is NULL, data is processed and prepended to a next call until * buffer is a valid pointer. * - * @param this calling object - * @param data a chunk containing the data to sign - * @param[out] buffer pointer where the signature will be written + * @param data a chunk containing the data to sign + * @param buffer pointer where the signature will be written */ void (*get_signature) (signer_t *this, chunk_t data, u_int8_t *buffer); /** - * @brief Generate a signature and allocate space for it. + * Generate a signature and allocate space for it. * * If chunk is NULL, data is processed and prepended to a next call until * chunk is a valid chunk pointer. * - * @param this calling object - * @param data a chunk containing the data to sign - * @param[out] chunk chunk which will hold the allocated signature + * @param data a chunk containing the data to sign + * @param chunk chunk which will hold the allocated signature */ void (*allocate_signature) (signer_t *this, chunk_t data, chunk_t *chunk); /** - * @brief Verify a signature. + * Verify a signature. * - * @param this calling object - * @param data a chunk containing the data to verify - * @param signature a chunk containing the signature - * @return TRUE, if signature is valid, FALSE otherwise + * @param data a chunk containing the data to verify + * @param signature a chunk containing the signature + * @return TRUE, if signature is valid, FALSE otherwise */ bool (*verify_signature) (signer_t *this, chunk_t data, chunk_t signature); /** - * @brief Get the block size of this signature algorithm. + * Get the block size of this signature algorithm. * - * @param this calling object - * @return block size in bytes + * @return block size in bytes */ size_t (*get_block_size) (signer_t *this); /** - * @brief Get the key size of the signature algorithm. + * Get the key size of the signature algorithm. * - * @param this calling object - * @return key size in bytes + * @return key size in bytes */ size_t (*get_key_size) (signer_t *this); /** - * @brief Set the key for this object. + * Set the key for this object. * - * @param this calling object - * @param key key to set + * @param key key to set */ void (*set_key) (signer_t *this, chunk_t key); /** - * @brief Destroys a signer_t object. - * - * @param this calling object + * Destroys a signer_t object. */ void (*destroy) (signer_t *this); }; -/** - * @brief Creates a new signer_t object. - * - * @param integrity_algorithm Algorithm to use for signing and verifying. - * @return - * - signer_t object - * - NULL if signer not supported - * - * @ingroup signers - */ -signer_t *signer_create(integrity_algorithm_t integrity_algorithm); - -#endif /*SIGNER_H_*/ +#endif /*SIGNER_H_ @} */ diff --git a/src/libstrongswan/crypto/x509.c b/src/libstrongswan/crypto/x509.c deleted file mode 100755 index ff490a095..000000000 --- a/src/libstrongswan/crypto/x509.c +++ /dev/null @@ -1,1562 +0,0 @@ -/** - * @file x509.c - * - * @brief Implementation of x509_t. - * - */ - -/* - * Copyright (C) 2000 Andreas Hess, Patric Lichtsteiner, Roger Wegmann - * Copyright (C) 2001 Marco Bertossa, Andreas Schleiss - * Copyright (C) 2002 Mario Strasser - * Copyright (C) 2006 Martin Willi - * Copyright (C) 2000-2008 Andreas Steffen - * - * 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 . - * - * 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. - * - * RCSID $Id$ - */ - -#include -#include -#include -#include -#include - -#include "x509.h" -#include "hashers/hasher.h" -#include -#include -#include -#include -#include -#include -#include - -#define CERT_WARNING_INTERVAL 30 /* days */ - -/** - * Different kinds of generalNames - */ -typedef enum generalNames_t generalNames_t; - -enum generalNames_t { - GN_OTHER_NAME = 0, - GN_RFC822_NAME = 1, - GN_DNS_NAME = 2, - GN_X400_ADDRESS = 3, - GN_DIRECTORY_NAME = 4, - GN_EDI_PARTY_NAME = 5, - GN_URI = 6, - GN_IP_ADDRESS = 7, - GN_REGISTERED_ID = 8, -}; - -typedef struct private_x509_t private_x509_t; - -/** - * Private data of a x509_t object. - */ -struct private_x509_t { - /** - * Public interface for this certificate. - */ - x509_t public; - - /** - * Time when certificate was installed - */ - time_t installed; - - /** - * Time until certificate can be trusted - */ - time_t until; - - /** - * Certificate status - */ - cert_status_t status; - - /** - * Authority flags - */ - u_int authority_flags; - - /** - * X.509 Certificate in DER format - */ - chunk_t certificate; - - /** - * X.509 certificate body over which signature is computed - */ - chunk_t tbsCertificate; - - /** - * Version of the X.509 certificate - */ - u_int version; - - /** - * Serial number of the X.509 certificate - */ - chunk_t serialNumber; - - /** - * Signature algorithm - */ - int signatureAlgorithm; - - /** - * ID representing the certificate issuer - */ - identification_t *issuer; - - /** - * link to the info recored of the certificate issuer - */ - ca_info_t *ca_info; - - /** - * Start time of certificate validity - */ - time_t notBefore; - - /** - * End time of certificate validity - */ - time_t notAfter; - - /** - * ID representing the certificate subject - */ - identification_t *subject; - - /** - * List of identification_t's representing subjectAltNames - */ - linked_list_t *subjectAltNames; - - /** - * List of identification_t's representing crlDistributionPoints - */ - linked_list_t *crlDistributionPoints; - - /** - * List of identification_t's representing ocspAccessLocations - */ - linked_list_t *ocspAccessLocations; - - /** - * Subject public key - */ - chunk_t subjectPublicKey; - - /** - * Subject RSA public key, if subjectPublicKeyAlgorithm == RSA - */ - rsa_public_key_t *public_key; - - /** - * Subject Key Identifier - */ - chunk_t subjectKeyID; - - /** - * Authority Key Identifier - */ - chunk_t authKeyID; - - /** - * Authority Key Serial Number - */ - chunk_t authKeySerialNumber; - - /** - * Indicates if the certificate is self-signed - */ - bool isSelfSigned; - - /** - * CA basic constraints flag - */ - bool isCA; - - /** - * OCSPSigner extended key usage flag - */ - bool isOcspSigner; - - /** - * Signature - */ - chunk_t signature; - -}; - -/** - * ASN.1 definition of generalName - */ -static const asn1Object_t generalNameObjects[] = { - { 0, "otherName", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_BODY }, /* 0 */ - { 0, "end choice", ASN1_EOC, ASN1_END }, /* 1 */ - { 0, "rfc822Name", ASN1_CONTEXT_S_1, ASN1_OPT|ASN1_BODY }, /* 2 */ - { 0, "end choice", ASN1_EOC, ASN1_END }, /* 3 */ - { 0, "dnsName", ASN1_CONTEXT_S_2, ASN1_OPT|ASN1_BODY }, /* 4 */ - { 0, "end choice", ASN1_EOC, ASN1_END }, /* 5 */ - { 0, "x400Address", ASN1_CONTEXT_S_3, ASN1_OPT|ASN1_BODY }, /* 6 */ - { 0, "end choice", ASN1_EOC, ASN1_END }, /* 7 */ - { 0, "directoryName", ASN1_CONTEXT_C_4, ASN1_OPT|ASN1_BODY }, /* 8 */ - { 0, "end choice", ASN1_EOC, ASN1_END }, /* 9 */ - { 0, "ediPartyName", ASN1_CONTEXT_C_5, ASN1_OPT|ASN1_BODY }, /* 10 */ - { 0, "end choice", ASN1_EOC, ASN1_END }, /* 11 */ - { 0, "URI", ASN1_CONTEXT_S_6, ASN1_OPT|ASN1_BODY }, /* 12 */ - { 0, "end choice", ASN1_EOC, ASN1_END }, /* 13 */ - { 0, "ipAddress", ASN1_CONTEXT_S_7, ASN1_OPT|ASN1_BODY }, /* 14 */ - { 0, "end choice", ASN1_EOC, ASN1_END }, /* 15 */ - { 0, "registeredID", ASN1_CONTEXT_S_8, ASN1_OPT|ASN1_BODY }, /* 16 */ - { 0, "end choice", ASN1_EOC, ASN1_END } /* 17 */ -}; -#define GN_OBJ_OTHER_NAME 0 -#define GN_OBJ_RFC822_NAME 2 -#define GN_OBJ_DNS_NAME 4 -#define GN_OBJ_X400_ADDRESS 6 -#define GN_OBJ_DIRECTORY_NAME 8 -#define GN_OBJ_EDI_PARTY_NAME 10 -#define GN_OBJ_URI 12 -#define GN_OBJ_IP_ADDRESS 14 -#define GN_OBJ_REGISTERED_ID 16 -#define GN_OBJ_ROOF 18 - -/** - * ASN.1 definition of otherName - */ -static const asn1Object_t otherNameObjects[] = { - {0, "type-id", ASN1_OID, ASN1_BODY }, /* 0 */ - {0, "value", ASN1_CONTEXT_C_0, ASN1_BODY } /* 1 */ -}; -#define ON_OBJ_ID_TYPE 0 -#define ON_OBJ_VALUE 1 -#define ON_OBJ_ROOF 2 -/** - * ASN.1 definition of a basicConstraints extension - */ -static const asn1Object_t basicConstraintsObjects[] = { - { 0, "basicConstraints", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ - { 1, "CA", ASN1_BOOLEAN, ASN1_DEF|ASN1_BODY }, /* 1 */ - { 1, "pathLenConstraint", ASN1_INTEGER, ASN1_OPT|ASN1_BODY }, /* 2 */ - { 1, "end opt", ASN1_EOC, ASN1_END } /* 3 */ -}; -#define BASIC_CONSTRAINTS_CA 1 -#define BASIC_CONSTRAINTS_ROOF 4 - -/** - * ASN.1 definition of a keyIdentifier - */ -static const asn1Object_t keyIdentifierObjects[] = { - { 0, "keyIdentifier", ASN1_OCTET_STRING, ASN1_BODY } /* 0 */ -}; - -/** - * ASN.1 definition of a authorityKeyIdentifier extension - */ -static const asn1Object_t authorityKeyIdentifierObjects[] = { - { 0, "authorityKeyIdentifier", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ - { 1, "keyIdentifier", ASN1_CONTEXT_S_0, ASN1_OPT|ASN1_OBJ }, /* 1 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 2 */ - { 1, "authorityCertIssuer", ASN1_CONTEXT_C_1, ASN1_OPT|ASN1_OBJ }, /* 3 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 4 */ - { 1, "authorityCertSerialNumber",ASN1_CONTEXT_S_2, ASN1_OPT|ASN1_BODY }, /* 5 */ - { 1, "end opt", ASN1_EOC, ASN1_END } /* 6 */ -}; -#define AUTH_KEY_ID_KEY_ID 1 -#define AUTH_KEY_ID_CERT_ISSUER 3 -#define AUTH_KEY_ID_CERT_SERIAL 5 -#define AUTH_KEY_ID_ROOF 7 - -/** - * ASN.1 definition of a authorityInfoAccess extension - */ -static const asn1Object_t authorityInfoAccessObjects[] = { - { 0, "authorityInfoAccess", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ - { 1, "accessDescription", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */ - { 2, "accessMethod", ASN1_OID, ASN1_BODY }, /* 2 */ - { 2, "accessLocation", ASN1_EOC, ASN1_RAW }, /* 3 */ - { 0, "end loop", ASN1_EOC, ASN1_END } /* 4 */ -}; -#define AUTH_INFO_ACCESS_METHOD 2 -#define AUTH_INFO_ACCESS_LOCATION 3 -#define AUTH_INFO_ACCESS_ROOF 5 - -/** - * ASN.1 definition of a extendedKeyUsage extension - */ -static const asn1Object_t extendedKeyUsageObjects[] = { - { 0, "extendedKeyUsage", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ - { 1, "keyPurposeID", ASN1_OID, ASN1_BODY }, /* 1 */ - { 0, "end loop", ASN1_EOC, ASN1_END }, /* 2 */ -}; - -#define EXT_KEY_USAGE_PURPOSE_ID 1 -#define EXT_KEY_USAGE_ROOF 3 - -/** - * ASN.1 definition of generalNames - */ -static const asn1Object_t generalNamesObjects[] = { - { 0, "generalNames", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ - { 1, "generalName", ASN1_EOC, ASN1_RAW }, /* 1 */ - { 0, "end loop", ASN1_EOC, ASN1_END } /* 2 */ -}; -#define GENERAL_NAMES_GN 1 -#define GENERAL_NAMES_ROOF 3 - - -/** - * ASN.1 definition of crlDistributionPoints - */ -static const asn1Object_t crlDistributionPointsObjects[] = { - { 0, "crlDistributionPoints", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ - { 1, "DistributionPoint", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */ - { 2, "distributionPoint", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_LOOP }, /* 2 */ - { 3, "fullName", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_OBJ }, /* 3 */ - { 3, "end choice", ASN1_EOC, ASN1_END }, /* 4 */ - { 3, "nameRelToCRLIssuer",ASN1_CONTEXT_C_1, ASN1_OPT|ASN1_BODY }, /* 5 */ - { 3, "end choice", ASN1_EOC, ASN1_END }, /* 6 */ - { 2, "end opt", ASN1_EOC, ASN1_END }, /* 7 */ - { 2, "reasons", ASN1_CONTEXT_C_1, ASN1_OPT|ASN1_BODY }, /* 8 */ - { 2, "end opt", ASN1_EOC, ASN1_END }, /* 9 */ - { 2, "crlIssuer", ASN1_CONTEXT_C_2, ASN1_OPT|ASN1_BODY }, /* 10 */ - { 2, "end opt", ASN1_EOC, ASN1_END }, /* 11 */ - { 0, "end loop", ASN1_EOC, ASN1_END }, /* 12 */ -}; -#define CRL_DIST_POINTS_FULLNAME 3 -#define CRL_DIST_POINTS_ROOF 13 - -/** - * ASN.1 definition of an X.509v3 x509 - */ -static const asn1Object_t certObjects[] = { - { 0, "x509", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */ - { 1, "tbsCertificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */ - { 2, "DEFAULT v1", ASN1_CONTEXT_C_0, ASN1_DEF }, /* 2 */ - { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 3 */ - { 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 4 */ - { 2, "signature", ASN1_EOC, ASN1_RAW }, /* 5 */ - { 2, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 6 */ - { 2, "validity", ASN1_SEQUENCE, ASN1_NONE }, /* 7 */ - { 3, "notBefore", ASN1_EOC, ASN1_RAW }, /* 8 */ - { 3, "notAfter", ASN1_EOC, ASN1_RAW }, /* 9 */ - { 2, "subject", ASN1_SEQUENCE, ASN1_OBJ }, /* 10 */ - { 2, "subjectPublicKeyInfo",ASN1_SEQUENCE, ASN1_NONE }, /* 11 */ - { 3, "algorithm", ASN1_EOC, ASN1_RAW }, /* 12 */ - { 3, "subjectPublicKey", ASN1_BIT_STRING, ASN1_NONE }, /* 13 */ - { 4, "RSAPublicKey", ASN1_SEQUENCE, ASN1_RAW }, /* 14 */ - { 2, "issuerUniqueID", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 15 */ - { 2, "end opt", ASN1_EOC, ASN1_END }, /* 16 */ - { 2, "subjectUniqueID", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 17 */ - { 2, "end opt", ASN1_EOC, ASN1_END }, /* 18 */ - { 2, "optional extensions", ASN1_CONTEXT_C_3, ASN1_OPT }, /* 19 */ - { 3, "extensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 20 */ - { 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 21 */ - { 5, "extnID", ASN1_OID, ASN1_BODY }, /* 22 */ - { 5, "critical", ASN1_BOOLEAN, ASN1_DEF|ASN1_BODY }, /* 23 */ - { 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 24 */ - { 3, "end loop", ASN1_EOC, ASN1_END }, /* 25 */ - { 2, "end opt", ASN1_EOC, ASN1_END }, /* 26 */ - { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 27 */ - { 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY } /* 28 */ -}; -#define X509_OBJ_CERTIFICATE 0 -#define X509_OBJ_TBS_CERTIFICATE 1 -#define X509_OBJ_VERSION 3 -#define X509_OBJ_SERIAL_NUMBER 4 -#define X509_OBJ_SIG_ALG 5 -#define X509_OBJ_ISSUER 6 -#define X509_OBJ_NOT_BEFORE 8 -#define X509_OBJ_NOT_AFTER 9 -#define X509_OBJ_SUBJECT 10 -#define X509_OBJ_SUBJECT_PUBLIC_KEY_ALGORITHM 12 -#define X509_OBJ_SUBJECT_PUBLIC_KEY 13 -#define X509_OBJ_RSA_PUBLIC_KEY 14 -#define X509_OBJ_EXTN_ID 22 -#define X509_OBJ_CRITICAL 23 -#define X509_OBJ_EXTN_VALUE 24 -#define X509_OBJ_ALGORITHM 27 -#define X509_OBJ_SIGNATURE 28 -#define X509_OBJ_ROOF 29 - - -static u_char ASN1_subjectAltName_oid_str[] = { - 0x06, 0x03, 0x55, 0x1D, 0x11 -}; - -static const chunk_t ASN1_subjectAltName_oid = chunk_from_buf(ASN1_subjectAltName_oid_str); - - -/** - * compare two X.509 x509s by comparing their signatures - */ -static bool equals(const private_x509_t *this, const private_x509_t *other) -{ - return chunk_equals(this->signature, other->signature); -} - -/** - * extracts the basicConstraints extension - */ -static bool parse_basicConstraints(chunk_t blob, int level0) -{ - asn1_ctx_t ctx; - chunk_t object; - u_int level; - int objectID = 0; - bool isCA = FALSE; - - asn1_init(&ctx, blob, level0, FALSE, FALSE); - - while (objectID < BASIC_CONSTRAINTS_ROOF) { - - if (!extract_object(basicConstraintsObjects, &objectID, &object,&level, &ctx)) - { - break; - } - if (objectID == BASIC_CONSTRAINTS_CA) - { - isCA = object.len && *object.ptr; - DBG2(" %s", isCA ? "TRUE" : "FALSE"); - } - objectID++; - } - return isCA; -} - -/** - * extracts an otherName - */ -static bool parse_otherName(chunk_t blob, int level0) -{ - asn1_ctx_t ctx; - chunk_t object; - u_int level; - int objectID = 0; - int oid = OID_UNKNOWN; - - asn1_init(&ctx, blob, level0, FALSE, FALSE); - - while (objectID < ON_OBJ_ROOF) - { - if (!extract_object(otherNameObjects, &objectID, &object, &level, &ctx)) - return FALSE; - - switch (objectID) - { - case ON_OBJ_ID_TYPE: - oid = known_oid(object); - break; - case ON_OBJ_VALUE: - if (oid == OID_XMPP_ADDR) - { - if (!parse_asn1_simple_object(&object, ASN1_UTF8STRING, level + 1, "xmppAddr")) - return FALSE; - } - break; - default: - break; - } - objectID++; - } - return TRUE; -} - -/** - * extracts a generalName - */ -static identification_t *parse_generalName(chunk_t blob, int level0) -{ - asn1_ctx_t ctx; - chunk_t object; - int objectID = 0; - u_int level; - - asn1_init(&ctx, blob, level0, FALSE, FALSE); - - while (objectID < GN_OBJ_ROOF) - { - id_type_t id_type = ID_ANY; - - if (!extract_object(generalNameObjects, &objectID, &object, &level, &ctx)) - return NULL; - - switch (objectID) - { - case GN_OBJ_RFC822_NAME: - id_type = ID_RFC822_ADDR; - break; - case GN_OBJ_DNS_NAME: - id_type = ID_FQDN; - break; - case GN_OBJ_URI: - id_type = ID_DER_ASN1_GN_URI; - break; - case GN_OBJ_DIRECTORY_NAME: - id_type = ID_DER_ASN1_DN; - break; - case GN_OBJ_IP_ADDRESS: - id_type = (object.len == 4)? ID_IPV4_ADDR : ID_IPV6_ADDR; - break; - case GN_OBJ_OTHER_NAME: - if (!parse_otherName(object, level + 1)) - return NULL; - break; - case GN_OBJ_X400_ADDRESS: - case GN_OBJ_EDI_PARTY_NAME: - case GN_OBJ_REGISTERED_ID: - break; - default: - break; - } - - if (id_type != ID_ANY) - { - identification_t *gn = identification_create_from_encoding(id_type, object); - DBG2(" '%D'", gn); - return gn; - } - objectID++; - } - return NULL; -} - - -/* - * Defined in header. - */ -void x509_parse_generalNames(chunk_t blob, int level0, bool implicit, linked_list_t *list) -{ - asn1_ctx_t ctx; - chunk_t object; - u_int level; - int objectID = 0; - - asn1_init(&ctx, blob, level0, implicit, FALSE); - - while (objectID < GENERAL_NAMES_ROOF) - { - if (!extract_object(generalNamesObjects, &objectID, &object, &level, &ctx)) - return; - - if (objectID == GENERAL_NAMES_GN) - { - identification_t *gn = parse_generalName(object, level+1); - - if (gn != NULL) - list->insert_last(list, (void *)gn); - } - objectID++; - } - return; -} - -/** - * extracts a keyIdentifier - */ -static chunk_t parse_keyIdentifier(chunk_t blob, int level0, bool implicit) -{ - asn1_ctx_t ctx; - chunk_t object; - u_int level; - int objectID = 0; - - asn1_init(&ctx, blob, level0, implicit, FALSE); - - extract_object(keyIdentifierObjects, &objectID, &object, &level, &ctx); - return object; -} - -/* - * Defined in header. - */ -void x509_parse_authorityKeyIdentifier(chunk_t blob, int level0 , chunk_t *authKeyID, chunk_t *authKeySerialNumber) -{ - asn1_ctx_t ctx; - chunk_t object; - u_int level; - int objectID = 0; - - *authKeyID = chunk_empty; - *authKeySerialNumber = chunk_empty; - - asn1_init(&ctx, blob, level0, FALSE, FALSE); - - while (objectID < AUTH_KEY_ID_ROOF) - { - if (!extract_object(authorityKeyIdentifierObjects, &objectID, &object, &level, &ctx)) - { - return; - } - switch (objectID) - { - case AUTH_KEY_ID_KEY_ID: - *authKeyID = parse_keyIdentifier(object, level+1, TRUE); - break; - case AUTH_KEY_ID_CERT_ISSUER: - { - /* TODO: parse_generalNames(object, level+1, TRUE); */ - break; - } - case AUTH_KEY_ID_CERT_SERIAL: - *authKeySerialNumber = object; - break; - default: - break; - } - objectID++; - } -} - -/** - * extracts an authorityInfoAcess location - */ -static void parse_authorityInfoAccess(chunk_t blob, int level0, linked_list_t *list) -{ - asn1_ctx_t ctx; - chunk_t object; - u_int level; - int objectID = 0; - int accessMethod = OID_UNKNOWN; - - asn1_init(&ctx, blob, level0, FALSE, FALSE); - while (objectID < AUTH_INFO_ACCESS_ROOF) - { - if (!extract_object(authorityInfoAccessObjects, &objectID, &object, &level, &ctx)) - { - return; - } - switch (objectID) - { - case AUTH_INFO_ACCESS_METHOD: - accessMethod = known_oid(object); - break; - case AUTH_INFO_ACCESS_LOCATION: - { - switch (accessMethod) - { - case OID_OCSP: - case OID_CA_ISSUERS: - { - identification_t *accessLocation; - - accessLocation = parse_generalName(object, level+1); - if (accessLocation == NULL) - { - /* parsing went wrong - abort */ - return; - } - DBG2(" '%D'", accessLocation); - if (accessMethod == OID_OCSP) - { - list->insert_last(list, (void *)accessLocation); - } - else - { - /* caIsssuer accessLocation is not used yet */ - accessLocation->destroy(accessLocation); - } - } - break; - default: - /* unkown accessMethod, ignoring */ - break; - } - break; - } - default: - break; - } - objectID++; - } -} - -/** - * extracts extendedKeyUsage OIDs - */ -static bool parse_extendedKeyUsage(chunk_t blob, int level0) -{ - asn1_ctx_t ctx; - chunk_t object; - u_int level; - int objectID = 0; - - asn1_init(&ctx, blob, level0, FALSE, FALSE); - while (objectID < EXT_KEY_USAGE_ROOF) - { - if (!extract_object(extendedKeyUsageObjects, &objectID, &object, &level, &ctx)) - { - return FALSE; - } - if (objectID == EXT_KEY_USAGE_PURPOSE_ID && - known_oid(object) == OID_OCSP_SIGNING) - { - return TRUE; - } - objectID++; - } - return FALSE; -} - -/** - * extracts one or several crlDistributionPoints and puts them into - * a chained list - */ -static void parse_crlDistributionPoints(chunk_t blob, int level0, linked_list_t *list) -{ - asn1_ctx_t ctx; - chunk_t object; - u_int level; - int objectID = 0; - - asn1_init(&ctx, blob, level0, FALSE, FALSE); - while (objectID < CRL_DIST_POINTS_ROOF) - { - if (!extract_object(crlDistributionPointsObjects, &objectID, &object, &level, &ctx)) - { - return; - } - if (objectID == CRL_DIST_POINTS_FULLNAME) - { - /* append extracted generalNames to existing chained list */ - x509_parse_generalNames(object, level+1, TRUE, list); - - } - objectID++; - } -} - - -/** - * Parses an X.509v3 certificate - */ -static bool parse_certificate(chunk_t blob, u_int level0, private_x509_t *this) -{ - asn1_ctx_t ctx; - bool critical; - chunk_t object; - u_int level; - int objectID = 0; - int extn_oid = OID_UNKNOWN; - - asn1_init(&ctx, blob, level0, FALSE, FALSE); - while (objectID < X509_OBJ_ROOF) - { - if (!extract_object(certObjects, &objectID, &object, &level, &ctx)) - { - return FALSE; - } - - /* those objects which will parsed further need the next higher level */ - level++; - - switch (objectID) - { - case X509_OBJ_CERTIFICATE: - this->certificate = object; - break; - case X509_OBJ_TBS_CERTIFICATE: - this->tbsCertificate = object; - break; - case X509_OBJ_VERSION: - this->version = (object.len) ? (1+(u_int)*object.ptr) : 1; - DBG2(" v%d", this->version); - break; - case X509_OBJ_SERIAL_NUMBER: - this->serialNumber = object; - break; - case X509_OBJ_SIG_ALG: - this->signatureAlgorithm = parse_algorithmIdentifier(object, level, NULL); - break; - case X509_OBJ_ISSUER: - this->issuer = identification_create_from_encoding(ID_DER_ASN1_DN, object); - DBG2(" '%D'", this->issuer); - break; - case X509_OBJ_NOT_BEFORE: - this->notBefore = parse_time(object, level); - break; - case X509_OBJ_NOT_AFTER: - this->notAfter = parse_time(object, level); - break; - case X509_OBJ_SUBJECT: - this->subject = identification_create_from_encoding(ID_DER_ASN1_DN, object); - DBG2(" '%D'", this->subject); - break; - case X509_OBJ_SUBJECT_PUBLIC_KEY_ALGORITHM: - if (parse_algorithmIdentifier(object, level, NULL) != OID_RSA_ENCRYPTION) - { - DBG1(" unsupported public key algorithm"); - return FALSE; - } - break; - case X509_OBJ_SUBJECT_PUBLIC_KEY: - if (ctx.blobs[4].len > 0 && *ctx.blobs[4].ptr == 0x00) - { - /* skip initial bit string octet defining 0 unused bits */ - ctx.blobs[4].ptr++; ctx.blobs[4].len--; - } - else - { - DBG1(" invalid RSA public key format"); - return FALSE; - } - break; - case X509_OBJ_RSA_PUBLIC_KEY: - this->subjectPublicKey = object; - break; - case X509_OBJ_EXTN_ID: - extn_oid = known_oid(object); - break; - case X509_OBJ_CRITICAL: - critical = object.len && *object.ptr; - DBG2(" %s", critical ? "TRUE" : "FALSE"); - break; - case X509_OBJ_EXTN_VALUE: - { - switch (extn_oid) - { - case OID_SUBJECT_KEY_ID: - this->subjectKeyID = chunk_clone(parse_keyIdentifier(object, level, FALSE)); - break; - case OID_SUBJECT_ALT_NAME: - x509_parse_generalNames(object, level, FALSE, this->subjectAltNames); - break; - case OID_BASIC_CONSTRAINTS: - this->isCA = parse_basicConstraints(object, level); - break; - case OID_CRL_DISTRIBUTION_POINTS: - parse_crlDistributionPoints(object, level, this->crlDistributionPoints); - break; - case OID_AUTHORITY_KEY_ID: - x509_parse_authorityKeyIdentifier(object, level, - &this->authKeyID, &this->authKeySerialNumber); - break; - case OID_AUTHORITY_INFO_ACCESS: - parse_authorityInfoAccess(object, level, this->ocspAccessLocations); - break; - case OID_EXTENDED_KEY_USAGE: - this->isOcspSigner = parse_extendedKeyUsage(object, level); - break; - case OID_NS_REVOCATION_URL: - case OID_NS_CA_REVOCATION_URL: - case OID_NS_CA_POLICY_URL: - case OID_NS_COMMENT: - if (!parse_asn1_simple_object(&object, ASN1_IA5STRING , level, oid_names[extn_oid].name)) - return FALSE; - break; - default: - break; - } - break; - } - case X509_OBJ_ALGORITHM: - { - int alg = parse_algorithmIdentifier(object, level, NULL); - - if (alg != this->signatureAlgorithm) - { - DBG1(" signature algorithms do not agree"); - return FALSE; - } - } - break; - case X509_OBJ_SIGNATURE: - this->signature = object; - break; - default: - break; - } - objectID++; - } - - /* generate the subjectKeyID if it is missing in the certificate */ - if (this->subjectKeyID.ptr == NULL) - { - hasher_t *hasher = hasher_create(HASH_SHA1); - - hasher->allocate_hash(hasher, this->subjectPublicKey, &this->subjectKeyID); - hasher->destroy(hasher); - } - - this->installed = time(NULL); - return TRUE; -} - -/** - * Implements x509_t.is_valid - */ -static err_t is_valid(const private_x509_t *this, time_t *until) -{ - time_t current_time = time(NULL); - - DBG2(" not before : %T", &this->notBefore); - DBG2(" current time: %T", ¤t_time); - DBG2(" not after : %T", &this->notAfter); - - if (until != NULL && - (*until == UNDEFINED_TIME || this->notAfter < *until)) - { - *until = this->notAfter; - } - if (current_time < this->notBefore) - { - return "is not valid yet"; - } - if (current_time > this->notAfter) - { - return "has expired"; - } - DBG2(" certificate is valid"); - return NULL; -} - -/** - * Implements x509_t.is_ca - */ -static bool is_ca(const private_x509_t *this) -{ - return this->isCA; -} - -/** - * Implements x509_t.is_ocsp_signer - */ -static bool is_ocsp_signer(const private_x509_t *this) -{ - return this->isOcspSigner; -} - -/** - * Implements x509_t.is_self_signed - */ -static bool is_self_signed(const private_x509_t *this) -{ - return this->isSelfSigned; -} - -/** - * Implements x509_t.equals_subjectAltName - */ -static bool equals_subjectAltName(const private_x509_t *this, identification_t *id) -{ - bool found = FALSE; - identification_t *subjectAltName; - iterator_t *iterator; - - iterator = this->subjectAltNames->create_iterator(this->subjectAltNames, TRUE); - while (iterator->iterate(iterator, (void**)&subjectAltName)) - { - if (id->equals(id, subjectAltName)) - { - found = TRUE; - break; - } - } - iterator->destroy(iterator); - return found; -} - -/** - * Implements x509_t.is_issuer - */ -static bool is_issuer(const private_x509_t *this, const private_x509_t *issuer) -{ - return (this->authKeyID.ptr) - ? chunk_equals(this->authKeyID, issuer->subjectKeyID) - : (this->issuer->equals(this->issuer, issuer->subject) - && chunk_equals_or_null(this->authKeySerialNumber, issuer->serialNumber)); -} - -/** - * Implements x509_t.get_certificate - */ -static chunk_t get_certificate(const private_x509_t *this) -{ - return this->certificate; -} - -/** - * Implements x509_t.get_public_key - */ -static rsa_public_key_t *get_public_key(const private_x509_t *this) -{ - return this->public_key; -} - -/** - * Implements x509_t.get_serialNumber - */ -static chunk_t get_serialNumber(const private_x509_t *this) -{ - return this->serialNumber; -} - -/** - * Implements x509_t.get_subjectKeyID - */ -static chunk_t get_subjectKeyID(const private_x509_t *this) -{ - return this->subjectKeyID; -} - -/** - * Implements x509_t.get_keyid - */ -static chunk_t get_keyid(const private_x509_t *this) -{ - return this->public_key->get_keyid(this->public_key); -} - -/** - * Implements x509_t.get_issuer - */ -static identification_t *get_issuer(const private_x509_t *this) -{ - return this->issuer; -} - -/** - * Implements x509_t.get_subject - */ -static identification_t *get_subject(const private_x509_t *this) -{ - return this->subject; -} - -/** - * Implements x509_t.set_ca_info - */ -static void set_ca_info(private_x509_t *this, ca_info_t *ca_info) -{ - this->ca_info = ca_info; -} - -/** - * Implements x509_t.get_ca_info - */ -static ca_info_t *get_ca_info(const private_x509_t *this) -{ - return this->ca_info; -} - -/** - * Implements x509_t.set_until - */ -static void set_until(private_x509_t *this, time_t until) -{ - this->until = until; -} - -/** - * Implements x509_t.get_until - */ -static time_t get_until(const private_x509_t *this) -{ - return this->until; -} - -/** - * Implements x509_t.set_status - */ -static void set_status(private_x509_t *this, cert_status_t status) -{ - this->status = status; -} - -/** - * Implements x509_t.get_status - */ -static cert_status_t get_status(const private_x509_t *this) -{ - return this->status; -} - -/** - * Implements x509_t.add_authority_flags - */ -static void add_authority_flags(private_x509_t *this, u_int flags) -{ - this->authority_flags |= flags; -} - -/** - * Implements x509_t.add_authority_flags - */ -static u_int get_authority_flags(private_x509_t *this) -{ - return this->authority_flags; -} - -/** - * Implements x509_t.has_authority_flag - */ -static bool has_authority_flag(private_x509_t *this, u_int flags) -{ - return (this->authority_flags & flags) != AUTH_NONE; -} - -/** - * Implements x509_t.create_crluri_iterator - */ -static iterator_t *create_crluri_iterator(const private_x509_t *this) -{ - return this->crlDistributionPoints->create_iterator(this->crlDistributionPoints, TRUE); -} - -/** - * Implements x509_t.create_crluri_iterator - */ -static iterator_t *create_ocspuri_iterator(const private_x509_t *this) -{ - return this->ocspAccessLocations->create_iterator(this->ocspAccessLocations, TRUE); -} - -/** - * Implements x509_t.verify - */ -static bool verify(const private_x509_t *this, const rsa_public_key_t *signer) -{ - hash_algorithm_t algorithm = hasher_algorithm_from_oid(this->signatureAlgorithm); - - if (algorithm == HASH_UNKNOWN) - { - DBG1(" unknown signature algorithm"); - return FALSE; - } - return signer->verify_emsa_pkcs1_signature(signer, algorithm, this->tbsCertificate, this->signature) == SUCCESS; -} - -/** - * Implementation of x509_t.list. - */ -static void list(private_x509_t *this, FILE *out, bool utc) -{ - iterator_t *iterator; - time_t now = time(NULL); - - fprintf(out, "%#T\n", &this->installed, utc); - - if (this->subjectAltNames->get_count(this->subjectAltNames)) - { - identification_t *subjectAltName; - bool first = TRUE; - - fprintf(out, " altNames: "); - iterator = this->subjectAltNames->create_iterator(this->subjectAltNames, TRUE); - while (iterator->iterate(iterator, (void**)&subjectAltName)) - { - if (first) - { - first = FALSE; - } - else - { - fprintf(out, ", "); - } - fprintf(out, "'%D'", subjectAltName); - } - iterator->destroy(iterator); - fprintf(out, "\n"); - } - fprintf(out, " subject: '%D'\n", this->subject); - fprintf(out, " issuer: '%D'\n", this->issuer); - fprintf(out, " serial: %#B\n", &this->serialNumber); - fprintf(out, " validity: not before %#T, ", &this->notBefore, utc); - if (now < this->notBefore) - { - fprintf(out, "not valid yet (valid in %#V)\n", &now, &this->notBefore); - } - else - { - fprintf(out, "ok\n"); - } - - fprintf(out, " not after %#T, ", &this->notAfter, utc); - if (now > this->notAfter) - { - fprintf(out, "expired (%#V ago)\n", &now, &this->notAfter); - } - else - { - fprintf(out, "ok"); - if (now > this->notAfter - CERT_WARNING_INTERVAL * 60 * 60 * 24) - { - fprintf(out, " (expires in %#V)", &now, &this->notAfter); - } - fprintf(out, " \n"); - } - - { - chunk_t keyid = this->public_key->get_keyid(this->public_key); - fprintf(out, " keyid: %#B\n", &keyid); - } - - if (this->subjectKeyID.ptr) - { - fprintf(out, " subjkey: %#B\n", &this->subjectKeyID); - } - if (this->authKeyID.ptr) - { - fprintf(out, " authkey: %#B\n", &this->authKeyID); - } - if (this->authKeySerialNumber.ptr) - { - fprintf(out, " aserial: %#B\n", &this->authKeySerialNumber); - } - - fprintf(out, " pubkey: RSA %d bits", BITS_PER_BYTE * - this->public_key->get_keysize(this->public_key)); - fprintf(out, ", status %N", - cert_status_names, this->status); - - switch (this->status) - { - case CERT_GOOD: - fprintf(out, " until %#T", &this->until, utc); - break; - case CERT_REVOKED: - fprintf(out, " on %#T", &this->until, utc); - break; - case CERT_UNKNOWN: - case CERT_UNDEFINED: - case CERT_UNTRUSTED: - default: - break; - } -} - -/** - * Implements x509_t.add_subjectAltNames. - */ -static void add_subjectAltNames(private_x509_t *this, linked_list_t *subjectAltNames) -{ - iterator_t *iterator = subjectAltNames->create_iterator(subjectAltNames, TRUE); - identification_t *name = NULL; - - while (iterator->iterate(iterator, (void**)&name)) - { - name = name->clone(name); - this->subjectAltNames->insert_last(this->subjectAltNames, (void*)name); - } - iterator->destroy(iterator); -} - -/* - * Defined in header. - */ -chunk_t x509_build_generalNames(linked_list_t *list) -{ - linked_list_t *generalNames = linked_list_create(); - iterator_t *iterator = list->create_iterator(list, TRUE); - identification_t *name; - chunk_t names = chunk_empty; - size_t len = 0; - - while (iterator->iterate(iterator, (void**)&name)) - { - asn1_t asn1_type = ASN1_EOC; - chunk_t *generalName; - - switch (name->get_type(name)) - { - case ID_RFC822_ADDR: - asn1_type = ASN1_CONTEXT_S_1; - break; - case ID_FQDN: - asn1_type = ASN1_CONTEXT_S_2; - break; - case ID_DER_ASN1_DN: - asn1_type = ASN1_CONTEXT_C_4; - break; - case ID_DER_ASN1_GN_URI: - asn1_type = ASN1_CONTEXT_S_6; - break; - case ID_IPV4_ADDR: - case ID_IPV6_ADDR: - asn1_type = ASN1_CONTEXT_S_7; - break; - default: - continue; - } - - generalName = malloc_thing(chunk_t); - *generalName = asn1_simple_object(asn1_type, name->get_encoding(name)); - len += generalName->len; - generalNames->insert_last(generalNames, (void*)generalName); - } - iterator->destroy(iterator); - - if (len > 0) - { - iterator_t *iterator = generalNames->create_iterator(generalNames, TRUE); - chunk_t *generalName; - u_char *pos = build_asn1_object(&names, ASN1_SEQUENCE, len); - - while (iterator->iterate(iterator, (void**)&generalName)) - { - memcpy(pos, generalName->ptr, generalName->len); - pos += generalName->len; - free(generalName->ptr); - free(generalName); - } - iterator->destroy(iterator); - } - generalNames->destroy(generalNames); - return names; -} - -/* - * Defined in header. - */ -chunk_t x509_build_subjectAltNames(linked_list_t *list) -{ - chunk_t generalNames = x509_build_generalNames(list); - - if (generalNames.len) - { - return asn1_wrap(ASN1_SEQUENCE, "cm", - ASN1_subjectAltName_oid, - asn1_wrap(ASN1_OCTET_STRING, "m", generalNames) - ); - } - else - { - return chunk_empty; - } -} - -/** - * Build a to-be-signed X.509 certificate body - */ -static chunk_t x509_build_tbs(private_x509_t *this) -{ - /* version is always X.509v3 */ - chunk_t version = asn1_simple_object(ASN1_CONTEXT_C_0, ASN1_INTEGER_2); - - chunk_t extensions = chunk_empty; - - if (this->subjectAltNames->get_count(this->subjectAltNames)) - { - extensions = asn1_wrap(ASN1_CONTEXT_C_3, "m", - asn1_wrap(ASN1_SEQUENCE, "m", - x509_build_subjectAltNames(this->subjectAltNames))); - } - - return asn1_wrap(ASN1_SEQUENCE, "mmccmcmm", - version, - asn1_simple_object(ASN1_INTEGER, this->serialNumber), - asn1_algorithmIdentifier(this->signatureAlgorithm), - this->issuer->get_encoding(this->issuer), - asn1_wrap(ASN1_SEQUENCE, "mm", - timetoasn1(&this->notBefore, ASN1_UTCTIME), - timetoasn1(&this->notAfter, ASN1_UTCTIME) - ), - this->subject->get_encoding(this->subject), - this->public_key->get_publicKeyInfo(this->public_key), - extensions - ); -} - -/** - * Implementation of x509_t.build_encoding. - */ -static void build_encoding(private_x509_t *this, hash_algorithm_t alg, - rsa_private_key_t *private_key) -{ - chunk_t signature; - - this->signatureAlgorithm = hasher_signature_algorithm_to_oid(alg); - this->tbsCertificate = x509_build_tbs(this); - private_key->build_emsa_pkcs1_signature(private_key, alg, - this->tbsCertificate, &signature); - this->signature = asn1_bitstring("m", signature); - this->certificate = asn1_wrap(ASN1_SEQUENCE, "mcm", - this->tbsCertificate, - asn1_algorithmIdentifier(this->signatureAlgorithm), - this->signature); - -} - -/** - * Implements x509_t.destroy - */ -static void destroy(private_x509_t *this) -{ - this->subjectAltNames->destroy_offset(this->subjectAltNames, - offsetof(identification_t, destroy)); - this->crlDistributionPoints->destroy_offset(this->crlDistributionPoints, - offsetof(identification_t, destroy)); - this->ocspAccessLocations->destroy_offset(this->ocspAccessLocations, - offsetof(identification_t, destroy)); - DESTROY_IF(this->issuer); - DESTROY_IF(this->subject); - DESTROY_IF(this->public_key); - free(this->subjectKeyID.ptr); - free(this->certificate.ptr); - free(this); -} - -/** - * Internal generic constructor - */ -static private_x509_t *x509_create_empty(void) -{ - private_x509_t *this = malloc_thing(private_x509_t); - - /* initialize */ - this->subjectPublicKey = chunk_empty; - this->public_key = NULL; - this->subject = NULL; - this->issuer = NULL; - this->ca_info = NULL; - this->subjectAltNames = linked_list_create(); - this->crlDistributionPoints = linked_list_create(); - this->ocspAccessLocations = linked_list_create(); - this->subjectKeyID = chunk_empty; - this->authKeyID = chunk_empty; - this->authKeySerialNumber = chunk_empty; - this->authority_flags = AUTH_NONE; - this->isCA = FALSE; - this->isOcspSigner = FALSE; - - /* public functions */ - this->public.equals = (bool (*) (const x509_t*,const x509_t*))equals; - this->public.equals_subjectAltName = (bool (*) (const x509_t*,identification_t*))equals_subjectAltName; - this->public.is_issuer = (bool (*) (const x509_t*,const x509_t*))is_issuer; - this->public.is_valid = (err_t (*) (const x509_t*,time_t*))is_valid; - this->public.is_ca = (bool (*) (const x509_t*))is_ca; - this->public.is_self_signed = (bool (*) (const x509_t*))is_self_signed; - this->public.is_ocsp_signer = (bool (*) (const x509_t*))is_ocsp_signer; - this->public.get_certificate = (chunk_t (*) (const x509_t*))get_certificate; - this->public.get_public_key = (rsa_public_key_t* (*) (const x509_t*))get_public_key; - this->public.get_serialNumber = (chunk_t (*) (const x509_t*))get_serialNumber; - this->public.get_subjectKeyID = (chunk_t (*) (const x509_t*))get_subjectKeyID; - this->public.get_keyid = (chunk_t (*) (const x509_t*))get_keyid; - this->public.get_issuer = (identification_t* (*) (const x509_t*))get_issuer; - this->public.get_subject = (identification_t* (*) (const x509_t*))get_subject; - this->public.set_ca_info = (void (*) (x509_t*,ca_info_t*))set_ca_info; - this->public.get_ca_info = (ca_info_t* (*) (const x509_t*))get_ca_info; - this->public.set_until = (void (*) (x509_t*,time_t))set_until; - this->public.get_until = (time_t (*) (const x509_t*))get_until; - this->public.set_status = (void (*) (x509_t*,cert_status_t))set_status; - this->public.get_status = (cert_status_t (*) (const x509_t*))get_status; - this->public.add_authority_flags = (void (*) (x509_t*,u_int))add_authority_flags; - this->public.get_authority_flags = (u_int (*) (x509_t*))get_authority_flags; - this->public.has_authority_flag = (bool (*) (x509_t*,u_int))has_authority_flag; - this->public.create_crluri_iterator = (iterator_t* (*) (const x509_t*))create_crluri_iterator; - this->public.create_ocspuri_iterator = (iterator_t* (*) (const x509_t*))create_ocspuri_iterator; - this->public.verify = (bool (*) (const x509_t*,const rsa_public_key_t*))verify; - this->public.list = (void (*) (x509_t*, FILE *out, bool utc))list; - this->public.add_subjectAltNames = (void (*) (x509_t*,linked_list_t*))add_subjectAltNames; - this->public.build_encoding = (void (*) (x509_t*,hash_algorithm_t,rsa_private_key_t*))build_encoding; - this->public.destroy = (void (*) (x509_t*))destroy; - - return this; -} - -/* - * Described in header. - */ -x509_t *x509_create(chunk_t serialNumber, identification_t *issuer, - time_t notBefore, time_t notAfter, - identification_t *subject, - rsa_public_key_t *public_key) -{ - private_x509_t *this = x509_create_empty(); - - this->serialNumber = serialNumber; - this->issuer = issuer->clone(issuer); - this->notBefore = notBefore; - this->notAfter = notAfter; - this->subject = subject->clone(subject); - this->public_key = public_key->clone(public_key); - - return &this->public; -} - -/* - * Described in header. - */ -x509_t *x509_create_from_chunk(chunk_t chunk, u_int level) -{ - private_x509_t *this = x509_create_empty(); - - if (!parse_certificate(chunk, level, this)) - { - destroy(this); - return NULL; - } - - /* extract public key from certificate */ - this->public_key = rsa_public_key_create_from_chunk(this->subjectPublicKey); - if (this->public_key == NULL) - { - destroy(this); - return NULL; - } - - /* set trusted lifetime of public key to notAfter */ - this->until = this->notAfter; - - /* check if the certificate is self-signed */ - this->isSelfSigned = FALSE; - if (this->subject->equals(this->subject, this->issuer)) - { - hash_algorithm_t algorithm = hasher_algorithm_from_oid(this->signatureAlgorithm); - - if (algorithm == HASH_UNKNOWN) - { - destroy(this); - return NULL; - } - this->isSelfSigned = this->public_key->verify_emsa_pkcs1_signature(this->public_key, - algorithm, this->tbsCertificate, this->signature) == SUCCESS; - } - if (this->isSelfSigned) - { - DBG2(" certificate is self-signed"); - this->status = CERT_GOOD; - } - else - { - this->status = CERT_UNDEFINED; - } - - return &this->public; -} - -/* - * Described in header. - */ -x509_t *x509_create_from_file(const char *filename, const char *label) -{ - bool pgp = FALSE; - chunk_t chunk = chunk_empty; - char cert_label[BUF_LEN]; - - snprintf(cert_label, BUF_LEN, "%s certificate", label); - - if (!pem_asn1_load_file(filename, NULL, cert_label, &chunk, &pgp)) - { - return NULL; - } - return x509_create_from_chunk(chunk, 0); -} diff --git a/src/libstrongswan/crypto/x509.h b/src/libstrongswan/crypto/x509.h deleted file mode 100755 index 4c49c8e80..000000000 --- a/src/libstrongswan/crypto/x509.h +++ /dev/null @@ -1,406 +0,0 @@ -/** - * @file x509.h - * - * @brief Interface of x509_t. - * - */ - -/* - * Copyright (C) 2000 Andreas Hess, Patric Lichtsteiner, Roger Wegmann - * Copyright (C) 2001 Marco Bertossa, Andreas Schleiss - * Copyright (C) 2002 Mario Strasser - * Copyright (C) 2006 Martin Willi - * Copyright (C) 2000-2008 Andreas Steffen - * - * 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 . - * - * 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. - * - * RCSID $Id$ - */ - -#ifndef X509_H_ -#define X509_H_ - -typedef struct x509_t x509_t; - -#include -#include -#include -#include -#include -#include -#include -#include - -/* authority flags */ - -#define AUTH_NONE 0x00 /* no authorities */ -#define AUTH_CA 0x01 /* certification authority */ -#define AUTH_AA 0x02 /* authorization authority */ -#define AUTH_OCSP 0x04 /* ocsp signing authority */ - -/** - * @brief X.509 certificate. - * - * @b Constructors: - * - x509_create() - * - x509_create_from_chunk() - * - x509_create_from_file() - * - * @ingroup crypto - */ -struct x509_t { - - /** - * @brief Set trusted public key life. - * - * @param this calling object - * @param until time until public key is trusted - */ - void (*set_until) (x509_t *this, time_t until); - - /** - * @brief Get trusted public key life. - * - * @param this calling object - * @return time until public key is trusted - */ - time_t (*get_until) (const x509_t *this); - - /** - * @brief Set the certificate status - * - * @param this calling object - * @param status certificate status - */ - void (*set_status) (x509_t *this, cert_status_t status); - - /** - * @brief Get the certificate status - * - * @param this calling object - * @return certificate status - */ - cert_status_t (*get_status) (const x509_t *this); - - /** - * @brief Add authority flags - * - * @param this calling object - * @param flag flags to be added - */ - void (*add_authority_flags) (x509_t *this, u_int flags); - - /** - * @brief Get authority flags - * - * @param this calling object - * @return authority flags - */ - u_int (*get_authority_flags) (x509_t *this); - - /** - * @brief Check a specific authority flag - * - * @param this calling object - * @param flag flag to be checked - * @return TRUE if flag is present - */ - bool (*has_authority_flag) (x509_t *this, u_int flag); - - /** - * @brief Get the DER-encoded X.509 certificate body - * - * @param this calling object - * @return DER-encoded X.509 certificate - */ - chunk_t (*get_certificate) (const x509_t *this); - - /** - * @brief Get the RSA public key from the certificate. - * - * @param this calling object - * @return public_key - */ - rsa_public_key_t *(*get_public_key) (const x509_t *this); - - /** - * @brief Get serial number from the certificate. - * - * @param this calling object - * @return serialNumber - */ - chunk_t (*get_serialNumber) (const x509_t *this); - - /** - * @brief Get subjectKeyID from the certificate. - * - * @param this calling object - * @return subjectKeyID - */ - chunk_t (*get_subjectKeyID) (const x509_t *this); - - /** - * @brief Get keyid from the certificate's public key. - * - * @param this calling object - * @return keyid - */ - chunk_t (*get_keyid) (const x509_t *this); - - /** - * @brief Get the issuerDistinguishedName - * - * The resulting ID is always a identification_t - * of type ID_DER_ASN1_DN. - * - * @param this calling object - * @return issuers ID - */ - identification_t *(*get_issuer) (const x509_t *this); - - /** - * @brief Get the subjectDistinguishedName. - * - * The resulting ID is always a identification_t - * of type ID_DER_ASN1_DN. - * - * @param this calling object - * @return subjects ID - */ - identification_t *(*get_subject) (const x509_t *this); - - /** - * @brief Set a link ca info - * - * @param this calling object - * @param ca_info link to the info record of the issuing ca - */ - void (*set_ca_info) (x509_t *this, ca_info_t *ca_info); - - /** - * @brief Get the . - * - * The resulting ID is always a identification_t - * of type ID_DER_ASN1_DN. - * - * @param this calling object - * @return link to the info record of the issuing ca - * or NULL if it does not [yet] exist - */ - ca_info_t *(*get_ca_info) (const x509_t *this); - - /** - * @brief Create an iterator for the crlDistributionPoints. - * - * @param this calling object - * @return iterator for crlDistributionPoints - */ - iterator_t *(*create_crluri_iterator) (const x509_t *this); - - /** - * @brief Create an iterator for the ocspAccessLocations. - * - * @param this calling object - * @return iterator for ocspAccessLocations - */ - iterator_t *(*create_ocspuri_iterator) (const x509_t *this); - - /** - * @brief Check if a certificate is trustworthy - * - * @param this calling object - * @param signer signer's RSA public key - */ - bool (*verify) (const x509_t *this, const rsa_public_key_t *signer); - - /** - * @brief Compare two certificates. - * - * Comparison is done via the certificates signature. - * - * @param this first cert for compare - * @param other second cert for compare - * @return TRUE if signature is equal - */ - bool (*equals) (const x509_t *this, const x509_t *that); - - /** - * @brief Checks if the certificate contains a subjectAltName equal to id. - * - * @param this certificate being examined - * @param id id which is being compared to the subjectAltNames - * @return TRUE if a match is found - */ - bool (*equals_subjectAltName) (const x509_t *this, identification_t *id); - - /** - * @brief Checks if the subject of the other cert is the issuer of this cert. - * - * @param this certificate - * @param issuer potential issuer certificate - * @return TRUE if issuer is found - */ - bool (*is_issuer) (const x509_t *this, const x509_t *issuer); - - /** - * @brief Checks the validity interval of the certificate - * - * @param this certificate being examined - * @param until until = min(until, notAfter) - * @return NULL if the certificate is valid - */ - err_t (*is_valid) (const x509_t *this, time_t *until); - - /** - * @brief Returns the CA basic constraints flag - * - * @param this certificate being examined - * @return TRUE if the CA flag is set - */ - bool (*is_ca) (const x509_t *this); - - /** - * @brief Returns the OCSPSigner extended key usage flag - * - * @param this certificate being examined - * @return TRUE if the OCSPSigner flag is set - */ - bool (*is_ocsp_signer) (const x509_t *this); - - /** - * @brief Checks if the certificate is self-signed (subject equals issuer) - * - * @param this certificate being examined - * @return TRUE if self-signed - */ - bool (*is_self_signed) (const x509_t *this); - - /** - * @brief Log the certificate info to out. - * - * @param this calling object - * @param out stream to write to - * @param utc TRUE for UTC times, FALSE for local time - */ - void (*list) (x509_t *this, FILE *out, bool utc); - - /** - * @brief Adds a list of subjectAltNames - * - * @param this calling object - * @param subjectAltNames list of subjectAltNames to be added - */ - void (*add_subjectAltNames) (x509_t *this, linked_list_t *subjectAltNames); - - /** - * @brief Builds a DER-encoded signed X.509 certificate - * - * @param this calling object - * @param alg hash algorithm used to compute the certificate digest - * @param private_key RSA private key used to sign the certificate digest - */ - void (*build_encoding) (x509_t *this, hash_algorithm_t alg, rsa_private_key_t *private_key); - - /** - * @brief Destroys the certificate. - * - * @param this certificate to destroy - */ - void (*destroy) (x509_t *this); -}; - -/** - * @brief Create a X.509 certificate from its components - * - * @param serialNumber chunk containing the serialNumber - * @param issuer issuer distinguished name - * @param notBefore start date of validity - * @param notAfter end date of validity - * @param subject subject distinguished name - * @param public_key public key - * - * @return created x509_t certificate, or NULL if invalid. - * - * @ingroup crypto - */ -x509_t *x509_create(chunk_t serialNumber, identification_t *issuer, - time_t notBefore, time_t notAfter, - identification_t *subject, - rsa_public_key_t *public_key); - -/** - * @brief Read a X.509 certificate from a DER encoded blob. - * - * @param chunk chunk containing DER encoded data - * @return created x509_t certificate, or NULL if invalid. - * - * @ingroup crypto - */ -x509_t *x509_create_from_chunk(chunk_t chunk, u_int level); - -/** - * @brief Read a X.509 certificate from a DER encoded file. - * - * @param filename file containing DER encoded data - * @param label label describing kind of certificate - * @return created x509_t certificate, or NULL if invalid. - * - * @ingroup crypto - */ -x509_t *x509_create_from_file(const char *filename, const char *label); - -/** - * @brief Parses a DER encoded authorityKeyIdentifier - * - * @param blob blob containing DER encoded data - * @param level0 indicates the current parsing level - * @param authKeyID assigns the authorityKeyIdentifier - * @param authKeySerialNumber assigns the authKeySerialNumber - * - * @ingroup crypto - */ -void x509_parse_authorityKeyIdentifier(chunk_t blob, int level0, chunk_t *authKeyID, chunk_t *authKeySerialNumber); - -/** - * @brief Parses DER encoded generalNames - * - * @param blob blob containing DER encoded data - * @param level0 indicates the current parsing level - * @param implicit implicit coding is used - * @param list list of decoded generalNames - * - * @ingroup crypto - */ -void x509_parse_generalNames(chunk_t blob, int level0, bool implicit, linked_list_t *list); - -/** - * @brief Builds a DER encoded list of generalNames - * - * @param list list of generalNames to be encoded - * @return DER encoded list of generalNames - * - * @ingroup crypto - */ -chunk_t x509_build_generalNames(linked_list_t *list); - -/** - * @brief Builds a DER encoded list of subjectAltNames - * - * @param list list of subjectAltNames to be encoded - * @return DER encoded list of subjectAltNames - * - * @ingroup crypto - */ -chunk_t x509_build_subjectAltNames(linked_list_t *list); - -#endif /* X509_H_ */ diff --git a/src/libstrongswan/database/database.h b/src/libstrongswan/database/database.h new file mode 100644 index 000000000..3ed09ee13 --- /dev/null +++ b/src/libstrongswan/database/database.h @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 database database + * @{ @ingroup database + */ + +#ifndef DATABASE_H_ +#define DATABASE_H_ + +typedef enum db_type_t db_type_t; +typedef struct database_t database_t; + +#include + +/** + * Database column types + */ +enum db_type_t { + /** integer type, argument is an "int" */ + DB_INT, + /** unsigned integer, argument is an "u_int" */ + DB_UINT, + /** string type, argument is a "char*" */ + DB_TEXT, + /** binary large object type, argument is a "chunk_t" */ + DB_BLOB, + /** floating point, argument is a "double" */ + DB_DOUBLE, + /** NULL, takes no argument */ + DB_NULL, +}; + + +/** + * Interface for a database implementation. + * + * @code + int affected, rowid, aint; + char *atext; + database_t *db; + enumerator_t *enumerator; + + db = lib->database->create("mysql://user:pass@host/database"); + affected = db->execute(db, &rowid, "INSERT INTO table VALUES (?, ?)", + DB_INT, 77, DB_TEXT, "a text"); + printf("inserted %d row, new row ID: %d\n", affected, rowid); + + enumerator = db->query(db, "SELECT aint, atext FROM table WHERE aint > ?", + DB_INT, 10, // 1 argument to SQL string + DB_INT, DB_TEXT); // 2 enumerated types in query + if (enumerator) + { + while (enumerator->enumerate(enumerator, &aint, &atext)) + { + printf("%d: %s\n", aint, atext); + } + enumerator->destroy(enumerator); + } + @endcode + */ +struct database_t { + + /** + * Run a query which returns rows, such as a SELECT. + * + * @param sql sql query string, containing '?' placeholders + * @param ... list of sql placeholder db_type_t followed by its value, + * followed by enumerators arguments as db_type_t's + * @return enumerator as defined with arguments, NULL on failure + */ + enumerator_t* (*query)(database_t *this, char *sql, ...); + + /** + * Execute a query which dows not return rows, such as INSERT. + * + * @param rowid pointer to write inserted AUTO_INCREMENT row ID, or NULL + * @param sql sql string, containing '?' placeholders + * @param ... list of sql placeholder db_type_t followed by its value + * @return number of affected rows, < 0 on failure + */ + int (*execute)(database_t *this, int *rowid, char *sql, ...); + + /** + * Destroy a database connection. + */ + void (*destroy)(database_t *this); +}; + +#endif /* DATABASE_H_ @}*/ diff --git a/src/libstrongswan/database/database_factory.c b/src/libstrongswan/database/database_factory.c new file mode 100644 index 000000000..e72550359 --- /dev/null +++ b/src/libstrongswan/database/database_factory.c @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "database_factory.h" + +#include +#include + +typedef struct private_database_factory_t private_database_factory_t; + +/** + * private data of database_factory + */ +struct private_database_factory_t { + + /** + * public functions + */ + database_factory_t public; + + /** + * list of registered database_t implementations + */ + linked_list_t *databases; + + /** + * mutex to lock access to databases + */ + mutex_t *mutex; +}; + +/** + * Implementation of database_factory_t.create. + */ +static database_t* create(private_database_factory_t *this, char *uri) +{ + enumerator_t *enumerator; + database_t *database = NULL; + database_constructor_t create; + + this->mutex->lock(this->mutex); + enumerator = this->databases->create_enumerator(this->databases); + while (enumerator->enumerate(enumerator, &create)) + { + database = create(uri); + if (database) + { + break; + } + } + enumerator->destroy(enumerator); + this->mutex->unlock(this->mutex); + return database; +} + +/** + * Implementation of database_factory_t.add_database. + */ +static void add_database(private_database_factory_t *this, + database_constructor_t create) +{ + this->mutex->lock(this->mutex); + this->databases->insert_last(this->databases, create); + this->mutex->unlock(this->mutex); +} + +/** + * Implementation of database_factory_t.remove_database. + */ +static void remove_database(private_database_factory_t *this, + database_constructor_t create) +{ + this->mutex->lock(this->mutex); + this->databases->remove(this->databases, create, NULL); + this->mutex->unlock(this->mutex); +} + +/** + * Implementation of database_factory_t.destroy + */ +static void destroy(private_database_factory_t *this) +{ + this->databases->destroy(this->databases); + this->mutex->destroy(this->mutex); + free(this); +} + +/* + * see header file + */ +database_factory_t *database_factory_create() +{ + private_database_factory_t *this = malloc_thing(private_database_factory_t); + + this->public.create = (database_t*(*)(database_factory_t*, char *url))create; + this->public.add_database = (void(*)(database_factory_t*, database_constructor_t))add_database; + this->public.remove_database = (void(*)(database_factory_t*, database_constructor_t))remove_database; + this->public.destroy = (void(*)(database_factory_t*))destroy; + + this->databases = linked_list_create(); + this->mutex = mutex_create(MUTEX_DEFAULT); + + return &this->public; +} + diff --git a/src/libstrongswan/database/database_factory.h b/src/libstrongswan/database/database_factory.h new file mode 100644 index 000000000..358f49054 --- /dev/null +++ b/src/libstrongswan/database/database_factory.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 database_factory database_factory + * @{ @ingroup database + */ + +#ifndef DATABASE_FACTORY_H_ +#define DATABASE_FACTORY_H_ + +typedef struct database_factory_t database_factory_t; + +#include + +/** + * Generic database construction function. + * + * @param uri implementation specific connection URI + */ +typedef database_t*(*database_constructor_t)(char *uri); + +/** + * Create instances of database connections using registered constructors. + */ +struct database_factory_t { + + /** + * Create a database connection instance. + * + * @param uri implementation specific connection URI + * @return database_t instance, NULL if not supported/failed + */ + database_t* (*create)(database_factory_t *this, char *uri); + + /** + * Register a database constructor. + * + * @param create database constructor to register + */ + void (*add_database)(database_factory_t *this, database_constructor_t create); + + /** + * Unregister a previously registered database constructor. + * + * @param create database constructor to unregister + */ + void (*remove_database)(database_factory_t *this, database_constructor_t create); + + /** + * Destroy a database_factory instance. + */ + void (*destroy)(database_factory_t *this); +}; + +/** + * Create a database_factory instance. + */ +database_factory_t *database_factory_create(); + +#endif /* DATABASE_FACTORY_H_ @}*/ diff --git a/src/libstrongswan/debug.c b/src/libstrongswan/debug.c index a71e978b8..a5a509665 100644 --- a/src/libstrongswan/debug.c +++ b/src/libstrongswan/debug.c @@ -1,10 +1,3 @@ -/** - * @file library.c - * - * @brief Logging functions for the library. - * - */ - /* * Copyright (C) 2006 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,8 @@ * 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. + * + * $Id$ */ #include diff --git a/src/libstrongswan/debug.h b/src/libstrongswan/debug.h index 71f2c7dfd..611569c7a 100644 --- a/src/libstrongswan/debug.h +++ b/src/libstrongswan/debug.h @@ -1,10 +1,3 @@ -/** - * @file log.h - * - * @brief Logging functions for the library. - * - */ - /* * Copyright (C) 2006 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup debug debug + * @{ @ingroup libstrongswan */ #ifndef DEBUG_H_ @@ -60,4 +60,4 @@ extern void (*dbg) (int level, char *fmt, ...); /** default logging function, prints to stderr */ void dbg_default(int level, char *fmt, ...); -#endif /* DEBUG_H_ */ +#endif /* DEBUG_H_ @} */ diff --git a/src/libstrongswan/enum.c b/src/libstrongswan/enum.c index ade7c16a1..724246e25 100644 --- a/src/libstrongswan/enum.c +++ b/src/libstrongswan/enum.c @@ -1,10 +1,3 @@ -/** - * @file library.c - * - * @brief enum value to string conversion functions. - * - */ - /* * Copyright (C) 2006 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,8 @@ * 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. + * + * $Id$ */ #include @@ -46,7 +41,7 @@ static char *enum_name(enum_name_t *e, int val) /** * output handler in printf() for enum names */ -static int print_enum(FILE *stream, const struct printf_info *info, +static int print(FILE *stream, const struct printf_info *info, const void *const *args) { enum_name_t *ed = *((enum_name_t**)(args[0])); @@ -65,9 +60,25 @@ static int print_enum(FILE *stream, const struct printf_info *info, } /** - * register printf() handlers + * arginfo handler for printf() hook + */ +static int arginfo(const struct printf_info *info, size_t n, int *argtypes) +{ + if (n > 1) + { + argtypes[0] = PA_POINTER; + argtypes[1] = PA_INT; + } + return 2; +} + +/** + * return printf hook functions */ -static void __attribute__ ((constructor))print_register() +printf_hook_functions_t enum_get_printf_hooks() { - register_printf_function(PRINTF_ENUM, print_enum, arginfo_ptr_int); + printf_hook_functions_t hooks = {print, arginfo}; + + return hooks; } + diff --git a/src/libstrongswan/enum.h b/src/libstrongswan/enum.h index cd06e424b..cbf15de73 100644 --- a/src/libstrongswan/enum.h +++ b/src/libstrongswan/enum.h @@ -1,12 +1,5 @@ -/** - * @file enum.h - * - * @brief enum value to string conversion functions. - * - */ - /* - * Copyright (C) 2006 Martin Willi + * Copyright (C) 2006-2008 Martin Willi * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -18,15 +11,24 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup enum enum + * @{ @ingroup libstrongswan */ #ifndef ENUM_H_ #define ENUM_H_ +#include + typedef struct enum_name_t enum_name_t; /** - * @brief Struct to store names for enums. + * Struct to store names for enums. * * To print the string representation of enumeration values, the strings * are stored in these structures. Every enum_name contains a range @@ -34,14 +36,16 @@ typedef struct enum_name_t enum_name_t; * Use the convenience macros to define these linked ranges. * * For a single range, use: - * ENUM(name, first, last, string1, string2, ...) - * + * @code + ENUM(name, first, last, string1, string2, ...) + @endcode * For multiple linked ranges, use: - * ENUM_BEGIN(name, first, last, string1, string2, ...) - * ENUM_NEXT(name, first, last, last_from_previous, string3, ...) - * ENUM_NEXT(name, first, last, last_from_previous, string4, ...) - * ENUM_END(name, last_from_previous) - * + * @code + ENUM_BEGIN(name, first, last, string1, string2, ...) + ENUM_NEXT(name, first, last, last_from_previous, string3, ...) + ENUM_NEXT(name, first, last, last_from_previous, string4, ...) + ENUM_END(name, last_from_previous) + @endcode * The ENUM and the ENUM_END define a enum_name_t pointer with the name supplied * in "name". * @@ -62,7 +66,7 @@ struct enum_name_t { }; /** - * @brief Begin a new enum_name list. + * Begin a new enum_name list. * * @param name name of the enum_name list * @param first enum value of the first enum string @@ -72,7 +76,7 @@ struct enum_name_t { #define ENUM_BEGIN(name, first, last, ...) static enum_name_t name##last = {first, last, NULL, { __VA_ARGS__ }} /** - * @brief Continue a enum name list startetd with ENUM_BEGIN. + * Continue a enum name list startetd with ENUM_BEGIN. * * @param name name of the enum_name list * @param first enum value of the first enum string @@ -83,7 +87,7 @@ struct enum_name_t { #define ENUM_NEXT(name, first, last, prev, ...) static enum_name_t name##last = {first, last, &name##prev, { __VA_ARGS__ }} /** - * @brief Complete enum name list started with ENUM_BEGIN. + * Complete enum name list started with ENUM_BEGIN. * * @param name name of the enum_name list * @param prev enum value of the "last" defined in ENUM_BEGIN/previous ENUM_NEXT @@ -91,7 +95,7 @@ struct enum_name_t { #define ENUM_END(name, prev) enum_name_t *name = &name##prev; /** - * @brief Define a enum name with only one range. + * Define a enum name with only one range. * * This is a convenience macro to use when a enum_name list contains only * one range, and is equal as defining ENUM_BEGIN followed by ENUM_END. @@ -103,4 +107,13 @@ struct enum_name_t { */ #define ENUM(name, first, last, ...) ENUM_BEGIN(name, first, last, __VA_ARGS__); ENUM_END(name, last) -#endif /* ENUM_H_ */ +/** + * Get printf hook functions for enum_names_t. + * + * The handler takes the arguments: enum_names_t *names, int value + * + * @return printf hook functions + */ +printf_hook_functions_t enum_get_printf_hooks(); + +#endif /* ENUM_H_ @}*/ diff --git a/src/libstrongswan/fetcher/fetcher.h b/src/libstrongswan/fetcher/fetcher.h new file mode 100644 index 000000000..5cd021d4e --- /dev/null +++ b/src/libstrongswan/fetcher/fetcher.h @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 fetcher fetcher + * @{ @ingroup fetcher + */ + +#ifndef FETCHER_H_ +#define FETCHER_H_ + +typedef struct fetcher_t fetcher_t; +typedef enum fetcher_option_t fetcher_option_t; + +#include + +#include + +/** + * Fetching options to use for fetcher_t.fetch() call. + */ +enum fetcher_option_t { + + /** + * Data to include in fetch request, e.g. on a HTTP post. + * Additional argument is a chunk_t + */ + FETCH_REQUEST_DATA, + + /** + * Mime-Type of data included in FETCH_REQUEST_DATA. + * Additional argument is a char*. + */ + FETCH_REQUEST_TYPE, + + /** + * Timeout to use for fetch, in seconds. + * Additional argument is u_int + */ + FETCH_TIMEOUT, + + /** + * end of fetching options + */ + FETCH_END, +}; + +/** + * Constructor function which creates fetcher instances. + * + * @return fetcher instance + */ +typedef fetcher_t* (*fetcher_constructor_t)(); + +/** + * Fetcher interface, an implementation fetches data from an URL. + */ +struct fetcher_t { + + /** + * Fetch data from URI into chunk. + * + * The fetcher returns NOT_SUPPORTED to indicate that it is uncappable + * to handle such URLs. Other return values indicate a failure, and + * fetching of that URL gets cancelled. + * + * @param uri URI to fetch from + * @param result chunk which receives allocated data + * @return + * - SUCCESS if fetch was successful + * - NOT_SUPPORTED if fetcher does not support such URLs + * - FAILED, NOT_FOUND, PARSE_ERROR on failure + */ + status_t (*fetch)(fetcher_t *this, char *uri, chunk_t *result); + + /** + * Set a fetcher option, as defined in fetcher_option_t. + * + * Arguments passed to options must stay in memory until fetch() returns. + * + * @param option option to set + * @param ... variable argument(s) to option + * @return TRUE if option supported, FALSE otherwise + */ + bool (*set_option)(fetcher_t *this, fetcher_option_t option, ...); + + /** + * Destroy the fetcher instance. + */ + void (*destroy)(fetcher_t *this); +}; + +#endif /* FETCHER_H_ @}*/ diff --git a/src/libstrongswan/fetcher/fetcher_manager.c b/src/libstrongswan/fetcher/fetcher_manager.c new file mode 100644 index 000000000..286679616 --- /dev/null +++ b/src/libstrongswan/fetcher/fetcher_manager.c @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "fetcher_manager.h" + +#include +#include +#include + +typedef struct private_fetcher_manager_t private_fetcher_manager_t; + +/** + * private data of fetcher_manager + */ +struct private_fetcher_manager_t { + + /** + * public functions + */ + fetcher_manager_t public; + + /** + * list of registered fetchers, as entry_t + */ + linked_list_t *fetchers; + + /** + * read write lock to list + */ + pthread_rwlock_t lock; +}; + +typedef struct { + /** assocaited fetcher construction function */ + fetcher_constructor_t create; + /** URL this fetcher support */ + char *url; +} entry_t; + +/** + * destroy an entry_t + */ +static void entry_destroy(entry_t *entry) +{ + free(entry->url); + free(entry); +} + +/** + * Implementation of fetcher_manager_t.fetch. + */ +static status_t fetch(private_fetcher_manager_t *this, + char *url, chunk_t *response, ...) +{ + enumerator_t *enumerator; + status_t status = NOT_SUPPORTED; + entry_t *entry; + bool capable = FALSE; + + pthread_rwlock_rdlock(&this->lock); + enumerator = this->fetchers->create_enumerator(this->fetchers); + while (enumerator->enumerate(enumerator, &entry)) + { + fetcher_option_t opt; + fetcher_t *fetcher; + bool good = TRUE; + va_list args; + + /* check URL support of fetcher */ + if (strncasecmp(entry->url, url, strlen(entry->url))) + { + continue; + } + /* create fetcher instance and set options */ + fetcher = entry->create(); + if (!fetcher) + { + continue; + } + va_start(args, response); + while (good) + { + opt = va_arg(args, fetcher_option_t); + switch (opt) + { + case FETCH_REQUEST_DATA: + good = fetcher->set_option(fetcher, opt, va_arg(args, chunk_t)); + continue; + case FETCH_REQUEST_TYPE: + good = fetcher->set_option(fetcher, opt, va_arg(args, char*)); + continue; + case FETCH_TIMEOUT: + good = fetcher->set_option(fetcher, opt, va_arg(args, u_int)); + continue; + case FETCH_END: + break;; + } + break; + } + va_end(args); + if (!good) + { /* fetcher does not support supplied options, try another */ + fetcher->destroy(fetcher); + continue; + } + + status = fetcher->fetch(fetcher, url, response); + fetcher->destroy(fetcher); + /* try another fetcher only if this one does not support that URL */ + if (status == NOT_SUPPORTED) + { + continue; + } + capable = TRUE; + break; + } + enumerator->destroy(enumerator); + pthread_rwlock_unlock(&this->lock); + if (!capable) + { + DBG1("unable to fetch from %s, no capable fetcher found", url); + } + return status; +} + +/** + * Implementation of fetcher_manager_t.add_fetcher. + */ +static void add_fetcher(private_fetcher_manager_t *this, + fetcher_constructor_t create, char *url) +{ + entry_t *entry = malloc_thing(entry_t); + + entry->url = strdup(url); + entry->create = create; + + pthread_rwlock_wrlock(&this->lock); + this->fetchers->insert_last(this->fetchers, entry); + pthread_rwlock_unlock(&this->lock); +} + +/** + * Implementation of fetcher_manager_t.remove_fetcher. + */ +static void remove_fetcher(private_fetcher_manager_t *this, + fetcher_constructor_t create) +{ + enumerator_t *enumerator; + entry_t *entry; + + pthread_rwlock_wrlock(&this->lock); + enumerator = this->fetchers->create_enumerator(this->fetchers); + while (enumerator->enumerate(enumerator, &entry)) + { + if (entry->create == create) + { + this->fetchers->remove_at(this->fetchers, enumerator); + entry_destroy(entry); + } + } + enumerator->destroy(enumerator); + pthread_rwlock_unlock(&this->lock); +} + +/** + * Implementation of fetcher_manager_t.destroy + */ +static void destroy(private_fetcher_manager_t *this) +{ + this->fetchers->destroy_function(this->fetchers, (void*)entry_destroy); + pthread_rwlock_destroy(&this->lock); + free(this); +} + +/* + * see header file + */ +fetcher_manager_t *fetcher_manager_create() +{ + private_fetcher_manager_t *this = malloc_thing(private_fetcher_manager_t); + + this->public.fetch = (status_t(*)(fetcher_manager_t*, char *url, chunk_t *response, ...))fetch; + this->public.add_fetcher = (void(*)(fetcher_manager_t*, fetcher_constructor_t,char*))add_fetcher; + this->public.remove_fetcher = (void(*)(fetcher_manager_t*, fetcher_constructor_t))remove_fetcher; + this->public.destroy = (void(*)(fetcher_manager_t*))destroy; + + this->fetchers = linked_list_create(); + pthread_rwlock_init(&this->lock, NULL); + + return &this->public; +} + diff --git a/src/libstrongswan/fetcher/fetcher_manager.h b/src/libstrongswan/fetcher/fetcher_manager.h new file mode 100644 index 000000000..e94d44494 --- /dev/null +++ b/src/libstrongswan/fetcher/fetcher_manager.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 fetcher_manager fetcher_manager + * @{ @ingroup fetcher + */ + +#ifndef FETCHER_MANAGER_H_ +#define FETCHER_MANAGER_H_ + +typedef struct fetcher_manager_t fetcher_manager_t; + +#include + +/** + * Fetches from URIs using registerd fetcher_t instances. + */ +struct fetcher_manager_t { + + /** + * Fetch data from URI into chunk. + * + * The variable argument list contains fetcher_option_t's, followed + * by a option specific data argument. + * + * @param uri URI to fetch from + * @param result chunk which receives allocated data + * @param options FETCH_END terminated fetcher_option_t arguments + * @return status indicating result of fetch + */ + status_t (*fetch)(fetcher_manager_t *this, char *url, chunk_t *response, ...); + + /** + * Register a fetcher implementation. + * + * @param constructor fetcher constructor function + * @param url URL type this fetcher fetches, e.g. "http://" + */ + void (*add_fetcher)(fetcher_manager_t *this, + fetcher_constructor_t constructor, char *url); + + /** + * Unregister a previously registered fetcher implementation. + * + * @param constructor fetcher constructor function to unregister + */ + void (*remove_fetcher)(fetcher_manager_t *this, + fetcher_constructor_t constructor); + + /** + * Destroy a fetcher_manager instance. + */ + void (*destroy)(fetcher_manager_t *this); +}; + +/** + * Create a fetcher_manager instance. + */ +fetcher_manager_t *fetcher_manager_create(); + +#endif /* FETCHER_MANAGER_H_ @}*/ diff --git a/src/libstrongswan/fips/fips.c b/src/libstrongswan/fips/fips.c index aba292d81..6701e1f5d 100644 --- a/src/libstrongswan/fips/fips.c +++ b/src/libstrongswan/fips/fips.c @@ -1,10 +1,3 @@ -/** - * @file fips.c - * - * @brief Implementation of the libstrongswan integrity test. - * - */ - /* * Copyright (C) 2007 Bruno Krieg, Daniel Wydler * Hochschule fuer Technik Rapperswil @@ -18,6 +11,8 @@ * 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. + * + * $Id$ */ #include diff --git a/src/libstrongswan/fips/fips.h b/src/libstrongswan/fips/fips.h index decf73bfd..f252ad6d1 100644 --- a/src/libstrongswan/fips/fips.h +++ b/src/libstrongswan/fips/fips.h @@ -1,11 +1,3 @@ -/** - * @file fips.h - * - * @brief Interface of the libstrongswan integrity test - * - * @ingroup fips - */ - /* * Copyright (C) 2007 Bruno Krieg, Daniel Wydler * Hochschule fuer Technik Rapperswil @@ -19,6 +11,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup fips fips + * @{ @ingroup fips */ #ifndef FIPS_H_ @@ -27,21 +26,21 @@ #include /** - * @brief compute HMAC signature over RODATA and TEXT sections of libstrongswan + * compute HMAC signature over RODATA and TEXT sections of libstrongswan * - * @param key key used for HMAC signature in ASCII string format - * @param signature HMAC signature in HEX string format - * @return TRUE if HMAC signature computation was successful + * @param key key used for HMAC signature in ASCII string format + * @param signature HMAC signature in HEX string format + * @return TRUE if HMAC signature computation was successful */ bool fips_compute_hmac_signature(const char *key, char *signature); /** - * @brief verify HMAC signature over RODATA and TEXT sections of libstrongswan + * verify HMAC signature over RODATA and TEXT sections of libstrongswan * - * @param key key used for HMAC signature in ASCII string format - * @param signature signature value from fips_signature.h in HEX string format - * @return TRUE if signatures agree + * @param key key used for HMAC signature in ASCII string format + * @param signature signature value from fips_signature.h in HEX string format + * @return TRUE if signatures agree */ bool fips_verify_hmac_signature(const char *key, const char *signature); -#endif /*FIPS_H_*/ +#endif /*FIPS_H_ @} */ diff --git a/src/libstrongswan/fips/fips_canister_end.c b/src/libstrongswan/fips/fips_canister_end.c index 46d41a664..e210b6c09 100644 --- a/src/libstrongswan/fips/fips_canister_end.c +++ b/src/libstrongswan/fips/fips_canister_end.c @@ -1,14 +1,9 @@ -/** - * @file fips_canister_end.c - * - * @brief Marks the end of TEXT and RODATA. - * - */ - /* ==================================================================== * Copyright (c) 2005 The OpenSSL Project. Rights for redistribution * and usage in source and binary forms are granted according to the * OpenSSL license. + * + * $Id$ */ #include diff --git a/src/libstrongswan/fips/fips_canister_start.c b/src/libstrongswan/fips/fips_canister_start.c index eaf2571f8..be8e226cf 100644 --- a/src/libstrongswan/fips/fips_canister_start.c +++ b/src/libstrongswan/fips/fips_canister_start.c @@ -1,14 +1,9 @@ -/** - * @file fips_canister_start.c - * - * @brief Marks the start of TEXT and RODATA. - * - */ - /* ==================================================================== * Copyright (c) 2005 The OpenSSL Project. Rights for redistribution * and usage in source and binary forms are granted according to the * OpenSSL license. + * + * $Id$ */ #include diff --git a/src/libstrongswan/fips/fips_signer.c b/src/libstrongswan/fips/fips_signer.c index 7fb61d5b7..d4679435c 100644 --- a/src/libstrongswan/fips/fips_signer.c +++ b/src/libstrongswan/fips/fips_signer.c @@ -1,10 +1,3 @@ -/** - * @file fips_signer.c - * - * @brief Computes a HMAC signature and stores it in fips_signature.h. - * - */ - /* * Copyright (C) 2007 Bruno Krieg, Daniel Wydler * Hochschule fuer Technik Rapperswil, Switzerland @@ -18,6 +11,8 @@ * 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. + * + * $Id$ */ #include @@ -57,7 +52,7 @@ int main(int argc, char* argv[]) fprintf(f, "const char *hmac_key = \"%s\";\n", hmac_key); fprintf(f, "const char *hmac_signature = \"%s\";\n", hmac_signature); fprintf(f, "\n"); - fprintf(f, "#endif /* FIPS_SIGNATURE_H_ */\n"); + fprintf(f, "#endif /* FIPS_SIGNATURE_H_ @} */\n"); fclose(f); exit(0); } diff --git a/src/libstrongswan/library.c b/src/libstrongswan/library.c index f66818bc2..e265a1a3e 100644 --- a/src/libstrongswan/library.c +++ b/src/libstrongswan/library.c @@ -1,13 +1,5 @@ -/** - * @file library.c - * - * @brief Helper functions and definitions. - * - */ - /* - * Copyright (C) 2005-2006 Martin Willi - * Copyright (C) 2005 Jan Hutter + * Copyright (C) 2008 Martin Willi * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -19,175 +11,99 @@ * 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. + * + * $Id$ */ -#include -#include -#include -#include -#include - #include "library.h" -#include +#include -ENUM(status_names, SUCCESS, DESTROY_ME, - "SUCCESS", - "FAILED", - "OUT_OF_RES", - "ALREADY_DONE", - "NOT_SUPPORTED", - "INVALID_ARG", - "NOT_FOUND", - "PARSE_ERROR", - "VERIFY_ERROR", - "INVALID_STATE", - "DESTROY_ME", - "NEED_MORE", -); +#include +#include +#include +#include +#include -/** - * Described in header. - */ -void *clalloc(void * pointer, size_t size) -{ - void *data; - data = malloc(size); - - memcpy(data, pointer,size); - - return (data); -} +typedef struct private_library_t private_library_t; /** - * Described in header. + * private data of library */ -void memxor(u_int8_t dest[], u_int8_t src[], size_t n) -{ - size_t i; - for (i = 0; i < n; i++) - { - dest[i] ^= src[i]; - } -} +struct private_library_t { -/** - * We use a single mutex for all refcount variables. This - * is not optimal for performance, but the critical section - * is not that long... - * TODO: Consider to include a mutex in each refcount_t variable. - */ -static pthread_mutex_t ref_mutex = PTHREAD_MUTEX_INITIALIZER; + /** + * public functions + */ + library_t public; -/** - * Described in header. - * - * TODO: May be implemented with atomic CPU instructions - * instead of a mutex. - */ -void ref_get(refcount_t *ref) -{ - pthread_mutex_lock(&ref_mutex); - (*ref)++; - pthread_mutex_unlock(&ref_mutex); -} +#ifdef LEAK_DETECTIVE + /** + * Memory leak detective, if enabled + */ + leak_detective_t *detective; +#endif /* LEAK_DETECTIVE */ +}; /** - * Described in header. - * - * TODO: May be implemented with atomic CPU instructions - * instead of a mutex. + * library instance */ -bool ref_put(refcount_t *ref) -{ - bool more_refs; - - pthread_mutex_lock(&ref_mutex); - more_refs = --(*ref); - pthread_mutex_unlock(&ref_mutex); - return !more_refs; -} +library_t *lib; /** - * output handler in printf() for time_t + * Implementation of library_t.destroy */ -static int print_time(FILE *stream, const struct printf_info *info, - const void *const *args) +void library_deinit() { - static const char* months[] = { - "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" - }; - time_t *time = *((time_t**)(args[0])); - bool utc = TRUE; - struct tm t; + private_library_t *this = (private_library_t*)lib; + + this->public.plugins->destroy(this->public.plugins); + this->public.settings->destroy(this->public.settings); + this->public.creds->destroy(this->public.creds); + this->public.crypto->destroy(this->public.crypto); + this->public.fetcher->destroy(this->public.fetcher); + this->public.db->destroy(this->public.db); + this->public.printf_hook->destroy(this->public.printf_hook); - if (info->alt) - { - utc = *((bool*)(args[1])); - } - if (time == UNDEFINED_TIME) - { - return fprintf(stream, "--- -- --:--:--%s----", - info->alt ? " UTC " : " "); - } - if (utc) - { - gmtime_r(time, &t); - } - else +#ifdef LEAK_DETECTIVE + if (this->detective) { - localtime_r(time, &t); + this->detective->destroy(this->detective); } - return fprintf(stream, "%s %02d %02d:%02d:%02d%s%04d", - months[t.tm_mon], t.tm_mday, t.tm_hour, t.tm_min, - t.tm_sec, utc ? " UTC " : " ", t.tm_year + 1900); +#endif /* LEAK_DETECTIVE */ + free(this); + lib = NULL; } -/** - * output handler in printf() for time deltas +/* + * see header file */ -static int print_time_delta(FILE *stream, const struct printf_info *info, - const void *const *args) +void library_init(char *settings) { - char* unit = "second"; - time_t *arg1, *arg2; - time_t delta; + printf_hook_t *pfh; + private_library_t *this = malloc_thing(private_library_t); + lib = &this->public; - arg1 = *((time_t**)(args[0])); - if (info->alt) - { - arg2 = *((time_t**)(args[1])); - delta = abs(*arg1 - *arg2); - } - else - { - delta = *arg1; - } +#ifdef LEAK_DETECTIVE + this->detective = leak_detective_create(); +#endif /* LEAK_DETECTIVE */ - if (delta > 2 * 60 * 60 * 24) - { - delta /= 60 * 60 * 24; - unit = "day"; - } - else if (delta > 2 * 60 * 60) - { - delta /= 60 * 60; - unit = "hour"; - } - else if (delta > 2 * 60) - { - delta /= 60; - unit = "minute"; - } - return fprintf(stream, "%d %s%s", delta, unit, (delta == 1)? "":"s"); + pfh = printf_hook_create(); + this->public.printf_hook = pfh; + + pfh->add_handler(pfh, 'b', mem_get_printf_hooks()); + pfh->add_handler(pfh, 'B', chunk_get_printf_hooks()); + pfh->add_handler(pfh, 'D', identification_get_printf_hooks()); + pfh->add_handler(pfh, 'H', host_get_printf_hooks()); + pfh->add_handler(pfh, 'N', enum_get_printf_hooks()); + pfh->add_handler(pfh, 'T', time_get_printf_hooks()); + pfh->add_handler(pfh, 'V', time_delta_get_printf_hooks()); + + this->public.crypto = crypto_factory_create(); + this->public.creds = credential_factory_create(); + this->public.fetcher = fetcher_manager_create(); + this->public.db = database_factory_create(); + this->public.settings = settings_create(settings); + this->public.plugins = plugin_loader_create(); } -/** - * register printf() handlers for time_t - */ -static void __attribute__ ((constructor))print_register() -{ - register_printf_function(PRINTF_TIME, print_time, arginfo_ptr_alt_ptr_int); - register_printf_function(PRINTF_TIME_DELTA, print_time_delta, arginfo_ptr_alt_ptr_ptr); -} diff --git a/src/libstrongswan/library.h b/src/libstrongswan/library.h index bbe863fa0..9d151c4cc 100644 --- a/src/libstrongswan/library.h +++ b/src/libstrongswan/library.h @@ -1,12 +1,5 @@ -/** - * @file library.h - * - * @brief Helper functions and definitions. - * - */ - /* - * Copyright (C) 2006 Martin Willi + * Copyright (C) 2008 Martin Willi * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -19,318 +12,119 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id$ + * $Id$ */ -#ifndef LIBRARY_H_ -#define LIBRARY_H_ - /** * @defgroup libstrongswan libstrongswan * - * libstrongswan: library with various cryptographic, X.509 trust chain and - * identity management functions. - */ - -/** * @defgroup asn1 asn1 - * - * ASN.1 definitions, parser and generator functions. - * * @ingroup libstrongswan - */ - -/** - * @defgroup crypto crypto - * - * Various cryptographic algorithms. * + * @defgroup credentials credentials * @ingroup libstrongswan - */ - -/** - * @defgroup crypters crypters - * - * Symmetric encryption algorithms, used for - * encryption and decryption. - * - * @ingroup crypto - */ - -/** - * @defgroup hashers hashers - * - * Hashing algorithms, such as MD5 or SHA1 - * - * @ingroup crypto - */ - -/** - * @defgroup prfs prfs - * - * Pseudo random functions, used to generate - * pseude random byte sequences. - * - * @ingroup crypto - */ - -/** - * @defgroup rsa rsa - * - * RSA private/public key algorithm. * - * @ingroup crypto - */ - -/** - * @defgroup signers signers + * @defgroup keys keys + * @ingroup credentials * - * Symmetric signing algorithms, - * used to ensure message integrity. + * @defgroup certificates certificates + * @ingroup credentials * - * @ingroup crypto - */ - -/** + * @defgroup crypto crypto + * @ingroup libstrongswan + + * @defgroup database database + * @ingroup libstrongswan + + * @defgroup fetcher fetcher + * @ingroup libstrongswan + * @defgroup fips fips - * - * Code integrity check of libstrongswan - * * @ingroup libstrongswan - */ - -/** + + * @defgroup plugins plugins + * @ingroup libstrongswan + * @defgroup utils utils - * - * Generic helper classes. - * * @ingroup libstrongswan */ -#include -#include -#include -#include -#include - -#include - -/** - * Number of bits in a byte - */ -#define BITS_PER_BYTE 8 - -/** - * Default length for various auxiliary text buffers - */ -#define BUF_LEN 512 - -/** - * Macro compares two strings for equality - */ -#define streq(x,y) (strcmp(x, y) == 0) - -/** - * Macro compares two strings for equality - */ -#define strneq(x,y,len) (strncmp(x, y, len) == 0) - -/** - * Macro compares two binary blobs for equality - */ -#define memeq(x,y,len) (memcmp(x, y, len) == 0) - -/** - * Macro gives back larger of two values. - */ -#define max(x,y) ((x) > (y) ? (x):(y)) - -/** - * Macro gives back smaller of two values. - */ -#define min(x,y) ((x) < (y) ? (x):(y)) - -/** - * Call destructor of an object, if object != NULL - */ -#define DESTROY_IF(obj) if (obj) obj->destroy(obj) - -/** - * Call offset destructor of an object, if object != NULL - */ -#define DESTROY_OFFSET_IF(obj, offset) if (obj) obj->destroy_offset(obj, offset); - /** - * Call function destructor of an object, if object != NULL + * @defgroup library library + * @{ @ingroup libstrongswan */ -#define DESTROY_FUNCTION_IF(obj, fn) if (obj) obj->destroy_function(obj, fn); -/** - * Debug macro to follow control flow - */ -#define POS printf("%s, line %d\n", __FILE__, __LINE__) - -/** - * Macro to allocate a sized type. - */ -#define malloc_thing(thing) ((thing*)malloc(sizeof(thing))) +#ifndef LIBRARY_H_ +#define LIBRARY_H_ -/** - * Assign a function as a class method - */ -#define ASSIGN(method, function) (method = (typeof(method))function) +#include +#include +#include +#include +#include +#include +#include +#include +#include -/** - * time_t not defined - */ -#define UNDEFINED_TIME 0 +typedef struct library_t library_t; /** - * General purpose boolean type. + * Libstrongswan library context, contains library relevant globals. */ -typedef int bool; -#define FALSE 0 -#define TRUE 1 - -typedef enum status_t status_t; +struct library_t { -/** - * Return values of function calls. - */ -enum status_t { - /** - * Call succeeded. - */ - SUCCESS, - - /** - * Call failed. - */ - FAILED, - - /** - * Out of resources. - */ - OUT_OF_RES, - - /** - * The suggested operation is already done - */ - ALREADY_DONE, - /** - * Not supported. + * Printf hook registering facility */ - NOT_SUPPORTED, + printf_hook_t *printf_hook; /** - * One of the arguments is invalid. + * crypto algorithm registry and factory */ - INVALID_ARG, + crypto_factory_t *crypto; /** - * Something could not be found. + * credential constructor registry and factory */ - NOT_FOUND, + credential_factory_t *creds; /** - * Error while parsing. + * URL fetching facility */ - PARSE_ERROR, + fetcher_manager_t *fetcher; /** - * Error while verifying. + * database construction factory */ - VERIFY_ERROR, + database_factory_t *db; /** - * Object in invalid state. + * plugin loading facility */ - INVALID_STATE, + plugin_loader_t *plugins; /** - * Destroy object which called method belongs to. + * various settings loaded from settings file */ - DESTROY_ME, - - /** - * Another call to the method is required. - */ - NEED_MORE, + settings_t *settings; }; /** - * used by strict_crl_policy - */ -typedef enum { - STRICT_NO, - STRICT_YES, - STRICT_IFURI -} strict_t; - -/** - * enum_names for type status_t. - */ -extern enum_name_t *status_names; - -/** - * deprecated pluto style return value: - * error message, NULL for success - */ -typedef const char *err_t; - -/** - * Handle struct timeval like an own type. - */ -typedef struct timeval timeval_t; - -/** - * Handle struct timespec like an own type. - */ -typedef struct timespec timespec_t; - -/** - * Handle struct chunk_t like an own type. - */ -typedef struct sockaddr sockaddr_t; - -/** - * Clone a data to a newly allocated buffer - */ -void *clalloc(void *pointer, size_t size); - -/** - * Same as memcpy, but XORs src into dst instead of copy - */ -void memxor(u_int8_t dest[], u_int8_t src[], size_t n); - -/** - * Special type to count references + * Initialize library, creates "lib" instance. + * + * @param settings file to read settings from, may be NULL for none */ -typedef volatile u_int refcount_t; +void library_init(char *settings); /** - * @brief Get a new reference. - * - * Increments the reference counter atomic. - * - * @param ref pointer to ref counter + * Deinitialize library, destroys "lib" instance. */ -void ref_get(refcount_t *ref); +void library_deinit(); /** - * @brief Put back a unused reference. - * - * Decrements the reference counter atomic and - * says if more references available. - * - * @param ref pointer to ref counter - * @return TRUE if no more references counted + * Library instance, set after between library_init() and library_deinit() calls. */ -bool ref_put(refcount_t *ref); - - -#include -#include +extern library_t *lib; -#endif /* LIBRARY_H_ */ +#endif /* LIBRARY_H_ @}*/ diff --git a/src/libstrongswan/plugins/aes/Makefile.am b/src/libstrongswan/plugins/aes/Makefile.am new file mode 100644 index 000000000..e73040f27 --- /dev/null +++ b/src/libstrongswan/plugins/aes/Makefile.am @@ -0,0 +1,10 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan + +AM_CFLAGS = -rdynamic + +plugin_LTLIBRARIES = libstrongswan-aes.la + +libstrongswan_aes_la_SOURCES = aes_plugin.h aes_plugin.c aes_crypter.c aes_crypter.h +libstrongswan_aes_la_LDFLAGS = -module + diff --git a/src/libstrongswan/plugins/aes/aes_crypter.c b/src/libstrongswan/plugins/aes/aes_crypter.c new file mode 100644 index 000000000..f0c31cfa2 --- /dev/null +++ b/src/libstrongswan/plugins/aes/aes_crypter.c @@ -0,0 +1,1621 @@ +/* + * Copyright (C) 2001 Dr B. R. Gladman + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "aes_crypter.h" + +/* + * The number of key schedule words for different block and key lengths + * allowing for method of computation which requires the length to be a + * multiple of the key length. This version of AES implementation supports + * all three keylengths 16, 24 and 32 bytes! + * + * Nk = 4 6 8 + * ------------- + * Nb = 4 | 60 60 64 + * 6 | 96 90 96 + * 8 | 120 120 120 + */ +#define AES_KS_LENGTH 120 +#define AES_RC_LENGTH 29 + +#define AES_BLOCK_SIZE 16 + +typedef struct private_aes_crypter_t private_aes_crypter_t; + +/** + * Class implementing the AES symmetric encryption algorithm. + * + * @ingroup crypters + */ +struct private_aes_crypter_t { + + /** + * Public part of this class. + */ + aes_crypter_t public; + + /** + * Number of words in the key input block. + */ + u_int32_t aes_Nkey; + + /** + * The number of cipher rounds. + */ + u_int32_t aes_Nrnd; + + /** + * The encryption key schedule. + */ + u_int32_t aes_e_key[AES_KS_LENGTH]; + + /** + * The decryption key schedule. + */ + u_int32_t aes_d_key[AES_KS_LENGTH]; + + /** + * Key size of this AES cypher object. + */ + u_int32_t key_size; + + /** + * Decrypts a block. + * + * No memory gets allocated. + * + * @param this calling object + * @param[in] in_blk block to decrypt + * @param[out] out_blk decrypted data are written to this location + */ + void (*decrypt_block) (const private_aes_crypter_t *this, const unsigned char in_blk[], unsigned char out_blk[]); + + /** + * Encrypts a block. + * + * No memory gets allocated. + * + * @param this calling object + * @param[in] in_blk block to encrypt + * @param[out] out_blk encrypted data are written to this location + */ + void (*encrypt_block) (const private_aes_crypter_t *this, const unsigned char in_blk[], unsigned char out_blk[]); +}; + + +/* ugly macro stuff */ + +/* 1. Define UNROLL for full loop unrolling in encryption and decryption. + * 2. Define PARTIAL_UNROLL to unroll two loops in encryption and decryption. + * 3. Define FIXED_TABLES for compiled rather than dynamic tables. + * 4. Define FF_TABLES to use tables for field multiplies and inverses. + * Do not enable this without understanding stack space requirements. + * 5. Define ARRAYS to use arrays to hold the local state block. If this + * is not defined, individually declared 32-bit words are used. + * 6. Define FAST_VARIABLE if a high speed variable block implementation + * is needed (essentially three separate fixed block size code sequences) + * 7. Define either ONE_TABLE or FOUR_TABLES for a fast table driven + * version using 1 table (2 kbytes of table space) or 4 tables (8 + * kbytes of table space) for higher speed. + * 8. Define either ONE_LR_TABLE or FOUR_LR_TABLES for a further speed + * increase by using tables for the last rounds but with more table + * space (2 or 8 kbytes extra). + * 9. If neither ONE_TABLE nor FOUR_TABLES is defined, a compact but + * slower version is provided. + * 10. If fast decryption key scheduling is needed define ONE_IM_TABLE + * or FOUR_IM_TABLES for higher speed (2 or 8 kbytes extra). + */ + +#define UNROLL +//#define PARTIAL_UNROLL + +#define FIXED_TABLES +//#define FF_TABLES +//#define ARRAYS +#define FAST_VARIABLE + +//#define ONE_TABLE +#define FOUR_TABLES + +//#define ONE_LR_TABLE +#define FOUR_LR_TABLES + +//#define ONE_IM_TABLE +#define FOUR_IM_TABLES + +#if defined(UNROLL) && defined (PARTIAL_UNROLL) +#error both UNROLL and PARTIAL_UNROLL are defined +#endif + +#if defined(ONE_TABLE) && defined (FOUR_TABLES) +#error both ONE_TABLE and FOUR_TABLES are defined +#endif + +#if defined(ONE_LR_TABLE) && defined (FOUR_LR_TABLES) +#error both ONE_LR_TABLE and FOUR_LR_TABLES are defined +#endif + +#if defined(ONE_IM_TABLE) && defined (FOUR_IM_TABLES) +#error both ONE_IM_TABLE and FOUR_IM_TABLES are defined +#endif + +#if defined(AES_BLOCK_SIZE) && AES_BLOCK_SIZE != 16 && AES_BLOCK_SIZE != 24 && AES_BLOCK_SIZE != 32 +#error an illegal block size has been specified +#endif + +/** + * Rotates bytes within words by n positions, moving bytes + * to higher index positions with wrap around into low positions. + */ +#define upr(x,n) (((x) << 8 * (n)) | ((x) >> (32 - 8 * (n)))) +/** + * Moves bytes by n positions to higher index positions in + * words but without wrap around. + */ +#define ups(x,n) ((x) << 8 * (n)) + +/** + * Extracts a byte from a word. + */ +#define bval(x,n) ((unsigned char)((x) >> 8 * (n))) +#define bytes2word(b0, b1, b2, b3) \ + ((u_int32_t)(b3) << 24 | (u_int32_t)(b2) << 16 | (u_int32_t)(b1) << 8 | (b0)) + + +/* little endian processor without data alignment restrictions: AES_LE_OK */ +/* original code: i386 */ +#if defined(i386) || defined(_I386) || defined(__i386__) || defined(__i386) +#define AES_LE_OK 1 +/* added (tested): alpha --jjo */ +#elif defined(__alpha__)|| defined (__alpha) +#define AES_LE_OK 1 +/* added (tested): ia64 --jjo */ +#elif defined(__ia64__)|| defined (__ia64) +#define AES_LE_OK 1 +#endif + +#ifdef AES_LE_OK +/* little endian processor without data alignment restrictions */ +#define word_in(x) *(u_int32_t*)(x) +#define const_word_in(x) *(const u_int32_t*)(x) +#define word_out(x,v) *(u_int32_t*)(x) = (v) +#define const_word_out(x,v) *(const u_int32_t*)(x) = (v) +#else +/* slower but generic big endian or with data alignment restrictions */ +/* some additional "const" touches to stop "gcc -Wcast-qual" complains --jjo */ +#define word_in(x) ((u_int32_t)(((unsigned char *)(x))[0])|((u_int32_t)(((unsigned char *)(x))[1])<<8)|((u_int32_t)(((unsigned char *)(x))[2])<<16)|((u_int32_t)(((unsigned char *)(x))[3])<<24)) +#define const_word_in(x) ((const u_int32_t)(((const unsigned char *)(x))[0])|((const u_int32_t)(((const unsigned char *)(x))[1])<<8)|((const u_int32_t)(((const unsigned char *)(x))[2])<<16)|((const u_int32_t)(((const unsigned char *)(x))[3])<<24)) +#define word_out(x,v) ((unsigned char *)(x))[0]=(v),((unsigned char *)(x))[1]=((v)>>8),((unsigned char *)(x))[2]=((v)>>16),((unsigned char *)(x))[3]=((v)>>24) +#define const_word_out(x,v) ((const unsigned char *)(x))[0]=(v),((const unsigned char *)(x))[1]=((v)>>8),((const unsigned char *)(x))[2]=((v)>>16),((const unsigned char *)(x))[3]=((v)>>24) +#endif + +// Disable at least some poor combinations of options + +#if !defined(ONE_TABLE) && !defined(FOUR_TABLES) +#define FIXED_TABLES +#undef UNROLL +#undef ONE_LR_TABLE +#undef FOUR_LR_TABLES +#undef ONE_IM_TABLE +#undef FOUR_IM_TABLES +#elif !defined(FOUR_TABLES) +#ifdef FOUR_LR_TABLES +#undef FOUR_LR_TABLES +#define ONE_LR_TABLE +#endif +#ifdef FOUR_IM_TABLES +#undef FOUR_IM_TABLES +#define ONE_IM_TABLE +#endif +#elif !defined(AES_BLOCK_SIZE) +#if defined(UNROLL) +#define PARTIAL_UNROLL +#undef UNROLL +#endif +#endif + +// the finite field modular polynomial and elements + +#define ff_poly 0x011b +#define ff_hi 0x80 + +// multiply four bytes in GF(2^8) by 'x' {02} in parallel + +#define m1 0x80808080 +#define m2 0x7f7f7f7f +#define m3 0x0000001b +#define FFmulX(x) ((((x) & m2) << 1) ^ ((((x) & m1) >> 7) * m3)) + +// The following defines provide alternative definitions of FFmulX that might +// give improved performance if a fast 32-bit multiply is not available. Note +// that a temporary variable u needs to be defined where FFmulX is used. + +// #define FFmulX(x) (u = (x) & m1, u |= (u >> 1), ((x) & m2) << 1) ^ ((u >> 3) | (u >> 6)) +// #define m4 0x1b1b1b1b +// #define FFmulX(x) (u = (x) & m1, ((x) & m2) << 1) ^ ((u - (u >> 7)) & m4) + +// perform column mix operation on four bytes in parallel + +#define fwd_mcol(x) (f2 = FFmulX(x), f2 ^ upr(x ^ f2,3) ^ upr(x,2) ^ upr(x,1)) + +#if defined(FIXED_TABLES) + +// the S-Box table + +static const unsigned char s_box[256] = +{ + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, + 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, + 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, + 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, + 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, + 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, + 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, + 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, + 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, + 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, + 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, + 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, + 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, + 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, + 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, + 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, + 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, + 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, + 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, + 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, + 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, + 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, + 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, + 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, + 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, + 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 +}; + +// the inverse S-Box table + +static const unsigned char inv_s_box[256] = +{ + 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, + 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, + 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, + 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, + 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, + 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, + 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, + 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, + 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, + 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, + 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, + 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, + 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, + 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, + 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, + 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, + 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, + 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, + 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, + 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, + 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, + 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, + 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, + 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, + 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, + 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, + 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, + 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, + 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, + 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, + 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d +}; + +#define w0(p) 0x000000##p + +// Number of elements required in this table for different +// block and key lengths is: +// +// Nk = 4 6 8 +// ---------- +// Nb = 4 | 10 8 7 +// 6 | 19 12 11 +// 8 | 29 19 14 +// +// this table can be a table of bytes if the key schedule +// code is adjusted accordingly + +static const u_int32_t rcon_tab[29] = +{ + w0(01), w0(02), w0(04), w0(08), + w0(10), w0(20), w0(40), w0(80), + w0(1b), w0(36), w0(6c), w0(d8), + w0(ab), w0(4d), w0(9a), w0(2f), + w0(5e), w0(bc), w0(63), w0(c6), + w0(97), w0(35), w0(6a), w0(d4), + w0(b3), w0(7d), w0(fa), w0(ef), + w0(c5) +}; + +#undef w0 + +#define r0(p,q,r,s) 0x##p##q##r##s +#define r1(p,q,r,s) 0x##q##r##s##p +#define r2(p,q,r,s) 0x##r##s##p##q +#define r3(p,q,r,s) 0x##s##p##q##r +#define w0(p) 0x000000##p +#define w1(p) 0x0000##p##00 +#define w2(p) 0x00##p##0000 +#define w3(p) 0x##p##000000 + +#if defined(FIXED_TABLES) && (defined(ONE_TABLE) || defined(FOUR_TABLES)) + +// data for forward tables (other than last round) + +#define f_table \ + r(a5,63,63,c6), r(84,7c,7c,f8), r(99,77,77,ee), r(8d,7b,7b,f6),\ + r(0d,f2,f2,ff), r(bd,6b,6b,d6), r(b1,6f,6f,de), r(54,c5,c5,91),\ + r(50,30,30,60), r(03,01,01,02), r(a9,67,67,ce), r(7d,2b,2b,56),\ + r(19,fe,fe,e7), r(62,d7,d7,b5), r(e6,ab,ab,4d), r(9a,76,76,ec),\ + r(45,ca,ca,8f), r(9d,82,82,1f), r(40,c9,c9,89), r(87,7d,7d,fa),\ + r(15,fa,fa,ef), r(eb,59,59,b2), r(c9,47,47,8e), r(0b,f0,f0,fb),\ + r(ec,ad,ad,41), r(67,d4,d4,b3), r(fd,a2,a2,5f), r(ea,af,af,45),\ + r(bf,9c,9c,23), r(f7,a4,a4,53), r(96,72,72,e4), r(5b,c0,c0,9b),\ + r(c2,b7,b7,75), r(1c,fd,fd,e1), r(ae,93,93,3d), r(6a,26,26,4c),\ + r(5a,36,36,6c), r(41,3f,3f,7e), r(02,f7,f7,f5), r(4f,cc,cc,83),\ + r(5c,34,34,68), r(f4,a5,a5,51), r(34,e5,e5,d1), r(08,f1,f1,f9),\ + r(93,71,71,e2), r(73,d8,d8,ab), r(53,31,31,62), r(3f,15,15,2a),\ + r(0c,04,04,08), r(52,c7,c7,95), r(65,23,23,46), r(5e,c3,c3,9d),\ + r(28,18,18,30), r(a1,96,96,37), r(0f,05,05,0a), r(b5,9a,9a,2f),\ + r(09,07,07,0e), r(36,12,12,24), r(9b,80,80,1b), r(3d,e2,e2,df),\ + r(26,eb,eb,cd), r(69,27,27,4e), r(cd,b2,b2,7f), r(9f,75,75,ea),\ + r(1b,09,09,12), r(9e,83,83,1d), r(74,2c,2c,58), r(2e,1a,1a,34),\ + r(2d,1b,1b,36), r(b2,6e,6e,dc), r(ee,5a,5a,b4), r(fb,a0,a0,5b),\ + r(f6,52,52,a4), r(4d,3b,3b,76), r(61,d6,d6,b7), r(ce,b3,b3,7d),\ + r(7b,29,29,52), r(3e,e3,e3,dd), r(71,2f,2f,5e), r(97,84,84,13),\ + r(f5,53,53,a6), r(68,d1,d1,b9), r(00,00,00,00), r(2c,ed,ed,c1),\ + r(60,20,20,40), r(1f,fc,fc,e3), r(c8,b1,b1,79), r(ed,5b,5b,b6),\ + r(be,6a,6a,d4), r(46,cb,cb,8d), r(d9,be,be,67), r(4b,39,39,72),\ + r(de,4a,4a,94), r(d4,4c,4c,98), r(e8,58,58,b0), r(4a,cf,cf,85),\ + r(6b,d0,d0,bb), r(2a,ef,ef,c5), r(e5,aa,aa,4f), r(16,fb,fb,ed),\ + r(c5,43,43,86), r(d7,4d,4d,9a), r(55,33,33,66), r(94,85,85,11),\ + r(cf,45,45,8a), r(10,f9,f9,e9), r(06,02,02,04), r(81,7f,7f,fe),\ + r(f0,50,50,a0), r(44,3c,3c,78), r(ba,9f,9f,25), r(e3,a8,a8,4b),\ + r(f3,51,51,a2), r(fe,a3,a3,5d), r(c0,40,40,80), r(8a,8f,8f,05),\ + r(ad,92,92,3f), r(bc,9d,9d,21), r(48,38,38,70), r(04,f5,f5,f1),\ + r(df,bc,bc,63), r(c1,b6,b6,77), r(75,da,da,af), r(63,21,21,42),\ + r(30,10,10,20), r(1a,ff,ff,e5), r(0e,f3,f3,fd), r(6d,d2,d2,bf),\ + r(4c,cd,cd,81), r(14,0c,0c,18), r(35,13,13,26), r(2f,ec,ec,c3),\ + r(e1,5f,5f,be), r(a2,97,97,35), r(cc,44,44,88), r(39,17,17,2e),\ + r(57,c4,c4,93), r(f2,a7,a7,55), r(82,7e,7e,fc), r(47,3d,3d,7a),\ + r(ac,64,64,c8), r(e7,5d,5d,ba), r(2b,19,19,32), r(95,73,73,e6),\ + r(a0,60,60,c0), r(98,81,81,19), r(d1,4f,4f,9e), r(7f,dc,dc,a3),\ + r(66,22,22,44), r(7e,2a,2a,54), r(ab,90,90,3b), r(83,88,88,0b),\ + r(ca,46,46,8c), r(29,ee,ee,c7), r(d3,b8,b8,6b), r(3c,14,14,28),\ + r(79,de,de,a7), r(e2,5e,5e,bc), r(1d,0b,0b,16), r(76,db,db,ad),\ + r(3b,e0,e0,db), r(56,32,32,64), r(4e,3a,3a,74), r(1e,0a,0a,14),\ + r(db,49,49,92), r(0a,06,06,0c), r(6c,24,24,48), r(e4,5c,5c,b8),\ + r(5d,c2,c2,9f), r(6e,d3,d3,bd), r(ef,ac,ac,43), r(a6,62,62,c4),\ + r(a8,91,91,39), r(a4,95,95,31), r(37,e4,e4,d3), r(8b,79,79,f2),\ + r(32,e7,e7,d5), r(43,c8,c8,8b), r(59,37,37,6e), r(b7,6d,6d,da),\ + r(8c,8d,8d,01), r(64,d5,d5,b1), r(d2,4e,4e,9c), r(e0,a9,a9,49),\ + r(b4,6c,6c,d8), r(fa,56,56,ac), r(07,f4,f4,f3), r(25,ea,ea,cf),\ + r(af,65,65,ca), r(8e,7a,7a,f4), r(e9,ae,ae,47), r(18,08,08,10),\ + r(d5,ba,ba,6f), r(88,78,78,f0), r(6f,25,25,4a), r(72,2e,2e,5c),\ + r(24,1c,1c,38), r(f1,a6,a6,57), r(c7,b4,b4,73), r(51,c6,c6,97),\ + r(23,e8,e8,cb), r(7c,dd,dd,a1), r(9c,74,74,e8), r(21,1f,1f,3e),\ + r(dd,4b,4b,96), r(dc,bd,bd,61), r(86,8b,8b,0d), r(85,8a,8a,0f),\ + r(90,70,70,e0), r(42,3e,3e,7c), r(c4,b5,b5,71), r(aa,66,66,cc),\ + r(d8,48,48,90), r(05,03,03,06), r(01,f6,f6,f7), r(12,0e,0e,1c),\ + r(a3,61,61,c2), r(5f,35,35,6a), r(f9,57,57,ae), r(d0,b9,b9,69),\ + r(91,86,86,17), r(58,c1,c1,99), r(27,1d,1d,3a), r(b9,9e,9e,27),\ + r(38,e1,e1,d9), r(13,f8,f8,eb), r(b3,98,98,2b), r(33,11,11,22),\ + r(bb,69,69,d2), r(70,d9,d9,a9), r(89,8e,8e,07), r(a7,94,94,33),\ + r(b6,9b,9b,2d), r(22,1e,1e,3c), r(92,87,87,15), r(20,e9,e9,c9),\ + r(49,ce,ce,87), r(ff,55,55,aa), r(78,28,28,50), r(7a,df,df,a5),\ + r(8f,8c,8c,03), r(f8,a1,a1,59), r(80,89,89,09), r(17,0d,0d,1a),\ + r(da,bf,bf,65), r(31,e6,e6,d7), r(c6,42,42,84), r(b8,68,68,d0),\ + r(c3,41,41,82), r(b0,99,99,29), r(77,2d,2d,5a), r(11,0f,0f,1e),\ + r(cb,b0,b0,7b), r(fc,54,54,a8), r(d6,bb,bb,6d), r(3a,16,16,2c) + +// data for inverse tables (other than last round) + +#define i_table \ + r(50,a7,f4,51), r(53,65,41,7e), r(c3,a4,17,1a), r(96,5e,27,3a),\ + r(cb,6b,ab,3b), r(f1,45,9d,1f), r(ab,58,fa,ac), r(93,03,e3,4b),\ + r(55,fa,30,20), r(f6,6d,76,ad), r(91,76,cc,88), r(25,4c,02,f5),\ + r(fc,d7,e5,4f), r(d7,cb,2a,c5), r(80,44,35,26), r(8f,a3,62,b5),\ + r(49,5a,b1,de), r(67,1b,ba,25), r(98,0e,ea,45), r(e1,c0,fe,5d),\ + r(02,75,2f,c3), r(12,f0,4c,81), r(a3,97,46,8d), r(c6,f9,d3,6b),\ + r(e7,5f,8f,03), r(95,9c,92,15), r(eb,7a,6d,bf), r(da,59,52,95),\ + r(2d,83,be,d4), r(d3,21,74,58), r(29,69,e0,49), r(44,c8,c9,8e),\ + r(6a,89,c2,75), r(78,79,8e,f4), r(6b,3e,58,99), r(dd,71,b9,27),\ + r(b6,4f,e1,be), r(17,ad,88,f0), r(66,ac,20,c9), r(b4,3a,ce,7d),\ + r(18,4a,df,63), r(82,31,1a,e5), r(60,33,51,97), r(45,7f,53,62),\ + r(e0,77,64,b1), r(84,ae,6b,bb), r(1c,a0,81,fe), r(94,2b,08,f9),\ + r(58,68,48,70), r(19,fd,45,8f), r(87,6c,de,94), r(b7,f8,7b,52),\ + r(23,d3,73,ab), r(e2,02,4b,72), r(57,8f,1f,e3), r(2a,ab,55,66),\ + r(07,28,eb,b2), r(03,c2,b5,2f), r(9a,7b,c5,86), r(a5,08,37,d3),\ + r(f2,87,28,30), r(b2,a5,bf,23), r(ba,6a,03,02), r(5c,82,16,ed),\ + r(2b,1c,cf,8a), r(92,b4,79,a7), r(f0,f2,07,f3), r(a1,e2,69,4e),\ + r(cd,f4,da,65), r(d5,be,05,06), r(1f,62,34,d1), r(8a,fe,a6,c4),\ + r(9d,53,2e,34), r(a0,55,f3,a2), r(32,e1,8a,05), r(75,eb,f6,a4),\ + r(39,ec,83,0b), r(aa,ef,60,40), r(06,9f,71,5e), r(51,10,6e,bd),\ + r(f9,8a,21,3e), r(3d,06,dd,96), r(ae,05,3e,dd), r(46,bd,e6,4d),\ + r(b5,8d,54,91), r(05,5d,c4,71), r(6f,d4,06,04), r(ff,15,50,60),\ + r(24,fb,98,19), r(97,e9,bd,d6), r(cc,43,40,89), r(77,9e,d9,67),\ + r(bd,42,e8,b0), r(88,8b,89,07), r(38,5b,19,e7), r(db,ee,c8,79),\ + r(47,0a,7c,a1), r(e9,0f,42,7c), r(c9,1e,84,f8), r(00,00,00,00),\ + r(83,86,80,09), r(48,ed,2b,32), r(ac,70,11,1e), r(4e,72,5a,6c),\ + r(fb,ff,0e,fd), r(56,38,85,0f), r(1e,d5,ae,3d), r(27,39,2d,36),\ + r(64,d9,0f,0a), r(21,a6,5c,68), r(d1,54,5b,9b), r(3a,2e,36,24),\ + r(b1,67,0a,0c), r(0f,e7,57,93), r(d2,96,ee,b4), r(9e,91,9b,1b),\ + r(4f,c5,c0,80), r(a2,20,dc,61), r(69,4b,77,5a), r(16,1a,12,1c),\ + r(0a,ba,93,e2), r(e5,2a,a0,c0), r(43,e0,22,3c), r(1d,17,1b,12),\ + r(0b,0d,09,0e), r(ad,c7,8b,f2), r(b9,a8,b6,2d), r(c8,a9,1e,14),\ + r(85,19,f1,57), r(4c,07,75,af), r(bb,dd,99,ee), r(fd,60,7f,a3),\ + r(9f,26,01,f7), r(bc,f5,72,5c), r(c5,3b,66,44), r(34,7e,fb,5b),\ + r(76,29,43,8b), r(dc,c6,23,cb), r(68,fc,ed,b6), r(63,f1,e4,b8),\ + r(ca,dc,31,d7), r(10,85,63,42), r(40,22,97,13), r(20,11,c6,84),\ + r(7d,24,4a,85), r(f8,3d,bb,d2), r(11,32,f9,ae), r(6d,a1,29,c7),\ + r(4b,2f,9e,1d), r(f3,30,b2,dc), r(ec,52,86,0d), r(d0,e3,c1,77),\ + r(6c,16,b3,2b), r(99,b9,70,a9), r(fa,48,94,11), r(22,64,e9,47),\ + r(c4,8c,fc,a8), r(1a,3f,f0,a0), r(d8,2c,7d,56), r(ef,90,33,22),\ + r(c7,4e,49,87), r(c1,d1,38,d9), r(fe,a2,ca,8c), r(36,0b,d4,98),\ + r(cf,81,f5,a6), r(28,de,7a,a5), r(26,8e,b7,da), r(a4,bf,ad,3f),\ + r(e4,9d,3a,2c), r(0d,92,78,50), r(9b,cc,5f,6a), r(62,46,7e,54),\ + r(c2,13,8d,f6), r(e8,b8,d8,90), r(5e,f7,39,2e), r(f5,af,c3,82),\ + r(be,80,5d,9f), r(7c,93,d0,69), r(a9,2d,d5,6f), r(b3,12,25,cf),\ + r(3b,99,ac,c8), r(a7,7d,18,10), r(6e,63,9c,e8), r(7b,bb,3b,db),\ + r(09,78,26,cd), r(f4,18,59,6e), r(01,b7,9a,ec), r(a8,9a,4f,83),\ + r(65,6e,95,e6), r(7e,e6,ff,aa), r(08,cf,bc,21), r(e6,e8,15,ef),\ + r(d9,9b,e7,ba), r(ce,36,6f,4a), r(d4,09,9f,ea), r(d6,7c,b0,29),\ + r(af,b2,a4,31), r(31,23,3f,2a), r(30,94,a5,c6), r(c0,66,a2,35),\ + r(37,bc,4e,74), r(a6,ca,82,fc), r(b0,d0,90,e0), r(15,d8,a7,33),\ + r(4a,98,04,f1), r(f7,da,ec,41), r(0e,50,cd,7f), r(2f,f6,91,17),\ + r(8d,d6,4d,76), r(4d,b0,ef,43), r(54,4d,aa,cc), r(df,04,96,e4),\ + r(e3,b5,d1,9e), r(1b,88,6a,4c), r(b8,1f,2c,c1), r(7f,51,65,46),\ + r(04,ea,5e,9d), r(5d,35,8c,01), r(73,74,87,fa), r(2e,41,0b,fb),\ + r(5a,1d,67,b3), r(52,d2,db,92), r(33,56,10,e9), r(13,47,d6,6d),\ + r(8c,61,d7,9a), r(7a,0c,a1,37), r(8e,14,f8,59), r(89,3c,13,eb),\ + r(ee,27,a9,ce), r(35,c9,61,b7), r(ed,e5,1c,e1), r(3c,b1,47,7a),\ + r(59,df,d2,9c), r(3f,73,f2,55), r(79,ce,14,18), r(bf,37,c7,73),\ + r(ea,cd,f7,53), r(5b,aa,fd,5f), r(14,6f,3d,df), r(86,db,44,78),\ + r(81,f3,af,ca), r(3e,c4,68,b9), r(2c,34,24,38), r(5f,40,a3,c2),\ + r(72,c3,1d,16), r(0c,25,e2,bc), r(8b,49,3c,28), r(41,95,0d,ff),\ + r(71,01,a8,39), r(de,b3,0c,08), r(9c,e4,b4,d8), r(90,c1,56,64),\ + r(61,84,cb,7b), r(70,b6,32,d5), r(74,5c,6c,48), r(42,57,b8,d0) + +// generate the required tables in the desired endian format + +#undef r +#define r r0 + +#if defined(ONE_TABLE) +static const u_int32_t ft_tab[256] = + { f_table }; +#elif defined(FOUR_TABLES) +static const u_int32_t ft_tab[4][256] = +{ { f_table }, +#undef r +#define r r1 + { f_table }, +#undef r +#define r r2 + { f_table }, +#undef r +#define r r3 + { f_table } +}; +#endif + +#undef r +#define r r0 +#if defined(ONE_TABLE) +static const u_int32_t it_tab[256] = + { i_table }; +#elif defined(FOUR_TABLES) +static const u_int32_t it_tab[4][256] = +{ { i_table }, +#undef r +#define r r1 + { i_table }, +#undef r +#define r r2 + { i_table }, +#undef r +#define r r3 + { i_table } +}; +#endif + +#endif + +#if defined(FIXED_TABLES) && (defined(ONE_LR_TABLE) || defined(FOUR_LR_TABLES)) + +// data for inverse tables (last round) + +#define li_table \ + w(52), w(09), w(6a), w(d5), w(30), w(36), w(a5), w(38),\ + w(bf), w(40), w(a3), w(9e), w(81), w(f3), w(d7), w(fb),\ + w(7c), w(e3), w(39), w(82), w(9b), w(2f), w(ff), w(87),\ + w(34), w(8e), w(43), w(44), w(c4), w(de), w(e9), w(cb),\ + w(54), w(7b), w(94), w(32), w(a6), w(c2), w(23), w(3d),\ + w(ee), w(4c), w(95), w(0b), w(42), w(fa), w(c3), w(4e),\ + w(08), w(2e), w(a1), w(66), w(28), w(d9), w(24), w(b2),\ + w(76), w(5b), w(a2), w(49), w(6d), w(8b), w(d1), w(25),\ + w(72), w(f8), w(f6), w(64), w(86), w(68), w(98), w(16),\ + w(d4), w(a4), w(5c), w(cc), w(5d), w(65), w(b6), w(92),\ + w(6c), w(70), w(48), w(50), w(fd), w(ed), w(b9), w(da),\ + w(5e), w(15), w(46), w(57), w(a7), w(8d), w(9d), w(84),\ + w(90), w(d8), w(ab), w(00), w(8c), w(bc), w(d3), w(0a),\ + w(f7), w(e4), w(58), w(05), w(b8), w(b3), w(45), w(06),\ + w(d0), w(2c), w(1e), w(8f), w(ca), w(3f), w(0f), w(02),\ + w(c1), w(af), w(bd), w(03), w(01), w(13), w(8a), w(6b),\ + w(3a), w(91), w(11), w(41), w(4f), w(67), w(dc), w(ea),\ + w(97), w(f2), w(cf), w(ce), w(f0), w(b4), w(e6), w(73),\ + w(96), w(ac), w(74), w(22), w(e7), w(ad), w(35), w(85),\ + w(e2), w(f9), w(37), w(e8), w(1c), w(75), w(df), w(6e),\ + w(47), w(f1), w(1a), w(71), w(1d), w(29), w(c5), w(89),\ + w(6f), w(b7), w(62), w(0e), w(aa), w(18), w(be), w(1b),\ + w(fc), w(56), w(3e), w(4b), w(c6), w(d2), w(79), w(20),\ + w(9a), w(db), w(c0), w(fe), w(78), w(cd), w(5a), w(f4),\ + w(1f), w(dd), w(a8), w(33), w(88), w(07), w(c7), w(31),\ + w(b1), w(12), w(10), w(59), w(27), w(80), w(ec), w(5f),\ + w(60), w(51), w(7f), w(a9), w(19), w(b5), w(4a), w(0d),\ + w(2d), w(e5), w(7a), w(9f), w(93), w(c9), w(9c), w(ef),\ + w(a0), w(e0), w(3b), w(4d), w(ae), w(2a), w(f5), w(b0),\ + w(c8), w(eb), w(bb), w(3c), w(83), w(53), w(99), w(61),\ + w(17), w(2b), w(04), w(7e), w(ba), w(77), w(d6), w(26),\ + w(e1), w(69), w(14), w(63), w(55), w(21), w(0c), w(7d), + +// generate the required tables in the desired endian format + +#undef r +#define r(p,q,r,s) w0(q) +#if defined(ONE_LR_TABLE) +static const u_int32_t fl_tab[256] = + { f_table }; +#elif defined(FOUR_LR_TABLES) +static const u_int32_t fl_tab[4][256] = +{ { f_table }, +#undef r +#define r(p,q,r,s) w1(q) + { f_table }, +#undef r +#define r(p,q,r,s) w2(q) + { f_table }, +#undef r +#define r(p,q,r,s) w3(q) + { f_table } +}; +#endif + +#undef w +#define w w0 +#if defined(ONE_LR_TABLE) +static const u_int32_t il_tab[256] = + { li_table }; +#elif defined(FOUR_LR_TABLES) +static const u_int32_t il_tab[4][256] = +{ { li_table }, +#undef w +#define w w1 + { li_table }, +#undef w +#define w w2 + { li_table }, +#undef w +#define w w3 + { li_table } +}; +#endif + +#endif + +#if defined(FIXED_TABLES) && (defined(ONE_IM_TABLE) || defined(FOUR_IM_TABLES)) + +#define m_table \ + r(00,00,00,00), r(0b,0d,09,0e), r(16,1a,12,1c), r(1d,17,1b,12),\ + r(2c,34,24,38), r(27,39,2d,36), r(3a,2e,36,24), r(31,23,3f,2a),\ + r(58,68,48,70), r(53,65,41,7e), r(4e,72,5a,6c), r(45,7f,53,62),\ + r(74,5c,6c,48), r(7f,51,65,46), r(62,46,7e,54), r(69,4b,77,5a),\ + r(b0,d0,90,e0), r(bb,dd,99,ee), r(a6,ca,82,fc), r(ad,c7,8b,f2),\ + r(9c,e4,b4,d8), r(97,e9,bd,d6), r(8a,fe,a6,c4), r(81,f3,af,ca),\ + r(e8,b8,d8,90), r(e3,b5,d1,9e), r(fe,a2,ca,8c), r(f5,af,c3,82),\ + r(c4,8c,fc,a8), r(cf,81,f5,a6), r(d2,96,ee,b4), r(d9,9b,e7,ba),\ + r(7b,bb,3b,db), r(70,b6,32,d5), r(6d,a1,29,c7), r(66,ac,20,c9),\ + r(57,8f,1f,e3), r(5c,82,16,ed), r(41,95,0d,ff), r(4a,98,04,f1),\ + r(23,d3,73,ab), r(28,de,7a,a5), r(35,c9,61,b7), r(3e,c4,68,b9),\ + r(0f,e7,57,93), r(04,ea,5e,9d), r(19,fd,45,8f), r(12,f0,4c,81),\ + r(cb,6b,ab,3b), r(c0,66,a2,35), r(dd,71,b9,27), r(d6,7c,b0,29),\ + r(e7,5f,8f,03), r(ec,52,86,0d), r(f1,45,9d,1f), r(fa,48,94,11),\ + r(93,03,e3,4b), r(98,0e,ea,45), r(85,19,f1,57), r(8e,14,f8,59),\ + r(bf,37,c7,73), r(b4,3a,ce,7d), r(a9,2d,d5,6f), r(a2,20,dc,61),\ + r(f6,6d,76,ad), r(fd,60,7f,a3), r(e0,77,64,b1), r(eb,7a,6d,bf),\ + r(da,59,52,95), r(d1,54,5b,9b), r(cc,43,40,89), r(c7,4e,49,87),\ + r(ae,05,3e,dd), r(a5,08,37,d3), r(b8,1f,2c,c1), r(b3,12,25,cf),\ + r(82,31,1a,e5), r(89,3c,13,eb), r(94,2b,08,f9), r(9f,26,01,f7),\ + r(46,bd,e6,4d), r(4d,b0,ef,43), r(50,a7,f4,51), r(5b,aa,fd,5f),\ + r(6a,89,c2,75), r(61,84,cb,7b), r(7c,93,d0,69), r(77,9e,d9,67),\ + r(1e,d5,ae,3d), r(15,d8,a7,33), r(08,cf,bc,21), r(03,c2,b5,2f),\ + r(32,e1,8a,05), r(39,ec,83,0b), r(24,fb,98,19), r(2f,f6,91,17),\ + r(8d,d6,4d,76), r(86,db,44,78), r(9b,cc,5f,6a), r(90,c1,56,64),\ + r(a1,e2,69,4e), r(aa,ef,60,40), r(b7,f8,7b,52), r(bc,f5,72,5c),\ + r(d5,be,05,06), r(de,b3,0c,08), r(c3,a4,17,1a), r(c8,a9,1e,14),\ + r(f9,8a,21,3e), r(f2,87,28,30), r(ef,90,33,22), r(e4,9d,3a,2c),\ + r(3d,06,dd,96), r(36,0b,d4,98), r(2b,1c,cf,8a), r(20,11,c6,84),\ + r(11,32,f9,ae), r(1a,3f,f0,a0), r(07,28,eb,b2), r(0c,25,e2,bc),\ + r(65,6e,95,e6), r(6e,63,9c,e8), r(73,74,87,fa), r(78,79,8e,f4),\ + r(49,5a,b1,de), r(42,57,b8,d0), r(5f,40,a3,c2), r(54,4d,aa,cc),\ + r(f7,da,ec,41), r(fc,d7,e5,4f), r(e1,c0,fe,5d), r(ea,cd,f7,53),\ + r(db,ee,c8,79), r(d0,e3,c1,77), r(cd,f4,da,65), r(c6,f9,d3,6b),\ + r(af,b2,a4,31), r(a4,bf,ad,3f), r(b9,a8,b6,2d), r(b2,a5,bf,23),\ + r(83,86,80,09), r(88,8b,89,07), r(95,9c,92,15), r(9e,91,9b,1b),\ + r(47,0a,7c,a1), r(4c,07,75,af), r(51,10,6e,bd), r(5a,1d,67,b3),\ + r(6b,3e,58,99), r(60,33,51,97), r(7d,24,4a,85), r(76,29,43,8b),\ + r(1f,62,34,d1), r(14,6f,3d,df), r(09,78,26,cd), r(02,75,2f,c3),\ + r(33,56,10,e9), r(38,5b,19,e7), r(25,4c,02,f5), r(2e,41,0b,fb),\ + r(8c,61,d7,9a), r(87,6c,de,94), r(9a,7b,c5,86), r(91,76,cc,88),\ + r(a0,55,f3,a2), r(ab,58,fa,ac), r(b6,4f,e1,be), r(bd,42,e8,b0),\ + r(d4,09,9f,ea), r(df,04,96,e4), r(c2,13,8d,f6), r(c9,1e,84,f8),\ + r(f8,3d,bb,d2), r(f3,30,b2,dc), r(ee,27,a9,ce), r(e5,2a,a0,c0),\ + r(3c,b1,47,7a), r(37,bc,4e,74), r(2a,ab,55,66), r(21,a6,5c,68),\ + r(10,85,63,42), r(1b,88,6a,4c), r(06,9f,71,5e), r(0d,92,78,50),\ + r(64,d9,0f,0a), r(6f,d4,06,04), r(72,c3,1d,16), r(79,ce,14,18),\ + r(48,ed,2b,32), r(43,e0,22,3c), r(5e,f7,39,2e), r(55,fa,30,20),\ + r(01,b7,9a,ec), r(0a,ba,93,e2), r(17,ad,88,f0), r(1c,a0,81,fe),\ + r(2d,83,be,d4), r(26,8e,b7,da), r(3b,99,ac,c8), r(30,94,a5,c6),\ + r(59,df,d2,9c), r(52,d2,db,92), r(4f,c5,c0,80), r(44,c8,c9,8e),\ + r(75,eb,f6,a4), r(7e,e6,ff,aa), r(63,f1,e4,b8), r(68,fc,ed,b6),\ + r(b1,67,0a,0c), r(ba,6a,03,02), r(a7,7d,18,10), r(ac,70,11,1e),\ + r(9d,53,2e,34), r(96,5e,27,3a), r(8b,49,3c,28), r(80,44,35,26),\ + r(e9,0f,42,7c), r(e2,02,4b,72), r(ff,15,50,60), r(f4,18,59,6e),\ + r(c5,3b,66,44), r(ce,36,6f,4a), r(d3,21,74,58), r(d8,2c,7d,56),\ + r(7a,0c,a1,37), r(71,01,a8,39), r(6c,16,b3,2b), r(67,1b,ba,25),\ + r(56,38,85,0f), r(5d,35,8c,01), r(40,22,97,13), r(4b,2f,9e,1d),\ + r(22,64,e9,47), r(29,69,e0,49), r(34,7e,fb,5b), r(3f,73,f2,55),\ + r(0e,50,cd,7f), r(05,5d,c4,71), r(18,4a,df,63), r(13,47,d6,6d),\ + r(ca,dc,31,d7), r(c1,d1,38,d9), r(dc,c6,23,cb), r(d7,cb,2a,c5),\ + r(e6,e8,15,ef), r(ed,e5,1c,e1), r(f0,f2,07,f3), r(fb,ff,0e,fd),\ + r(92,b4,79,a7), r(99,b9,70,a9), r(84,ae,6b,bb), r(8f,a3,62,b5),\ + r(be,80,5d,9f), r(b5,8d,54,91), r(a8,9a,4f,83), r(a3,97,46,8d) + +#undef r +#define r r0 + +#if defined(ONE_IM_TABLE) +static const u_int32_t im_tab[256] = + { m_table }; +#elif defined(FOUR_IM_TABLES) +static const u_int32_t im_tab[4][256] = +{ { m_table }, +#undef r +#define r r1 + { m_table }, +#undef r +#define r r2 + { m_table }, +#undef r +#define r r3 + { m_table } +}; +#endif + +#endif + +#else + +static int tab_gen = 0; + +static unsigned char s_box[256]; // the S box +static unsigned char inv_s_box[256]; // the inverse S box +static u_int32_t rcon_tab[AES_RC_LENGTH]; // table of round constants + +#if defined(ONE_TABLE) +static u_int32_t ft_tab[256]; +static u_int32_t it_tab[256]; +#elif defined(FOUR_TABLES) +static u_int32_t ft_tab[4][256]; +static u_int32_t it_tab[4][256]; +#endif + +#if defined(ONE_LR_TABLE) +static u_int32_t fl_tab[256]; +static u_int32_t il_tab[256]; +#elif defined(FOUR_LR_TABLES) +static u_int32_t fl_tab[4][256]; +static u_int32_t il_tab[4][256]; +#endif + +#if defined(ONE_IM_TABLE) +static u_int32_t im_tab[256]; +#elif defined(FOUR_IM_TABLES) +static u_int32_t im_tab[4][256]; +#endif + +// Generate the tables for the dynamic table option + +#if !defined(FF_TABLES) + +// It will generally be sensible to use tables to compute finite +// field multiplies and inverses but where memory is scarse this +// code might sometimes be better. + +// return 2 ^ (n - 1) where n is the bit number of the highest bit +// set in x with x in the range 1 < x < 0x00000200. This form is +// used so that locals within FFinv can be bytes rather than words + +static unsigned char hibit(const u_int32_t x) +{ unsigned char r = (unsigned char)((x >> 1) | (x >> 2)); + + r |= (r >> 2); + r |= (r >> 4); + return (r + 1) >> 1; +} + +// return the inverse of the finite field element x + +static unsigned char FFinv(const unsigned char x) +{ unsigned char p1 = x, p2 = 0x1b, n1 = hibit(x), n2 = 0x80, v1 = 1, v2 = 0; + + if(x < 2) return x; + + for(;;) + { + if(!n1) return v1; + + while(n2 >= n1) + { + n2 /= n1; p2 ^= p1 * n2; v2 ^= v1 * n2; n2 = hibit(p2); + } + + if(!n2) return v2; + + while(n1 >= n2) + { + n1 /= n2; p1 ^= p2 * n1; v1 ^= v2 * n1; n1 = hibit(p1); + } + } +} + +// define the finite field multiplies required for Rijndael + +#define FFmul02(x) ((((x) & 0x7f) << 1) ^ ((x) & 0x80 ? 0x1b : 0)) +#define FFmul03(x) ((x) ^ FFmul02(x)) +#define FFmul09(x) ((x) ^ FFmul02(FFmul02(FFmul02(x)))) +#define FFmul0b(x) ((x) ^ FFmul02((x) ^ FFmul02(FFmul02(x)))) +#define FFmul0d(x) ((x) ^ FFmul02(FFmul02((x) ^ FFmul02(x)))) +#define FFmul0e(x) FFmul02((x) ^ FFmul02((x) ^ FFmul02(x))) + +#else + +#define FFinv(x) ((x) ? pow[255 - log[x]]: 0) + +#define FFmul02(x) (x ? pow[log[x] + 0x19] : 0) +#define FFmul03(x) (x ? pow[log[x] + 0x01] : 0) +#define FFmul09(x) (x ? pow[log[x] + 0xc7] : 0) +#define FFmul0b(x) (x ? pow[log[x] + 0x68] : 0) +#define FFmul0d(x) (x ? pow[log[x] + 0xee] : 0) +#define FFmul0e(x) (x ? pow[log[x] + 0xdf] : 0) + +#endif + +// The forward and inverse affine transformations used in the S-box + +#define fwd_affine(x) \ + (w = (u_int32_t)x, w ^= (w<<1)^(w<<2)^(w<<3)^(w<<4), 0x63^(unsigned char)(w^(w>>8))) + +#define inv_affine(x) \ + (w = (u_int32_t)x, w = (w<<1)^(w<<3)^(w<<6), 0x05^(unsigned char)(w^(w>>8))) + +static void gen_tabs(void) +{ u_int32_t i, w; + +#if defined(FF_TABLES) + + unsigned char pow[512], log[256]; + + // log and power tables for GF(2^8) finite field with + // 0x011b as modular polynomial - the simplest primitive + // root is 0x03, used here to generate the tables + + i = 0; w = 1; + do + { + pow[i] = (unsigned char)w; + pow[i + 255] = (unsigned char)w; + log[w] = (unsigned char)i++; + w ^= (w << 1) ^ (w & ff_hi ? ff_poly : 0); + } + while (w != 1); + +#endif + + for(i = 0, w = 1; i < AES_RC_LENGTH; ++i) + { + rcon_tab[i] = bytes2word(w, 0, 0, 0); + w = (w << 1) ^ (w & ff_hi ? ff_poly : 0); + } + + for(i = 0; i < 256; ++i) + { unsigned char b; + + s_box[i] = b = fwd_affine(FFinv((unsigned char)i)); + + w = bytes2word(b, 0, 0, 0); +#if defined(ONE_LR_TABLE) + fl_tab[i] = w; +#elif defined(FOUR_LR_TABLES) + fl_tab[0][i] = w; + fl_tab[1][i] = upr(w,1); + fl_tab[2][i] = upr(w,2); + fl_tab[3][i] = upr(w,3); +#endif + w = bytes2word(FFmul02(b), b, b, FFmul03(b)); +#if defined(ONE_TABLE) + ft_tab[i] = w; +#elif defined(FOUR_TABLES) + ft_tab[0][i] = w; + ft_tab[1][i] = upr(w,1); + ft_tab[2][i] = upr(w,2); + ft_tab[3][i] = upr(w,3); +#endif + inv_s_box[i] = b = FFinv(inv_affine((unsigned char)i)); + + w = bytes2word(b, 0, 0, 0); +#if defined(ONE_LR_TABLE) + il_tab[i] = w; +#elif defined(FOUR_LR_TABLES) + il_tab[0][i] = w; + il_tab[1][i] = upr(w,1); + il_tab[2][i] = upr(w,2); + il_tab[3][i] = upr(w,3); +#endif + w = bytes2word(FFmul0e(b), FFmul09(b), FFmul0d(b), FFmul0b(b)); +#if defined(ONE_TABLE) + it_tab[i] = w; +#elif defined(FOUR_TABLES) + it_tab[0][i] = w; + it_tab[1][i] = upr(w,1); + it_tab[2][i] = upr(w,2); + it_tab[3][i] = upr(w,3); +#endif +#if defined(ONE_IM_TABLE) + im_tab[b] = w; +#elif defined(FOUR_IM_TABLES) + im_tab[0][b] = w; + im_tab[1][b] = upr(w,1); + im_tab[2][b] = upr(w,2); + im_tab[3][b] = upr(w,3); +#endif + + } +} + +#endif + +#define no_table(x,box,vf,rf,c) bytes2word( \ + box[bval(vf(x,0,c),rf(0,c))], \ + box[bval(vf(x,1,c),rf(1,c))], \ + box[bval(vf(x,2,c),rf(2,c))], \ + box[bval(vf(x,3,c),rf(3,c))]) + +#define one_table(x,op,tab,vf,rf,c) \ + ( tab[bval(vf(x,0,c),rf(0,c))] \ + ^ op(tab[bval(vf(x,1,c),rf(1,c))],1) \ + ^ op(tab[bval(vf(x,2,c),rf(2,c))],2) \ + ^ op(tab[bval(vf(x,3,c),rf(3,c))],3)) + +#define four_tables(x,tab,vf,rf,c) \ + ( tab[0][bval(vf(x,0,c),rf(0,c))] \ + ^ tab[1][bval(vf(x,1,c),rf(1,c))] \ + ^ tab[2][bval(vf(x,2,c),rf(2,c))] \ + ^ tab[3][bval(vf(x,3,c),rf(3,c))]) + +#define vf1(x,r,c) (x) +#define rf1(r,c) (r) +#define rf2(r,c) ((r-c)&3) + +#if defined(FOUR_LR_TABLES) +#define ls_box(x,c) four_tables(x,fl_tab,vf1,rf2,c) +#elif defined(ONE_LR_TABLE) +#define ls_box(x,c) one_table(x,upr,fl_tab,vf1,rf2,c) +#else +#define ls_box(x,c) no_table(x,s_box,vf1,rf2,c) +#endif + +#if defined(FOUR_IM_TABLES) +#define inv_mcol(x) four_tables(x,im_tab,vf1,rf1,0) +#elif defined(ONE_IM_TABLE) +#define inv_mcol(x) one_table(x,upr,im_tab,vf1,rf1,0) +#else +#define inv_mcol(x) \ + (f9 = (x),f2 = FFmulX(f9), f4 = FFmulX(f2), f8 = FFmulX(f4), f9 ^= f8, \ + f2 ^= f4 ^ f8 ^ upr(f2 ^ f9,3) ^ upr(f4 ^ f9,2) ^ upr(f9,1)) +#endif + +#define nc (AES_BLOCK_SIZE/4) + +// Initialise the key schedule from the user supplied key. The key +// length is now specified in bytes - 16, 24 or 32 as appropriate. +// This corresponds to bit lengths of 128, 192 and 256 bits, and +// to Nk values of 4, 6 and 8 respectively. + +#define mx(t,f) (*t++ = inv_mcol(*f),f++) +#define cp(t,f) *t++ = *f++ + +#if AES_BLOCK_SIZE == 16 +#define cpy(d,s) cp(d,s); cp(d,s); cp(d,s); cp(d,s) +#define mix(d,s) mx(d,s); mx(d,s); mx(d,s); mx(d,s) +#elif AES_BLOCK_SIZE == 24 +#define cpy(d,s) cp(d,s); cp(d,s); cp(d,s); cp(d,s); \ + cp(d,s); cp(d,s) +#define mix(d,s) mx(d,s); mx(d,s); mx(d,s); mx(d,s); \ + mx(d,s); mx(d,s) +#elif AES_BLOCK_SIZE == 32 +#define cpy(d,s) cp(d,s); cp(d,s); cp(d,s); cp(d,s); \ + cp(d,s); cp(d,s); cp(d,s); cp(d,s) +#define mix(d,s) mx(d,s); mx(d,s); mx(d,s); mx(d,s); \ + mx(d,s); mx(d,s); mx(d,s); mx(d,s) +#else + +#define cpy(d,s) \ +switch(nc) \ +{ case 8: cp(d,s); cp(d,s); \ + case 6: cp(d,s); cp(d,s); \ + case 4: cp(d,s); cp(d,s); \ + cp(d,s); cp(d,s); \ +} + +#define mix(d,s) \ +switch(nc) \ +{ case 8: mx(d,s); mx(d,s); \ + case 6: mx(d,s); mx(d,s); \ + case 4: mx(d,s); mx(d,s); \ + mx(d,s); mx(d,s); \ +} + +#endif + +// y = output word, x = input word, r = row, c = column +// for r = 0, 1, 2 and 3 = column accessed for row r + +#if defined(ARRAYS) +#define s(x,c) x[c] +#else +#define s(x,c) x##c +#endif + +// I am grateful to Frank Yellin for the following constructions +// which, given the column (c) of the output state variable that +// is being computed, return the input state variables which are +// needed for each row (r) of the state + +// For the fixed block size options, compilers reduce these two +// expressions to fixed variable references. For variable block +// size code conditional clauses will sometimes be returned + +#define unused 77 // Sunset Strip + +#define fwd_var(x,r,c) \ + ( r==0 ? \ + ( c==0 ? s(x,0) \ + : c==1 ? s(x,1) \ + : c==2 ? s(x,2) \ + : c==3 ? s(x,3) \ + : c==4 ? s(x,4) \ + : c==5 ? s(x,5) \ + : c==6 ? s(x,6) \ + : s(x,7)) \ + : r==1 ? \ + ( c==0 ? s(x,1) \ + : c==1 ? s(x,2) \ + : c==2 ? s(x,3) \ + : c==3 ? nc==4 ? s(x,0) : s(x,4) \ + : c==4 ? s(x,5) \ + : c==5 ? nc==8 ? s(x,6) : s(x,0) \ + : c==6 ? s(x,7) \ + : s(x,0)) \ + : r==2 ? \ + ( c==0 ? nc==8 ? s(x,3) : s(x,2) \ + : c==1 ? nc==8 ? s(x,4) : s(x,3) \ + : c==2 ? nc==4 ? s(x,0) : nc==8 ? s(x,5) : s(x,4) \ + : c==3 ? nc==4 ? s(x,1) : nc==8 ? s(x,6) : s(x,5) \ + : c==4 ? nc==8 ? s(x,7) : s(x,0) \ + : c==5 ? nc==8 ? s(x,0) : s(x,1) \ + : c==6 ? s(x,1) \ + : s(x,2)) \ + : \ + ( c==0 ? nc==8 ? s(x,4) : s(x,3) \ + : c==1 ? nc==4 ? s(x,0) : nc==8 ? s(x,5) : s(x,4) \ + : c==2 ? nc==4 ? s(x,1) : nc==8 ? s(x,6) : s(x,5) \ + : c==3 ? nc==4 ? s(x,2) : nc==8 ? s(x,7) : s(x,0) \ + : c==4 ? nc==8 ? s(x,0) : s(x,1) \ + : c==5 ? nc==8 ? s(x,1) : s(x,2) \ + : c==6 ? s(x,2) \ + : s(x,3))) + +#define inv_var(x,r,c) \ + ( r==0 ? \ + ( c==0 ? s(x,0) \ + : c==1 ? s(x,1) \ + : c==2 ? s(x,2) \ + : c==3 ? s(x,3) \ + : c==4 ? s(x,4) \ + : c==5 ? s(x,5) \ + : c==6 ? s(x,6) \ + : s(x,7)) \ + : r==1 ? \ + ( c==0 ? nc==4 ? s(x,3) : nc==8 ? s(x,7) : s(x,5) \ + : c==1 ? s(x,0) \ + : c==2 ? s(x,1) \ + : c==3 ? s(x,2) \ + : c==4 ? s(x,3) \ + : c==5 ? s(x,4) \ + : c==6 ? s(x,5) \ + : s(x,6)) \ + : r==2 ? \ + ( c==0 ? nc==4 ? s(x,2) : nc==8 ? s(x,5) : s(x,4) \ + : c==1 ? nc==4 ? s(x,3) : nc==8 ? s(x,6) : s(x,5) \ + : c==2 ? nc==8 ? s(x,7) : s(x,0) \ + : c==3 ? nc==8 ? s(x,0) : s(x,1) \ + : c==4 ? nc==8 ? s(x,1) : s(x,2) \ + : c==5 ? nc==8 ? s(x,2) : s(x,3) \ + : c==6 ? s(x,3) \ + : s(x,4)) \ + : \ + ( c==0 ? nc==4 ? s(x,1) : nc==8 ? s(x,4) : s(x,3) \ + : c==1 ? nc==4 ? s(x,2) : nc==8 ? s(x,5) : s(x,4) \ + : c==2 ? nc==4 ? s(x,3) : nc==8 ? s(x,6) : s(x,5) \ + : c==3 ? nc==8 ? s(x,7) : s(x,0) \ + : c==4 ? nc==8 ? s(x,0) : s(x,1) \ + : c==5 ? nc==8 ? s(x,1) : s(x,2) \ + : c==6 ? s(x,2) \ + : s(x,3))) + +#define si(y,x,k,c) s(y,c) = const_word_in(x + 4 * c) ^ k[c] +#define so(y,x,c) word_out(y + 4 * c, s(x,c)) + +#if defined(FOUR_TABLES) +#define fwd_rnd(y,x,k,c) s(y,c)= (k)[c] ^ four_tables(x,ft_tab,fwd_var,rf1,c) +#define inv_rnd(y,x,k,c) s(y,c)= (k)[c] ^ four_tables(x,it_tab,inv_var,rf1,c) +#elif defined(ONE_TABLE) +#define fwd_rnd(y,x,k,c) s(y,c)= (k)[c] ^ one_table(x,upr,ft_tab,fwd_var,rf1,c) +#define inv_rnd(y,x,k,c) s(y,c)= (k)[c] ^ one_table(x,upr,it_tab,inv_var,rf1,c) +#else +#define fwd_rnd(y,x,k,c) s(y,c) = fwd_mcol(no_table(x,s_box,fwd_var,rf1,c)) ^ (k)[c] +#define inv_rnd(y,x,k,c) s(y,c) = inv_mcol(no_table(x,inv_s_box,inv_var,rf1,c) ^ (k)[c]) +#endif + +#if defined(FOUR_LR_TABLES) +#define fwd_lrnd(y,x,k,c) s(y,c)= (k)[c] ^ four_tables(x,fl_tab,fwd_var,rf1,c) +#define inv_lrnd(y,x,k,c) s(y,c)= (k)[c] ^ four_tables(x,il_tab,inv_var,rf1,c) +#elif defined(ONE_LR_TABLE) +#define fwd_lrnd(y,x,k,c) s(y,c)= (k)[c] ^ one_table(x,ups,fl_tab,fwd_var,rf1,c) +#define inv_lrnd(y,x,k,c) s(y,c)= (k)[c] ^ one_table(x,ups,il_tab,inv_var,rf1,c) +#else +#define fwd_lrnd(y,x,k,c) s(y,c) = no_table(x,s_box,fwd_var,rf1,c) ^ (k)[c] +#define inv_lrnd(y,x,k,c) s(y,c) = no_table(x,inv_s_box,inv_var,rf1,c) ^ (k)[c] +#endif + +#if AES_BLOCK_SIZE == 16 + +#if defined(ARRAYS) +#define locals(y,x) x[4],y[4] +#else +#define locals(y,x) x##0,x##1,x##2,x##3,y##0,y##1,y##2,y##3 +// the following defines prevent the compiler requiring the declaration +// of generated but unused variables in the fwd_var and inv_var macros +#define b04 unused +#define b05 unused +#define b06 unused +#define b07 unused +#define b14 unused +#define b15 unused +#define b16 unused +#define b17 unused +#endif +#define l_copy(y, x) s(y,0) = s(x,0); s(y,1) = s(x,1); \ + s(y,2) = s(x,2); s(y,3) = s(x,3); +#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); si(y,x,k,3) +#define state_out(y,x) so(y,x,0); so(y,x,1); so(y,x,2); so(y,x,3) +#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); rm(y,x,k,3) + +#elif AES_BLOCK_SIZE == 24 + +#if defined(ARRAYS) +#define locals(y,x) x[6],y[6] +#else +#define locals(y,x) x##0,x##1,x##2,x##3,x##4,x##5, \ + y##0,y##1,y##2,y##3,y##4,y##5 +#define b06 unused +#define b07 unused +#define b16 unused +#define b17 unused +#endif +#define l_copy(y, x) s(y,0) = s(x,0); s(y,1) = s(x,1); \ + s(y,2) = s(x,2); s(y,3) = s(x,3); \ + s(y,4) = s(x,4); s(y,5) = s(x,5); +#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); \ + si(y,x,k,3); si(y,x,k,4); si(y,x,k,5) +#define state_out(y,x) so(y,x,0); so(y,x,1); so(y,x,2); \ + so(y,x,3); so(y,x,4); so(y,x,5) +#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); \ + rm(y,x,k,3); rm(y,x,k,4); rm(y,x,k,5) +#else + +#if defined(ARRAYS) +#define locals(y,x) x[8],y[8] +#else +#define locals(y,x) x##0,x##1,x##2,x##3,x##4,x##5,x##6,x##7, \ + y##0,y##1,y##2,y##3,y##4,y##5,y##6,y##7 +#endif +#define l_copy(y, x) s(y,0) = s(x,0); s(y,1) = s(x,1); \ + s(y,2) = s(x,2); s(y,3) = s(x,3); \ + s(y,4) = s(x,4); s(y,5) = s(x,5); \ + s(y,6) = s(x,6); s(y,7) = s(x,7); + +#if AES_BLOCK_SIZE == 32 + +#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); si(y,x,k,3); \ + si(y,x,k,4); si(y,x,k,5); si(y,x,k,6); si(y,x,k,7) +#define state_out(y,x) so(y,x,0); so(y,x,1); so(y,x,2); so(y,x,3); \ + so(y,x,4); so(y,x,5); so(y,x,6); so(y,x,7) +#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); rm(y,x,k,3); \ + rm(y,x,k,4); rm(y,x,k,5); rm(y,x,k,6); rm(y,x,k,7) +#else + +#define state_in(y,x,k) \ +switch(nc) \ +{ case 8: si(y,x,k,7); si(y,x,k,6); \ + case 6: si(y,x,k,5); si(y,x,k,4); \ + case 4: si(y,x,k,3); si(y,x,k,2); \ + si(y,x,k,1); si(y,x,k,0); \ +} + +#define state_out(y,x) \ +switch(nc) \ +{ case 8: so(y,x,7); so(y,x,6); \ + case 6: so(y,x,5); so(y,x,4); \ + case 4: so(y,x,3); so(y,x,2); \ + so(y,x,1); so(y,x,0); \ +} + +#if defined(FAST_VARIABLE) + +#define round(rm,y,x,k) \ +switch(nc) \ +{ case 8: rm(y,x,k,7); rm(y,x,k,6); \ + rm(y,x,k,5); rm(y,x,k,4); \ + rm(y,x,k,3); rm(y,x,k,2); \ + rm(y,x,k,1); rm(y,x,k,0); \ + break; \ + case 6: rm(y,x,k,5); rm(y,x,k,4); \ + rm(y,x,k,3); rm(y,x,k,2); \ + rm(y,x,k,1); rm(y,x,k,0); \ + break; \ + case 4: rm(y,x,k,3); rm(y,x,k,2); \ + rm(y,x,k,1); rm(y,x,k,0); \ + break; \ +} +#else + +#define round(rm,y,x,k) \ +switch(nc) \ +{ case 8: rm(y,x,k,7); rm(y,x,k,6); \ + case 6: rm(y,x,k,5); rm(y,x,k,4); \ + case 4: rm(y,x,k,3); rm(y,x,k,2); \ + rm(y,x,k,1); rm(y,x,k,0); \ +} + +#endif + +#endif +#endif + +/** + * Implementation of private_aes_crypter_t.encrypt_block. + */ +static void encrypt_block(const private_aes_crypter_t *this, const unsigned char in_blk[], unsigned char out_blk[]) +{ u_int32_t locals(b0, b1); + const u_int32_t *kp = this->aes_e_key; + +#if !defined(ONE_TABLE) && !defined(FOUR_TABLES) + u_int32_t f2; +#endif + + state_in(b0, in_blk, kp); kp += nc; + +#if defined(UNROLL) + + switch(this->aes_Nrnd) + { + case 14: round(fwd_rnd, b1, b0, kp ); + round(fwd_rnd, b0, b1, kp + nc ); kp += 2 * nc; + case 12: round(fwd_rnd, b1, b0, kp ); + round(fwd_rnd, b0, b1, kp + nc ); kp += 2 * nc; + case 10: round(fwd_rnd, b1, b0, kp ); + round(fwd_rnd, b0, b1, kp + nc); + round(fwd_rnd, b1, b0, kp + 2 * nc); + round(fwd_rnd, b0, b1, kp + 3 * nc); + round(fwd_rnd, b1, b0, kp + 4 * nc); + round(fwd_rnd, b0, b1, kp + 5 * nc); + round(fwd_rnd, b1, b0, kp + 6 * nc); + round(fwd_rnd, b0, b1, kp + 7 * nc); + round(fwd_rnd, b1, b0, kp + 8 * nc); + round(fwd_lrnd, b0, b1, kp + 9 * nc); + } + +#elif defined(PARTIAL_UNROLL) + { u_int32_t rnd; + + for(rnd = 0; rnd < (this->aes_Nrnd >> 1) - 1; ++rnd) + { + round(fwd_rnd, b1, b0, kp); + round(fwd_rnd, b0, b1, kp + nc); kp += 2 * nc; + } + + round(fwd_rnd, b1, b0, kp); + round(fwd_lrnd, b0, b1, kp + nc); + } +#else + { u_int32_t rnd; + + for(rnd = 0; rnd < this->aes_Nrnd - 1; ++rnd) + { + round(fwd_rnd, b1, b0, kp); + l_copy(b0, b1); kp += nc; + } + + round(fwd_lrnd, b0, b1, kp); + } +#endif + + state_out(out_blk, b0); +} + +/** + * Implementation of private_aes_crypter_t.decrypt_block. + */ +static void decrypt_block(const private_aes_crypter_t *this, const unsigned char in_blk[], unsigned char out_blk[]) +{ u_int32_t locals(b0, b1); + const u_int32_t *kp = this->aes_d_key; + +#if !defined(ONE_TABLE) && !defined(FOUR_TABLES) + u_int32_t f2, f4, f8, f9; +#endif + + state_in(b0, in_blk, kp); kp += nc; + +#if defined(UNROLL) + + switch(this->aes_Nrnd) + { + case 14: round(inv_rnd, b1, b0, kp ); + round(inv_rnd, b0, b1, kp + nc ); kp += 2 * nc; + case 12: round(inv_rnd, b1, b0, kp ); + round(inv_rnd, b0, b1, kp + nc ); kp += 2 * nc; + case 10: round(inv_rnd, b1, b0, kp ); + round(inv_rnd, b0, b1, kp + nc); + round(inv_rnd, b1, b0, kp + 2 * nc); + round(inv_rnd, b0, b1, kp + 3 * nc); + round(inv_rnd, b1, b0, kp + 4 * nc); + round(inv_rnd, b0, b1, kp + 5 * nc); + round(inv_rnd, b1, b0, kp + 6 * nc); + round(inv_rnd, b0, b1, kp + 7 * nc); + round(inv_rnd, b1, b0, kp + 8 * nc); + round(inv_lrnd, b0, b1, kp + 9 * nc); + } + +#elif defined(PARTIAL_UNROLL) + { u_int32_t rnd; + + for(rnd = 0; rnd < (this->aes_Nrnd >> 1) - 1; ++rnd) + { + round(inv_rnd, b1, b0, kp); + round(inv_rnd, b0, b1, kp + nc); kp += 2 * nc; + } + + round(inv_rnd, b1, b0, kp); + round(inv_lrnd, b0, b1, kp + nc); + } +#else + { u_int32_t rnd; + + for(rnd = 0; rnd < this->aes_Nrnd - 1; ++rnd) + { + round(inv_rnd, b1, b0, kp); + l_copy(b0, b1); kp += nc; + } + + round(inv_lrnd, b0, b1, kp); + } +#endif + + state_out(out_blk, b0); +} + +/** + * Implementation of crypter_t.decrypt. + */ +static status_t decrypt (private_aes_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *decrypted) +{ + int ret, pos; + const u_int32_t *iv_i; + u_int8_t *in, *out; + + ret = data.len; + if (((data.len) % 16) != 0) + { + /* data length must be padded to a multiple of blocksize */ + return INVALID_ARG; + } + + decrypted->ptr = malloc(data.len); + if (decrypted->ptr == NULL) + { + return OUT_OF_RES; + } + decrypted->len = data.len; + + in = data.ptr; + out = decrypted->ptr; + + pos=data.len-16; + in+=pos; + out+=pos; + while(pos>=0) { + this->decrypt_block(this,in,out); + if (pos==0) + iv_i=(const u_int32_t*) (iv.ptr); + else + iv_i=(const u_int32_t*) (in-16); + *((u_int32_t *)(&out[ 0])) ^= iv_i[0]; + *((u_int32_t *)(&out[ 4])) ^= iv_i[1]; + *((u_int32_t *)(&out[ 8])) ^= iv_i[2]; + *((u_int32_t *)(&out[12])) ^= iv_i[3]; + in-=16; + out-=16; + pos-=16; + } + + return SUCCESS; +} + + +/** + * Implementation of crypter_t.decrypt. + */ +static status_t encrypt (private_aes_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *encrypted) +{ + int ret, pos; + const u_int32_t *iv_i; + u_int8_t *in, *out; + + ret = data.len; + if (((data.len) % 16) != 0) + { + /* data length must be padded to a multiple of blocksize */ + return INVALID_ARG; + } + + encrypted->ptr = malloc(data.len); + if (encrypted->ptr == NULL) + { + return OUT_OF_RES; + } + encrypted->len = data.len; + + in = data.ptr; + out = encrypted->ptr; + + pos=0; + while(posencrypt_block(this,out,out); + in+=16; + out+=16; + pos+=16; + } + return SUCCESS; +} + +/** + * Implementation of crypter_t.get_block_size. + */ +static size_t get_block_size (private_aes_crypter_t *this) +{ + return AES_BLOCK_SIZE; +} + +/** + * Implementation of crypter_t.get_key_size. + */ +static size_t get_key_size (private_aes_crypter_t *this) +{ + return this->key_size; +} + +/** + * Implementation of crypter_t.set_key. + */ +static status_t set_key (private_aes_crypter_t *this, chunk_t key) +{ + u_int32_t *kf, *kt, rci, f = 0; + u_int8_t *in_key = key.ptr; + + if (key.len != this->key_size) + { + return INVALID_ARG; + } + + this->aes_Nrnd = (this->aes_Nkey > (nc) ? this->aes_Nkey : (nc)) + 6; + + this->aes_e_key[0] = const_word_in(in_key ); + this->aes_e_key[1] = const_word_in(in_key + 4); + this->aes_e_key[2] = const_word_in(in_key + 8); + this->aes_e_key[3] = const_word_in(in_key + 12); + + kf = this->aes_e_key; + kt = kf + nc * (this->aes_Nrnd + 1) - this->aes_Nkey; + rci = 0; + + switch(this->aes_Nkey) + { + case 4: do + { kf[4] = kf[0] ^ ls_box(kf[3],3) ^ rcon_tab[rci++]; + kf[5] = kf[1] ^ kf[4]; + kf[6] = kf[2] ^ kf[5]; + kf[7] = kf[3] ^ kf[6]; + kf += 4; + } + while(kf < kt); + break; + + case 6: this->aes_e_key[4] = const_word_in(in_key + 16); + this->aes_e_key[5] = const_word_in(in_key + 20); + do + { kf[ 6] = kf[0] ^ ls_box(kf[5],3) ^ rcon_tab[rci++]; + kf[ 7] = kf[1] ^ kf[ 6]; + kf[ 8] = kf[2] ^ kf[ 7]; + kf[ 9] = kf[3] ^ kf[ 8]; + kf[10] = kf[4] ^ kf[ 9]; + kf[11] = kf[5] ^ kf[10]; + kf += 6; + } + while(kf < kt); + break; + + case 8: this->aes_e_key[4] = const_word_in(in_key + 16); + this->aes_e_key[5] = const_word_in(in_key + 20); + this->aes_e_key[6] = const_word_in(in_key + 24); + this->aes_e_key[7] = const_word_in(in_key + 28); + do + { kf[ 8] = kf[0] ^ ls_box(kf[7],3) ^ rcon_tab[rci++]; + kf[ 9] = kf[1] ^ kf[ 8]; + kf[10] = kf[2] ^ kf[ 9]; + kf[11] = kf[3] ^ kf[10]; + kf[12] = kf[4] ^ ls_box(kf[11],0); + kf[13] = kf[5] ^ kf[12]; + kf[14] = kf[6] ^ kf[13]; + kf[15] = kf[7] ^ kf[14]; + kf += 8; + } + while (kf < kt); + break; + } + + if(!f) + { + u_int32_t i; + + kt = this->aes_d_key + nc * this->aes_Nrnd; + kf = this->aes_e_key; + + cpy(kt, kf); kt -= 2 * nc; + + for(i = 1; i < this->aes_Nrnd; ++i) + { +#if defined(ONE_TABLE) || defined(FOUR_TABLES) +#if !defined(ONE_IM_TABLE) && !defined(FOUR_IM_TABLES) + u_int32_t f2, f4, f8, f9; +#endif + mix(kt, kf); +#else + cpy(kt, kf); +#endif + kt -= 2 * nc; + } + cpy(kt, kf); + } + + return SUCCESS; +} + +/** + * Implementation of crypter_t.destroy and aes_crypter_t.destroy. + */ +static void destroy (private_aes_crypter_t *this) +{ + free(this); +} + +/* + * Described in header + */ +aes_crypter_t *aes_crypter_create(encryption_algorithm_t algo, size_t key_size) +{ + private_aes_crypter_t *this; + + if (algo != ENCR_AES_CBC) + { + return NULL; + } + + this = malloc_thing(private_aes_crypter_t); + + #if !defined(FIXED_TABLES) + if(!tab_gen) { gen_tabs(); tab_gen = 1; } + #endif + + this->key_size = key_size; + switch(key_size) + { + case 32: /* bytes */ + this->aes_Nkey = 8; + break; + case 24: /* bytes */ + this->aes_Nkey = 6; + break; + case 16: /* bytes */ + this->aes_Nkey = 4; + break; + default: + free(this); + return NULL; + } + + /* functions of crypter_t interface */ + this->public.crypter_interface.encrypt = (status_t (*) (crypter_t *, chunk_t,chunk_t, chunk_t *)) encrypt; + this->public.crypter_interface.decrypt = (status_t (*) (crypter_t *, chunk_t , chunk_t, chunk_t *)) decrypt; + this->public.crypter_interface.get_block_size = (size_t (*) (crypter_t *)) get_block_size; + this->public.crypter_interface.get_key_size = (size_t (*) (crypter_t *)) get_key_size; + this->public.crypter_interface.set_key = (status_t (*) (crypter_t *,chunk_t)) set_key; + this->public.crypter_interface.destroy = (void (*) (crypter_t *)) destroy; + + /* private functions */ + this->decrypt_block = decrypt_block; + this->encrypt_block = encrypt_block; + + return &(this->public); +} diff --git a/src/libstrongswan/plugins/aes/aes_crypter.h b/src/libstrongswan/plugins/aes/aes_crypter.h new file mode 100644 index 000000000..e42a6bc5b --- /dev/null +++ b/src/libstrongswan/plugins/aes/aes_crypter.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2005-2008 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 aes_crypter aes_crypter + * @{ @ingroup aes_p + */ + +#ifndef AES_CRYPTER_H_ +#define AES_CRYPTER_H_ + +typedef struct aes_crypter_t aes_crypter_t; + +#include + +/** + * Class implementing the AES encryption algorithm. + */ +struct aes_crypter_t { + + /** + * The crypter_t interface. + */ + crypter_t crypter_interface; +}; + +/** + * Constructor to create aes_crypter_t objects. + * + * @param key_size key size in bytes + * @param algo algorithm to implement + * @return aes_crypter_t object, NULL if not supported + */ +aes_crypter_t *aes_crypter_create(encryption_algorithm_t algo, + size_t key_size); + +#endif /* AES_CRYPTER_H_ @}*/ diff --git a/src/libstrongswan/plugins/aes/aes_plugin.c b/src/libstrongswan/plugins/aes/aes_plugin.c new file mode 100644 index 000000000..590948f07 --- /dev/null +++ b/src/libstrongswan/plugins/aes/aes_plugin.c @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "aes_plugin.h" + +#include +#include "aes_crypter.h" + +typedef struct private_aes_plugin_t private_aes_plugin_t; + +/** + * private data of aes_plugin + */ +struct private_aes_plugin_t { + + /** + * public functions + */ + aes_plugin_t public; +}; + +/** + * Implementation of aes_plugin_t.destroy + */ +static void destroy(private_aes_plugin_t *this) +{ + lib->crypto->remove_crypter(lib->crypto, + (crypter_constructor_t)aes_crypter_create); + free(this); +} + +/* + * see header file + */ +plugin_t *plugin_create() +{ + private_aes_plugin_t *this = malloc_thing(private_aes_plugin_t); + + this->public.plugin.destroy = (void(*)(plugin_t*))destroy; + + lib->crypto->add_crypter(lib->crypto, ENCR_AES_CBC, + (crypter_constructor_t)aes_crypter_create); + + return &this->public.plugin; +} + diff --git a/src/libstrongswan/plugins/aes/aes_plugin.h b/src/libstrongswan/plugins/aes/aes_plugin.h new file mode 100644 index 000000000..4cf0bc15e --- /dev/null +++ b/src/libstrongswan/plugins/aes/aes_plugin.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 aes_p aes + * @ingroup plugins + * + * @defgroup aes_plugin aes_plugin + * @{ @ingroup aes_p + */ + +#ifndef AES_PLUGIN_H_ +#define AES_PLUGIN_H_ + +#include + +typedef struct aes_plugin_t aes_plugin_t; + +/** + * Plugin implementing AES based algorithms in software. + */ +struct aes_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +/** + * Create a aes_plugin instance. + */ +plugin_t *plugin_create(); + +#endif /* AES_PLUGIN_H_ @}*/ diff --git a/src/libstrongswan/plugins/curl/Makefile.am b/src/libstrongswan/plugins/curl/Makefile.am new file mode 100644 index 000000000..1b44516b2 --- /dev/null +++ b/src/libstrongswan/plugins/curl/Makefile.am @@ -0,0 +1,11 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan + +AM_CFLAGS = -rdynamic + +plugin_LTLIBRARIES = libstrongswan-curl.la + +libstrongswan_curl_la_SOURCES = curl_plugin.h curl_plugin.c curl_fetcher.c curl_fetcher.h +libstrongswan_curl_la_LDFLAGS = -module +libstrongswan_curl_la_LIBADD = -lcurl + diff --git a/src/libstrongswan/plugins/curl/curl_fetcher.c b/src/libstrongswan/plugins/curl/curl_fetcher.c new file mode 100644 index 000000000..fe49717fa --- /dev/null +++ b/src/libstrongswan/plugins/curl/curl_fetcher.c @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2008 Martin Willi + * Copyright (C) 2007 Andreas Steffen + * 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 . + * + * 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. + * + * $Id$ + */ + +#include + +#include +#include + +#include "curl_fetcher.h" + +#define DEFAULT_TIMEOUT 10 + +typedef struct private_curl_fetcher_t private_curl_fetcher_t; + +/** + * private data of a curl_fetcher_t object. + */ +struct private_curl_fetcher_t { + /** + * Public data + */ + curl_fetcher_t public; + + /** + * CURL handle + */ + CURL* curl; + + /** + * request type, as set with FETCH_REQUEST_TYPE + */ + char *request_type; +}; + +/** + * writes data into a dynamically resizeable chunk_t + */ +static size_t append(void *ptr, size_t size, size_t nmemb, chunk_t *data) +{ + size_t realsize = size * nmemb; + + data->ptr = (u_char*)realloc(data->ptr, data->len + realsize); + if (data->ptr) + { + memcpy(&data->ptr[data->len], ptr, realsize); + data->len += realsize; + } + return realsize; +} + +/** + * Implements fetcher_t.fetch. + */ +static status_t fetch(private_curl_fetcher_t *this, char *uri, chunk_t *result) +{ + struct curl_slist *headers = NULL; + char error[CURL_ERROR_SIZE]; + char buf[256];; + status_t status; + + *result = chunk_empty; + + if (curl_easy_setopt(this->curl, CURLOPT_URL, uri) != CURLE_OK) + { /* URL type not supported by curl */ + return NOT_SUPPORTED; + } + curl_easy_setopt(this->curl, CURLOPT_ERRORBUFFER, error); + curl_easy_setopt(this->curl, CURLOPT_FAILONERROR, TRUE); + curl_easy_setopt(this->curl, CURLOPT_NOSIGNAL, TRUE); + curl_easy_setopt(this->curl, CURLOPT_CONNECTTIMEOUT, DEFAULT_TIMEOUT); + curl_easy_setopt(this->curl, CURLOPT_WRITEFUNCTION, (void*)append); + curl_easy_setopt(this->curl, CURLOPT_WRITEDATA, (void*)result); + if (this->request_type) + { + snprintf(buf, sizeof(buf), "Content-Type: %s", this->request_type); + headers = curl_slist_append(headers, buf); + curl_easy_setopt(this->curl, CURLOPT_HTTPHEADER, headers); + } + + DBG2("sending http request to '%s'...", uri); + switch (curl_easy_perform(this->curl)) + { + case CURLE_UNSUPPORTED_PROTOCOL: + status = NOT_SUPPORTED; + break; + case CURLE_OK: + status = SUCCESS; + break; + default: + DBG1("libcurl http request failed: %s", error); + status = FAILED; + break; + } + curl_slist_free_all(headers); + return status; +} + +/** + * Implementation of fetcher_t.set_option. + */ +static bool set_option(private_curl_fetcher_t *this, fetcher_option_t option, ...) +{ + va_list args; + + va_start(args, option); + switch (option) + { + case FETCH_REQUEST_DATA: + { + chunk_t data = va_arg(args, chunk_t); + curl_easy_setopt(this->curl, CURLOPT_POSTFIELDS, data.ptr); + curl_easy_setopt(this->curl, CURLOPT_POSTFIELDSIZE, data.len); + return TRUE; + } + case FETCH_REQUEST_TYPE: + { + this->request_type = va_arg(args, char*); + return TRUE; + } + case FETCH_TIMEOUT: + { + curl_easy_setopt(this->curl, CURLOPT_CONNECTTIMEOUT, + va_arg(args, u_int)); + return TRUE; + } + default: + return FALSE; + } +} + +/** + * Implements fetcher_t.destroy + */ +static void destroy(private_curl_fetcher_t *this) +{ + curl_easy_cleanup(this->curl); + free(this); +} + +/* + * Described in header. + */ +curl_fetcher_t *curl_fetcher_create() +{ + private_curl_fetcher_t *this = malloc_thing(private_curl_fetcher_t); + + this->curl = curl_easy_init(); + if (this->curl == NULL) + { + free(this); + return NULL; + } + this->request_type = NULL; + + this->public.interface.fetch = (status_t(*)(fetcher_t*,char*,chunk_t*))fetch; + this->public.interface.set_option = (bool(*)(fetcher_t*, fetcher_option_t option, ...))set_option; + this->public.interface.destroy = (void (*)(fetcher_t*))destroy; + + return &this->public; +} + diff --git a/src/libstrongswan/plugins/curl/curl_fetcher.h b/src/libstrongswan/plugins/curl/curl_fetcher.h new file mode 100644 index 000000000..3028eac1b --- /dev/null +++ b/src/libstrongswan/plugins/curl/curl_fetcher.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 curl_fetcher curl_fetcher + * @{ @ingroup curl_p + */ + +#ifndef CURL_FETCHER_H_ +#define CURL_FETCHER_H_ + +typedef struct curl_fetcher_t curl_fetcher_t; + +/** + * Fetcher implementation using libcurl + */ +struct curl_fetcher_t { + + /** + * Implements fetcher interface + */ + fetcher_t interface; + + /** + * Destroy a curl_fetcher instance. + */ + void (*destroy)(curl_fetcher_t *this); +}; + +/** + * Create a curl_fetcher instance. + */ +curl_fetcher_t *curl_fetcher_create(); + +#endif /* CURL_FETCHER_H_ @}*/ diff --git a/src/libstrongswan/plugins/curl/curl_plugin.c b/src/libstrongswan/plugins/curl/curl_plugin.c new file mode 100644 index 000000000..04e9b1783 --- /dev/null +++ b/src/libstrongswan/plugins/curl/curl_plugin.c @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "curl_plugin.h" + +#include +#include +#include "curl_fetcher.h" + +#include + +typedef struct private_curl_plugin_t private_curl_plugin_t; + +/** + * private data of curl_plugin + */ +struct private_curl_plugin_t { + + /** + * public functions + */ + curl_plugin_t public; +}; + +/** + * Implementation of curl_plugin_t.curltroy + */ +static void destroy(private_curl_plugin_t *this) +{ + lib->fetcher->remove_fetcher(lib->fetcher, + (fetcher_constructor_t)curl_fetcher_create); + curl_global_cleanup(); + free(this); +} + +/* + * see header file + */ +plugin_t *plugin_create() +{ + CURLcode res; + private_curl_plugin_t *this = malloc_thing(private_curl_plugin_t); + + this->public.plugin.destroy = (void(*)(plugin_t*))destroy; + + res = curl_global_init(CURL_GLOBAL_NOTHING); + if (res == CURLE_OK) + { + lib->fetcher->add_fetcher(lib->fetcher, + (fetcher_constructor_t)curl_fetcher_create, "file://"); + lib->fetcher->add_fetcher(lib->fetcher, + (fetcher_constructor_t)curl_fetcher_create, "http://"); + lib->fetcher->add_fetcher(lib->fetcher, + (fetcher_constructor_t)curl_fetcher_create, "https://"); + lib->fetcher->add_fetcher(lib->fetcher, + (fetcher_constructor_t)curl_fetcher_create, "ftp://"); + } + else + { + DBG1("global libcurl initializing failed: %s, curl disabled", + curl_easy_strerror(res)); + } + return &this->public.plugin; +} + diff --git a/src/libstrongswan/plugins/curl/curl_plugin.h b/src/libstrongswan/plugins/curl/curl_plugin.h new file mode 100644 index 000000000..73166a25b --- /dev/null +++ b/src/libstrongswan/plugins/curl/curl_plugin.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 curl_p curl + * @ingroup plugins + * + * @defgroup curl_plugin curl_plugin + * @{ @ingroup curl_p + */ + +#ifndef CURL_PLUGIN_H_ +#define CURL_PLUGIN_H_ + +#include + +typedef struct curl_plugin_t curl_plugin_t; + +/** + * Plugin implementing fetcher interface using libcurl http library. + */ +struct curl_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +/** + * Create a curl_plugin instance. + */ +plugin_t *plugin_create(); + +#endif /* CURL_PLUGIN_H_ @}*/ diff --git a/src/libstrongswan/plugins/des/Makefile.am b/src/libstrongswan/plugins/des/Makefile.am new file mode 100644 index 000000000..ea94eda8a --- /dev/null +++ b/src/libstrongswan/plugins/des/Makefile.am @@ -0,0 +1,10 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan + +AM_CFLAGS = -rdynamic + +plugin_LTLIBRARIES = libstrongswan-des.la + +libstrongswan_des_la_SOURCES = des_plugin.h des_plugin.c des_crypter.c des_crypter.h +libstrongswan_des_la_LDFLAGS = -module + diff --git a/src/libstrongswan/plugins/des/des_crypter.c b/src/libstrongswan/plugins/des/des_crypter.c new file mode 100644 index 000000000..55c12ad81 --- /dev/null +++ b/src/libstrongswan/plugins/des/des_crypter.c @@ -0,0 +1,1531 @@ +/* Copyright (C) 2006 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * Derived from Plutos DES library by Eric Young. + * + * Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + * + * $Id$ + */ + +#include "des_crypter.h" + +typedef u_char des_cblock[8]; + +typedef struct des_ks_struct { + des_cblock _; +} des_key_schedule[16]; + + +typedef struct private_des_crypter_t private_des_crypter_t; + +/** + * Private data for des_crypter_t + */ +struct private_des_crypter_t { + + /** + * Public part of this class. + */ + des_crypter_t public; + + /** + * Key size, depends on algoritm... + */ + size_t key_size; + + union { + /** key schedule for single des */ + des_key_schedule ks; + /** key schedule for 3des */ + des_key_schedule ks3[3]; + }; +}; + + +#define DES_ENCRYPT 1 +#define DES_DECRYPT 0 + +#define DES_LONG u_int32_t + +#if defined(WIN32) || defined(WIN16) +#ifndef MSDOS +#define MSDOS +#endif +#endif + +#ifndef DES_DEFAULT_OPTIONS +/* the following is tweaked from a config script, that is why it is a + * protected undef/define */ +#ifndef DES_PTR +#define DES_PTR +#endif + +/* This helps C compiler generate the correct code for multiple functional + * units. It reduces register dependancies at the expense of 2 more + * registers */ +#ifndef DES_RISC1 +#define DES_RISC1 +#endif + +#ifndef DES_RISC2 +#undef DES_RISC2 +#endif + +#if defined(DES_RISC1) && defined(DES_RISC2) +YOU SHOULD NOT HAVE BOTH DES_RISC1 AND DES_RISC2 DEFINED!!!!! +#endif + +/* Unroll the inner loop, this sometimes helps, sometimes hinders. + * Very mucy CPU dependant */ +#ifndef DES_UNROLL +#define DES_UNROLL +#endif + +/* These default values were supplied by + * Peter Gutman + * They are only used if nothing else has been defined */ +#if !defined(DES_PTR) && !defined(DES_RISC1) && !defined(DES_RISC2) && !defined(DES_UNROLL) +/* Special defines which change the way the code is built depending on the + CPU and OS. For SGI machines you can use _MIPS_SZLONG (32 or 64) to find + even newer MIPS CPU's, but at the moment one size fits all for + optimization options. Older Sparc's work better with only UNROLL, but + there's no way to tell at compile time what it is you're running on */ + +#if defined( sun ) /* Newer Sparc's */ +#define DES_PTR +#define DES_RISC1 +#define DES_UNROLL +#elif defined( __ultrix ) /* Older MIPS */ +#define DES_PTR +#define DES_RISC2 +#define DES_UNROLL +#elif defined( __osf1__ ) /* Alpha */ +#define DES_PTR +#define DES_RISC2 +#elif defined ( _AIX ) /* RS6000 */ + /* Unknown */ +#elif defined( __hpux ) /* HP-PA */ + /* Unknown */ +#elif defined( __aux ) /* 68K */ + /* Unknown */ +#elif defined( __dgux ) /* 88K (but P6 in latest boxes) */ +#define DES_UNROLL +#elif defined( __sgi ) /* Newer MIPS */ +#define DES_PTR +#define DES_RISC2 +#define DES_UNROLL +#elif defined( i386 ) /* x86 boxes, should be gcc */ +#define DES_PTR +#define DES_RISC1 +#define DES_UNROLL +#endif /* Systems-specific speed defines */ +#endif + +#endif /* DES_DEFAULT_OPTIONS */ + +#ifdef MSDOS /* Visual C++ 2.1 (Windows NT/95) */ +#include +#include +#include +#include +#ifndef RAND +#define RAND +#endif +#undef NOPROTO +#endif + +#if defined(__STDC__) || defined(VMS) || defined(M_XENIX) || defined(MSDOS) +#ifndef __KERNEL__ +#include +#else +#include +#endif +#endif + +#ifndef RAND +#define RAND +#endif + +#ifdef linux +#undef RAND +#endif + +#ifdef MSDOS +#define getpid() 2 +#define RAND +#undef NOPROTO +#endif + +#if defined(NOCONST) +#define const +#endif + +#ifdef __STDC__ +#undef NOPROTO +#endif + +#ifdef RAND +#define srandom(s) srand(s) +#define random rand +#endif + +#define ITERATIONS 16 +#define HALF_ITERATIONS 8 + +/* used in des_read and des_write */ +#define MAXWRITE (1024*16) +#define BSIZE (MAXWRITE+4) + +#define c2l(c,l) (l =((DES_LONG)(*((c)++))) , \ + l|=((DES_LONG)(*((c)++)))<< 8L, \ + l|=((DES_LONG)(*((c)++)))<<16L, \ + l|=((DES_LONG)(*((c)++)))<<24L) + +/* NOTE - c is not incremented as per c2l */ +#define c2ln(c,l1,l2,n) { \ + c+=n; \ + l1=l2=0; \ + switch (n) { \ + case 8: l2 =((DES_LONG)(*(--(c))))<<24L; \ + case 7: l2|=((DES_LONG)(*(--(c))))<<16L; \ + case 6: l2|=((DES_LONG)(*(--(c))))<< 8L; \ + case 5: l2|=((DES_LONG)(*(--(c)))); \ + case 4: l1 =((DES_LONG)(*(--(c))))<<24L; \ + case 3: l1|=((DES_LONG)(*(--(c))))<<16L; \ + case 2: l1|=((DES_LONG)(*(--(c))))<< 8L; \ + case 1: l1|=((DES_LONG)(*(--(c)))); \ +} \ +} + +#define l2c(l,c) (*((c)++)=(unsigned char)(((l) )&0xff), \ + *((c)++)=(unsigned char)(((l)>> 8L)&0xff), \ + *((c)++)=(unsigned char)(((l)>>16L)&0xff), \ + *((c)++)=(unsigned char)(((l)>>24L)&0xff)) + +/* replacements for htonl and ntohl since I have no idea what to do + * when faced with machines with 8 byte longs. */ +#define HDRSIZE 4 + +#define n2l(c,l) (l =((DES_LONG)(*((c)++)))<<24L, \ + l|=((DES_LONG)(*((c)++)))<<16L, \ + l|=((DES_LONG)(*((c)++)))<< 8L, \ + l|=((DES_LONG)(*((c)++)))) + +#define l2n(l,c) (*((c)++)=(unsigned char)(((l)>>24L)&0xff), \ + *((c)++)=(unsigned char)(((l)>>16L)&0xff), \ + *((c)++)=(unsigned char)(((l)>> 8L)&0xff), \ + *((c)++)=(unsigned char)(((l) )&0xff)) + +/* NOTE - c is not incremented as per l2c */ +#define l2cn(l1,l2,c,n) { \ + c+=n; \ + switch (n) { \ + case 8: *(--(c))=(unsigned char)(((l2)>>24L)&0xff); \ + case 7: *(--(c))=(unsigned char)(((l2)>>16L)&0xff); \ + case 6: *(--(c))=(unsigned char)(((l2)>> 8L)&0xff); \ + case 5: *(--(c))=(unsigned char)(((l2) )&0xff); \ + case 4: *(--(c))=(unsigned char)(((l1)>>24L)&0xff); \ + case 3: *(--(c))=(unsigned char)(((l1)>>16L)&0xff); \ + case 2: *(--(c))=(unsigned char)(((l1)>> 8L)&0xff); \ + case 1: *(--(c))=(unsigned char)(((l1) )&0xff); \ +} \ +} + +#if defined(WIN32) +#define ROTATE(a,n) (_lrotr(a,n)) +#else +#define ROTATE(a,n) (((a)>>(n))+((a)<<(32-(n)))) +#endif + +/* Don't worry about the LOAD_DATA() stuff, that is used by + * fcrypt() to add it's little bit to the front */ + +#ifdef DES_FCRYPT + +#define LOAD_DATA_tmp(R,S,u,t,E0,E1) \ +{ DES_LONG tmp; LOAD_DATA(R,S,u,t,E0,E1,tmp); } + +#define LOAD_DATA(R,S,u,t,E0,E1,tmp) \ + t=R^(R>>16L); \ + u=t&E0; t&=E1; \ + tmp=(u<<16); u^=R^s[S ]; u^=tmp; \ + tmp=(t<<16); t^=R^s[S+1]; t^=tmp +#else +#define LOAD_DATA_tmp(a,b,c,d,e,f) LOAD_DATA(a,b,c,d,e,f,g) +#define LOAD_DATA(R,S,u,t,E0,E1,tmp) \ + u=R^s[S ]; \ + t=R^s[S+1] +#endif + +/* The changes to this macro may help or hinder, depending on the + * compiler and the achitecture. gcc2 always seems to do well :-). + * Inspired by Dana How + * DO NOT use the alternative version on machines with 8 byte longs. + * It does not seem to work on the Alpha, even when DES_LONG is 4 + * bytes, probably an issue of accessing non-word aligned objects :-( */ +#ifdef DES_PTR + +/* It recently occured to me that 0^0^0^0^0^0^0 == 0, so there + * is no reason to not xor all the sub items together. This potentially + * saves a register since things can be xored directly into L */ + +#if defined(DES_RISC1) || defined(DES_RISC2) +#ifdef DES_RISC1 +#define D_ENCRYPT(LL,R,S) { \ + unsigned int u1,u2,u3; \ + LOAD_DATA(R,S,u,t,E0,E1,u1); \ + u2=(int)u>>8L; \ + u1=(int)u&0xfc; \ + u2&=0xfc; \ + t=ROTATE(t,4); \ + u>>=16L; \ + LL^= *(DES_LONG *)((unsigned char *)des_SP +u1); \ + LL^= *(DES_LONG *)((unsigned char *)des_SP+0x200+u2); \ + u3=(int)(u>>8L); \ + u1=(int)u&0xfc; \ + u3&=0xfc; \ + LL^= *(DES_LONG *)((unsigned char *)des_SP+0x400+u1); \ + LL^= *(DES_LONG *)((unsigned char *)des_SP+0x600+u3); \ + u2=(int)t>>8L; \ + u1=(int)t&0xfc; \ + u2&=0xfc; \ + t>>=16L; \ + LL^= *(DES_LONG *)((unsigned char *)des_SP+0x100+u1); \ + LL^= *(DES_LONG *)((unsigned char *)des_SP+0x300+u2); \ + u3=(int)t>>8L; \ + u1=(int)t&0xfc; \ + u3&=0xfc; \ + LL^= *(DES_LONG *)((unsigned char *)des_SP+0x500+u1); \ + LL^= *(DES_LONG *)((unsigned char *)des_SP+0x700+u3); } +#endif +#ifdef DES_RISC2 +#define D_ENCRYPT(LL,R,S) { \ + unsigned int u1,u2,s1,s2; \ + LOAD_DATA(R,S,u,t,E0,E1,u1); \ + u2=(int)u>>8L; \ + u1=(int)u&0xfc; \ + u2&=0xfc; \ + t=ROTATE(t,4); \ + LL^= *(DES_LONG *)((unsigned char *)des_SP +u1); \ + LL^= *(DES_LONG *)((unsigned char *)des_SP+0x200+u2); \ + s1=(int)(u>>16L); \ + s2=(int)(u>>24L); \ + s1&=0xfc; \ + s2&=0xfc; \ + LL^= *(DES_LONG *)((unsigned char *)des_SP+0x400+s1); \ + LL^= *(DES_LONG *)((unsigned char *)des_SP+0x600+s2); \ + u2=(int)t>>8L; \ + u1=(int)t&0xfc; \ + u2&=0xfc; \ + LL^= *(DES_LONG *)((unsigned char *)des_SP+0x100+u1); \ + LL^= *(DES_LONG *)((unsigned char *)des_SP+0x300+u2); \ + s1=(int)(t>>16L); \ + s2=(int)(t>>24L); \ + s1&=0xfc; \ + s2&=0xfc; \ + LL^= *(DES_LONG *)((unsigned char *)des_SP+0x500+s1); \ + LL^= *(DES_LONG *)((unsigned char *)des_SP+0x700+s2); } +#endif +#else +#define D_ENCRYPT(LL,R,S) { \ + LOAD_DATA_tmp(R,S,u,t,E0,E1); \ + t=ROTATE(t,4); \ + LL^= \ + *(DES_LONG *)((unsigned char *)des_SP +((u )&0xfc))^ \ + *(DES_LONG *)((unsigned char *)des_SP+0x200+((u>> 8L)&0xfc))^ \ + *(DES_LONG *)((unsigned char *)des_SP+0x400+((u>>16L)&0xfc))^ \ + *(DES_LONG *)((unsigned char *)des_SP+0x600+((u>>24L)&0xfc))^ \ + *(DES_LONG *)((unsigned char *)des_SP+0x100+((t )&0xfc))^ \ + *(DES_LONG *)((unsigned char *)des_SP+0x300+((t>> 8L)&0xfc))^ \ + *(DES_LONG *)((unsigned char *)des_SP+0x500+((t>>16L)&0xfc))^ \ + *(DES_LONG *)((unsigned char *)des_SP+0x700+((t>>24L)&0xfc)); } +#endif + +#else /* original version */ + +#if defined(DES_RISC1) || defined(DES_RISC2) +#ifdef DES_RISC1 +#define D_ENCRYPT(LL,R,S) {\ + unsigned int u1,u2,u3; \ + LOAD_DATA(R,S,u,t,E0,E1,u1); \ + u>>=2L; \ + t=ROTATE(t,6); \ + u2=(int)u>>8L; \ + u1=(int)u&0x3f; \ + u2&=0x3f; \ + u>>=16L; \ + LL^=des_SPtrans[0][u1]; \ + LL^=des_SPtrans[2][u2]; \ + u3=(int)u>>8L; \ + u1=(int)u&0x3f; \ + u3&=0x3f; \ + LL^=des_SPtrans[4][u1]; \ + LL^=des_SPtrans[6][u3]; \ + u2=(int)t>>8L; \ + u1=(int)t&0x3f; \ + u2&=0x3f; \ + t>>=16L; \ + LL^=des_SPtrans[1][u1]; \ + LL^=des_SPtrans[3][u2]; \ + u3=(int)t>>8L; \ + u1=(int)t&0x3f; \ + u3&=0x3f; \ + LL^=des_SPtrans[5][u1]; \ + LL^=des_SPtrans[7][u3]; } +#endif +#ifdef DES_RISC2 +#define D_ENCRYPT(LL,R,S) {\ + unsigned int u1,u2,s1,s2; \ + LOAD_DATA(R,S,u,t,E0,E1,u1); \ + u>>=2L; \ + t=ROTATE(t,6); \ + u2=(int)u>>8L; \ + u1=(int)u&0x3f; \ + u2&=0x3f; \ + LL^=des_SPtrans[0][u1]; \ + LL^=des_SPtrans[2][u2]; \ + s1=(int)u>>16L; \ + s2=(int)u>>24L; \ + s1&=0x3f; \ + s2&=0x3f; \ + LL^=des_SPtrans[4][s1]; \ + LL^=des_SPtrans[6][s2]; \ + u2=(int)t>>8L; \ + u1=(int)t&0x3f; \ + u2&=0x3f; \ + LL^=des_SPtrans[1][u1]; \ + LL^=des_SPtrans[3][u2]; \ + s1=(int)t>>16; \ + s2=(int)t>>24L; \ + s1&=0x3f; \ + s2&=0x3f; \ + LL^=des_SPtrans[5][s1]; \ + LL^=des_SPtrans[7][s2]; } +#endif + +#else + +#define D_ENCRYPT(LL,R,S) {\ + LOAD_DATA_tmp(R,S,u,t,E0,E1); \ + t=ROTATE(t,4); \ + LL^=\ + des_SPtrans[0][(u>> 2L)&0x3f]^ \ + des_SPtrans[2][(u>>10L)&0x3f]^ \ + des_SPtrans[4][(u>>18L)&0x3f]^ \ + des_SPtrans[6][(u>>26L)&0x3f]^ \ + des_SPtrans[1][(t>> 2L)&0x3f]^ \ + des_SPtrans[3][(t>>10L)&0x3f]^ \ + des_SPtrans[5][(t>>18L)&0x3f]^ \ + des_SPtrans[7][(t>>26L)&0x3f]; } +#endif +#endif + + /* IP and FP + * The problem is more of a geometric problem that random bit fiddling. + 0 1 2 3 4 5 6 7 62 54 46 38 30 22 14 6 + 8 9 10 11 12 13 14 15 60 52 44 36 28 20 12 4 + 16 17 18 19 20 21 22 23 58 50 42 34 26 18 10 2 + 24 25 26 27 28 29 30 31 to 56 48 40 32 24 16 8 0 + + 32 33 34 35 36 37 38 39 63 55 47 39 31 23 15 7 + 40 41 42 43 44 45 46 47 61 53 45 37 29 21 13 5 + 48 49 50 51 52 53 54 55 59 51 43 35 27 19 11 3 + 56 57 58 59 60 61 62 63 57 49 41 33 25 17 9 1 + + The output has been subject to swaps of the form + 0 1 -> 3 1 but the odd and even bits have been put into + 2 3 2 0 + different words. The main trick is to remember that + t=((l>>size)^r)&(mask); + r^=t; + l^=(t<>(n))^(b))&(m)),\ + (b)^=(t),\ + (a)^=((t)<<(n))) + +#define IP(l,r) \ +{ \ + register DES_LONG tt; \ + PERM_OP(r,l,tt, 4,0x0f0f0f0fL); \ + PERM_OP(l,r,tt,16,0x0000ffffL); \ + PERM_OP(r,l,tt, 2,0x33333333L); \ + PERM_OP(l,r,tt, 8,0x00ff00ffL); \ + PERM_OP(r,l,tt, 1,0x55555555L); \ +} + +#define FP(l,r) \ +{ \ + register DES_LONG tt; \ + PERM_OP(l,r,tt, 1,0x55555555L); \ + PERM_OP(r,l,tt, 8,0x00ff00ffL); \ + PERM_OP(l,r,tt, 2,0x33333333L); \ + PERM_OP(r,l,tt,16,0x0000ffffL); \ + PERM_OP(l,r,tt, 4,0x0f0f0f0fL); \ +} + +#ifndef NOPROTO +void fcrypt_body(DES_LONG *out,des_key_schedule ks, + DES_LONG Eswap0, DES_LONG Eswap1); +#else +void fcrypt_body(); +#endif + +static const DES_LONG des_skb[8][64]={ + { /* for C bits (numbered as per FIPS 46) 1 2 3 4 5 6 */ + 0x00000000L,0x00000010L,0x20000000L,0x20000010L, + 0x00010000L,0x00010010L,0x20010000L,0x20010010L, + 0x00000800L,0x00000810L,0x20000800L,0x20000810L, + 0x00010800L,0x00010810L,0x20010800L,0x20010810L, + 0x00000020L,0x00000030L,0x20000020L,0x20000030L, + 0x00010020L,0x00010030L,0x20010020L,0x20010030L, + 0x00000820L,0x00000830L,0x20000820L,0x20000830L, + 0x00010820L,0x00010830L,0x20010820L,0x20010830L, + 0x00080000L,0x00080010L,0x20080000L,0x20080010L, + 0x00090000L,0x00090010L,0x20090000L,0x20090010L, + 0x00080800L,0x00080810L,0x20080800L,0x20080810L, + 0x00090800L,0x00090810L,0x20090800L,0x20090810L, + 0x00080020L,0x00080030L,0x20080020L,0x20080030L, + 0x00090020L,0x00090030L,0x20090020L,0x20090030L, + 0x00080820L,0x00080830L,0x20080820L,0x20080830L, + 0x00090820L,0x00090830L,0x20090820L,0x20090830L, + }, + { /* for C bits (numbered as per FIPS 46) 7 8 10 11 12 13 */ + 0x00000000L,0x02000000L,0x00002000L,0x02002000L, + 0x00200000L,0x02200000L,0x00202000L,0x02202000L, + 0x00000004L,0x02000004L,0x00002004L,0x02002004L, + 0x00200004L,0x02200004L,0x00202004L,0x02202004L, + 0x00000400L,0x02000400L,0x00002400L,0x02002400L, + 0x00200400L,0x02200400L,0x00202400L,0x02202400L, + 0x00000404L,0x02000404L,0x00002404L,0x02002404L, + 0x00200404L,0x02200404L,0x00202404L,0x02202404L, + 0x10000000L,0x12000000L,0x10002000L,0x12002000L, + 0x10200000L,0x12200000L,0x10202000L,0x12202000L, + 0x10000004L,0x12000004L,0x10002004L,0x12002004L, + 0x10200004L,0x12200004L,0x10202004L,0x12202004L, + 0x10000400L,0x12000400L,0x10002400L,0x12002400L, + 0x10200400L,0x12200400L,0x10202400L,0x12202400L, + 0x10000404L,0x12000404L,0x10002404L,0x12002404L, + 0x10200404L,0x12200404L,0x10202404L,0x12202404L, + }, + { /* for C bits (numbered as per FIPS 46) 14 15 16 17 19 20 */ + 0x00000000L,0x00000001L,0x00040000L,0x00040001L, + 0x01000000L,0x01000001L,0x01040000L,0x01040001L, + 0x00000002L,0x00000003L,0x00040002L,0x00040003L, + 0x01000002L,0x01000003L,0x01040002L,0x01040003L, + 0x00000200L,0x00000201L,0x00040200L,0x00040201L, + 0x01000200L,0x01000201L,0x01040200L,0x01040201L, + 0x00000202L,0x00000203L,0x00040202L,0x00040203L, + 0x01000202L,0x01000203L,0x01040202L,0x01040203L, + 0x08000000L,0x08000001L,0x08040000L,0x08040001L, + 0x09000000L,0x09000001L,0x09040000L,0x09040001L, + 0x08000002L,0x08000003L,0x08040002L,0x08040003L, + 0x09000002L,0x09000003L,0x09040002L,0x09040003L, + 0x08000200L,0x08000201L,0x08040200L,0x08040201L, + 0x09000200L,0x09000201L,0x09040200L,0x09040201L, + 0x08000202L,0x08000203L,0x08040202L,0x08040203L, + 0x09000202L,0x09000203L,0x09040202L,0x09040203L, + }, + { /* for C bits (numbered as per FIPS 46) 21 23 24 26 27 28 */ + 0x00000000L,0x00100000L,0x00000100L,0x00100100L, + 0x00000008L,0x00100008L,0x00000108L,0x00100108L, + 0x00001000L,0x00101000L,0x00001100L,0x00101100L, + 0x00001008L,0x00101008L,0x00001108L,0x00101108L, + 0x04000000L,0x04100000L,0x04000100L,0x04100100L, + 0x04000008L,0x04100008L,0x04000108L,0x04100108L, + 0x04001000L,0x04101000L,0x04001100L,0x04101100L, + 0x04001008L,0x04101008L,0x04001108L,0x04101108L, + 0x00020000L,0x00120000L,0x00020100L,0x00120100L, + 0x00020008L,0x00120008L,0x00020108L,0x00120108L, + 0x00021000L,0x00121000L,0x00021100L,0x00121100L, + 0x00021008L,0x00121008L,0x00021108L,0x00121108L, + 0x04020000L,0x04120000L,0x04020100L,0x04120100L, + 0x04020008L,0x04120008L,0x04020108L,0x04120108L, + 0x04021000L,0x04121000L,0x04021100L,0x04121100L, + 0x04021008L,0x04121008L,0x04021108L,0x04121108L, + }, + { /* for D bits (numbered as per FIPS 46) 1 2 3 4 5 6 */ + 0x00000000L,0x10000000L,0x00010000L,0x10010000L, + 0x00000004L,0x10000004L,0x00010004L,0x10010004L, + 0x20000000L,0x30000000L,0x20010000L,0x30010000L, + 0x20000004L,0x30000004L,0x20010004L,0x30010004L, + 0x00100000L,0x10100000L,0x00110000L,0x10110000L, + 0x00100004L,0x10100004L,0x00110004L,0x10110004L, + 0x20100000L,0x30100000L,0x20110000L,0x30110000L, + 0x20100004L,0x30100004L,0x20110004L,0x30110004L, + 0x00001000L,0x10001000L,0x00011000L,0x10011000L, + 0x00001004L,0x10001004L,0x00011004L,0x10011004L, + 0x20001000L,0x30001000L,0x20011000L,0x30011000L, + 0x20001004L,0x30001004L,0x20011004L,0x30011004L, + 0x00101000L,0x10101000L,0x00111000L,0x10111000L, + 0x00101004L,0x10101004L,0x00111004L,0x10111004L, + 0x20101000L,0x30101000L,0x20111000L,0x30111000L, + 0x20101004L,0x30101004L,0x20111004L,0x30111004L, + }, + { /* for D bits (numbered as per FIPS 46) 8 9 11 12 13 14 */ + 0x00000000L,0x08000000L,0x00000008L,0x08000008L, + 0x00000400L,0x08000400L,0x00000408L,0x08000408L, + 0x00020000L,0x08020000L,0x00020008L,0x08020008L, + 0x00020400L,0x08020400L,0x00020408L,0x08020408L, + 0x00000001L,0x08000001L,0x00000009L,0x08000009L, + 0x00000401L,0x08000401L,0x00000409L,0x08000409L, + 0x00020001L,0x08020001L,0x00020009L,0x08020009L, + 0x00020401L,0x08020401L,0x00020409L,0x08020409L, + 0x02000000L,0x0A000000L,0x02000008L,0x0A000008L, + 0x02000400L,0x0A000400L,0x02000408L,0x0A000408L, + 0x02020000L,0x0A020000L,0x02020008L,0x0A020008L, + 0x02020400L,0x0A020400L,0x02020408L,0x0A020408L, + 0x02000001L,0x0A000001L,0x02000009L,0x0A000009L, + 0x02000401L,0x0A000401L,0x02000409L,0x0A000409L, + 0x02020001L,0x0A020001L,0x02020009L,0x0A020009L, + 0x02020401L,0x0A020401L,0x02020409L,0x0A020409L, + }, + { /* for D bits (numbered as per FIPS 46) 16 17 18 19 20 21 */ + 0x00000000L,0x00000100L,0x00080000L,0x00080100L, + 0x01000000L,0x01000100L,0x01080000L,0x01080100L, + 0x00000010L,0x00000110L,0x00080010L,0x00080110L, + 0x01000010L,0x01000110L,0x01080010L,0x01080110L, + 0x00200000L,0x00200100L,0x00280000L,0x00280100L, + 0x01200000L,0x01200100L,0x01280000L,0x01280100L, + 0x00200010L,0x00200110L,0x00280010L,0x00280110L, + 0x01200010L,0x01200110L,0x01280010L,0x01280110L, + 0x00000200L,0x00000300L,0x00080200L,0x00080300L, + 0x01000200L,0x01000300L,0x01080200L,0x01080300L, + 0x00000210L,0x00000310L,0x00080210L,0x00080310L, + 0x01000210L,0x01000310L,0x01080210L,0x01080310L, + 0x00200200L,0x00200300L,0x00280200L,0x00280300L, + 0x01200200L,0x01200300L,0x01280200L,0x01280300L, + 0x00200210L,0x00200310L,0x00280210L,0x00280310L, + 0x01200210L,0x01200310L,0x01280210L,0x01280310L, + }, + { /* for D bits (numbered as per FIPS 46) 22 23 24 25 27 28 */ + 0x00000000L,0x04000000L,0x00040000L,0x04040000L, + 0x00000002L,0x04000002L,0x00040002L,0x04040002L, + 0x00002000L,0x04002000L,0x00042000L,0x04042000L, + 0x00002002L,0x04002002L,0x00042002L,0x04042002L, + 0x00000020L,0x04000020L,0x00040020L,0x04040020L, + 0x00000022L,0x04000022L,0x00040022L,0x04040022L, + 0x00002020L,0x04002020L,0x00042020L,0x04042020L, + 0x00002022L,0x04002022L,0x00042022L,0x04042022L, + 0x00000800L,0x04000800L,0x00040800L,0x04040800L, + 0x00000802L,0x04000802L,0x00040802L,0x04040802L, + 0x00002800L,0x04002800L,0x00042800L,0x04042800L, + 0x00002802L,0x04002802L,0x00042802L,0x04042802L, + 0x00000820L,0x04000820L,0x00040820L,0x04040820L, + 0x00000822L,0x04000822L,0x00040822L,0x04040822L, + 0x00002820L,0x04002820L,0x00042820L,0x04042820L, + 0x00002822L,0x04002822L,0x00042822L,0x04042822L, + } +}; + +const DES_LONG des_SPtrans[8][64]={ + { + /* nibble 0 */ + 0x02080800L, 0x00080000L, 0x02000002L, 0x02080802L, + 0x02000000L, 0x00080802L, 0x00080002L, 0x02000002L, + 0x00080802L, 0x02080800L, 0x02080000L, 0x00000802L, + 0x02000802L, 0x02000000L, 0x00000000L, 0x00080002L, + 0x00080000L, 0x00000002L, 0x02000800L, 0x00080800L, + 0x02080802L, 0x02080000L, 0x00000802L, 0x02000800L, + 0x00000002L, 0x00000800L, 0x00080800L, 0x02080002L, + 0x00000800L, 0x02000802L, 0x02080002L, 0x00000000L, + 0x00000000L, 0x02080802L, 0x02000800L, 0x00080002L, + 0x02080800L, 0x00080000L, 0x00000802L, 0x02000800L, + 0x02080002L, 0x00000800L, 0x00080800L, 0x02000002L, + 0x00080802L, 0x00000002L, 0x02000002L, 0x02080000L, + 0x02080802L, 0x00080800L, 0x02080000L, 0x02000802L, + 0x02000000L, 0x00000802L, 0x00080002L, 0x00000000L, + 0x00080000L, 0x02000000L, 0x02000802L, 0x02080800L, + 0x00000002L, 0x02080002L, 0x00000800L, 0x00080802L, + }, + { /* nibble 1 */ + 0x40108010L, 0x00000000L, 0x00108000L, 0x40100000L, + 0x40000010L, 0x00008010L, 0x40008000L, 0x00108000L, + 0x00008000L, 0x40100010L, 0x00000010L, 0x40008000L, + 0x00100010L, 0x40108000L, 0x40100000L, 0x00000010L, + 0x00100000L, 0x40008010L, 0x40100010L, 0x00008000L, + 0x00108010L, 0x40000000L, 0x00000000L, 0x00100010L, + 0x40008010L, 0x00108010L, 0x40108000L, 0x40000010L, + 0x40000000L, 0x00100000L, 0x00008010L, 0x40108010L, + 0x00100010L, 0x40108000L, 0x40008000L, 0x00108010L, + 0x40108010L, 0x00100010L, 0x40000010L, 0x00000000L, + 0x40000000L, 0x00008010L, 0x00100000L, 0x40100010L, + 0x00008000L, 0x40000000L, 0x00108010L, 0x40008010L, + 0x40108000L, 0x00008000L, 0x00000000L, 0x40000010L, + 0x00000010L, 0x40108010L, 0x00108000L, 0x40100000L, + 0x40100010L, 0x00100000L, 0x00008010L, 0x40008000L, + 0x40008010L, 0x00000010L, 0x40100000L, 0x00108000L, + }, + { /* nibble 2 */ + 0x04000001L, 0x04040100L, 0x00000100L, 0x04000101L, + 0x00040001L, 0x04000000L, 0x04000101L, 0x00040100L, + 0x04000100L, 0x00040000L, 0x04040000L, 0x00000001L, + 0x04040101L, 0x00000101L, 0x00000001L, 0x04040001L, + 0x00000000L, 0x00040001L, 0x04040100L, 0x00000100L, + 0x00000101L, 0x04040101L, 0x00040000L, 0x04000001L, + 0x04040001L, 0x04000100L, 0x00040101L, 0x04040000L, + 0x00040100L, 0x00000000L, 0x04000000L, 0x00040101L, + 0x04040100L, 0x00000100L, 0x00000001L, 0x00040000L, + 0x00000101L, 0x00040001L, 0x04040000L, 0x04000101L, + 0x00000000L, 0x04040100L, 0x00040100L, 0x04040001L, + 0x00040001L, 0x04000000L, 0x04040101L, 0x00000001L, + 0x00040101L, 0x04000001L, 0x04000000L, 0x04040101L, + 0x00040000L, 0x04000100L, 0x04000101L, 0x00040100L, + 0x04000100L, 0x00000000L, 0x04040001L, 0x00000101L, + 0x04000001L, 0x00040101L, 0x00000100L, 0x04040000L, + }, + { /* nibble 3 */ + 0x00401008L, 0x10001000L, 0x00000008L, 0x10401008L, + 0x00000000L, 0x10400000L, 0x10001008L, 0x00400008L, + 0x10401000L, 0x10000008L, 0x10000000L, 0x00001008L, + 0x10000008L, 0x00401008L, 0x00400000L, 0x10000000L, + 0x10400008L, 0x00401000L, 0x00001000L, 0x00000008L, + 0x00401000L, 0x10001008L, 0x10400000L, 0x00001000L, + 0x00001008L, 0x00000000L, 0x00400008L, 0x10401000L, + 0x10001000L, 0x10400008L, 0x10401008L, 0x00400000L, + 0x10400008L, 0x00001008L, 0x00400000L, 0x10000008L, + 0x00401000L, 0x10001000L, 0x00000008L, 0x10400000L, + 0x10001008L, 0x00000000L, 0x00001000L, 0x00400008L, + 0x00000000L, 0x10400008L, 0x10401000L, 0x00001000L, + 0x10000000L, 0x10401008L, 0x00401008L, 0x00400000L, + 0x10401008L, 0x00000008L, 0x10001000L, 0x00401008L, + 0x00400008L, 0x00401000L, 0x10400000L, 0x10001008L, + 0x00001008L, 0x10000000L, 0x10000008L, 0x10401000L, + }, + { /* nibble 4 */ + 0x08000000L, 0x00010000L, 0x00000400L, 0x08010420L, + 0x08010020L, 0x08000400L, 0x00010420L, 0x08010000L, + 0x00010000L, 0x00000020L, 0x08000020L, 0x00010400L, + 0x08000420L, 0x08010020L, 0x08010400L, 0x00000000L, + 0x00010400L, 0x08000000L, 0x00010020L, 0x00000420L, + 0x08000400L, 0x00010420L, 0x00000000L, 0x08000020L, + 0x00000020L, 0x08000420L, 0x08010420L, 0x00010020L, + 0x08010000L, 0x00000400L, 0x00000420L, 0x08010400L, + 0x08010400L, 0x08000420L, 0x00010020L, 0x08010000L, + 0x00010000L, 0x00000020L, 0x08000020L, 0x08000400L, + 0x08000000L, 0x00010400L, 0x08010420L, 0x00000000L, + 0x00010420L, 0x08000000L, 0x00000400L, 0x00010020L, + 0x08000420L, 0x00000400L, 0x00000000L, 0x08010420L, + 0x08010020L, 0x08010400L, 0x00000420L, 0x00010000L, + 0x00010400L, 0x08010020L, 0x08000400L, 0x00000420L, + 0x00000020L, 0x00010420L, 0x08010000L, 0x08000020L, + }, + { /* nibble 5 */ + 0x80000040L, 0x00200040L, 0x00000000L, 0x80202000L, + 0x00200040L, 0x00002000L, 0x80002040L, 0x00200000L, + 0x00002040L, 0x80202040L, 0x00202000L, 0x80000000L, + 0x80002000L, 0x80000040L, 0x80200000L, 0x00202040L, + 0x00200000L, 0x80002040L, 0x80200040L, 0x00000000L, + 0x00002000L, 0x00000040L, 0x80202000L, 0x80200040L, + 0x80202040L, 0x80200000L, 0x80000000L, 0x00002040L, + 0x00000040L, 0x00202000L, 0x00202040L, 0x80002000L, + 0x00002040L, 0x80000000L, 0x80002000L, 0x00202040L, + 0x80202000L, 0x00200040L, 0x00000000L, 0x80002000L, + 0x80000000L, 0x00002000L, 0x80200040L, 0x00200000L, + 0x00200040L, 0x80202040L, 0x00202000L, 0x00000040L, + 0x80202040L, 0x00202000L, 0x00200000L, 0x80002040L, + 0x80000040L, 0x80200000L, 0x00202040L, 0x00000000L, + 0x00002000L, 0x80000040L, 0x80002040L, 0x80202000L, + 0x80200000L, 0x00002040L, 0x00000040L, 0x80200040L, + }, + { /* nibble 6 */ + 0x00004000L, 0x00000200L, 0x01000200L, 0x01000004L, + 0x01004204L, 0x00004004L, 0x00004200L, 0x00000000L, + 0x01000000L, 0x01000204L, 0x00000204L, 0x01004000L, + 0x00000004L, 0x01004200L, 0x01004000L, 0x00000204L, + 0x01000204L, 0x00004000L, 0x00004004L, 0x01004204L, + 0x00000000L, 0x01000200L, 0x01000004L, 0x00004200L, + 0x01004004L, 0x00004204L, 0x01004200L, 0x00000004L, + 0x00004204L, 0x01004004L, 0x00000200L, 0x01000000L, + 0x00004204L, 0x01004000L, 0x01004004L, 0x00000204L, + 0x00004000L, 0x00000200L, 0x01000000L, 0x01004004L, + 0x01000204L, 0x00004204L, 0x00004200L, 0x00000000L, + 0x00000200L, 0x01000004L, 0x00000004L, 0x01000200L, + 0x00000000L, 0x01000204L, 0x01000200L, 0x00004200L, + 0x00000204L, 0x00004000L, 0x01004204L, 0x01000000L, + 0x01004200L, 0x00000004L, 0x00004004L, 0x01004204L, + 0x01000004L, 0x01004200L, 0x01004000L, 0x00004004L, + }, + { /* nibble 7 */ + 0x20800080L, 0x20820000L, 0x00020080L, 0x00000000L, + 0x20020000L, 0x00800080L, 0x20800000L, 0x20820080L, + 0x00000080L, 0x20000000L, 0x00820000L, 0x00020080L, + 0x00820080L, 0x20020080L, 0x20000080L, 0x20800000L, + 0x00020000L, 0x00820080L, 0x00800080L, 0x20020000L, + 0x20820080L, 0x20000080L, 0x00000000L, 0x00820000L, + 0x20000000L, 0x00800000L, 0x20020080L, 0x20800080L, + 0x00800000L, 0x00020000L, 0x20820000L, 0x00000080L, + 0x00800000L, 0x00020000L, 0x20000080L, 0x20820080L, + 0x00020080L, 0x20000000L, 0x00000000L, 0x00820000L, + 0x20800080L, 0x20020080L, 0x20020000L, 0x00800080L, + 0x20820000L, 0x00000080L, 0x00800080L, 0x20020000L, + 0x20820080L, 0x00800000L, 0x20800000L, 0x20000080L, + 0x00820000L, 0x00020080L, 0x20020080L, 0x20800000L, + 0x00000080L, 0x20820000L, 0x00820080L, 0x00000000L, + 0x20000000L, 0x20800080L, 0x00020000L, 0x00820080L, + } +}; + +#define HPERM_OP(a,t,n,m) ((t)=((((a)<<(16-(n)))^(a))&(m)),\ + (a)=(a)^(t)^(t>>(16-(n)))) + +static const unsigned char odd_parity[256]={ + 1, 1, 2, 2, 4, 4, 7, 7, 8, 8, 11, 11, 13, 13, 14, 14, + 16, 16, 19, 19, 21, 21, 22, 22, 25, 25, 26, 26, 28, 28, 31, 31, + 32, 32, 35, 35, 37, 37, 38, 38, 41, 41, 42, 42, 44, 44, 47, 47, + 49, 49, 50, 50, 52, 52, 55, 55, 56, 56, 59, 59, 61, 61, 62, 62, + 64, 64, 67, 67, 69, 69, 70, 70, 73, 73, 74, 74, 76, 76, 79, 79, + 81, 81, 82, 82, 84, 84, 87, 87, 88, 88, 91, 91, 93, 93, 94, 94, + 97, 97, 98, 98,100,100,103,103,104,104,107,107,109,109,110,110, + 112,112,115,115,117,117,118,118,121,121,122,122,124,124,127,127, + 128,128,131,131,133,133,134,134,137,137,138,138,140,140,143,143, + 145,145,146,146,148,148,151,151,152,152,155,155,157,157,158,158, + 161,161,162,162,164,164,167,167,168,168,171,171,173,173,174,174, + 176,176,179,179,181,181,182,182,185,185,186,186,188,188,191,191, + 193,193,194,194,196,196,199,199,200,200,203,203,205,205,206,206, + 208,208,211,211,213,213,214,214,217,217,218,218,220,220,223,223, + 224,224,227,227,229,229,230,230,233,233,234,234,236,236,239,239, + 241,241,242,242,244,244,247,247,248,248,251,251,253,253,254,254 +}; + +/** + * Create key schedule for a single DES 64Bit key + */ +static int des_set_key(des_cblock *key, des_key_schedule *schedule) +{ + static int shifts2[16] = {0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,0}; + register DES_LONG c,d,t,s,t2; + register unsigned char *in; + register DES_LONG *k; + register int i; + des_cblock odd; + + for (i = 0; i < sizeof(des_cblock); i++) + { + odd[i] = odd_parity[(*key)[i]]; + } + + k=(DES_LONG *)schedule; + in=(unsigned char *)&odd; + + c2l(in,c); + c2l(in,d); + + /* do PC1 in 60 simple operations */ +/* PERM_OP(d,c,t,4,0x0f0f0f0fL); + HPERM_OP(c,t,-2, 0xcccc0000L); + HPERM_OP(c,t,-1, 0xaaaa0000L); + HPERM_OP(c,t, 8, 0x00ff0000L); + HPERM_OP(c,t,-1, 0xaaaa0000L); + HPERM_OP(d,t,-8, 0xff000000L); + HPERM_OP(d,t, 8, 0x00ff0000L); + HPERM_OP(d,t, 2, 0x33330000L); + d=((d&0x00aa00aaL)<<7L)|((d&0x55005500L)>>7L)|(d&0xaa55aa55L); + d=(d>>8)|((c&0xf0000000L)>>4); + c&=0x0fffffffL; */ + + /* I now do it in 47 simple operations :-) + * Thanks to John Fletcher (john_fletcher@lccmail.ocf.llnl.gov) + * for the inspiration. :-) */ + PERM_OP (d,c,t,4,0x0f0f0f0fL); + HPERM_OP(c,t,-2,0xcccc0000L); + HPERM_OP(d,t,-2,0xcccc0000L); + PERM_OP (d,c,t,1,0x55555555L); + PERM_OP (c,d,t,8,0x00ff00ffL); + PERM_OP (d,c,t,1,0x55555555L); + d= (((d&0x000000ffL)<<16L)| (d&0x0000ff00L) | + ((d&0x00ff0000L)>>16L)|((c&0xf0000000L)>>4L)); + c&=0x0fffffffL; + + for (i=0; i>2L)|(c<<26L)); d=((d>>2L)|(d<<26L)); } + else + { c=((c>>1L)|(c<<27L)); d=((d>>1L)|(d<<27L)); } + c&=0x0fffffffL; + d&=0x0fffffffL; + /* could be a few less shifts but I am to lazy at this + * point in time to investigate */ + s= des_skb[0][ (c )&0x3f ]| + des_skb[1][((c>> 6)&0x03)|((c>> 7L)&0x3c)]| + des_skb[2][((c>>13)&0x0f)|((c>>14L)&0x30)]| + des_skb[3][((c>>20)&0x01)|((c>>21L)&0x06) | + ((c>>22L)&0x38)]; + t= des_skb[4][ (d )&0x3f ]| + des_skb[5][((d>> 7L)&0x03)|((d>> 8L)&0x3c)]| + des_skb[6][ (d>>15L)&0x3f ]| + des_skb[7][((d>>21L)&0x0f)|((d>>22L)&0x30)]; + + /* table contained 0213 4657 */ + t2=((t<<16L)|(s&0x0000ffffL))&0xffffffffL; + *(k++)=ROTATE(t2,30)&0xffffffffL; + + t2=((s>>16L)|(t&0xffff0000L)); + *(k++)=ROTATE(t2,26)&0xffffffffL; + } + return(0); +} + + +static void des_encrypt(DES_LONG *data, des_key_schedule ks, int enc) +{ + register DES_LONG l,r,t,u; +#ifdef DES_PTR + register unsigned char *des_SP=(unsigned char *)des_SPtrans; +#endif +#ifndef DES_UNROLL + register int i; +#endif + register DES_LONG *s; + + r=data[0]; + l=data[1]; + + IP(r,l); + /* Things have been modified so that the initial rotate is + * done outside the loop. This required the + * des_SPtrans values in sp.h to be rotated 1 bit to the right. + * One perl script later and things have a 5% speed up on a sparc2. + * Thanks to Richard Outerbridge <71755.204@CompuServe.COM> + * for pointing this out. */ + /* clear the top bits on machines with 8byte longs */ + /* shift left by 2 */ + r=ROTATE(r,29)&0xffffffffL; + l=ROTATE(l,29)&0xffffffffL; + + s=(DES_LONG *)ks; + /* I don't know if it is worth the effort of loop unrolling the + * inner loop */ + if (enc) + { +#ifdef DES_UNROLL + D_ENCRYPT(l,r, 0); /* 1 */ + D_ENCRYPT(r,l, 2); /* 2 */ + D_ENCRYPT(l,r, 4); /* 3 */ + D_ENCRYPT(r,l, 6); /* 4 */ + D_ENCRYPT(l,r, 8); /* 5 */ + D_ENCRYPT(r,l,10); /* 6 */ + D_ENCRYPT(l,r,12); /* 7 */ + D_ENCRYPT(r,l,14); /* 8 */ + D_ENCRYPT(l,r,16); /* 9 */ + D_ENCRYPT(r,l,18); /* 10 */ + D_ENCRYPT(l,r,20); /* 11 */ + D_ENCRYPT(r,l,22); /* 12 */ + D_ENCRYPT(l,r,24); /* 13 */ + D_ENCRYPT(r,l,26); /* 14 */ + D_ENCRYPT(l,r,28); /* 15 */ + D_ENCRYPT(r,l,30); /* 16 */ +#else + for (i=0; i<32; i+=8) +{ + D_ENCRYPT(l,r,i+0); /* 1 */ + D_ENCRYPT(r,l,i+2); /* 2 */ + D_ENCRYPT(l,r,i+4); /* 3 */ + D_ENCRYPT(r,l,i+6); /* 4 */ +} +#endif + } + else +{ +#ifdef DES_UNROLL + D_ENCRYPT(l,r,30); /* 16 */ + D_ENCRYPT(r,l,28); /* 15 */ + D_ENCRYPT(l,r,26); /* 14 */ + D_ENCRYPT(r,l,24); /* 13 */ + D_ENCRYPT(l,r,22); /* 12 */ + D_ENCRYPT(r,l,20); /* 11 */ + D_ENCRYPT(l,r,18); /* 10 */ + D_ENCRYPT(r,l,16); /* 9 */ + D_ENCRYPT(l,r,14); /* 8 */ + D_ENCRYPT(r,l,12); /* 7 */ + D_ENCRYPT(l,r,10); /* 6 */ + D_ENCRYPT(r,l, 8); /* 5 */ + D_ENCRYPT(l,r, 6); /* 4 */ + D_ENCRYPT(r,l, 4); /* 3 */ + D_ENCRYPT(l,r, 2); /* 2 */ + D_ENCRYPT(r,l, 0); /* 1 */ +#else + for (i=30; i>0; i-=8) +{ + D_ENCRYPT(l,r,i-0); /* 16 */ + D_ENCRYPT(r,l,i-2); /* 15 */ + D_ENCRYPT(l,r,i-4); /* 14 */ + D_ENCRYPT(r,l,i-6); /* 13 */ +} +#endif +} + + /* rotate and clear the top bits on machines with 8byte longs */ + l=ROTATE(l,3)&0xffffffffL; + r=ROTATE(r,3)&0xffffffffL; + + FP(r,l); + data[0]=l; + data[1]=r; + l=r=t=u=0; +} + +/** + * DES CBC encrypt decrypt routine + */ +static void des_cbc_encrypt(des_cblock *input, des_cblock *output, long length, + des_key_schedule schedule, des_cblock *ivec, int enc) +{ + register DES_LONG tin0,tin1; + register DES_LONG tout0,tout1,xor0,xor1; + register unsigned char *in,*out; + register long l=length; + DES_LONG tin[2]; + unsigned char *iv; + + in=(unsigned char *)input; + out=(unsigned char *)output; + iv=(unsigned char *)ivec; + + if (enc) + { + c2l(iv,tout0); + c2l(iv,tout1); + for (l-=8; l>=0; l-=8) + { + c2l(in,tin0); + c2l(in,tin1); + tin0^=tout0; tin[0]=tin0; + tin1^=tout1; tin[1]=tin1; + des_encrypt((DES_LONG *)tin,schedule,DES_ENCRYPT); + tout0=tin[0]; l2c(tout0,out); + tout1=tin[1]; l2c(tout1,out); + } + if (l != -8) + { + c2ln(in,tin0,tin1,l+8); + tin0^=tout0; tin[0]=tin0; + tin1^=tout1; tin[1]=tin1; + des_encrypt((DES_LONG *)tin,schedule,DES_ENCRYPT); + tout0=tin[0]; l2c(tout0,out); + tout1=tin[1]; l2c(tout1,out); + } + } + else + { + c2l(iv,xor0); + c2l(iv,xor1); + for (l-=8; l>=0; l-=8) + { + c2l(in,tin0); tin[0]=tin0; + c2l(in,tin1); tin[1]=tin1; + des_encrypt((DES_LONG *)tin,schedule,DES_DECRYPT); + tout0=tin[0]^xor0; + tout1=tin[1]^xor1; + l2c(tout0,out); + l2c(tout1,out); + xor0=tin0; + xor1=tin1; + } + if (l != -8) + { + c2l(in,tin0); tin[0]=tin0; + c2l(in,tin1); tin[1]=tin1; + des_encrypt((DES_LONG *)tin,schedule,DES_DECRYPT); + tout0=tin[0]^xor0; + tout1=tin[1]^xor1; + l2cn(tout0,tout1,out,l+8); + /* xor0=tin0; + xor1=tin1; */ + } + } + tin0=tin1=tout0=tout1=xor0=xor1=0; + tin[0]=tin[1]=0; +} + +static void des_encrypt2(DES_LONG *data, des_key_schedule ks, int enc) +{ + register DES_LONG l,r,t,u; +#ifdef DES_PTR + register unsigned char *des_SP=(unsigned char *)des_SPtrans; +#endif +#ifndef DES_UNROLL + register int i; +#endif + register DES_LONG *s; + + r=data[0]; + l=data[1]; + + /* Things have been modified so that the initial rotate is + * done outside the loop. This required the + * des_SPtrans values in sp.h to be rotated 1 bit to the right. + * One perl script later and things have a 5% speed up on a sparc2. + * Thanks to Richard Outerbridge <71755.204@CompuServe.COM> + * for pointing this out. + * clear the top bits on machines with 8byte longs */ + r=ROTATE(r,29)&0xffffffffL; + l=ROTATE(l,29)&0xffffffffL; + + s=(DES_LONG *)ks; + /* I don't know if it is worth the effort of loop unrolling the + * inner loop */ + if (enc) + { +#ifdef DES_UNROLL + D_ENCRYPT(l,r, 0); /* 1 */ + D_ENCRYPT(r,l, 2); /* 2 */ + D_ENCRYPT(l,r, 4); /* 3 */ + D_ENCRYPT(r,l, 6); /* 4 */ + D_ENCRYPT(l,r, 8); /* 5 */ + D_ENCRYPT(r,l,10); /* 6 */ + D_ENCRYPT(l,r,12); /* 7 */ + D_ENCRYPT(r,l,14); /* 8 */ + D_ENCRYPT(l,r,16); /* 9 */ + D_ENCRYPT(r,l,18); /* 10 */ + D_ENCRYPT(l,r,20); /* 11 */ + D_ENCRYPT(r,l,22); /* 12 */ + D_ENCRYPT(l,r,24); /* 13 */ + D_ENCRYPT(r,l,26); /* 14 */ + D_ENCRYPT(l,r,28); /* 15 */ + D_ENCRYPT(r,l,30); /* 16 */ +#else + for (i=0; i<32; i+=8) +{ + D_ENCRYPT(l,r,i+0); /* 1 */ + D_ENCRYPT(r,l,i+2); /* 2 */ + D_ENCRYPT(l,r,i+4); /* 3 */ + D_ENCRYPT(r,l,i+6); /* 4 */ +} +#endif + } + else +{ +#ifdef DES_UNROLL + D_ENCRYPT(l,r,30); /* 16 */ + D_ENCRYPT(r,l,28); /* 15 */ + D_ENCRYPT(l,r,26); /* 14 */ + D_ENCRYPT(r,l,24); /* 13 */ + D_ENCRYPT(l,r,22); /* 12 */ + D_ENCRYPT(r,l,20); /* 11 */ + D_ENCRYPT(l,r,18); /* 10 */ + D_ENCRYPT(r,l,16); /* 9 */ + D_ENCRYPT(l,r,14); /* 8 */ + D_ENCRYPT(r,l,12); /* 7 */ + D_ENCRYPT(l,r,10); /* 6 */ + D_ENCRYPT(r,l, 8); /* 5 */ + D_ENCRYPT(l,r, 6); /* 4 */ + D_ENCRYPT(r,l, 4); /* 3 */ + D_ENCRYPT(l,r, 2); /* 2 */ + D_ENCRYPT(r,l, 0); /* 1 */ +#else + for (i=30; i>0; i-=8) +{ + D_ENCRYPT(l,r,i-0); /* 16 */ + D_ENCRYPT(r,l,i-2); /* 15 */ + D_ENCRYPT(l,r,i-4); /* 14 */ + D_ENCRYPT(r,l,i-6); /* 13 */ +} +#endif +} + /* rotate and clear the top bits on machines with 8byte longs */ + data[0]=ROTATE(l,3)&0xffffffffL; + data[1]=ROTATE(r,3)&0xffffffffL; + l=r=t=u=0; +} + +/** + * Single block 3DES EDE encrypt routine + */ +static void des_encrypt3(DES_LONG *data, des_key_schedule ks1, + des_key_schedule ks2, des_key_schedule ks3) +{ + register DES_LONG l,r; + + l=data[0]; + r=data[1]; + IP(l,r); + data[0]=l; + data[1]=r; + des_encrypt2((DES_LONG *)data,ks1,DES_ENCRYPT); + des_encrypt2((DES_LONG *)data,ks2,DES_DECRYPT); + des_encrypt2((DES_LONG *)data,ks3,DES_ENCRYPT); + l=data[0]; + r=data[1]; + FP(r,l); + data[0]=l; + data[1]=r; +} + +/** + * Single block 3DES EDE decrypt routine + */ +static void des_decrypt3(DES_LONG *data, des_key_schedule ks1, + des_key_schedule ks2, des_key_schedule ks3) +{ + register DES_LONG l,r; + + l=data[0]; + r=data[1]; + IP(l,r); + data[0]=l; + data[1]=r; + des_encrypt2((DES_LONG *)data,ks3,DES_DECRYPT); + des_encrypt2((DES_LONG *)data,ks2,DES_ENCRYPT); + des_encrypt2((DES_LONG *)data,ks1,DES_DECRYPT); + l=data[0]; + r=data[1]; + FP(r,l); + data[0]=l; + data[1]=r; +} + +/** + * 3DES EDE CBC encrypt/decrypt routine + */ +static void des_ede3_cbc_encrypt(des_cblock *input, des_cblock *output, long length, + des_key_schedule ks1, des_key_schedule ks2, + des_key_schedule ks3, des_cblock *ivec, int enc) +{ + register DES_LONG tin0,tin1; + register DES_LONG tout0,tout1,xor0,xor1; + register unsigned char *in,*out; + register long l=length; + DES_LONG tin[2]; + unsigned char *iv; + + in=(unsigned char *)input; + out=(unsigned char *)output; + iv=(unsigned char *)ivec; + + if (enc) + { + c2l(iv,tout0); + c2l(iv,tout1); + for (l-=8; l>=0; l-=8) + { + c2l(in,tin0); + c2l(in,tin1); + tin0^=tout0; + tin1^=tout1; + + tin[0]=tin0; + tin[1]=tin1; + des_encrypt3((DES_LONG *)tin,ks1,ks2,ks3); + tout0=tin[0]; + tout1=tin[1]; + + l2c(tout0,out); + l2c(tout1,out); + } + if (l != -8) + { + c2ln(in,tin0,tin1,l+8); + tin0^=tout0; + tin1^=tout1; + + tin[0]=tin0; + tin[1]=tin1; + des_encrypt3((DES_LONG *)tin,ks1,ks2,ks3); + tout0=tin[0]; + tout1=tin[1]; + + l2c(tout0,out); + l2c(tout1,out); + } + iv=(unsigned char *)ivec; + l2c(tout0,iv); + l2c(tout1,iv); + } + else + { + register DES_LONG t0,t1; + + c2l(iv,xor0); + c2l(iv,xor1); + for (l-=8; l>=0; l-=8) + { + c2l(in,tin0); + c2l(in,tin1); + + t0=tin0; + t1=tin1; + + tin[0]=tin0; + tin[1]=tin1; + des_decrypt3((DES_LONG *)tin,ks1,ks2,ks3); + tout0=tin[0]; + tout1=tin[1]; + + tout0^=xor0; + tout1^=xor1; + l2c(tout0,out); + l2c(tout1,out); + xor0=t0; + xor1=t1; + } + if (l != -8) + { + c2l(in,tin0); + c2l(in,tin1); + + t0=tin0; + t1=tin1; + + tin[0]=tin0; + tin[1]=tin1; + des_decrypt3((DES_LONG *)tin,ks1,ks2,ks3); + tout0=tin[0]; + tout1=tin[1]; + + tout0^=xor0; + tout1^=xor1; + l2cn(tout0,tout1,out,l+8); + xor0=t0; + xor1=t1; + } + + iv=(unsigned char *)ivec; + l2c(xor0,iv); + l2c(xor1,iv); + } + tin0=tin1=tout0=tout1=xor0=xor1=0; + tin[0]=tin[1]=0; +} + +/** + * Implementation of crypter_t.decrypt for DES. + */ +static status_t decrypt(private_des_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *decrypted) +{ + des_cblock ivb; + + if (data.len % sizeof(des_cblock) != 0 || + iv.len != sizeof(des_cblock)) + { + return INVALID_ARG; + } + + *decrypted = chunk_alloc(data.len); + memcpy(&ivb, iv.ptr, sizeof(des_cblock)); + des_cbc_encrypt((des_cblock*)(data.ptr), (des_cblock*)(decrypted->ptr), + data.len, this->ks, &ivb, DES_DECRYPT); + return SUCCESS; +} + + +/** + * Implementation of crypter_t.decrypt for DES. + */ +static status_t encrypt(private_des_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *encrypted) +{ + des_cblock ivb; + + if (data.len % sizeof(des_cblock) != 0 || + iv.len != sizeof(des_cblock)) + { + return INVALID_ARG; + } + + *encrypted = chunk_alloc(data.len); + memcpy(&ivb, iv.ptr, sizeof(des_cblock)); + des_cbc_encrypt((des_cblock*)(data.ptr), (des_cblock*)(encrypted->ptr), + data.len, this->ks, &ivb, DES_ENCRYPT); + return SUCCESS; +} + +/** + * Implementation of crypter_t.decrypt for 3DES. + */ +static status_t decrypt3(private_des_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *decrypted) +{ + des_cblock ivb; + + if (data.len % sizeof(des_cblock) != 0 || + iv.len != sizeof(des_cblock)) + { + return INVALID_ARG; + } + + *decrypted = chunk_alloc(data.len); + memcpy(&ivb, iv.ptr, sizeof(des_cblock)); + des_ede3_cbc_encrypt((des_cblock*)(data.ptr), (des_cblock*)(decrypted->ptr), + data.len, this->ks3[0], this->ks3[1], this->ks3[2], + &ivb, DES_DECRYPT); + return SUCCESS; +} + +/** + * Implementation of crypter_t.decrypt for 3DES. + */ +static status_t encrypt3(private_des_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *encrypted) +{ + des_cblock ivb; + + if (data.len % sizeof(des_cblock) != 0 || + iv.len != sizeof(des_cblock)) + { + return INVALID_ARG; + } + + *encrypted = chunk_alloc(data.len); + memcpy(&ivb, iv.ptr, sizeof(des_cblock)); + des_ede3_cbc_encrypt((des_cblock*)(data.ptr), (des_cblock*)(encrypted->ptr), + data.len, this->ks3[0], this->ks3[1], this->ks3[2], + &ivb, DES_ENCRYPT); + return SUCCESS; +} + +/** + * Implementation of crypter_t.get_block_size. + */ +static size_t get_block_size (private_des_crypter_t *this) +{ + return sizeof(des_cblock); +} + +/** + * Implementation of crypter_t.get_key_size. + */ +static size_t get_key_size (private_des_crypter_t *this) +{ + return this->key_size; +} + +/** + * Implementation of crypter_t.set_key for DES. + */ +static status_t set_key(private_des_crypter_t *this, chunk_t key) +{ + if (key.len != sizeof(des_cblock)) + { + return INVALID_ARG; + } + + des_set_key((des_cblock*)(key.ptr), &this->ks); + + return SUCCESS; +} + +/** + * Implementation of crypter_t.set_key for 3DES. + */ +static status_t set_key3(private_des_crypter_t *this, chunk_t key) +{ + if (key.len != 3 * sizeof(des_cblock)) + { + return INVALID_ARG; + } + + des_set_key((des_cblock*)(key.ptr) + 0, &this->ks3[0]); + des_set_key((des_cblock*)(key.ptr) + 1, &this->ks3[1]); + des_set_key((des_cblock*)(key.ptr) + 2, &this->ks3[2]); + + return SUCCESS; +} + +/** + * Implementation of crypter_t.destroy and des_crypter_t.destroy. + */ +static void destroy(private_des_crypter_t *this) +{ + free(this); +} + +/* + * Described in header + */ +des_crypter_t *des_crypter_create(encryption_algorithm_t algo) +{ + private_des_crypter_t *this = malloc_thing(private_des_crypter_t); + + /* functions of crypter_t interface */ + this->public.crypter_interface.get_block_size = (size_t (*) (crypter_t *)) get_block_size; + this->public.crypter_interface.get_key_size = (size_t (*) (crypter_t *)) get_key_size; + this->public.crypter_interface.destroy = (void (*) (crypter_t *)) destroy; + + /* use functions depending on algorithm */ + switch (algo) + { + case ENCR_DES: + this->key_size = sizeof(des_cblock); + this->public.crypter_interface.set_key = (status_t (*) (crypter_t *,chunk_t)) set_key; + this->public.crypter_interface.encrypt = (status_t (*) (crypter_t *, chunk_t,chunk_t, chunk_t *)) encrypt; + this->public.crypter_interface.decrypt = (status_t (*) (crypter_t *, chunk_t , chunk_t, chunk_t *)) decrypt; + break; + case ENCR_3DES: + this->key_size = 3 * sizeof(des_cblock); + this->public.crypter_interface.set_key = (status_t (*) (crypter_t *,chunk_t)) set_key3; + this->public.crypter_interface.encrypt = (status_t (*) (crypter_t *, chunk_t,chunk_t, chunk_t *)) encrypt3; + this->public.crypter_interface.decrypt = (status_t (*) (crypter_t *, chunk_t , chunk_t, chunk_t *)) decrypt3; + break; + default: + free(this); + return NULL; + } + return &(this->public); +} diff --git a/src/libstrongswan/plugins/des/des_crypter.h b/src/libstrongswan/plugins/des/des_crypter.h new file mode 100644 index 000000000..d40d9cf2f --- /dev/null +++ b/src/libstrongswan/plugins/des/des_crypter.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2006-2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 des_crypter des_crypter + * @{ @ingroup des_p + */ + +#ifndef DES_CRYPTER_H_ +#define DES_CRYPTER_H_ + +typedef struct des_crypter_t des_crypter_t; + +#include + + +/** + * Class implementing the DES and 3DES encryption algorithms. + */ +struct des_crypter_t { + + /** + * The crypter_t interface. + */ + crypter_t crypter_interface; +}; + +/** + * Constructor to create des_crypter_t objects. + * + * @param algo ENCR_DES for single DES, ENCR_3DES for triple DES + * @return des_crypter_t object, NULL if algo not supported + */ +des_crypter_t *des_crypter_create(encryption_algorithm_t algo); + + +#endif /* DES_CRYPTER_H_ @}*/ diff --git a/src/libstrongswan/plugins/des/des_plugin.c b/src/libstrongswan/plugins/des/des_plugin.c new file mode 100644 index 000000000..4fb98c1d2 --- /dev/null +++ b/src/libstrongswan/plugins/des/des_plugin.c @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "des_plugin.h" + +#include +#include "des_crypter.h" + +typedef struct private_des_plugin_t private_des_plugin_t; + +/** + * private data of des_plugin + */ +struct private_des_plugin_t { + + /** + * public functions + */ + des_plugin_t public; +}; + +/** + * Implementation of des_plugin_t.destroy + */ +static void destroy(private_des_plugin_t *this) +{ + lib->crypto->remove_crypter(lib->crypto, + (crypter_constructor_t)des_crypter_create); + free(this); +} + +/* + * see header file + */ +plugin_t *plugin_create() +{ + private_des_plugin_t *this = malloc_thing(private_des_plugin_t); + + this->public.plugin.destroy = (void(*)(plugin_t*))destroy; + + lib->crypto->add_crypter(lib->crypto, ENCR_DES, + (crypter_constructor_t)des_crypter_create); + lib->crypto->add_crypter(lib->crypto, ENCR_3DES, + (crypter_constructor_t)des_crypter_create); + + return &this->public.plugin; +} + diff --git a/src/libstrongswan/plugins/des/des_plugin.h b/src/libstrongswan/plugins/des/des_plugin.h new file mode 100644 index 000000000..8cabd082b --- /dev/null +++ b/src/libstrongswan/plugins/des/des_plugin.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 des_p des + * @ingroup plugins + * + * @defgroup des_plugin des_plugin + * @{ @ingroup des_p + */ + +#ifndef DES_PLUGIN_H_ +#define DES_PLUGIN_H_ + +#include + +typedef struct des_plugin_t des_plugin_t; + +/** + * Plugin implementing DES based algorithms in software. + */ +struct des_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +/** + * Create a des_plugin instance. + */ +plugin_t *plugin_create(); + +#endif /* DES_PLUGIN_H_ @}*/ diff --git a/src/libstrongswan/plugins/fips_prf/Makefile.am b/src/libstrongswan/plugins/fips_prf/Makefile.am new file mode 100644 index 000000000..73f28825a --- /dev/null +++ b/src/libstrongswan/plugins/fips_prf/Makefile.am @@ -0,0 +1,10 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan + +AM_CFLAGS = -rdynamic + +plugin_LTLIBRARIES = libstrongswan-fips-prf.la + +libstrongswan_fips_prf_la_SOURCES = fips_prf_plugin.h fips_prf_plugin.c fips_prf.c fips_prf.h +libstrongswan_fips_prf_la_LDFLAGS = -module + diff --git a/src/libstrongswan/plugins/fips_prf/fips_prf.c b/src/libstrongswan/plugins/fips_prf/fips_prf.c new file mode 100644 index 000000000..20b752e30 --- /dev/null +++ b/src/libstrongswan/plugins/fips_prf/fips_prf.c @@ -0,0 +1,261 @@ +/* + * Copyright (C) 2006 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "fips_prf.h" + +#include + +#include + +typedef struct private_fips_prf_t private_fips_prf_t; + +/** + * Private data of a fips_prf_t object. + */ +struct private_fips_prf_t { + /** + * Public fips_prf_t interface. + */ + fips_prf_t public; + + /** + * key of prf function, "b" long + */ + u_int8_t *key; + + /** + * size of "b" in bytes + */ + size_t b; + + /** + * associated hasher when using SHA1 mode + */ + hasher_t *hasher; + + /** + * G function, either SHA1 or DES + */ + void (*g)(private_fips_prf_t *this, u_int8_t t[], chunk_t c, u_int8_t res[]); +}; + +/** + * t used in G(), equals to initial SHA1 value + */ +static u_int8_t t[] = { + 0x67,0x45,0x23,0x01,0xEF,0xCD,0xAB,0x89,0x98,0xBA, + 0xDC,0xFE,0x10,0x32,0x54,0x76,0xC3,0xD2,0xE1,0xF0, +}; + + +/** + * sum = (a + b) mod 2 ^ (length * 8) + */ +static void add_mod(size_t length, u_int8_t a[], u_int8_t b[], u_int8_t sum[]) +{ + int i, c = 0; + + for(i = length - 1; i >= 0; i--) + { + u_int32_t tmp; + + tmp = a[i] + b[i] + c; + sum[i] = 0xff & tmp; + c = tmp >> 8; + } +} + +/** + * calculate "chunk mod 2^(length*8)" and save it into buffer + */ +static void chunk_mod(size_t length, chunk_t chunk, u_int8_t buffer[]) +{ + if (chunk.len < length) + { + /* apply seed as least significant bits, others are zero */ + memset(buffer, 0, length - chunk.len); + memcpy(buffer + length - chunk.len, chunk.ptr, chunk.len); + } + else + { + /* use least significant bytes from seed, as we use mod 2^b */ + memcpy(buffer, chunk.ptr + chunk.len - length, length); + } +} + +/** + * Implementation of prf_t.get_bytes. + * + * Test vector: + * + * key: + * 0xbd, 0x02, 0x9b, 0xbe, 0x7f, 0x51, 0x96, 0x0b, + * 0xcf, 0x9e, 0xdb, 0x2b, 0x61, 0xf0, 0x6f, 0x0f, + * 0xeb, 0x5a, 0x38, 0xb6 + * + * seed: + * 0x00 + * + * result: + * 0x20, 0x70, 0xb3, 0x22, 0x3d, 0xba, 0x37, 0x2f, + * 0xde, 0x1c, 0x0f, 0xfc, 0x7b, 0x2e, 0x3b, 0x49, + * 0x8b, 0x26, 0x06, 0x14, 0x3c, 0x6c, 0x18, 0xba, + * 0xcb, 0x0f, 0x6c, 0x55, 0xba, 0xbb, 0x13, 0x78, + * 0x8e, 0x20, 0xd7, 0x37, 0xa3, 0x27, 0x51, 0x16 + */ +static void get_bytes(private_fips_prf_t *this, chunk_t seed, u_int8_t w[]) +{ + int i; + u_int8_t xval[this->b]; + u_int8_t xseed[this->b]; + u_int8_t sum[this->b]; + u_int8_t *xkey = this->key; + u_int8_t one[this->b]; + chunk_t xval_chunk = chunk_from_buf(xval); + + memset(one, 0, this->b); + one[this->b - 1] = 0x01; + + /* 3.1 */ + chunk_mod(this->b, seed, xseed); + + /* 3.2 */ + for (i = 0; i < 2; i++) /* twice */ + { + /* a. XVAL = (XKEY + XSEED j) mod 2^b */ + add_mod(this->b, xkey, xseed, xval); + DBG3("XVAL %b", xval, this->b); + /* b. wi = G(t, XVAL ) */ + this->g(this, t, xval_chunk, &w[i * this->b]); + DBG3("w[%d] %b", i, &w[i * this->b], this->b); + /* c. XKEY = (1 + XKEY + wi) mod 2b */ + add_mod(this->b, xkey, &w[i * this->b], sum); + add_mod(this->b, sum, one, xkey); + DBG3("XKEY %b", xkey, this->b); + } + + /* 3.3 done already, mod q not used */ +} + +/** + * Implementation of prf_t.get_block_size. + */ +static size_t get_block_size(private_fips_prf_t *this) +{ + return 2 * this->b; +} +/** + * Implementation of prf_t.allocate_bytes. + */ +static void allocate_bytes(private_fips_prf_t *this, chunk_t seed, chunk_t *chunk) +{ + *chunk = chunk_alloc(get_block_size(this)); + get_bytes(this, seed, chunk->ptr); +} + +/** + * Implementation of prf_t.get_key_size. + */ +static size_t get_key_size(private_fips_prf_t *this) +{ + return this->b; +} + +/** + * Implementation of prf_t.set_key. + */ +static void set_key(private_fips_prf_t *this, chunk_t key) +{ + /* save key as "key mod 2^b" */ + chunk_mod(this->b, key, this->key); +} + +/** + * Implementation of the G() function based on SHA1 + */ +void g_sha1(private_fips_prf_t *this, u_int8_t t[], chunk_t c, u_int8_t res[]) +{ + u_int8_t buf[64]; + + if (c.len < sizeof(buf)) + { + /* pad c with zeros */ + memset(buf, 0, sizeof(buf)); + memcpy(buf, c.ptr, c.len); + c.ptr = buf; + c.len = sizeof(buf); + } + else + { + /* not more than 512 bits can be G()-ed */ + c.len = sizeof(buf); + } + + /* calculate the special (HASH_SHA1_STATE) hash*/ + this->hasher->get_hash(this->hasher, c, res); +} + +/** + * Implementation of prf_t.destroy. + */ +static void destroy(private_fips_prf_t *this) +{ + this->hasher->destroy(this->hasher); + free(this->key); + free(this); +} + +/* + * Described in header. + */ +fips_prf_t *fips_prf_create(pseudo_random_function_t algo) +{ + private_fips_prf_t *this = malloc_thing(private_fips_prf_t); + + this->public.prf_interface.get_bytes = (void (*) (prf_t *,chunk_t,u_int8_t*))get_bytes; + this->public.prf_interface.allocate_bytes = (void (*) (prf_t*,chunk_t,chunk_t*))allocate_bytes; + this->public.prf_interface.get_block_size = (size_t (*) (prf_t*))get_block_size; + this->public.prf_interface.get_key_size = (size_t (*) (prf_t*))get_key_size; + this->public.prf_interface.set_key = (void (*) (prf_t *,chunk_t))set_key; + this->public.prf_interface.destroy = (void (*) (prf_t *))destroy; + + switch (algo) + { + case PRF_FIPS_SHA1_160: + { + this->g = g_sha1; + this->b = 20; + this->hasher = lib->crypto->create_hasher(lib->crypto, + HASH_SHA1_NOFINAL); + if (this->hasher == NULL) + { + free(this); + return NULL; + } + break; + } + case PRF_FIPS_DES: + /* not implemented yet */ + default: + free(this); + return NULL; + } + this->key = malloc(this->b); + + return &this->public; +} + diff --git a/src/libstrongswan/plugins/fips_prf/fips_prf.h b/src/libstrongswan/plugins/fips_prf/fips_prf.h new file mode 100644 index 000000000..3fead6b9b --- /dev/null +++ b/src/libstrongswan/plugins/fips_prf/fips_prf.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2006-2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 fips_prf fips_prf + * @{ @ingroup fips_prf_p + */ + +#ifndef FIPS_PRF_H_ +#define FIPS_PRF_H_ + +typedef struct fips_prf_t fips_prf_t; + +#include +#include +#include + +/** + * Implementation of prf_t using the FIPS 186-2-change1 standard. + * + * FIPS defines a "General Purpose Random Number Generator" (Revised + * Algorithm for Computing m values of x (Appendix 3.1 of FIPS 186-2)). This + * implementation is not intended for private key generation and therefore does + * not include the "mod q" operation (see FIPS 186-2-change1 p74). + * The FIPS PRF is stateful; the key changes every time when bytes are acquired. + */ +struct fips_prf_t { + + /** + * Generic prf_t interface for this fips_prf_t class. + */ + prf_t prf_interface; +}; + +/** + * Creates a new fips_prf_t object. + * + * FIPS 186-2 defines G() functions used in the PRF function. It can + * be implemented either based on SHA1 or DES. + * The G() function is selected using the algo parameter. + * + * @param algo specific FIPS PRF implementation, specifies G() function + * @return fips_prf_t object, NULL if not supported. + */ +fips_prf_t *fips_prf_create(pseudo_random_function_t algo); + +#endif /* FIPS_PRF_H_ @}*/ diff --git a/src/libstrongswan/plugins/fips_prf/fips_prf_plugin.c b/src/libstrongswan/plugins/fips_prf/fips_prf_plugin.c new file mode 100644 index 000000000..68252932c --- /dev/null +++ b/src/libstrongswan/plugins/fips_prf/fips_prf_plugin.c @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "fips_prf_plugin.h" + +#include +#include "fips_prf.h" + +typedef struct private_fips_prf_plugin_t private_fips_prf_plugin_t; + +/** + * private data of fips_prf_plugin + */ +struct private_fips_prf_plugin_t { + + /** + * public functions + */ + fips_prf_plugin_t public; +}; + +/** + * Implementation of fips_prf_plugin_t.destroy + */ +static void destroy(private_fips_prf_plugin_t *this) +{ + lib->crypto->remove_prf(lib->crypto, + (prf_constructor_t)fips_prf_create); + free(this); +} + +/* + * see header file + */ +plugin_t *plugin_create() +{ + private_fips_prf_plugin_t *this = malloc_thing(private_fips_prf_plugin_t); + + this->public.plugin.destroy = (void(*)(plugin_t*))destroy; + + lib->crypto->add_prf(lib->crypto, PRF_FIPS_SHA1_160, + (prf_constructor_t)fips_prf_create); + + return &this->public.plugin; +} diff --git a/src/libstrongswan/plugins/fips_prf/fips_prf_plugin.h b/src/libstrongswan/plugins/fips_prf/fips_prf_plugin.h new file mode 100644 index 000000000..6816eb66f --- /dev/null +++ b/src/libstrongswan/plugins/fips_prf/fips_prf_plugin.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 fips_prf_p fips_prf + * @ingroup plugins + * + * @defgroup fips_prf_plugin fips_prf_plugin + * @{ @ingroup fips_prf_p + */ + +#ifndef FIPS_PRF_PLUGIN_H_ +#define FIPS_PRF_PLUGIN_H_ + +#include + +typedef struct fips_prf_plugin_t fips_prf_plugin_t; + +/** + * Plugin implementing the fips_prf algorithm in software. + */ +struct fips_prf_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +/** + * Create a fips_prf_plugin instance. + */ +plugin_t *plugin_create(); + +#endif /* FIPS_PRF_PLUGIN_H_ @}*/ diff --git a/src/libstrongswan/plugins/gmp/Makefile.am b/src/libstrongswan/plugins/gmp/Makefile.am new file mode 100644 index 000000000..3d4065c1b --- /dev/null +++ b/src/libstrongswan/plugins/gmp/Makefile.am @@ -0,0 +1,14 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan + +AM_CFLAGS = -rdynamic + +plugin_LTLIBRARIES = libstrongswan-gmp.la + +libstrongswan_gmp_la_SOURCES = gmp_plugin.h gmp_plugin.c \ + gmp_diffie_hellman.c gmp_diffie_hellman.h \ + gmp_rsa_private_key.c gmp_rsa_private_key.h \ + gmp_rsa_public_key.c gmp_rsa_public_key.h +libstrongswan_gmp_la_LDFLAGS = -module +libstrongswan_gmp_la_LIBADD = -lgmp + diff --git a/src/libstrongswan/plugins/gmp/gmp_diffie_hellman.c b/src/libstrongswan/plugins/gmp/gmp_diffie_hellman.c new file mode 100644 index 000000000..349ec419e --- /dev/null +++ b/src/libstrongswan/plugins/gmp/gmp_diffie_hellman.c @@ -0,0 +1,569 @@ +/* + * Copyright (C) 1998-2002 D. Hugh Redelmeier. + * Copyright (C) 1999, 2000, 2001 Henry Spencer. + * Copyright (C) 2005-2008 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include + +#include "gmp_diffie_hellman.h" + +#include +#include + + +/** + * Modulus of Group 1 (MODP_768_BIT). + */ +static u_int8_t group1_modulus[] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x34, + 0xC4,0xC6,0x62,0x8B,0x80 ,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74, + 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 +}; + +/** + * Modulus of Group 2 (MODP_1024_BIT). + */ +static u_int8_t group2_modulus[] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x34, + 0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74, + 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,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 +}; + +/** + * Modulus of Group 5 (MODP_1536_BIT). + */ +static u_int8_t group5_modulus[] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x34, + 0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74, + 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,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,0xE4,0x5B,0x3D,0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05, + 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 +}; +/** + * Modulus of Group 14 (MODP_2048_BIT). + */ +static u_int8_t group14_modulus[] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x34, + 0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74, + 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,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,0xE4,0x5B,0x3D,0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05, + 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,0x18,0x21,0x7C,0x32,0x90,0x5E,0x46,0x2E,0x36,0xCE,0x3B, + 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 +}; + +/** + * Modulus of Group 15 (MODP_3072_BIT). + */ +static u_int8_t group15_modulus[] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x34, + 0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74, + 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,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,0xE4,0x5B,0x3D,0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05, + 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,0x18,0x21,0x7C,0x32,0x90,0x5E,0x46,0x2E,0x36,0xCE,0x3B, + 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,0xAA,0xC4,0x2D,0xAD,0x33,0x17,0x0D,0x04,0x50,0x7A,0x33, + 0xA8,0x55,0x21,0xAB,0xDF,0x1C,0xBA,0x64,0xEC,0xFB,0x85,0x04,0x58,0xDB,0xEF,0x0A, + 0x8A,0xEA,0x71,0x57,0x5D,0x06,0x0C,0x7D,0xB3,0x97,0x0F,0x85,0xA6,0xE1,0xE4,0xC7, + 0xAB,0xF5,0xAE,0x8C,0xDB,0x09,0x33,0xD7,0x1E,0x8C,0x94,0xE0,0x4A,0x25,0x61,0x9D, + 0xCE,0xE3,0xD2,0x26,0x1A,0xD2,0xEE,0x6B,0xF1,0x2F,0xFA,0x06,0xD9,0x8A,0x08,0x64, + 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 +}; + +/** + * Modulus of Group 16 (MODP_4096_BIT). + */ +static u_int8_t group16_modulus[] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x34, + 0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74, + 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,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,0xE4,0x5B,0x3D,0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05, + 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,0x18,0x21,0x7C,0x32,0x90,0x5E,0x46,0x2E,0x36,0xCE,0x3B, + 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,0xAA,0xC4,0x2D,0xAD,0x33,0x17,0x0D,0x04,0x50,0x7A,0x33, + 0xA8,0x55,0x21,0xAB,0xDF,0x1C,0xBA,0x64,0xEC,0xFB,0x85,0x04,0x58,0xDB,0xEF,0x0A, + 0x8A,0xEA,0x71,0x57,0x5D,0x06,0x0C,0x7D,0xB3,0x97,0x0F,0x85,0xA6,0xE1,0xE4,0xC7, + 0xAB,0xF5,0xAE,0x8C,0xDB,0x09,0x33,0xD7,0x1E,0x8C,0x94,0xE0,0x4A,0x25,0x61,0x9D, + 0xCE,0xE3,0xD2,0x26,0x1A,0xD2,0xEE,0x6B,0xF1,0x2F,0xFA,0x06,0xD9,0x8A,0x08,0x64, + 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,0x21,0x08,0x01,0x1A,0x72,0x3C,0x12,0xA7,0x87,0xE6,0xD7, + 0x88,0x71,0x9A,0x10,0xBD,0xBA,0x5B,0x26,0x99,0xC3,0x27,0x18,0x6A,0xF4,0xE2,0x3C, + 0x1A,0x94,0x68,0x34,0xB6,0x15,0x0B,0xDA,0x25,0x83,0xE9,0xCA,0x2A,0xD4,0x4C,0xE8, + 0xDB,0xBB,0xC2,0xDB,0x04,0xDE,0x8E,0xF9,0x2E,0x8E,0xFC,0x14,0x1F,0xBE,0xCA,0xA6, + 0x28,0x7C,0x59,0x47,0x4E,0x6B,0xC0,0x5D,0x99,0xB2,0x96,0x4F,0xA0,0x90,0xC3,0xA2, + 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 +}; + +/** + * Modulus of Group 17 (MODP_6144_BIT). + */ +static u_int8_t group17_modulus[] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x34, + 0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74, + 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,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,0xE4,0x5B,0x3D,0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05, + 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,0x18,0x21,0x7C,0x32,0x90,0x5E,0x46,0x2E,0x36,0xCE,0x3B, + 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,0xAA,0xC4,0x2D,0xAD,0x33,0x17,0x0D,0x04,0x50,0x7A,0x33, + 0xA8,0x55,0x21,0xAB,0xDF,0x1C,0xBA,0x64,0xEC,0xFB,0x85,0x04,0x58,0xDB,0xEF,0x0A, + 0x8A,0xEA,0x71,0x57,0x5D,0x06,0x0C,0x7D,0xB3,0x97,0x0F,0x85,0xA6,0xE1,0xE4,0xC7, + 0xAB,0xF5,0xAE,0x8C,0xDB,0x09,0x33,0xD7,0x1E,0x8C,0x94,0xE0,0x4A,0x25,0x61,0x9D, + 0xCE,0xE3,0xD2,0x26,0x1A,0xD2,0xEE,0x6B,0xF1,0x2F,0xFA,0x06,0xD9,0x8A,0x08,0x64, + 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,0x21,0x08,0x01,0x1A,0x72,0x3C,0x12,0xA7,0x87,0xE6,0xD7, + 0x88,0x71,0x9A,0x10,0xBD,0xBA,0x5B,0x26,0x99,0xC3,0x27,0x18,0x6A,0xF4,0xE2,0x3C, + 0x1A,0x94,0x68,0x34,0xB6,0x15,0x0B,0xDA,0x25,0x83,0xE9,0xCA,0x2A,0xD4,0x4C,0xE8, + 0xDB,0xBB,0xC2,0xDB,0x04,0xDE,0x8E,0xF9,0x2E,0x8E,0xFC,0x14,0x1F,0xBE,0xCA,0xA6, + 0x28,0x7C,0x59,0x47,0x4E,0x6B,0xC0,0x5D,0x99,0xB2,0x96,0x4F,0xA0,0x90,0xC3,0xA2, + 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,0x02,0x84,0x92,0x36,0xC3,0xFA,0xB4,0xD2,0x7C,0x70,0x26, + 0xC1,0xD4,0xDC,0xB2,0x60,0x26,0x46,0xDE,0xC9,0x75,0x1E,0x76,0x3D,0xBA,0x37,0xBD, + 0xF8,0xFF,0x94,0x06,0xAD,0x9E,0x53,0x0E,0xE5,0xDB,0x38,0x2F,0x41,0x30,0x01,0xAE, + 0xB0,0x6A,0x53,0xED,0x90,0x27,0xD8,0x31,0x17,0x97,0x27,0xB0,0x86,0x5A,0x89,0x18, + 0xDA,0x3E,0xDB,0xEB,0xCF,0x9B,0x14,0xED,0x44,0xCE,0x6C,0xBA,0xCE,0xD4,0xBB,0x1B, + 0xDB,0x7F,0x14,0x47,0xE6,0xCC,0x25,0x4B,0x33,0x20,0x51,0x51,0x2B,0xD7,0xAF,0x42, + 0x6F,0xB8,0xF4,0x01,0x37,0x8C,0xD2,0xBF,0x59,0x83,0xCA,0x01,0xC6,0x4B,0x92,0xEC, + 0xF0,0x32,0xEA,0x15,0xD1,0x72,0x1D,0x03,0xF4,0x82,0xD7,0xCE,0x6E,0x74,0xFE,0xF6, + 0xD5,0x5E,0x70,0x2F,0x46,0x98,0x0C,0x82,0xB5,0xA8,0x40,0x31,0x90,0x0B,0x1C,0x9E, + 0x59,0xE7,0xC9,0x7F,0xBE,0xC7,0xE8,0xF3,0x23,0xA9,0x7A,0x7E,0x36,0xCC,0x88,0xBE, + 0x0F,0x1D,0x45,0xB7,0xFF,0x58,0x5A,0xC5,0x4B,0xD4,0x07,0xB2,0x2B,0x41,0x54,0xAA, + 0xCC,0x8F,0x6D,0x7E,0xBF,0x48,0xE1,0xD8,0x14,0xCC,0x5E,0xD2,0x0F,0x80,0x37,0xE0, + 0xA7,0x97,0x15,0xEE,0xF2,0x9B,0xE3,0x28,0x06,0xA1,0xD5,0x8B,0xB7,0xC5,0xDA,0x76, + 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 +}; + +/** + * Modulus of Group 18 (MODP_8192_BIT). + */ +static u_int8_t group18_modulus[] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x34, + 0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74, + 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,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,0xE4,0x5B,0x3D,0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05, + 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,0x18,0x21,0x7C,0x32,0x90,0x5E,0x46,0x2E,0x36,0xCE,0x3B, + 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,0xAA,0xC4,0x2D,0xAD,0x33,0x17,0x0D,0x04,0x50,0x7A,0x33, + 0xA8,0x55,0x21,0xAB,0xDF,0x1C,0xBA,0x64,0xEC,0xFB,0x85,0x04,0x58,0xDB,0xEF,0x0A, + 0x8A,0xEA,0x71,0x57,0x5D,0x06,0x0C,0x7D,0xB3,0x97,0x0F,0x85,0xA6,0xE1,0xE4,0xC7, + 0xAB,0xF5,0xAE,0x8C,0xDB,0x09,0x33,0xD7,0x1E,0x8C,0x94,0xE0,0x4A,0x25,0x61,0x9D, + 0xCE,0xE3,0xD2,0x26,0x1A,0xD2,0xEE,0x6B,0xF1,0x2F,0xFA,0x06,0xD9,0x8A,0x08,0x64, + 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,0x21,0x08,0x01,0x1A,0x72,0x3C,0x12,0xA7,0x87,0xE6,0xD7, + 0x88,0x71,0x9A,0x10,0xBD,0xBA,0x5B,0x26,0x99,0xC3,0x27,0x18,0x6A,0xF4,0xE2,0x3C, + 0x1A,0x94,0x68,0x34,0xB6,0x15,0x0B,0xDA,0x25,0x83,0xE9,0xCA,0x2A,0xD4,0x4C,0xE8, + 0xDB,0xBB,0xC2,0xDB,0x04,0xDE,0x8E,0xF9,0x2E,0x8E,0xFC,0x14,0x1F,0xBE,0xCA,0xA6, + 0x28,0x7C,0x59,0x47,0x4E,0x6B,0xC0,0x5D,0x99,0xB2,0x96,0x4F,0xA0,0x90,0xC3,0xA2, + 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,0x02,0x84,0x92,0x36,0xC3,0xFA,0xB4,0xD2,0x7C,0x70,0x26, + 0xC1,0xD4,0xDC,0xB2,0x60,0x26,0x46,0xDE,0xC9,0x75,0x1E,0x76,0x3D,0xBA,0x37,0xBD, + 0xF8,0xFF,0x94,0x06,0xAD,0x9E,0x53,0x0E,0xE5,0xDB,0x38,0x2F,0x41,0x30,0x01,0xAE, + 0xB0,0x6A,0x53,0xED,0x90,0x27,0xD8,0x31,0x17,0x97,0x27,0xB0,0x86,0x5A,0x89,0x18, + 0xDA,0x3E,0xDB,0xEB,0xCF,0x9B,0x14,0xED,0x44,0xCE,0x6C,0xBA,0xCE,0xD4,0xBB,0x1B, + 0xDB,0x7F,0x14,0x47,0xE6,0xCC,0x25,0x4B,0x33,0x20,0x51,0x51,0x2B,0xD7,0xAF,0x42, + 0x6F,0xB8,0xF4,0x01,0x37,0x8C,0xD2,0xBF,0x59,0x83,0xCA,0x01,0xC6,0x4B,0x92,0xEC, + 0xF0,0x32,0xEA,0x15,0xD1,0x72,0x1D,0x03,0xF4,0x82,0xD7,0xCE,0x6E,0x74,0xFE,0xF6, + 0xD5,0x5E,0x70,0x2F,0x46,0x98,0x0C,0x82,0xB5,0xA8,0x40,0x31,0x90,0x0B,0x1C,0x9E, + 0x59,0xE7,0xC9,0x7F,0xBE,0xC7,0xE8,0xF3,0x23,0xA9,0x7A,0x7E,0x36,0xCC,0x88,0xBE, + 0x0F,0x1D,0x45,0xB7,0xFF,0x58,0x5A,0xC5,0x4B,0xD4,0x07,0xB2,0x2B,0x41,0x54,0xAA, + 0xCC,0x8F,0x6D,0x7E,0xBF,0x48,0xE1,0xD8,0x14,0xCC,0x5E,0xD2,0x0F,0x80,0x37,0xE0, + 0xA7,0x97,0x15,0xEE,0xF2,0x9B,0xE3,0x28,0x06,0xA1,0xD5,0x8B,0xB7,0xC5,0xDA,0x76, + 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,0xBE,0x11,0x59,0x74,0xA3,0x92,0x6F,0x12,0xFE,0xE5,0xE4, + 0x38,0x77,0x7C,0xB6,0xA9,0x32,0xDF,0x8C,0xD8,0xBE,0xC4,0xD0,0x73,0xB9,0x31,0xBA, + 0x3B,0xC8,0x32,0xB6,0x8D,0x9D,0xD3,0x00,0x74,0x1F,0xA7,0xBF,0x8A,0xFC,0x47,0xED, + 0x25,0x76,0xF6,0x93,0x6B,0xA4,0x24,0x66,0x3A,0xAB,0x63,0x9C,0x5A,0xE4,0xF5,0x68, + 0x34,0x23,0xB4,0x74,0x2B,0xF1,0xC9,0x78,0x23,0x8F,0x16,0xCB,0xE3,0x9D,0x65,0x2D, + 0xE3,0xFD,0xB8,0xBE,0xFC,0x84,0x8A,0xD9,0x22,0x22,0x2E,0x04,0xA4,0x03,0x7C,0x07, + 0x13,0xEB,0x57,0xA8,0x1A,0x23,0xF0,0xC7,0x34,0x73,0xFC,0x64,0x6C,0xEA,0x30,0x6B, + 0x4B,0xCB,0xC8,0x86,0x2F,0x83,0x85,0xDD,0xFA,0x9D,0x4B,0x7F,0xA2,0xC0,0x87,0xE8, + 0x79,0x68,0x33,0x03,0xED,0x5B,0xDD,0x3A,0x06,0x2B,0x3C,0xF5,0xB3,0xA2,0x78,0xA6, + 0x6D,0x2A,0x13,0xF8,0x3F,0x44,0xF8,0x2D,0xDF,0x31,0x0E,0xE0,0x74,0xAB,0x6A,0x36, + 0x45,0x97,0xE8,0x99,0xA0,0x25,0x5D,0xC1,0x64,0xF3,0x1C,0xC5,0x08,0x46,0x85,0x1D, + 0xF9,0xAB,0x48,0x19,0x5D,0xED,0x7E,0xA1,0xB1,0xD5,0x10,0xBD,0x7E,0xE7,0x4D,0x73, + 0xFA,0xF3,0x6B,0xC3,0x1E,0xCF,0xA2,0x68,0x35,0x90,0x46,0xF4,0xEB,0x87,0x9F,0x92, + 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, +}; + +typedef struct modulus_entry_t modulus_entry_t; + +/** + * Entry of the modulus list. + */ +struct modulus_entry_t { + /** + * Group number as it is defined in file transform_substructure.h. + */ + diffie_hellman_group_t group; + + /** + * Pointer to first byte of modulus (network order). + */ + u_int8_t *modulus; + + /* + * Length of modulus in bytes. + */ + size_t modulus_len; + + /* + * Generator value. + */ + u_int16_t generator; +}; + +/** + * All supported modulus values. + */ +static modulus_entry_t modulus_entries[] = { + {MODP_768_BIT, group1_modulus, sizeof(group1_modulus), 2}, + {MODP_1024_BIT, group2_modulus, sizeof(group2_modulus), 2}, + {MODP_1536_BIT, group5_modulus, sizeof(group5_modulus), 2}, + {MODP_2048_BIT, group14_modulus, sizeof(group14_modulus), 2}, + {MODP_3072_BIT, group15_modulus, sizeof(group15_modulus), 2}, + {MODP_4096_BIT, group16_modulus, sizeof(group16_modulus), 2}, + {MODP_6144_BIT, group17_modulus, sizeof(group17_modulus), 2}, + {MODP_8192_BIT, group18_modulus, sizeof(group18_modulus), 2}, +}; + +typedef struct private_gmp_diffie_hellman_t private_gmp_diffie_hellman_t; + +/** + * Private data of an gmp_diffie_hellman_t object. + */ +struct private_gmp_diffie_hellman_t { + /** + * Public gmp_diffie_hellman_t interface. + */ + gmp_diffie_hellman_t public; + + /** + * Diffie Hellman group number. + */ + u_int16_t group; + + /* + * Generator value. + */ + mpz_t g; + + /** + * My private value. + */ + mpz_t xa; + + /** + * My public value. + */ + mpz_t ya; + + /** + * Other public value. + */ + mpz_t yb; + + /** + * Shared secret. + */ + mpz_t zz; + + /** + * Modulus. + */ + mpz_t p; + + /** + * Modulus length. + */ + size_t p_len; + + /** + * True if shared secret is computed and stored in my_public_value. + */ + bool computed; +}; + +/** + * Implementation of gmp_diffie_hellman_t.set_other_public_value. + */ +static void set_other_public_value(private_gmp_diffie_hellman_t *this, chunk_t value) +{ + mpz_t p_min_1; + + mpz_init(p_min_1); + mpz_sub_ui(p_min_1, this->p, 1); + + mpz_import(this->yb, value.len, 1, 1, 1, 0, value.ptr); + + /* check public value: + * 1. 0 or 1 is invalid as 0^a = 0 and 1^a = 1 + * 2. a public value larger or equal the modulus is invalid */ + if (mpz_cmp_ui(this->yb, 1) > 0 || + mpz_cmp(this->yb, p_min_1) < 0) + { +#ifdef EXTENDED_DH_TEST + /* 3. test if y ^ q mod p = 1, where q = (p - 1)/2. */ + mpz_t q, one; + + mpz_init(q); + mpz_init(one); + mpz_fdiv_q_2exp(q, p_min_1, 1); + mpz_powm(one, this->yb, q, this->p); + mpz_clear(q); + if (mpz_cmp_ui(one, 1) == 0) + { + mpz_powm(this->zz, this->yb, this->xa, this->p); + this->computed = TRUE; + } + else + { + DBG1("public DH value verification failed: y ^ q mod p != 1"); + } + mpz_clear(one); +#else + mpz_powm(this->zz, this->yb, this->xa, this->p); + this->computed = TRUE; +#endif + } + else + { + DBG1("public DH value verification failed: y < 2 || y > p - 1 "); + } + mpz_clear(p_min_1); +} + +/** + * Implementation of gmp_diffie_hellman_t.get_other_public_value. + */ +static status_t get_other_public_value(private_gmp_diffie_hellman_t *this, + chunk_t *value) +{ + if (!this->computed) + { + return FAILED; + } + value->len = this->p_len; + value->ptr = mpz_export(NULL, NULL, 1, value->len, 1, 0, this->yb); + return SUCCESS; +} + +/** + * Implementation of gmp_diffie_hellman_t.get_my_public_value. + */ +static void get_my_public_value(private_gmp_diffie_hellman_t *this,chunk_t *value) +{ + value->len = this->p_len; + value->ptr = mpz_export(NULL, NULL, 1, value->len, 1, 0, this->ya); +} + +/** + * Implementation of gmp_diffie_hellman_t.get_shared_secret. + */ +static status_t get_shared_secret(private_gmp_diffie_hellman_t *this, chunk_t *secret) +{ + if (!this->computed) + { + return FAILED; + } + secret->len = this->p_len; + secret->ptr = mpz_export(NULL, NULL, 1, secret->len, 1, 0, this->zz); + return SUCCESS; +} + +/** + * Implementation of gmp_diffie_hellman_t.get_dh_group. + */ +static diffie_hellman_group_t get_dh_group(private_gmp_diffie_hellman_t *this) +{ + return this->group; +} + +/** + * Lookup the modulus in modulo table + */ +static status_t set_modulus(private_gmp_diffie_hellman_t *this) +{ + int i; + status_t status = NOT_FOUND; + + for (i = 0; i < (sizeof(modulus_entries) / sizeof(modulus_entry_t)); i++) + { + if (modulus_entries[i].group == this->group) + { + chunk_t chunk; + chunk.ptr = modulus_entries[i].modulus; + chunk.len = modulus_entries[i].modulus_len; + mpz_import(this->p, chunk.len, 1, 1, 1, 0, chunk.ptr); + this->p_len = chunk.len; + mpz_set_ui(this->g, modulus_entries[i].generator); + status = SUCCESS; + break; + } + } + return status; +} + +/** + * Implementation of gmp_diffie_hellman_t.destroy. + */ +static void destroy(private_gmp_diffie_hellman_t *this) +{ + mpz_clear(this->p); + mpz_clear(this->xa); + mpz_clear(this->ya); + mpz_clear(this->yb); + mpz_clear(this->zz); + mpz_clear(this->g); + free(this); +} + +/* + * Described in header. + */ +gmp_diffie_hellman_t *gmp_diffie_hellman_create(diffie_hellman_group_t group) +{ + private_gmp_diffie_hellman_t *this = malloc_thing(private_gmp_diffie_hellman_t); + randomizer_t *randomizer; + chunk_t random; + status_t status; + + /* public functions */ + this->public.dh.get_shared_secret = (status_t (*)(diffie_hellman_t *, chunk_t *)) get_shared_secret; + this->public.dh.set_other_public_value = (void (*)(diffie_hellman_t *, chunk_t )) set_other_public_value; + this->public.dh.get_other_public_value = (status_t (*)(diffie_hellman_t *, chunk_t *)) get_other_public_value; + this->public.dh.get_my_public_value = (void (*)(diffie_hellman_t *, chunk_t *)) get_my_public_value; + this->public.dh.get_dh_group = (diffie_hellman_group_t (*)(diffie_hellman_t *)) get_dh_group; + this->public.dh.destroy = (void (*)(diffie_hellman_t *)) destroy; + + /* private variables */ + this->group = group; + mpz_init(this->p); + mpz_init(this->yb); + mpz_init(this->ya); + mpz_init(this->xa); + mpz_init(this->zz); + mpz_init(this->g); + + this->computed = FALSE; + + /* find a modulus according to group */ + if (set_modulus(this) != SUCCESS) + { + destroy(this); + return NULL; + } + randomizer = randomizer_create(); + status = randomizer->allocate_pseudo_random_bytes( + randomizer, this->p_len, &random); + randomizer->destroy(randomizer); + if (status != SUCCESS) + { + destroy(this); + return NULL; + } + mpz_import(this->xa, random.len, 1, 1, 1, 0, random.ptr); + chunk_free(&random); + + mpz_powm(this->ya, this->g, this->xa, this->p); + + return &this->public; +} + diff --git a/src/libstrongswan/plugins/gmp/gmp_diffie_hellman.h b/src/libstrongswan/plugins/gmp/gmp_diffie_hellman.h new file mode 100644 index 000000000..e2d4d6851 --- /dev/null +++ b/src/libstrongswan/plugins/gmp/gmp_diffie_hellman.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2005-2007 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 gmp_diffie_hellman gmp_diffie_hellman + * @{ @ingroup gmp_p + */ + +#ifndef GMP_DIFFIE_HELLMAN_H_ +#define GMP_DIFFIE_HELLMAN_H_ + +typedef struct gmp_diffie_hellman_t gmp_diffie_hellman_t; + +#include + +/** + * Implementation of the Diffie-Hellman algorithm, as in RFC2631. Uses libgmp. + */ +struct gmp_diffie_hellman_t { + + /** + * Implements diffie_hellman_t interface. + */ + diffie_hellman_t dh; +}; + +/** + * Creates a new gmp_diffie_hellman_t object. + * + * @param group Diffie Hellman group number to use + * @return gmp_diffie_hellman_t object, NULL if not supported + */ +gmp_diffie_hellman_t *gmp_diffie_hellman_create(diffie_hellman_group_t group); + +#endif /*GMP_DIFFIE_HELLMAN_H_ @}*/ + diff --git a/src/libstrongswan/plugins/gmp/gmp_plugin.c b/src/libstrongswan/plugins/gmp/gmp_plugin.c new file mode 100644 index 000000000..ffae66933 --- /dev/null +++ b/src/libstrongswan/plugins/gmp/gmp_plugin.c @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "gmp_plugin.h" + +#include +#include "gmp_diffie_hellman.h" +#include "gmp_rsa_private_key.h" +#include "gmp_rsa_public_key.h" + +typedef struct private_gmp_plugin_t private_gmp_plugin_t; + +/** + * private data of gmp_plugin + */ +struct private_gmp_plugin_t { + + /** + * public functions + */ + gmp_plugin_t public; +}; + +/** + * Implementation of gmp_plugin_t.gmptroy + */ +static void destroy(private_gmp_plugin_t *this) +{ + lib->crypto->remove_dh(lib->crypto, + (dh_constructor_t)gmp_diffie_hellman_create); + lib->creds->remove_builder(lib->creds, + (builder_constructor_t)gmp_rsa_private_key_builder); + lib->creds->remove_builder(lib->creds, + (builder_constructor_t)gmp_rsa_public_key_builder); + free(this); +} + +/* + * see header file + */ +plugin_t *plugin_create() +{ + private_gmp_plugin_t *this = malloc_thing(private_gmp_plugin_t); + + this->public.plugin.destroy = (void(*)(plugin_t*))destroy; + + lib->crypto->add_dh(lib->crypto, MODP_768_BIT, + (dh_constructor_t)gmp_diffie_hellman_create); + lib->crypto->add_dh(lib->crypto, MODP_1024_BIT, + (dh_constructor_t)gmp_diffie_hellman_create); + lib->crypto->add_dh(lib->crypto, MODP_1536_BIT, + (dh_constructor_t)gmp_diffie_hellman_create); + lib->crypto->add_dh(lib->crypto, MODP_2048_BIT, + (dh_constructor_t)gmp_diffie_hellman_create); + lib->crypto->add_dh(lib->crypto, MODP_3072_BIT, + (dh_constructor_t)gmp_diffie_hellman_create); + lib->crypto->add_dh(lib->crypto, MODP_4096_BIT, + (dh_constructor_t)gmp_diffie_hellman_create); + lib->crypto->add_dh(lib->crypto, MODP_6144_BIT, + (dh_constructor_t)gmp_diffie_hellman_create); + lib->crypto->add_dh(lib->crypto, MODP_8192_BIT, + (dh_constructor_t)gmp_diffie_hellman_create); + + lib->creds->add_builder(lib->creds, CRED_PRIVATE_KEY, KEY_RSA, + (builder_constructor_t)gmp_rsa_private_key_builder); + lib->creds->add_builder(lib->creds, CRED_PUBLIC_KEY, KEY_RSA, + (builder_constructor_t)gmp_rsa_public_key_builder); + + return &this->public.plugin; +} + diff --git a/src/libstrongswan/plugins/gmp/gmp_plugin.h b/src/libstrongswan/plugins/gmp/gmp_plugin.h new file mode 100644 index 000000000..a853064b7 --- /dev/null +++ b/src/libstrongswan/plugins/gmp/gmp_plugin.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 gmp_p gmp + * @ingroup plugins + * + * @defgroup gmp_plugin gmp_plugin + * @{ @ingroup gmp_p + */ + +#ifndef GMP_PLUGIN_H_ +#define GMP_PLUGIN_H_ + +#include + +typedef struct gmp_plugin_t gmp_plugin_t; + +/** + * Plugin implementing asymmetric crypto algorithms using the GNU MP library. + */ +struct gmp_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +/** + * Create a gmp_plugin instance. + */ +plugin_t *plugin_create(); + +#endif /* GMP_PLUGIN_H_ @}*/ diff --git a/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c b/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c new file mode 100644 index 000000000..2315df595 --- /dev/null +++ b/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c @@ -0,0 +1,844 @@ +/* + * Copyright (C) 2005-2008 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include +#include +#include +#include + +#include "gmp_rsa_private_key.h" +#include "gmp_rsa_public_key.h" + +#include +#include +#include +#include + +/** + * Public exponent to use for key generation. + */ +#define PUBLIC_EXPONENT 0x10001 + +typedef struct private_gmp_rsa_private_key_t private_gmp_rsa_private_key_t; + +/** + * Private data of a gmp_rsa_private_key_t object. + */ +struct private_gmp_rsa_private_key_t { + /** + * Public interface for this signer. + */ + gmp_rsa_private_key_t public; + + /** + * Version of key, as encoded in PKCS#1 + */ + u_int version; + + /** + * Public modulus. + */ + mpz_t n; + + /** + * Public exponent. + */ + mpz_t e; + + /** + * Private prime 1. + */ + mpz_t p; + + /** + * Private Prime 2. + */ + mpz_t q; + + /** + * Private exponent. + */ + mpz_t d; + + /** + * Private exponent 1. + */ + mpz_t exp1; + + /** + * Private exponent 2. + */ + mpz_t exp2; + + /** + * Private coefficient. + */ + mpz_t coeff; + + /** + * Keysize in bytes. + */ + size_t k; + + /** + * Keyid formed as a SHA-1 hash of a publicKey object + */ + identification_t* keyid; + + /** + * Keyid formed as a SHA-1 hash of a publicKeyInfo object + */ + identification_t* keyid_info; + + /** + * reference count + */ + refcount_t ref; +}; + +/* ASN.1 definition of a PKCS#1 RSA private key */ +static const asn1Object_t privkey_objects[] = { + { 0, "RSAPrivateKey", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ + { 1, "version", ASN1_INTEGER, ASN1_BODY }, /* 1 */ + { 1, "modulus", ASN1_INTEGER, ASN1_BODY }, /* 2 */ + { 1, "publicExponent", ASN1_INTEGER, ASN1_BODY }, /* 3 */ + { 1, "privateExponent", ASN1_INTEGER, ASN1_BODY }, /* 4 */ + { 1, "prime1", ASN1_INTEGER, ASN1_BODY }, /* 5 */ + { 1, "prime2", ASN1_INTEGER, ASN1_BODY }, /* 6 */ + { 1, "exponent1", ASN1_INTEGER, ASN1_BODY }, /* 7 */ + { 1, "exponent2", ASN1_INTEGER, ASN1_BODY }, /* 8 */ + { 1, "coefficient", ASN1_INTEGER, ASN1_BODY }, /* 9 */ + { 1, "otherPrimeInfos", ASN1_SEQUENCE, ASN1_OPT | + ASN1_LOOP }, /* 10 */ + { 2, "otherPrimeInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 11 */ + { 3, "prime", ASN1_INTEGER, ASN1_BODY }, /* 12 */ + { 3, "exponent", ASN1_INTEGER, ASN1_BODY }, /* 13 */ + { 3, "coefficient", ASN1_INTEGER, ASN1_BODY }, /* 14 */ + { 1, "end opt or loop", ASN1_EOC, ASN1_END } /* 15 */ +}; + +#define PRIV_KEY_VERSION 1 +#define PRIV_KEY_MODULUS 2 +#define PRIV_KEY_PUB_EXP 3 +#define PRIV_KEY_PRIV_EXP 4 +#define PRIV_KEY_PRIME1 5 +#define PRIV_KEY_PRIME2 6 +#define PRIV_KEY_EXP1 7 +#define PRIV_KEY_EXP2 8 +#define PRIV_KEY_COEFF 9 +#define PRIV_KEY_ROOF 16 + +/** + * defined in rsa_public_key.c + */ +bool gmp_rsa_public_key_build_id(mpz_t n, mpz_t e, identification_t **keyid, + identification_t **keyid_info); + +/** + * Auxiliary function overwriting private key material with + * pseudo-random bytes before releasing it + */ +static void mpz_clear_randomized(mpz_t z) +{ + size_t len = mpz_size(z) * GMP_LIMB_BITS / BITS_PER_BYTE; + u_int8_t *random_bytes = alloca(len); + + randomizer_t *randomizer = randomizer_create(); + + randomizer->get_pseudo_random_bytes(randomizer, len, random_bytes); + + /* overwrite mpz_t with pseudo-random bytes before clearing it */ + mpz_import(z, len, 1, 1, 1, 0, random_bytes); + mpz_clear(z); + + randomizer->destroy(randomizer); +} + +/** + * Create a mpz prime of at least prime_size + */ +static status_t compute_prime(private_gmp_rsa_private_key_t *this, + size_t prime_size, mpz_t *prime) +{ + randomizer_t *randomizer; + chunk_t random_bytes; + status_t status; + + randomizer = randomizer_create(); + mpz_init(*prime); + + do + { + status = randomizer->allocate_random_bytes(randomizer, prime_size, + &random_bytes); + if (status != SUCCESS) + { + randomizer->destroy(randomizer); + mpz_clear(*prime); + return FAILED; + } + /* make sure most significant bit is set */ + random_bytes.ptr[0] = random_bytes.ptr[0] | 0x80; + + mpz_import(*prime, random_bytes.len, 1, 1, 1, 0, random_bytes.ptr); + mpz_nextprime (*prime, *prime); + chunk_free_randomized(&random_bytes); + } + /* check if it isn't too large */ + while (((mpz_sizeinbase(*prime, 2) + 7) / 8) > prime_size); + + randomizer->destroy(randomizer); + return SUCCESS; +} + +/** + * PKCS#1 RSADP function + */ +static chunk_t rsadp(private_gmp_rsa_private_key_t *this, chunk_t data) +{ + mpz_t t1, t2; + chunk_t decrypted; + + mpz_init(t1); + mpz_init(t2); + + mpz_import(t1, data.len, 1, 1, 1, 0, data.ptr); + + mpz_powm(t2, t1, this->exp1, this->p); /* m1 = c^dP mod p */ + mpz_powm(t1, t1, this->exp2, this->q); /* m2 = c^dQ mod Q */ + mpz_sub(t2, t2, t1); /* h = qInv (m1 - m2) mod p */ + mpz_mod(t2, t2, this->p); + mpz_mul(t2, t2, this->coeff); + mpz_mod(t2, t2, this->p); + + mpz_mul(t2, t2, this->q); /* m = m2 + h q */ + mpz_add(t1, t1, t2); + + decrypted.len = this->k; + decrypted.ptr = mpz_export(NULL, NULL, 1, decrypted.len, 1, 0, t1); + + mpz_clear_randomized(t1); + mpz_clear_randomized(t2); + + return decrypted; +} + +/** + * PKCS#1 RSASP1 function + */ +static chunk_t rsasp1(private_gmp_rsa_private_key_t *this, chunk_t data) +{ + return rsadp(this, data); +} + +/** + * Implementation of gmp_rsa_private_key_t.build_emsa_pkcs1_signature. + */ +static bool build_emsa_pkcs1_signature(private_gmp_rsa_private_key_t *this, + hash_algorithm_t hash_algorithm, + chunk_t data, chunk_t *signature) +{ + hasher_t *hasher; + chunk_t em, digestInfo, hash; + int hash_oid = hasher_algorithm_to_oid(hash_algorithm); + + if (hash_oid == OID_UNKNOWN) + { + return FALSE; + } + + /* get hasher */ + hasher = lib->crypto->create_hasher(lib->crypto, hash_algorithm); + if (hasher == NULL) + { + return FALSE; + } + + /* build hash */ + hasher->allocate_hash(hasher, data, &hash); + hasher->destroy(hasher); + + /* build DER-encoded digestInfo */ + digestInfo = asn1_wrap(ASN1_SEQUENCE, "cm", + asn1_algorithmIdentifier(hash_oid), + asn1_simple_object(ASN1_OCTET_STRING, hash) + ); + chunk_free(&hash); + + /* build chunk to rsa-decrypt: + * EM = 0x00 || 0x01 || PS || 0x00 || T. + * PS = 0xFF padding, with length to fill em + * T = encoded_hash + */ + em.len = this->k; + em.ptr = malloc(em.len); + + /* fill em with padding */ + memset(em.ptr, 0xFF, em.len); + /* set magic bytes */ + *(em.ptr) = 0x00; + *(em.ptr+1) = 0x01; + *(em.ptr + em.len - digestInfo.len - 1) = 0x00; + /* set DER-encoded hash */ + memcpy(em.ptr + em.len - digestInfo.len, digestInfo.ptr, digestInfo.len); + + /* build signature */ + *signature = rsasp1(this, em); + + free(digestInfo.ptr); + free(em.ptr); + + return TRUE; +} + +/** + * Implementation of gmp_rsa_private_key.destroy. + */ +static key_type_t get_type(private_gmp_rsa_private_key_t *this) +{ + return KEY_RSA; +} + +/** + * Implementation of gmp_rsa_private_key.destroy. + */ +static bool sign(private_gmp_rsa_private_key_t *this, signature_scheme_t scheme, + chunk_t data, chunk_t *signature) +{ + switch (scheme) + { + case SIGN_DEFAULT: + /* default is EMSA-PKCS1 using SHA1 */ + case SIGN_RSA_EMSA_PKCS1_SHA1: + return build_emsa_pkcs1_signature(this, HASH_SHA1, data, signature); + case SIGN_RSA_EMSA_PKCS1_SHA256: + return build_emsa_pkcs1_signature(this, HASH_SHA256, data, signature); + case SIGN_RSA_EMSA_PKCS1_SHA384: + return build_emsa_pkcs1_signature(this, HASH_SHA384, data, signature); + case SIGN_RSA_EMSA_PKCS1_SHA512: + return build_emsa_pkcs1_signature(this, HASH_SHA512, data, signature); + case SIGN_RSA_EMSA_PKCS1_MD5: + return build_emsa_pkcs1_signature(this, HASH_MD5, data, signature); + default: + DBG1("signature scheme %N not supported in RSA", + signature_scheme_names, scheme); + return FALSE; + } +} + +/** + * Implementation of gmp_rsa_private_key.destroy. + */ +static bool decrypt(private_gmp_rsa_private_key_t *this, + chunk_t crypto, chunk_t *plain) +{ + DBG1("RSA private key decryption not implemented"); + return FALSE; +} + +/** + * Implementation of gmp_rsa_private_key.destroy. + */ +static size_t get_keysize(private_gmp_rsa_private_key_t *this) +{ + return this->k; +} + +/** + * Implementation of gmp_rsa_private_key.destroy. + */ +static identification_t* get_id(private_gmp_rsa_private_key_t *this, + id_type_t type) +{ + switch (type) + { + case ID_PUBKEY_INFO_SHA1: + return this->keyid_info; + case ID_PUBKEY_SHA1: + return this->keyid; + default: + return NULL; + } +} + +/** + * Implementation of gmp_rsa_private_key.destroy. + */ +static gmp_rsa_public_key_t* get_public_key(private_gmp_rsa_private_key_t *this) +{ + DBG1("creating RSA public key from private key not implemented"); + return NULL; +} + +/** + * Implementation of gmp_rsa_private_key.destroy. + */ +static bool belongs_to(private_gmp_rsa_private_key_t *this, public_key_t *public) +{ + identification_t *keyid; + + if (public->get_type(public) != KEY_RSA) + { + return FALSE; + } + keyid = public->get_id(public, ID_PUBKEY_SHA1); + if (keyid && keyid->equals(keyid, this->keyid)) + { + return TRUE; + } + keyid = public->get_id(public, ID_PUBKEY_INFO_SHA1); + if (keyid && keyid->equals(keyid, this->keyid_info)) + { + return TRUE; + } + return FALSE; +} + +/** + * convert a MP integer into a DER coded ASN.1 object + */ +chunk_t gmp_mpz_to_asn1(const mpz_t value) +{ + size_t bits = mpz_sizeinbase(value, 2); /* size in bits */ + chunk_t n; + + n.len = 1 + bits / 8; /* size in bytes */ + n.ptr = mpz_export(NULL, NULL, 1, n.len, 1, 0, value); + + return asn1_wrap(ASN1_INTEGER, "m", n); +} + +/** + * Implementation of private_key_t.get_encoding. + */ +static chunk_t get_encoding(private_gmp_rsa_private_key_t *this) +{ + return asn1_wrap(ASN1_SEQUENCE, "cmmmmmmmm", + ASN1_INTEGER_0, + gmp_mpz_to_asn1(this->n), + gmp_mpz_to_asn1(this->e), + gmp_mpz_to_asn1(this->d), + gmp_mpz_to_asn1(this->p), + gmp_mpz_to_asn1(this->q), + gmp_mpz_to_asn1(this->exp1), + gmp_mpz_to_asn1(this->exp2), + gmp_mpz_to_asn1(this->coeff)); +} + +/** + * Implementation of gmp_rsa_private_key.destroy. + */ +static private_gmp_rsa_private_key_t* get_ref(private_gmp_rsa_private_key_t *this) +{ + ref_get(&this->ref); + return this; + +} + +/** + * Implementation of gmp_rsa_private_key.destroy. + */ +static void destroy(private_gmp_rsa_private_key_t *this) +{ + if (ref_put(&this->ref)) + { + mpz_clear_randomized(this->n); + mpz_clear_randomized(this->e); + mpz_clear_randomized(this->p); + mpz_clear_randomized(this->q); + mpz_clear_randomized(this->d); + mpz_clear_randomized(this->exp1); + mpz_clear_randomized(this->exp2); + mpz_clear_randomized(this->coeff); + DESTROY_IF(this->keyid); + DESTROY_IF(this->keyid_info); + free(this); + } +} + +/** + * Check the loaded key if it is valid and usable + */ +static status_t check(private_gmp_rsa_private_key_t *this) +{ + mpz_t t, u, q1; + status_t status = SUCCESS; + + /* PKCS#1 1.5 section 6 requires modulus to have at least 12 octets. + * We actually require more (for security). + */ + if (this->k < 512/8) + { + DBG1("key shorter than 512 bits"); + return FAILED; + } + + /* we picked a max modulus size to simplify buffer allocation */ + if (this->k > 8192/8) + { + DBG1("key larger thant 8192 bits"); + return FAILED; + } + + mpz_init(t); + mpz_init(u); + mpz_init(q1); + + /* check that n == p * q */ + mpz_mul(u, this->p, this->q); + if (mpz_cmp(u, this->n) != 0) + { + status = FAILED; + } + + /* check that e divides neither p-1 nor q-1 */ + mpz_sub_ui(t, this->p, 1); + mpz_mod(t, t, this->e); + if (mpz_cmp_ui(t, 0) == 0) + { + status = FAILED; + } + + mpz_sub_ui(t, this->q, 1); + mpz_mod(t, t, this->e); + if (mpz_cmp_ui(t, 0) == 0) + { + status = FAILED; + } + + /* check that d is e^-1 (mod lcm(p-1, q-1)) */ + /* see PKCS#1v2, aka RFC 2437, for the "lcm" */ + mpz_sub_ui(q1, this->q, 1); + mpz_sub_ui(u, this->p, 1); + mpz_gcd(t, u, q1); /* t := gcd(p-1, q-1) */ + mpz_mul(u, u, q1); /* u := (p-1) * (q-1) */ + mpz_divexact(u, u, t); /* u := lcm(p-1, q-1) */ + + mpz_mul(t, this->d, this->e); + mpz_mod(t, t, u); + if (mpz_cmp_ui(t, 1) != 0) + { + status = FAILED; + } + + /* check that exp1 is d mod (p-1) */ + mpz_sub_ui(u, this->p, 1); + mpz_mod(t, this->d, u); + if (mpz_cmp(t, this->exp1) != 0) + { + status = FAILED; + } + + /* check that exp2 is d mod (q-1) */ + mpz_sub_ui(u, this->q, 1); + mpz_mod(t, this->d, u); + if (mpz_cmp(t, this->exp2) != 0) + { + status = FAILED; + } + + /* check that coeff is (q^-1) mod p */ + mpz_mul(t, this->coeff, this->q); + mpz_mod(t, t, this->p); + if (mpz_cmp_ui(t, 1) != 0) + { + status = FAILED; + } + + mpz_clear_randomized(t); + mpz_clear_randomized(u); + mpz_clear_randomized(q1); + if (status != SUCCESS) + { + DBG1("key integrity tests failed"); + } + return status; +} + +/** + * Internal generic constructor + */ +static private_gmp_rsa_private_key_t *gmp_rsa_private_key_create_empty(void) +{ + private_gmp_rsa_private_key_t *this = malloc_thing(private_gmp_rsa_private_key_t); + + this->public.interface.get_type = (key_type_t (*)(private_key_t *this))get_type; + this->public.interface.sign = (bool (*)(private_key_t *this, signature_scheme_t scheme, chunk_t data, chunk_t *signature))sign; + this->public.interface.decrypt = (bool (*)(private_key_t *this, chunk_t crypto, chunk_t *plain))decrypt; + this->public.interface.get_keysize = (size_t (*) (private_key_t *this))get_keysize; + this->public.interface.get_id = (identification_t* (*) (private_key_t *this,id_type_t))get_id; + this->public.interface.get_public_key = (public_key_t* (*)(private_key_t *this))get_public_key; + this->public.interface.belongs_to = (bool (*) (private_key_t *this, public_key_t *public))belongs_to; + this->public.interface.get_encoding = (chunk_t(*)(private_key_t*))get_encoding; + this->public.interface.get_ref = (private_key_t* (*)(private_key_t *this))get_ref; + this->public.interface.destroy = (void (*)(private_key_t *this))destroy; + + this->keyid = NULL; + this->keyid_info = NULL; + this->ref = 1; + + return this; +} + +/** + * Generate an RSA key of specified key size + */ +static gmp_rsa_private_key_t *generate(size_t key_size) +{ + mpz_t p, q, n, e, d, exp1, exp2, coeff; + mpz_t m, q1, t; + private_gmp_rsa_private_key_t *this = gmp_rsa_private_key_create_empty(); + + key_size = key_size / 8; + + /* Get values of primes p and q */ + if (compute_prime(this, key_size/2, &p) != SUCCESS) + { + free(this); + return NULL; + } + if (compute_prime(this, key_size/2, &q) != SUCCESS) + { + mpz_clear(p); + free(this); + return NULL; + } + + mpz_init(t); + mpz_init(n); + mpz_init(d); + mpz_init(exp1); + mpz_init(exp2); + mpz_init(coeff); + + /* Swapping Primes so p is larger then q */ + if (mpz_cmp(p, q) < 0) + { + mpz_swap(p, q); + } + + mpz_mul(n, p, q); /* n = p*q */ + mpz_init_set_ui(e, PUBLIC_EXPONENT); /* assign public exponent */ + mpz_init_set(m, p); /* m = p */ + mpz_sub_ui(m, m, 1); /* m = m -1 */ + mpz_init_set(q1, q); /* q1 = q */ + mpz_sub_ui(q1, q1, 1); /* q1 = q1 -1 */ + mpz_gcd(t, m, q1); /* t = gcd(p-1, q-1) */ + mpz_mul(m, m, q1); /* m = (p-1)*(q-1) */ + mpz_divexact(m, m, t); /* m = m / t */ + mpz_gcd(t, m, e); /* t = gcd(m, e) */ + + mpz_invert(d, e, m); /* e has an inverse mod m */ + if (mpz_cmp_ui(d, 0) < 0) /* make sure d is positive */ + { + mpz_add(d, d, m); + } + mpz_sub_ui(t, p, 1); /* t = p-1 */ + mpz_mod(exp1, d, t); /* exp1 = d mod p-1 */ + mpz_sub_ui(t, q, 1); /* t = q-1 */ + mpz_mod(exp2, d, t); /* exp2 = d mod q-1 */ + + mpz_invert(coeff, q, p); /* coeff = q^-1 mod p */ + if (mpz_cmp_ui(coeff, 0) < 0) /* make coeff d is positive */ + { + mpz_add(coeff, coeff, p); + } + + mpz_clear_randomized(q1); + mpz_clear_randomized(m); + mpz_clear_randomized(t); + + /* apply values */ + *(this->p) = *p; + *(this->q) = *q; + *(this->n) = *n; + *(this->e) = *e; + *(this->d) = *d; + *(this->exp1) = *exp1; + *(this->exp2) = *exp2; + *(this->coeff) = *coeff; + + /* set key size in bytes */ + this->k = key_size; + + return &this->public; +} + +/** + * load private key from a ASN1 encoded blob + */ +static gmp_rsa_private_key_t *load(chunk_t blob) +{ + asn1_ctx_t ctx; + chunk_t object; + u_int level; + int objectID = 0; + private_gmp_rsa_private_key_t *this = gmp_rsa_private_key_create_empty(); + + mpz_init(this->n); + mpz_init(this->e); + mpz_init(this->p); + mpz_init(this->q); + mpz_init(this->d); + mpz_init(this->exp1); + mpz_init(this->exp2); + mpz_init(this->coeff); + + asn1_init(&ctx, blob, 0, FALSE, TRUE); + + while (objectID < PRIV_KEY_ROOF) + { + if (!extract_object(privkey_objects, &objectID, &object, &level, &ctx)) + { + chunk_free_randomized(&blob); + destroy(this); + return NULL; + } + switch (objectID) + { + case PRIV_KEY_VERSION: + if (object.len > 0 && *object.ptr != 0) + { + chunk_free_randomized(&blob); + destroy(this); + return NULL; + } + break; + case PRIV_KEY_MODULUS: + mpz_import(this->n, object.len, 1, 1, 1, 0, object.ptr); + break; + case PRIV_KEY_PUB_EXP: + mpz_import(this->e, object.len, 1, 1, 1, 0, object.ptr); + break; + case PRIV_KEY_PRIV_EXP: + mpz_import(this->d, object.len, 1, 1, 1, 0, object.ptr); + break; + case PRIV_KEY_PRIME1: + mpz_import(this->p, object.len, 1, 1, 1, 0, object.ptr); + break; + case PRIV_KEY_PRIME2: + mpz_import(this->q, object.len, 1, 1, 1, 0, object.ptr); + break; + case PRIV_KEY_EXP1: + mpz_import(this->exp1, object.len, 1, 1, 1, 0, object.ptr); + break; + case PRIV_KEY_EXP2: + mpz_import(this->exp2, object.len, 1, 1, 1, 0, object.ptr); + break; + case PRIV_KEY_COEFF: + mpz_import(this->coeff, object.len, 1, 1, 1, 0, object.ptr); + break; + } + objectID++; + } + chunk_free_randomized(&blob); + + this->k = (mpz_sizeinbase(this->n, 2) + 7) / BITS_PER_BYTE; + if (!gmp_rsa_public_key_build_id(this->n, this->e, + &this->keyid, &this->keyid_info)) + { + destroy(this); + return NULL; + } + + if (check(this) != SUCCESS) + { + destroy(this); + return NULL; + } + return &this->public; +} + +typedef struct private_builder_t private_builder_t; +/** + * Builder implementation for key loading/generation + */ +struct private_builder_t { + /** implements the builder interface */ + builder_t public; + /** loaded/generated private key */ + gmp_rsa_private_key_t *key; +}; + +/** + * Implementation of builder_t.build + */ +static gmp_rsa_private_key_t *build(private_builder_t *this) +{ + gmp_rsa_private_key_t *key = this->key; + + free(this); + return key; +} + +/** + * Implementation of builder_t.add + */ +static void add(private_builder_t *this, builder_part_t part, ...) +{ + va_list args; + + if (this->key) + { + DBG1("ignoring surplus build part %N", builder_part_names, part); + return; + } + + switch (part) + { + case BUILD_BLOB_ASN1_DER: + { + va_start(args, part); + this->key = load(va_arg(args, chunk_t)); + va_end(args); + break; + } + case BUILD_KEY_SIZE: + { + va_start(args, part); + this->key = generate(va_arg(args, u_int)); + va_end(args); + break; + } + default: + DBG1("ignoring unsupported build part %N", builder_part_names, part); + break; + } +} + +/** + * Builder construction function + */ +builder_t *gmp_rsa_private_key_builder(key_type_t type) +{ + private_builder_t *this; + + if (type != KEY_RSA) + { + return NULL; + } + + this = malloc_thing(private_builder_t); + + this->key = NULL; + this->public.add = (void(*)(builder_t *this, builder_part_t part, ...))add; + this->public.build = (void*(*)(builder_t *this))build; + + return &this->public; +} + diff --git a/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.h b/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.h new file mode 100644 index 000000000..6f59b2ad2 --- /dev/null +++ b/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2005-2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 gmp_rsa_private_key gmp_rsa_private_key + * @{ @ingroup gmp_p + */ + +#ifndef GMP_RSA_PRIVATE_KEY_H_ +#define GMP_RSA_PRIVATE_KEY_H_ + +#include + +typedef struct gmp_rsa_private_key_t gmp_rsa_private_key_t; + +/** + * Private_key_t implementation of RSA algorithm using libgmp. + */ +struct gmp_rsa_private_key_t { + + /** + * Implements private_key_t interface + */ + private_key_t interface; +}; + +/** + * Create the builder for a private key. + * + * @param type type of the key, must be KEY_RSA + * @return builder instance + */ +builder_t *gmp_rsa_private_key_builder(key_type_t type); + +#endif /*GMP_RSA_PRIVATE_KEY_H_ @}*/ + diff --git a/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c b/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c new file mode 100644 index 000000000..13ced714d --- /dev/null +++ b/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c @@ -0,0 +1,574 @@ +/* + * Copyright (C) 2005-2008 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include +#include +#include +#include +#include + +#include "gmp_rsa_public_key.h" + +#include +#include +#include +#include + +/** + * defined in gmp_rsa_private_key.c + */ +extern chunk_t gmp_mpz_to_asn1(const mpz_t value); + +/** + * ASN.1 definition of a subjectPublicKeyInfo structure + */ +static const asn1Object_t pkinfoObjects[] = { + { 0, "subjectPublicKeyInfo",ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ + { 1, "algorithm", ASN1_EOC, ASN1_RAW }, /* 1 */ + { 1, "subjectPublicKey", ASN1_BIT_STRING, ASN1_NONE }, /* 2 */ + { 2, "RSAPublicKey", ASN1_SEQUENCE, ASN1_RAW }, /* 3 */ +}; +#define PKINFO 0 +#define PKINFO_SUBJECT_PK_ALGORITHM 1 +#define PKINFO_SUBJECT_PK 2 +#define PKINFO_gmp_rsa_public_key 3 +#define PKINFO_ROOF 4 + +/* ASN.1 definition of RSApublicKey */ +static const asn1Object_t pubkeyObjects[] = { + { 0, "RSAPublicKey", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */ + { 1, "modulus", ASN1_INTEGER, ASN1_BODY }, /* 1 */ + { 1, "publicExponent", ASN1_INTEGER, ASN1_BODY }, /* 2 */ +}; + +#define PUB_KEY_gmp_rsa_public_key 0 +#define PUB_KEY_MODULUS 1 +#define PUB_KEY_EXPONENT 2 +#define PUB_KEY_ROOF 3 + +/* ASN.1 definition of digestInfo */ +static const asn1Object_t digestInfoObjects[] = { + { 0, "digestInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */ + { 1, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 1 */ + { 1, "digest", ASN1_OCTET_STRING, ASN1_BODY }, /* 2 */ +}; + +#define DIGEST_INFO 0 +#define DIGEST_INFO_ALGORITHM 1 +#define DIGEST_INFO_DIGEST 2 +#define DIGEST_INFO_ROOF 3 + +typedef struct private_gmp_rsa_public_key_t private_gmp_rsa_public_key_t; + +/** + * Private data structure with signing context. + */ +struct private_gmp_rsa_public_key_t { + /** + * Public interface for this signer. + */ + gmp_rsa_public_key_t public; + + /** + * Public modulus. + */ + mpz_t n; + + /** + * Public exponent. + */ + mpz_t e; + + /** + * Keysize in bytes. + */ + size_t k; + + /** + * Keyid formed as a SHA-1 hash of a publicKeyInfo object + */ + identification_t *keyid_info; + + /** + * Keyid formed as a SHA-1 hash of a publicKey object + */ + identification_t *keyid; + + /** + * reference counter + */ + refcount_t ref; +}; + +/** + * RSAEP algorithm specified in PKCS#1. + */ +static chunk_t rsaep(private_gmp_rsa_public_key_t *this, chunk_t data) +{ + mpz_t m, c; + chunk_t encrypted; + + mpz_init(c); + mpz_init(m); + + mpz_import(m, data.len, 1, 1, 1, 0, data.ptr); + + mpz_powm(c, m, this->e, this->n); + + encrypted.len = this->k; + encrypted.ptr = mpz_export(NULL, NULL, 1, encrypted.len, 1, 0, c); + + mpz_clear(c); + mpz_clear(m); + + return encrypted; +} + +/** + * RSAVP1 algorithm specified in PKCS#1. + */ +static chunk_t rsavp1(private_gmp_rsa_public_key_t *this, chunk_t data) +{ + return rsaep(this, data); +} + +/** + * Verification of an EMPSA PKCS1 signature described in PKCS#1 + */ +static bool verify_emsa_pkcs1_signature(private_gmp_rsa_public_key_t *this, + hash_algorithm_t algorithm, + chunk_t data, chunk_t signature) +{ + chunk_t em_ori, em; + bool res = FALSE; + + /* remove any preceding 0-bytes from signature */ + while (signature.len && *(signature.ptr) == 0x00) + { + signature.len -= 1; + signature.ptr++; + } + + if (signature.len > this->k) + { + return INVALID_ARG; + } + + /* unpack signature */ + em_ori = em = rsavp1(this, signature); + + /* result should look like this: + * EM = 0x00 || 0x01 || PS || 0x00 || T. + * PS = 0xFF padding, with length to fill em + * T = oid || hash + */ + + /* check magic bytes */ + if (*(em.ptr) != 0x00 || *(em.ptr+1) != 0x01) + { + goto end; + } + em.ptr += 2; + em.len -= 2; + + /* find magic 0x00 */ + while (em.len > 0) + { + if (*em.ptr == 0x00) + { + /* found magic byte, stop */ + em.ptr++; + em.len--; + break; + } + else if (*em.ptr != 0xFF) + { + /* bad padding, decryption failed ?!*/ + goto end; + } + em.ptr++; + em.len--; + } + + if (em.len == 0) + { + /* no digestInfo found */ + goto end; + } + + /* parse ASN.1-based digestInfo */ + { + asn1_ctx_t ctx; + chunk_t object; + u_int level; + int objectID = 0; + hash_algorithm_t hash_algorithm = HASH_UNKNOWN; + + asn1_init(&ctx, em, 0, FALSE, FALSE); + + while (objectID < DIGEST_INFO_ROOF) + { + if (!extract_object(digestInfoObjects, &objectID, &object, &level, &ctx)) + { + goto end; + } + switch (objectID) + { + case DIGEST_INFO: + { + if (em.len > object.len) + { + DBG1("digestInfo field in signature is followed by %u surplus bytes", + em.len - object.len); + goto end; + } + break; + } + case DIGEST_INFO_ALGORITHM: + { + int hash_oid = parse_algorithmIdentifier(object, level+1, NULL); + + hash_algorithm = hasher_algorithm_from_oid(hash_oid); + if (hash_algorithm == HASH_UNKNOWN || + (algorithm != HASH_UNKNOWN && hash_algorithm != algorithm)) + { + DBG1("wrong hash algorithm used in signature"); + goto end; + } + break; + } + case DIGEST_INFO_DIGEST: + { + chunk_t hash; + hasher_t *hasher; + + hasher = lib->crypto->create_hasher(lib->crypto, hash_algorithm); + if (hasher == NULL) + { + DBG1("hash algorithm %N not supported", + hash_algorithm_names, hash_algorithm); + goto end; + } + + if (object.len != hasher->get_hash_size(hasher)) + { + DBG1("hash size in signature is %u bytes instead of %u " + "bytes", object.len, hasher->get_hash_size(hasher)); + hasher->destroy(hasher); + goto end; + } + + /* build our own hash and compare */ + hasher->allocate_hash(hasher, data, &hash); + hasher->destroy(hasher); + res = memeq(object.ptr, hash.ptr, hash.len); + free(hash.ptr); + break; + } + default: + break; + } + objectID++; + } + } + +end: + free(em_ori.ptr); + return res; +} + +/** + * Implementation of public_key_t.get_type. + */ +static key_type_t get_type(private_gmp_rsa_public_key_t *this) +{ + return KEY_RSA; +} + +/** + * Implementation of public_key_t.verify. + */ +static bool verify(private_gmp_rsa_public_key_t *this, signature_scheme_t scheme, + chunk_t data, chunk_t signature) +{ + switch (scheme) + { + case SIGN_DEFAULT: /* default is EMSA-PKCS1 using included OID */ + return verify_emsa_pkcs1_signature(this, HASH_UNKNOWN, data, signature); + case SIGN_RSA_EMSA_PKCS1_MD5: + return verify_emsa_pkcs1_signature(this, HASH_MD5, data, signature); + case SIGN_RSA_EMSA_PKCS1_SHA1: + return verify_emsa_pkcs1_signature(this, HASH_SHA1, data, signature); + case SIGN_RSA_EMSA_PKCS1_SHA256: + return verify_emsa_pkcs1_signature(this, HASH_SHA256, data, signature); + case SIGN_RSA_EMSA_PKCS1_SHA384: + return verify_emsa_pkcs1_signature(this, HASH_SHA384, data, signature); + case SIGN_RSA_EMSA_PKCS1_SHA512: + return verify_emsa_pkcs1_signature(this, HASH_SHA512, data, signature); + default: + DBG1("signature scheme %N not supported in RSA", + signature_scheme_names, scheme); + return FALSE; + } +} + +/** + * Implementation of public_key_t.get_keysize. + */ +static bool encrypt(private_gmp_rsa_public_key_t *this, chunk_t crypto, chunk_t *plain) +{ + DBG1("RSA public key encryption not implemented"); + return FALSE; +} + +/** + * Implementation of public_key_t.get_keysize. + */ +static size_t get_keysize(private_gmp_rsa_public_key_t *this) +{ + return this->k; +} + +/** + * Implementation of public_key_t.get_id. + */ +static identification_t *get_id(private_gmp_rsa_public_key_t *this, + id_type_t type) +{ + switch (type) + { + case ID_PUBKEY_INFO_SHA1: + return this->keyid_info; + case ID_PUBKEY_SHA1: + return this->keyid; + default: + return NULL; + } +} + +/* + * Implementation of public_key_t.get_encoding. + */ +static chunk_t get_encoding(private_gmp_rsa_public_key_t *this) +{ + return asn1_wrap(ASN1_SEQUENCE, "mm", + gmp_mpz_to_asn1(this->n), + gmp_mpz_to_asn1(this->e)); +} + +/** + * Implementation of public_key_t.get_ref. + */ +static private_gmp_rsa_public_key_t* get_ref(private_gmp_rsa_public_key_t *this) +{ + ref_get(&this->ref); + return this; +} + +/** + * Implementation of gmp_rsa_public_key.destroy. + */ +static void destroy(private_gmp_rsa_public_key_t *this) +{ + if (ref_put(&this->ref)) + { + mpz_clear(this->n); + mpz_clear(this->e); + DESTROY_IF(this->keyid); + DESTROY_IF(this->keyid_info); + free(this); + } +} + +/** + * Generic private constructor + */ +static private_gmp_rsa_public_key_t *gmp_rsa_public_key_create_empty() +{ + private_gmp_rsa_public_key_t *this = malloc_thing(private_gmp_rsa_public_key_t); + + this->public.interface.get_type = (key_type_t (*)(public_key_t *this))get_type; + this->public.interface.verify = (bool (*)(public_key_t *this, signature_scheme_t scheme, chunk_t data, chunk_t signature))verify; + this->public.interface.encrypt = (bool (*)(public_key_t *this, chunk_t crypto, chunk_t *plain))encrypt; + this->public.interface.get_keysize = (size_t (*) (public_key_t *this))get_keysize; + this->public.interface.get_id = (identification_t* (*) (public_key_t *this,id_type_t))get_id; + this->public.interface.get_encoding = (chunk_t(*)(public_key_t*))get_encoding; + this->public.interface.get_ref = (public_key_t* (*)(public_key_t *this))get_ref; + this->public.interface.destroy = (void (*)(public_key_t *this))destroy; + + this->keyid = NULL; + this->keyid_info = NULL; + this->ref = 1; + + return this; +} + +/** + * Build the RSA key identifier from n and e using SHA1 hashed publicKey(Info). + * Also used in rsa_private_key.c. + */ +bool gmp_rsa_public_key_build_id(mpz_t n, mpz_t e, identification_t **keyid, + identification_t **keyid_info) +{ + chunk_t publicKeyInfo, publicKey, hash; + hasher_t *hasher; + + hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); + if (hasher == NULL) + { + DBG1("SHA1 hash algorithm not supported, unable to use RSA"); + return FALSE; + } + publicKey = asn1_wrap(ASN1_SEQUENCE, "mm", + gmp_mpz_to_asn1(n), + gmp_mpz_to_asn1(e)); + hasher->allocate_hash(hasher, publicKey, &hash); + *keyid = identification_create_from_encoding(ID_PUBKEY_SHA1, hash); + chunk_free(&hash); + + publicKeyInfo = asn1_wrap(ASN1_SEQUENCE, "cm", + asn1_algorithmIdentifier(OID_RSA_ENCRYPTION), + asn1_bitstring("m", publicKey)); + hasher->allocate_hash(hasher, publicKeyInfo, &hash); + *keyid_info = identification_create_from_encoding(ID_PUBKEY_INFO_SHA1, hash); + chunk_free(&hash); + + hasher->destroy(hasher); + chunk_free(&publicKeyInfo); + + return TRUE; +} + +/** + * Load a public key from an ASN1 encoded blob + */ +static gmp_rsa_public_key_t *load(chunk_t blob) +{ + asn1_ctx_t ctx; + chunk_t object; + u_int level; + int objectID = 0; + private_gmp_rsa_public_key_t *this = gmp_rsa_public_key_create_empty(); + + mpz_init(this->n); + mpz_init(this->e); + + asn1_init(&ctx, blob, 0, FALSE, FALSE); + + while (objectID < PUB_KEY_ROOF) + { + if (!extract_object(pubkeyObjects, &objectID, &object, &level, &ctx)) + { + free(blob.ptr); + destroy(this); + return NULL; + } + switch (objectID) + { + case PUB_KEY_MODULUS: + mpz_import(this->n, object.len, 1, 1, 1, 0, object.ptr); + break; + case PUB_KEY_EXPONENT: + mpz_import(this->e, object.len, 1, 1, 1, 0, object.ptr); + break; + } + objectID++; + } + free(blob.ptr); + this->k = (mpz_sizeinbase(this->n, 2) + 7) / 8; + if (!gmp_rsa_public_key_build_id(this->n, this->e, + &this->keyid, &this->keyid_info)) + { + destroy(this); + return NULL; + } + return &this->public; +} + + +typedef struct private_builder_t private_builder_t; +/** + * Builder implementation for key loading + */ +struct private_builder_t { + /** implements the builder interface */ + builder_t public; + /** loaded public key */ + gmp_rsa_public_key_t *key; +}; + +/** + * Implementation of builder_t.build + */ +static gmp_rsa_public_key_t *build(private_builder_t *this) +{ + gmp_rsa_public_key_t *key = this->key; + + free(this); + return key; +} + +/** + * Implementation of builder_t.add + */ +static void add(private_builder_t *this, builder_part_t part, ...) +{ + va_list args; + + if (this->key) + { + DBG1("ignoring surplus build part %N", builder_part_names, part); + return; + } + + switch (part) + { + case BUILD_BLOB_ASN1_DER: + { + va_start(args, part); + this->key = load(va_arg(args, chunk_t)); + va_end(args); + break; + } + default: + DBG1("ignoring unsupported build part %N", builder_part_names, part); + break; + } +} + +/** + * Builder construction function + */ +builder_t *gmp_rsa_public_key_builder(key_type_t type) +{ + private_builder_t *this; + + if (type != KEY_RSA) + { + return NULL; + } + + this = malloc_thing(private_builder_t); + + this->key = NULL; + this->public.add = (void(*)(builder_t *this, builder_part_t part, ...))add; + this->public.build = (void*(*)(builder_t *this))build; + + return &this->public; +} + diff --git a/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.h b/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.h new file mode 100644 index 000000000..e471cd067 --- /dev/null +++ b/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2005-2008 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 gmp_rsa_public_key gmp_rsa_public_key + * @{ @ingroup gmp_p + */ + +#ifndef GMP_RSA_PUBLIC_KEY_H_ +#define GMP_RSA_PUBLIC_KEY_H_ + +typedef struct gmp_rsa_public_key_t gmp_rsa_public_key_t; + +#include + +/** + * public_key_t implementation of RSA algorithm using libgmp. + */ +struct gmp_rsa_public_key_t { + + /** + * Implements the public_key_t interface + */ + public_key_t interface; +}; + +/** + * Create the builder for a public key. + * + * @param type type of the key, must be KEY_RSA + * @return builder instance + */ +builder_t *gmp_rsa_public_key_builder(key_type_t type); + +#endif /*GMP_RSA_PUBLIC_KEY_H_ @}*/ diff --git a/src/libstrongswan/plugins/hmac/Makefile.am b/src/libstrongswan/plugins/hmac/Makefile.am new file mode 100644 index 000000000..89e0638f3 --- /dev/null +++ b/src/libstrongswan/plugins/hmac/Makefile.am @@ -0,0 +1,11 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan + +AM_CFLAGS = -rdynamic + +plugin_LTLIBRARIES = libstrongswan-hmac.la + +libstrongswan_hmac_la_SOURCES = hmac_plugin.h hmac_plugin.c hmac.h hmac.c \ + hmac_prf.h hmac_prf.c hmac_signer.h hmac_signer.c +libstrongswan_hmac_la_LDFLAGS = -module + diff --git a/src/libstrongswan/plugins/hmac/hmac.c b/src/libstrongswan/plugins/hmac/hmac.c new file mode 100644 index 000000000..2b41bf4aa --- /dev/null +++ b/src/libstrongswan/plugins/hmac/hmac.c @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General hmac License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 hmac License + * for more details. + * + * $Id$ + */ + +#include + +#include "hmac.h" + + +typedef struct private_hmac_t private_hmac_t; + +/** + * Private data of a hmac_t object. + * + * The variable names are the same as in the RFC. + */ +struct private_hmac_t { + /** + * Public hmac_t interface. + */ + hmac_t hmac; + + /** + * Block size, as in RFC. + */ + u_int8_t b; + + /** + * Hash function. + */ + hasher_t *h; + + /** + * Previously xor'ed key using opad. + */ + chunk_t opaded_key; + + /** + * Previously xor'ed key using ipad. + */ + chunk_t ipaded_key; +}; + +/** + * Implementation of hmac_t.get_mac. + */ +static void get_mac(private_hmac_t *this, chunk_t data, u_int8_t *out) +{ + /* H(K XOR opad, H(K XOR ipad, text)) + * + * if out is NULL, we append text to the inner hash. + * else, we complete the inner and do the outer. + * + */ + + u_int8_t buffer[this->h->get_hash_size(this->h)]; + chunk_t inner; + + if (out == NULL) + { + /* append data to inner */ + this->h->get_hash(this->h, data, NULL); + } + else + { + /* append and do outer hash */ + inner.ptr = buffer; + inner.len = this->h->get_hash_size(this->h); + + /* complete inner */ + this->h->get_hash(this->h, data, buffer); + + /* do outer */ + this->h->get_hash(this->h, this->opaded_key, NULL); + this->h->get_hash(this->h, inner, out); + + /* reinit for next call */ + this->h->get_hash(this->h, this->ipaded_key, NULL); + } +} + +/** + * Implementation of hmac_t.allocate_mac. + */ +static void allocate_mac(private_hmac_t *this, chunk_t data, chunk_t *out) +{ + /* allocate space and use get_mac */ + if (out == NULL) + { + /* append mode */ + this->hmac.get_mac(&(this->hmac), data, NULL); + } + else + { + out->len = this->h->get_hash_size(this->h); + out->ptr = malloc(out->len); + this->hmac.get_mac(&(this->hmac), data, out->ptr); + } +} + +/** + * Implementation of hmac_t.get_block_size. + */ +static size_t get_block_size(private_hmac_t *this) +{ + return this->h->get_hash_size(this->h); +} + +/** + * Implementation of hmac_t.set_key. + */ +static void set_key(private_hmac_t *this, chunk_t key) +{ + int i; + u_int8_t buffer[this->b]; + + memset(buffer, 0, this->b); + + if (key.len > this->b) + { + /* if key is too long, it will be hashed */ + this->h->get_hash(this->h, key, buffer); + } + else + { + /* if not, just copy it in our pre-padded k */ + memcpy(buffer, key.ptr, key.len); + } + + /* apply ipad and opad to key */ + for (i = 0; i < this->b; i++) + { + this->ipaded_key.ptr[i] = buffer[i] ^ 0x36; + this->opaded_key.ptr[i] = buffer[i] ^ 0x5C; + } + + /* begin hashing of inner pad */ + this->h->reset(this->h); + this->h->get_hash(this->h, this->ipaded_key, NULL); +} + +/** + * Implementation of hmac_t.destroy. + */ +static void destroy(private_hmac_t *this) +{ + this->h->destroy(this->h); + free(this->opaded_key.ptr); + free(this->ipaded_key.ptr); + free(this); +} + +/* + * Described in header + */ +hmac_t *hmac_create(hash_algorithm_t hash_algorithm) +{ + private_hmac_t *this = malloc_thing(private_hmac_t); + + /* set hmac_t methods */ + this->hmac.get_mac = (void (*)(hmac_t *,chunk_t,u_int8_t*))get_mac; + this->hmac.allocate_mac = (void (*)(hmac_t *,chunk_t,chunk_t*))allocate_mac; + this->hmac.get_block_size = (size_t (*)(hmac_t *))get_block_size; + this->hmac.set_key = (void (*)(hmac_t *,chunk_t))set_key; + this->hmac.destroy = (void (*)(hmac_t *))destroy; + + /* set b, according to hasher */ + switch (hash_algorithm) + { + case HASH_SHA1: + case HASH_MD5: + case HASH_SHA256: + this->b = 64; + break; + case HASH_SHA384: + case HASH_SHA512: + this->b = 128; + break; + default: + free(this); + return NULL; + } + + /* build the hasher */ + this->h = lib->crypto->create_hasher(lib->crypto, hash_algorithm); + if (this->h == NULL) + { + free(this); + return NULL; + } + + /* build ipad and opad */ + this->opaded_key.ptr = malloc(this->b); + this->opaded_key.len = this->b; + + this->ipaded_key.ptr = malloc(this->b); + this->ipaded_key.len = this->b; + + return &(this->hmac); +} diff --git a/src/libstrongswan/plugins/hmac/hmac.h b/src/libstrongswan/plugins/hmac/hmac.h new file mode 100644 index 000000000..5f266e133 --- /dev/null +++ b/src/libstrongswan/plugins/hmac/hmac.h @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2005-2008 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 hmac hmac + * @{ @ingroup hmac_p + */ + +#ifndef HMAC_H_ +#define HMAC_H_ + +typedef struct hmac_t hmac_t; + +#include + +/** + * Message authentication using hash functions. + * + * This class implements the message authenticaion algorithm + * described in RFC2104. It uses a hash function, wich must + * be implemented as a hasher_t class. + */ +struct hmac_t { + /** + * Generate message authentication code. + * + * If buffer is NULL, no result is given back. A next call will + * append the data to already supplied data. If buffer is not NULL, + * the mac of all apended data is calculated, returned and the + * state of the hmac_t is reseted. + * + * @param data chunk of data to authenticate + * @param buffer pointer where the generated bytes will be written + */ + void (*get_mac) (hmac_t *this, chunk_t data, u_int8_t *buffer); + + /** + * Generates message authentication code and allocate space for them. + * + * If chunk is NULL, no result is given back. A next call will + * append the data to already supplied. If chunk is not NULL, + * the mac of all apended data is calculated, returned and the + * state of the hmac_t reset; + * + * @param data chunk of data to authenticate + * @param chunk chunk which will hold generated bytes + */ + void (*allocate_mac) (hmac_t *this, chunk_t data, chunk_t *chunk); + + /** + * Get the block size of this hmac_t object. + * + * @return block size in bytes + */ + size_t (*get_block_size) (hmac_t *this); + + /** + * Set the key for this hmac_t object. + * + * Any key length is accepted. + * + * @param key key to set + */ + void (*set_key) (hmac_t *this, chunk_t key); + + /** + * Destroys a hmac_t object. + */ + void (*destroy) (hmac_t *this); +}; + +/** + * Creates a new hmac_t object. + * + * @param hash_algorithm hash algorithm to use + * @return hmac_t object, NULL if not supported + */ +hmac_t *hmac_create(hash_algorithm_t hash_algorithm); + +#endif /*HMAC_H_ @}*/ diff --git a/src/libstrongswan/plugins/hmac/hmac_plugin.c b/src/libstrongswan/plugins/hmac/hmac_plugin.c new file mode 100644 index 000000000..246fbb031 --- /dev/null +++ b/src/libstrongswan/plugins/hmac/hmac_plugin.c @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "hmac_plugin.h" + +#include +#include "hmac_signer.h" +#include "hmac_prf.h" + +typedef struct private_hmac_plugin_t private_hmac_plugin_t; + +/** + * private data of hmac_plugin + */ +struct private_hmac_plugin_t { + + /** + * public functions + */ + hmac_plugin_t public; +}; + +/** + * Implementation of hmac_plugin_t.hmactroy + */ +static void destroy(private_hmac_plugin_t *this) +{ + lib->crypto->remove_prf(lib->crypto, + (prf_constructor_t)hmac_prf_create); + lib->crypto->remove_signer(lib->crypto, + (signer_constructor_t)hmac_signer_create); + free(this); +} + +/* + * see header file + */ +plugin_t *plugin_create() +{ + private_hmac_plugin_t *this = malloc_thing(private_hmac_plugin_t); + + this->public.plugin.destroy = (void(*)(plugin_t*))destroy; + + lib->crypto->add_prf(lib->crypto, PRF_HMAC_MD5, + (prf_constructor_t)hmac_prf_create); + lib->crypto->add_prf(lib->crypto, PRF_HMAC_SHA1, + (prf_constructor_t)hmac_prf_create); + lib->crypto->add_prf(lib->crypto, PRF_HMAC_SHA2_256, + (prf_constructor_t)hmac_prf_create); + lib->crypto->add_prf(lib->crypto, PRF_HMAC_SHA2_384, + (prf_constructor_t)hmac_prf_create); + lib->crypto->add_prf(lib->crypto, PRF_HMAC_SHA2_512, + (prf_constructor_t)hmac_prf_create); + + lib->crypto->add_signer(lib->crypto, AUTH_HMAC_MD5_96, + (signer_constructor_t)hmac_signer_create); + lib->crypto->add_signer(lib->crypto, AUTH_HMAC_SHA1_96, + (signer_constructor_t)hmac_signer_create); + lib->crypto->add_signer(lib->crypto, AUTH_HMAC_SHA1_128, + (signer_constructor_t)hmac_signer_create); + lib->crypto->add_signer(lib->crypto, AUTH_HMAC_SHA2_256_128, + (signer_constructor_t)hmac_signer_create); + lib->crypto->add_signer(lib->crypto, AUTH_HMAC_SHA2_384_192, + (signer_constructor_t)hmac_signer_create); + lib->crypto->add_signer(lib->crypto, AUTH_HMAC_SHA2_512_256, + (signer_constructor_t)hmac_signer_create); + + return &this->public.plugin; +} + diff --git a/src/libstrongswan/plugins/hmac/hmac_plugin.h b/src/libstrongswan/plugins/hmac/hmac_plugin.h new file mode 100644 index 000000000..55ba0b5f4 --- /dev/null +++ b/src/libstrongswan/plugins/hmac/hmac_plugin.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 hmac_p hmac + * @ingroup plugins + * + * @defgroup hmac_plugin hmac_plugin + * @{ @ingroup hmac_p + */ + +#ifndef HMAC_PLUGIN_H_ +#define HMAC_PLUGIN_H_ + +#include + +typedef struct hmac_plugin_t hmac_plugin_t; + +/** + * Plugin implementing HMAC algorithm to prvoide hash based PRF and signers. + */ +struct hmac_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +/** + * Create a hmac_plugin instance. + */ +plugin_t *plugin_create(); + +#endif /* HMAC_PLUGIN_H_ @}*/ diff --git a/src/libstrongswan/plugins/hmac/hmac_prf.c b/src/libstrongswan/plugins/hmac/hmac_prf.c new file mode 100644 index 000000000..02159bb1b --- /dev/null +++ b/src/libstrongswan/plugins/hmac/hmac_prf.c @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "hmac_prf.h" + +#include "hmac.h" + + +typedef struct private_hmac_prf_t private_hmac_prf_t; + +/** + * Private data of a hma_prf_t object. + */ +struct private_hmac_prf_t { + /** + * Public hmac_prf_t interface. + */ + hmac_prf_t public; + + /** + * Hmac to use for generation. + */ + hmac_t *hmac; +}; + +/** + * Implementation of prf_t.get_bytes. + */ +static void get_bytes(private_hmac_prf_t *this, chunk_t seed, u_int8_t *buffer) +{ + this->hmac->get_mac(this->hmac, seed, buffer); +} + +/** + * Implementation of prf_t.allocate_bytes. + */ +static void allocate_bytes(private_hmac_prf_t *this, chunk_t seed, chunk_t *chunk) +{ + this->hmac->allocate_mac(this->hmac, seed, chunk); +} + +/** + * Implementation of prf_t.get_block_size. + */ +static size_t get_block_size(private_hmac_prf_t *this) +{ + return this->hmac->get_block_size(this->hmac); +} + +/** + * Implementation of prf_t.get_block_size. + */ +static size_t get_key_size(private_hmac_prf_t *this) +{ + /* for HMAC prfs, IKEv2 uses block size as key size */ + return this->hmac->get_block_size(this->hmac); +} + +/** + * Implementation of prf_t.set_key. + */ +static void set_key(private_hmac_prf_t *this, chunk_t key) +{ + this->hmac->set_key(this->hmac, key); +} + +/** + * Implementation of prf_t.destroy. + */ +static void destroy(private_hmac_prf_t *this) +{ + this->hmac->destroy(this->hmac); + free(this); +} + +/* + * Described in header. + */ +hmac_prf_t *hmac_prf_create(pseudo_random_function_t algo) +{ + private_hmac_prf_t *this; + hash_algorithm_t hash; + + switch (algo) + { + case PRF_HMAC_SHA1: + hash = HASH_SHA1; + break; + case PRF_HMAC_MD5: + hash = HASH_MD5; + break; + case PRF_HMAC_SHA2_256: + hash = HASH_SHA256; + break; + case PRF_HMAC_SHA2_384: + hash = HASH_SHA384; + break; + case PRF_HMAC_SHA2_512: + hash = HASH_SHA512; + break; + default: + return NULL; + } + + this = malloc_thing(private_hmac_prf_t); + this->hmac = hmac_create(hash); + if (this->hmac == NULL) + { + free(this); + return NULL; + } + + this->public.prf_interface.get_bytes = (void (*) (prf_t *,chunk_t,u_int8_t*))get_bytes; + this->public.prf_interface.allocate_bytes = (void (*) (prf_t*,chunk_t,chunk_t*))allocate_bytes; + this->public.prf_interface.get_block_size = (size_t (*) (prf_t*))get_block_size; + this->public.prf_interface.get_key_size = (size_t (*) (prf_t*))get_key_size; + this->public.prf_interface.set_key = (void (*) (prf_t *,chunk_t))set_key; + this->public.prf_interface.destroy = (void (*) (prf_t *))destroy; + + return &(this->public); +} + diff --git a/src/libstrongswan/plugins/hmac/hmac_prf.h b/src/libstrongswan/plugins/hmac/hmac_prf.h new file mode 100644 index 000000000..46d05f03a --- /dev/null +++ b/src/libstrongswan/plugins/hmac/hmac_prf.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2008 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 hmac_prf hmac_prf + * @{ @ingroup hmac_p + */ + +#ifndef PRF_HMAC_H_ +#define PRF_HMAC_H_ + +typedef struct hmac_prf_t hmac_prf_t; + +#include + +/** + * Implementation of prf_t interface using the HMAC algorithm. + * + * This simply wraps a hmac_t in a prf_t. More a question of + * interface matching. + */ +struct hmac_prf_t { + + /** + * Generic prf_t interface for this hmac_prf_t class. + */ + prf_t prf_interface; +}; + +/** + * Creates a new hmac_prf_t object. + * + * @param algo algorithm to implement + * @return hmac_prf_t object, NULL if hash not supported + */ +hmac_prf_t *hmac_prf_create(pseudo_random_function_t algo); + +#endif /*PRF_HMAC_SHA1_H_ @}*/ diff --git a/src/libstrongswan/plugins/hmac/hmac_signer.c b/src/libstrongswan/plugins/hmac/hmac_signer.c new file mode 100644 index 000000000..1b6f80d7b --- /dev/null +++ b/src/libstrongswan/plugins/hmac/hmac_signer.c @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2005-2008 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include + +#include "hmac_signer.h" +#include "hmac.h" + +typedef struct private_hmac_signer_t private_hmac_signer_t; + +/** + * Private data structure with signing context. + */ +struct private_hmac_signer_t { + /** + * Public interface of hmac_signer_t. + */ + hmac_signer_t public; + + /** + * Assigned hmac function. + */ + hmac_t *hmac; + + /** + * Block size (truncation of HMAC Hash) + */ + size_t block_size; +}; + +/** + * Implementation of signer_t.get_signature. + */ +static void get_signature(private_hmac_signer_t *this, + chunk_t data, u_int8_t *buffer) +{ + if (buffer == NULL) + { /* append mode */ + this->hmac->get_mac(this->hmac, data, NULL); + } + else + { + u_int8_t mac[this->hmac->get_block_size(this->hmac)]; + + this->hmac->get_mac(this->hmac, data, mac); + memcpy(buffer, mac, this->block_size); + } +} + +/** + * Implementation of signer_t.allocate_signature. + */ +static void allocate_signature (private_hmac_signer_t *this, + chunk_t data, chunk_t *chunk) +{ + if (chunk == NULL) + { /* append mode */ + this->hmac->get_mac(this->hmac, data, NULL); + } + else + { + u_int8_t mac[this->hmac->get_block_size(this->hmac)]; + + this->hmac->get_mac(this->hmac, data, mac); + + chunk->ptr = malloc(this->block_size); + chunk->len = this->block_size; + + memcpy(chunk->ptr, mac, this->block_size); + } +} + +/** + * Implementation of signer_t.verify_signature. + */ +static bool verify_signature(private_hmac_signer_t *this, + chunk_t data, chunk_t signature) +{ + u_int8_t mac[this->hmac->get_block_size(this->hmac)]; + + this->hmac->get_mac(this->hmac, data, mac); + + if (signature.len != this->block_size) + { + return FALSE; + } + return memeq(signature.ptr, mac, this->block_size); +} + +/** + * Implementation of signer_t.get_key_size. + */ +static size_t get_key_size(private_hmac_signer_t *this) +{ + return this->hmac->get_block_size(this->hmac); +} + +/** + * Implementation of signer_t.get_block_size. + */ +static size_t get_block_size(private_hmac_signer_t *this) +{ + return this->block_size; +} + +/** + * Implementation of signer_t.set_key. + */ +static void set_key(private_hmac_signer_t *this, chunk_t key) +{ + this->hmac->set_key(this->hmac, key); +} + +/** + * Implementation of signer_t.destroy. + */ +static status_t destroy(private_hmac_signer_t *this) +{ + this->hmac->destroy(this->hmac); + free(this); + return SUCCESS; +} + +/* + * Described in header + */ +hmac_signer_t *hmac_signer_create(integrity_algorithm_t algo) +{ + private_hmac_signer_t *this; + size_t trunc; + hash_algorithm_t hash; + + switch (algo) + { + case AUTH_HMAC_SHA1_96: + hash = HASH_SHA1; + trunc = 12; + break; + case AUTH_HMAC_SHA1_128: + hash = HASH_SHA1; + trunc = 16; + break; + case AUTH_HMAC_MD5_96: + hash = HASH_MD5; + trunc = 12; + break; + case AUTH_HMAC_SHA2_256_128: + hash = HASH_SHA256; + trunc = 16; + break; + case AUTH_HMAC_SHA2_384_192: + hash = HASH_SHA384; + trunc = 24; + break; + case AUTH_HMAC_SHA2_512_256: + hash = HASH_SHA512; + trunc = 32; + break; + default: + return NULL; + } + + this = malloc_thing(private_hmac_signer_t); + this->hmac = hmac_create(hash); + if (this->hmac == NULL) + { + free(this); + return NULL; + } + /* prevent invalid truncation */ + this->block_size = min(trunc, this->hmac->get_block_size(this->hmac)); + + /* interface functions */ + this->public.signer_interface.get_signature = (void (*) (signer_t*, chunk_t, u_int8_t*))get_signature; + this->public.signer_interface.allocate_signature = (void (*) (signer_t*, chunk_t, chunk_t*))allocate_signature; + this->public.signer_interface.verify_signature = (bool (*) (signer_t*, chunk_t, chunk_t))verify_signature; + this->public.signer_interface.get_key_size = (size_t (*) (signer_t*))get_key_size; + this->public.signer_interface.get_block_size = (size_t (*) (signer_t*))get_block_size; + this->public.signer_interface.set_key = (void (*) (signer_t*,chunk_t))set_key; + this->public.signer_interface.destroy = (void (*) (signer_t*))destroy; + + return &(this->public); +} + diff --git a/src/libstrongswan/plugins/hmac/hmac_signer.h b/src/libstrongswan/plugins/hmac/hmac_signer.h new file mode 100644 index 000000000..969f482e7 --- /dev/null +++ b/src/libstrongswan/plugins/hmac/hmac_signer.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2005-2008 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 hmac_signer hmac_signer + * @{ @ingroup hmac_p + */ + +#ifndef HMAC_SIGNER_H_ +#define HMAC_SIGNER_H_ + +typedef struct hmac_signer_t hmac_signer_t; + +#include + +/** + * Implementation of signer_t interface using HMAC. + * + * HMAC uses a standard hash function implemented in a hasher_t to build a MAC. + */ +struct hmac_signer_t { + + /** + * generic signer_t interface for this signer + */ + signer_t signer_interface; +}; + +/** + * Creates a new hmac_signer_t. + * + * HMAC signatures are often truncated to shorten them to a more usable, but + * still secure enough length. + * Block size must be equal or smaller then the hash algorithms + * hash. + * + * @param algo algorithm to implement + * @return hmac_signer_t, NULL if not supported + */ +hmac_signer_t *hmac_signer_create(integrity_algorithm_t algo); + +#endif /*HMAC_SIGNER_H_ @}*/ diff --git a/src/libstrongswan/plugins/ldap/Makefile.am b/src/libstrongswan/plugins/ldap/Makefile.am new file mode 100644 index 000000000..ac6b4be00 --- /dev/null +++ b/src/libstrongswan/plugins/ldap/Makefile.am @@ -0,0 +1,11 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan + +AM_CFLAGS = -rdynamic + +plugin_LTLIBRARIES = libstrongswan-ldap.la + +libstrongswan_ldap_la_SOURCES = ldap_plugin.h ldap_plugin.c ldap_fetcher.h ldap_fetcher.c +libstrongswan_ldap_la_LDFLAGS = -module +libstrongswan_ldap_la_LIBADD = -lldap -llber + diff --git a/src/libstrongswan/plugins/ldap/ldap_fetcher.c b/src/libstrongswan/plugins/ldap/ldap_fetcher.c new file mode 100644 index 000000000..501927d33 --- /dev/null +++ b/src/libstrongswan/plugins/ldap/ldap_fetcher.c @@ -0,0 +1,213 @@ +/* + * Copyright (C) 2008 Martin Willi + * Copyright (C) 2007 Andreas Steffen + * 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 . + * + * 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. + * + * $Id$ + */ + +#ifndef LDAP_DEPRECATED +#define LDAP_DEPRECATED 1 +#endif /* LDAP_DEPRECATED */ +#include + +#include + +#include +#include + +#include "ldap_fetcher.h" + +#define DEFAULT_TIMEOUT 10 + +typedef struct private_ldap_fetcher_t private_ldap_fetcher_t; + +/** + * Private Data of a ldap_fetcher_t object. + */ +struct private_ldap_fetcher_t { + /** + * Public data + */ + ldap_fetcher_t public; + + /** + * timeout to use for fetches + */ + u_int timeout; +}; + +/** + * Parses the result returned by an ldap query + */ +static bool parse(LDAP *ldap, LDAPMessage *result, chunk_t *response) +{ + LDAPMessage *entry = ldap_first_entry(ldap, result); + bool success = FALSE; + + if (entry) + { + BerElement *ber = NULL; + char *attr; + + attr = ldap_first_attribute(ldap, entry, &ber); + if (attr) + { + struct berval **values = ldap_get_values_len(ldap, entry, attr); + + if (values) + { + if (values[0]) + { + *response = chunk_alloc(values[0]->bv_len); + memcpy(response->ptr, values[0]->bv_val, response->len); + success = TRUE; + } + else + { + DBG1("LDAP response contains no values"); + } + ldap_value_free_len(values); + } + else + { + DBG1("getting LDAP values failed: %s", + ldap_err2string(ldap_result2error(ldap, entry, 0))); + } + ldap_memfree(attr); + } + else + { + DBG1("finding LDAP attributes failed: %s", + ldap_err2string(ldap_result2error(ldap, entry, 0))); + } + ber_free(ber, 0); + } + else + { + DBG1("finding first LDAP entry failed: %s", + ldap_err2string(ldap_result2error(ldap, entry, 0))); + } + return success; +} + + +static status_t fetch(private_ldap_fetcher_t *this, char *url, + chunk_t *result, va_list args) +{ + LDAP *ldap; + LDAPURLDesc *lurl; + LDAPMessage *msg; + int res; + int ldap_version = LDAP_VERSION3; + struct timeval timeout; + status_t status = FAILED; + + if (!strneq(url, "ldap", 4)) + { + return NOT_SUPPORTED; + } + if (ldap_url_parse(url, &lurl) != LDAP_SUCCESS) + { + return NOT_SUPPORTED; + } + ldap = ldap_init(lurl->lud_host, lurl->lud_port); + if (ldap == NULL) + { + DBG1("LDAP initialization failed: %s", strerror(errno)); + ldap_free_urldesc(lurl); + return FAILED; + } + + timeout.tv_sec = this->timeout; + timeout.tv_usec = 0; + + ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION, &ldap_version); + ldap_set_option(ldap, LDAP_OPT_NETWORK_TIMEOUT, &timeout); + + DBG1("sending LDAP request to '%s'...", url); + + res = ldap_simple_bind_s(ldap, NULL, NULL); + if (res == LDAP_SUCCESS) + { + res = ldap_search_st(ldap, lurl->lud_dn, lurl->lud_scope, + lurl->lud_filter, lurl->lud_attrs, + 0, &timeout, &msg); + + if (res == LDAP_SUCCESS) + { + if (parse(ldap, msg, result)) + { + status = SUCCESS; + } + ldap_msgfree(msg); + } + else + { + DBG1("LDAP search failed: %s", ldap_err2string(res)); + } + } + else + { + DBG1("LDAP bind to '%s' failed: %s", url, ldap_err2string(res)); + } + ldap_unbind_s(ldap); + ldap_free_urldesc(lurl); + return status; +} + + +/** + * Implementation of fetcher_t.set_option. + */ +static bool set_option(private_ldap_fetcher_t *this, fetcher_option_t option, ...) +{ + va_list args; + + va_start(args, option); + switch (option) + { + case FETCH_TIMEOUT: + { + this->timeout = va_arg(args, u_int); + return TRUE; + } + default: + return FALSE; + } +} + +/** + * Implements ldap_fetcher_t.destroy + */ +static void destroy(private_ldap_fetcher_t *this) +{ + free(this); +} + +/* + * Described in header. + */ +ldap_fetcher_t *ldap_fetcher_create() +{ + private_ldap_fetcher_t *this = malloc_thing(private_ldap_fetcher_t); + + this->public.interface.fetch = (status_t(*)(fetcher_t*,char*,chunk_t*))fetch; + this->public.interface.set_option = (bool(*)(fetcher_t*, fetcher_option_t option, ...))set_option; + this->public.interface.destroy = (void (*)(fetcher_t*))destroy; + + this->timeout = DEFAULT_TIMEOUT; + + return &this->public; +} + diff --git a/src/libstrongswan/plugins/ldap/ldap_fetcher.h b/src/libstrongswan/plugins/ldap/ldap_fetcher.h new file mode 100644 index 000000000..bde60c799 --- /dev/null +++ b/src/libstrongswan/plugins/ldap/ldap_fetcher.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 ldap_fetcher ldap_fetcher + * @{ @ingroup ldap_p + */ + +#ifndef LDAP_FETCHER_H_ +#define LDAP_FETCHER_H_ + +typedef struct ldap_fetcher_t ldap_fetcher_t; + +/** + * Fetcher implementation using OpenLDAP. + */ +struct ldap_fetcher_t { + + /** + * Implements fetcher interface + */ + fetcher_t interface; +}; + +/** + * Create a ldap_fetcher instance. + */ +ldap_fetcher_t *ldap_fetcher_create(); + +#endif /* LDAP_FETCHER_H_ @}*/ diff --git a/src/libstrongswan/plugins/ldap/ldap_plugin.c b/src/libstrongswan/plugins/ldap/ldap_plugin.c new file mode 100644 index 000000000..f063ef791 --- /dev/null +++ b/src/libstrongswan/plugins/ldap/ldap_plugin.c @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "ldap_plugin.h" + +#include +#include "ldap_fetcher.h" + +typedef struct private_ldap_plugin_t private_ldap_plugin_t; + +/** + * private data of ldap_plugin + */ +struct private_ldap_plugin_t { + + /** + * public functions + */ + ldap_plugin_t public; +}; + +/** + * Implementation of ldap_plugin_t.destroy + */ +static void destroy(private_ldap_plugin_t *this) +{ + lib->fetcher->remove_fetcher(lib->fetcher, + (fetcher_constructor_t)ldap_fetcher_create); + free(this); +} + +/* + * see header file + */ +plugin_t *plugin_create() +{ + private_ldap_plugin_t *this = malloc_thing(private_ldap_plugin_t); + + this->public.plugin.destroy = (void(*)(plugin_t*))destroy; + + lib->fetcher->add_fetcher(lib->fetcher, + (fetcher_constructor_t)ldap_fetcher_create, "ldap://"); + lib->fetcher->add_fetcher(lib->fetcher, + (fetcher_constructor_t)ldap_fetcher_create, "ldaps://"); + + return &this->public.plugin; +} + diff --git a/src/libstrongswan/plugins/ldap/ldap_plugin.h b/src/libstrongswan/plugins/ldap/ldap_plugin.h new file mode 100644 index 000000000..7b2bb3232 --- /dev/null +++ b/src/libstrongswan/plugins/ldap/ldap_plugin.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 ldap_p ldap + * @ingroup plugins + * + * @defgroup ldap_plugin ldap_plugin + * @{ @ingroup ldap_p + */ + +#ifndef LDAP_PLUGIN_H_ +#define LDAP_PLUGIN_H_ + +#include + +typedef struct ldap_plugin_t ldap_plugin_t; + +/** + * Plugin implementing LDAP fetcher using OpenLDAP. + */ +struct ldap_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +/** + * Create a ldap_plugin instance. + */ +plugin_t *plugin_create(); + +#endif /* LDAP_PLUGIN_H_ @}*/ diff --git a/src/libstrongswan/plugins/md5/Makefile.am b/src/libstrongswan/plugins/md5/Makefile.am new file mode 100644 index 000000000..0a9c5cbf4 --- /dev/null +++ b/src/libstrongswan/plugins/md5/Makefile.am @@ -0,0 +1,10 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan + +AM_CFLAGS = -rdynamic + +plugin_LTLIBRARIES = libstrongswan-md5.la + +libstrongswan_md5_la_SOURCES = md5_plugin.h md5_plugin.c md5_hasher.c md5_hasher.h +libstrongswan_md5_la_LDFLAGS = -module + diff --git a/src/libstrongswan/plugins/md5/md5_hasher.c b/src/libstrongswan/plugins/md5/md5_hasher.c new file mode 100644 index 000000000..8b24f8cb2 --- /dev/null +++ b/src/libstrongswan/plugins/md5/md5_hasher.c @@ -0,0 +1,392 @@ +/* + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * Copyright (C) 1991-1992, RSA Data Security, Inc. Created 1991. + * All rights reserved. + * + * Derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm. + * Ported to fulfill hasher_t interface. + * + * 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 . + * + * 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. + * + * $Id$ + */ + +#include + +#include "md5_hasher.h" + + +/* Constants for MD5Transform routine. */ +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + +static u_int8_t PADDING[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * ugly macro stuff + */ +/* F, G, H and I are basic MD5 functions. + */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/* ROTATE_LEFT rotates x left n bits. + */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. +Rotation is separate from addition to prevent recomputation. + */ +#define FF(a, b, c, d, x, s, ac) { \ + (a) += F ((b), (c), (d)) + (x) + (u_int32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define GG(a, b, c, d, x, s, ac) { \ + (a) += G ((b), (c), (d)) + (x) + (u_int32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define HH(a, b, c, d, x, s, ac) { \ + (a) += H ((b), (c), (d)) + (x) + (u_int32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define II(a, b, c, d, x, s, ac) { \ + (a) += I ((b), (c), (d)) + (x) + (u_int32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + + + +typedef struct private_md5_hasher_t private_md5_hasher_t; + +/** + * Private data structure with hasing context. + */ +struct private_md5_hasher_t { + /** + * Public interface for this hasher. + */ + md5_hasher_t public; + + /* + * State of the hasher. + */ + u_int32_t state[5]; + u_int32_t count[2]; + u_int8_t buffer[64]; +}; + + +#if BYTE_ORDER != LITTLE_ENDIAN + +/* Encodes input (u_int32_t) into output (u_int8_t). Assumes len is + * a multiple of 4. + */ +static void Encode (u_int8_t *output, u_int32_t *input, size_t len) +{ + size_t i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + { + output[j] = (u_int8_t)(input[i] & 0xff); + output[j+1] = (u_int8_t)((input[i] >> 8) & 0xff); + output[j+2] = (u_int8_t)((input[i] >> 16) & 0xff); + output[j+3] = (u_int8_t)((input[i] >> 24) & 0xff); + } +} + +/* Decodes input (u_int8_t) into output (u_int32_t). Assumes len is + * a multiple of 4. + */ +static void Decode(u_int32_t *output, u_int8_t *input, size_t len) +{ + size_t i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + { + output[i] = ((u_int32_t)input[j]) | (((u_int32_t)input[j+1]) << 8) | + (((u_int32_t)input[j+2]) << 16) | (((u_int32_t)input[j+3]) << 24); + } +} + +#elif BYTE_ORDER == LITTLE_ENDIAN + #define Encode memcpy + #define Decode memcpy +#endif + +/* MD5 basic transformation. Transforms state based on block. + */ +static void MD5Transform(u_int32_t state[4], u_int8_t block[64]) +{ + u_int32_t a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + + Decode(x, block, 64); + + /* Round 1 */ + FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ + FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ + FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ + FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ + FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ + FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ + FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ + FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ + FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ + FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ + FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ + FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ + FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ + FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ + FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ + FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ + + /* Round 2 */ + GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ + GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ + GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ + GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ + GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ + GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ + GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ + GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ + GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ + GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ + GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ + GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ + GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ + GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ + GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ + GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ + + /* Round 3 */ + HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ + HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ + HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ + HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ + HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ + HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ + HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ + HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ + HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ + HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ + HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ + HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ + HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ + HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ + HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ + HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ + + /* Round 4 */ + II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ + II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ + II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ + II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ + II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ + II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ + II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ + II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ + II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ + II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ + II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ + II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ + II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ + II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ + II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ + II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; +} + +/* MD5 block update operation. Continues an MD5 message-digest + * operation, processing another message block, and updating the + * context. + */ +static void MD5Update(private_md5_hasher_t *this, u_int8_t *input, size_t inputLen) +{ + u_int32_t i; + size_t index, partLen; + + /* Compute number of bytes mod 64 */ + index = (u_int8_t)((this->count[0] >> 3) & 0x3F); + + /* Update number of bits */ + if ((this->count[0] += (inputLen << 3)) < (inputLen << 3)) + { + this->count[1]++; + } + this->count[1] += (inputLen >> 29); + + partLen = 64 - index; + + /* Transform as many times as possible. */ + if (inputLen >= partLen) + { + memcpy(&this->buffer[index], input, partLen); + MD5Transform (this->state, this->buffer); + + for (i = partLen; i + 63 < inputLen; i += 64) + { + MD5Transform (this->state, &input[i]); + } + index = 0; + } + else + { + i = 0; + } + + /* Buffer remaining input */ + memcpy(&this->buffer[index], &input[i], inputLen-i); +} + +/* MD5 finalization. Ends an MD5 message-digest operation, writing the + * the message digest and zeroizing the context. + */ +static void MD5Final (private_md5_hasher_t *this, u_int8_t digest[16]) +{ + u_int8_t bits[8]; + size_t index, padLen; + + /* Save number of bits */ + Encode (bits, this->count, 8); + + /* Pad out to 56 mod 64. */ + index = (size_t)((this->count[0] >> 3) & 0x3f); + padLen = (index < 56) ? (56 - index) : (120 - index); + MD5Update (this, PADDING, padLen); + + /* Append length (before padding) */ + MD5Update (this, bits, 8); + + if (digest != NULL) /* Bill Simpson's padding */ + { + /* store state in digest */ + Encode (digest, this->state, 16); + } +} + + + +/** + * Implementation of hasher_t.get_hash. + */ +static void get_hash(private_md5_hasher_t *this, chunk_t chunk, u_int8_t *buffer) +{ + MD5Update(this, chunk.ptr, chunk.len); + if (buffer != NULL) + { + MD5Final(this, buffer); + this->public.hasher_interface.reset(&(this->public.hasher_interface)); + } +} + + +/** + * Implementation of hasher_t.allocate_hash. + */ +static void allocate_hash(private_md5_hasher_t *this, chunk_t chunk, chunk_t *hash) +{ + chunk_t allocated_hash; + + MD5Update(this, chunk.ptr, chunk.len); + if (hash != NULL) + { + allocated_hash.ptr = malloc(HASH_SIZE_MD5); + allocated_hash.len = HASH_SIZE_MD5; + + MD5Final(this, allocated_hash.ptr); + this->public.hasher_interface.reset(&(this->public.hasher_interface)); + + *hash = allocated_hash; + } +} + +/** + * Implementation of hasher_t.get_hash_size. + */ +static size_t get_hash_size(private_md5_hasher_t *this) +{ + return HASH_SIZE_MD5; +} + +/** + * Implementation of hasher_t.reset. + */ +static void reset(private_md5_hasher_t *this) +{ + this->state[0] = 0x67452301; + this->state[1] = 0xefcdab89; + this->state[2] = 0x98badcfe; + this->state[3] = 0x10325476; + this->count[0] = 0; + this->count[1] = 0; +} + +/** + * Implementation of hasher_t.destroy. + */ +static void destroy(private_md5_hasher_t *this) +{ + free(this); +} + +/* + * Described in header. + */ +md5_hasher_t *md5_hasher_create(hash_algorithm_t algo) +{ + private_md5_hasher_t *this; + + if (algo != HASH_MD5) + { + return NULL; + } + this = malloc_thing(private_md5_hasher_t); + + this->public.hasher_interface.get_hash = (void (*) (hasher_t*, chunk_t, u_int8_t*))get_hash; + this->public.hasher_interface.allocate_hash = (void (*) (hasher_t*, chunk_t, chunk_t*))allocate_hash; + this->public.hasher_interface.get_hash_size = (size_t (*) (hasher_t*))get_hash_size; + this->public.hasher_interface.reset = (void (*) (hasher_t*))reset; + this->public.hasher_interface.destroy = (void (*) (hasher_t*))destroy; + + /* initialize */ + reset(this); + + return &(this->public); +} diff --git a/src/libstrongswan/plugins/md5/md5_hasher.h b/src/libstrongswan/plugins/md5/md5_hasher.h new file mode 100644 index 000000000..d4a0417ab --- /dev/null +++ b/src/libstrongswan/plugins/md5/md5_hasher.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2008 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 md5_hasher md5_hasher + * @{ @ingroup md5_p + */ + +#ifndef MD5_HASHER_H_ +#define MD5_HASHER_H_ + +typedef struct md5_hasher_t md5_hasher_t; + +#include + +/** + * Implementation of hasher_t interface using the MD5 algorithm. + */ +struct md5_hasher_t { + + /** + * Generic hasher_t interface for this hasher. + */ + hasher_t hasher_interface; +}; + +/** + * Creates a new md5_hasher_t. + * + * @param algo hash algorithm, must be HASH_MD5 + * @return md5_hasher_t object, NULL if not supported + */ +md5_hasher_t *md5_hasher_create(hash_algorithm_t algo); + +#endif /*MD5_HASHER_H_@}*/ diff --git a/src/libstrongswan/plugins/md5/md5_plugin.c b/src/libstrongswan/plugins/md5/md5_plugin.c new file mode 100644 index 000000000..94ff04d9d --- /dev/null +++ b/src/libstrongswan/plugins/md5/md5_plugin.c @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "md5_plugin.h" + +#include +#include "md5_hasher.h" + +typedef struct private_md5_plugin_t private_md5_plugin_t; + +/** + * private data of md5_plugin + */ +struct private_md5_plugin_t { + + /** + * public functions + */ + md5_plugin_t public; +}; + +/** + * Implementation of md5_plugin_t.destroy + */ +static void destroy(private_md5_plugin_t *this) +{ + lib->crypto->remove_hasher(lib->crypto, + (hasher_constructor_t)md5_hasher_create); + free(this); +} + +/* + * see header file + */ +plugin_t *plugin_create() +{ + private_md5_plugin_t *this = malloc_thing(private_md5_plugin_t); + + this->public.plugin.destroy = (void(*)(plugin_t*))destroy; + + lib->crypto->add_hasher(lib->crypto, HASH_MD5, + (hasher_constructor_t)md5_hasher_create); + + return &this->public.plugin; +} + diff --git a/src/libstrongswan/plugins/md5/md5_plugin.h b/src/libstrongswan/plugins/md5/md5_plugin.h new file mode 100644 index 000000000..e8e8dd535 --- /dev/null +++ b/src/libstrongswan/plugins/md5/md5_plugin.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 md5_p md5 + * @ingroup plugins + * + * @defgroup md5_plugin md5_plugin + * @{ @ingroup md5_p + */ + +#ifndef MD5_PLUGIN_H_ +#define MD5_PLUGIN_H_ + +#include + +typedef struct md5_plugin_t md5_plugin_t; + +/** + * Plugin implementing the MD5 hash algorithm in software. + */ +struct md5_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +/** + * Create a md5_plugin instance. + */ +plugin_t *plugin_create(); + +#endif /* MD5_PLUGIN_H_ @}*/ diff --git a/src/libstrongswan/plugins/mysql/Makefile.am b/src/libstrongswan/plugins/mysql/Makefile.am new file mode 100644 index 000000000..ec94b8fda --- /dev/null +++ b/src/libstrongswan/plugins/mysql/Makefile.am @@ -0,0 +1,12 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan + +AM_CFLAGS = -rdynamic + +plugin_LTLIBRARIES = libstrongswan-mysql.la + +libstrongswan_mysql_la_SOURCES = mysql_plugin.h mysql_plugin.c \ + mysql_database.h mysql_database.c +libstrongswan_mysql_la_LDFLAGS = -module +libstrongswan_mysql_la_LIBADD = -lmysqlclient_r + diff --git a/src/libstrongswan/plugins/mysql/mysql_database.c b/src/libstrongswan/plugins/mysql/mysql_database.c new file mode 100644 index 000000000..0fd3d5368 --- /dev/null +++ b/src/libstrongswan/plugins/mysql/mysql_database.c @@ -0,0 +1,686 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#define _GNU_SOURCE +#include +#include +#include + +#include "mysql_database.h" + +#include +#include +#include + + +typedef struct private_mysql_database_t private_mysql_database_t; + +/** + * private data of mysql_database + */ +struct private_mysql_database_t { + + /** + * public functions + */ + mysql_database_t public; + + /** + * connection pool, contains conn_t + */ + linked_list_t *pool; + + /** + * mutex to lock pool + */ + mutex_t *mutex; + + /** + * hostname to connect to + */ + char *host; + + /** + * username to use + */ + char *username; + + /** + * password + */ + char *password; + + /** + * database name + */ + char *database; + + /** + * tcp port + */ + int port; +}; + +typedef struct conn_t conn_t; + +/** + * connection pool entry + */ +struct conn_t { + + /** + * MySQL database connection + */ + MYSQL *mysql; + + /** + * connection in use? + */ + bool in_use; +}; + +/** + * Release a mysql connection + */ +static void conn_release(conn_t *conn) +{ + conn->in_use = FALSE; +} +/** + * thread specific initialization flag + */ +pthread_key_t initialized; + +/** + * Initialize a thread for mysql usage + */ +static void thread_initialize() +{ + if (pthread_getspecific(initialized) == NULL) + { + pthread_setspecific(initialized, (void*)TRUE); + mysql_thread_init(); + } +} + +/** + * mysql library initialization function + */ +bool mysql_database_init() +{ + if (mysql_library_init(0, NULL, NULL)) + { + return FALSE; + } + if (pthread_key_create(&initialized, (void*)mysql_thread_end)) + { + mysql_library_end(); + return FALSE; + } + return TRUE; +} + +/** + * mysql library cleanup function + */ +void mysql_database_deinit() +{ + pthread_key_delete(initialized); + mysql_thread_end(); + /* mysql_library_end(); would be the clean way, however, it hangs... */ +} + +/** + * Destroy a mysql connection + */ +static void conn_destroy(conn_t *this) +{ + mysql_close(this->mysql); + free(this); +} + +/** + * Acquire/Reuse a mysql connection + */ +static conn_t *conn_get(private_mysql_database_t *this) +{ + conn_t *current, *found = NULL; + enumerator_t *enumerator; + + thread_initialize(); + + while (TRUE) + { + this->mutex->lock(this->mutex); + enumerator = this->pool->create_enumerator(this->pool); + while (enumerator->enumerate(enumerator, ¤t)) + { + if (!current->in_use) + { + found = current; + found->in_use = TRUE; + break; + } + } + enumerator->destroy(enumerator); + this->mutex->unlock(this->mutex); + if (found) + { /* check connection if found, release if ping fails */ + if (mysql_ping(found->mysql) == 0) + { + break; + } + this->mutex->lock(this->mutex); + this->pool->remove(this->pool, found, NULL); + this->mutex->unlock(this->mutex); + conn_destroy(found); + found = NULL; + continue; + } + break; + } + if (found == NULL) + { + found = malloc_thing(conn_t); + found->in_use = TRUE; + found->mysql = mysql_init(NULL); + if (!mysql_real_connect(found->mysql, this->host, this->username, + this->password, this->database, this->port, + NULL, 0)) + { + DBG1("connecting to mysql://%s:***@%s:%d/%s failed: %s", + this->username, this->host, this->port, this->database, + mysql_error(found->mysql)); + conn_destroy(found); + found = NULL; + } + else + { + this->mutex->lock(this->mutex); + this->pool->insert_last(this->pool, found); + DBG1("increased MySQL connection pool size to %d", + this->pool->get_count(this->pool)); + this->mutex->unlock(this->mutex); + } + } + return found; +} + +/** + * Create and run a MySQL stmt using a sql string and args + */ +static MYSQL_STMT* run(MYSQL *mysql, char *sql, va_list *args) +{ + MYSQL_STMT *stmt; + int params; + + stmt = mysql_stmt_init(mysql); + if (stmt == NULL) + { + DBG1("creating MySQL statement failed: %s", mysql_error(mysql)); + return NULL; + } + if (mysql_stmt_prepare(stmt, sql, strlen(sql))) + { + DBG1("preparing MySQL statement failed: %s", mysql_stmt_error(stmt)); + mysql_stmt_close(stmt); + return NULL; + } + params = mysql_stmt_param_count(stmt); + if (params > 0) + { + int i; + MYSQL_BIND *bind; + + bind = alloca(sizeof(MYSQL_BIND) * params); + memset(bind, 0, sizeof(MYSQL_BIND) * params); + + for (i = 0; i < params; i++) + { + switch (va_arg(*args, db_type_t)) + { + case DB_INT: + { + bind[i].buffer_type = MYSQL_TYPE_LONG; + bind[i].buffer = (char*)alloca(sizeof(int)); + *(int*)bind[i].buffer = va_arg(*args, int); + bind[i].buffer_length = sizeof(int); + break; + } + case DB_UINT: + { + bind[i].buffer_type = MYSQL_TYPE_LONG; + bind[i].buffer = (char*)alloca(sizeof(u_int)); + *(u_int*)bind[i].buffer = va_arg(*args, u_int); + bind[i].buffer_length = sizeof(u_int); + bind[i].is_unsigned = TRUE; + break; + } + case DB_TEXT: + { + bind[i].buffer_type = MYSQL_TYPE_STRING;; + bind[i].buffer = va_arg(*args, char*); + bind[i].buffer_length = strlen(bind[i].buffer); + break; + } + case DB_BLOB: + { + chunk_t chunk = va_arg(*args, chunk_t); + bind[i].buffer_type = MYSQL_TYPE_BLOB; + bind[i].buffer = chunk.ptr; + bind[i].buffer_length = chunk.len; + break; + } + case DB_DOUBLE: + { + bind[i].buffer_type = MYSQL_TYPE_DOUBLE; + bind[i].buffer = (char*)alloca(sizeof(double)); + *(double*)bind[i].buffer = va_arg(*args, double); + bind[i].buffer_length = sizeof(double); + break; + } + case DB_NULL: + { + bind[i].buffer_type = MYSQL_TYPE_NULL; + break; + } + default: + DBG1("invalid data type supplied"); + mysql_stmt_close(stmt); + return NULL; + } + } + if (mysql_stmt_bind_param(stmt, bind)) + { + DBG1("binding MySQL param failed: %s", mysql_stmt_error(stmt)); + mysql_stmt_close(stmt); + return NULL; + } + } + if (mysql_stmt_execute(stmt)) + { + DBG1("executing MySQL statement failed: %s", mysql_stmt_error(stmt)); + mysql_stmt_close(stmt); + return NULL; + } + return stmt; +} + +typedef struct { + /** implements enumerator_t */ + enumerator_t public; + /** associated MySQL statement */ + MYSQL_STMT *stmt; + /** result bindings */ + MYSQL_BIND *bind; + /** pooled connection handle */ + conn_t *conn; + /** value for INT, UINT, double */ + union { + void *p_void;; + int *p_int; + u_int *p_uint; + double *p_double; + } val; + /* length for TEXT and BLOB */ + unsigned long *length; +} mysql_enumerator_t; + +/** + * create a mysql enumerator + */ +static void mysql_enumerator_destroy(mysql_enumerator_t *this) +{ + int columns, i; + + columns = mysql_stmt_field_count(this->stmt); + + for (i = 0; i < columns; i++) + { + switch (this->bind[i].buffer_type) + { + case MYSQL_TYPE_STRING: + case MYSQL_TYPE_BLOB: + { + free(this->bind[i].buffer); + break; + } + default: + break; + } + } + mysql_stmt_close(this->stmt); + conn_release(this->conn); + free(this->bind); + free(this->val.p_void); + free(this->length); + free(this); +} + +/** + * Implementation of database.query().enumerate + */ +static bool mysql_enumerator_enumerate(mysql_enumerator_t *this, ...) +{ + int i, columns; + va_list args; + + columns = mysql_stmt_field_count(this->stmt); + + /* free/reset data set of previous call */ + for (i = 0; i < columns; i++) + { + switch (this->bind[i].buffer_type) + { + case MYSQL_TYPE_STRING: + case MYSQL_TYPE_BLOB: + { + free(this->bind[i].buffer); + this->bind[i].buffer = NULL; + this->bind[i].buffer_length = 0; + this->bind[i].length = &this->length[i]; + this->length[i] = 0; + break; + } + default: + break; + } + } + + switch (mysql_stmt_fetch(this->stmt)) + { + case 0: + case MYSQL_DATA_TRUNCATED: + break; + case MYSQL_NO_DATA: + return FALSE; + default: + DBG1("fetching MySQL row failed: %s", mysql_stmt_error(this->stmt)); + return FALSE; + } + + va_start(args, this); + for (i = 0; i < columns; i++) + { + switch (this->bind[i].buffer_type) + { + case MYSQL_TYPE_LONG: + { + if (this->bind[i].is_unsigned) + { + u_int *value = va_arg(args, u_int*); + *value = this->val.p_uint[i]; + } + else + { + int *value = va_arg(args, int*); + *value = this->val.p_int[i]; + } + break; + } + case MYSQL_TYPE_STRING: + { + char **value = va_arg(args, char**); + this->bind[i].buffer = malloc(this->length[i]+1); + this->bind[i].buffer_length = this->length[i]; + *value = this->bind[i].buffer; + mysql_stmt_fetch_column(this->stmt, &this->bind[i], i, 0); + ((char*)this->bind[i].buffer)[this->length[i]] = '\0'; + break; + } + case MYSQL_TYPE_BLOB: + { + chunk_t *value = va_arg(args, chunk_t*); + this->bind[i].buffer = malloc(this->length[i]); + this->bind[i].buffer_length = this->length[i]; + value->ptr = this->bind[i].buffer; + value->len = this->length[i]; + mysql_stmt_fetch_column(this->stmt, &this->bind[i], i, 0); + break; + } + case MYSQL_TYPE_DOUBLE: + { + double *value = va_arg(args, double*); + *value = this->val.p_double[i]; + break; + } + default: + break; + } + } + return TRUE; +} + +/** + * Implementation of database_t.query. + */ +static enumerator_t* query(private_mysql_database_t *this, char *sql, ...) +{ + MYSQL_STMT *stmt; + va_list args; + mysql_enumerator_t *enumerator = NULL; + conn_t *conn; + + conn = conn_get(this); + if (!conn) + { + return NULL; + } + + va_start(args, sql); + stmt = run(conn->mysql, sql, &args); + if (stmt) + { + int columns, i; + + enumerator = malloc_thing(mysql_enumerator_t); + enumerator->public.enumerate = (void*)mysql_enumerator_enumerate; + enumerator->public.destroy = (void*)mysql_enumerator_destroy; + enumerator->stmt = stmt; + enumerator->conn = conn; + columns = mysql_stmt_field_count(stmt); + enumerator->bind = calloc(columns, sizeof(MYSQL_BIND)); + enumerator->length = calloc(columns, sizeof(unsigned long)); + enumerator->val.p_void = calloc(columns, sizeof(enumerator->val)); + for (i = 0; i < columns; i++) + { + switch (va_arg(args, db_type_t)) + { + case DB_INT: + { + enumerator->bind[i].buffer_type = MYSQL_TYPE_LONG; + enumerator->bind[i].buffer = (char*)&enumerator->val.p_int[i]; + break; + } + case DB_UINT: + { + enumerator->bind[i].buffer_type = MYSQL_TYPE_LONG; + enumerator->bind[i].buffer = (char*)&enumerator->val.p_uint[i]; + enumerator->bind[i].is_unsigned = TRUE; + break; + } + case DB_TEXT: + { + enumerator->bind[i].buffer_type = MYSQL_TYPE_STRING; + enumerator->bind[i].length = &enumerator->length[i]; + break; + } + case DB_BLOB: + { + enumerator->bind[i].buffer_type = MYSQL_TYPE_BLOB; + enumerator->bind[i].length = &enumerator->length[i]; + break; + } + case DB_DOUBLE: + { + enumerator->bind[i].buffer_type = MYSQL_TYPE_DOUBLE; + enumerator->bind[i].buffer = (char*)&enumerator->val.p_double[i]; + break; + } + default: + DBG1("invalid result data type supplied"); + mysql_enumerator_destroy(enumerator); + va_end(args); + return NULL; + } + } + if (mysql_stmt_bind_result(stmt, enumerator->bind)) + { + DBG1("binding MySQL result failed: %s", mysql_stmt_error(stmt)); + mysql_enumerator_destroy(enumerator); + enumerator = NULL; + } + } + else + { + conn_release(conn); + } + va_end(args); + return (enumerator_t*)enumerator; +} + +/** + * Implementation of database_t.execute. + */ +static int execute(private_mysql_database_t *this, int *rowid, char *sql, ...) +{ + MYSQL_STMT *stmt; + va_list args; + conn_t *conn; + int affected = -1; + + conn = conn_get(this); + if (!conn) + { + return -1; + } + va_start(args, sql); + stmt = run(conn->mysql, sql, &args); + if (stmt) + { + if (rowid) + { + *rowid = mysql_stmt_insert_id(stmt); + } + affected = mysql_stmt_affected_rows(stmt); + mysql_stmt_close(stmt); + } + va_end(args); + conn_release(conn); + return affected; +} + +/** + * Implementation of database_t.destroy + */ +static void destroy(private_mysql_database_t *this) +{ + this->pool->destroy_function(this->pool, (void*)conn_destroy); + this->mutex->destroy(this->mutex); + free(this->host); + free(this->username); + free(this->password); + free(this->database); + free(this); +} + +static bool parse_uri(private_mysql_database_t *this, char *uri) +{ + char *username, *password, *host, *port = "0", *database, *pos; + + /** + * parse mysql://username:pass@host:port/database uri + */ + username = strdupa(uri + 8); + pos = strchr(username, ':'); + if (pos) + { + *pos = '\0'; + password = pos + 1; + pos = strrchr(password, '@'); + if (pos) + { + *pos = '\0'; + host = pos + 1; + pos = strrchr(host, ':'); + if (pos) + { + *pos = '\0'; + port = pos + 1; + pos = strchr(port, '/'); + } + else + { + pos = strchr(host, '/'); + } + if (pos) + { + *pos = '\0'; + database = pos + 1; + + this->host = strdup(host); + this->username = strdup(username); + this->password = strdup(password); + this->database = strdup(database); + this->port = atoi(port); + return TRUE; + } + } + } + DBG1("parsing MySQL database uri '%s' failed", uri); + return FALSE; +} + + +/* + * see header file + */ +mysql_database_t *mysql_database_create(char *uri) +{ + conn_t *conn; + private_mysql_database_t *this; + + if (!strneq(uri, "mysql://", 8)) + { + return NULL; + } + + this = malloc_thing(private_mysql_database_t); + + this->public.db.query = (enumerator_t* (*)(database_t *this, char *sql, ...))query; + this->public.db.execute = (int (*)(database_t *this, int *rowid, char *sql, ...))execute; + this->public.db.destroy = (void(*)(database_t*))destroy; + + if (!parse_uri(this, uri)) + { + free(this); + return NULL; + } + this->mutex = mutex_create(MUTEX_DEFAULT); + this->pool = linked_list_create(); + + /* check connectivity */ + conn = conn_get(this); + if (!conn) + { + destroy(this); + return NULL; + } + conn_release(conn); + return &this->public; +} + diff --git a/src/libstrongswan/plugins/mysql/mysql_database.h b/src/libstrongswan/plugins/mysql/mysql_database.h new file mode 100644 index 000000000..d04aa79fa --- /dev/null +++ b/src/libstrongswan/plugins/mysql/mysql_database.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2007-2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 mysql_database mysql_database + * @{ @ingroup mysql_p + */ + +#ifndef MYSQL_DATABASE_H_ +#define MYSQL_DATABASE_H_ + +#include + +typedef struct mysql_database_t mysql_database_t; + +/** + * MySQL databse_t implementation. + */ +struct mysql_database_t { + + /** + * Implements database_t + */ + database_t db; +}; + +/** + * Create a mysql_database instance. + * + * @param uri connection URI, mysql://user:pass@host:port/database + */ +mysql_database_t *mysql_database_create(char *uri); + +/** + * MySQL client library initialization function + * + * @return FALSE if initialization failed + */ +bool mysql_database_init(); + +/** + * Mysql client library cleanup function + */ +void mysql_database_deinit(); + +#endif /* MYSQL_DATABASE_H_ @}*/ diff --git a/src/libstrongswan/plugins/mysql/mysql_plugin.c b/src/libstrongswan/plugins/mysql/mysql_plugin.c new file mode 100644 index 000000000..907c746e3 --- /dev/null +++ b/src/libstrongswan/plugins/mysql/mysql_plugin.c @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "mysql_plugin.h" + +#include +#include +#include "mysql_database.h" + +typedef struct private_mysql_plugin_t private_mysql_plugin_t; + +/** + * private data of mysql_plugin + */ +struct private_mysql_plugin_t { + + /** + * public functions + */ + mysql_plugin_t public; +}; + +/** + * Implementation of plugin_t.destroy + */ +static void destroy(private_mysql_plugin_t *this) +{ + lib->db->remove_database(lib->db, + (database_constructor_t)mysql_database_create); + mysql_database_deinit(); + free(this); +} + +/* + * see header file + */ +plugin_t *plugin_create() +{ + private_mysql_plugin_t *this; + + if (!mysql_database_init()) + { + DBG1("MySQL client library initialization failed"); + return NULL; + } + + this = malloc_thing(private_mysql_plugin_t); + this->public.plugin.destroy = (void(*)(plugin_t*))destroy; + + lib->db->add_database(lib->db, + (database_constructor_t)mysql_database_create); + + return &this->public.plugin; +} + diff --git a/src/libstrongswan/plugins/mysql/mysql_plugin.h b/src/libstrongswan/plugins/mysql/mysql_plugin.h new file mode 100644 index 000000000..dbcabaafe --- /dev/null +++ b/src/libstrongswan/plugins/mysql/mysql_plugin.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 mysql_p mysql + * @ingroup plugins + * + * @defgroup mysql_plugin mysql_plugin + * @{ @ingroup mysql_p + */ + +#ifndef MYSQL_PLUGIN_H_ +#define MYSQL_PLUGIN_H_ + +#include + +typedef struct mysql_plugin_t mysql_plugin_t; + +/** + * Plugin implementing mysql database connectivity. + */ +struct mysql_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +/** + * Create a mysql_plugin instance. + */ +plugin_t *plugin_create(); + +#endif /* MYSQL_PLUGIN_H_ @}*/ diff --git a/src/libstrongswan/plugins/plugin.h b/src/libstrongswan/plugins/plugin.h new file mode 100644 index 000000000..cf0b728a3 --- /dev/null +++ b/src/libstrongswan/plugins/plugin.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 plugin plugin + * @{ @ingroup plugins + */ + +#ifndef PLUGIN_H_ +#define PLUGIN_H_ + +typedef struct plugin_t plugin_t; + +/** + * Interface definition of a plugin. + */ +struct plugin_t { + + /** + * Destroy a plugin instance. + */ + void (*destroy)(plugin_t *this); +}; + + +/** + * Plugin constructor function definiton. + * + * Each plugin has a constructor functions. This function is called on daemon + * startup to initialize each plugin. + * The plugin function is named plugin_create(). + * + * @return plugin_t instance + */ +typedef plugin_t *(*plugin_constructor_t)(void); + +#endif /* PLUGIN_H_ @}*/ diff --git a/src/libstrongswan/plugins/plugin_loader.c b/src/libstrongswan/plugins/plugin_loader.c new file mode 100644 index 000000000..215ed53d6 --- /dev/null +++ b/src/libstrongswan/plugins/plugin_loader.c @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "plugin_loader.h" + +#include + +#include +#include +#include + +typedef struct private_plugin_loader_t private_plugin_loader_t; + +/** + * private data of plugin_loader + */ +struct private_plugin_loader_t { + + /** + * public functions + */ + plugin_loader_t public; + + /** + * list of loaded plugins + */ + linked_list_t *plugins; +}; + +/** + * Implementation of plugin_loader_t.load_plugins. + */ +static int load(private_plugin_loader_t *this, char *path, char *prefix) +{ + enumerator_t *enumerator; + char *file, *ending, *rel; + void *handle; + int count = 0; + + enumerator = enumerator_create_directory(path); + if (!enumerator) + { + DBG1("opening plugin directory %s failed", path); + return 0; + } + DBG1("loading plugins from %s", path); + while (enumerator->enumerate(enumerator, &rel, &file, NULL)) + { + plugin_t *plugin; + plugin_constructor_t constructor; + + ending = file + strlen(file) - 3; + if (ending <= file || !streq(ending, ".so")) + { /* only process .so libraries */ + continue; + } + if (!strneq(prefix, rel, strlen(prefix))) + { + continue; + } + handle = dlopen(file, RTLD_LAZY); + if (handle == NULL) + { + DBG1("loading plugin %s failed: %s", rel, dlerror()); + continue; + } + constructor = dlsym(handle, "plugin_create"); + if (constructor == NULL) + { + DBG1("plugin %s has no plugin_create() function, skipped", rel); + dlclose(handle); + continue; + } + plugin = constructor(); + if (plugin == NULL) + { + DBG1("plugin %s constructor failed, skipping", rel); + dlclose(handle); + continue; + } + DBG1("plugin %s loaded successfully", rel); + /* insert in front to destroy them in reverse order */ + this->plugins->insert_last(this->plugins, plugin); + /* we do not store or free dlopen() handles, leak_detective requires + * the modules to keep loaded until leak report */ + count++; + } + enumerator->destroy(enumerator); + return count; +} + +/** + * Implementation of plugin_loader_t.destroy + */ +static void destroy(private_plugin_loader_t *this) +{ + this->plugins->destroy_offset(this->plugins, offsetof(plugin_t, destroy)); + free(this); +} + +/* + * see header file + */ +plugin_loader_t *plugin_loader_create() +{ + private_plugin_loader_t *this = malloc_thing(private_plugin_loader_t); + + this->public.load = (int(*)(plugin_loader_t*, char *path, char *prefix))load; + this->public.destroy = (void(*)(plugin_loader_t*))destroy; + + this->plugins = linked_list_create(); + + return &this->public; +} + diff --git a/src/libstrongswan/plugins/plugin_loader.h b/src/libstrongswan/plugins/plugin_loader.h new file mode 100644 index 000000000..455332556 --- /dev/null +++ b/src/libstrongswan/plugins/plugin_loader.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 plugin_loader plugin_loader + * @{ @ingroup plugin + */ + +#ifndef PLUGIN_LOADER_H_ +#define PLUGIN_LOADER_H_ + +typedef struct plugin_loader_t plugin_loader_t; + +/** + * The plugin_loader loads plugins from a directory and initializes them + */ +struct plugin_loader_t { + + /** + * Load plugins from a directory. + * + * @param path path containing loadable plugins + * @param prefix prefix of plugin libraries to load + * @return number of successfully loaded plugins + */ + int (*load)(plugin_loader_t *this, char *path, char *prefix); + + /** + * Unload loaded plugins, destroy plugin_loader instance. + */ + void (*destroy)(plugin_loader_t *this); +}; + +/** + * Create a plugin_loader instance. + * + * @return plugin loader instance + */ +plugin_loader_t *plugin_loader_create(); + +#endif /* PLUGIN_LOADER_H_ @}*/ diff --git a/src/libstrongswan/plugins/sha1/Makefile.am b/src/libstrongswan/plugins/sha1/Makefile.am new file mode 100644 index 000000000..299e85083 --- /dev/null +++ b/src/libstrongswan/plugins/sha1/Makefile.am @@ -0,0 +1,10 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan + +AM_CFLAGS = -rdynamic + +plugin_LTLIBRARIES = libstrongswan-sha1.la + +libstrongswan_sha1_la_SOURCES = sha1_plugin.h sha1_plugin.c sha1_hasher.c sha1_hasher.h +libstrongswan_sha1_la_LDFLAGS = -module + diff --git a/src/libstrongswan/plugins/sha1/sha1_hasher.c b/src/libstrongswan/plugins/sha1/sha1_hasher.c new file mode 100644 index 000000000..97a2f207f --- /dev/null +++ b/src/libstrongswan/plugins/sha1/sha1_hasher.c @@ -0,0 +1,294 @@ +/* + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * Ported from Steve Reid's implementation + * "SHA1 in C" found in strongSwan. + * + * 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 . + * + * 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. + * + * $Id$ + */ + +#include +#include + +#include "sha1_hasher.h" + +/* + * ugly macro stuff + */ +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +#if BYTE_ORDER == LITTLE_ENDIAN + #define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) |(rol(block->l[i],8)&0x00FF00FF)) +#elif BYTE_ORDER == BIG_ENDIAN + #define blk0(i) block->l[i] +#else + #error "Endianness not defined!" +#endif +#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] ^block->l[(i+2)&15]^block->l[i&15],1)) + +/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ +#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); +#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); +#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); + + +typedef struct private_sha1_hasher_t private_sha1_hasher_t; + +/** + * Private data structure with hasing context. + */ +struct private_sha1_hasher_t { + /** + * Public interface for this hasher. + */ + sha1_hasher_t public; + + /** + * implemented algorithm + */ + hash_algorithm_t algo; + + /* + * State of the hasher. + */ + u_int32_t state[5]; + u_int32_t count[2]; + u_int8_t buffer[64]; +}; + +/* + * Hash a single 512-bit block. This is the core of the algorithm. * + */ +static void SHA1Transform(u_int32_t state[5], const unsigned char buffer[64]) +{ + u_int32_t a, b, c, d, e; + typedef union { + u_int8_t c[64]; + u_int32_t l[16]; + } CHAR64LONG16; + CHAR64LONG16 block[1]; /* use array to appear as a pointer */ + memcpy(block, buffer, 64); + + /* Copy context->state[] to working vars */ + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); + R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); + R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); + R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); + R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); + R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); + R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); + R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); + R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); + R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); + R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); + R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); + R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); + R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); + R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); + R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); + R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); + R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); + R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); + R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); + /* Add the working vars back into context.state[] */ + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + /* Wipe variables */ + a = b = c = d = e = 0; + memset(block, '\0', sizeof(block)); +} + +/* + * Run your data through this. + */ +static void SHA1Update(private_sha1_hasher_t* this, u_int8_t *data, u_int32_t len) +{ + u_int32_t i; + u_int32_t j; + + j = this->count[0]; + if ((this->count[0] += len << 3) < j) + { + this->count[1]++; + } + this->count[1] += (len>>29); + j = (j >> 3) & 63; + if ((j + len) > 63) + { + memcpy(&this->buffer[j], data, (i = 64-j)); + SHA1Transform(this->state, this->buffer); + for ( ; i + 63 < len; i += 64) + { + SHA1Transform(this->state, &data[i]); + } + j = 0; + } + else + { + i = 0; + } + memcpy(&this->buffer[j], &data[i], len - i); +} + + +/* + * Add padding and return the message digest. + */ +static void SHA1Final(private_sha1_hasher_t *this, u_int8_t *digest) +{ + u_int32_t i; + u_int8_t finalcount[8]; + u_int8_t c; + + for (i = 0; i < 8; i++) + { + finalcount[i] = (u_int8_t)((this->count[(i >= 4 ? 0 : 1)] + >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ + } + c = 0200; + SHA1Update(this, &c, 1); + while ((this->count[0] & 504) != 448) + { + c = 0000; + SHA1Update(this, &c, 1); + } + SHA1Update(this, finalcount, 8); /* Should cause a SHA1Transform() */ + for (i = 0; i < 20; i++) + { + digest[i] = (u_int8_t)((this->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); + } +} + +/** + * Implementation of hasher_t.reset. + */ +static void reset(private_sha1_hasher_t *this) +{ + this->state[0] = 0x67452301; + this->state[1] = 0xEFCDAB89; + this->state[2] = 0x98BADCFE; + this->state[3] = 0x10325476; + this->state[4] = 0xC3D2E1F0; + this->count[0] = 0; + this->count[1] = 0; +} + +/** + * copy hasher state to buf + */ +static void state_to_buf(private_sha1_hasher_t *this, u_int8_t *buffer) +{ + u_int32_t *hash = (u_int32_t*)buffer; + hash[0] = htonl(this->state[0]); + hash[1] = htonl(this->state[1]); + hash[2] = htonl(this->state[2]); + hash[3] = htonl(this->state[3]); + hash[4] = htonl(this->state[4]); +} + +/** + * Implementation of hasher_t.get_hash. + */ +static void get_hash(private_sha1_hasher_t *this, chunk_t chunk, u_int8_t *buffer) +{ + SHA1Update(this, chunk.ptr, chunk.len); + if (buffer != NULL) + { + if (this->algo == HASH_SHA1_NOFINAL) + { + state_to_buf(this, buffer); + } + else + { + SHA1Final(this, buffer); + } + reset(this); + } +} + + +/** + * Implementation of hasher_t.allocate_hash. + */ +static void allocate_hash(private_sha1_hasher_t *this, chunk_t chunk, chunk_t *hash) +{ + SHA1Update(this, chunk.ptr, chunk.len); + if (hash != NULL) + { + hash->ptr = malloc(HASH_SIZE_SHA1); + hash->len = HASH_SIZE_SHA1; + + if (this->algo == HASH_SHA1_NOFINAL) + { + state_to_buf(this, hash->ptr); + } + else + { + SHA1Final(this, hash->ptr); + } + reset(this); + } +} + +/** + * Implementation of hasher_t.get_hash_size. + */ +static size_t get_hash_size(private_sha1_hasher_t *this) +{ + return HASH_SIZE_SHA1; +} + +/** + * Implementation of hasher_t.destroy. + */ +static void destroy(private_sha1_hasher_t *this) +{ + free(this); +} + +/* + * Described in header. + */ +sha1_hasher_t *sha1_hasher_create(hash_algorithm_t algo) +{ + private_sha1_hasher_t *this; + if (algo != HASH_SHA1 && algo != HASH_SHA1_NOFINAL) + { + return NULL; + } + this = malloc_thing(private_sha1_hasher_t); + this->algo = algo; + this->public.hasher_interface.get_hash = (void (*) (hasher_t*, chunk_t, u_int8_t*))get_hash; + this->public.hasher_interface.allocate_hash = (void (*) (hasher_t*, chunk_t, chunk_t*))allocate_hash; + this->public.hasher_interface.get_hash_size = (size_t (*) (hasher_t*))get_hash_size; + this->public.hasher_interface.reset = (void (*) (hasher_t*))reset; + this->public.hasher_interface.destroy = (void (*) (hasher_t*))destroy; + + /* initialize */ + reset(this); + + return &(this->public); +} diff --git a/src/libstrongswan/plugins/sha1/sha1_hasher.h b/src/libstrongswan/plugins/sha1/sha1_hasher.h new file mode 100644 index 000000000..aff0eae11 --- /dev/null +++ b/src/libstrongswan/plugins/sha1/sha1_hasher.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2005-2008 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 sha1_hasher sha1_hasher + * @{ @ingroup sha1_p + */ + +#ifndef SHA1_HASHER_H_ +#define SHA1_HASHER_H_ + +typedef struct sha1_hasher_t sha1_hasher_t; + +#include + +/** + * Implementation of hasher_t interface using the SHA1 algorithm. + */ +struct sha1_hasher_t { + + /** + * Implements hasher_t interface. + */ + hasher_t hasher_interface; +}; + +/** + * Creates a new sha1_hasher_t. + * + * This implementation supports two algorithms, HASH_SHA1 and HASH_SHA1_NOFINAL + * + * @param algo algorithm + * @return sha1_hasher_t object + */ +sha1_hasher_t *sha1_hasher_create(hash_algorithm_t algo); + +#endif /*SHA1_HASHER_H_ @}*/ diff --git a/src/libstrongswan/plugins/sha1/sha1_plugin.c b/src/libstrongswan/plugins/sha1/sha1_plugin.c new file mode 100644 index 000000000..4a69c4e76 --- /dev/null +++ b/src/libstrongswan/plugins/sha1/sha1_plugin.c @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "sha1_plugin.h" + +#include +#include "sha1_hasher.h" + +typedef struct private_sha1_plugin_t private_sha1_plugin_t; + +/** + * private data of sha1_plugin + */ +struct private_sha1_plugin_t { + + /** + * public functions + */ + sha1_plugin_t public; +}; + +/** + * Implementation of sha1_plugin_t.destroy + */ +static void destroy(private_sha1_plugin_t *this) +{ + lib->crypto->remove_hasher(lib->crypto, + (hasher_constructor_t)sha1_hasher_create); + free(this); +} + +/* + * see header file + */ +plugin_t *plugin_create() +{ + private_sha1_plugin_t *this = malloc_thing(private_sha1_plugin_t); + + this->public.plugin.destroy = (void(*)(plugin_t*))destroy; + + lib->crypto->add_hasher(lib->crypto, HASH_SHA1, + (hasher_constructor_t)sha1_hasher_create); + lib->crypto->add_hasher(lib->crypto, HASH_SHA1_NOFINAL, + (hasher_constructor_t)sha1_hasher_create); + + return &this->public.plugin; +} + diff --git a/src/libstrongswan/plugins/sha1/sha1_plugin.h b/src/libstrongswan/plugins/sha1/sha1_plugin.h new file mode 100644 index 000000000..82ab04c86 --- /dev/null +++ b/src/libstrongswan/plugins/sha1/sha1_plugin.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 sha1_p sha1 + * @ingroup plugins + * + * @defgroup sha1_plugin sha1_plugin + * @{ @ingroup sha1_p + */ + +#ifndef SHA1_PLUGIN_H_ +#define SHA1_PLUGIN_H_ + +#include + +typedef struct sha1_plugin_t sha1_plugin_t; + +/** + * Plugin implementing the SHA1 algorithm in software. + */ +struct sha1_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +/** + * Create a sha1_plugin instance. + */ +plugin_t *plugin_create(); + +#endif /* SHA1_PLUGIN_H_ @}*/ diff --git a/src/libstrongswan/plugins/sha2/Makefile.am b/src/libstrongswan/plugins/sha2/Makefile.am new file mode 100644 index 000000000..066e49476 --- /dev/null +++ b/src/libstrongswan/plugins/sha2/Makefile.am @@ -0,0 +1,10 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan + +AM_CFLAGS = -rdynamic + +plugin_LTLIBRARIES = libstrongswan-sha2.la + +libstrongswan_sha2_la_SOURCES = sha2_plugin.h sha2_plugin.c sha2_hasher.c sha2_hasher.h +libstrongswan_sha2_la_LDFLAGS = -module + diff --git a/src/libstrongswan/plugins/sha2/sha2_hasher.c b/src/libstrongswan/plugins/sha2/sha2_hasher.c new file mode 100644 index 000000000..1ec397086 --- /dev/null +++ b/src/libstrongswan/plugins/sha2/sha2_hasher.c @@ -0,0 +1,632 @@ +/* + * Copyright (C) 2006 Martin Willi + * Hochschule fuer Technik Rapperswil + * Copyright (C) 2001 Jari Ruusu. + * + * Ported from strongSwans implementation written by Jari Ruusu. + * + * 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 . + * + * 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. + * + * $Id$ + */ + +#include + +#include "sha2_hasher.h" + + +typedef struct private_sha512_hasher_t private_sha512_hasher_t; + +/** + * Private data structure with hasing context for SHA384 and SHA512 + */ +struct private_sha512_hasher_t { + /** + * Public interface for this hasher. + */ + sha2_hasher_t public; + + unsigned char sha_out[128]; /* results are here, bytes 0..47/0..63 */ + u_int64_t sha_H[8]; + u_int64_t sha_blocks; + u_int64_t sha_blocksMSB; + int sha_bufCnt; +}; + + +typedef struct private_sha256_hasher_t private_sha256_hasher_t; + +/** + * Private data structure with hasing context for SHA256 + */ +struct private_sha256_hasher_t { + /** + * Public interface for this hasher. + */ + sha2_hasher_t public; + + unsigned char sha_out[64]; /* results are here, bytes 0...31 */ + u_int32_t sha_H[8]; + u_int64_t sha_blocks; + int sha_bufCnt; +}; + + +static const u_int32_t sha256_hashInit[8] = { + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, + 0x1f83d9ab, 0x5be0cd19 +}; + +static const u_int32_t sha256_K[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, + 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, + 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, + 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, + 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, + 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 +}; + +static const u_int64_t sha512_hashInit[8] = { + 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, 0x3c6ef372fe94f82bULL, + 0xa54ff53a5f1d36f1ULL, 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, + 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL +}; + +static const u_int64_t sha384_hashInit[8] = { + 0xcbbb9d5dc1059ed8ULL, 0x629a292a367cd507ULL, 0x9159015a3070dd17ULL, + 0x152fecd8f70e5939ULL, 0x67332667ffc00b31ULL, 0x8eb44a8768581511ULL, + 0xdb0c2e0d64f98fa7ULL, 0x47b5481dbefa4fa4ULL +}; + +static const u_int64_t sha512_K[80] = { + 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, + 0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, + 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL, + 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, + 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, + 0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, + 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL, + 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, + 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, + 0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, + 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL, + 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, + 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, + 0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, + 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL, + 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, + 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, + 0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, + 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL, + 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, + 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, + 0xc67178f2e372532bULL, 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, + 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL, + 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, + 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, + 0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, + 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL +}; + + +/* set macros for SHA256 */ +#define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z))) +#define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) +#define R(x,y) ((y) >> (x)) + +#define S(x,y) (((y) >> (x)) | ((y) << (32 - (x)))) +#define uSig0(x) ((S(2,(x))) ^ (S(13,(x))) ^ (S(22,(x)))) +#define uSig1(x) ((S(6,(x))) ^ (S(11,(x))) ^ (S(25,(x)))) +#define lSig0(x) ((S(7,(x))) ^ (S(18,(x))) ^ (R(3,(x)))) +#define lSig1(x) ((S(17,(x))) ^ (S(19,(x))) ^ (R(10,(x)))) + +/** + * Single block SHA256 transformation + */ +static void sha256_transform(private_sha256_hasher_t *ctx, + const unsigned char *datap) +{ + register int j; + u_int32_t a, b, c, d, e, f, g, h; + u_int32_t T1, T2, W[64], Wm2, Wm15; + + /* read the data, big endian byte order */ + j = 0; + do { + W[j] = (((u_int32_t)(datap[0]))<<24) | (((u_int32_t)(datap[1]))<<16) | + (((u_int32_t)(datap[2]))<<8 ) | ((u_int32_t)(datap[3])); + datap += 4; + } while(++j < 16); + + /* initialize variables a...h */ + a = ctx->sha_H[0]; + b = ctx->sha_H[1]; + c = ctx->sha_H[2]; + d = ctx->sha_H[3]; + e = ctx->sha_H[4]; + f = ctx->sha_H[5]; + g = ctx->sha_H[6]; + h = ctx->sha_H[7]; + + /* apply compression function */ + j = 0; + do + { + if(j >= 16) + { + Wm2 = W[j - 2]; + Wm15 = W[j - 15]; + W[j] = lSig1(Wm2) + W[j - 7] + lSig0(Wm15) + W[j - 16]; + } + T1 = h + uSig1(e) + Ch(e,f,g) + sha256_K[j] + W[j]; + T2 = uSig0(a) + Maj(a,b,c); + h = g; g = f; f = e; + e = d + T1; + d = c; c = b; b = a; + a = T1 + T2; + } while(++j < 64); + + /* compute intermediate hash value */ + ctx->sha_H[0] += a; + ctx->sha_H[1] += b; + ctx->sha_H[2] += c; + ctx->sha_H[3] += d; + ctx->sha_H[4] += e; + ctx->sha_H[5] += f; + ctx->sha_H[6] += g; + ctx->sha_H[7] += h; + + ctx->sha_blocks++; +} + +/** + * Update SHA256 hash + */ +static void sha256_write(private_sha256_hasher_t *ctx, + const unsigned char *datap, int length) +{ + while(length > 0) + { + if(!ctx->sha_bufCnt) + { + while(length >= sizeof(ctx->sha_out)) + { + sha256_transform(ctx, datap); + datap += sizeof(ctx->sha_out); + length -= sizeof(ctx->sha_out); + } + if(!length) return; + } + ctx->sha_out[ctx->sha_bufCnt] = *datap++; + length--; + if(++ctx->sha_bufCnt == sizeof(ctx->sha_out)) + { + sha256_transform(ctx, &ctx->sha_out[0]); + ctx->sha_bufCnt = 0; + } + } +} + +/** + * finalize SHA256 hash + */ +static void sha256_final(private_sha256_hasher_t *ctx) +{ + register int j; + u_int64_t bitLength; + u_int32_t i; + unsigned char padByte, *datap; + + bitLength = (ctx->sha_blocks << 9) | (ctx->sha_bufCnt << 3); + padByte = 0x80; + sha256_write(ctx, &padByte, 1); + + /* pad extra space with zeroes */ + padByte = 0; + while(ctx->sha_bufCnt != 56) + { + sha256_write(ctx, &padByte, 1); + } + + /* write bit length, big endian byte order */ + ctx->sha_out[56] = bitLength >> 56; + ctx->sha_out[57] = bitLength >> 48; + ctx->sha_out[58] = bitLength >> 40; + ctx->sha_out[59] = bitLength >> 32; + ctx->sha_out[60] = bitLength >> 24; + ctx->sha_out[61] = bitLength >> 16; + ctx->sha_out[62] = bitLength >> 8; + ctx->sha_out[63] = bitLength; + sha256_transform(ctx, &ctx->sha_out[0]); + + /* return results in ctx->sha_out[0...31] */ + datap = &ctx->sha_out[0]; + j = 0; + do { + i = ctx->sha_H[j]; + datap[0] = i >> 24; + datap[1] = i >> 16; + datap[2] = i >> 8; + datap[3] = i; + datap += 4; + } while(++j < 8); +} + +/* update macros for SHA512 */ +#undef S +#undef uSig0 +#undef uSig1 +#undef lSig0 +#undef lSig1 +#define S(x,y) (((y) >> (x)) | ((y) << (64 - (x)))) +#define uSig0(x) ((S(28,(x))) ^ (S(34,(x))) ^ (S(39,(x)))) +#define uSig1(x) ((S(14,(x))) ^ (S(18,(x))) ^ (S(41,(x)))) +#define lSig0(x) ((S(1,(x))) ^ (S(8,(x))) ^ (R(7,(x)))) +#define lSig1(x) ((S(19,(x))) ^ (S(61,(x))) ^ (R(6,(x)))) + +/** + * Single block SHA384/SHA512 transformation + */ +static void sha512_transform(private_sha512_hasher_t *ctx, + const unsigned char *datap) +{ + register int j; + u_int64_t a, b, c, d, e, f, g, h; + u_int64_t T1, T2, W[80], Wm2, Wm15; + + /* read the data, big endian byte order */ + j = 0; + do { + W[j] = (((u_int64_t)(datap[0]))<<56) | (((u_int64_t)(datap[1]))<<48) | + (((u_int64_t)(datap[2]))<<40) | (((u_int64_t)(datap[3]))<<32) | + (((u_int64_t)(datap[4]))<<24) | (((u_int64_t)(datap[5]))<<16) | + (((u_int64_t)(datap[6]))<<8 ) | ((u_int64_t)(datap[7])); + datap += 8; + } while(++j < 16); + + /* initialize variables a...h */ + a = ctx->sha_H[0]; + b = ctx->sha_H[1]; + c = ctx->sha_H[2]; + d = ctx->sha_H[3]; + e = ctx->sha_H[4]; + f = ctx->sha_H[5]; + g = ctx->sha_H[6]; + h = ctx->sha_H[7]; + + /* apply compression function */ + j = 0; + do { + if(j >= 16) { + Wm2 = W[j - 2]; + Wm15 = W[j - 15]; + W[j] = lSig1(Wm2) + W[j - 7] + lSig0(Wm15) + W[j - 16]; + } + T1 = h + uSig1(e) + Ch(e,f,g) + sha512_K[j] + W[j]; + T2 = uSig0(a) + Maj(a,b,c); + h = g; g = f; f = e; + e = d + T1; + d = c; c = b; b = a; + a = T1 + T2; + } while(++j < 80); + + /* compute intermediate hash value */ + ctx->sha_H[0] += a; + ctx->sha_H[1] += b; + ctx->sha_H[2] += c; + ctx->sha_H[3] += d; + ctx->sha_H[4] += e; + ctx->sha_H[5] += f; + ctx->sha_H[6] += g; + ctx->sha_H[7] += h; + + ctx->sha_blocks++; + if(!ctx->sha_blocks) ctx->sha_blocksMSB++; +} + +/** + * Update a SHA384/SHA512 hash + */ +static void sha512_write(private_sha512_hasher_t *ctx, + const unsigned char *datap, int length) +{ + while(length > 0) + { + if(!ctx->sha_bufCnt) + { + while(length >= sizeof(ctx->sha_out)) + { + sha512_transform(ctx, datap); + datap += sizeof(ctx->sha_out); + length -= sizeof(ctx->sha_out); + } + if(!length) return; + } + ctx->sha_out[ctx->sha_bufCnt] = *datap++; + length--; + if(++ctx->sha_bufCnt == sizeof(ctx->sha_out)) + { + sha512_transform(ctx, &ctx->sha_out[0]); + ctx->sha_bufCnt = 0; + } + } +} + +/** + * Finalize a SHA384/SHA512 hash + */ +static void sha512_final(private_sha512_hasher_t *ctx) +{ + register int j; + u_int64_t bitLength, bitLengthMSB; + u_int64_t i; + unsigned char padByte, *datap; + + bitLength = (ctx->sha_blocks << 10) | (ctx->sha_bufCnt << 3); + bitLengthMSB = (ctx->sha_blocksMSB << 10) | (ctx->sha_blocks >> 54); + padByte = 0x80; + sha512_write(ctx, &padByte, 1); + + /* pad extra space with zeroes */ + padByte = 0; + while(ctx->sha_bufCnt != 112) + { + sha512_write(ctx, &padByte, 1); + } + + /* write bit length, big endian byte order */ + ctx->sha_out[112] = bitLengthMSB >> 56; + ctx->sha_out[113] = bitLengthMSB >> 48; + ctx->sha_out[114] = bitLengthMSB >> 40; + ctx->sha_out[115] = bitLengthMSB >> 32; + ctx->sha_out[116] = bitLengthMSB >> 24; + ctx->sha_out[117] = bitLengthMSB >> 16; + ctx->sha_out[118] = bitLengthMSB >> 8; + ctx->sha_out[119] = bitLengthMSB; + ctx->sha_out[120] = bitLength >> 56; + ctx->sha_out[121] = bitLength >> 48; + ctx->sha_out[122] = bitLength >> 40; + ctx->sha_out[123] = bitLength >> 32; + ctx->sha_out[124] = bitLength >> 24; + ctx->sha_out[125] = bitLength >> 16; + ctx->sha_out[126] = bitLength >> 8; + ctx->sha_out[127] = bitLength; + sha512_transform(ctx, &ctx->sha_out[0]); + + /* return results in ctx->sha_out[0...63] */ + datap = &ctx->sha_out[0]; + j = 0; + do { + i = ctx->sha_H[j]; + datap[0] = i >> 56; + datap[1] = i >> 48; + datap[2] = i >> 40; + datap[3] = i >> 32; + datap[4] = i >> 24; + datap[5] = i >> 16; + datap[6] = i >> 8; + datap[7] = i; + datap += 8; + } while(++j < 8); +} + +/** + * Implementation of hasher_t.get_hash for SHA256. + */ +static void get_hash256(private_sha256_hasher_t *this, + chunk_t chunk, u_int8_t *buffer) +{ + sha256_write(this, chunk.ptr, chunk.len); + if (buffer != NULL) + { + sha256_final(this); + memcpy(buffer, this->sha_out, HASH_SIZE_SHA256); + this->public.hasher_interface.reset(&(this->public.hasher_interface)); + } +} + +/** + * Implementation of hasher_t.get_hash for SHA384. + */ +static void get_hash384(private_sha512_hasher_t *this, + chunk_t chunk, u_int8_t *buffer) +{ + sha512_write(this, chunk.ptr, chunk.len); + if (buffer != NULL) + { + sha512_final(this); + memcpy(buffer, this->sha_out, HASH_SIZE_SHA384); + this->public.hasher_interface.reset(&(this->public.hasher_interface)); + } +} + +/** + * Implementation of hasher_t.get_hash for SHA512. + */ +static void get_hash512(private_sha512_hasher_t *this, + chunk_t chunk, u_int8_t *buffer) +{ + sha512_write(this, chunk.ptr, chunk.len); + if (buffer != NULL) + { + sha512_final(this); + memcpy(buffer, this->sha_out, HASH_SIZE_SHA512); + this->public.hasher_interface.reset(&(this->public.hasher_interface)); + } +} + +/** + * Implementation of hasher_t.allocate_hash for SHA256. + */ +static void allocate_hash256(private_sha256_hasher_t *this, + chunk_t chunk, chunk_t *hash) +{ + chunk_t allocated_hash; + + sha256_write(this, chunk.ptr, chunk.len); + if (hash != NULL) + { + sha256_final(this); + allocated_hash = chunk_alloc(HASH_SIZE_SHA256); + memcpy(allocated_hash.ptr, this->sha_out, HASH_SIZE_SHA256); + this->public.hasher_interface.reset(&(this->public.hasher_interface)); + *hash = allocated_hash; + } +} + +/** + * Implementation of hasher_t.allocate_hash for SHA384. + */ +static void allocate_hash384(private_sha512_hasher_t *this, + chunk_t chunk, chunk_t *hash) +{ + chunk_t allocated_hash; + + sha512_write(this, chunk.ptr, chunk.len); + if (hash != NULL) + { + sha512_final(this); + allocated_hash = chunk_alloc(HASH_SIZE_SHA384); + memcpy(allocated_hash.ptr, this->sha_out, HASH_SIZE_SHA384); + this->public.hasher_interface.reset(&(this->public.hasher_interface)); + *hash = allocated_hash; + } +} + +/** + * Implementation of hasher_t.allocate_hash for SHA512. + */ +static void allocate_hash512(private_sha512_hasher_t *this, + chunk_t chunk, chunk_t *hash) +{ + chunk_t allocated_hash; + + sha512_write(this, chunk.ptr, chunk.len); + if (hash != NULL) + { + sha512_final(this); + allocated_hash = chunk_alloc(HASH_SIZE_SHA512); + memcpy(allocated_hash.ptr, this->sha_out, HASH_SIZE_SHA512); + this->public.hasher_interface.reset(&(this->public.hasher_interface)); + *hash = allocated_hash; + } +} + +/** + * Implementation of hasher_t.get_hash_size for SHA256. + */ +static size_t get_hash_size256(private_sha256_hasher_t *this) +{ + return HASH_SIZE_SHA256; +} + +/** + * Implementation of hasher_t.get_hash_size for SHA384. + */ +static size_t get_hash_size384(private_sha512_hasher_t *this) +{ + return HASH_SIZE_SHA384; +} + +/** + * Implementation of hasher_t.get_hash_size for SHA512. + */ +static size_t get_hash_size512(private_sha512_hasher_t *this) +{ + return HASH_SIZE_SHA512; +} + +/** + * Implementation of hasher_t.reset for SHA256 + */ +static void reset256(private_sha256_hasher_t *ctx) +{ + memcpy(&ctx->sha_H[0], &sha256_hashInit[0], sizeof(ctx->sha_H)); + ctx->sha_blocks = 0; + ctx->sha_bufCnt = 0; +} + +/** + * Implementation of hasher_t.reset for SHA384 + */ +static void reset384(private_sha512_hasher_t *ctx) +{ + memcpy(&ctx->sha_H[0], &sha384_hashInit[0], sizeof(ctx->sha_H)); + ctx->sha_blocks = 0; + ctx->sha_blocksMSB = 0; + ctx->sha_bufCnt = 0; +} + +/** + * Implementation of hasher_t.reset for SHA512 + */ +static void reset512(private_sha512_hasher_t *ctx) +{ + memcpy(&ctx->sha_H[0], &sha512_hashInit[0], sizeof(ctx->sha_H)); + ctx->sha_blocks = 0; + ctx->sha_blocksMSB = 0; + ctx->sha_bufCnt = 0; +} + +/** + * Implementation of hasher_t.destroy. + */ +static void destroy(sha2_hasher_t *this) +{ + free(this); +} + +/* + * Described in header. + */ +sha2_hasher_t *sha2_hasher_create(hash_algorithm_t algorithm) +{ + sha2_hasher_t *this; + + switch (algorithm) + { + case HASH_SHA256: + this = (sha2_hasher_t*)malloc_thing(private_sha256_hasher_t); + this->hasher_interface.reset = (void(*)(hasher_t*))reset256; + this->hasher_interface.get_hash_size = (size_t(*)(hasher_t*))get_hash_size256; + this->hasher_interface.get_hash = (void(*)(hasher_t*,chunk_t,u_int8_t*))get_hash256; + this->hasher_interface.allocate_hash = (void(*)(hasher_t*,chunk_t,chunk_t*))allocate_hash256; + break; + case HASH_SHA384: + /* uses SHA512 data structure */ + this = (sha2_hasher_t*)malloc_thing(private_sha512_hasher_t); + this->hasher_interface.reset = (void(*)(hasher_t*))reset384; + this->hasher_interface.get_hash_size = (size_t(*)(hasher_t*))get_hash_size384; + this->hasher_interface.get_hash = (void(*)(hasher_t*,chunk_t,u_int8_t*))get_hash384; + this->hasher_interface.allocate_hash = (void(*)(hasher_t*,chunk_t,chunk_t*))allocate_hash384; + break; + case HASH_SHA512: + this = (sha2_hasher_t*)malloc_thing(private_sha512_hasher_t); + this->hasher_interface.reset = (void(*)(hasher_t*))reset512; + this->hasher_interface.get_hash_size = (size_t(*)(hasher_t*))get_hash_size512; + this->hasher_interface.get_hash = (void(*)(hasher_t*,chunk_t,u_int8_t*))get_hash512; + this->hasher_interface.allocate_hash = (void(*)(hasher_t*,chunk_t,chunk_t*))allocate_hash512; + break; + default: + return NULL; + } + this->hasher_interface.destroy = (void(*)(hasher_t*))destroy; + + /* initialize */ + this->hasher_interface.reset(&this->hasher_interface); + + return this; +} diff --git a/src/libstrongswan/plugins/sha2/sha2_hasher.h b/src/libstrongswan/plugins/sha2/sha2_hasher.h new file mode 100644 index 000000000..6d732495a --- /dev/null +++ b/src/libstrongswan/plugins/sha2/sha2_hasher.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2006-2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 sha2_hasher sha2_hasher + * @{ @ingroup sha2_p + */ + +#ifndef SHA2_HASHER_H_ +#define SHA2_HASHER_H_ + +typedef struct sha2_hasher_t sha2_hasher_t; + +#include + +/** + * Implementation of hasher_t interface using the SHA2 algorithms. + * + * SHA2 is an other name for the SHA-256, SHA-384 and SHA-512 variants of + * the SHA hash algorithm. + */ +struct sha2_hasher_t { + + /** + * Generic hasher_t interface for this hasher. + */ + hasher_t hasher_interface; +}; + +/** + * Creates a new sha2_hasher_t. + * + * @param algorithm HASH_SHA256, HASH_SHA384 or HASH_SHA512 + * @return sha2_hasher_t object, NULL if not supported + */ +sha2_hasher_t *sha2_hasher_create(hash_algorithm_t algorithm); + +#endif /* SHA2_HASHER_H_ @}*/ diff --git a/src/libstrongswan/plugins/sha2/sha2_plugin.c b/src/libstrongswan/plugins/sha2/sha2_plugin.c new file mode 100644 index 000000000..993fa8793 --- /dev/null +++ b/src/libstrongswan/plugins/sha2/sha2_plugin.c @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "sha2_plugin.h" + +#include +#include "sha2_hasher.h" + +typedef struct private_sha2_plugin_t private_sha2_plugin_t; + +/** + * private data of sha2_plugin + */ +struct private_sha2_plugin_t { + + /** + * public functions + */ + sha2_plugin_t public; +}; + +/** + * Implementation of sha2_plugin_t.destroy + */ +static void destroy(private_sha2_plugin_t *this) +{ + lib->crypto->remove_hasher(lib->crypto, + (hasher_constructor_t)sha2_hasher_create); + free(this); +} + +/* + * see header file + */ +plugin_t *plugin_create() +{ + private_sha2_plugin_t *this = malloc_thing(private_sha2_plugin_t); + + this->public.plugin.destroy = (void(*)(plugin_t*))destroy; + + lib->crypto->add_hasher(lib->crypto, HASH_SHA256, + (hasher_constructor_t)sha2_hasher_create); + lib->crypto->add_hasher(lib->crypto, HASH_SHA384, + (hasher_constructor_t)sha2_hasher_create); + lib->crypto->add_hasher(lib->crypto, HASH_SHA512, + (hasher_constructor_t)sha2_hasher_create); + + return &this->public.plugin; +} + diff --git a/src/libstrongswan/plugins/sha2/sha2_plugin.h b/src/libstrongswan/plugins/sha2/sha2_plugin.h new file mode 100644 index 000000000..859597758 --- /dev/null +++ b/src/libstrongswan/plugins/sha2/sha2_plugin.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 sha2_p sha2 + * @ingroup plugins + * + * @defgroup sha2_plugin sha2_plugin + * @{ @ingroup sha2_p + */ + +#ifndef SHA2_PLUGIN_H_ +#define SHA2_PLUGIN_H_ + +#include + +typedef struct sha2_plugin_t sha2_plugin_t; + +/** + * Plugin implementing the SHA256, SHA384 and SHA512 algorithms in software. + */ +struct sha2_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +/** + * Create a sha2_plugin instance. + */ +plugin_t *plugin_create(); + +#endif /* SHA2_PLUGIN_H_ @}*/ diff --git a/src/libstrongswan/plugins/sqlite/Makefile.am b/src/libstrongswan/plugins/sqlite/Makefile.am new file mode 100644 index 000000000..7c3017abf --- /dev/null +++ b/src/libstrongswan/plugins/sqlite/Makefile.am @@ -0,0 +1,12 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan + +AM_CFLAGS = -rdynamic + +plugin_LTLIBRARIES = libstrongswan-sqlite.la + +libstrongswan_sqlite_la_SOURCES = sqlite_plugin.h sqlite_plugin.c \ + sqlite_database.h sqlite_database.c +libstrongswan_sqlite_la_LDFLAGS = -module +libstrongswan_sqlite_la_LIBADD = -lsqlite3 + diff --git a/src/libstrongswan/plugins/sqlite/sqlite_database.c b/src/libstrongswan/plugins/sqlite/sqlite_database.c new file mode 100644 index 000000000..06a89c68f --- /dev/null +++ b/src/libstrongswan/plugins/sqlite/sqlite_database.c @@ -0,0 +1,296 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "sqlite_database.h" + +#include +#include +#include +#include + +typedef struct private_sqlite_database_t private_sqlite_database_t; + +/** + * private data of sqlite_database + */ +struct private_sqlite_database_t { + + /** + * public functions + */ + sqlite_database_t public; + + /** + * sqlite database connection + */ + sqlite3 *db; + + /** + * mutex used to lock execute() + */ + mutex_t *mutex; +}; + +/** + * Create and run a sqlite stmt using a sql string and args + */ +static sqlite3_stmt* run(private_sqlite_database_t *this, char *sql, + va_list *args) +{ + sqlite3_stmt *stmt; + int params, i, res = SQLITE_OK; + + if (sqlite3_prepare_v2(this->db, sql, -1, &stmt, NULL) == SQLITE_OK) + { + params = sqlite3_bind_parameter_count(stmt); + for (i = 1; i <= params; i++) + { + switch (va_arg(*args, db_type_t)) + { + case DB_INT: + { + res = sqlite3_bind_int(stmt, i, va_arg(*args, int)); + break; + } + case DB_UINT: + { + res = sqlite3_bind_int64(stmt, i, va_arg(*args, u_int)); + break; + } + case DB_TEXT: + { + const char *text = va_arg(*args, const char*); + res = sqlite3_bind_text(stmt, i, text, -1, SQLITE_STATIC); + break; + } + case DB_BLOB: + { + chunk_t c = va_arg(*args, chunk_t); + res = sqlite3_bind_blob(stmt, i, c.ptr, c.len, SQLITE_STATIC); + break; + } + case DB_DOUBLE: + { + res = sqlite3_bind_double(stmt, i, va_arg(*args, double)); + break; + } + case DB_NULL: + { + res = sqlite3_bind_null(stmt, i); + break; + } + default: + { + res = SQLITE_MISUSE; + break; + } + } + if (res != SQLITE_OK) + { + break; + } + } + } + if (res != SQLITE_OK) + { + sqlite3_finalize(stmt); + return NULL; + } + return stmt; +} + +typedef struct { + /** implements enumerator_t */ + enumerator_t public; + /** associated sqlite statement */ + sqlite3_stmt *stmt; + /** number of result columns */ + int count; + /** column types */ + db_type_t *columns; +} sqlite_enumerator_t; + +/** + * destroy a sqlite enumerator + */ +static void sqlite_enumerator_destroy(sqlite_enumerator_t *this) +{ + sqlite3_finalize(this->stmt); + free(this->columns); + free(this); +} + +/** + * Implementation of database.query().enumerate + */ +static bool sqlite_enumerator_enumerate(sqlite_enumerator_t *this, ...) +{ + int i; + va_list args; + + if (sqlite3_step(this->stmt) != SQLITE_ROW) + { + return FALSE; + } + va_start(args, this); + for (i = 0; i < this->count; i++) + { + switch (this->columns[i]) + { + case DB_INT: + { + int *value = va_arg(args, int*); + *value = sqlite3_column_int(this->stmt, i); + break; + } + case DB_UINT: + { + u_int *value = va_arg(args, u_int*); + *value = (u_int)sqlite3_column_int64(this->stmt, i); + break; + } + case DB_TEXT: + { + const unsigned char **value = va_arg(args, const unsigned char**); + *value = sqlite3_column_text(this->stmt, i); + break; + } + case DB_BLOB: + { + chunk_t *chunk = va_arg(args, chunk_t*); + chunk->len = sqlite3_column_bytes(this->stmt, i); + chunk->ptr = (u_char*)sqlite3_column_blob(this->stmt, i); + break; + } + case DB_DOUBLE: + { + double *value = va_arg(args, double*); + *value = sqlite3_column_double(this->stmt, i); + break; + } + default: + return FALSE; + } + } + va_end(args); + return TRUE; +} + +/** + * Implementation of database_t.query. + */ +static enumerator_t* query(private_sqlite_database_t *this, char *sql, ...) +{ + sqlite3_stmt *stmt; + va_list args; + sqlite_enumerator_t *enumerator = NULL; + int i; + + + va_start(args, sql); + stmt = run(this, sql, &args); + if (stmt) + { + enumerator = malloc_thing(sqlite_enumerator_t); + enumerator->public.enumerate = (void*)sqlite_enumerator_enumerate; + enumerator->public.destroy = (void*)sqlite_enumerator_destroy; + enumerator->stmt = stmt; + enumerator->count = sqlite3_column_count(stmt); + enumerator->columns = malloc(sizeof(db_type_t) * enumerator->count); + for (i = 0; i < enumerator->count; i++) + { + enumerator->columns[i] = va_arg(args, db_type_t); + } + } + va_end(args); + return (enumerator_t*)enumerator; +} + +/** + * Implementation of database_t.execute. + */ +static int execute(private_sqlite_database_t *this, int *rowid, char *sql, ...) +{ + sqlite3_stmt *stmt; + int affected = -1; + va_list args; + + /* we need a lock to get our rowid/changes correctly */ + this->mutex->lock(this->mutex); + va_start(args, sql); + stmt = run(this, sql, &args); + va_end(args); + if (stmt) + { + if (sqlite3_step(stmt) == SQLITE_DONE) + { + if (rowid) + { + *rowid = sqlite3_last_insert_rowid(this->db); + } + affected = sqlite3_changes(this->db); + } + sqlite3_finalize(stmt); + } + this->mutex->unlock(this->mutex); + return affected; +} + +/** + * Implementation of database_t.destroy + */ +static void destroy(private_sqlite_database_t *this) +{ + sqlite3_close(this->db); + this->mutex->destroy(this->mutex); + free(this); +} + +/* + * see header file + */ +sqlite_database_t *sqlite_database_create(char *uri) +{ + char *file; + private_sqlite_database_t *this; + + /** + * parse sqlite:///path/to/file.db uri + */ + if (!strneq(uri, "sqlite://", 9)) + { + return NULL; + } + file = uri + 9; + + this = malloc_thing(private_sqlite_database_t); + + this->public.db.query = (enumerator_t* (*)(database_t *this, char *sql, ...))query; + this->public.db.execute = (int (*)(database_t *this, int *rowid, char *sql, ...))execute; + this->public.db.destroy = (void(*)(database_t*))destroy; + + if (sqlite3_open(file, &this->db) != SQLITE_OK) + { + DBG1("opening SQLite database '%s' failed", file); + destroy(this); + return NULL; + } + this->mutex = mutex_create(MUTEX_DEFAULT); + + return &this->public; +} + diff --git a/src/libstrongswan/plugins/sqlite/sqlite_database.h b/src/libstrongswan/plugins/sqlite/sqlite_database.h new file mode 100644 index 000000000..795785627 --- /dev/null +++ b/src/libstrongswan/plugins/sqlite/sqlite_database.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2007-2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 sqlite_database sqlite_database + * @{ @ingroup sqlite_p + */ + +#ifndef SQLITE_DATABASE_H_ +#define SQLITE_DATABASE_H_ + +#include + +typedef struct sqlite_database_t sqlite_database_t; + +/** + * sqlite databse_t implementation. + */ +struct sqlite_database_t { + + /** + * Implements database_t + */ + database_t db; +}; + +/** + * Create a sqlite_database instance. + * + * @param uri connection URI, sqlite:///path/to/file.db + */ +sqlite_database_t *sqlite_database_create(char *uri); + +#endif /* SQLITE_DATABASE_H_ @}*/ diff --git a/src/libstrongswan/plugins/sqlite/sqlite_plugin.c b/src/libstrongswan/plugins/sqlite/sqlite_plugin.c new file mode 100644 index 000000000..e31b572fa --- /dev/null +++ b/src/libstrongswan/plugins/sqlite/sqlite_plugin.c @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "sqlite_plugin.h" + +#include +#include "sqlite_database.h" + +typedef struct private_sqlite_plugin_t private_sqlite_plugin_t; + +/** + * private data of sqlite_plugin + */ +struct private_sqlite_plugin_t { + + /** + * public functions + */ + sqlite_plugin_t public; +}; + +/** + * Implementation of plugin_t.destroy + */ +static void destroy(private_sqlite_plugin_t *this) +{ + lib->db->remove_database(lib->db, + (database_constructor_t)sqlite_database_create); + free(this); +} + +/* + * see header file + */ +plugin_t *plugin_create() +{ + private_sqlite_plugin_t *this = malloc_thing(private_sqlite_plugin_t); + + this->public.plugin.destroy = (void(*)(plugin_t*))destroy; + + lib->db->add_database(lib->db, + (database_constructor_t)sqlite_database_create); + + return &this->public.plugin; +} + diff --git a/src/libstrongswan/plugins/sqlite/sqlite_plugin.h b/src/libstrongswan/plugins/sqlite/sqlite_plugin.h new file mode 100644 index 000000000..07bf9618f --- /dev/null +++ b/src/libstrongswan/plugins/sqlite/sqlite_plugin.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 sqlite_p sqlite + * @ingroup plugins + * + * @defgroup sqlite_plugin sqlite_plugin + * @{ @ingroup sqlite_p + */ + +#ifndef SQLITE_PLUGIN_H_ +#define SQLITE_PLUGIN_H_ + +#include + +typedef struct sqlite_plugin_t sqlite_plugin_t; + +/** + * Plugin implementing sqlite database connectivity + */ +struct sqlite_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +/** + * Create a sqlite_plugin instance. + */ +plugin_t *plugin_create(); + +#endif /* SQLITE_PLUGIN_H_ @}*/ diff --git a/src/libstrongswan/plugins/x509/Makefile.am b/src/libstrongswan/plugins/x509/Makefile.am new file mode 100644 index 000000000..12441b357 --- /dev/null +++ b/src/libstrongswan/plugins/x509/Makefile.am @@ -0,0 +1,13 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan + +AM_CFLAGS = -rdynamic + +plugin_LTLIBRARIES = libstrongswan-x509.la + +libstrongswan_x509_la_SOURCES = x509_plugin.h x509_plugin.c \ + x509_cert.h x509_cert.c x509_crl.h x509_crl.c \ + x509_ocsp_request.h x509_ocsp_request.c \ + x509_ocsp_response.h x509_ocsp_response.c +libstrongswan_x509_la_LDFLAGS = -module + diff --git a/src/libstrongswan/plugins/x509/x509_cert.c b/src/libstrongswan/plugins/x509/x509_cert.c new file mode 100644 index 000000000..47a841c51 --- /dev/null +++ b/src/libstrongswan/plugins/x509/x509_cert.c @@ -0,0 +1,1273 @@ +/* + * Copyright (C) 2000 Andreas Hess, Patric Lichtsteiner, Roger Wegmann + * Copyright (C) 2001 Marco Bertossa, Andreas Schleiss + * Copyright (C) 2002 Mario Strasser + * Copyright (C) 2000-2006 Andreas Steffen + * Copyright (C) 2006-2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#define _GNU_SOURCE + +#include "x509_cert.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * Different kinds of generalNames + */ +typedef enum { + GN_OTHER_NAME = 0, + GN_RFC822_NAME = 1, + GN_DNS_NAME = 2, + GN_X400_ADDRESS = 3, + GN_DIRECTORY_NAME = 4, + GN_EDI_PARTY_NAME = 5, + GN_URI = 6, + GN_IP_ADDRESS = 7, + GN_REGISTERED_ID = 8, +} generalNames_t; + + +typedef struct private_x509_cert_t private_x509_cert_t; + +/** + * Private data of a x509_cert_t object. + */ +struct private_x509_cert_t { + /** + * Public interface for this certificate. + */ + x509_cert_t public; + + /** + * DER encoded X.509 certificate + */ + chunk_t certificate; + + /** + * X.509 certificate body over which signature is computed + */ + chunk_t tbsCertificate; + + /** + * Version of the X.509 certificate + */ + u_int version; + + /** + * Serial number of the X.509 certificate + */ + chunk_t serialNumber; + + /** + * ID representing the certificate issuer + */ + identification_t *issuer; + + /** + * Start time of certificate validity + */ + time_t notBefore; + + /** + * End time of certificate validity + */ + time_t notAfter; + + /** + * ID representing the certificate subject + */ + identification_t *subject; + + /** + * List of subjectAltNames as identification_t + */ + linked_list_t *subjectAltNames; + + /** + * List of crlDistributionPoints as allocated char* + */ + linked_list_t *crl_uris; + + /** + * List ocspAccessLocations as identification_t + */ + linked_list_t *ocsp_uris; + + /** + * certificates embedded public key + */ + public_key_t *public_key; + + /** + * Subject Key Identifier + */ + chunk_t subjectKeyID; + + /** + * Authority Key Identifier + */ + identification_t *authKeyIdentifier; + + /** + * Authority Key Serial Number + */ + chunk_t authKeySerialNumber; + + /** + * x509 constraints and other flags + */ + x509_flag_t flags; + + /** + * Signature algorithm + */ + int algorithm; + + /** + * Signature + */ + chunk_t signature; + + /** + * reference count + */ + refcount_t ref; +}; + +/** + * ASN.1 definition of generalName + */ +static const asn1Object_t generalNameObjects[] = { + { 0, "otherName", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_BODY }, /* 0 */ + { 0, "end choice", ASN1_EOC, ASN1_END }, /* 1 */ + { 0, "rfc822Name", ASN1_CONTEXT_S_1, ASN1_OPT|ASN1_BODY }, /* 2 */ + { 0, "end choice", ASN1_EOC, ASN1_END }, /* 3 */ + { 0, "dnsName", ASN1_CONTEXT_S_2, ASN1_OPT|ASN1_BODY }, /* 4 */ + { 0, "end choice", ASN1_EOC, ASN1_END }, /* 5 */ + { 0, "x400Address", ASN1_CONTEXT_S_3, ASN1_OPT|ASN1_BODY }, /* 6 */ + { 0, "end choice", ASN1_EOC, ASN1_END }, /* 7 */ + { 0, "directoryName", ASN1_CONTEXT_C_4, ASN1_OPT|ASN1_BODY }, /* 8 */ + { 0, "end choice", ASN1_EOC, ASN1_END }, /* 9 */ + { 0, "ediPartyName", ASN1_CONTEXT_C_5, ASN1_OPT|ASN1_BODY }, /* 10 */ + { 0, "end choice", ASN1_EOC, ASN1_END }, /* 11 */ + { 0, "URI", ASN1_CONTEXT_S_6, ASN1_OPT|ASN1_BODY }, /* 12 */ + { 0, "end choice", ASN1_EOC, ASN1_END }, /* 13 */ + { 0, "ipAddress", ASN1_CONTEXT_S_7, ASN1_OPT|ASN1_BODY }, /* 14 */ + { 0, "end choice", ASN1_EOC, ASN1_END }, /* 15 */ + { 0, "registeredID", ASN1_CONTEXT_S_8, ASN1_OPT|ASN1_BODY }, /* 16 */ + { 0, "end choice", ASN1_EOC, ASN1_END } /* 17 */ +}; + +#define GN_OBJ_OTHER_NAME 0 +#define GN_OBJ_RFC822_NAME 2 +#define GN_OBJ_DNS_NAME 4 +#define GN_OBJ_X400_ADDRESS 6 +#define GN_OBJ_DIRECTORY_NAME 8 +#define GN_OBJ_EDI_PARTY_NAME 10 +#define GN_OBJ_URI 12 +#define GN_OBJ_IP_ADDRESS 14 +#define GN_OBJ_REGISTERED_ID 16 +#define GN_OBJ_ROOF 18 + +/** + * ASN.1 definition of otherName + */ +static const asn1Object_t otherNameObjects[] = { + {0, "type-id", ASN1_OID, ASN1_BODY }, /* 0 */ + {0, "value", ASN1_CONTEXT_C_0, ASN1_BODY } /* 1 */ +}; + +#define ON_OBJ_ID_TYPE 0 +#define ON_OBJ_VALUE 1 +#define ON_OBJ_ROOF 2 + +/** + * ASN.1 definition of a basicConstraints extension + */ +static const asn1Object_t basicConstraintsObjects[] = { + { 0, "basicConstraints", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ + { 1, "CA", ASN1_BOOLEAN, ASN1_DEF|ASN1_BODY }, /* 1 */ + { 1, "pathLenConstraint", ASN1_INTEGER, ASN1_OPT|ASN1_BODY }, /* 2 */ + { 1, "end opt", ASN1_EOC, ASN1_END } /* 3 */ +}; + +#define BASIC_CONSTRAINTS_CA 1 +#define BASIC_CONSTRAINTS_ROOF 4 + +/** + * ASN.1 definition of a keyIdentifier + */ +static const asn1Object_t keyIdentifierObjects[] = { + { 0, "keyIdentifier", ASN1_OCTET_STRING, ASN1_BODY } /* 0 */ +}; + +/** + * ASN.1 definition of a authorityKeyIdentifier extension + */ +static const asn1Object_t authorityKeyIdentifierObjects[] = { + { 0, "authorityKeyIdentifier", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ + { 1, "keyIdentifier", ASN1_CONTEXT_S_0, ASN1_OPT|ASN1_OBJ }, /* 1 */ + { 1, "end opt", ASN1_EOC, ASN1_END }, /* 2 */ + { 1, "authorityCertIssuer", ASN1_CONTEXT_C_1, ASN1_OPT|ASN1_OBJ }, /* 3 */ + { 1, "end opt", ASN1_EOC, ASN1_END }, /* 4 */ + { 1, "authorityCertSerialNumber",ASN1_CONTEXT_S_2, ASN1_OPT|ASN1_BODY }, /* 5 */ + { 1, "end opt", ASN1_EOC, ASN1_END } /* 6 */ +}; + +#define AUTH_KEY_ID_KEY_ID 1 +#define AUTH_KEY_ID_CERT_ISSUER 3 +#define AUTH_KEY_ID_CERT_SERIAL 5 +#define AUTH_KEY_ID_ROOF 7 + +/** + * ASN.1 definition of a authorityInfoAccess extension + */ +static const asn1Object_t authorityInfoAccessObjects[] = { + { 0, "authorityInfoAccess", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ + { 1, "accessDescription", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */ + { 2, "accessMethod", ASN1_OID, ASN1_BODY }, /* 2 */ + { 2, "accessLocation", ASN1_EOC, ASN1_RAW }, /* 3 */ + { 0, "end loop", ASN1_EOC, ASN1_END } /* 4 */ +}; + +#define AUTH_INFO_ACCESS_METHOD 2 +#define AUTH_INFO_ACCESS_LOCATION 3 +#define AUTH_INFO_ACCESS_ROOF 5 + +/** + * ASN.1 definition of a extendedKeyUsage extension + */ +static const asn1Object_t extendedKeyUsageObjects[] = { + { 0, "extendedKeyUsage", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ + { 1, "keyPurposeID", ASN1_OID, ASN1_BODY }, /* 1 */ + { 0, "end loop", ASN1_EOC, ASN1_END }, /* 2 */ +}; + +#define EXT_KEY_USAGE_PURPOSE_ID 1 +#define EXT_KEY_USAGE_ROOF 3 + +/** + * ASN.1 definition of generalNames + */ +static const asn1Object_t generalNamesObjects[] = { + { 0, "generalNames", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ + { 1, "generalName", ASN1_EOC, ASN1_RAW }, /* 1 */ + { 0, "end loop", ASN1_EOC, ASN1_END } /* 2 */ +}; + +#define GENERAL_NAMES_GN 1 +#define GENERAL_NAMES_ROOF 3 + + +/** + * ASN.1 definition of crlDistributionPoints + */ +static const asn1Object_t crlDistributionPointsObjects[] = { + { 0, "crlDistributionPoints", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ + { 1, "DistributionPoint", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */ + { 2, "distributionPoint", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_LOOP }, /* 2 */ + { 3, "fullName", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_OBJ }, /* 3 */ + { 3, "end choice", ASN1_EOC, ASN1_END }, /* 4 */ + { 3, "nameRelToCRLIssuer",ASN1_CONTEXT_C_1, ASN1_OPT|ASN1_BODY }, /* 5 */ + { 3, "end choice", ASN1_EOC, ASN1_END }, /* 6 */ + { 2, "end opt", ASN1_EOC, ASN1_END }, /* 7 */ + { 2, "reasons", ASN1_CONTEXT_C_1, ASN1_OPT|ASN1_BODY }, /* 8 */ + { 2, "end opt", ASN1_EOC, ASN1_END }, /* 9 */ + { 2, "crlIssuer", ASN1_CONTEXT_C_2, ASN1_OPT|ASN1_BODY }, /* 10 */ + { 2, "end opt", ASN1_EOC, ASN1_END }, /* 11 */ + { 0, "end loop", ASN1_EOC, ASN1_END }, /* 12 */ +}; + +#define CRL_DIST_POINTS_FULLNAME 3 +#define CRL_DIST_POINTS_ROOF 13 + +/** + * ASN.1 definition of an X.509v3 x509_cert + */ +static const asn1Object_t certObjects[] = { + { 0, "x509", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */ + { 1, "tbsCertificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */ + { 2, "DEFAULT v1", ASN1_CONTEXT_C_0, ASN1_DEF }, /* 2 */ + { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 3 */ + { 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 4 */ + { 2, "signature", ASN1_EOC, ASN1_RAW }, /* 5 */ + { 2, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 6 */ + { 2, "validity", ASN1_SEQUENCE, ASN1_NONE }, /* 7 */ + { 3, "notBefore", ASN1_EOC, ASN1_RAW }, /* 8 */ + { 3, "notAfter", ASN1_EOC, ASN1_RAW }, /* 9 */ + { 2, "subject", ASN1_SEQUENCE, ASN1_OBJ }, /* 10 */ + { 2, "subjectPublicKeyInfo",ASN1_SEQUENCE, ASN1_NONE }, /* 11 */ + { 3, "algorithm", ASN1_EOC, ASN1_RAW }, /* 12 */ + { 3, "subjectPublicKey", ASN1_BIT_STRING, ASN1_NONE }, /* 13 */ + { 4, "RSAPublicKey", ASN1_SEQUENCE, ASN1_RAW }, /* 14 */ + { 2, "issuerUniqueID", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 15 */ + { 2, "end opt", ASN1_EOC, ASN1_END }, /* 16 */ + { 2, "subjectUniqueID", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 17 */ + { 2, "end opt", ASN1_EOC, ASN1_END }, /* 18 */ + { 2, "optional extensions", ASN1_CONTEXT_C_3, ASN1_OPT }, /* 19 */ + { 3, "extensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 20 */ + { 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 21 */ + { 5, "extnID", ASN1_OID, ASN1_BODY }, /* 22 */ + { 5, "critical", ASN1_BOOLEAN, ASN1_DEF|ASN1_BODY }, /* 23 */ + { 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 24 */ + { 3, "end loop", ASN1_EOC, ASN1_END }, /* 25 */ + { 2, "end opt", ASN1_EOC, ASN1_END }, /* 26 */ + { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 27 */ + { 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY } /* 28 */ +}; + +#define X509_OBJ_TBS_CERTIFICATE 1 +#define X509_OBJ_VERSION 3 +#define X509_OBJ_SERIAL_NUMBER 4 +#define X509_OBJ_SIG_ALG 5 +#define X509_OBJ_ISSUER 6 +#define X509_OBJ_NOT_BEFORE 8 +#define X509_OBJ_NOT_AFTER 9 +#define X509_OBJ_SUBJECT 10 +#define X509_OBJ_SUBJECT_PUBLIC_KEY_ALGORITHM 12 +#define X509_OBJ_SUBJECT_PUBLIC_KEY 13 +#define X509_OBJ_RSA_PUBLIC_KEY 14 +#define X509_OBJ_EXTN_ID 22 +#define X509_OBJ_CRITICAL 23 +#define X509_OBJ_EXTN_VALUE 24 +#define X509_OBJ_ALGORITHM 27 +#define X509_OBJ_SIGNATURE 28 +#define X509_OBJ_ROOF 29 + + +static u_char ASN1_sAN_oid_buf[] = { + 0x06, 0x03, 0x55, 0x1D, 0x11 +}; +static const chunk_t ASN1_subjectAltName_oid = chunk_from_buf(ASN1_sAN_oid_buf); + +/** + * extracts the basicConstraints extension + */ +static bool parse_basicConstraints(chunk_t blob, int level0) +{ + asn1_ctx_t ctx; + chunk_t object; + u_int level; + int objectID = 0; + bool isCA = FALSE; + + asn1_init(&ctx, blob, level0, FALSE, FALSE); + while (objectID < BASIC_CONSTRAINTS_ROOF) { + + if (!extract_object(basicConstraintsObjects, &objectID, &object,&level, &ctx)) + { + break; + } + if (objectID == BASIC_CONSTRAINTS_CA) + { + isCA = object.len && *object.ptr; + DBG2(" %s", isCA ? "TRUE" : "FALSE"); + } + objectID++; + } + return isCA; +} + +/* + * extracts an otherName + */ +static bool parse_otherName(chunk_t blob, int level0) +{ + asn1_ctx_t ctx; + chunk_t object; + u_int level; + int objectID = 0; + int oid = OID_UNKNOWN; + + asn1_init(&ctx, blob, level0, FALSE, FALSE); + while (objectID < ON_OBJ_ROOF) + { + if (!extract_object(otherNameObjects, &objectID, &object, &level, &ctx)) + { + return FALSE; + } + switch (objectID) + { + case ON_OBJ_ID_TYPE: + oid = known_oid(object); + break; + case ON_OBJ_VALUE: + if (oid == OID_XMPP_ADDR) + { + if (!parse_asn1_simple_object(&object, ASN1_UTF8STRING, + level + 1, "xmppAddr")) + { + return FALSE; + } + } + break; + default: + break; + } + objectID++; + } + return TRUE; +} + +/* + * extracts a generalName + */ +static identification_t *parse_generalName(chunk_t blob, int level0) +{ + asn1_ctx_t ctx; + chunk_t object; + int objectID = 0; + u_int level; + + asn1_init(&ctx, blob, level0, FALSE, FALSE); + while (objectID < GN_OBJ_ROOF) + { + id_type_t id_type = ID_ANY; + + if (!extract_object(generalNameObjects, &objectID, &object, &level, &ctx)) + { + return NULL; + } + switch (objectID) + { + case GN_OBJ_RFC822_NAME: + id_type = ID_RFC822_ADDR; + break; + case GN_OBJ_DNS_NAME: + id_type = ID_FQDN; + break; + case GN_OBJ_URI: + id_type = ID_DER_ASN1_GN_URI; + break; + case GN_OBJ_DIRECTORY_NAME: + id_type = ID_DER_ASN1_DN; + break; + case GN_OBJ_IP_ADDRESS: + id_type = ID_IPV4_ADDR; + break; + case GN_OBJ_OTHER_NAME: + if (!parse_otherName(object, level + 1)) + return NULL; + break; + case GN_OBJ_X400_ADDRESS: + case GN_OBJ_EDI_PARTY_NAME: + case GN_OBJ_REGISTERED_ID: + break; + default: + break; + } + if (id_type != ID_ANY) + { + identification_t *gn = identification_create_from_encoding(id_type, object); + DBG2(" '%D'", gn); + return gn; + } + objectID++; + } + return NULL; +} + + +/** + * extracts one or several GNs and puts them into a chained list + */ +void parse_generalNames(chunk_t blob, int level0, bool implicit, linked_list_t *list) +{ + asn1_ctx_t ctx; + chunk_t object; + u_int level; + int objectID = 0; + + asn1_init(&ctx, blob, level0, implicit, FALSE); + while (objectID < GENERAL_NAMES_ROOF) + { + if (!extract_object(generalNamesObjects, &objectID, &object, &level, &ctx)) + { + return; + } + if (objectID == GENERAL_NAMES_GN) + { + identification_t *gn = parse_generalName(object, level+1); + + if (gn != NULL) + { + list->insert_last(list, (void *)gn); + } + } + objectID++; + } + return; +} + +/** + * extracts a keyIdentifier + */ +static chunk_t parse_keyIdentifier(chunk_t blob, int level0, bool implicit) +{ + asn1_ctx_t ctx; + chunk_t object; + u_int level; + int objectID = 0; + + asn1_init(&ctx, blob, level0, implicit, FALSE); + if (!extract_object(keyIdentifierObjects, &objectID, &object, &level, &ctx)) + { + return chunk_empty; + } + return object; +} + +/** + * extracts an authoritykeyIdentifier + */ +identification_t* x509_parse_authorityKeyIdentifier(chunk_t blob, int level0, + chunk_t *authKeySerialNumber) +{ + asn1_ctx_t ctx; + chunk_t object; + u_int level; + int objectID = 0; + identification_t *authKeyIdentifier = NULL; + + *authKeySerialNumber = chunk_empty; + + asn1_init(&ctx, blob, level0, FALSE, FALSE); + while (objectID < AUTH_KEY_ID_ROOF) + { + if (!extract_object(authorityKeyIdentifierObjects, &objectID, &object, &level, &ctx)) + { + return NULL; + } + switch (objectID) + { + case AUTH_KEY_ID_KEY_ID: + { + chunk_t authKeyID = parse_keyIdentifier(object, level+1, TRUE); + + if (authKeyID.ptr == NULL) + { + return NULL; + } + authKeyIdentifier = identification_create_from_encoding( + ID_PUBKEY_SHA1, authKeyID); + break; + } + case AUTH_KEY_ID_CERT_ISSUER: + { + /* TODO: parse_generalNames(object, level+1, TRUE); */ + break; + } + case AUTH_KEY_ID_CERT_SERIAL: + *authKeySerialNumber = object; + break; + default: + break; + } + objectID++; + } + return authKeyIdentifier; +} + +/** + * extracts an authorityInfoAcess location + */ +static void parse_authorityInfoAccess(chunk_t blob, int level0, + private_x509_cert_t *this) +{ + asn1_ctx_t ctx; + chunk_t object; + u_int level; + int objectID = 0; + int accessMethod = OID_UNKNOWN; + + asn1_init(&ctx, blob, level0, FALSE, FALSE); + while (objectID < AUTH_INFO_ACCESS_ROOF) + { + if (!extract_object(authorityInfoAccessObjects, &objectID, &object, &level, &ctx)) + { + return; + } + switch (objectID) + { + case AUTH_INFO_ACCESS_METHOD: + accessMethod = known_oid(object); + break; + case AUTH_INFO_ACCESS_LOCATION: + { + switch (accessMethod) + { + case OID_OCSP: + case OID_CA_ISSUERS: + { + identification_t *id; + char *uri; + + id = parse_generalName(object, level+1); + if (id == NULL) + { /* parsing went wrong - abort */ + return; + } + DBG2(" '%D'", id); + if (accessMethod == OID_OCSP && + asprintf(&uri, "%D", id) > 0) + { + this->ocsp_uris->insert_last(this->ocsp_uris, uri); + } + id->destroy(id); + } + break; + default: + /* unkown accessMethod, ignoring */ + break; + } + break; + } + default: + break; + } + objectID++; + } +} + +/** + * extracts extendedKeyUsage OIDs + */ +static bool parse_extendedKeyUsage(chunk_t blob, int level0) +{ + asn1_ctx_t ctx; + chunk_t object; + u_int level; + int objectID = 0; + + asn1_init(&ctx, blob, level0, FALSE, FALSE); + while (objectID < EXT_KEY_USAGE_ROOF) + { + if (!extract_object(extendedKeyUsageObjects, &objectID, &object, &level, &ctx)) + { + return FALSE; + } + if (objectID == EXT_KEY_USAGE_PURPOSE_ID && + known_oid(object) == OID_OCSP_SIGNING) + { + return TRUE; + } + objectID++; + } + return FALSE; +} + +/** + * extracts one or several crlDistributionPoints into a list + */ +static void parse_crlDistributionPoints(chunk_t blob, int level0, + private_x509_cert_t *this) +{ + asn1_ctx_t ctx; + chunk_t object; + u_int level; + int objectID = 0; + linked_list_t *list; + identification_t *id; + char *uri; + + list = linked_list_create(); + asn1_init(&ctx, blob, level0, FALSE, FALSE); + while (objectID < CRL_DIST_POINTS_ROOF) + { + if (!extract_object(crlDistributionPointsObjects, &objectID, &object, &level, &ctx)) + { + list->destroy_offset(list, offsetof(identification_t, destroy)); + return; + } + if (objectID == CRL_DIST_POINTS_FULLNAME) + { /* append extracted generalNames to existing chained list */ + parse_generalNames(object, level+1, TRUE, list); + + while (list->remove_last(list, (void**)&id) == SUCCESS) + { + if (asprintf(&uri, "%D", id) > 0) + { + this->crl_uris->insert_last(this->crl_uris, uri); + } + id->destroy(id); + } + } + objectID++; + } + list->destroy(list); +} + +/** + * Parses an X.509v3 certificate + */ +static bool parse_certificate(private_x509_cert_t *this) +{ + asn1_ctx_t ctx; + bool critical; + chunk_t object; + u_int level; + int objectID = 0; + int extn_oid = OID_UNKNOWN; + int key_alg = 0; + int sig_alg = 0; + chunk_t subjectPublicKey = chunk_empty; + + asn1_init(&ctx, this->certificate, 0, FALSE, FALSE); + while (objectID < X509_OBJ_ROOF) + { + if (!extract_object(certObjects, &objectID, &object, &level, &ctx)) + { + return FALSE; + } + /* those objects which will parsed further need the next higher level */ + level++; + switch (objectID) + { + case X509_OBJ_TBS_CERTIFICATE: + this->tbsCertificate = object; + break; + case X509_OBJ_VERSION: + this->version = (object.len) ? (1+(u_int)*object.ptr) : 1; + DBG2(" v%d", this->version); + break; + case X509_OBJ_SERIAL_NUMBER: + this->serialNumber = object; + break; + case X509_OBJ_SIG_ALG: + sig_alg = parse_algorithmIdentifier(object, level, NULL); + break; + case X509_OBJ_ISSUER: + this->issuer = identification_create_from_encoding(ID_DER_ASN1_DN, object); + DBG2(" '%D'", this->issuer); + break; + case X509_OBJ_NOT_BEFORE: + this->notBefore = parse_time(object, level); + break; + case X509_OBJ_NOT_AFTER: + this->notAfter = parse_time(object, level); + break; + case X509_OBJ_SUBJECT: + this->subject = identification_create_from_encoding(ID_DER_ASN1_DN, object); + DBG2(" '%D'", this->subject); + break; + case X509_OBJ_SUBJECT_PUBLIC_KEY_ALGORITHM: + key_alg = parse_algorithmIdentifier(object, level, NULL); + break; + case X509_OBJ_SUBJECT_PUBLIC_KEY: + if (ctx.blobs[4].len > 0 && *ctx.blobs[4].ptr == 0x00) + { + /* skip initial bit string octet defining 0 unused bits */ + ctx.blobs[4].ptr++; ctx.blobs[4].len--; + } + break; + case X509_OBJ_RSA_PUBLIC_KEY: + subjectPublicKey = object; + switch (key_alg) + { + case OID_RSA_ENCRYPTION: + this->public_key = lib->creds->create(lib->creds, + CRED_PUBLIC_KEY, KEY_RSA, + BUILD_BLOB_ASN1_DER, chunk_clone(subjectPublicKey), + BUILD_END); + break; + default: + DBG1("parsing key type %d failed", key_alg); + return FALSE; + } + break; + case X509_OBJ_EXTN_ID: + extn_oid = known_oid(object); + break; + case X509_OBJ_CRITICAL: + critical = object.len && *object.ptr; + DBG2(" %s", critical ? "TRUE" : "FALSE"); + break; + case X509_OBJ_EXTN_VALUE: + { + switch (extn_oid) + { + case OID_SUBJECT_KEY_ID: + this->subjectKeyID = parse_keyIdentifier(object, level, FALSE); + break; + case OID_SUBJECT_ALT_NAME: + parse_generalNames(object, level, FALSE, this->subjectAltNames); + break; + case OID_BASIC_CONSTRAINTS: + if (parse_basicConstraints(object, level)) + { + this->flags |= X509_CA; + } + break; + case OID_CRL_DISTRIBUTION_POINTS: + parse_crlDistributionPoints(object, level, this); + break; + case OID_AUTHORITY_KEY_ID: + this->authKeyIdentifier = x509_parse_authorityKeyIdentifier(object, + level, &this->authKeySerialNumber); + break; + case OID_AUTHORITY_INFO_ACCESS: + parse_authorityInfoAccess(object, level, this); + break; + case OID_EXTENDED_KEY_USAGE: + if (parse_extendedKeyUsage(object, level)) + { + this->flags |= X509_OCSP_SIGNER; + } + break; + case OID_NS_REVOCATION_URL: + case OID_NS_CA_REVOCATION_URL: + case OID_NS_CA_POLICY_URL: + case OID_NS_COMMENT: + if (!parse_asn1_simple_object(&object, ASN1_IA5STRING, + level, oid_names[extn_oid].name)) + return FALSE; + break; + default: + break; + } + break; + } + case X509_OBJ_ALGORITHM: + this->algorithm = parse_algorithmIdentifier(object, level, NULL); + if (this->algorithm != sig_alg) + { + DBG1(" signature algorithms do not agree"); + return FALSE; + } + break; + case X509_OBJ_SIGNATURE: + this->signature = object; + break; + default: + break; + } + objectID++; + } + return TRUE; +} + +/** + * Implementation of certificate_t.get_type + */ +static certificate_type_t get_type(private_x509_cert_t *this) +{ + return CERT_X509; +} + +/** + * Implementation of certificate_t.get_subject + */ +static identification_t* get_subject(private_x509_cert_t *this) +{ + return this->subject; +} + +/** + * Implementation of certificate_t.get_issuer + */ +static identification_t* get_issuer(private_x509_cert_t *this) +{ + return this->issuer; +} + +/** + * Implementation of certificate_t.has_subject. + */ +static id_match_t has_subject(private_x509_cert_t *this, identification_t *subject) +{ + identification_t *current; + enumerator_t *enumerator; + id_match_t match, best; + + best = this->subject->matches(this->subject, subject); + enumerator = this->subjectAltNames->create_enumerator(this->subjectAltNames); + while (enumerator->enumerate(enumerator, ¤t)) + { + match = current->matches(current, subject); + if (match > best) + { + best = match; + } + } + enumerator->destroy(enumerator); + return best; +} + +/** + * Implementation of certificate_t.has_subject. + */ +static id_match_t has_issuer(private_x509_cert_t *this, identification_t *issuer) +{ + /* issuerAltNames currently not supported */ + return this->issuer->matches(this->issuer, issuer); +} + +/** + * Implementation of certificate_t.issued_by + */ +static bool issued_by(private_x509_cert_t *this, certificate_t *issuer, + bool sigcheck) +{ + public_key_t *key; + signature_scheme_t scheme; + bool valid; + x509_t *x509 = (x509_t*)issuer; + + if (&this->public.interface.interface == issuer && + (this->flags & X509_SELF_SIGNED)) + { + return TRUE; + } + if (issuer->get_type(issuer) != CERT_X509) + { + return FALSE; + } + if (!this->issuer->equals(this->issuer, issuer->get_subject(issuer))) + { + return FALSE; + } + if (!(x509->get_flags(x509) & X509_CA)) + { + return FALSE; + } + if (!sigcheck) + { + return TRUE; + } + /* TODO: generic OID to scheme mapper? */ + switch (this->algorithm) + { + case OID_MD5_WITH_RSA: + scheme = SIGN_RSA_EMSA_PKCS1_MD5; + break; + case OID_SHA1_WITH_RSA: + scheme = SIGN_RSA_EMSA_PKCS1_SHA1; + break; + case OID_SHA256_WITH_RSA: + scheme = SIGN_RSA_EMSA_PKCS1_SHA256; + break; + case OID_SHA384_WITH_RSA: + scheme = SIGN_RSA_EMSA_PKCS1_SHA384; + break; + case OID_SHA512_WITH_RSA: + scheme = SIGN_RSA_EMSA_PKCS1_SHA512; + break; + default: + return FALSE; + } + key = issuer->get_public_key(issuer); + if (key == NULL) + { + return FALSE; + } + /* TODO: add a lightweight check option (comparing auth/subject keyids only) */ + valid = key->verify(key, scheme, this->tbsCertificate, this->signature); + key->destroy(key); + return valid; +} + +/** + * Implementation of certificate_t.get_public_key + */ +static public_key_t* get_public_key(private_x509_cert_t *this) +{ + this->public_key->get_ref(this->public_key); + return this->public_key; +} + +/** + * Implementation of certificate_t.asdf + */ +static private_x509_cert_t* get_ref(private_x509_cert_t *this) +{ + ref_get(&this->ref); + return this; +} + +/** + * Implementation of x509_cert_t.set_flags. + */ +static void set_flags(private_x509_cert_t *this, x509_flag_t flags) +{ + this->flags = flags; +} + +/** + * Implementation of x509_cert_t.get_flags. + */ +static x509_flag_t get_flags(private_x509_cert_t *this) +{ + return this->flags; +} + +/** + * Implementation of x509_cert_t.get_validity. + */ +static bool get_validity(private_x509_cert_t *this, time_t *when, + time_t *not_before, time_t *not_after) +{ + time_t t; + + if (when) + { + t = *when; + } + else + { + t = time(NULL); + } + if (not_after) + { + *not_after = this->notAfter; + } + if (not_before) + { + *not_before = this->notBefore; + } + return (t >= this->notBefore && t <= this->notAfter); +} + +/** + * Implementation of certificate_t.get_encoding. + */ +static chunk_t get_encoding(private_x509_cert_t *this) +{ + return chunk_clone(this->certificate); +} + +/** + * Implementation of certificate_t.equals. + */ +static bool equals(private_x509_cert_t *this, certificate_t *other) +{ + if (this == (private_x509_cert_t*)other) + { + return TRUE; + } + if (other->get_type(other) != CERT_X509) + { + return FALSE; + } + /* check if we have the same X509 implementation */ + if (other->equals == (void*)equals) + { + if (this->signature.len == 0) + { + return FALSE; + } + return chunk_equals(this->signature, ((private_x509_cert_t*)other)->signature); + } + /* TODO: compare against other implementation */ + return FALSE; +} + +/** + * Implementation of x509_t.get_serial. + */ +static chunk_t get_serial(private_x509_cert_t *this) +{ + return this->serialNumber; +} + +/** + * Implementation of x509_t.get_authKeyIdentifier. + */ +static identification_t *get_authKeyIdentifier(private_x509_cert_t *this) +{ + return this->authKeyIdentifier; +} + +/** + * Implementation of x509_cert_t.create_subjectAltName_enumerator. + */ +static enumerator_t* create_subjectAltName_enumerator(private_x509_cert_t *this) +{ + return this->subjectAltNames->create_enumerator(this->subjectAltNames); +} + +/** + * Implementation of x509_cert_t.create_ocsp_uri_enumerator. + */ +static enumerator_t* create_ocsp_uri_enumerator(private_x509_cert_t *this) +{ + return this->ocsp_uris->create_enumerator(this->ocsp_uris); +} + +/** + * Implementation of x509_cert_t.create_crl_uri_enumerator. + */ +static enumerator_t* create_crl_uri_enumerator(private_x509_cert_t *this) +{ + return this->crl_uris->create_enumerator(this->crl_uris); +} + +/** + * Implementation of certificate_t.asdf + */ +static void destroy(private_x509_cert_t *this) +{ + if (ref_put(&this->ref)) + { + this->subjectAltNames->destroy_offset(this->subjectAltNames, + offsetof(identification_t, destroy)); + this->crl_uris->destroy_function(this->crl_uris, free); + this->ocsp_uris->destroy_function(this->ocsp_uris, free); + DESTROY_IF(this->issuer); + DESTROY_IF(this->subject); + DESTROY_IF(this->public_key); + DESTROY_IF(this->authKeyIdentifier); + chunk_free(&this->certificate); + free(this); + } +} + +/** + * load x509 certificate from a chunk + */ +static x509_cert_t *load(chunk_t chunk) +{ + private_x509_cert_t *this = malloc_thing(private_x509_cert_t); + + this->public.interface.interface.get_type = (certificate_type_t (*)(certificate_t *this))get_type; + this->public.interface.interface.get_subject = (identification_t* (*)(certificate_t *this))get_subject; + this->public.interface.interface.get_issuer = (identification_t* (*)(certificate_t *this))get_issuer; + this->public.interface.interface.has_subject = (id_match_t (*)(certificate_t*, identification_t *subject))has_subject; + this->public.interface.interface.has_issuer = (id_match_t (*)(certificate_t*, identification_t *issuer))has_issuer; + this->public.interface.interface.issued_by = (bool (*)(certificate_t *this, certificate_t *issuer,bool))issued_by; + this->public.interface.interface.get_public_key = (public_key_t* (*)(certificate_t *this))get_public_key; + this->public.interface.interface.get_validity = (bool (*)(certificate_t*, time_t *when, time_t *, time_t*))get_validity; + this->public.interface.interface.get_encoding = (chunk_t (*)(certificate_t*))get_encoding; + this->public.interface.interface.equals = (bool (*)(certificate_t*, certificate_t *other))equals; + this->public.interface.interface.get_ref = (certificate_t* (*)(certificate_t *this))get_ref; + this->public.interface.interface.destroy = (void (*)(certificate_t *this))destroy; + this->public.interface.set_flags = (void (*)(x509_t*, x509_flag_t flags))set_flags; + this->public.interface.get_flags = (x509_flag_t (*)(x509_t*))get_flags; + this->public.interface.get_serial = (chunk_t (*)(x509_t*))get_serial; + this->public.interface.get_authKeyIdentifier = (identification_t* (*)(x509_t*))get_authKeyIdentifier; + this->public.interface.create_subjectAltName_enumerator = (enumerator_t* (*)(x509_t*))create_subjectAltName_enumerator; + this->public.interface.create_crl_uri_enumerator = (enumerator_t* (*)(x509_t*))create_crl_uri_enumerator; + this->public.interface.create_ocsp_uri_enumerator = (enumerator_t* (*)(x509_t*))create_ocsp_uri_enumerator; + + this->certificate = chunk; + this->public_key = NULL; + this->subject = NULL; + this->issuer = NULL; + this->subjectAltNames = linked_list_create(); + this->crl_uris = linked_list_create(); + this->ocsp_uris = linked_list_create(); + this->subjectKeyID = chunk_empty; + this->authKeyIdentifier = NULL; + this->authKeySerialNumber = chunk_empty; + this->flags = 0; + this->ref = 1; + + if (!parse_certificate(this)) + { + destroy(this); + return NULL; + } + if (issued_by(this, &this->public.interface.interface, FALSE)) + { + this->flags |= X509_SELF_SIGNED; + } + return &this->public; +} + +typedef struct private_builder_t private_builder_t; +/** + * Builder implementation for certificate loading + */ +struct private_builder_t { + /** implements the builder interface */ + builder_t public; + /** loaded certificate */ + x509_cert_t *cert; +}; + +/** + * Implementation of builder_t.build + */ +static x509_cert_t *build(private_builder_t *this) +{ + x509_cert_t *cert = this->cert; + + free(this); + return cert; +} + +/** + * Implementation of builder_t.add + */ +static void add(private_builder_t *this, builder_part_t part, ...) +{ + va_list args; + + if (this->cert) + { + DBG1("ignoring surplus build part %N", builder_part_names, part); + return; + } + + switch (part) + { + case BUILD_BLOB_ASN1_DER: + { + va_start(args, part); + this->cert = load(va_arg(args, chunk_t)); + va_end(args); + break; + } + default: + DBG1("ignoring unsupported build part %N", builder_part_names, part); + break; + } +} + +/** + * Builder construction function + */ +builder_t *x509_cert_builder(certificate_type_t type) +{ + private_builder_t *this; + + if (type != CERT_X509) + { + return NULL; + } + + this = malloc_thing(private_builder_t); + + this->cert = NULL; + this->public.add = (void(*)(builder_t *this, builder_part_t part, ...))add; + this->public.build = (void*(*)(builder_t *this))build; + + return &this->public; +} + diff --git a/src/libstrongswan/plugins/x509/x509_cert.h b/src/libstrongswan/plugins/x509/x509_cert.h new file mode 100644 index 000000000..be6e41b4d --- /dev/null +++ b/src/libstrongswan/plugins/x509/x509_cert.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 x509_cert x509_cert + * @{ @ingroup x509_p + */ + +#ifndef X509_CERT_H_ +#define X509_CERT_H_ + +typedef struct x509_cert_t x509_cert_t; + +#include + +/** + * Implementation of x509_t/certificate_t using own ASN1 parser. + */ +struct x509_cert_t { + + /** + * Implements the x509_t interface + */ + x509_t interface; +}; + +/** + * Create the building facility for x509 certificates + * + * @param type certificate type, CERT_X509 only + * @return builder instance to build certificate + */ +builder_t *x509_cert_builder(certificate_type_t type); + +#endif /* X509_CERT_H_ @}*/ diff --git a/src/libstrongswan/plugins/x509/x509_crl.c b/src/libstrongswan/plugins/x509/x509_crl.c new file mode 100644 index 000000000..7e2bdf2b6 --- /dev/null +++ b/src/libstrongswan/plugins/x509/x509_crl.c @@ -0,0 +1,717 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "x509_crl.h" + +typedef struct private_x509_crl_t private_x509_crl_t; +typedef struct revoked_t revoked_t; + +#include +#include +#include +#include + +/** + * entry for a revoked certificate + */ +struct revoked_t { + /** + * serial of the revoked certificate + */ + chunk_t serial; + + /** + * date of revocation + */ + time_t date; + + /** + * reason for revocation + */ + crl_reason_t reason; +}; + +/** + * private data of x509_crl + */ +struct private_x509_crl_t { + + /** + * public functions + */ + x509_crl_t public; + + /** + * X.509 crl in DER format + */ + chunk_t certificateList; + + /** + * X.509 crl body over which signature is computed + */ + chunk_t tbsCertList; + + /** + * Version of the X.509 crl + */ + u_int version; + + /** + * ID representing the crl issuer + */ + identification_t *issuer; + + /** + * CRL number + */ + chunk_t crlNumber; + + /** + * Time when the crl was generated + */ + time_t thisUpdate; + + /** + * Time when an update crl will be available + */ + time_t nextUpdate; + + /** + * list of revoked certificates as revoked_t + */ + linked_list_t *revoked; + + /** + * Authority Key Identifier + */ + identification_t *authKeyIdentifier; + + /** + * Authority Key Serial Number + */ + chunk_t authKeySerialNumber; + + /** + * Signature algorithm + */ + int algorithm; + + /** + * Signature + */ + chunk_t signature; + + /** + * reference counter + */ + refcount_t ref; +}; + +/** + * from x509_cert + */ +extern identification_t* x509_parse_authorityKeyIdentifier( + chunk_t blob, int level0, + chunk_t *authKeySerialNumber); + +/** + * ASN.1 definition of an X.509 certificate revocation list + */ +static const asn1Object_t crlObjects[] = { + { 0, "certificateList", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */ + { 1, "tbsCertList", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */ + { 2, "version", ASN1_INTEGER, ASN1_OPT | + ASN1_BODY }, /* 2 */ + { 2, "end opt", ASN1_EOC, ASN1_END }, /* 3 */ + { 2, "signature", ASN1_EOC, ASN1_RAW }, /* 4 */ + { 2, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */ + { 2, "thisUpdate", ASN1_EOC, ASN1_RAW }, /* 6 */ + { 2, "nextUpdate", ASN1_EOC, ASN1_RAW }, /* 7 */ + { 2, "revokedCertificates", ASN1_SEQUENCE, ASN1_OPT | + ASN1_LOOP }, /* 8 */ + { 3, "certList", ASN1_SEQUENCE, ASN1_NONE }, /* 9 */ + { 4, "userCertificate", ASN1_INTEGER, ASN1_BODY }, /* 10 */ + { 4, "revocationDate", ASN1_EOC, ASN1_RAW }, /* 11 */ + { 4, "crlEntryExtensions", ASN1_SEQUENCE, ASN1_OPT | + ASN1_LOOP }, /* 12 */ + { 5, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 13 */ + { 6, "extnID", ASN1_OID, ASN1_BODY }, /* 14 */ + { 6, "critical", ASN1_BOOLEAN, ASN1_DEF | + ASN1_BODY }, /* 15 */ + { 6, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 16 */ + { 4, "end opt or loop", ASN1_EOC, ASN1_END }, /* 17 */ + { 2, "end opt or loop", ASN1_EOC, ASN1_END }, /* 18 */ + { 2, "optional extensions", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 19 */ + { 3, "crlExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 20 */ + { 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 21 */ + { 5, "extnID", ASN1_OID, ASN1_BODY }, /* 22 */ + { 5, "critical", ASN1_BOOLEAN, ASN1_DEF | + ASN1_BODY }, /* 23 */ + { 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 24 */ + { 3, "end loop", ASN1_EOC, ASN1_END }, /* 25 */ + { 2, "end opt", ASN1_EOC, ASN1_END }, /* 26 */ + { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 27 */ + { 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY } /* 28 */ + }; + +#define CRL_OBJ_TBS_CERT_LIST 1 +#define CRL_OBJ_VERSION 2 +#define CRL_OBJ_SIG_ALG 4 +#define CRL_OBJ_ISSUER 5 +#define CRL_OBJ_THIS_UPDATE 6 +#define CRL_OBJ_NEXT_UPDATE 7 +#define CRL_OBJ_USER_CERTIFICATE 10 +#define CRL_OBJ_REVOCATION_DATE 11 +#define CRL_OBJ_CRL_ENTRY_EXTN_ID 14 +#define CRL_OBJ_CRL_ENTRY_CRITICAL 15 +#define CRL_OBJ_CRL_ENTRY_EXTN_VALUE 16 +#define CRL_OBJ_EXTN_ID 22 +#define CRL_OBJ_CRITICAL 23 +#define CRL_OBJ_EXTN_VALUE 24 +#define CRL_OBJ_ALGORITHM 27 +#define CRL_OBJ_SIGNATURE 28 +#define CRL_OBJ_ROOF 29 + +/** + * Parses an X.509 Certificate Revocation List (CRL) + */ +static bool parse(private_x509_crl_t *this) +{ + asn1_ctx_t ctx; + bool critical; + chunk_t extnID; + chunk_t userCertificate = chunk_empty; + revoked_t *revoked = NULL; + chunk_t object; + u_int level; + int objectID = 0; + + asn1_init(&ctx, this->certificateList, 0, FALSE, FALSE); + while (objectID < CRL_OBJ_ROOF) + { + if (!extract_object(crlObjects, &objectID, &object, &level, &ctx)) + { + return FALSE; + } + + /* those objects which will parsed further need the next higher level */ + level++; + + switch (objectID) + { + case CRL_OBJ_TBS_CERT_LIST: + this->tbsCertList = object; + break; + case CRL_OBJ_VERSION: + this->version = (object.len) ? (1+(u_int)*object.ptr) : 1; + DBG2(" v%d", this->version); + break; + case CRL_OBJ_SIG_ALG: + this->algorithm = parse_algorithmIdentifier(object, level, NULL); + break; + case CRL_OBJ_ISSUER: + this->issuer = identification_create_from_encoding(ID_DER_ASN1_DN, object); + DBG2(" '%D'", this->issuer); + break; + case CRL_OBJ_THIS_UPDATE: + this->thisUpdate = parse_time(object, level); + break; + case CRL_OBJ_NEXT_UPDATE: + this->nextUpdate = parse_time(object, level); + break; + case CRL_OBJ_USER_CERTIFICATE: + userCertificate = object; + break; + case CRL_OBJ_REVOCATION_DATE: + revoked = malloc_thing(revoked_t); + revoked->serial = userCertificate; + revoked->date = parse_time(object, level); + revoked->reason = CRL_UNSPECIFIED; + this->revoked->insert_last(this->revoked, (void *)revoked); + break; + case CRL_OBJ_CRL_ENTRY_EXTN_ID: + case CRL_OBJ_EXTN_ID: + extnID = object; + break; + case CRL_OBJ_CRL_ENTRY_CRITICAL: + case CRL_OBJ_CRITICAL: + critical = object.len && *object.ptr; + DBG2(" %s", critical ? "TRUE" : "FALSE"); + break; + case CRL_OBJ_CRL_ENTRY_EXTN_VALUE: + case CRL_OBJ_EXTN_VALUE: + { + int extn_oid = known_oid(extnID); + + if (revoked && extn_oid == OID_CRL_REASON_CODE) + { + if (*object.ptr == ASN1_ENUMERATED && + asn1_length(&object) == 1) + { + revoked->reason = *object.ptr; + } + DBG2(" '%N'", crl_reason_names, revoked->reason); + } + else if (extn_oid == OID_AUTHORITY_KEY_ID) + { + + this->authKeyIdentifier = x509_parse_authorityKeyIdentifier(object, + level, &this->authKeySerialNumber); + } + else if (extn_oid == OID_CRL_NUMBER) + { + if (!parse_asn1_simple_object(&object, ASN1_INTEGER, + level, "crlNumber")) + { + return FALSE; + } + this->crlNumber = object; + } + } + break; + case CRL_OBJ_ALGORITHM: + { + int algo = parse_algorithmIdentifier(object, level, NULL); + if (this->algorithm != algo) + { + DBG1(" signature algorithms do not agree"); + return FALSE; + } + break; + } + case CRL_OBJ_SIGNATURE: + this->signature = object; + break; + default: + break; + } + objectID++; + } + return TRUE; +} + +/** + * enumerator filter callback for create_enumerator + */ +static bool filter(void *data, revoked_t *revoked, chunk_t *serial, void *p2, + time_t *date, void *p3, crl_reason_t *reason) +{ + if (serial) + { + *serial = revoked->serial; + } + if (date) + { + *date = revoked->date; + } + if (reason) + { + *reason = revoked->reason; + } + return TRUE; +} + +/** + * Implementation of crl_t.is_newer. + */ +static bool is_newer(private_x509_crl_t *this, crl_t *that) +{ + chunk_t that_crlNumber = that->get_serial(that); + bool new; + + /* compare crlNumbers if available - otherwise use thisUpdate */ + if (this->crlNumber.ptr != NULL && that_crlNumber.ptr != NULL) + { + new = chunk_compare(this->crlNumber, that_crlNumber) > 0; + DBG1(" crl #%#B is %s - existing crl #%#B %s", + &this->crlNumber, new ? "newer":"not newer", + &that_crlNumber, new ? "replaced":"retained"); + } + else + { + certificate_t *this_cert = &this->public.crl.certificate; + certificate_t *that_cert = &that->certificate; + + time_t this_update, that_update, now = time(NULL); + + this_cert->get_validity(this_cert, &now, &this_update, NULL); + that_cert->get_validity(that_cert, &now, &that_update, NULL); + new = this_update > that_update; + DBG1(" crl from %#T is %s - existing crl from %#T %s", + &this_update, FALSE, new ? "newer":"not newer", + &that_update, FALSE, new ? "replaced":"retained"); + } + return new; +} + +/** + * Implementation of crl_t.get_serial. + */ +static chunk_t get_serial(private_x509_crl_t *this) +{ + return this->crlNumber; +} + +/** + * Implementation of crl_t.get_authKeyIdentifier. + */ +static identification_t* get_authKeyIdentifier(private_x509_crl_t *this) +{ + return this->authKeyIdentifier; +} +/** + * Implementation of crl_t.create_enumerator. + */ +static enumerator_t* create_enumerator(private_x509_crl_t *this) +{ + return enumerator_create_filter( + this->revoked->create_enumerator(this->revoked), + (void*)filter, NULL, NULL); +} + +/** + * Implementation of certificate_t.get_type + */ +static certificate_type_t get_type(private_x509_crl_t *this) +{ + return CERT_X509_CRL; +} + +/** + * Implementation of certificate_t.get_subject + */ +static identification_t* get_subject(private_x509_crl_t *this) +{ + return this->issuer; +} + +/** + * Implementation of certificate_t.get_issuer + */ +static identification_t* get_issuer(private_x509_crl_t *this) +{ + return this->issuer; +} + +/** + * Implementation of certificate_t.has_subject. + */ +static id_match_t has_subject(private_x509_crl_t *this, identification_t *subject) +{ + return ID_MATCH_NONE; +} + +/** + * Implementation of certificate_t.has_issuer. + */ +static id_match_t has_issuer(private_x509_crl_t *this, identification_t *issuer) +{ + id_match_t match; + + if (issuer->get_type(issuer) == ID_PUBKEY_SHA1) + { + if (this->authKeyIdentifier) + { + match = issuer->matches(issuer, this->authKeyIdentifier); + } + else + { + match = ID_MATCH_NONE; + } + } + else + { + match = this->issuer->matches(this->issuer, issuer); + } + return match; +} + +/** + * Implementation of certificate_t.issued_by + */ +static bool issued_by(private_x509_crl_t *this, certificate_t *issuer, + bool sigcheck) +{ + public_key_t *key; + signature_scheme_t scheme; + bool valid; + x509_t *x509 = (x509_t*)issuer; + + /* check if issuer is an X.509 CA certificate */ + if (issuer->get_type(issuer) != CERT_X509) + { + return FALSE; + } + if (!(x509->get_flags(x509) & X509_CA)) + { + return FALSE; + } + + /* get the public key of the issuer */ + key = issuer->get_public_key(issuer); + + /* compare keyIdentifiers if available, otherwise use DNs */ + if (this->authKeyIdentifier && key) + { + identification_t *subjectKeyIdentifier = key->get_id(key, ID_PUBKEY_SHA1); + + if (!subjectKeyIdentifier->equals(subjectKeyIdentifier, + this->authKeyIdentifier)) + { + return FALSE; + } + } + else + { + if (!this->issuer->equals(this->issuer, issuer->get_subject(issuer))) + { + return FALSE; + } + } + + if (!sigcheck) + { + return TRUE; + } + /* TODO: generic OID to scheme mapper? */ + switch (this->algorithm) + { + case OID_MD5_WITH_RSA: + scheme = SIGN_RSA_EMSA_PKCS1_MD5; + break; + case OID_SHA1_WITH_RSA: + scheme = SIGN_RSA_EMSA_PKCS1_SHA1; + break; + case OID_SHA256_WITH_RSA: + scheme = SIGN_RSA_EMSA_PKCS1_SHA256; + break; + case OID_SHA384_WITH_RSA: + scheme = SIGN_RSA_EMSA_PKCS1_SHA384; + break; + case OID_SHA512_WITH_RSA: + scheme = SIGN_RSA_EMSA_PKCS1_SHA512; + break; + default: + return FALSE; + } + if (key == NULL) + { + return FALSE; + } + valid = key->verify(key, scheme, this->tbsCertList, this->signature); + key->destroy(key); + return valid; +} + +/** + * Implementation of certificate_t.get_public_key + */ +static public_key_t* get_public_key(private_x509_crl_t *this) +{ + return NULL; +} + +/** + * Implementation of certificate_t.asdf + */ +static private_x509_crl_t* get_ref(private_x509_crl_t *this) +{ + ref_get(&this->ref); + return this; +} + +/** + * Implementation of certificate_t.get_validity. + */ +static bool get_validity(private_x509_crl_t *this, time_t *when, + time_t *not_before, time_t *not_after) +{ + time_t t; + + if (when) + { + t = *when; + } + else + { + t = time(NULL); + } + if (not_after) + { + *not_after = this->nextUpdate; + } + if (not_before) + { + *not_before = this->thisUpdate; + } + return (t <= this->nextUpdate); +} + +/** + * Implementation of certificate_t.get_encoding. + */ +static chunk_t get_encoding(private_x509_crl_t *this) +{ + return chunk_clone(this->certificateList); +} + +/** + * Implementation of certificate_t.equals. + */ +static bool equals(private_x509_crl_t *this, certificate_t *other) +{ + if ((certificate_t*)this == other) + { + return TRUE; + } + if (other->equals == (void*)equals) + { /* same implementation */ + return chunk_equals(this->signature, + ((private_x509_crl_t*)other)->signature); + } + /* TODO: compare against other implementations */ + return FALSE; +} + +/** + * Implementation of certificate_t.destroy + */ +static void destroy(private_x509_crl_t *this) +{ + if (ref_put(&this->ref)) + { + this->revoked->destroy_function(this->revoked, free); + DESTROY_IF(this->issuer); + DESTROY_IF(this->authKeyIdentifier); + free(this->certificateList.ptr); + free(this); + } +} + +/** + * load a X509 CRL from a chunk of date (ASN1 DER) + */ +static x509_crl_t *load(chunk_t chunk) +{ + private_x509_crl_t *this = malloc_thing(private_x509_crl_t); + + this->public.crl.is_newer = (bool (*)(crl_t*,crl_t*))is_newer; + this->public.crl.get_serial = (chunk_t (*)(crl_t*))get_serial; + this->public.crl.get_authKeyIdentifier = (identification_t* (*)(crl_t*))get_authKeyIdentifier; + this->public.crl.create_enumerator = (enumerator_t* (*)(crl_t*))create_enumerator; + this->public.crl.certificate.get_type = (certificate_type_t (*)(certificate_t *this))get_type; + this->public.crl.certificate.get_subject = (identification_t* (*)(certificate_t *this))get_subject; + this->public.crl.certificate.get_issuer = (identification_t* (*)(certificate_t *this))get_issuer; + this->public.crl.certificate.has_subject = (id_match_t (*)(certificate_t*, identification_t *subject))has_subject; + this->public.crl.certificate.has_issuer = (id_match_t (*)(certificate_t*, identification_t *issuer))has_issuer; + this->public.crl.certificate.issued_by = (bool (*)(certificate_t *this, certificate_t *issuer,bool))issued_by; + this->public.crl.certificate.get_public_key = (public_key_t* (*)(certificate_t *this))get_public_key; + this->public.crl.certificate.get_validity = (bool (*)(certificate_t*, time_t *when, time_t *, time_t*))get_validity; + this->public.crl.certificate.get_encoding = (chunk_t (*)(certificate_t*))get_encoding; + this->public.crl.certificate.equals = (bool (*)(certificate_t*, certificate_t *other))equals; + this->public.crl.certificate.get_ref = (certificate_t* (*)(certificate_t *this))get_ref; + this->public.crl.certificate.destroy = (void (*)(certificate_t *this))destroy; + + this->certificateList = chunk; + this->tbsCertList = chunk_empty; + this->issuer = NULL; + this->crlNumber = chunk_empty; + this->revoked = linked_list_create(); + this->authKeyIdentifier = NULL; + this->authKeySerialNumber = chunk_empty; + this->ref = 1; + + if (!parse(this)) + { + destroy(this); + return NULL; + } + + return &this->public; +} + +typedef struct private_builder_t private_builder_t; +/** + * Builder implementation for certificate loading + */ +struct private_builder_t { + /** implements the builder interface */ + builder_t public; + /** loaded CRL */ + x509_crl_t *crl; +}; + +/** + * Implementation of builder_t.build + */ +static x509_crl_t *build(private_builder_t *this) +{ + x509_crl_t *crl = this->crl; + + free(this); + return crl; +} + +/** + * Implementation of builder_t.add + */ +static void add(private_builder_t *this, builder_part_t part, ...) +{ + va_list args; + + if (this->crl) + { + DBG1("ignoring surplus build part %N", builder_part_names, part); + return; + } + + switch (part) + { + case BUILD_BLOB_ASN1_DER: + { + va_start(args, part); + this->crl = load(va_arg(args, chunk_t)); + va_end(args); + break; + } + default: + DBG1("ignoring unsupported build part %N", builder_part_names, part); + break; + } +} + +/** + * Builder construction function + */ +builder_t *x509_crl_builder(certificate_type_t type) +{ + private_builder_t *this; + + if (type != CERT_X509_CRL) + { + return NULL; + } + + this = malloc_thing(private_builder_t); + + this->crl = NULL; + this->public.add = (void(*)(builder_t *this, builder_part_t part, ...))add; + this->public.build = (void*(*)(builder_t *this))build; + + return &this->public; +} + diff --git a/src/libstrongswan/plugins/x509/x509_crl.h b/src/libstrongswan/plugins/x509/x509_crl.h new file mode 100644 index 000000000..0d9e5cca4 --- /dev/null +++ b/src/libstrongswan/plugins/x509/x509_crl.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 x509_crl x509_crl + * @{ @ingroup x509_p + */ + +#ifndef X509_CRL_H_ +#define X509_CRL_H_ + +typedef struct x509_crl_t x509_crl_t; + +#include + +/** + * Implementation of the X509 certification revocation list. + */ +struct x509_crl_t { + + /** + * Implements the crl_t interface + */ + crl_t crl; +}; + + +/** + * Create the building facility for x509 certificate revocation lists. + * + * @param type certificate type, CERT_X509_CRL only + * @return builder instance to build certificate + */ +builder_t *x509_crl_builder(certificate_type_t type); + +#endif /* X509_CRL_H_ @}*/ diff --git a/src/libstrongswan/plugins/x509/x509_ocsp_request.c b/src/libstrongswan/plugins/x509/x509_ocsp_request.c new file mode 100644 index 000000000..7e3230412 --- /dev/null +++ b/src/libstrongswan/plugins/x509/x509_ocsp_request.c @@ -0,0 +1,603 @@ +/* + * Copyright (C) 2008 Martin Willi + * Copyright (C) 2007 Andreas Steffen + * Hochschule fuer Technik Rapperswil + * Copyright (C) 2003 Christoph Gysin, Simon Zwahlen + * + * 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 . + * + * 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. + * + * $Id$ + */ + +#include "x509_ocsp_request.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#define NONCE_LEN 16 + +typedef struct private_x509_ocsp_request_t private_x509_ocsp_request_t; + +/** + * private data of x509_ocsp_request + */ +struct private_x509_ocsp_request_t { + + /** + * public functions + */ + x509_ocsp_request_t public; + + /** + * CA the candidates belong to + */ + x509_t *ca; + + /** + * Requestor name, subject of cert used if not set + */ + identification_t *requestor; + + /** + * Requestor certificate, included in request + */ + certificate_t *cert; + + /** + * Requestor private key to sign request + */ + private_key_t *key; + + /** + * list of certificates to check, x509_t + */ + linked_list_t *candidates; + + /** + * nonce used in request + */ + chunk_t nonce; + + /** + * encoded OCSP request + */ + chunk_t encoding; + + /** + * reference count + */ + refcount_t ref; +}; + +static u_char ASN1_nonce_oid_str[] = { + 0x06, 0x09, + 0x2B, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x02 +}; + +static u_char ASN1_response_oid_str[] = { + 0x06, 0x09, + 0x2B, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x04 +}; + +static u_char ASN1_response_content_str[] = { + 0x04, 0x0D, + 0x30, 0x0B, + 0x06, 0x09, + 0x2B, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x01 +}; + +static const chunk_t ASN1_nonce_oid = chunk_from_buf(ASN1_nonce_oid_str); +static const chunk_t ASN1_response_oid = chunk_from_buf(ASN1_response_oid_str); +static const chunk_t ASN1_response_content = chunk_from_buf(ASN1_response_content_str); + +/** + * build requestorName + */ +static chunk_t build_requestorName(private_x509_ocsp_request_t *this) +{ + if (this->requestor || this->cert) + { /* use requestor name, fallback to his cert subject */ + if (!this->requestor) + { + this->requestor = this->cert->get_subject(this->cert); + this->requestor = this->requestor->clone(this->requestor); + } + return asn1_wrap(ASN1_CONTEXT_C_1, "m", + asn1_simple_object(ASN1_CONTEXT_C_4, + this->requestor->get_encoding(this->requestor))); + + } + return chunk_empty; +} + +/** + * build Request, not using singleRequestExtensions + */ +static chunk_t build_Request(private_x509_ocsp_request_t *this, + chunk_t issuerNameHash, chunk_t issuerKeyHash, + chunk_t serialNumber) +{ + return asn1_wrap(ASN1_SEQUENCE, "m", + asn1_wrap(ASN1_SEQUENCE, "cmmm", + asn1_algorithmIdentifier(OID_SHA1), + asn1_simple_object(ASN1_OCTET_STRING, issuerNameHash), + asn1_simple_object(ASN1_OCTET_STRING, issuerKeyHash), + asn1_simple_object(ASN1_INTEGER, serialNumber))); +} + +/** + * build requestList + */ +static chunk_t build_requestList(private_x509_ocsp_request_t *this) +{ + chunk_t issuerNameHash, issuerKeyHash; + identification_t *issuer; + x509_t *x509; + certificate_t *cert; + chunk_t list = chunk_empty; + public_key_t *public; + + cert = (certificate_t*)this->ca; + public = cert->get_public_key(cert); + if (public) + { + hasher_t *hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); + if (hasher) + { + identification_t *keyid = public->get_id(public, ID_PUBKEY_SHA1); + if (keyid) + { + enumerator_t *enumerator; + + issuerKeyHash = keyid->get_encoding(keyid); + + issuer = cert->get_subject(cert); + hasher->allocate_hash(hasher, issuer->get_encoding(issuer), + &issuerNameHash); + hasher->destroy(hasher); + + enumerator = this->candidates->create_enumerator(this->candidates); + while (enumerator->enumerate(enumerator, &x509)) + { + chunk_t request, serialNumber; + + serialNumber = x509->get_serial(x509); + request = build_Request(this, issuerNameHash, issuerKeyHash, + serialNumber); + list = chunk_cat("mm", list, request); + } + enumerator->destroy(enumerator); + chunk_free(&issuerNameHash); + } + } + else + { + DBG1("creating OCSP request failed, SHA1 not supported"); + } + public->destroy(public); + } + else + { + DBG1("creating OCSP request failed, CA certificate has no public key"); + } + return asn1_wrap(ASN1_SEQUENCE, "m", list); +} + +/** + * build nonce extension + */ +static chunk_t build_nonce(private_x509_ocsp_request_t *this) +{ + randomizer_t *randomizer; + + randomizer = randomizer_create(); + randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_LEN, &this->nonce); + randomizer->destroy(randomizer); + + return asn1_wrap(ASN1_SEQUENCE, "cm", ASN1_nonce_oid, + asn1_simple_object(ASN1_OCTET_STRING, this->nonce)); +} + +/** + * build acceptableResponses extension + */ +static chunk_t build_acceptableResponses(private_x509_ocsp_request_t *this) +{ + return asn1_wrap(ASN1_SEQUENCE, "cc", + ASN1_response_oid, + ASN1_response_content); +} + +/** + * build requestExtensions + */ +static chunk_t build_requestExtensions(private_x509_ocsp_request_t *this) +{ + return asn1_wrap(ASN1_CONTEXT_C_2, "m", + asn1_wrap(ASN1_SEQUENCE, "mm", + build_nonce(this), + build_acceptableResponses(this))); +} + +/** + * build tbsRequest + */ +static chunk_t build_tbsRequest(private_x509_ocsp_request_t *this) +{ + return asn1_wrap(ASN1_SEQUENCE, "mmm", + build_requestorName(this), + build_requestList(this), + build_requestExtensions(this)); +} + +/** + * Build the optionalSignature + */ +static chunk_t build_optionalSignature(private_x509_ocsp_request_t *this, + chunk_t tbsRequest) +{ + int oid; + signature_scheme_t scheme; + chunk_t certs, signature; + + switch (this->key->get_type(this->key)) + { + /* TODO: use a generic mapping function */ + case KEY_RSA: + oid = OID_SHA1_WITH_RSA; + scheme = SIGN_RSA_EMSA_PKCS1_SHA1; + break; + default: + DBG1("unable to sign OCSP request, %N signature not supported", + key_type_names, this->key->get_type(this->key)); + return chunk_empty; + } + + if (!this->key->sign(this->key, scheme, tbsRequest, &signature)) + { + DBG1("creating OCSP signature failed, skipped"); + return chunk_empty; + } + if (this->cert) + { + certs = asn1_wrap(ASN1_CONTEXT_C_0, "m", + asn1_wrap(ASN1_SEQUENCE, "m", + this->cert->get_encoding(this->cert))); + } + return asn1_wrap(ASN1_CONTEXT_C_0, "m", + asn1_wrap(ASN1_SEQUENCE, "cmm", + asn1_algorithmIdentifier(oid), + asn1_bitstring("m", signature), + certs)); +} + +/** + * Build the OCSPRequest data + * + */ +static chunk_t build_OCSPRequest(private_x509_ocsp_request_t *this) +{ + chunk_t tbsRequest, optionalSignature = chunk_empty; + + tbsRequest = build_tbsRequest(this); + if (this->key) + { + optionalSignature = build_optionalSignature(this, tbsRequest); + } + return asn1_wrap(ASN1_SEQUENCE, "mm", tbsRequest, optionalSignature); +} + + +/** + * Implementation of certificate_t.get_type + */ +static certificate_type_t get_type(private_x509_ocsp_request_t *this) +{ + return CERT_X509_OCSP_REQUEST; +} + +/** + * Implementation of certificate_t.get_subject + */ +static identification_t* get_subject(private_x509_ocsp_request_t *this) +{ + certificate_t *ca = (certificate_t*)this->ca; + + if (this->requestor) + { + return this->requestor; + } + if (this->cert) + { + return this->cert->get_subject(this->cert); + } + return ca->get_subject(ca); +} + +/** + * Implementation of certificate_t.get_issuer + */ +static identification_t* get_issuer(private_x509_ocsp_request_t *this) +{ + certificate_t *ca = (certificate_t*)this->ca; + + return ca->get_subject(ca); +} + +/** + * Implementation of certificate_t.has_subject. + */ +static id_match_t has_subject(private_x509_ocsp_request_t *this, + identification_t *subject) +{ + certificate_t *current; + enumerator_t *enumerator; + id_match_t match, best = ID_MATCH_NONE; + + enumerator = this->candidates->create_enumerator(this->candidates); + while (enumerator->enumerate(enumerator, ¤t)) + { + match = current->has_subject(current, subject); + if (match > best) + { + best = match; + } + } + enumerator->destroy(enumerator); + return best; +} + +/** + * Implementation of certificate_t.has_subject. + */ +static id_match_t has_issuer(private_x509_ocsp_request_t *this, + identification_t *issuer) +{ + certificate_t *ca = (certificate_t*)this->ca; + + return ca->has_subject(ca, issuer); +} + +/** + * Implementation of certificate_t.issued_by + */ +static bool issued_by(private_x509_ocsp_request_t *this, certificate_t *issuer, + bool sigcheck) +{ + DBG1("OCSP request validation not implemented!"); + return FALSE; +} + +/** + * Implementation of certificate_t.get_public_key + */ +static public_key_t* get_public_key(private_x509_ocsp_request_t *this) +{ + return NULL; +} + +/** + * Implementation of x509_cert_t.get_validity. + */ +static bool get_validity(private_x509_ocsp_request_t *this, time_t *when, + time_t *not_before, time_t *not_after) +{ + certificate_t *cert; + + if (this->cert) + { + cert = this->cert; + } + else + { + cert = (certificate_t*)this->ca; + } + return cert->get_validity(cert, when, not_before, not_after); +} + +/** + * Implementation of certificate_t.get_encoding. + */ +static chunk_t get_encoding(private_x509_ocsp_request_t *this) +{ + return chunk_clone(this->encoding); +} + +/** + * Implementation of certificate_t.equals. + */ +static bool equals(private_x509_ocsp_request_t *this, certificate_t *other) +{ + if (this == (private_x509_ocsp_request_t*)other) + { + return TRUE; + } + if (other->get_type(other) != CERT_X509_OCSP_REQUEST) + { + return FALSE; + } + /* check if we have the same X509 implementation */ + if (other->equals == (void*)equals) + { + return chunk_equals(this->encoding, + ((private_x509_ocsp_request_t*)other)->encoding); + } + /* TODO: compare against other implementation */ + return FALSE; +} + +/** + * Implementation of certificate_t.asdf + */ +static private_x509_ocsp_request_t* get_ref(private_x509_ocsp_request_t *this) +{ + ref_get(&this->ref); + return this; +} + +/** + * Implementation of x509_ocsp_request_t.destroy + */ +static void destroy(private_x509_ocsp_request_t *this) +{ + if (ref_put(&this->ref)) + { + DESTROY_IF((certificate_t*)this->ca); + DESTROY_IF(this->requestor); + DESTROY_IF(this->cert); + DESTROY_IF(this->key); + this->candidates->destroy_offset(this->candidates, offsetof(certificate_t, destroy)); + chunk_free(&this->nonce); + chunk_free(&this->encoding); + free(this); + } +} + +/** + * create an empty but initialized OCSP request + */ +static private_x509_ocsp_request_t *create_empty() +{ + private_x509_ocsp_request_t *this = malloc_thing(private_x509_ocsp_request_t); + + this->public.interface.interface.get_type = (certificate_type_t (*)(certificate_t *this))get_type; + this->public.interface.interface.get_subject = (identification_t* (*)(certificate_t *this))get_subject; + this->public.interface.interface.get_issuer = (identification_t* (*)(certificate_t *this))get_issuer; + this->public.interface.interface.has_subject = (id_match_t(*)(certificate_t*, identification_t *subject))has_subject; + this->public.interface.interface.has_issuer = (id_match_t(*)(certificate_t*, identification_t *issuer))has_issuer; + this->public.interface.interface.issued_by = (bool (*)(certificate_t *this, certificate_t *issuer,bool))issued_by; + this->public.interface.interface.get_public_key = (public_key_t* (*)(certificate_t *this))get_public_key; + this->public.interface.interface.get_validity = (bool(*)(certificate_t*, time_t *when, time_t *, time_t*))get_validity; + this->public.interface.interface.get_encoding = (chunk_t(*)(certificate_t*))get_encoding; + this->public.interface.interface.equals = (bool(*)(certificate_t*, certificate_t *other))equals; + this->public.interface.interface.get_ref = (certificate_t* (*)(certificate_t *this))get_ref; + this->public.interface.interface.destroy = (void (*)(certificate_t *this))destroy; + + this->ca = NULL; + this->requestor = NULL; + this->cert = NULL; + this->key = NULL; + this->nonce = chunk_empty; + this->encoding = chunk_empty; + this->candidates = linked_list_create(); + this->ref = 1; + + return this; +} + +typedef struct private_builder_t private_builder_t; +/** + * Builder implementation for certificate loading + */ +struct private_builder_t { + /** implements the builder interface */ + builder_t public; + /** OCSP request to build */ + private_x509_ocsp_request_t *req; +}; + +/** + * Implementation of builder_t.build + */ +static x509_ocsp_request_t *build(private_builder_t *this) +{ + private_x509_ocsp_request_t *req; + + req = this->req; + free(this); + if (req->ca) + { + req->encoding = build_OCSPRequest(req); + return &req->public; + } + destroy(req); + return NULL; +} + +/** + * Implementation of builder_t.add + */ +static void add(private_builder_t *this, builder_part_t part, ...) +{ + va_list args; + certificate_t *cert; + + va_start(args, part); + switch (part) + { + case BUILD_CA_CERT: + cert = va_arg(args, certificate_t*); + if (cert->get_type(cert) == CERT_X509) + { + this->req->ca = (x509_t*)cert; + } + else + { + cert->destroy(cert); + } + break; + case BUILD_CERT: + cert = va_arg(args, certificate_t*); + if (cert->get_type(cert) == CERT_X509) + { + this->req->candidates->insert_last(this->req->candidates, cert); + } + else + { + cert->destroy(cert); + } + break; + case BUILD_SIGNING_CERT: + this->req->cert = va_arg(args, certificate_t*); + break; + case BUILD_SIGNING_KEY: + this->req->key = va_arg(args, private_key_t*); + break; + case BUILD_SUBJECT: + this->req->requestor = va_arg(args, identification_t*); + break; + default: + DBG1("ignoring unsupported build part %N", builder_part_names, part); + break; + } + va_end(args); +} + +/** + * Builder construction function + */ +builder_t *x509_ocsp_request_builder(certificate_type_t type) +{ + private_builder_t *this; + + if (type != CERT_X509_OCSP_REQUEST) + { + return NULL; + } + + this = malloc_thing(private_builder_t); + + this->req = create_empty(); + this->public.add = (void(*)(builder_t *this, builder_part_t part, ...))add; + this->public.build = (void*(*)(builder_t *this))build; + + return &this->public; +} + diff --git a/src/libstrongswan/plugins/x509/x509_ocsp_request.h b/src/libstrongswan/plugins/x509/x509_ocsp_request.h new file mode 100644 index 000000000..0a4016f65 --- /dev/null +++ b/src/libstrongswan/plugins/x509/x509_ocsp_request.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 x509_ocsp_request x509_ocsp_request + * @{ @ingroup x509_p + */ + +#ifndef X509_OCSP_REQUEST_H_ +#define X509_OCSP_REQUEST_H_ + +#include + +typedef struct x509_ocsp_request_t x509_ocsp_request_t; + +/** + * Implementation of ocsp_request_t using own ASN1 parser. + */ +struct x509_ocsp_request_t { + + /** + * Implements the ocsp_request_t interface + */ + ocsp_request_t interface; +}; + +/** + * Create the building facility for OCSP requests. + * + * The resulting builder accepts: + * BUILD_CA_CERT: CA of the checked certificates, exactly one + * BUILD_CERT: certificates to check with the request, at least one + * BUILD_SUBJECT: subject requesting check, optional + * BUILD_SIGNING_CERT: certificate to create requestor signature, optional + * BUILD_SIGNING_KEY: private key to create requestor signature, optional + * + * @param type certificate type, CERT_X509_OCSP_REQUEST only + * @return builder instance to build OCSP requests + */ +builder_t *x509_ocsp_request_builder(certificate_type_t type); + +#endif /* X509_OCSP_REQUEST_H_ @}*/ diff --git a/src/libstrongswan/plugins/x509/x509_ocsp_response.c b/src/libstrongswan/plugins/x509/x509_ocsp_response.c new file mode 100644 index 000000000..4ea2871d2 --- /dev/null +++ b/src/libstrongswan/plugins/x509/x509_ocsp_response.c @@ -0,0 +1,928 @@ +/** + * Copyright (C) 2008 Martin Willi + * Copyright (C) 2007 Andreas Steffen + * Hochschule für Technik Rapperswil + * Copyright (C) 2003 Christoph Gysin, Simon Zwahlen + * + * 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 . + * + * 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. + * + * $Id$ + */ + +#include "x509_ocsp_response.h" + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +typedef struct private_x509_ocsp_response_t private_x509_ocsp_response_t; + +/** + * Private data of a ocsp_t object. + */ +struct private_x509_ocsp_response_t { + /** + * Public interface for this ocsp object. + */ + x509_ocsp_response_t public; + + /** + * complete encoded OCSP response + */ + chunk_t data; + + /** + * data for signature verficiation + */ + chunk_t tbsResponseData; + + /** + * signature algorithm (OID) + */ + int signatureAlgorithm; + + /** + * signature value + */ + chunk_t signature; + + /** + * name or keyid of the responder + */ + identification_t *responderId; + + /** + * time of response production + */ + time_t producedAt; + + /** + * list of included certificates + */ + linked_list_t *certs; + + /** + * Linked list of OCSP responses, single_response_t + */ + linked_list_t *responses; + + /** + * Nonce required for ocsp request and response + */ + chunk_t nonce; + + /** + * reference counter + */ + refcount_t ref; +}; + +/** + * single response contained in OCSP response + */ +typedef struct { + /** hash algorithm OID to for the two hashes */ + int hashAlgorithm; + /** hash of issuer DN */ + chunk_t issuerNameHash; + /** issuerKeyID */ + chunk_t issuerKeyHash; + /** serial number of certificate */ + chunk_t serialNumber; + /** OCSP certificate status */ + cert_validation_t status; + /** time of revocation, if revoked */ + time_t revocationTime; + /** revocation reason, if revoked */ + crl_reason_t revocationReason; + /** creation of associated CRL */ + time_t thisUpdate; + /** creation of next CRL */ + time_t nextUpdate; +} single_response_t; + +/* our OCSP response version implementation */ +#define OCSP_BASIC_RESPONSE_VERSION 1 + +/* some OCSP specific prefabricated ASN.1 constants */ +static u_char ASN1_nonce_oid_str[] = { + 0x06, 0x09, + 0x2B, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x02 +}; + +static u_char ASN1_response_oid_str[] = { + 0x06, 0x09, + 0x2B, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x04 +}; + +static u_char ASN1_response_content_str[] = { + 0x04, 0x0D, + 0x30, 0x0B, + 0x06, 0x09, + 0x2B, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x01 +}; + +static const chunk_t ASN1_nonce_oid = chunk_from_buf(ASN1_nonce_oid_str); +static const chunk_t ASN1_response_oid = chunk_from_buf(ASN1_response_oid_str); +static const chunk_t ASN1_response_content = chunk_from_buf(ASN1_response_content_str); + +/* asn.1 definitions for parsing */ + +static const asn1Object_t ocspResponseObjects[] = { + { 0, "OCSPResponse", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ + { 1, "responseStatus", ASN1_ENUMERATED, ASN1_BODY }, /* 1 */ + { 1, "responseBytesContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 2 */ + { 2, "responseBytes", ASN1_SEQUENCE, ASN1_NONE }, /* 3 */ + { 3, "responseType", ASN1_OID, ASN1_BODY }, /* 4 */ + { 3, "response", ASN1_OCTET_STRING, ASN1_BODY }, /* 5 */ + { 1, "end opt", ASN1_EOC, ASN1_END } /* 6 */ +}; + +#define OCSP_RESPONSE_STATUS 1 +#define OCSP_RESPONSE_TYPE 4 +#define OCSP_RESPONSE 5 +#define OCSP_RESPONSE_ROOF 7 + +static const asn1Object_t basicResponseObjects[] = { + { 0, "BasicOCSPResponse", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ + { 1, "tbsResponseData", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */ + { 2, "versionContext", ASN1_CONTEXT_C_0, ASN1_NONE | + ASN1_DEF }, /* 2 */ + { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 3 */ + { 2, "responderIdContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 4 */ + { 3, "responderIdByName", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */ + { 2, "end choice", ASN1_EOC, ASN1_END }, /* 6 */ + { 2, "responderIdContext", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 7 */ + { 3, "responderIdByKey", ASN1_OCTET_STRING, ASN1_BODY }, /* 8 */ + { 2, "end choice", ASN1_EOC, ASN1_END }, /* 9 */ + { 2, "producedAt", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 10 */ + { 2, "responses", ASN1_SEQUENCE, ASN1_OBJ }, /* 11 */ + { 2, "responseExtensionsContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 12 */ + { 3, "responseExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 13 */ + { 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 14 */ + { 5, "extnID", ASN1_OID, ASN1_BODY }, /* 15 */ + { 5, "critical", ASN1_BOOLEAN, ASN1_BODY | + ASN1_DEF }, /* 16 */ + { 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 17 */ + { 4, "end loop", ASN1_EOC, ASN1_END }, /* 18 */ + { 2, "end opt", ASN1_EOC, ASN1_END }, /* 19 */ + { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 20 */ + { 1, "signature", ASN1_BIT_STRING, ASN1_BODY }, /* 21 */ + { 1, "certsContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 22 */ + { 2, "certs", ASN1_SEQUENCE, ASN1_LOOP }, /* 23 */ + { 3, "certificate", ASN1_SEQUENCE, ASN1_RAW }, /* 24 */ + { 2, "end loop", ASN1_EOC, ASN1_END }, /* 25 */ + { 1, "end opt", ASN1_EOC, ASN1_END } /* 26 */ +}; + +#define BASIC_RESPONSE_TBS_DATA 1 +#define BASIC_RESPONSE_VERSION 3 +#define BASIC_RESPONSE_ID_BY_NAME 5 +#define BASIC_RESPONSE_ID_BY_KEY 8 +#define BASIC_RESPONSE_PRODUCED_AT 10 +#define BASIC_RESPONSE_RESPONSES 11 +#define BASIC_RESPONSE_EXT_ID 15 +#define BASIC_RESPONSE_CRITICAL 16 +#define BASIC_RESPONSE_EXT_VALUE 17 +#define BASIC_RESPONSE_ALGORITHM 20 +#define BASIC_RESPONSE_SIGNATURE 21 +#define BASIC_RESPONSE_CERTIFICATE 24 +#define BASIC_RESPONSE_ROOF 27 + +static const asn1Object_t responsesObjects[] = { + { 0, "responses", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ + { 1, "singleResponse", ASN1_EOC, ASN1_RAW }, /* 1 */ + { 0, "end loop", ASN1_EOC, ASN1_END } /* 2 */ +}; + +#define RESPONSES_SINGLE_RESPONSE 1 +#define RESPONSES_ROOF 3 + +static const asn1Object_t singleResponseObjects[] = { + { 0, "singleResponse", ASN1_SEQUENCE, ASN1_BODY }, /* 0 */ + { 1, "certID", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */ + { 2, "algorithm", ASN1_EOC, ASN1_RAW }, /* 2 */ + { 2, "issuerNameHash", ASN1_OCTET_STRING, ASN1_BODY }, /* 3 */ + { 2, "issuerKeyHash", ASN1_OCTET_STRING, ASN1_BODY }, /* 4 */ + { 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 5 */ + { 1, "certStatusGood", ASN1_CONTEXT_S_0, ASN1_OPT }, /* 6 */ + { 1, "end opt", ASN1_EOC, ASN1_END }, /* 7 */ + { 1, "certStatusRevoked", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 8 */ + { 2, "revocationTime", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 9 */ + { 2, "revocationReason", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 10 */ + { 3, "crlReason", ASN1_ENUMERATED, ASN1_BODY }, /* 11 */ + { 2, "end opt", ASN1_EOC, ASN1_END }, /* 12 */ + { 1, "end opt", ASN1_EOC, ASN1_END }, /* 13 */ + { 1, "certStatusUnknown", ASN1_CONTEXT_S_2, ASN1_OPT }, /* 14 */ + { 1, "end opt", ASN1_EOC, ASN1_END }, /* 15 */ + { 1, "thisUpdate", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 16 */ + { 1, "nextUpdateContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 17 */ + { 2, "nextUpdate", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 18 */ + { 1, "end opt", ASN1_EOC, ASN1_END }, /* 19 */ + { 1, "singleExtensionsContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 20 */ + { 2, "singleExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 21 */ + { 3, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 22 */ + { 4, "extnID", ASN1_OID, ASN1_BODY }, /* 23 */ + { 4, "critical", ASN1_BOOLEAN, ASN1_BODY | + ASN1_DEF }, /* 24 */ + { 4, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 25 */ + { 2, "end loop", ASN1_EOC, ASN1_END }, /* 26 */ + { 1, "end opt", ASN1_EOC, ASN1_END } /* 27 */ +}; + +#define SINGLE_RESPONSE_ALGORITHM 2 +#define SINGLE_RESPONSE_ISSUER_NAME_HASH 3 +#define SINGLE_RESPONSE_ISSUER_KEY_HASH 4 +#define SINGLE_RESPONSE_SERIAL_NUMBER 5 +#define SINGLE_RESPONSE_CERT_STATUS_GOOD 6 +#define SINGLE_RESPONSE_CERT_STATUS_REVOKED 8 +#define SINGLE_RESPONSE_CERT_STATUS_REVOCATION_TIME 9 +#define SINGLE_RESPONSE_CERT_STATUS_CRL_REASON 11 +#define SINGLE_RESPONSE_CERT_STATUS_UNKNOWN 14 +#define SINGLE_RESPONSE_THIS_UPDATE 16 +#define SINGLE_RESPONSE_NEXT_UPDATE 18 +#define SINGLE_RESPONSE_EXT_ID 23 +#define SINGLE_RESPONSE_CRITICAL 24 +#define SINGLE_RESPONSE_EXT_VALUE 25 +#define SINGLE_RESPONSE_ROOF 28 + +/** + * Implementaiton of ocsp_response_t.get_status + */ +static cert_validation_t get_status(private_x509_ocsp_response_t *this, + x509_t *subject, x509_t *issuer, + time_t *revocation_time, + crl_reason_t *revocation_reason, + time_t *this_update, time_t *next_update) +{ + enumerator_t *enumerator; + single_response_t *response; + cert_validation_t status = VALIDATION_FAILED; + certificate_t *issuercert = &issuer->interface; + + enumerator = this->responses->create_enumerator(this->responses); + while (enumerator->enumerate(enumerator, &response)) + { + hasher_t *hasher; + identification_t *id; + chunk_t hash; + + /* check serial first, is cheaper */ + if (!chunk_equals(subject->get_serial(subject), response->serialNumber)) + { + continue; + } + /* check issuerKeyHash if available */ + if (response->issuerKeyHash.ptr) + { + public_key_t *public; + + public = issuercert->get_public_key(issuercert); + if (!public) + { + continue; + } + switch (response->hashAlgorithm) + { /* TODO: generic mapper function */ + case OID_SHA1: + id = public->get_id(public, ID_PUBKEY_SHA1); + break; + default: + public->destroy(public); + continue; + } + if (!chunk_equals(response->issuerKeyHash, id->get_encoding(id))) + { + public->destroy(public); + continue; + } + public->destroy(public); + } + /* check issuerNameHash, if available */ + else if (response->issuerNameHash.ptr) + { + hasher = lib->crypto->create_hasher(lib->crypto, + hasher_algorithm_from_oid(response->hashAlgorithm)); + if (!hasher) + { + continue; + } + id = issuercert->get_subject(issuercert); + hasher->allocate_hash(hasher, id->get_encoding(id), &hash); + hasher->destroy(hasher); + if (!chunk_equals(hash, response->issuerNameHash)) + { + continue; + } + } + else + { + continue; + } + /* got a match */ + status = response->status; + *revocation_time = response->revocationTime; + *revocation_reason = response->revocationReason; + *this_update = response->thisUpdate; + *next_update = response->nextUpdate; + + break; + } + enumerator->destroy(enumerator); + return status; +} + +/** + * Implementation of ocsp_response_t.create_cert_enumerator. + */ +static enumerator_t* create_cert_enumerator(private_x509_ocsp_response_t *this) +{ + return this->certs->create_enumerator(this->certs); +} + +/** + * parse a single OCSP response + */ +static bool parse_singleResponse(private_x509_ocsp_response_t *this, + chunk_t blob, int level0) +{ + u_int level; + asn1_ctx_t ctx; + chunk_t object; + int objectID = 0; + single_response_t *response; + + response = malloc_thing(single_response_t); + response->hashAlgorithm = OID_UNKNOWN; + response->issuerNameHash = chunk_empty; + response->issuerKeyHash = chunk_empty; + response->serialNumber = chunk_empty; + response->status = VALIDATION_FAILED; + response->revocationTime = 0; + response->revocationReason = CRL_UNSPECIFIED; + response->thisUpdate = 0; + response->nextUpdate = 0; + + asn1_init(&ctx, blob, level0, FALSE, FALSE); + while (objectID < SINGLE_RESPONSE_ROOF) + { + if (!extract_object(singleResponseObjects, &objectID, &object, &level, &ctx)) + { + free(response); + return FALSE; + } + switch (objectID) + { + case SINGLE_RESPONSE_ALGORITHM: + response->hashAlgorithm = parse_algorithmIdentifier(object, level+1, NULL); + break; + case SINGLE_RESPONSE_ISSUER_NAME_HASH: + response->issuerNameHash = object; + break; + case SINGLE_RESPONSE_ISSUER_KEY_HASH: + response->issuerKeyHash = object; + break; + case SINGLE_RESPONSE_SERIAL_NUMBER: + response->serialNumber = object; + break; + case SINGLE_RESPONSE_CERT_STATUS_GOOD: + response->status = VALIDATION_GOOD; + break; + case SINGLE_RESPONSE_CERT_STATUS_REVOKED: + response->status = VALIDATION_REVOKED; + break; + case SINGLE_RESPONSE_CERT_STATUS_REVOCATION_TIME: + response->revocationTime = asn1totime(&object, ASN1_GENERALIZEDTIME); + break; + case SINGLE_RESPONSE_CERT_STATUS_CRL_REASON: + if (object.len == 1) + { + response->revocationReason = *object.ptr; + } + break; + case SINGLE_RESPONSE_CERT_STATUS_UNKNOWN: + response->status = VALIDATION_FAILED; + break; + case SINGLE_RESPONSE_THIS_UPDATE: + response->thisUpdate = asn1totime(&object, ASN1_GENERALIZEDTIME); + break; + case SINGLE_RESPONSE_NEXT_UPDATE: + response->nextUpdate = asn1totime(&object, ASN1_GENERALIZEDTIME); + break; + } + objectID++; + } + this->responses->insert_last(this->responses, response); + return TRUE; +} + +/** + * parse all contained responses + */ +static bool parse_responses(private_x509_ocsp_response_t *this, + chunk_t blob, int level0) +{ + u_int level; + asn1_ctx_t ctx; + chunk_t object; + int objectID = 0; + + asn1_init(&ctx, blob, level0, FALSE, FALSE); + while (objectID < RESPONSES_ROOF) + { + if (!extract_object(responsesObjects, &objectID, &object, &level, &ctx)) + { + return FALSE; + } + switch (objectID) + { + case RESPONSES_SINGLE_RESPONSE: + if (!parse_singleResponse(this, object, level+1)) + { + return FALSE; + } + break; + default: + break; + } + objectID++; + } + return TRUE; +} + +/** + * parse a basicOCSPResponse + */ +static bool parse_basicOCSPResponse(private_x509_ocsp_response_t *this, + chunk_t blob, int level0) +{ + u_int level, version; + asn1_ctx_t ctx; + bool critical; + chunk_t object, responses = chunk_empty; + int objectID = 0; + int extn_oid = OID_UNKNOWN; + certificate_t *cert; + + asn1_init(&ctx, blob, level0, FALSE, FALSE); + while (objectID < BASIC_RESPONSE_ROOF) + { + if (!extract_object(basicResponseObjects, &objectID, &object, &level, &ctx)) + { + return FALSE; + } + switch (objectID) + { + case BASIC_RESPONSE_TBS_DATA: + this->tbsResponseData = object; + break; + case BASIC_RESPONSE_VERSION: + version = (object.len)? (1 + (u_int)*object.ptr) : 1; + if (version != OCSP_BASIC_RESPONSE_VERSION) + { + DBG1("OCSP ResponseData version %d not supported", version); + return FALSE; + } + break; + case BASIC_RESPONSE_ID_BY_NAME: + this->responderId = identification_create_from_encoding( + ID_DER_ASN1_DN, object); + DBG3(" %D", this->responderId); + break; + case BASIC_RESPONSE_ID_BY_KEY: + this->responderId = identification_create_from_encoding( + ID_PUBKEY_INFO_SHA1, object); + DBG3(" %D", this->responderId); + break; + case BASIC_RESPONSE_PRODUCED_AT: + this->producedAt = asn1totime(&object, ASN1_GENERALIZEDTIME); + break; + case BASIC_RESPONSE_RESPONSES: + responses = object; + break; + case BASIC_RESPONSE_EXT_ID: + extn_oid = known_oid(object); + break; + case BASIC_RESPONSE_CRITICAL: + critical = object.len && *object.ptr; + DBG3(" %s", critical ? "TRUE" : "FALSE"); + break; + case BASIC_RESPONSE_EXT_VALUE: + if (extn_oid == OID_NONCE) + { + this->nonce = object; + } + break; + case BASIC_RESPONSE_ALGORITHM: + this->signatureAlgorithm = parse_algorithmIdentifier( + object, level+1, NULL); + break; + case BASIC_RESPONSE_SIGNATURE: + this->signature = object; + break; + case BASIC_RESPONSE_CERTIFICATE: + { + cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,CERT_X509, + BUILD_BLOB_ASN1_DER, chunk_clone(object), + BUILD_END); + if (cert) + { + this->certs->insert_last(this->certs, cert); + } + break; + } + } + objectID++; + } + if (!this->responderId) + { + this->responderId = identification_create_from_encoding(ID_ANY, chunk_empty); + } + return parse_responses(this, responses, level + 1); +} + +/** + * Parse OCSPResponse object + */ +static bool parse_OCSPResponse(private_x509_ocsp_response_t *this) +{ + asn1_ctx_t ctx; + chunk_t object; + u_int level; + int objectID = 0; + int responseType = OID_UNKNOWN; + ocsp_status_t status; + + asn1_init(&ctx, this->data, 0, FALSE, FALSE); + while (objectID < OCSP_RESPONSE_ROOF) + { + if (!extract_object(ocspResponseObjects, &objectID, &object, &level, &ctx)) + { + return FALSE; + } + switch (objectID) + { + case OCSP_RESPONSE_STATUS: + status = (ocsp_status_t)*object.ptr; + switch (status) + { + case OCSP_SUCCESSFUL: + break; + default: + DBG1("OCSP response status: %N", + ocsp_status_names, status); + return FALSE; + } + break; + case OCSP_RESPONSE_TYPE: + responseType = known_oid(object); + break; + case OCSP_RESPONSE: + switch (responseType) + { + case OID_BASIC: + return parse_basicOCSPResponse(this, object, level+1); + default: + DBG1("OCSP response type %#B not supported", &object); + return FALSE; + } + break; + } + objectID++; + } + return FALSE; +} + +/** + * Implementation of certificate_t.get_type + */ +static certificate_type_t get_type(private_x509_ocsp_response_t *this) +{ + return CERT_X509_OCSP_RESPONSE; +} + +/** + * Implementation of certificate_t.get_issuer + */ +static identification_t* get_issuer(private_x509_ocsp_response_t *this) +{ + return this->responderId; +} + +/** + * Implementation of certificate_t.has_subject. + */ +static id_match_t has_issuer(private_x509_ocsp_response_t *this, + identification_t *issuer) +{ + return this->responderId->matches(this->responderId, issuer); +} + +/** + * Implementation of certificate_t.issued_by + */ +static bool issued_by(private_x509_ocsp_response_t *this, certificate_t *issuer, + bool sigcheck) +{ + public_key_t *key; + signature_scheme_t scheme; + bool valid; + x509_t *x509 = (x509_t*)issuer; + + if (issuer->get_type(issuer) != CERT_X509) + { + return FALSE; + } + if (this->responderId->get_type(this->responderId) == ID_DER_ASN1_DN) + { + if (!this->responderId->equals(this->responderId, + issuer->get_subject(issuer))) + { + return FALSE; + } + } + else + { + bool equal; + public_key_t *public = issuer->get_public_key(issuer); + + if (public == NULL) + { + return FALSE; + } + equal = this->responderId->equals(this->responderId, + public->get_id(public, ID_PUBKEY_SHA1)); + public->destroy(public); + if (!equal) + { + return FALSE; + } + } + if (!(x509->get_flags(x509) & X509_OCSP_SIGNER)) + { + return FALSE; + } + if (!sigcheck) + { + return TRUE; + } + /* TODO: generic OID to scheme mapper? */ + switch (this->signatureAlgorithm) + { + case OID_MD5_WITH_RSA: + scheme = SIGN_RSA_EMSA_PKCS1_MD5; + break; + case OID_SHA1_WITH_RSA: + scheme = SIGN_RSA_EMSA_PKCS1_SHA1; + break; + case OID_SHA256_WITH_RSA: + scheme = SIGN_RSA_EMSA_PKCS1_SHA256; + break; + case OID_SHA384_WITH_RSA: + scheme = SIGN_RSA_EMSA_PKCS1_SHA384; + break; + case OID_SHA512_WITH_RSA: + scheme = SIGN_RSA_EMSA_PKCS1_SHA512; + break; + default: + return FALSE; + } + key = issuer->get_public_key(issuer); + if (key == NULL) + { + return FALSE; + } + valid = key->verify(key, scheme, this->tbsResponseData, this->signature); + key->destroy(key); + return valid; +} + +/** + * Implementation of certificate_t.get_public_key + */ +static public_key_t* get_public_key(private_x509_ocsp_response_t *this) +{ + return NULL; +} + +/** + * Implementation of x509_cert_t.get_validity. + */ +static bool get_validity(private_x509_ocsp_response_t *this, time_t *when, + time_t *not_before, time_t *not_after) +{ + time_t t; + + if (when == NULL) + { + t = time(NULL); + } + else + { + t = *when; + } + if (not_before) + { + *not_before = this->producedAt; + } + if (not_after) + { + *not_after = ~0; + } + /* valid from produceAt up to infinity */ + if (t >= this->producedAt) + { + return TRUE; + } + return FALSE; +} + +/** + * Implementation of certificate_t.get_encoding. + */ +static chunk_t get_encoding(private_x509_ocsp_response_t *this) +{ + return chunk_clone(this->data); +} + +/** + * Implementation of certificate_t.equals. + */ +static bool equals(private_x509_ocsp_response_t *this, certificate_t *other) +{ + if (this == (private_x509_ocsp_response_t*)other) + { + return TRUE; + } + if (other->get_type(other) != CERT_X509_OCSP_RESPONSE) + { + return FALSE; + } + /* check if we have the same X509 implementation */ + if (other->equals == (void*)equals) + { + return chunk_equals(this->data, + ((private_x509_ocsp_response_t*)other)->data); + } + /* TODO: compare against other implementation */ + return FALSE; +} + +/** + * Implementation of certificate_t.get_ref + */ +static private_x509_ocsp_response_t* get_ref(private_x509_ocsp_response_t *this) +{ + ref_get(&this->ref); + return this; +} + +/** + * Implements ocsp_t.destroy. + */ +static void destroy(private_x509_ocsp_response_t *this) +{ + if (ref_put(&this->ref)) + { + this->certs->destroy_offset(this->certs, offsetof(certificate_t, destroy)); + this->responses->destroy_function(this->responses, free); + DESTROY_IF(this->responderId); + free(this->data.ptr); + free(this); + } +} + +/** + * load an OCSP response + */ +static x509_ocsp_response_t *load(chunk_t data) +{ + private_x509_ocsp_response_t *this; + + this = malloc_thing(private_x509_ocsp_response_t); + + this->public.interface.certificate.get_type = (certificate_type_t (*)(certificate_t *this))get_type; + this->public.interface.certificate.get_subject = (identification_t* (*)(certificate_t *this))get_issuer; + this->public.interface.certificate.get_issuer = (identification_t* (*)(certificate_t *this))get_issuer; + this->public.interface.certificate.has_subject = (id_match_t(*)(certificate_t*, identification_t *subject))has_issuer; + this->public.interface.certificate.has_issuer = (id_match_t(*)(certificate_t*, identification_t *issuer))has_issuer; + this->public.interface.certificate.issued_by = (bool (*)(certificate_t *this, certificate_t *issuer,bool))issued_by; + this->public.interface.certificate.get_public_key = (public_key_t* (*)(certificate_t *this))get_public_key; + this->public.interface.certificate.get_validity = (bool(*)(certificate_t*, time_t *when, time_t *, time_t*))get_validity; + this->public.interface.certificate.get_encoding = (chunk_t(*)(certificate_t*))get_encoding; + this->public.interface.certificate.equals = (bool(*)(certificate_t*, certificate_t *other))equals; + this->public.interface.certificate.get_ref = (certificate_t* (*)(certificate_t *this))get_ref; + this->public.interface.certificate.destroy = (void (*)(certificate_t *this))destroy; + this->public.interface.get_status = (cert_validation_t(*)(ocsp_response_t*, x509_t *subject, x509_t *issuer, time_t *revocation_time,crl_reason_t *revocation_reason,time_t *this_update, time_t *next_update))get_status; + this->public.interface.create_cert_enumerator = (enumerator_t*(*)(ocsp_response_t*))create_cert_enumerator; + + this->ref = 1; + this->data = data; + this->tbsResponseData = chunk_empty; + this->responderId = NULL; + this->producedAt = UNDEFINED_TIME; + this->responses = linked_list_create(); + this->nonce = chunk_empty; + this->signatureAlgorithm = OID_UNKNOWN; + this->signature = chunk_empty; + this->certs = linked_list_create(); + + if (!parse_OCSPResponse(this)) + { + destroy(this); + return NULL; + } + return &this->public; +} + + +typedef struct private_builder_t private_builder_t; +/** + * Builder implementation for certificate loading + */ +struct private_builder_t { + /** implements the builder interface */ + builder_t public; + /** loaded response */ + x509_ocsp_response_t *res; +}; + +/** + * Implementation of builder_t.build + */ +static x509_ocsp_response_t *build(private_builder_t *this) +{ + x509_ocsp_response_t *res = this->res; + + free(this); + return res; +} + +/** + * Implementation of builder_t.add + */ +static void add(private_builder_t *this, builder_part_t part, ...) +{ + va_list args; + + if (this->res) + { + DBG1("ignoring surplus build part %N", builder_part_names, part); + return; + } + + switch (part) + { + case BUILD_BLOB_ASN1_DER: + { + va_start(args, part); + this->res = load(va_arg(args, chunk_t)); + va_end(args); + break; + } + default: + DBG1("ignoring unsupported build part %N", builder_part_names, part); + break; + } +} + +/** + * Builder construction function + */ +builder_t *x509_ocsp_response_builder(certificate_type_t type) +{ + private_builder_t *this; + + if (type != CERT_X509_OCSP_RESPONSE) + { + return NULL; + } + + this = malloc_thing(private_builder_t); + + this->res = NULL; + this->public.add = (void(*)(builder_t *this, builder_part_t part, ...))add; + this->public.build = (void*(*)(builder_t *this))build; + + return &this->public; +} + diff --git a/src/libstrongswan/plugins/x509/x509_ocsp_response.h b/src/libstrongswan/plugins/x509/x509_ocsp_response.h new file mode 100644 index 000000000..8b4c8328d --- /dev/null +++ b/src/libstrongswan/plugins/x509/x509_ocsp_response.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 x509_ocsp_response x509_ocsp_response + * @{ @ingroup x509_p + */ + +#ifndef X509_OCSP_RESPONSE_H_ +#define X509_OCSP_RESPONSE_H_ + +#include + +typedef struct x509_ocsp_response_t x509_ocsp_response_t; + +/** + * Implementation of ocsp_response_t using own ASN1 parser. + */ +struct x509_ocsp_response_t { + + /** + * Implements the ocsp_response_t interface + */ + ocsp_response_t interface; +}; + +/** + * Create the building facility for OCSP responses. + * + * @param type certificate type, CERT_X509_OCSP_RESPONSE only + * @return builder instance to build OCSP responses + */ +builder_t *x509_ocsp_response_builder(certificate_type_t type); + +#endif /* X509_OCSP_RESPONSE_H_ @}*/ diff --git a/src/libstrongswan/plugins/x509/x509_plugin.c b/src/libstrongswan/plugins/x509/x509_plugin.c new file mode 100644 index 000000000..8ddef3bcd --- /dev/null +++ b/src/libstrongswan/plugins/x509/x509_plugin.c @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "x509_plugin.h" + +#include +#include "x509_cert.h" +#include "x509_crl.h" +#include "x509_ocsp_request.h" +#include "x509_ocsp_response.h" + +typedef struct private_x509_plugin_t private_x509_plugin_t; + +/** + * private data of x509_plugin + */ +struct private_x509_plugin_t { + + /** + * public functions + */ + x509_plugin_t public; +}; + +/** + * Implementation of x509_plugin_t.x509troy + */ +static void destroy(private_x509_plugin_t *this) +{ + lib->creds->remove_builder(lib->creds, + (builder_constructor_t)x509_cert_builder); + lib->creds->remove_builder(lib->creds, + (builder_constructor_t)x509_crl_builder); + lib->creds->remove_builder(lib->creds, + (builder_constructor_t)x509_ocsp_request_builder); + lib->creds->remove_builder(lib->creds, + (builder_constructor_t)x509_ocsp_response_builder); + free(this); +} + +/* + * see header file + */ +plugin_t *plugin_create() +{ + private_x509_plugin_t *this = malloc_thing(private_x509_plugin_t); + + this->public.plugin.destroy = (void(*)(plugin_t*))destroy; + + lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_X509, + (builder_constructor_t)x509_cert_builder); + lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_X509_CRL, + (builder_constructor_t)x509_crl_builder); + lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_X509_OCSP_REQUEST, + (builder_constructor_t)x509_ocsp_request_builder); + lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_X509_OCSP_RESPONSE, + (builder_constructor_t)x509_ocsp_response_builder); + + return &this->public.plugin; +} + diff --git a/src/libstrongswan/plugins/x509/x509_plugin.h b/src/libstrongswan/plugins/x509/x509_plugin.h new file mode 100644 index 000000000..9743a2367 --- /dev/null +++ b/src/libstrongswan/plugins/x509/x509_plugin.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 x509_p x509 + * @ingroup plugins + * + * @defgroup x509_plugin x509_plugin + * @{ @ingroup x509_p + */ + +#ifndef X509_PLUGIN_H_ +#define X509_PLUGIN_H_ + +#include + +typedef struct x509_plugin_t x509_plugin_t; + +/** + * Plugin implementing x509, CRL and OCSP certificates. + */ +struct x509_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +/** + * Create a x509_plugin instance. + */ +plugin_t *plugin_create(); + +#endif /* X509_PLUGIN_H_ @}*/ diff --git a/src/libstrongswan/printf_hook.c b/src/libstrongswan/printf_hook.c index baf339640..26c0cac55 100644 --- a/src/libstrongswan/printf_hook.c +++ b/src/libstrongswan/printf_hook.c @@ -1,12 +1,5 @@ -/** - * @file printf_hook.c - * - * @brief Printf hook definitions and arginfo functions. - * - */ - /* - * Copyright (C) 2006 Martin Willi + * Copyright (C) 2006-2008 Martin Willi * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -18,124 +11,55 @@ * 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. + * + * $Id$ */ #include "printf_hook.h" -/** - * arginfo handler in printf() pointer - */ -int arginfo_ptr(const struct printf_info *info, size_t n, int *argtypes) -{ - if (n > 0) - { - argtypes[0] = PA_POINTER; - } - return 1; -} +#include -/** - * arginfo handler for two prt arguments - */ -int arginfo_ptr_ptr(const struct printf_info *info, size_t n, int *argtypes) -{ - if (n > 1) - { - argtypes[0] = PA_POINTER; - argtypes[1] = PA_POINTER; - } - return 2; -} +typedef struct private_printf_hook_t private_printf_hook_t; /** - * arginfo handler for one ptr, one int + * private data of printf_hook */ -int arginfo_ptr_int(const struct printf_info *info, size_t n, int *argtypes) -{ - if (n > 1) - { - argtypes[0] = PA_POINTER; - argtypes[1] = PA_INT; - } - return 2; -} +struct private_printf_hook_t { -/** - * arginfo handler for two int arguments - */ -int arginfo_int_int(const struct printf_info *info, size_t n, int *argtypes) -{ - if (n > 1) - { - argtypes[0] = PA_INT; - argtypes[1] = PA_INT; - } - return 2; -} + /** + * public functions + */ + printf_hook_t public; +}; /** - * special arginfo handler respecting alt flag + * Implementation of printf_hook_t.add_handler. */ -int arginfo_int_alt_int_int(const struct printf_info *info, size_t n, int *argtypes) +static void add_handler(private_printf_hook_t *this, char spec, + printf_hook_functions_t hook) { - if (info->alt) - { - if (n > 1) - { - argtypes[0] = PA_INT; - argtypes[1] = PA_INT; - } - return 2; - } - - if (n > 0) - { - argtypes[0] = PA_INT; - } - return 1; + register_printf_function(spec, hook.print, hook.arginfo); } /** - * special arginfo handler respecting alt flag + * Implementation of printf_hook_t.destroy */ -int arginfo_ptr_alt_ptr_int(const struct printf_info *info, size_t n, int *argtypes) +static void destroy(private_printf_hook_t *this) { - if (info->alt) - { - if (n > 1) - { - argtypes[0] = PA_POINTER; - argtypes[1] = PA_INT; - } - return 2; - } - - if (n > 0) - { - argtypes[0] = PA_POINTER; - } - return 1; + free(this); } -/** - * special arginfo handler respecting alt flag +/* + * see header file */ -int arginfo_ptr_alt_ptr_ptr(const struct printf_info *info, size_t n, int *argtypes) +printf_hook_t *printf_hook_create() { - if (info->alt) - { - if (n > 1) - { - argtypes[0] = PA_POINTER; - argtypes[1] = PA_POINTER; - } - return 2; - } + private_printf_hook_t *this = malloc_thing(private_printf_hook_t); + + this->public.add_handler = (void(*)(printf_hook_t*, char, printf_hook_functions_t))add_handler; + this->public.destroy = (void(*)(printf_hook_t*))destroy; + - if (n > 0) - { - argtypes[0] = PA_POINTER; - } - return 1; + return &this->public; } diff --git a/src/libstrongswan/printf_hook.h b/src/libstrongswan/printf_hook.h index 77b228da0..d9708c0f9 100644 --- a/src/libstrongswan/printf_hook.h +++ b/src/libstrongswan/printf_hook.h @@ -1,12 +1,5 @@ -/** - * @file printf_hook.h - * - * @brief Printf hook definitions and arginfo functions. - * - */ - /* - * Copyright (C) 2006 Martin Willi + * Copyright (C) 2006-2008 Martin Willi * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -18,44 +11,65 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup printf_hook printf_hook + * @{ @ingroup libstrongswan */ #ifndef PRINTF_HOOK_H_ #define PRINTF_HOOK_H_ +typedef struct printf_hook_t printf_hook_t; +typedef struct printf_hook_functions_t printf_hook_functions_t; + #include /** - * Printf() hook characters. - * We define all characters here to have them on a central place. + * Printf hook function set. + * + * A printf hook has two functions, one to print the string, one to read + * in the number of arguments. See . */ +struct printf_hook_functions_t { -/** 2 arguments: u_char *buffer, int size */ -#define PRINTF_BYTES 'b' -/** 1 argument: chunk_t *chunk; use #-modifier to print inline */ -#define PRINTF_CHUNK 'B' -/** 1 argument: identification_t *id */ -#define PRINTF_IDENTIFICATION 'D' -/** 1 argumnet: host_t *host; use #-modifier to include port number */ -#define PRINTF_HOST 'H' -/** 1 argument: ike_sa_t *ike_sa */ -#define PRINTF_ENUM 'N' -/** 1 argument: child_sa_t *child_sa */ -#define PRINTF_TRAFFIC_SELECTOR 'R' -/** 1 argument: time_t *time; with #-modifier 2 arguments: time_t *time, bool utc */ -#define PRINTF_TIME 'T' -/** 1 argument: time_t *delta; with #-modifier 2 arguments: time_t *begin, time_t *end */ -#define PRINTF_TIME_DELTA 'V' + /** + * Printf hook print function + */ + printf_function *print; + + /** + * Printf hook arginfo function + */ + printf_arginfo_function *arginfo; +}; /** - * Generic arginfo handlers for printf() hooks + * Printf handler management. */ -int arginfo_ptr(const struct printf_info *info, size_t n, int *argtypes); -int arginfo_ptr_ptr(const struct printf_info *info, size_t n, int *argtypes); -int arginfo_ptr_int(const struct printf_info *info, size_t n, int *argtypes); -int arginfo_int_int(const struct printf_info *info, size_t n, int *argtypes); -int arginfo_ptr_alt_ptr_int(const struct printf_info *info, size_t n, int *argtypes); -int arginfo_ptr_alt_ptr_ptr(const struct printf_info *info, size_t n, int *argtypes); -int arginfo_int_alt_int_int(const struct printf_info *info, size_t n, int *argtypes); - -#endif /* PRINTF_HOOK_H_ */ +struct printf_hook_t { + + /** + * Register a printf handler. + * + * @param spec printf hook format character + * @param hook hook functions + */ + void (*add_handler)(printf_hook_t *this, char spec, + printf_hook_functions_t hook); + + /** + * Destroy a printf_hook instance. + */ + void (*destroy)(printf_hook_t *this); +}; + +/** + * Create a printf_hook instance. + */ +printf_hook_t *printf_hook_create(); + +#endif /* PRINTF_HOOK_H_ @}*/ diff --git a/src/libstrongswan/settings.c b/src/libstrongswan/settings.c new file mode 100644 index 000000000..57325b50d --- /dev/null +++ b/src/libstrongswan/settings.c @@ -0,0 +1,408 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#define _GNU_SOURCE +#include +#include +#include + +#include "settings.h" + +#include +#include + + +typedef struct private_settings_t private_settings_t; +typedef struct section_t section_t; +typedef struct kv_t kv_t; + +/** + * private data of settings + */ +struct private_settings_t { + + /** + * public functions + */ + settings_t public; + + /** + * top level section + */ + section_t *top; + + /** + * allocated file text + */ + char *text; +}; + +/** + * section containing subsections and key value pairs + */ +struct section_t { + + /** + * name of the section + */ + char *name; + + /** + * subsections, as section_t + */ + linked_list_t *sections; + + /** + * key value pairs, as kv_t + */ + linked_list_t *kv; +}; + +/** + * Key value pair + */ +struct kv_t { + + /** + * key string, relative + */ + char *key; + + /** + * value as string + */ + char *value; +}; + +static char *find(section_t *section, char *key) +{ + char *name, *pos, *value = NULL; + enumerator_t *enumerator; + kv_t *kv; + section_t *current, *found = NULL; + + if (section == NULL) + { + return NULL; + } + + name = strdupa(key); + + pos = strchr(name, '.'); + if (pos) + { + *pos = '\0'; + pos++; + enumerator = section->sections->create_enumerator(section->sections); + while (enumerator->enumerate(enumerator, ¤t)) + { + if (streq(current->name, name)) + { + found = current; + break; + } + } + enumerator->destroy(enumerator); + if (found) + { + return find(found, pos); + } + } + else + { + enumerator = section->kv->create_enumerator(section->kv); + while (enumerator->enumerate(enumerator, &kv)) + { + if (streq(kv->key, name)) + { + value = kv->value; + break; + } + } + enumerator->destroy(enumerator); + } + return value; +} + +/** + * Implementation of settings_t.get. + */ +static char* get_str(private_settings_t *this, char *key, char *def) +{ + char *value; + + value = find(this->top, key); + if (value) + { + return value; + } + return def; +} + +/** + * Implementation of settings_t.get_bool. + */ +static bool get_bool(private_settings_t *this, char *key, bool def) +{ + char *value; + + value = find(this->top, key); + if (value) + { + if (strcasecmp(value, "true") == 0 || + strcasecmp(value, "enables") == 0 || + strcasecmp(value, "yes") == 0 || + strcasecmp(value, "1") == 0) + { + return TRUE; + } + else if (strcasecmp(value, "false") == 0 || + strcasecmp(value, "disabled") == 0 || + strcasecmp(value, "no") == 0 || + strcasecmp(value, "0") == 0) + { + return FALSE; + } + } + return def; +} + +/** + * Implementation of settings_t.get_int. + */ +static int get_int(private_settings_t *this, char *key, int def) +{ + char *value; + int intval; + + value = find(this->top, key); + if (value) + { + errno = 0; + intval = strtol(value, NULL, 10); + if (errno == 0) + { + return intval; + } + } + return def; +} + +/** + * destry a section +*/ +static void section_destroy(section_t *this) +{ + this->kv->destroy_function(this->kv, free); + this->sections->destroy_function(this->sections, (void*)section_destroy); + + free(this); +} + +/** + * parse text, truncate "skip" chars, delimited by term respecting brackets. + * + * Chars in "skip" are truncated at the beginning and the end of the resulting + * token. "term" contains a list of characters to read up to (first match), + * while "br" contains bracket counterparts found in "term" to skip. + */ +static char parse(char **text, char *skip, char *term, char *br, char **token) +{ + char *best = NULL; + char best_term = '\0'; + + /* skip leading chars */ + while (strchr(skip, **text)) + { + (*text)++; + if (!**text) + { + return 0; + } + } + /* mark begin of subtext */ + *token = *text; + while (*term) + { + char *pos = *text; + int level = 1; + + /* find terminator */ + while (*pos) + { + if (*pos == *term) + { + level--; + } + else if (br && *pos == *br) + { + level++; + } + if (level == 0) + { + if (best == NULL || best > pos) + { + best = pos; + best_term = *term; + } + break; + } + pos++; + } + /* try next terminator */ + term++; + if (br) + { + br++; + } + } + if (best) + { + /* update input */ + *text = best; + /* null trailing bytes */ + do + { + *best = '\0'; + best--; + } + while (best >= *token && strchr(skip, *best)); + /* return found terminator */ + return best_term; + } + return 0; +} + +/** + * Parse a section + */ +static section_t* parse_section(char **text, char *name) +{ + section_t *sub, *section; + bool finished = FALSE; + char *key, *value, *inner; + + static int lev = 0; + lev++; + + section = malloc_thing(section_t); + section->name = name; + section->sections = linked_list_create(); + section->kv = linked_list_create(); + + while (!finished) + { + switch (parse(text, "\t\n ", "{=#", NULL, &key)) + { + case '{': + if (parse(text, "\t ", "}", "{", &inner)) + { + sub = parse_section(&inner, key); + if (sub) + { + section->sections->insert_last(section->sections, sub); + continue; + } + } + break; + case '=': + if (parse(text, "\t ", "\n", NULL, &value)) + { + kv_t *kv = malloc_thing(kv_t); + kv->key = key; + kv->value = value; + section->kv->insert_last(section->kv, kv); + continue; + } + break; + case '#': + parse(text, "", "\n", NULL, &value); + continue; + default: + finished = TRUE; + continue; + } + section_destroy(section); + return NULL; + } + return section; +} + +/** + * Implementation of settings_t.destroy + */ +static void destroy(private_settings_t *this) +{ + if (this->top) + { + section_destroy(this->top); + } + free(this->text); + free(this); +} + +/* + * see header file + */ +settings_t *settings_create(char *file) +{ + private_settings_t *this = malloc_thing(private_settings_t); + + this->public.get_str = (char*(*)(settings_t*, char *key, char* def))get_str; + this->public.get_int = (int(*)(settings_t*, char *key, bool def))get_int; + this->public.get_bool = (bool(*)(settings_t*, char *key, bool def))get_bool; + this->public.destroy = (void(*)(settings_t*))destroy; + + this->top = NULL; + this->text = NULL; + + if (file) + { + FILE *fd; + int len; + char *pos; + + fd = fopen(file, "r"); + if (fd == NULL) + { + return &this->public; + } + fseek(fd, 0, SEEK_END); + len = ftell(fd); + rewind(fd); + this->text = malloc(len + 1); + this->text[len] = '\0'; + if (fread(this->text, 1, len, fd) != len) + { + free(this->text); + this->text = NULL; + return &this->public; + } + fclose(fd); + + pos = this->text; + this->top = parse_section(&pos, NULL); + if (this->top == NULL) + { + free(this->text); + this->text = NULL; + return &this->public; + } + } + return &this->public; +} + diff --git a/src/libstrongswan/settings.h b/src/libstrongswan/settings.h new file mode 100644 index 000000000..91770973b --- /dev/null +++ b/src/libstrongswan/settings.h @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +/** + * @defgroup settings settings + * @{ @ingroup libstrongswan + */ + +#ifndef SETTINGS_H_ +#define SETTINGS_H_ + +typedef struct settings_t settings_t; + +#include + +/** + * Generic configuration options read from a config file. + * + * The sytax is quite simple: + * + * settings := (section|keyvalue)* + * section := name { settings } + * keyvalue := key = value\n + * + * E.g.: + * @code + a = b + section-one { + somevalue = asdf + subsection { + othervalue = xxx + } + yetanother = zz + } + section-two { + } + @endcode + * + * The values are accesses using the get() functions using dotted keys, e.g. + * section-one.subsection.othervalue + */ +struct settings_t { + + /** + * Get a settings value as a string. + * + * @param key key including sections + * @param def value returned if key not found + * @return value pointing to internal string + */ + char* (*get_str)(settings_t *this, char *key, char *def); + + /** + * Get a boolean yes|no, true|false value. + * + * @param jey key including sections + * @param def default value returned if key not found + * @return value of the key + */ + bool (*get_bool)(settings_t *this, char *key, bool def); + + /** + * Get an integer value. + * + * @param key key including sections + * @param def default value to return if key not found + * @return value of the key + */ + int (*get_int)(settings_t *this, char *key, bool def); + + /** + * Destroy a settings instance. + */ + void (*destroy)(settings_t *this); +}; + +/** + * Load setings from a file. + */ +settings_t *settings_create(char *file); + +#endif /* SETTINGS_H_ @}*/ diff --git a/src/libstrongswan/utils.c b/src/libstrongswan/utils.c new file mode 100644 index 000000000..d6920cf28 --- /dev/null +++ b/src/libstrongswan/utils.c @@ -0,0 +1,327 @@ +/* + * Copyright (C) 2005-2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "utils.h" + +#include +#include +#include + +#include + +ENUM(status_names, SUCCESS, DESTROY_ME, + "SUCCESS", + "FAILED", + "OUT_OF_RES", + "ALREADY_DONE", + "NOT_SUPPORTED", + "INVALID_ARG", + "NOT_FOUND", + "PARSE_ERROR", + "VERIFY_ERROR", + "INVALID_STATE", + "DESTROY_ME", + "NEED_MORE", +); + +/** + * Described in header. + */ +void *clalloc(void * pointer, size_t size) +{ + void *data; + data = malloc(size); + + memcpy(data, pointer, size); + + return (data); +} + +/** + * Described in header. + */ +void memxor(u_int8_t dest[], u_int8_t src[], size_t n) +{ + size_t i; + for (i = 0; i < n; i++) + { + dest[i] ^= src[i]; + } +} + +/** + * We use a single mutex for all refcount variables. This + * is not optimal for performance, but the critical section + * is not that long... + * TODO: Consider to include a mutex in each refcount_t variable. + */ +static pthread_mutex_t ref_mutex = PTHREAD_MUTEX_INITIALIZER; + +/** + * Described in header. + * + * TODO: May be implemented with atomic CPU instructions + * instead of a mutex. + */ +void ref_get(refcount_t *ref) +{ + pthread_mutex_lock(&ref_mutex); + (*ref)++; + pthread_mutex_unlock(&ref_mutex); +} + +/** + * Described in header. + * + * TODO: May be implemented with atomic CPU instructions + * instead of a mutex. + */ +bool ref_put(refcount_t *ref) +{ + bool more_refs; + + pthread_mutex_lock(&ref_mutex); + more_refs = --(*ref); + pthread_mutex_unlock(&ref_mutex); + return !more_refs; +} + +/** + * output handler in printf() for time_t + */ +static int time_print(FILE *stream, const struct printf_info *info, + const void *const *args) +{ + static const char* months[] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" + }; + time_t *time = *((time_t**)(args[0])); + bool utc = TRUE; + struct tm t; + + if (info->alt) + { + utc = *((bool*)(args[1])); + } + if (time == UNDEFINED_TIME) + { + return fprintf(stream, "--- -- --:--:--%s----", + info->alt ? " UTC " : " "); + } + if (utc) + { + gmtime_r(time, &t); + } + else + { + localtime_r(time, &t); + } + return fprintf(stream, "%s %02d %02d:%02d:%02d%s%04d", + months[t.tm_mon], t.tm_mday, t.tm_hour, t.tm_min, + t.tm_sec, utc ? " UTC " : " ", t.tm_year + 1900); +} + +/** + * arginfo handler for printf() time + */ +static int time_arginfo(const struct printf_info *info, size_t n, int *argtypes) +{ + if (info->alt) + { + if (n > 1) + { + argtypes[0] = PA_POINTER; + argtypes[1] = PA_INT; + } + return 2; + } + + if (n > 0) + { + argtypes[0] = PA_POINTER; + } + return 1; +} + +/** + * output handler in printf() for time deltas + */ +static int time_delta_print(FILE *stream, const struct printf_info *info, + const void *const *args) +{ + char* unit = "second"; + time_t *arg1, *arg2; + time_t delta; + + arg1 = *((time_t**)(args[0])); + if (info->alt) + { + arg2 = *((time_t**)(args[1])); + delta = abs(*arg1 - *arg2); + } + else + { + delta = *arg1; + } + + if (delta > 2 * 60 * 60 * 24) + { + delta /= 60 * 60 * 24; + unit = "day"; + } + else if (delta > 2 * 60 * 60) + { + delta /= 60 * 60; + unit = "hour"; + } + else if (delta > 2 * 60) + { + delta /= 60; + unit = "minute"; + } + return fprintf(stream, "%d %s%s", delta, unit, (delta == 1)? "":"s"); +} + +/** + * arginfo handler for printf() time deltas + */ +int time_delta_arginfo(const struct printf_info *info, size_t n, int *argtypes) +{ + if (info->alt) + { + if (n > 1) + { + argtypes[0] = PA_POINTER; + argtypes[1] = PA_POINTER; + } + return 2; + } + + if (n > 0) + { + argtypes[0] = PA_POINTER; + } + return 1; +} + +/** + * Number of bytes per line to dump raw data + */ +#define BYTES_PER_LINE 16 + +static char hexdig_upper[] = "0123456789ABCDEF"; + +/** + * output handler in printf() for mem ranges + */ +static int mem_print(FILE *stream, const struct printf_info *info, + const void *const *args) +{ + char *bytes = *((void**)(args[0])); + int len = *((size_t*)(args[1])); + + char buffer[BYTES_PER_LINE * 3]; + char ascii_buffer[BYTES_PER_LINE + 1]; + char *buffer_pos = buffer; + char *bytes_pos = bytes; + char *bytes_roof = bytes + len; + int line_start = 0; + int i = 0; + int written = 0; + + written += fprintf(stream, "=> %d bytes @ %p", len, bytes); + + while (bytes_pos < bytes_roof) + { + *buffer_pos++ = hexdig_upper[(*bytes_pos >> 4) & 0xF]; + *buffer_pos++ = hexdig_upper[ *bytes_pos & 0xF]; + + ascii_buffer[i++] = + (*bytes_pos > 31 && *bytes_pos < 127) ? *bytes_pos : '.'; + + if (++bytes_pos == bytes_roof || i == BYTES_PER_LINE) + { + int padding = 3 * (BYTES_PER_LINE - i); + int written; + + while (padding--) + { + *buffer_pos++ = ' '; + } + *buffer_pos++ = '\0'; + ascii_buffer[i] = '\0'; + + written += fprintf(stream, "\n%4d: %s %s", + line_start, buffer, ascii_buffer); + + + buffer_pos = buffer; + line_start += BYTES_PER_LINE; + i = 0; + } + else + { + *buffer_pos++ = ' '; + } + } + return written; +} + +/** + * arginfo handler for printf() mem ranges + */ +int mem_arginfo(const struct printf_info *info, size_t n, int *argtypes) +{ + if (n > 1) + { + argtypes[0] = PA_POINTER; + argtypes[1] = PA_INT; + } + return 2; +} + +/** + * return printf hook functions for a time + */ +printf_hook_functions_t time_get_printf_hooks() +{ + printf_hook_functions_t hooks = {time_print, time_arginfo}; + + return hooks; +} + +/** + * return printf hook functions for a time delta + */ +printf_hook_functions_t time_delta_get_printf_hooks() +{ + printf_hook_functions_t hooks = {time_delta_print, time_delta_arginfo}; + + return hooks; +} + +/** + * return printf hook functions for mem ranges + */ +printf_hook_functions_t mem_get_printf_hooks() +{ + printf_hook_functions_t hooks = {mem_print, mem_arginfo}; + + return hooks; +} + diff --git a/src/libstrongswan/utils.h b/src/libstrongswan/utils.h new file mode 100644 index 000000000..2624c31d1 --- /dev/null +++ b/src/libstrongswan/utils.h @@ -0,0 +1,265 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +/** + * @defgroup utils utils + * @{ @ingroup libstrongswan + */ + +#ifndef UTILS_H_ +#define UTILS_H_ + +#include +#include +#include + +#include + +/** + * Number of bits in a byte + */ +#define BITS_PER_BYTE 8 + +/** + * Default length for various auxiliary text buffers + */ +#define BUF_LEN 512 + +/** + * Macro compares two strings for equality + */ +#define streq(x,y) (strcmp(x, y) == 0) + +/** + * Macro compares two strings for equality + */ +#define strneq(x,y,len) (strncmp(x, y, len) == 0) + +/** + * Macro compares two binary blobs for equality + */ +#define memeq(x,y,len) (memcmp(x, y, len) == 0) + +/** + * Macro gives back larger of two values. + */ +#define max(x,y) ((x) > (y) ? (x):(y)) + +/** + * Macro gives back smaller of two values. + */ +#define min(x,y) ((x) < (y) ? (x):(y)) + +/** + * Call destructor of an object, if object != NULL + */ +#define DESTROY_IF(obj) if (obj) (obj)->destroy(obj) + +/** + * Call offset destructor of an object, if object != NULL + */ +#define DESTROY_OFFSET_IF(obj, offset) if (obj) obj->destroy_offset(obj, offset); + +/** + * Call function destructor of an object, if object != NULL + */ +#define DESTROY_FUNCTION_IF(obj, fn) if (obj) obj->destroy_function(obj, fn); + +/** + * Debug macro to follow control flow + */ +#define POS printf("%s, line %d\n", __FILE__, __LINE__) + +/** + * Macro to allocate a sized type. + */ +#define malloc_thing(thing) ((thing*)malloc(sizeof(thing))) + +/** + * Assign a function as a class method + */ +#define ASSIGN(method, function) (method = (typeof(method))function) + +/** + * time_t not defined + */ +#define UNDEFINED_TIME 0 + +/** + * General purpose boolean type. + */ +typedef int bool; +#define FALSE 0 +#define TRUE 1 + +typedef enum status_t status_t; + +/** + * Return values of function calls. + */ +enum status_t { + /** + * Call succeeded. + */ + SUCCESS, + + /** + * Call failed. + */ + FAILED, + + /** + * Out of resources. + */ + OUT_OF_RES, + + /** + * The suggested operation is already done + */ + ALREADY_DONE, + + /** + * Not supported. + */ + NOT_SUPPORTED, + + /** + * One of the arguments is invalid. + */ + INVALID_ARG, + + /** + * Something could not be found. + */ + NOT_FOUND, + + /** + * Error while parsing. + */ + PARSE_ERROR, + + /** + * Error while verifying. + */ + VERIFY_ERROR, + + /** + * Object in invalid state. + */ + INVALID_STATE, + + /** + * Destroy object which called method belongs to. + */ + DESTROY_ME, + + /** + * Another call to the method is required. + */ + NEED_MORE, +}; + +/** + * enum_names for type status_t. + */ +extern enum_name_t *status_names; + +/** + * deprecated pluto style return value: + * error message, NULL for success + */ +typedef const char *err_t; + +/** + * Handle struct timeval like an own type. + */ +typedef struct timeval timeval_t; + +/** + * Handle struct timespec like an own type. + */ +typedef struct timespec timespec_t; + +/** + * Handle struct chunk_t like an own type. + */ +typedef struct sockaddr sockaddr_t; + +/** + * Clone a data to a newly allocated buffer + */ +void *clalloc(void *pointer, size_t size); + +/** + * Same as memcpy, but XORs src into dst instead of copy + */ +void memxor(u_int8_t dest[], u_int8_t src[], size_t n); + +/** + * Special type to count references + */ +typedef volatile u_int refcount_t; + +/** + * Get a new reference. + * + * Increments the reference counter atomic. + * + * @param ref pointer to ref counter + */ +void ref_get(refcount_t *ref); + +/** + * Put back a unused reference. + * + * Decrements the reference counter atomic and + * says if more references available. + * + * @param ref pointer to ref counter + * @return TRUE if no more references counted + */ +bool ref_put(refcount_t *ref); + +/** + * Get printf hooks for time. + * + * Arguments are: + * time_t* time + * Arguments using #-specificer + * time_t* time, bool utc + */ +printf_hook_functions_t time_get_printf_hooks(); + +/** + * Get printf hooks for time deltas. + * + * Arguments are: + * time_t* delta + * Arguments using #-specificer + * time_t* begin, time_t* end + */ +printf_hook_functions_t time_delta_get_printf_hooks(); + +/** + * Get printf hooks for time deltas. + * + * Arguments are: + * u_char *ptr, int len + */ +printf_hook_functions_t mem_get_printf_hooks(); + +#endif /* UTILS_H_ @}*/ diff --git a/src/libstrongswan/utils/enumerator.c b/src/libstrongswan/utils/enumerator.c index 842a2e997..67d0c8d1a 100644 --- a/src/libstrongswan/utils/enumerator.c +++ b/src/libstrongswan/utils/enumerator.c @@ -1,10 +1,3 @@ -/** - * @file enumerator.c - * - * @brief Implementation of enumerator_t. - * - */ - /* * Copyright (C) 2007 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,10 +11,20 @@ * 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. + * + * $Id$ */ #include "enumerator.h" +#include +#include +#include +#include +#include +#include + +#include /** * Implementation of enumerator_create_empty().enumerate @@ -42,3 +45,350 @@ enumerator_t* enumerator_create_empty() return this; } +/** + * Enumerator implementation for directory enumerator + */ +typedef struct { + /** implements enumerator_t */ + enumerator_t public; + /** directory handle */ + DIR *dir; + /** absolute path of current file */ + char full[PATH_MAX]; + /** where directory part of full ends and relative file gets written */ + char *full_end; +} dir_enum_t; + +/** + * Implementation of enumerator_create_directory().destroy + */ +static void destroy_dir_enum(dir_enum_t *this) +{ + closedir(this->dir); + free(this); +} + +/** + * Implementation of enumerator_create_directory().enumerate + */ +static bool enumerate_dir_enum(dir_enum_t *this, char **relative, + char **absolute, struct stat *st) +{ + struct dirent *entry = readdir(this->dir); + size_t len, remaining; + + if (!entry) + { + return FALSE; + } + if (streq(entry->d_name, ".") || streq(entry->d_name, "..")) + { + return enumerate_dir_enum(this, relative, absolute, st); + } + if (relative) + { + *relative = entry->d_name; + } + if (absolute || st) + { + remaining = sizeof(this->full) - (this->full_end - this->full); + len = snprintf(this->full_end, remaining, "%s", entry->d_name); + if (len < 0 || len >= remaining) + { + DBG1("buffer too small to enumerate file '%s'", entry->d_name); + return FALSE; + } + if (absolute) + { + *absolute = this->full; + } + if (st) + { + if (stat(this->full, st)) + { + DBG1("stat() on '%s' failed: %s", this->full, strerror(errno)); + return FALSE; + } + } + } + return TRUE; +} + +/** + * See header + */ +enumerator_t* enumerator_create_directory(char *path) +{ + size_t len; + dir_enum_t *this = malloc_thing(dir_enum_t); + this->public.enumerate = (void*)enumerate_dir_enum; + this->public.destroy = (void*)destroy_dir_enum; + + if (*path == '\0') + { + path = "./"; + } + len = snprintf(this->full, sizeof(this->full)-1, "%s", path); + if (len < 0 || len >= sizeof(this->full)-1) + { + DBG1("path string %s too long", path); + free(this); + return NULL; + } + /* append a '/' if not already done */ + if (this->full[len-1] != '/') + { + this->full[len++] = '/'; + this->full[len] = '\0'; + } + this->full_end = &this->full[len]; + + this->dir = opendir(path); + if (this->dir == NULL) + { + DBG1("opening directory %s failed: %s", path, strerror(errno)); + free(this); + return NULL; + } + return &this->public; +} + +/** + * enumerator for nested enumerations + */ +typedef struct { + /* implements enumerator_t */ + enumerator_t public; + /* outer enumerator */ + enumerator_t *outer; + /* inner enumerator */ + enumerator_t *inner; + /* constructor for inner enumerator */ + enumerator_t *(*create_inner)(void *outer, void *data); + /* data to pass to constructor above */ + void *data; + /* destructor for data */ + void (*destroy_data)(void *data); +} nested_enumerator_t; + + +/** + * Implementation of enumerator_create_nested().enumerate() + */ +static bool enumerate_nested(nested_enumerator_t *this, void *v1, void *v2, + void *v3, void *v4, void *v5) +{ + while (TRUE) + { + while (this->inner == NULL) + { + void *outer; + + if (!this->outer->enumerate(this->outer, &outer)) + { + return FALSE; + } + this->inner = this->create_inner(outer, this->data); + } + if (this->inner->enumerate(this->inner, v1, v2, v3, v4, v5)) + { + return TRUE; + } + this->inner->destroy(this->inner); + this->inner = NULL; + } +} + +/** + * Implementation of enumerator_create_nested().destroy() + **/ +static void destroy_nested(nested_enumerator_t *this) +{ + if (this->destroy_data) + { + this->destroy_data(this->data); + } + DESTROY_IF(this->inner); + this->outer->destroy(this->outer); + free(this); +} + +/** + * See header + */ +enumerator_t *enumerator_create_nested(enumerator_t *outer, + enumerator_t *(inner_constructor)(void *outer, void *data), + void *data, void (*destroy_data)(void *data)) +{ + nested_enumerator_t *enumerator = malloc_thing(nested_enumerator_t); + + enumerator->public.enumerate = (void*)enumerate_nested; + enumerator->public.destroy = (void*)destroy_nested; + enumerator->outer = outer; + enumerator->inner = NULL; + enumerator->create_inner = (void*)inner_constructor; + enumerator->data = data; + enumerator->destroy_data = destroy_data; + + return &enumerator->public; +} + +/** + * enumerator for filtered enumerator + */ +typedef struct { + enumerator_t public; + enumerator_t *unfiltered; + void *data; + bool (*filter)(void *data, ...); + void (*destructor)(void *data); +} filter_enumerator_t; + +/** + * Implementation of enumerator_create_filter().destroy + */ +void destroy_filter(filter_enumerator_t *this) +{ + if (this->destructor) + { + this->destructor(this->data); + } + this->unfiltered->destroy(this->unfiltered); + free(this); +} + +/** + * Implementation of enumerator_create_filter().enumerate + */ +bool enumerate_filter(filter_enumerator_t *this, void *o1, void *o2, + void *o3, void *o4, void *o5) +{ + void *i1, *i2, *i3, *i4, *i5; + + while (this->unfiltered->enumerate(this->unfiltered, &i1, &i2, &i3, &i4, &i5)) + { + if (this->filter(this->data, &i1, o1, &i2, o2, &i3, o3, &i4, o4, &i5, o5)) + { + return TRUE; + } + } + return FALSE; +} + +/** + * see header + */ +enumerator_t *enumerator_create_filter(enumerator_t *unfiltered, + bool (*filter)(void *data, ...), + void *data, void (*destructor)(void *data)) +{ + filter_enumerator_t *this = malloc_thing(filter_enumerator_t); + + this->public.enumerate = (void*)enumerate_filter; + this->public.destroy = (void*)destroy_filter; + this->unfiltered = unfiltered; + this->filter = filter; + this->data = data; + this->destructor = destructor; + + return &this->public; +} + +/** + * enumerator for cleaner enumerator + */ +typedef struct { + enumerator_t public; + enumerator_t *wrapped; + void (*cleanup)(void *data); + void *data; +} cleaner_enumerator_t; + +/** + * Implementation of enumerator_create_cleanup().destroy + */ +static void destroy_cleaner(cleaner_enumerator_t *this) +{ + this->cleanup(this->data); + this->wrapped->destroy(this->wrapped); + free(this); +} + +/** + * Implementation of enumerator_create_cleaner().enumerate + */ +static bool enumerate_cleaner(cleaner_enumerator_t *this, void *v1, void *v2, + void *v3, void *v4, void *v5) +{ + return this->wrapped->enumerate(this->wrapped, v1, v2, v3, v4, v5); +} + +/** + * see header + */ +enumerator_t *enumerator_create_cleaner(enumerator_t *wrapped, + void (*cleanup)(void *data), void *data) +{ + cleaner_enumerator_t *this = malloc_thing(cleaner_enumerator_t); + + this->public.enumerate = (void*)enumerate_cleaner; + this->public.destroy = (void*)destroy_cleaner; + this->wrapped = wrapped; + this->cleanup = cleanup; + this->data = data; + + return &this->public; +} + +/** + * enumerator for single enumerator + */ +typedef struct { + enumerator_t public; + void *item; + void (*cleanup)(void *item); + bool done; +} single_enumerator_t; + +/** + * Implementation of enumerator_create_single().destroy + */ +static void destroy_single(single_enumerator_t *this) +{ + if (this->cleanup) + { + this->cleanup(this->item); + } + free(this); +} + +/** + * Implementation of enumerator_create_single().enumerate + */ +static bool enumerate_single(single_enumerator_t *this, void **item) +{ + if (this->done) + { + return FALSE; + } + *item = this->item; + this->done = TRUE; + return TRUE; +} + +/** + * see header + */ +enumerator_t *enumerator_create_single(void *item, void (*cleanup)(void *item)) +{ + single_enumerator_t *this = malloc_thing(single_enumerator_t); + + this->public.enumerate = (void*)enumerate_single; + this->public.destroy = (void*)destroy_single; + this->item = item; + this->cleanup = cleanup; + this->done = FALSE; + + return &this->public; +} + diff --git a/src/libstrongswan/utils/enumerator.h b/src/libstrongswan/utils/enumerator.h index df1d78206..4de287890 100644 --- a/src/libstrongswan/utils/enumerator.h +++ b/src/libstrongswan/utils/enumerator.h @@ -1,10 +1,3 @@ -/** - * @file enumerator.h - * - * @brief Interface of enumerator_t. - * - */ - /* * Copyright (C) 2007 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,22 +11,29 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup enumerator enumerator + * @{ @ingroup utils */ #ifndef ENUMERATOR_H_ #define ENUMERATOR_H_ -#include - typedef struct enumerator_t enumerator_t; +#include + /** - * @brief Enumerate is simpler, but more flexible than iterator. + * Enumerate is simpler, but more flexible than iterator. */ struct enumerator_t { /** - * @brief Enumerate collection. + * Enumerate collection. * * The enumerate function takes a variable argument list containing * pointers where the enumerated values get written. @@ -44,14 +44,104 @@ struct enumerator_t { bool (*enumerate)(enumerator_t *this, ...); /** - * @brief Destroy a enumerator instance. + * Destroy a enumerator instance. */ void (*destroy)(enumerator_t *this); }; /** - * @brief Create an enumerator which enumerates over nothing + * Create an enumerator which enumerates over nothing + * + * @return an enumerator over no values */ enumerator_t* enumerator_create_empty(); -#endif /* ENUMERATOR_H_ */ +/** + * Create an enumerator which enumerates over a single item + * + * @param item item to enumerate + * @param cleanup cleanup function called on destroy with the item + * @return an enumerator over a single value + */ +enumerator_t *enumerator_create_single(void *item, void (*cleanup)(void *item)); + +/** + * Create an enumerator over files/subdirectories in a directory. + * + * This enumerator_t.enumerate() function returns a (to the directory) relative + * filename (as a char*), an absolute filename (as a char*) and a file status + * (to a struct stat), which all may be NULL. "." and ".." entries are + * skipped. Example: + * + * @code + char *rel, *abs; + struct stat st; + enumerator_t *e; + + e = enumerator_create_directory("/tmp"); + if (e) + { + while (e->enumerate(e, &rel, &abs, &st)) + { + if (S_ISDIR(st.st_mode) && *rel != '.') + { + printf("%s\n", abs); + } + } + e->destroy(e); + } + @endcode + * + * @param path path of the directory + * @return the directory enumerator, NULL on failure + */ +enumerator_t* enumerator_create_directory(char *path); + +/** + * Creates an enumerator which enumerates over enumerated enumerators :-). + * + * The variable argument list of enumeration values is limit to 5. + * + * @param outer outer enumerator + * @param inner_constructor constructor to inner enumerator + * @param data data to pass to each inner_constructor call + * @param destroy_data destructor to pass to data + * @return the nested enumerator + */ +enumerator_t *enumerator_create_nested(enumerator_t *outer, + enumerator_t *(inner_constructor)(void *outer, void *data), + void *data, void (*destroy_data)(void *data)); + +/** + * Creates an enumerator which filters output of another enumerator. + * + * The filter function receives the user supplied "data" followed by a + * unfiltered enumeration item, followed by an output pointer where to write + * the filtered data. Then the next input/output pair follows. + * It returns TRUE to deliver the + * values to the caller of enumerate(), FALSE to filter this enumeration. + * + * The variable argument list of enumeration values is limit to 5. + * + * @param unfiltered unfiltered enumerator to wrap, gets destroyed + * @param filter filter function + * @param data user data to supply to filter + * @param destructor destructor function to clean up data after use + * @return the filtered enumerator + */ +enumerator_t *enumerator_create_filter(enumerator_t *unfiltered, + bool (*filter)(void *data, ...), + void *data, void (*destructor)(void *data)); + +/** + * Create an enumerator wrapper which does a cleanup on destroy. + * + * @param wrapped wrapped enumerator + * @param cleanup cleanup function called on destroy + * @param data user data to supply to cleanup + * @return the enumerator with cleanup + */ +enumerator_t *enumerator_create_cleaner(enumerator_t *wrapped, + void (*cleanup)(void *data), void *data); + +#endif /* ENUMERATOR_H_ @} */ diff --git a/src/libstrongswan/utils/fetcher.c b/src/libstrongswan/utils/fetcher.c deleted file mode 100644 index 7a06999aa..000000000 --- a/src/libstrongswan/utils/fetcher.c +++ /dev/null @@ -1,424 +0,0 @@ -/** - * @file fetcher.c - * - * @brief Implementation of fetcher_t. - * - */ - -/* - * Copyright (C) 2007 Andreas Steffen - * 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 . - * - * 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. - */ - -#ifdef LIBCURL -#include -#endif /* LIBCURL */ - -#ifdef LIBLDAP -#ifndef LDAP_DEPRECATED -#define LDAP_DEPRECATED 1 -#endif -#include -#endif /* LIBLDAP */ - -#include -#include - -#include "fetcher.h" - -typedef struct private_fetcher_t private_fetcher_t; - -/** - * @brief Private Data of a fetcher_t object. - */ -struct private_fetcher_t { - /** - * Public data - */ - fetcher_t public; - - /** - * URI of the information source - */ - const char *uri; - -#ifdef LIBCURL - /** - * we use libcurl from http://curl.haxx.se/ as a fetcher - */ - CURL* curl; -#endif /* LIBCURL */ - -#ifdef LIBLDAP - /** - * we use libldap from http://www.openssl.org/ as a fetcher - */ - LDAP *ldap; - LDAPURLDesc *lurl; -#endif /* LIBLDAP */ -}; - -/** - * writes data into a dynamically resizeable chunk_t - * needed for libcurl responses - */ -static size_t curl_write_buffer(void *ptr, size_t size, size_t nmemb, void *data) -{ - size_t realsize = size * nmemb; - chunk_t *mem = (chunk_t*)data; - - mem->ptr = (u_char *)realloc(mem->ptr, mem->len + realsize); - if (mem->ptr) { - memcpy(&(mem->ptr[mem->len]), ptr, realsize); - mem->len += realsize; - } - return realsize; -} - -/** - * Implements fetcher_t.get for curl methods - */ -static chunk_t curl_get(private_fetcher_t *this) -{ - chunk_t response = chunk_empty; - -#ifdef LIBCURL - if (this->curl) - { - CURLcode res; - chunk_t curl_response = chunk_empty; - char curl_error_buffer[CURL_ERROR_SIZE]; - - curl_easy_setopt(this->curl, CURLOPT_URL, this->uri); - curl_easy_setopt(this->curl, CURLOPT_WRITEFUNCTION, curl_write_buffer); - curl_easy_setopt(this->curl, CURLOPT_WRITEDATA, (void *)&curl_response); - curl_easy_setopt(this->curl, CURLOPT_ERRORBUFFER, &curl_error_buffer); - curl_easy_setopt(this->curl, CURLOPT_FAILONERROR, TRUE); - curl_easy_setopt(this->curl, CURLOPT_CONNECTTIMEOUT, FETCHER_TIMEOUT); - curl_easy_setopt(this->curl, CURLOPT_NOSIGNAL, TRUE); - - DBG1("sending curl request to '%s'...", this->uri); - res = curl_easy_perform(this->curl); - - if (res == CURLE_OK) - { - DBG1("received valid curl response"); - response = chunk_clone(curl_response); - } - else - { - DBG1("curl request failed: %s", curl_error_buffer); - } - curl_free(curl_response.ptr); - } -#else - DBG1("warning: libcurl fetching not compiled in"); -#endif /* LIBCURL */ - return response; -} - -/** - * Implements fetcher_t.post. - */ -static chunk_t http_post(private_fetcher_t *this, const char *request_type, chunk_t request) -{ - chunk_t response = chunk_empty; - -#ifdef LIBCURL - if (this->curl) - { - CURLcode res; - struct curl_slist *headers = NULL; - chunk_t curl_response = chunk_empty; - char curl_error_buffer[CURL_ERROR_SIZE]; - char content_type[BUF_LEN]; - - /* set content type header */ - snprintf(content_type, BUF_LEN, "Content-Type: %s", request_type); - headers = curl_slist_append(headers, content_type); - - /* set options */ - curl_easy_setopt(this->curl, CURLOPT_HTTPHEADER, headers); - curl_easy_setopt(this->curl, CURLOPT_URL, this->uri); - curl_easy_setopt(this->curl, CURLOPT_WRITEFUNCTION, curl_write_buffer); - curl_easy_setopt(this->curl, CURLOPT_WRITEDATA, (void *)&curl_response); - curl_easy_setopt(this->curl, CURLOPT_POSTFIELDS, request.ptr); - curl_easy_setopt(this->curl, CURLOPT_POSTFIELDSIZE, request.len); - curl_easy_setopt(this->curl, CURLOPT_ERRORBUFFER, &curl_error_buffer); - curl_easy_setopt(this->curl, CURLOPT_FAILONERROR, TRUE); - curl_easy_setopt(this->curl, CURLOPT_CONNECTTIMEOUT, FETCHER_TIMEOUT); - curl_easy_setopt(this->curl, CURLOPT_NOSIGNAL, TRUE); - - DBG1("sending http post request to '%s'...", this->uri); - res = curl_easy_perform(this->curl); - - if (res == CURLE_OK) - { - DBG1("received valid http response"); - response = chunk_clone(curl_response); - } - else - { - DBG1("http post request using libcurl failed: %s", curl_error_buffer); - } - curl_slist_free_all(headers); - curl_free(curl_response.ptr); - } -#else - DBG1("warning: libcurl fetching not compiled in"); -#endif /* LIBCURL */ - return response; -} - -#ifdef LIBLDAP -/** - * Parses the result returned by an ldap query - */ -static chunk_t ldap_parse(LDAP *ldap, LDAPMessage *result) -{ - chunk_t response = chunk_empty; - err_t ugh = NULL; - - LDAPMessage *entry = ldap_first_entry(ldap, result); - - if (entry != NULL) - { - BerElement *ber = NULL; - char *attr; - - attr = ldap_first_attribute(ldap, entry, &ber); - - if (attr != NULL) - { - struct berval **values = ldap_get_values_len(ldap, entry, attr); - - if (values != NULL) - { - if (values[0] != NULL) - { - response.len = values[0]->bv_len; - response.ptr = malloc(response.len); - memcpy(response.ptr, values[0]->bv_val, response.len); - - if (values[1] != NULL) - { - ugh = "more than one value was fetched - first selected"; - } - } - else - { - ugh = "no values in attribute"; - } - ldap_value_free_len(values); - } - else - { - ugh = ldap_err2string(ldap_result2error(ldap, entry, 0)); - } - ldap_memfree(attr); - } - else - { - ugh = ldap_err2string(ldap_result2error(ldap, entry, 0)); - } - ber_free(ber, 0); - } - else - { - ugh = ldap_err2string(ldap_result2error(ldap, result, 0)); - } - if (ugh) - { - DBG1("ldap request failed: %s", ugh); - } - return response; -} -#endif /* LIBLDAP */ - -/** - * Implements fetcher_t.get for curl methods - */ -static chunk_t ldap_get(private_fetcher_t *this) -{ - chunk_t response = chunk_empty; - -#ifdef LIBLDAP - if (this->ldap) - { - err_t ugh = NULL; - int rc; - int ldap_version = LDAP_VERSION3; - - struct timeval timeout; - - timeout.tv_sec = FETCHER_TIMEOUT; - timeout.tv_usec = 0; - - ldap_set_option(this->ldap, LDAP_OPT_PROTOCOL_VERSION, &ldap_version); - ldap_set_option(this->ldap, LDAP_OPT_NETWORK_TIMEOUT, &timeout); - - DBG1("sending ldap request to '%s'...", this->uri); - - rc = ldap_simple_bind_s(this->ldap, NULL, NULL); - if (rc == LDAP_SUCCESS) - { - LDAPMessage *result; - - timeout.tv_sec = FETCHER_TIMEOUT; - timeout.tv_usec = 0; - - rc = ldap_search_st(this->ldap, this->lurl->lud_dn, - this->lurl->lud_scope, - this->lurl->lud_filter, - this->lurl->lud_attrs, - 0, &timeout, &result); - - if (rc == LDAP_SUCCESS) - { - response = ldap_parse(this->ldap, result); - if (response.ptr) - { - DBG1("received valid ldap response"); - } - ldap_msgfree(result); - } - else - { - ugh = ldap_err2string(rc); - } - } - else - { - ugh = ldap_err2string(rc); - } - ldap_unbind_s(this->ldap); - - if (ugh) - { - DBG1("ldap request failed: %s", ugh); - } - } -#else /* !LIBLDAP */ - DBG1("warning: libldap fetching not compiled in"); -#endif /* !LIBLDAP */ - return response; -} - -/** - * Implements fetcher_t.destroy - */ -static void destroy(private_fetcher_t *this) -{ -#ifdef LIBCURL - if (this->curl) - { - curl_easy_cleanup(this->curl); - } -#endif /* LIBCURL */ - -#ifdef LIBLDAP - if (this->lurl) - { - ldap_free_urldesc(this->lurl); - } -#endif /* LIBLDAP */ - - free(this); -} - -/* - * Described in header. - */ -fetcher_t *fetcher_create(const char *uri) -{ - private_fetcher_t *this = malloc_thing(private_fetcher_t); - - /* initialize */ - this->uri = uri; - -#ifdef LIBCURL - this->curl = NULL; -#endif /* LIBCURL */ - -#ifdef LIBLDAP - this->lurl = NULL; - this->ldap = NULL; -#endif /* LIBLDAP */ - - if (strlen(uri) >= 4 && strncasecmp(uri, "ldap", 4) == 0) - { -#ifdef LIBLDAP - int rc = ldap_url_parse(uri, &this->lurl); - - if (rc == LDAP_SUCCESS) - { - this->ldap = ldap_init(this->lurl->lud_host, - this->lurl->lud_port); - } - else - { - DBG1("ldap: %s", ldap_err2string(rc)); - this->ldap = NULL; - } -#endif /* LIBLDAP */ - this->public.get = (chunk_t (*) (fetcher_t*))ldap_get; - } - else - { -#ifdef LIBCURL - this->curl = curl_easy_init(); - if (this->curl == NULL) - { - DBG1("curl_easy_init_failed()"); - } -#endif /* LIBCURL */ - this->public.get = (chunk_t (*) (fetcher_t*))curl_get; - } - - /* public functions */ - this->public.post = (chunk_t (*) (fetcher_t*,const char*,chunk_t))http_post; - this->public.destroy = (void (*) (fetcher_t*))destroy; - - return &this->public; -} - -/** - * Described in header. - */ -void fetcher_initialize(void) -{ -#ifdef LIBCURL - CURLcode res; - - /* initialize libcurl */ - DBG1("initializing libcurl"); - res = curl_global_init(CURL_GLOBAL_NOTHING); - if (res != CURLE_OK) - { - DBG1("libcurl could not be initialized: %s", curl_easy_strerror(res)); - } -#endif /* LIBCURL */ -} - -/** - * Described in header. - */ -void fetcher_finalize(void) -{ -#ifdef LIBCURL - /* finalize libcurl */ - DBG1("finalizing libcurl"); - curl_global_cleanup(); -#endif /* LIBCURL */ -} - diff --git a/src/libstrongswan/utils/fetcher.h b/src/libstrongswan/utils/fetcher.h deleted file mode 100644 index 47b43a0b7..000000000 --- a/src/libstrongswan/utils/fetcher.h +++ /dev/null @@ -1,95 +0,0 @@ -/** - * @file fetcher.h - * - * @brief Interface of fetcher_t. - * - */ - -/* - * Copyright (C) 2007 Andreas Steffen - * 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 . - * - * 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 FETCHER_H_ -#define FETCHER_H_ - -typedef struct fetcher_t fetcher_t; - -#include - -#define FETCHER_TIMEOUT 10 /* seconds */ - -/** - * @brief Fetches information from an URI (http, file, ftp, etc.) - * - * @ingroup utils - */ -struct fetcher_t { - - /** - * @brief Get information via a get request. - * - * @param this calling object - * @param uri uri specifying the information source - * @return chunk_t containing the information - */ - chunk_t (*get) (fetcher_t *this); - - /** - * @brief Get information via a get request. - * - * @param this calling object - * @param uri uri specifying the information source - * @param type content type of http post request - * @param request binary data for http post request - * @return chunk_t containing the information - */ - chunk_t (*post) (fetcher_t *this, const char *type, chunk_t request); - - /** - * @brief Destroys the fetcher_t object. - * - * @param this fetcher_t to destroy - */ - void (*destroy) (fetcher_t *this); - -}; - -/** - * @brief Create a fetcher_t object. - * - * @return created fetcher_t object - * - * @ingroup utils - */ -fetcher_t* fetcher_create(const char *uri); - -/** - * @brief Initializes the fetcher_t class - * - * call this function only once in the main program - * - * @ingroup utils - */ -void fetcher_initialize(void); - -/** - * @brief Finalizes the fetcher_t class - * - * call this function only once befor exiting the main program - * - * @ingroup utils - */ -void fetcher_finalize(void); - -#endif /*FETCHER_H_*/ diff --git a/src/libstrongswan/utils/host.c b/src/libstrongswan/utils/host.c index 68e9c9500..835544e4d 100644 --- a/src/libstrongswan/utils/host.c +++ b/src/libstrongswan/utils/host.c @@ -1,10 +1,3 @@ -/** - * @file host.c - * - * @brief Implementation of host_t. - * - */ - /* * Copyright (C) 2006-2007 Tobias Brunner * Copyright (C) 2006 Daniel Roethlisberger @@ -21,6 +14,8 @@ * 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. + * + * $Id$ */ #include @@ -32,7 +27,7 @@ typedef struct private_host_t private_host_t; /** - * @brief Private Data of a host object. + * Private Data of a host object. */ struct private_host_t { /** @@ -155,12 +150,27 @@ static int print(FILE *stream, const struct printf_info *info, } } + /** - * register printf() handlers + * arginfo handler for printf() hosts */ -static void __attribute__ ((constructor))print_register() +int arginfo(const struct printf_info *info, size_t n, int *argtypes) { - register_printf_function(PRINTF_HOST, print, arginfo_ptr); + if (n > 0) + { + argtypes[0] = PA_POINTER; + } + return 1; +} + +/** + * return printf hook functions for a host + */ +printf_hook_functions_t host_get_printf_hooks() +{ + printf_hook_functions_t hooks = {print, arginfo}; + + return hooks; } /** diff --git a/src/libstrongswan/utils/host.h b/src/libstrongswan/utils/host.h index ee9aa457f..fd2fe01b1 100644 --- a/src/libstrongswan/utils/host.h +++ b/src/libstrongswan/utils/host.h @@ -1,14 +1,7 @@ -/** - * @file host.h - * - * @brief Interface of host_t. - * - */ - /* + * Copyright (C) 2005-2008 Martin Willi * Copyright (C) 2006-2007 Tobias Brunner * Copyright (C) 2006 Daniel Roethlisberger - * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil * @@ -23,6 +16,11 @@ * for more details. */ +/** + * @defgroup host host + * @{ @ingroup utils + */ + #ifndef HOST_H_ #define HOST_H_ @@ -49,42 +47,31 @@ enum host_diff_t { }; /** - * @brief Representates a Host + * Representates a Host * * Host object, identifies a address:port pair and defines some * useful functions on it. - * - * @b Constructors: - * - host_create() - * - host_create_from_chunk() - * - host_create_from_sockaddr() - * - * @todo Add IPv6 support - * - * @ingroup utils */ struct host_t { /** - * @brief Build a clone of this host object. + * Build a clone of this host object. * - * @param this object to clone - * @return cloned host + * @return cloned host */ host_t *(*clone) (host_t *this); /** - * @brief Get a pointer to the internal sockaddr struct. + * Get a pointer to the internal sockaddr struct. * * This is used for sending and receiving via sockets. * - * @param this object to clone - * @return pointer to the internal sockaddr structure + * @return pointer to the internal sockaddr structure */ sockaddr_t *(*get_sockaddr) (host_t *this); /** - * @brief Get the length of the sockaddr struct. + * Get the length of the sockaddr struct. * * Depending on the family, the length of the sockaddr struct * is different. Use this function to get the length of the sockaddr @@ -92,140 +79,119 @@ struct host_t { * * This is used for sending and receiving via sockets. * - * @param this object to clone - * @return length of the sockaddr struct + * @return length of the sockaddr struct */ socklen_t *(*get_sockaddr_len) (host_t *this); /** - * @brief Gets the family of the address + * Gets the family of the address * - * @param this calling object - * @return family + * @return family */ int (*get_family) (host_t *this); /** - * @brief Checks if the ip address of host is set to default route. + * Checks if the ip address of host is set to default route. * - * @param this calling object - * @return - * - TRUE if host has IP 0.0.0.0 for default route - * - FALSE otherwise + * @return TRUE if host is 0.0.0.0 or 0::0, FALSE otherwise */ bool (*is_anyaddr) (host_t *this); /** - * @brief get the address of this host as chunk_t + * Get the address of this host as chunk_t * * Returned chunk points to internal data. * - * @param this object - * @return address string, + * @return address string, */ chunk_t (*get_address) (host_t *this); /** - * @brief get the port of this host + * Get the port of this host * - * @param this object to clone - * @return port number + * @return port number */ u_int16_t (*get_port) (host_t *this); /** - * @brief set the port of this host + * Set the port of this host * - * @param this object to clone - * @param port port numer + * @param port port numer */ void (*set_port) (host_t *this, u_int16_t port); /** - * @brief Compare the ips of two hosts hosts. + * Compare the ips of two hosts hosts. * - * @param this object to compare - * @param other the other to compare - * @return TRUE if addresses are equal. + * @param other the other to compare + * @return TRUE if addresses are equal. */ bool (*ip_equals) (host_t *this, host_t *other); /** - * @brief Compare two hosts, with port. + * Compare two hosts, with port. * - * @param this object to compare - * @param other the other to compare - * @return TRUE if addresses and ports are equal. + * @param other the other to compare + * @return TRUE if addresses and ports are equal. */ bool (*equals) (host_t *this, host_t *other); /** - * @brief Compare two hosts and return the differences. + * Compare two hosts and return the differences. * - * @param this object to compare - * @param other the other to compare - * @return differences in a combination of host_diff_t's + * @param other the other to compare + * @return differences in a combination of host_diff_t's */ host_diff_t (*get_differences) (host_t *this, host_t *other); /** - * @brief Destroy this host object - * - * @param this calling - * @return SUCCESS in any case + * Destroy this host object. */ void (*destroy) (host_t *this); }; /** - * @brief Constructor to create a host_t object from an address string. + * Constructor to create a host_t object from an address string. * * @param string string of an address, such as "152.96.193.130" * @param port port number - * @return - * - host_t object - * - NULL, if string not an address. - * - * @ingroup network + * @return host_t, NULL if string not an address. */ host_t *host_create_from_string(char *string, u_int16_t port); /** - * @brief Constructor to create a host_t object from an address chunk + * Constructor to create a host_t object from an address chunk * - * @param family Address family to use for this object, such as AF_INET or AF_INET6 - * @param address address as 4 byte chunk_t in networ order + * @param family Address family, such as AF_INET or AF_INET6 + * @param address address as chunk_t in networ order * @param port port number - * @return - * - host_t object - * - NULL, if family not supported or chunk_t length not 4 bytes. - * - * @ingroup network + * @return host_t, NULL if family not supported/chunk invalid */ host_t *host_create_from_chunk(int family, chunk_t address, u_int16_t port); /** - * @brief Constructor to create a host_t object from a sockaddr struct + * Constructor to create a host_t object from a sockaddr struct * * @param sockaddr sockaddr struct which contains family, address and port - * @return - * - host_t object - * - NULL, if family not supported. - * - * @ingroup network + * @return host_t, NULL if family not supported */ host_t *host_create_from_sockaddr(sockaddr_t *sockaddr); /** - * @brief Create a host without an address, a "any" host. + * Create a host without an address, a "any" host. * * @param family family of the any host - * @return - * - host_t object - * - NULL, if family not supported. - * - * @ingroup network + * @return host_t, NULL if family not supported */ host_t *host_create_any(int family); -#endif /*HOST_H_*/ +/** + * Get printf hooks for a host. + * + * Arguments are: + * host_t *host + * Use #-modifier to include port number + */ +printf_hook_functions_t host_get_printf_hooks(); + +#endif /* HOST_H_ @}*/ diff --git a/src/libstrongswan/utils/identification.c b/src/libstrongswan/utils/identification.c index 6d969ed16..948472cc8 100644 --- a/src/libstrongswan/utils/identification.c +++ b/src/libstrongswan/utils/identification.c @@ -1,12 +1,5 @@ -/** - * @file identification.c - * - * @brief Implementation of identification_t. - * - */ - /* - * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005-2008 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil * @@ -20,7 +13,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id$ + * $Id$ */ #define _GNU_SOURCE @@ -36,6 +29,14 @@ #include +ENUM_BEGIN(id_match_names, ID_MATCH_NONE, ID_MATCH_MAX_WILDCARDS, + "MATCH_NONE", + "MATCH_ANY", + "MATCH_MAX_WILDCARDS"); +ENUM_NEXT(id_match_names, ID_MATCH_PERFECT, ID_MATCH_PERFECT, ID_MATCH_MAX_WILDCARDS, + "MATCH_PERFECT"); +ENUM_END(id_match_names, ID_MATCH_PERFECT); + ENUM_BEGIN(id_type_names, ID_ANY, ID_KEY_ID, "ID_ANY", "ID_IPV4_ADDR", @@ -49,10 +50,11 @@ ENUM_BEGIN(id_type_names, ID_ANY, ID_KEY_ID, "ID_DER_ASN1_DN", "ID_DER_ASN1_GN", "ID_KEY_ID"); -ENUM_NEXT(id_type_names, ID_DER_ASN1_GN_URI, ID_DER_ASN1_GN_URI, ID_KEY_ID, - "ID_DER_ASN1_GN_URI"); -ENUM_END(id_type_names, ID_DER_ASN1_GN_URI); - +ENUM_NEXT(id_type_names, ID_DER_ASN1_GN_URI, ID_PUBKEY_SHA1, ID_KEY_ID, + "ID_DER_ASN1_GN_URI", + "ID_PUBKEY_INFO_SHA1", + "ID_PUBKEY_SHA1"); +ENUM_END(id_type_names, ID_PUBKEY_SHA1); /** * X.501 acronyms for well known object identifiers (OIDs) @@ -237,7 +239,7 @@ static chunk_t sanitize_chunk(chunk_t chunk) /** * Pointer is set to the first RDN in a DN */ -static status_t init_rdn(chunk_t dn, chunk_t *rdn, chunk_t *attribute, bool *next) +static bool init_rdn(chunk_t dn, chunk_t *rdn, chunk_t *attribute, bool *next) { *rdn = chunk_empty; *attribute = chunk_empty; @@ -246,7 +248,7 @@ static status_t init_rdn(chunk_t dn, chunk_t *rdn, chunk_t *attribute, bool *nex if (*dn.ptr != ASN1_SEQUENCE) { /* DN is not a SEQUENCE */ - return FAILED; + return FALSE; } rdn->len = asn1_length(&dn); @@ -254,7 +256,7 @@ static status_t init_rdn(chunk_t dn, chunk_t *rdn, chunk_t *attribute, bool *nex if (rdn->len == ASN1_INVALID_LENGTH) { /* Invalid RDN length */ - return FAILED; + return FALSE; } rdn->ptr = dn.ptr; @@ -262,13 +264,13 @@ static status_t init_rdn(chunk_t dn, chunk_t *rdn, chunk_t *attribute, bool *nex /* are there any RDNs ? */ *next = rdn->len > 0; - return SUCCESS; + return TRUE; } /** * Fetches the next RDN in a DN */ -static status_t get_next_rdn(chunk_t *rdn, chunk_t * attribute, chunk_t *oid, chunk_t *value, asn1_t *type, bool *next) +static bool get_next_rdn(chunk_t *rdn, chunk_t * attribute, chunk_t *oid, chunk_t *value, asn1_t *type, bool *next) { chunk_t body; @@ -283,13 +285,13 @@ static status_t get_next_rdn(chunk_t *rdn, chunk_t * attribute, chunk_t *oid, ch if (*rdn->ptr != ASN1_SET) { /* RDN is not a SET */ - return FAILED; + return FALSE; } attribute->len = asn1_length(rdn); if (attribute->len == ASN1_INVALID_LENGTH) { /* Invalid attribute length */ - return FAILED; + return FALSE; } attribute->ptr = rdn->ptr; /* advance to start of next RDN */ @@ -301,7 +303,7 @@ static status_t get_next_rdn(chunk_t *rdn, chunk_t * attribute, chunk_t *oid, ch if (*attribute->ptr != ASN1_SEQUENCE) { /* attributeTypeAndValue is not a SEQUENCE */ - return FAILED; + return FALSE; } /* extract the attribute body */ @@ -310,7 +312,7 @@ static status_t get_next_rdn(chunk_t *rdn, chunk_t * attribute, chunk_t *oid, ch if (body.len == ASN1_INVALID_LENGTH) { /* Invalid attribute body length */ - return FAILED; + return FALSE; } body.ptr = attribute->ptr; @@ -323,7 +325,7 @@ static status_t get_next_rdn(chunk_t *rdn, chunk_t * attribute, chunk_t *oid, ch if (*body.ptr != ASN1_OID) { /* attributeType is not an OID */ - return FAILED; + return FALSE; } /* extract OID */ oid->len = asn1_length(&body); @@ -331,7 +333,7 @@ static status_t get_next_rdn(chunk_t *rdn, chunk_t * attribute, chunk_t *oid, ch if (oid->len == ASN1_INVALID_LENGTH) { /* Invalid attribute OID length */ - return FAILED; + return FALSE; } oid->ptr = body.ptr; @@ -348,19 +350,19 @@ static status_t get_next_rdn(chunk_t *rdn, chunk_t * attribute, chunk_t *oid, ch if (value->len == ASN1_INVALID_LENGTH) { /* Invalid attribute string length */ - return FAILED; + return FALSE; } value->ptr = body.ptr; /* are there any RDNs left? */ *next = rdn->len > 0 || attribute->len > 0; - return SUCCESS; + return TRUE; } /** * Parses an ASN.1 distinguished name int its OID/value pairs */ -static status_t dntoa(chunk_t dn, chunk_t *str) +static bool dntoa(chunk_t dn, chunk_t *str) { chunk_t rdn, oid, attribute, value, proper; asn1_t type; @@ -368,17 +370,17 @@ static status_t dntoa(chunk_t dn, chunk_t *str) bool next; bool first = TRUE; - status_t status = init_rdn(dn, &rdn, &attribute, &next); - - if (status != SUCCESS) - return status; + if (!init_rdn(dn, &rdn, &attribute, &next)) + { + return FALSE; + } while (next) { - status = get_next_rdn(&rdn, &attribute, &oid, &value, &type, &next); - - if (status != SUCCESS) - return status; + if (!get_next_rdn(&rdn, &attribute, &oid, &value, &type, &next)) + { + return FALSE; + } if (first) { /* first OID/value pair */ @@ -404,7 +406,7 @@ static status_t dntoa(chunk_t dn, chunk_t *str) update_chunk(str, snprintf(str->ptr,str->len,"=%.*s", (int)proper.len, proper.ptr)); chunk_free(&proper); } - return SUCCESS; + return TRUE; } /** @@ -420,15 +422,17 @@ static bool same_dn(chunk_t a, chunk_t b) /* same lengths for the DNs */ if (a.len != b.len) + { return FALSE; - + } /* try a binary comparison first */ if (memeq(a.ptr, b.ptr, b.len)) + { return TRUE; - + } /* initialize DN parsing */ - if (init_rdn(a, &rdn_a, &attribute_a, &next_a) != SUCCESS - || init_rdn(b, &rdn_b, &attribute_b, &next_b) != SUCCESS) + if (!init_rdn(a, &rdn_a, &attribute_a, &next_a) || + !init_rdn(b, &rdn_b, &attribute_b, &next_b)) { return FALSE; } @@ -437,23 +441,27 @@ static bool same_dn(chunk_t a, chunk_t b) while (next_a && next_b) { /* parse next RDNs and check for errors */ - if (get_next_rdn(&rdn_a, &attribute_a, &oid_a, &value_a, &type_a, &next_a) != SUCCESS - || get_next_rdn(&rdn_b, &attribute_b, &oid_b, &value_b, &type_b, &next_b) != SUCCESS) + if (!get_next_rdn(&rdn_a, &attribute_a, &oid_a, &value_a, &type_a, &next_a) || + !get_next_rdn(&rdn_b, &attribute_b, &oid_b, &value_b, &type_b, &next_b)) { return FALSE; } /* OIDs must agree */ - if (oid_a.len != oid_b.len || memcmp(oid_a.ptr, oid_b.ptr, oid_b.len) != 0) + if (oid_a.len != oid_b.len || !memeq(oid_a.ptr, oid_b.ptr, oid_b.len)) + { return FALSE; + } /* same lengths for values */ if (value_a.len != value_b.len) + { return FALSE; + } /* printableStrings and email RDNs require uppercase comparison */ - if (type_a == type_b && (type_a == ASN1_PRINTABLESTRING - || (type_a == ASN1_IA5STRING && known_oid(oid_a) == OID_PKCS9_EMAIL))) + if (type_a == type_b && (type_a == ASN1_PRINTABLESTRING || + (type_a == ASN1_IA5STRING && known_oid(oid_a) == OID_PKCS9_EMAIL))) { if (strncasecmp(value_a.ptr, value_b.ptr, value_b.len) != 0) { @@ -470,8 +478,9 @@ static bool same_dn(chunk_t a, chunk_t b) } /* both DNs must have same number of RDNs */ if (next_a || next_b) + { return FALSE; - + } /* the two DNs are equal! */ return TRUE; } @@ -490,14 +499,11 @@ bool match_dn(chunk_t a, chunk_t b, int *wildcards) bool next_a, next_b; /* initialize wildcard counter */ - if (wildcards) - { - *wildcards = 0; - } + *wildcards = 0; /* initialize DN parsing */ - if (init_rdn(a, &rdn_a, &attribute_a, &next_a) != SUCCESS - || init_rdn(b, &rdn_b, &attribute_b, &next_b) != SUCCESS) + if (!init_rdn(a, &rdn_a, &attribute_a, &next_a) || + !init_rdn(b, &rdn_b, &attribute_b, &next_b)) { return FALSE; } @@ -506,31 +512,32 @@ bool match_dn(chunk_t a, chunk_t b, int *wildcards) while (next_a && next_b) { /* parse next RDNs and check for errors */ - if (get_next_rdn(&rdn_a, &attribute_a, &oid_a, &value_a, &type_a, &next_a) != SUCCESS - || get_next_rdn(&rdn_b, &attribute_b, &oid_b, &value_b, &type_b, &next_b) != SUCCESS) + if (!get_next_rdn(&rdn_a, &attribute_a, &oid_a, &value_a, &type_a, &next_a) || + !get_next_rdn(&rdn_b, &attribute_b, &oid_b, &value_b, &type_b, &next_b)) { return FALSE; } /* OIDs must agree */ if (oid_a.len != oid_b.len || memcmp(oid_a.ptr, oid_b.ptr, oid_b.len) != 0) + { return FALSE; + } /* does rdn_b contain a wildcard? */ if (value_b.len == 1 && *value_b.ptr == '*') { - if (wildcards) - { - (*wildcards)++; - } + (*wildcards)++; continue; } /* same lengths for values */ if (value_a.len != value_b.len) + { return FALSE; + } /* printableStrings and email RDNs require uppercase comparison */ - if (type_a == type_b && (type_a == ASN1_PRINTABLESTRING - || (type_a == ASN1_IA5STRING && known_oid(oid_a) == OID_PKCS9_EMAIL))) + if (type_a == type_b && (type_a == ASN1_PRINTABLESTRING || + (type_a == ASN1_IA5STRING && known_oid(oid_a) == OID_PKCS9_EMAIL))) { if (strncasecmp(value_a.ptr, value_b.ptr, value_b.len) != 0) { @@ -550,12 +557,8 @@ bool match_dn(chunk_t a, chunk_t b, int *wildcards) { return FALSE; } - /* the two DNs match! */ - if (wildcards) - { - *wildcards = min(*wildcards, MAX_WILDCARDS); - } + *wildcards = min(*wildcards, ID_MATCH_ONE_WILDCARD - ID_MATCH_MAX_WILDCARDS); return TRUE; } @@ -776,120 +779,107 @@ static bool equals_strcasecmp(private_identification_t *this, /** * Default implementation of identification_t.matches. */ -static bool matches_binary(private_identification_t *this, - private_identification_t *other, int *wildcards) +static id_match_t matches_binary(private_identification_t *this, + private_identification_t *other) { if (other->type == ID_ANY) { - if (wildcards) - { - *wildcards = MAX_WILDCARDS; - } - return TRUE; + return ID_MATCH_ANY; } - if (wildcards) + if (this->type == other->type && + chunk_equals(this->encoded, other->encoded)) { - *wildcards = 0; + return ID_MATCH_PERFECT; } - return this->type == other->type && - chunk_equals(this->encoded, other->encoded); + return ID_MATCH_NONE; } /** * Special implementation of identification_t.matches for ID_RFC822_ADDR/ID_FQDN. * Checks for a wildcard in other-string, and compares it against this-string. */ -static bool matches_string(private_identification_t *this, - private_identification_t *other, int *wildcards) +static id_match_t matches_string(private_identification_t *this, + private_identification_t *other) { u_int len = other->encoded.len; if (other->type == ID_ANY) { - if (wildcards) - { - *wildcards = MAX_WILDCARDS; - } - return TRUE; + return ID_MATCH_ANY; } - if (this->type != other->type) - return FALSE; - + { + return ID_MATCH_NONE; + } /* try a binary comparison first */ if (equals_binary(this, other)) { - if (wildcards) - { - *wildcards = 0; - } - return TRUE; + return ID_MATCH_PERFECT; } - if (len == 0 || this->encoded.len < len) - return FALSE; + { + return ID_MATCH_NONE; + } /* check for single wildcard at the head of the string */ if (*other->encoded.ptr == '*') { - if (wildcards) - { - *wildcards = 1; - } - /* single asterisk matches any string */ if (len-- == 1) - return TRUE; - - if (memeq(this->encoded.ptr + this->encoded.len - len, other->encoded.ptr + 1, len)) - return TRUE; + { /* not better than ID_ANY */ + return ID_MATCH_ANY; + } + if (memeq(this->encoded.ptr + this->encoded.len - len, + other->encoded.ptr + 1, len)) + { + return ID_MATCH_ONE_WILDCARD; + } } - - return FALSE; + return ID_MATCH_NONE; } /** * Special implementation of identification_t.matches for ID_ANY. * ANY matches only another ANY, but nothing other */ -static bool matches_any(private_identification_t *this, - private_identification_t *other, int *wildcards) +static id_match_t matches_any(private_identification_t *this, + private_identification_t *other) { - if (wildcards) + if (other->type == ID_ANY) { - *wildcards = 0; + return ID_MATCH_ANY; } - return other->type == ID_ANY; + return ID_MATCH_NONE; } /** - * Special implementation of identification_t.matches for ID_DER_ASN1_DN. - * ANY matches any, even ANY, thats why its there... + * Special implementation of identification_t.matches for ID_DER_ASN1_DN */ -static bool matches_dn(private_identification_t *this, - private_identification_t *other, int *wildcards) +static id_match_t matches_dn(private_identification_t *this, + private_identification_t *other) { + int wc; + if (other->type == ID_ANY) { - if (wildcards) - { - *wildcards = MAX_WILDCARDS; - } - return TRUE; + return ID_MATCH_ANY; } if (this->type == other->type) { - return match_dn(this->encoded, other->encoded, wildcards); + if (match_dn(this->encoded, other->encoded, &wc)) + { + return ID_MATCH_PERFECT - wc; + } } - return FALSE; + return ID_MATCH_NONE; } /** * output handler in printf() */ static int print(FILE *stream, const struct printf_info *info, - const void *const *args) + const void *const *args) { private_identification_t *this = *((private_identification_t**)(args[0])); char buf[BUF_LEN]; @@ -944,12 +934,14 @@ static int print(FILE *stream, const struct printf_info *info, snprintf(buf, sizeof(buf), "%.*s", this->encoded.len, this->encoded.ptr); /* TODO: whats returned on failure?*/ dntoa(this->encoded, &buf_chunk); - return fprintf(stream, "%s", buf); + return fprintf(stream, "\"%s\"", buf); } case ID_DER_ASN1_GN: return fprintf(stream, "(ASN.1 general Name"); case ID_KEY_ID: - return fprintf(stream, "(KEY_ID)"); + case ID_PUBKEY_INFO_SHA1: + case ID_PUBKEY_SHA1: + return fprintf(stream, "%#B", &this->encoded); case ID_DER_ASN1_GN_URI: { proper = sanitize_chunk(this->encoded); @@ -963,11 +955,25 @@ static int print(FILE *stream, const struct printf_info *info, } /** - * register printf() handlers + * arginfo handler + */ +static int arginfo(const struct printf_info *info, size_t n, int *argtypes) +{ + if (n > 0) + { + argtypes[0] = PA_POINTER; + } + return 1; +} + +/** + * Get printf hook functions */ -static void __attribute__ ((constructor))print_register() +printf_hook_functions_t identification_get_printf_hooks() { - register_printf_function(PRINTF_IDENTIFICATION, print, arginfo_ptr); + printf_hook_functions_t hook = {print, arginfo}; + + return hook; } /** @@ -1011,7 +1017,7 @@ static private_identification_t *identification_create(void) this->public.destroy = (void (*) (identification_t*))destroy; /* we use these as defaults, the may be overloaded for special ID types */ this->public.equals = (bool (*) (identification_t*,identification_t*))equals_binary; - this->public.matches = (bool (*) (identification_t*,identification_t*,int*))matches_binary; + this->public.matches = (id_match_t (*) (identification_t*,identification_t*))matches_binary; this->encoded = chunk_empty; @@ -1041,7 +1047,7 @@ identification_t *identification_create_from_string(char *string) } this->type = ID_DER_ASN1_DN; this->public.equals = (bool (*) (identification_t*,identification_t*))equals_dn; - this->public.matches = (bool (*) (identification_t*,identification_t*,int*))matches_dn; + this->public.matches = (id_match_t (*) (identification_t*,identification_t*))matches_dn; return &this->public; } else if (strchr(string, '@') == NULL) @@ -1054,8 +1060,8 @@ identification_t *identification_create_from_string(char *string) { /* any ID will be accepted */ this->type = ID_ANY; - this->public.matches = (bool (*) - (identification_t*,identification_t*,int*))matches_any; + this->public.matches = (id_match_t (*) + (identification_t*,identification_t*))matches_any; return &this->public; } else @@ -1072,8 +1078,8 @@ identification_t *identification_create_from_string(char *string) this->type = ID_FQDN; this->encoded.ptr = strdup(string); this->encoded.len = strlen(string); - this->public.matches = (bool (*) - (identification_t*,identification_t*,int*))matches_string; + this->public.matches = (id_match_t (*) + (identification_t*,identification_t*))matches_string; this->public.equals = (bool (*) (identification_t*,identification_t*))equals_strcasecmp; return &(this->public); @@ -1114,8 +1120,8 @@ identification_t *identification_create_from_string(char *string) this->type = ID_FQDN; this->encoded.ptr = strdup(string + 1); this->encoded.len = strlen(string + 1); - this->public.matches = (bool (*) - (identification_t*,identification_t*,int*))matches_string; + this->public.matches = (id_match_t (*) + (identification_t*,identification_t*))matches_string; this->public.equals = (bool (*) (identification_t*,identification_t*))equals_strcasecmp; return &(this->public); @@ -1126,8 +1132,8 @@ identification_t *identification_create_from_string(char *string) this->type = ID_RFC822_ADDR; this->encoded.ptr = strdup(string); this->encoded.len = strlen(string); - this->public.matches = (bool (*) - (identification_t*,identification_t*,int*))matches_string; + this->public.matches = (id_match_t (*) + (identification_t*,identification_t*))matches_string; this->public.equals = (bool (*) (identification_t*,identification_t*))equals_strcasecmp; return &(this->public); @@ -1146,27 +1152,29 @@ identification_t *identification_create_from_encoding(id_type_t type, chunk_t en switch (type) { case ID_ANY: - this->public.matches = (bool (*) - (identification_t*,identification_t*,int*))matches_any; + this->public.matches = (id_match_t (*) + (identification_t*,identification_t*))matches_any; break; case ID_FQDN: case ID_RFC822_ADDR: - this->public.matches = (bool (*) - (identification_t*,identification_t*,int*))matches_string; + this->public.matches = (id_match_t (*) + (identification_t*,identification_t*))matches_string; this->public.equals = (bool (*) (identification_t*,identification_t*))equals_strcasecmp; break; case ID_DER_ASN1_DN: this->public.equals = (bool (*) (identification_t*,identification_t*))equals_dn; - this->public.matches = (bool (*) - (identification_t*,identification_t*,int*))matches_dn; + this->public.matches = (id_match_t (*) + (identification_t*,identification_t*))matches_dn; break; case ID_IPV4_ADDR: case ID_IPV6_ADDR: case ID_DER_ASN1_GN: case ID_KEY_ID: case ID_DER_ASN1_GN_URI: + case ID_PUBKEY_INFO_SHA1: + case ID_PUBKEY_SHA1: default: break; } diff --git a/src/libstrongswan/utils/identification.h b/src/libstrongswan/utils/identification.h index 59c568eaf..31c49c269 100644 --- a/src/libstrongswan/utils/identification.h +++ b/src/libstrongswan/utils/identification.h @@ -1,10 +1,3 @@ -/** - * @file identification.h - * - * @brief Interface of identification_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup identification identification + * @{ @ingroup utils */ @@ -27,15 +27,33 @@ typedef enum id_type_t id_type_t; typedef struct identification_t identification_t; +typedef enum id_match_t id_match_t; #include -#define MAX_WILDCARDS 14 +/** + * Matches returned from identification_t.match + */ +enum id_match_t { + /* no match */ + ID_MATCH_NONE = 0, + /* match to %any ID */ + ID_MATCH_ANY = 1, + /* match with maximum allowed wildcards */ + ID_MATCH_MAX_WILDCARDS = 2, + /* match with only one wildcard */ + ID_MATCH_ONE_WILDCARD = 19, + /* perfect match, won't get better */ + ID_MATCH_PERFECT = 20, +}; /** - * @brief ID Types in a ID payload. - * - * @ingroup utils + * enum names for id_match_t. + */ +extern enum_name_t *id_match_names; + +/** + * ID Types in a ID payload. */ enum id_type_t { @@ -109,7 +127,16 @@ enum id_type_t { * private type which represents a GeneralName of type URI */ ID_DER_ASN1_GN_URI = 201, - + + /** + * SHA1 hash over PKCS#1 subjectPublicKeyInfo + */ + ID_PUBKEY_INFO_SHA1, + + /** + * SHA1 hash over PKCS#1 subjectPublicKey + */ + ID_PUBKEY_SHA1, }; /** @@ -118,110 +145,84 @@ enum id_type_t { extern enum_name_t *id_type_names; /** - * @brief Generic identification, such as used in ID payload. - * - * The following types are possible: - * - ID_IPV4_ADDR - * - ID_FQDN - * - ID_RFC822_ADDR - * - ID_IPV6_ADDR - * - ID_DER_ASN1_DN - * - ID_DER_ASN1_GN - * - ID_KEY_ID - * - ID_DER_ASN1_GN_URI - * - * @b Constructors: - * - identification_create_from_string() - * - identification_create_from_encoding() + * Generic identification, such as used in ID payload. * * @todo Support for ID_DER_ASN1_GN is minimal right now. Comparison * between them and ID_IPV4_ADDR/RFC822_ADDR would be nice. - * - * @ingroup utils */ struct identification_t { /** - * @brief Get the encoding of this id, to send over + * Get the encoding of this id, to send over * the network. * - * @warning Result points to internal data, do NOT free! + * Result points to internal data, do not free. * - * @param this the identification_t object * @return a chunk containing the encoded bytes */ chunk_t (*get_encoding) (identification_t *this); /** - * @brief Get the type of this identification. + * Get the type of this identification. * - * @param this the identification_t object * @return id_type_t */ id_type_t (*get_type) (identification_t *this); /** - * @brief Check if two identification_t objects are equal. + * Check if two identification_t objects are equal. * - * @param this the identification_t object * @param other other identification_t object * @return TRUE if the IDs are equal */ bool (*equals) (identification_t *this, identification_t *other); /** - * @brief Check if an ID matches a wildcard ID. + * Check if an ID matches a wildcard ID. * * An identification_t may contain wildcards, such as * *@strongswan.org. This call checks if a given ID * (e.g. tester@strongswan.org) belongs to a such wildcard - * ID. Returns TRUE if + * ID. Returns > 0 if * - IDs are identical * - other is of type ID_ANY * - other contains a wildcard and matches this + * + * The larger the return value is, the better is the match. Zero means + * no match at all, 1 means a bad match, and 2 a slightly better match. * - * @param this the ID without wildcard - * @param other the ID containing a wildcard + * @param other the ID containing one or more wildcards * @param wildcards returns the number of wildcards, may be NULL - * @return TRUE if match is found + * @return match value as described above */ - bool (*matches) (identification_t *this, identification_t *other, int *wildcards); + id_match_t (*matches) (identification_t *this, identification_t *other); /** - * @brief Check if an ID is a wildcard ID. + * Check if an ID is a wildcard ID. * * If the ID represents multiple IDs (with wildcards, or * as the type ID_ANY), TRUE is returned. If it is unique, * FALSE is returned. * - * @param this identification_t object * @return TRUE if ID contains wildcards */ bool (*contains_wildcards) (identification_t *this); /** - * @brief Clone a identification_t instance. + * Clone a identification_t instance. * - * @param this the identification_t object to clone * @return clone of this */ identification_t *(*clone) (identification_t *this); /** - * @brief Destroys a identification_t object. - * - * @param this identification_t object + * Destroys a identification_t object. */ void (*destroy) (identification_t *this); }; /** - * @brief Creates an identification_t object from a string. - * - * @param string input string, which will be converted - * @return - * - created identification_t object, or - * - NULL if unsupported string supplied. + * Creates an identification_t object from a string. * * The input string may be e.g. one of the following: * - ID_IPV4_ADDR: 192.168.0.1 @@ -239,23 +240,29 @@ struct identification_t { * ND, UID, DC, CN, S, SN, serialNumber, C, L, ST, O, OU, T, D, * N, G, I, ID, EN, EmployeeNumber, E, Email, emailAddress, UN, * unstructuredName, TCGID. - * - * @ingroup utils + * + * @param string input string, which will be converted + * @return created identification_t, NULL if not supported. */ identification_t * identification_create_from_string(char *string); /** - * @brief Creates an identification_t object from an encoded chunk. - * - * @param type type of this id, such as ID_IPV4_ADDR - * @param encoded encoded bytes, such as from identification_t.get_encoding - * @return identification_t object + * Creates an identification_t object from an encoded chunk. * * In contrast to identification_create_from_string(), this constructor never * returns NULL, even when the conversion to a string representation fails. - * - * @ingroup utils + * + * @param type type of this id, such as ID_IPV4_ADDR + * @param encoded encoded bytes, such as from identification_t.get_encoding + * @return identification_t */ identification_t * identification_create_from_encoding(id_type_t type, chunk_t encoded); -#endif /* IDENTIFICATION_H_ */ +/** + * Get the printf hook functions. + * + * @return printf hook functions + */ +printf_hook_functions_t identification_get_printf_hooks(); + +#endif /* IDENTIFICATION_H_ @} */ diff --git a/src/libstrongswan/utils/iterator.h b/src/libstrongswan/utils/iterator.h index b4ff85bfb..4b845d740 100644 --- a/src/libstrongswan/utils/iterator.h +++ b/src/libstrongswan/utils/iterator.h @@ -1,10 +1,3 @@ -/** - * @file iterator.h - * - * @brief Interface iterator_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup iterator iterator + * @{ @ingroup utils */ #ifndef ITERATOR_H_ @@ -29,13 +29,11 @@ typedef enum hook_result_t hook_result_t; /** - * @brief Return value of an iterator hook. + * Return value of an iterator hook. * * Returning HOOK_AGAIN is useful to "inject" additional elements in an * iteration, HOOK_NEXT is the normal iterator behavior, and HOOK_SKIP may * be used to filter elements out. - * - * @ingroup utils */ enum hook_result_t { @@ -56,14 +54,12 @@ enum hook_result_t { }; /** - * @brief Iterator hook function prototype. + * Iterator hook function prototype. * * @param param user supplied parameter * @param in the value the hook receives from the iterator * @param out the value supplied as a result to the iterator * @return a hook_result_t - * - * @ingroup utils */ typedef hook_result_t (iterator_hook_t)(void *param, void *in, void **out); @@ -71,44 +67,34 @@ typedef hook_result_t (iterator_hook_t)(void *param, void *in, void **out); typedef struct iterator_t iterator_t; /** - * @brief Iterator interface, allows iteration over collections. + * Iterator interface, allows iteration over collections. * * iterator_t defines an interface for iterating over collections. * It allows searching, deleting, updating and inserting. * - * @b Constructors: - * - via linked_list_t.create_iterator, or - * - any other class which supports the iterator_t interface - * - * @see linked_list_t - * - * @ingroup utils + * @deprecated Use enumerator instead. */ struct iterator_t { /** - * @brief Return number of list items. + * Return number of list items. * - * @param this calling object * @return number of list items */ int (*get_count) (iterator_t *this); /** - * @brief Iterate over all items. + * Iterate over all items. * * The easy way to iterate over items. * - * @param this calling object - * @param[out] value item - * @return - * - TRUE, if there was an element available, - * - FALSE otherwise + * @param value item + * @return TRUE, if there was an element available, FALSE otherwise */ bool (*iterate) (iterator_t *this, void** value); /** - * @brief Hook a function into the iterator. + * Hook a function into the iterator. * * Sometimes it is useful to hook in an iterator. The hook function is * called before any successful return of iterate(). It takes the @@ -119,80 +105,67 @@ struct iterator_t { * If an iterator is hooked, only the iterate() method is valid, * all other methods behave undefined. * - * @param this calling object - * @param hook iterator hook which manipulates the iterated value - * @param param user supplied parameter to pass back to the hook + * @param hook iterator hook which manipulates the iterated value + * @param param user supplied parameter to pass back to the hook */ void (*set_iterator_hook) (iterator_t *this, iterator_hook_t *hook, void *param); /** - * @brief Inserts a new item before the given iterator position. + * Inserts a new item before the given iterator position. * * The iterator position is not changed after inserting * - * @param this calling iterator - * @param[in] item value to insert in list + * @param item value to insert in list */ void (*insert_before) (iterator_t *this, void *item); /** - * @brief Inserts a new item after the given iterator position. + * Inserts a new item after the given iterator position. * * The iterator position is not changed after inserting. * - * @param this calling iterator - * @param[in] item value to insert in list + * @param this calling iterator + * @param item value to insert in list */ void (*insert_after) (iterator_t *this, void *item); /** - * @brief Replace the current item at current iterator position. + * Replace the current item at current iterator position. * * The iterator position is not changed after replacing. * - * @param this calling iterator - * @param[out] old_item old value will be written here(can be NULL) - * @param[in] new_item new value - * - * @return - * - SUCCESS - * - FAILED if iterator is on an invalid position + * @param this calling iterator + * @param old old value will be written here(can be NULL) + * @param new new value + * @return SUCCESS, FAILED if iterator is on an invalid position */ - status_t (*replace) (iterator_t *this, void **old_item, void *new_item); + status_t (*replace) (iterator_t *this, void **old, void *new); /** - * @brief Removes an element from list at the given iterator position. + * Removes an element from list at the given iterator position. * * The iterator is set the the following position: * - to the item before, if available * - it gets reseted, otherwise * - * @param this calling object - * @return - * - SUCCESS - * - FAILED if iterator is on an invalid position + * @return SUCCESS, FAILED if iterator is on an invalid position */ status_t (*remove) (iterator_t *this); /** - * @brief Resets the iterator position. + * Resets the iterator position. * * After reset, the iterator_t objects doesn't point to an element. * A call to iterator_t.has_next is necessary to do any other operations * with the resetted iterator. - * - * @param this calling object */ void (*reset) (iterator_t *this); /** - * @brief Destroys an iterator. - * - * @param this iterator to destroy - * + * Destroys an iterator. */ void (*destroy) (iterator_t *this); }; -#endif /*ITERATOR_H_*/ +#endif /*ITERATOR_H_ @} */ diff --git a/src/libstrongswan/utils/leak_detective.c b/src/libstrongswan/utils/leak_detective.c index dab18fd5c..149456875 100644 --- a/src/libstrongswan/utils/leak_detective.c +++ b/src/libstrongswan/utils/leak_detective.c @@ -1,11 +1,5 @@ -/** - * @file leak_detective.c - * - * @brief Allocation hooks to find memory leaks. - */ - /* - * Copyright (C) 2006 Martin Willi + * Copyright (C) 2006-2008 Martin Willi * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -17,8 +11,15 @@ * 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. + * + * $Id$ */ +#ifdef HAVE_DLADDR +# define _GNU_SOURCE +# include +#endif /* HAVE_DLADDR */ + #include #include #include @@ -33,6 +34,7 @@ #include #include #include +#include #ifdef HAVE_BACKTRACE # include #endif /* HAVE_BACKTRACE */ @@ -42,7 +44,18 @@ #include #include -#ifdef LEAK_DETECTIVE +typedef struct private_leak_detective_t private_leak_detective_t; + +/** + * private data of leak_detective + */ +struct private_leak_detective_t { + + /** + * public functions + */ + leak_detective_t public; +}; /** * Magic value which helps to detect memory corruption. Yummy! @@ -146,77 +159,103 @@ static void log_stack_frames(void **stack_frames, int stack_frame_count) char **strings; size_t i; - strings = backtrace_symbols (stack_frames, stack_frame_count); + strings = backtrace_symbols(stack_frames, stack_frame_count); - DBG1(" dumping %d stack frame addresses", stack_frame_count); + fprintf(stderr, " dumping %d stack frame addresses\n", stack_frame_count); for (i = 0; i < stack_frame_count; i++) { - DBG1(" %s", strings[i]); +#ifdef HAVE_DLADDR + Dl_info info; + + /* TODO: this is quite hackish, but it works. A more proper solution + * would execve addr2strongline and pipe the output to DBG1() */ + if (dladdr(stack_frames[i], &info)) + { + char cmd[1024]; + void *ptr = stack_frames[i]; + + if (strstr(info.dli_fname, ".so")) + { + ptr = (void*)(stack_frames[i] - info.dli_fbase); + } + snprintf(cmd, sizeof(cmd), "addr2line -e %s %p", info.dli_fname, ptr); + if (info.dli_sname) + { + fprintf(stderr, " \e[33m%s\e[0m @ %p (\e[31m%s+0x%x\e[0m) [%p]\n", + info.dli_fname, info.dli_fbase, info.dli_sname, + stack_frames[i] - info.dli_saddr, stack_frames[i]); + } + else + { + fprintf(stderr, " \e[33m%s\e[0m @ %p [%p]\n", info.dli_fname, + info.dli_fbase, stack_frames[i]); + } + fprintf(stderr, " -> \e[32m"); + system(cmd); + fprintf(stderr, "\e[0m"); + } + else +#endif /* HAVE_DLADDR */ + { + fprintf(stderr, " %s\n", strings[i]); + } } free (strings); #endif /* HAVE_BACKTRACE */ } /** - * Whitelist, which contains address ranges in stack frames ignored when leaking. - * - * This is necessary, as some function use allocation hacks (static buffers) - * and so on, which we want to suppress on leak reports. + * Leak report white list * - * The range_size is calculated using the readelf utility, e.g.: - * readelf -s /lib/glibc.so.6 - * The values are for glibc-2.4 and may or may not be correct on other systems. + * List of functions using static allocation buffers or should be suppressed + * otherwise on leak report. */ -typedef struct whitelist_t whitelist_t; - -struct whitelist_t { - void* range_start; - size_t range_size; -}; - -#ifdef LIBCURL -/* dummy declaration for whitelisting */ -void *Curl_getaddrinfo(void); -#endif /* LIBCURL */ - -whitelist_t whitelist[] = { - {pthread_create, 2542}, - {pthread_setspecific, 217}, - {mktime, 60}, - {tzset, 123}, - {inet_ntoa, 249}, - {strerror, 180}, - {getprotobynumber, 291}, - {getservbyport, 311}, - {register_printf_function, 159}, - {syslog, 44}, - {vsyslog, 41}, - {dlopen, 109}, -# ifdef LIBCURL - /* from /usr/lib/libcurl.so.3 */ - {Curl_getaddrinfo, 480}, -# endif /* LIBCURL */ +char *whitelist[] = { + "pthread_create", + "pthread_setspecific", + "mktime", + "tzset", + "inet_ntoa", + "strerror", + "getprotobynumber", + "getservbyport", + "getservbyname", + "register_printf_function", + "syslog", + "vsyslog", + "dlopen", + "getaddrinfo", + "setlocale", + "mysql_init_character_set", + "init_client_errs", + "my_thread_init", }; /** - * Check if this stack frame is whitelisted. + * check if a stack frame contains functions listed above */ static bool is_whitelisted(void **stack_frames, int stack_frame_count) { int i, j; +#ifdef HAVE_DLADDR for (i=0; i< stack_frame_count; i++) { - for (j=0; j= whitelist[j].range_start && - stack_frames[i] <= (whitelist[j].range_start + whitelist[j].range_size)) + Dl_info info; + + if (dladdr(stack_frames[i], &info) && info.dli_sname) + { + for (j = 0; j < sizeof(whitelist)/sizeof(char*); j++) { - return TRUE; + if (streq(info.dli_sname, whitelist[j])) + { + return TRUE; + } } } } +#endif /* HAVE_DLADDR */ return FALSE; } @@ -232,8 +271,9 @@ void report_leaks() { if (!is_whitelisted(hdr->stack_frames, hdr->stack_frame_count)) { - DBG1("Leak (%d bytes at %p):", hdr->bytes, hdr + 1); - log_stack_frames(hdr->stack_frames, hdr->stack_frame_count); + fprintf(stderr, "Leak (%d bytes at %p):\n", hdr->bytes, hdr + 1); + /* skip the first frame, contains leak detective logic */ + log_stack_frames(hdr->stack_frames + 1, hdr->stack_frame_count - 1); leaks++; } } @@ -241,13 +281,13 @@ void report_leaks() switch (leaks) { case 0: - DBG1("No leaks detected"); + fprintf(stderr, "No leaks detected\n"); break; case 1: - DBG1("One leak detected"); + fprintf(stderr, "One leak detected\n"); break; default: - DBG1("%d leaks detected", leaks); + fprintf(stderr, "%d leaks detected\n", leaks); break; } } @@ -334,8 +374,8 @@ void free_hook(void *ptr, const void *caller) uninstall_hooks(); if (hdr->magic != MEMORY_HEADER_MAGIC) { - DBG1("freeing of invalid memory (%p, MAGIC 0x%x != 0x%x):", - ptr, hdr->magic, MEMORY_HEADER_MAGIC); + fprintf(stderr, "freeing of invalid memory (%p, MAGIC 0x%x != 0x%x):\n", + ptr, hdr->magic, MEMORY_HEADER_MAGIC); stack_frame_count = backtrace(stack_frames, STACK_FRAMES_COUNT); log_stack_frames(stack_frames, stack_frame_count); install_hooks(); @@ -380,7 +420,7 @@ void *realloc_hook(void *old, size_t bytes, const void *caller) uninstall_hooks(); if (hdr->magic != MEMORY_HEADER_MAGIC) { - DBG1("reallocation of invalid memory (%p):", old); + fprintf(stderr, "reallocation of invalid memory (%p):\n", old); stack_frame_count = backtrace(stack_frames, STACK_FRAMES_COUNT); log_stack_frames(stack_frames, stack_frame_count); install_hooks(); @@ -407,65 +447,31 @@ void *realloc_hook(void *old, size_t bytes, const void *caller) } /** - * Setup leak detective + * Implementation of leak_detective_t.destroy */ -void __attribute__ ((constructor)) leak_detective_init() +static void destroy(private_leak_detective_t *this) { - if (getenv("LEAK_DETECTIVE_DISABLE") == NULL) - { - install_hooks(); - } -} - -/** - * Clean up leak detective - */ -void __attribute__ ((destructor)) leak_detective_cleanup() -{ - if (getenv("LEAK_DETECTIVE_DISABLE") == NULL) + if (installed) { uninstall_hooks(); report_leaks(); } + free(this); } -/** - * Log memory allocation statistics +/* + * see header file */ -void leak_detective_status(FILE *stream) +leak_detective_t *leak_detective_create() { - u_int blocks = 0; - size_t bytes = 0; - memory_header_t *hdr = &first_header; + private_leak_detective_t *this = malloc_thing(private_leak_detective_t); - if (getenv("LEAK_DETECTIVE_DISABLE")) - { - return; - } + this->public.destroy = (void(*)(leak_detective_t*))destroy; - pthread_mutex_lock(&mutex); - while ((hdr = hdr->next)) + if (getenv("LEAK_DETECTIVE_DISABLE") == NULL) { - blocks++; - bytes += hdr->bytes; + install_hooks(); } - pthread_mutex_unlock(&mutex); - - fprintf(stream, "allocation statistics:\n"); - fprintf(stream, " call stats: malloc: %d, free: %d, realloc: %d\n", - count_malloc, count_free, count_realloc); - fprintf(stream, " allocated %d blocks, total size %d bytes (avg. %d bytes)\n", - blocks, bytes, bytes/blocks); -} - -#else /* !LEAK_DETECTION */ - -/** - * Dummy when !using LEAK_DETECTIVE - */ -void leak_detective_status(FILE *stream) -{ - + return &this->public; } -#endif /* LEAK_DETECTION */ diff --git a/src/libstrongswan/utils/leak_detective.h b/src/libstrongswan/utils/leak_detective.h index d4016b06e..763814726 100644 --- a/src/libstrongswan/utils/leak_detective.h +++ b/src/libstrongswan/utils/leak_detective.h @@ -1,11 +1,5 @@ -/** - * @file leak_detective.h - * - * @brief malloc/free hooks to detect leaks. - */ - /* - * Copyright (C) 2006 Martin Willi + * Copyright (C) 2008 Martin Willi * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -19,17 +13,41 @@ * for more details. */ +/** + * @defgroup leak_detective leak_detective + * @{ @ingroup utils + */ + #ifndef LEAK_DETECTIVE_H_ #define LEAK_DETECTIVE_H_ /** - * Log status information about allocation + * Maximum depth stack frames to register */ -void leak_detective_status(FILE *stream); +#define STACK_FRAMES_COUNT 20 + +typedef struct leak_detective_t leak_detective_t; /** - * Max number of stack frames to include in a backtrace. + * Leak detective finds leaks and bad frees using malloc hooks. + * + * Currently leaks are reported to stderr on destruction. + * + * @todo Build an API for leak detective, allowing leak enumeration, statistics + * and dynamic whitelisting. + */ +struct leak_detective_t { + + /** + * Destroy a leak_detective instance. + */ + void (*destroy)(leak_detective_t *this); +}; + +/** + * Create a leak_detective instance. */ -#define STACK_FRAMES_COUNT 30 +leak_detective_t *leak_detective_create(); + +#endif /* LEAK_DETECTIVE_H_ @}*/ -#endif /* LEAK_DETECTIVE_H_ */ diff --git a/src/libstrongswan/utils/lexparser.c b/src/libstrongswan/utils/lexparser.c index 35ba0d7a6..c23576971 100644 --- a/src/libstrongswan/utils/lexparser.c +++ b/src/libstrongswan/utils/lexparser.c @@ -1,12 +1,5 @@ -/** - * @file lexparser.c - * - * @brief lexical parser for text-based configuration files - * - */ - /* - * Copyright (C) 2001-2006 Andreas Steffen, Zuercher Hochschule Winterthur + * Copyright (C) 2001-2006 Andreas Steffen * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -18,7 +11,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id$ + * $Id$ */ /* memrchr is a GNU extension */ diff --git a/src/libstrongswan/utils/lexparser.h b/src/libstrongswan/utils/lexparser.h index db89ae2d2..1c0a9997a 100644 --- a/src/libstrongswan/utils/lexparser.h +++ b/src/libstrongswan/utils/lexparser.h @@ -1,10 +1,3 @@ -/** - * @file lexparser.h - * - * @brief lexical parser for text-based configuration files - * - */ - /* * Copyright (C) 2001-2006 Andreas Steffen, Zuercher Hochschule Winterthur * @@ -18,47 +11,57 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id$ + * $Id$ */ + +/** + * @defgroup lexparser lexparser + * @{ @ingroup utils + */ + +#ifndef LEXPARSER_H_ +#define LEXPARSER_H_ #include /** - * @brief Eats whitespace + * Eats whitespace */ bool eat_whitespace(chunk_t *src); /** - * @brief Compare null-terminated pattern with chunk + * Compare null-terminated pattern with chunk */ bool match(const char *pattern, const chunk_t *ch); /** - * @brief Extracts a token ending with the first occurence a given termination symbol + * Extracts a token ending with the first occurence a given termination symbol */ bool extract_token(chunk_t *token, const char termination, chunk_t *src); /** - * @brief Extracts a token ending with the last occurence a given termination symbol + * Extracts a token ending with the last occurence a given termination symbol */ bool extract_last_token(chunk_t *token, const char termination, chunk_t *src); /** - * @brief Fetches a new text line terminated by \n or \r\n + * Fetches a new text line terminated by \n or \r\n */ bool fetchline(chunk_t *src, chunk_t *line); /** - * @brief Extracts a value that might be single or double quoted + * Extracts a value that might be single or double quoted */ err_t extract_value(chunk_t *value, chunk_t *line); /** - * @brief extracts a name: value pair from a text line + * extracts a name: value pair from a text line */ err_t extract_name_value(chunk_t *name, chunk_t *value, chunk_t *line); /** - * @brief extracts a parameter: value from a text line + * extracts a parameter: value from a text line */ err_t extract_parameter_value(chunk_t *name, chunk_t *value, chunk_t *line); + +#endif /* LEXPARSER_H_ @} */ diff --git a/src/libstrongswan/utils/linked_list.c b/src/libstrongswan/utils/linked_list.c index 63e1bcfbf..16913b934 100644 --- a/src/libstrongswan/utils/linked_list.c +++ b/src/libstrongswan/utils/linked_list.c @@ -1,10 +1,3 @@ -/** - * @file linked_list.c - * - * @brief Implementation of linked_list_t. - * - */ - /* * Copyright (C) 2007 Tobias Brunner * Copyright (C) 2005-2006 Martin Willi @@ -20,6 +13,8 @@ * 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. + * + * $Id$ */ #include @@ -157,6 +152,11 @@ struct private_enumerator_t { * next item to enumerate */ element_t *next; + + /** + * current item + */ + element_t *current; }; /** @@ -169,6 +169,7 @@ static bool enumerate(private_enumerator_t *this, void **item) return FALSE; } *item = this->next->value; + this->current = this->next; this->next = this->next->next; return TRUE; } @@ -183,6 +184,7 @@ static enumerator_t* create_enumerator(private_linked_list_t *this) enumerator->enumerator.enumerate = (void*)enumerate; enumerator->enumerator.destroy = (void*)free; enumerator->next = this->first; + enumerator->current = NULL; return &enumerator->enumerator; } @@ -459,34 +461,37 @@ static void insert_first(private_linked_list_t *this, void *item) } /** - * Implementation of linked_list_t.remove_first. + * unlink an element form the list, returns following element */ -static status_t remove_first(private_linked_list_t *this, void **item) +static element_t* remove_element(private_linked_list_t *this, element_t *element) { - element_t *element = this->first; - - if (element == NULL) + element_t *next, *previous; + + next = element->next; + previous = element->previous; + free(element); + if (next) { - return NOT_FOUND; + next->previous = previous; } - if (element->next != NULL) + else { - element->next->previous = NULL; + this->last = previous; } - this->first = element->next; - - if (item != NULL) + if (previous) + { + previous->next = next; + } + else { - *item = element->value; + this->first = next; } if (--this->count == 0) { + this->first = NULL; this->last = NULL; } - - free(element); - - return SUCCESS; + return next; } /** @@ -502,6 +507,19 @@ static status_t get_first(private_linked_list_t *this, void **item) return SUCCESS; } +/** + * Implementation of linked_list_t.remove_first. + */ +static status_t remove_first(private_linked_list_t *this, void **item) +{ + if (get_first(this, item) == SUCCESS) + { + remove_element(this, this->first); + return SUCCESS; + } + return NOT_FOUND; +} + /** * Implementation of linked_list_t.insert_last. */ @@ -529,151 +547,67 @@ static void insert_last(private_linked_list_t *this, void *item) } /** - * Implementation of linked_list_t.remove_last. + * Implementation of linked_list_t.get_last. */ -static status_t remove_last(private_linked_list_t *this, void **item) +static status_t get_last(private_linked_list_t *this, void **item) { - element_t *element = this->last; - - if (element == NULL) + if (this->count == 0) { return NOT_FOUND; } - if (element->previous != NULL) - { - element->previous->next = NULL; - } - this->last = element->previous; - - if (item != NULL) - { - *item = element->value; - } - if (--this->count == 0) - { - this->first = NULL; - } - - free(element); - + *item = this->last->value; return SUCCESS; } /** - * Implementation of linked_list_t.insert_at_position. + * Implementation of linked_list_t.remove_last. */ -static status_t insert_at_position (private_linked_list_t *this,size_t position, void *item) +static status_t remove_last(private_linked_list_t *this, void **item) { - element_t *current_element; - int i; - - if (this->count <= position) - { - return INVALID_ARG; - } - - current_element = this->first; - - for (i = 0; i < position;i++) + if (get_last(this, item) == SUCCESS) { - current_element = current_element->next; - } - - if (current_element == NULL) - { - this->public.insert_last(&(this->public),item); + remove_element(this, this->last); return SUCCESS; } - - element_t *element = element_create(item); - if (current_element->previous == NULL) - { - current_element->previous = element; - element->next = current_element; - this->first = element; - } - else - { - current_element->previous->next = element; - element->previous = current_element->previous; - current_element->previous = element; - element->next = current_element; - } - - - this->count++; - return SUCCESS; + return NOT_FOUND; } /** - * Implementation of linked_list_t.remove_at_position. + * Implementation of linked_list_t.remove. */ -static status_t remove_at_position(private_linked_list_t *this,size_t position, void **item) +static int remove(private_linked_list_t *this, void *item, + bool (*compare)(void *,void*)) { - iterator_t *iterator; - int i; - - if (this->count <= position) - { - return INVALID_ARG; - } + element_t *current = this->first; + int removed = 0; - iterator = this->public.create_iterator(&(this->public),TRUE); - iterator->iterate(iterator, item); - for (i = 0; i < position; i++) + while (current) { - if (!iterator->iterate(iterator, item)) + if ((compare && compare(current->value, item)) || + (!compare && current->value == item)) { - iterator->destroy(iterator); - return INVALID_ARG; + removed++; + current = remove_element(this, current); } - } - iterator->remove(iterator); - iterator->destroy(iterator); - - return SUCCESS; -} - -/** - * Implementation of linked_list_t.get_at_position. - */ -static status_t get_at_position(private_linked_list_t *this,size_t position, void **item) -{ - int i; - iterator_t *iterator; - - if (this->count <= position) - { - return INVALID_ARG; - } - - iterator = this->public.create_iterator(&(this->public),TRUE); - iterator->iterate(iterator, item); - for (i = 0; i < position; i++) - { - if (!iterator->iterate(iterator, item)) + else { - iterator->destroy(iterator); - return INVALID_ARG; + current = current->next; } } - iterator->destroy(iterator); - return SUCCESS; + return removed; } /** - * Implementation of linked_list_t.get_last. + * Implementation of linked_list_t.remove_at. */ -static status_t get_last(private_linked_list_t *this, void **item) +static void remove_at(private_linked_list_t *this, private_enumerator_t *enumerator) { - if (this->count == 0) + if (enumerator->current) { - return NOT_FOUND; + remove_element(this, enumerator->current); + enumerator->current = NULL; + enumerator->next = this->first; } - - *item = this->last->value; - - return SUCCESS; } /** @@ -895,9 +829,8 @@ linked_list_t *linked_list_create() this->public.insert_last = (void (*) (linked_list_t *, void *item))insert_last; this->public.remove_first = (status_t (*) (linked_list_t *, void **item))remove_first; this->public.remove_last = (status_t (*) (linked_list_t *, void **item))remove_last; - this->public.insert_at_position = (status_t (*) (linked_list_t *,size_t, void *))insert_at_position; - this->public.remove_at_position = (status_t (*) (linked_list_t *,size_t, void **))remove_at_position; - this->public.get_at_position = (status_t (*) (linked_list_t *,size_t, void **))get_at_position; + this->public.remove = (int(*)(linked_list_t*, void *item, bool (*compare)(void *,void*)))remove; + this->public.remove_at = (void(*)(linked_list_t*, enumerator_t *enumerator))remove_at; this->public.invoke_offset = (void (*)(linked_list_t*,size_t))invoke_offset; this->public.invoke_function = (void (*)(linked_list_t*,void(*)(void*)))invoke_function; this->public.clone_offset = (linked_list_t * (*)(linked_list_t*,size_t))clone_offset; diff --git a/src/libstrongswan/utils/linked_list.h b/src/libstrongswan/utils/linked_list.h index ac36ef46d..3d7133f9d 100644 --- a/src/libstrongswan/utils/linked_list.h +++ b/src/libstrongswan/utils/linked_list.h @@ -1,10 +1,3 @@ -/** - * @file linked_list.h - * - * @brief Interface of linked_list_t. - * - */ - /* * Copyright (C) 2007 Tobias Brunner * Copyright (C) 2005-2006 Martin Willi @@ -20,6 +13,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup linked_list linked_list + * @{ @ingroup utils */ #ifndef LINKED_LIST_H_ @@ -42,51 +42,42 @@ typedef struct linked_list_t linked_list_t; * @return * - TRUE, if the item matched * - FALSE, otherwise - * @ingroup utils */ typedef bool (*linked_list_match_t)(void *item, ...); /** - * @brief Class implementing a double linked list. + * Class implementing a double linked list. * * General purpose linked list. This list is not synchronized. - * - * @b Costructors: - * - linked_list_create() - * - * @ingroup utils */ struct linked_list_t { /** - * @brief Gets the count of items in the list. + * Gets the count of items in the list. * - * @param this calling object * @return number of items in list */ int (*get_count) (linked_list_t *this); /** - * @brief Creates a iterator for the given list. + * Creates a iterator for the given list. * * @warning Created iterator_t object has to get destroyed by the caller. * * @deprecated Iterator is obsolete and will disappear, it is too * complicated to implement. Use enumerator instead. * - * @param this calling object * @param forward iterator direction (TRUE: front to end) * @return new iterator_t object */ iterator_t *(*create_iterator) (linked_list_t *this, bool forward); /** - * @brief Creates a iterator, locking a mutex. + * Creates a iterator, locking a mutex. * * The supplied mutex is acquired immediately, and released * when the iterator gets destroyed. * - * @param this calling object * @param mutex mutex to use for exclusive access * @return new iterator_t object */ @@ -94,113 +85,86 @@ struct linked_list_t { pthread_mutex_t *mutex); /** - * @brief Create an enumerator over the list. + * Create an enumerator over the list. * * The enumerator is a "lightweight" iterator. It only has two methods * and should therefore be much easier to implement. * - * @param this calling object * @return enumerator over list items */ enumerator_t* (*create_enumerator)(linked_list_t *this); /** - * @brief Inserts a new item at the beginning of the list. + * Inserts a new item at the beginning of the list. * - * @param this calling object - * @param[in] item item value to insert in list + * @param item item value to insert in list */ void (*insert_first) (linked_list_t *this, void *item); /** - * @brief Removes the first item in the list and returns its value. + * Removes the first item in the list and returns its value. * - * @param this calling object - * @param[out] item returned value of first item, or NULL - * @return - * - SUCCESS - * - NOT_FOUND, if list is empty + * @param item returned value of first item, or NULL + * @return SUCCESS, or NOT_FOUND if list is empty */ status_t (*remove_first) (linked_list_t *this, void **item); - - /** - * @brief Returns the value of the first list item without removing it. - * - * @param this calling object - * @param[out] item returned value of first item - * @return - * - SUCCESS - * - NOT_FOUND, if list is empty - */ - status_t (*get_first) (linked_list_t *this, void **item); - + /** - * @brief Inserts a new item at the end of the list. - * - * @param this calling object - * @param[in] item value to insert into list + * Remove an item from the list where the enumerator points to. + * + * @param enumerator enumerator with position */ - void (*insert_last) (linked_list_t *this, void *item); + void (*remove_at)(linked_list_t *this, enumerator_t *enumerator); /** - * @brief Inserts a new item at a given position in the list. + * Remove items from the list matching item. * - * @param this calling object - * @param position position starting at 0 to insert new entry - * @param[in] item value to insert into list - * @return - * - SUCCESS - * - INVALID_ARG if position not existing + * If a compare function is given, it is called for each item, where + * the first parameter is the current list item and the second parameter + * is the supplied item parameter. + * If compare is NULL, compare is is done by pointer. + * + * @param item item to remove/pass to comparator + * @param compare compare function, or NULL + * @return number of removed items */ - status_t (*insert_at_position) (linked_list_t *this,size_t position, void *item); + int (*remove)(linked_list_t *this, void *item, bool (*compare)(void *,void*)); /** - * @brief Removes an item from a given position in the list. + * Returns the value of the first list item without removing it. * * @param this calling object - * @param position position starting at 0 to remove entry from - * @param[out] item removed item will be stored at this location - * @return - * - SUCCESS - * - INVALID_ARG if position not existing + * @param item returned value of first item + * @return SUCCESS, NOT_FOUND if list is empty */ - status_t (*remove_at_position) (linked_list_t *this, size_t position, void **item); + status_t (*get_first) (linked_list_t *this, void **item); /** - * @brief Get an item from a given position in the list. + * Inserts a new item at the end of the list. * - * @param this calling object - * @param position position starting at 0 to get entry from - * @param[out] item item will be stored at this location - * @return - * - SUCCESS - * - INVALID_ARG if position not existing + * @param item value to insert into list */ - status_t (*get_at_position) (linked_list_t *this, size_t position, void **item); + void (*insert_last) (linked_list_t *this, void *item); /** - * @brief Removes the last item in the list and returns its value. + * Removes the last item in the list and returns its value. * * @param this calling object - * @param[out] item returned value of last item, or NULL - * @return - * - SUCCESS - * - NOT_FOUND if list is empty + * @param item returned value of last item, or NULL + * @return SUCCESS, NOT_FOUND if list is empty */ status_t (*remove_last) (linked_list_t *this, void **item); /** - * @brief Returns the value of the last list item without removing it. + * Returns the value of the last list item without removing it. * * @param this calling object - * @param[out] item returned value of last item - * @return - * - SUCCESS - * - NOT_FOUND if list is empty + * @param item returned value of last item + * @return SUCCESS, NOT_FOUND if list is empty */ status_t (*get_last) (linked_list_t *this, void **item); - /** @brief Find the first matching element in the list. + /** Find the first matching element in the list. * * The first object passed to the match function is the current list item, * followed by the user supplied data. @@ -210,19 +174,15 @@ struct linked_list_t { * * @warning Only use pointers as user supplied data. * - * @param this calling object * @param match comparison function to call on each object - * @param[out] item - * - the list item, if found - * - NULL, otherwise + * @param item the list item, if found * @param ... user data to supply to match function (limited to 5 arguments) - * @return - * - SUCCESS, if found - * - NOT_FOUND, otherwise + * @return SUCCESS if found, NOT_FOUND otherwise */ - status_t (*find_first) (linked_list_t *this, linked_list_match_t match, void **item, ...); + status_t (*find_first) (linked_list_t *this, linked_list_match_t match, + void **item, ...); - /** @brief Find the last matching element in the list. + /** Find the last matching element in the list. * * The first object passed to the match function is the current list item, * followed by the user supplied data. @@ -232,20 +192,16 @@ struct linked_list_t { * * @warning Only use pointers as user supplied data. * - * @param this calling object * @param match comparison function to call on each object - * @param[out] item - * - the list item, if found - * - NULL, otherwise + * @param item the list item, if found * @param ... user data to supply to match function (limited to 5 arguments) - * @return - * - SUCCESS, if found - * - NOT_FOUND, otherwise + * @return SUCCESS if found, NOT_FOUND otherwise */ - status_t (*find_last) (linked_list_t *this, linked_list_match_t match, void **item, ...); + status_t (*find_last) (linked_list_t *this, linked_list_match_t match, + void **item, ...); /** - * @brief Invoke a method on all of the contained objects. + * Invoke a method on all of the contained objects. * * If a linked list contains objects with function pointers, * invoke() can call a method on each of the objects. The @@ -253,79 +209,68 @@ struct linked_list_t { * which can be evalutated at compile time using the offsetof * macro, e.g.: list->invoke(list, offsetof(object_t, method)); * - * @param this calling object * @param offset offset of the method to invoke on objects */ void (*invoke_offset) (linked_list_t *this, size_t offset); /** - * @brief Invoke a function on all of the contained objects. + * Invoke a function on all of the contained objects. * - * @param this calling object * @param offset offset of the method to invoke on objects */ void (*invoke_function) (linked_list_t *this, void (*)(void*)); /** - * @brief Clones a list and its objects using the objects' clone method. + * Clones a list and its objects using the objects' clone method. * - * @param this calling object * @param offset offset ot the objects clone function * @return cloned list */ linked_list_t *(*clone_offset) (linked_list_t *this, size_t offset); /** - * @brief Clones a list and its objects using a given function. + * Clones a list and its objects using a given function. * - * @param this calling object * @param function function that clones an object * @return cloned list */ linked_list_t *(*clone_function) (linked_list_t *this, void*(*)(void*)); /** - * @brief Destroys a linked_list object. - * - * @param this calling object + * Destroys a linked_list object. */ void (*destroy) (linked_list_t *this); /** - * @brief Destroys a list and its objects using the destructor. + * Destroys a list and its objects using the destructor. * * If a linked list and the contained objects should be destroyed, use * destroy_offset. The supplied offset specifies the destructor to * call on each object. The offset may be calculated using the offsetof * macro, e.g.: list->destroy_offset(list, offsetof(object_t, destroy)); * - * @param this calling object * @param offset offset of the objects destructor */ void (*destroy_offset) (linked_list_t *this, size_t offset); /** - * @brief Destroys a list and its contents using a a cleanup function. + * Destroys a list and its contents using a a cleanup function. * * If a linked list and its contents should get destroyed using a specific * cleanup function, use destroy_function. This is useful when the * list contains malloc()-ed blocks which should get freed, * e.g.: list->destroy_function(list, free); * - * @param this calling object * @param function function to call on each object */ void (*destroy_function) (linked_list_t *this, void (*)(void*)); }; /** - * @brief Creates an empty linked list object. + * Creates an empty linked list object. * * @return linked_list_t object. - * - * @ingroup utils */ linked_list_t *linked_list_create(void); - -#endif /*LINKED_LIST_H_*/ +#endif /*LINKED_LIST_H_ @} */ diff --git a/src/libstrongswan/utils/mutex.c b/src/libstrongswan/utils/mutex.c new file mode 100644 index 000000000..f16c5b2c7 --- /dev/null +++ b/src/libstrongswan/utils/mutex.c @@ -0,0 +1,267 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "mutex.h" + +#include +#include + +#include +#include +#include +#include + + +typedef struct private_mutex_t private_mutex_t; +typedef struct private_n_mutex_t private_n_mutex_t; +typedef struct private_r_mutex_t private_r_mutex_t; +typedef struct private_condvar_t private_condvar_t; + +/** + * private data of mutex + */ +struct private_mutex_t { + + /** + * public functions + */ + mutex_t public; + + /** + * wrapped pthread mutex + */ + pthread_mutex_t mutex; +}; + +/** + * private data of mutex, extended by recursive locking information + */ +struct private_r_mutex_t { + + /** + * public functions + */ + private_mutex_t generic; + + /** + * thread which currently owns mutex + */ + pthread_t thread; + + /** + * times we have locked the lock + */ + int times; +}; + +/** + * private data of condvar + */ +struct private_condvar_t { + + /** + * public functions + */ + condvar_t public; + + /** + * wrapped pthread condvar + */ + pthread_cond_t condvar; +}; + +/** + * Implementation of mutex_t.lock. + */ +static void lock(private_mutex_t *this) +{ + if (pthread_mutex_lock(&this->mutex)) + { + DBG1("!!!! MUTEX %sLOCK ERROR, your code is buggy !!!", ""); + } +} + +/** + * Implementation of mutex_t.unlock. + */ +static void unlock(private_mutex_t *this) +{ + if (pthread_mutex_unlock(&this->mutex)) + { + DBG1("!!!! MUTEX %sLOCK ERROR, your code is buggy !!!", "UN"); + } +} + +/** + * Implementation of mutex_t.lock. + */ +static void lock_r(private_r_mutex_t *this) +{ + pthread_t self = pthread_self(); + + if (this->thread == self) + { + this->times++; + return; + } + lock(&this->generic); + this->thread = self; + this->times = 1; +} + +/** + * Implementation of mutex_t.unlock. + */ +static void unlock_r(private_r_mutex_t *this) +{ + if (--this->times == 0) + { + this->thread = 0; + unlock(&this->generic); + } +} + +/** + * Implementation of mutex_t.destroy + */ +static void mutex_destroy(private_mutex_t *this) +{ + pthread_mutex_destroy(&this->mutex); + free(this); +} + +/* + * see header file + */ +mutex_t *mutex_create(mutex_type_t type) +{ + switch (type) + { + case MUTEX_RECURSIVE: + { + private_r_mutex_t *this = malloc_thing(private_r_mutex_t); + + this->generic.public.lock = (void(*)(mutex_t*))lock_r; + this->generic.public.unlock = (void(*)(mutex_t*))unlock_r; + this->generic.public.destroy = (void(*)(mutex_t*))mutex_destroy; + + pthread_mutex_init(&this->generic.mutex, NULL); + this->thread = 0; + this->times = 0; + + return &this->generic.public; + } + case MUTEX_DEFAULT: + default: + { + private_mutex_t *this = malloc_thing(private_mutex_t); + + this->public.lock = (void(*)(mutex_t*))lock; + this->public.unlock = (void(*)(mutex_t*))unlock; + this->public.destroy = (void(*)(mutex_t*))mutex_destroy; + + pthread_mutex_init(&this->mutex, NULL); + + return &this->public; + } + } +} + +/** + * Implementation of condvar_t.wait. + */ +static void wait(private_condvar_t *this, private_mutex_t *mutex) +{ + pthread_cond_wait(&this->condvar, &mutex->mutex); +} + +/** + * Implementation of condvar_t.timed_wait. + */ +static bool timed_wait(private_condvar_t *this, private_mutex_t *mutex, + u_int timeout) +{ + struct timespec ts; + struct timeval tv; + u_int s, ms; + + gettimeofday(&tv, NULL); + + s = timeout / 1000; + ms = timeout % 1000; + + ts.tv_sec = tv.tv_sec + s; + ts.tv_nsec = tv.tv_usec * 1000 + ms * 1000000; + if (ts.tv_nsec > 1000000000 /* 1s */) + { + ts.tv_nsec -= 1000000000; + ts.tv_sec++; + } + return (pthread_cond_timedwait(&this->condvar, &mutex->mutex, + &ts) == ETIMEDOUT); +} + +/** + * Implementation of condvar_t.signal. + */ +static void signal(private_condvar_t *this) +{ + pthread_cond_signal(&this->condvar); +} + +/** + * Implementation of condvar_t.broadcast. + */ +static void broadcast(private_condvar_t *this) +{ + pthread_cond_broadcast(&this->condvar); +} + +/** + * Implementation of condvar_t.destroy + */ +static void condvar_destroy(private_condvar_t *this) +{ + pthread_cond_destroy(&this->condvar); + free(this); +} + +/* + * see header file + */ +condvar_t *condvar_create(condvar_type_t type) +{ + switch (type) + { + case CONDVAR_DEFAULT: + default: + { + private_condvar_t *this = malloc_thing(private_condvar_t); + + this->public.wait = (void(*)(condvar_t*, mutex_t *mutex))wait; + this->public.timed_wait = (bool(*)(condvar_t*, mutex_t *mutex, u_int timeout))timed_wait; + this->public.signal = (void(*)(condvar_t*))signal; + this->public.broadcast = (void(*)(condvar_t*))broadcast; + this->public.destroy = (void(*)(condvar_t*))condvar_destroy; + + pthread_cond_init(&this->condvar, NULL); + + return &this->public; + } + } +} + diff --git a/src/libstrongswan/utils/mutex.h b/src/libstrongswan/utils/mutex.h new file mode 100644 index 000000000..cf557c35c --- /dev/null +++ b/src/libstrongswan/utils/mutex.h @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 mutex mutex + * @{ @ingroup utils + */ + +#ifndef MUTEX_H_ +#define MUTEX_H_ + +typedef struct mutex_t mutex_t; +typedef struct condvar_t condvar_t; +typedef enum mutex_type_t mutex_type_t; +typedef enum condvar_type_t condvar_type_t; + +#include + +/** + * Type of mutex. + */ +enum mutex_type_t { + /** default mutex */ + MUTEX_DEFAULT = 0, + /** allow recursive locking of the mutex */ + MUTEX_RECURSIVE = 1, +}; + +/** + * Type of condvar. + */ +enum condvar_type_t { + /** default condvar */ + CONDVAR_DEFAULT = 0, +}; + +/** + * Mutex wrapper implements simple, portable and advanced mutex functions. + */ +struct mutex_t { + + /** + * Acquire the lock to the mutex. + */ + void (*lock)(mutex_t *this); + + /** + * Release the lock on the mutex. + */ + void (*unlock)(mutex_t *this); + + /** + * Destroy a mutex instance. + */ + void (*destroy)(mutex_t *this); +}; + +/** + * Condvar wrapper to use in conjunction with mutex_t. + */ +struct condvar_t { + + /** + * Wait on a condvar until it gets signalized. + * + * @param mutex mutex to release while waiting + */ + void (*wait)(condvar_t *this, mutex_t *mutex); + + /** + * Wait on a condvar until it gets signalized, or times out. + * + * @param mutex mutex to release while waiting + * @param timeout timeout im ms + * @return TRUE if timed out, FALSE otherwise + */ + bool (*timed_wait)(condvar_t *this, mutex_t *mutex, u_int timeout); + + /** + * Wake up a single thread in a condvar. + */ + void (*signal)(condvar_t *this); + + /** + * Wake up all threads in a condvar. + */ + void (*broadcast)(condvar_t *this); + + /** + * Destroy a condvar and free its resources. + */ + void (*destroy)(condvar_t *this); +}; + +/** + * Create a mutex instance. + * + * @param type type of mutex to create + * @return unlocked mutex instance + */ +mutex_t *mutex_create(mutex_type_t type); + +/** + * Create a condvar instance. + * + * @param type type of condvar to create + * @return condvar instance + */ +condvar_t *condvar_create(condvar_type_t type); + +#endif /* MUTEX_H_ @}*/ diff --git a/src/libstrongswan/utils/optionsfrom.c b/src/libstrongswan/utils/optionsfrom.c index 39e38cc58..38302105d 100644 --- a/src/libstrongswan/utils/optionsfrom.c +++ b/src/libstrongswan/utils/optionsfrom.c @@ -1,13 +1,5 @@ -/** - * @file optionsfrom.c - * - * @brief read command line options from a file - * - */ - /* * Copyright (C) 2007-2008 Andreas Steffen - * * Hochschule fuer Technik Rapperswil * * This library is free software; you can redistribute it and/or modify it @@ -20,7 +12,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public * License for more details. * - * RCSID $Id$ + * $Id$ */ #include diff --git a/src/libstrongswan/utils/optionsfrom.h b/src/libstrongswan/utils/optionsfrom.h index 0014cec36..3a5640907 100644 --- a/src/libstrongswan/utils/optionsfrom.h +++ b/src/libstrongswan/utils/optionsfrom.h @@ -1,10 +1,3 @@ -/** - * @file optionsfrom.h - * - * @brief Read command line options from a file - * - */ - /* * Copyright (C) 2007-2008 Andreas Steffen * @@ -20,7 +13,12 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id$ + * $Id$ + */ + +/** + * @defgroup optionsfrom optionsfrom + * @{ @ingroup utils */ #ifndef OPTIONSFROM_H_ @@ -29,41 +27,33 @@ typedef struct options_t options_t; /** - * @brief options object. - * - * @b Constructors: - * - options_create() - * - * @ingroup utils + * Reads additional command line arguments from a file */ struct options_t { + /** - * @brief Check if the PKCS#7 contentType is data + * Check if the PKCS#7 contentType is data * - * @param this calling object * @param filename file containing the options * @param argcp pointer to argc * @param argvp pointer to argv[] * @param optind current optind, number of next argument * @return TRUE if optionsfrom parsing successful */ - bool (*from) (options_t * this, char *filename, int *argcp, char **argvp[], int optind); + bool (*from) (options_t * this, char *filename, + int *argcp, char **argvp[], int optind); /** - * @brief Destroys the options_t object. - * - * @param this options_t object to destroy + * Destroys the options_t object. */ void (*destroy) (options_t *this); }; /** - * @brief Create an options object. + * Create an options object. * * @return created options_t object - * - * @ingroup utils */ options_t *options_create(void); -#endif /*OPTIONSFROM_H_*/ +#endif /*OPTIONSFROM_H_ @} */ diff --git a/src/libstrongswan/utils/randomizer.c b/src/libstrongswan/utils/randomizer.c index c15d108c7..74db0dead 100644 --- a/src/libstrongswan/utils/randomizer.c +++ b/src/libstrongswan/utils/randomizer.c @@ -1,10 +1,3 @@ -/** - * @file randomizer.c - * - * @brief Implementation of randomizer_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,8 @@ * 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. + * + * $Id$ */ #include @@ -41,25 +36,13 @@ struct private_randomizer_t { * Public randomizer_t interface. */ randomizer_t public; - - /** - * @brief Reads a specific number of bytes from random or pseudo random device. - * - * @param this calling object - * @param pseudo_random TRUE, if from pseudo random bytes should be read, - * FALSE for true random bytes - * @param bytes number of bytes to read - * @param[out] buffer pointer to buffer where to write the data in. - * Size of buffer has to be at least bytes. - */ - status_t (*get_bytes_from_device) (private_randomizer_t *this,bool pseudo_random, size_t bytes, u_int8_t *buffer); }; - /** - * Implementation of private_randomizer_t.get_bytes_from_device. + * Read bytes from the random device */ -static status_t get_bytes_from_device(private_randomizer_t *this,bool pseudo_random, size_t bytes, u_int8_t *buffer) +static status_t read_bytes(private_randomizer_t *this, + bool pseudo_random, size_t bytes, u_int8_t *buffer) { size_t ndone; int device; @@ -91,20 +74,22 @@ static status_t get_bytes_from_device(private_randomizer_t *this,bool pseudo_ran /** * Implementation of randomizer_t.get_random_bytes. */ -static status_t get_random_bytes(private_randomizer_t *this,size_t bytes, u_int8_t *buffer) +static status_t get_random_bytes(private_randomizer_t *this,size_t bytes, + u_int8_t *buffer) { - return this->get_bytes_from_device(this, FALSE, bytes, buffer); + return read_bytes(this, FALSE, bytes, buffer); } /** * Implementation of randomizer_t.allocate_random_bytes. */ -static status_t allocate_random_bytes(private_randomizer_t *this, size_t bytes, chunk_t *chunk) +static status_t allocate_random_bytes(private_randomizer_t *this, size_t bytes, + chunk_t *chunk) { status_t status; chunk->len = bytes; chunk->ptr = malloc(bytes); - status = this->get_bytes_from_device(this, FALSE, bytes, chunk->ptr); + status = read_bytes(this, FALSE, bytes, chunk->ptr); if (status != SUCCESS) { free(chunk->ptr); @@ -115,20 +100,22 @@ static status_t allocate_random_bytes(private_randomizer_t *this, size_t bytes, /** * Implementation of randomizer_t.get_pseudo_random_bytes. */ -static status_t get_pseudo_random_bytes(private_randomizer_t *this,size_t bytes, u_int8_t *buffer) +static status_t get_pseudo_random_bytes(private_randomizer_t *this, + size_t bytes, u_int8_t *buffer) { - return (this->get_bytes_from_device(this, TRUE, bytes, buffer)); + return read_bytes(this, TRUE, bytes, buffer); } /** * Implementation of randomizer_t.allocate_pseudo_random_bytes. */ -static status_t allocate_pseudo_random_bytes(private_randomizer_t *this, size_t bytes, chunk_t *chunk) +static status_t allocate_pseudo_random_bytes(private_randomizer_t *this, + size_t bytes, chunk_t *chunk) { status_t status; chunk->len = bytes; chunk->ptr = malloc(bytes); - status = this->get_bytes_from_device(this, TRUE, bytes, chunk->ptr); + status = read_bytes(this, TRUE, bytes, chunk->ptr); if (status != SUCCESS) { free(chunk->ptr); @@ -158,8 +145,6 @@ randomizer_t *randomizer_create(void) this->public.allocate_pseudo_random_bytes = (status_t (*) (randomizer_t *,size_t, chunk_t *)) allocate_pseudo_random_bytes; this->public.destroy = (void (*) (randomizer_t *))destroy; - /* private functions */ - this->get_bytes_from_device = get_bytes_from_device; - - return &(this->public); + return &this->public; } + diff --git a/src/libstrongswan/utils/randomizer.h b/src/libstrongswan/utils/randomizer.h index afbade059..c7aa86b01 100644 --- a/src/libstrongswan/utils/randomizer.h +++ b/src/libstrongswan/utils/randomizer.h @@ -1,10 +1,3 @@ -/** - * @file randomizer.h - * - * @brief Interface of randomizer_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,6 +12,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup randomizer randomizer + * @{ @ingroup utils */ #ifndef RANDOMIZER_H_ @@ -43,72 +43,59 @@ typedef struct randomizer_t randomizer_t; #endif /** - * @brief Class used to get random and pseudo random values. - * - * @b Constructors: - * - randomizer_create() - * - * @ingroup utils + * Class used to get random and pseudo random values. */ struct randomizer_t { /** - * @brief Reads a specific number of bytes from random device. - * - * @param this calling randomizer_t object - * @param bytes number of bytes to read - * @param[out] buffer pointer to buffer where to write the data in. - * Size of buffer has to be at least bytes. - * @return SUCCESS, or FAILED + * Reads a specific number of bytes from random device. + * + * @param bytes number of bytes to read + * @param buffer pointer to buffer where to write the data in. + * @return SUCCESS, or FAILED */ - status_t (*get_random_bytes) (randomizer_t *this, size_t bytes, u_int8_t *buffer); + status_t (*get_random_bytes) (randomizer_t *this, + size_t bytes, u_int8_t *buffer); /** - * @brief Allocates space and writes in random bytes. + * Allocates space and writes in random bytes. * - * @param this calling randomizer_t object - * @param bytes number of bytes to allocate - * @param[out] chunk chunk which will hold the allocated random bytes - * @return SUCCESS, or FAILED + * @param bytes number of bytes to allocate + * @param chunk chunk which will hold the allocated random bytes + * @return SUCCESS, or FAILED */ - status_t (*allocate_random_bytes) (randomizer_t *this, size_t bytes, chunk_t *chunk); + status_t (*allocate_random_bytes) (randomizer_t *this, + size_t bytes, chunk_t *chunk); /** - * @brief Reads a specific number of bytes from pseudo random device. + * Reads a specific number of bytes from pseudo random device. * - * @param this calling randomizer_t object - * @param bytes number of bytes to read - * @param[out] buffer pointer to buffer where to write the data in. - * size of buffer has to be at least bytes. - * @return SUCCESS, or FAILED + * @param bytes number of bytes to read + * @param buffer pointer to buffer where to write the data in. + * @return SUCCESS, or FAILED */ status_t (*get_pseudo_random_bytes) (randomizer_t *this,size_t bytes, u_int8_t *buffer); /** - * @brief Allocates space and writes in pseudo random bytes. + * Allocates space and writes in pseudo random bytes. * - * @param this calling randomizer_t object - * @param bytes number of bytes to allocate - * @param[out] chunk chunk which will hold the allocated random bytes - * @return SUCCESS, or FAILED + * @param bytes number of bytes to allocate + * @param chunk chunk which will hold the allocated random bytes + * @return SUCCESS, or FAILED */ status_t (*allocate_pseudo_random_bytes) (randomizer_t *this, size_t bytes, chunk_t *chunk); /** - * @brief Destroys a randomizer_t object. - * - * @param this randomizer_t object to destroy + * Destroys a randomizer_t object. */ void (*destroy) (randomizer_t *this); }; /** - * @brief Creates a randomizer_t object. - * - * @return created randomizer_t, or + * Creates a randomizer_t object. * - * @ingroup utils + * @return created randomizer_t */ randomizer_t *randomizer_create(void); -#endif /*RANDOMIZER_H_*/ +#endif /*RANDOMIZER_H_ @} */ diff --git a/src/manager/Makefile.am b/src/manager/Makefile.am index 7f77d1dba..366022fd1 100644 --- a/src/manager/Makefile.am +++ b/src/manager/Makefile.am @@ -1,27 +1,16 @@ ipsec_PROGRAMS = manager.fcgi manager_fcgi_SOURCES = \ -main.c manager.c manager.h gateway.h gateway.c database.h database.c \ +main.c manager.c manager.h gateway.h gateway.c storage.h storage.c xml.h xml.c \ controller/auth_controller.c controller/auth_controller.h \ controller/ikesa_controller.c controller/ikesa_controller.h \ controller/control_controller.c controller/control_controller.h \ controller/config_controller.c controller/config_controller.h \ controller/gateway_controller.c controller/gateway_controller.h -manager_fcgi_LDADD = $(top_builddir)/src/manager/libappserv.la -lsqlite3 +manager_fcgi_LDADD = $(top_builddir)/src/libfast/libfast.la ${xml_LIBS} - - -lib_LTLIBRARIES = libappserv.la - -libappserv_la_SOURCES = \ -lib/context.h lib/dispatcher.c lib/request.h lib/session.h \ -lib/controller.h lib/dispatcher.h lib/request.c lib/session.c \ -lib/xml.h lib/xml.c - -libappserv_la_LIBADD = $(top_builddir)/src/libstrongswan/libstrongswan.la -lfcgi -lpthread -lneo_cgi -lneo_cs -lneo_utl ${xml_LIBS} - -INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/manager/lib -I/usr/include/ClearSilver ${xml_CFLAGS} +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libfast ${xml_CFLAGS} AM_CFLAGS = -rdynamic -DIPSECDIR=\"${ipsecdir}\" -DIPSEC_PIDDIR=\"${piddir}\" ipsec_DATA = manager.db diff --git a/src/manager/controller/auth_controller.c b/src/manager/controller/auth_controller.c index e9b86941a..cccee8888 100644 --- a/src/manager/controller/auth_controller.c +++ b/src/manager/controller/auth_controller.c @@ -1,10 +1,3 @@ -/** - * @file auth_controller.c - * - * @brief Implementation of auth_controller_t. - * - */ - /* * Copyright (C) 2007 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,8 @@ * 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. + * + * $Id$ */ #include "auth_controller.h" diff --git a/src/manager/controller/auth_controller.h b/src/manager/controller/auth_controller.h index c90546a17..2e9f93459 100644 --- a/src/manager/controller/auth_controller.h +++ b/src/manager/controller/auth_controller.h @@ -1,10 +1,3 @@ -/** - * @file auth_controller.h - * - * @brief Interface of auth_controller_t. - * - */ - /* * Copyright (C) 2007 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup auth_controller auth_controller + * @{ @ingroup controller */ #ifndef AUTH_CONTROLLER_H_ @@ -29,7 +29,7 @@ typedef struct auth_controller_t auth_controller_t; /** - * @brief Authentication controller. + * Authentication controller. */ struct auth_controller_t { @@ -40,8 +40,8 @@ struct auth_controller_t { }; /** - * @brief Create a auth_controller controller instance. + * Create a auth_controller controller instance. */ controller_t *auth_controller_create(context_t *context, void *param); -#endif /* AUTH_CONTROLLER_H_ */ +#endif /* AUTH_CONTROLLER_H_ @} */ diff --git a/src/manager/controller/config_controller.c b/src/manager/controller/config_controller.c index e7941ada4..34f054a73 100644 --- a/src/manager/controller/config_controller.c +++ b/src/manager/controller/config_controller.c @@ -1,10 +1,3 @@ -/** - * @file config_controller.c - * - * @brief Implementation of config_controller_t. - * - */ - /* * Copyright (C) 2007 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,8 @@ * 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. + * + * $Id$ */ #include "config_controller.h" diff --git a/src/manager/controller/config_controller.h b/src/manager/controller/config_controller.h index fcf5f5c49..edc5cd0d0 100644 --- a/src/manager/controller/config_controller.h +++ b/src/manager/controller/config_controller.h @@ -1,10 +1,3 @@ -/** - * @file config_controller.h - * - * @brief Interface of config_controller_t. - * - */ - /* * Copyright (C) 2007 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup config_controller config_controller + * @{ @ingroup controller */ #ifndef CONFIG_CONTROLLER_H_ @@ -29,7 +29,7 @@ typedef struct config_controller_t config_controller_t; /** - * @brief Status controller. + * Status controller. */ struct config_controller_t { @@ -40,8 +40,8 @@ struct config_controller_t { }; /** - * @brief Create a config_controller controller instance. + * Create a config_controller controller instance. */ controller_t *config_controller_create(context_t *context, void *param); -#endif /* CONFIG_CONTROLLER_H_ */ +#endif /* CONFIG_CONTROLLER_H_ @} */ diff --git a/src/manager/controller/control_controller.c b/src/manager/controller/control_controller.c index 12cb5e907..d49941e2f 100644 --- a/src/manager/controller/control_controller.c +++ b/src/manager/controller/control_controller.c @@ -1,10 +1,3 @@ -/** - * @file control_controller.c - * - * @brief Implementation of control_controller_t. - * - */ - /* * Copyright (C) 2007 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,8 @@ * 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. + * + * $Id$ */ #include "control_controller.h" diff --git a/src/manager/controller/control_controller.h b/src/manager/controller/control_controller.h index 6a55170aa..a33cae50e 100644 --- a/src/manager/controller/control_controller.h +++ b/src/manager/controller/control_controller.h @@ -1,10 +1,3 @@ -/** - * @file control_controller.h - * - * @brief Interface of control_controller_t. - * - */ - /* * Copyright (C) 2007 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup control_controller control_controller + * @{ @ingroup controller */ #ifndef CONTROL_CONTROLLER_H_ @@ -29,7 +29,7 @@ typedef struct control_controller_t control_controller_t; /** - * @brief Status controller. + * Control controller. */ struct control_controller_t { @@ -40,7 +40,7 @@ struct control_controller_t { }; /** - * @brief Create a control_controller controller instance. + * Create a control_controller controller instance. */ controller_t *control_controller_create(context_t *context, void *param); diff --git a/src/manager/controller/gateway_controller.c b/src/manager/controller/gateway_controller.c index dff1cf3cf..e4015e06c 100644 --- a/src/manager/controller/gateway_controller.c +++ b/src/manager/controller/gateway_controller.c @@ -1,10 +1,3 @@ -/** - * @file gateway_controller.c - * - * @brief Implementation of gateway_controller_t. - * - */ - /* * Copyright (C) 2007 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,8 @@ * 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. + * + * $Id$ */ #include "gateway_controller.h" diff --git a/src/manager/controller/gateway_controller.h b/src/manager/controller/gateway_controller.h index 5872e20e2..eec089d7e 100644 --- a/src/manager/controller/gateway_controller.h +++ b/src/manager/controller/gateway_controller.h @@ -1,10 +1,3 @@ -/** - * @file gateway_controller.h - * - * @brief Interface of gateway_controller_t. - * - */ - /* * Copyright (C) 2007 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup gateway_controller gateway_controller + * @{ @ingroup controller */ #ifndef GATEWAY_CONTROLLER_H_ @@ -29,7 +29,7 @@ typedef struct gateway_controller_t gateway_controller_t; /** - * @brief Status controller. + * Status controller. */ struct gateway_controller_t { @@ -40,8 +40,8 @@ struct gateway_controller_t { }; /** - * @brief Create a gateway_controller controller instance. + * Create a gateway_controller controller instance. */ controller_t *gateway_controller_create(context_t *context, void *param); -#endif /* GATEWAY_CONTROLLER_H_ */ +#endif /* GATEWAY_CONTROLLER_H_ @} */ diff --git a/src/manager/controller/ikesa_controller.c b/src/manager/controller/ikesa_controller.c index 2b282b79c..a52adc189 100644 --- a/src/manager/controller/ikesa_controller.c +++ b/src/manager/controller/ikesa_controller.c @@ -1,10 +1,3 @@ -/** - * @file ikesa_controller.c - * - * @brief Implementation of ikesa_controller_t. - * - */ - /* * Copyright (C) 2007 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,8 @@ * 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. + * + * $Id$ */ #include "ikesa_controller.h" diff --git a/src/manager/controller/ikesa_controller.h b/src/manager/controller/ikesa_controller.h index 753cccad1..a238db307 100644 --- a/src/manager/controller/ikesa_controller.h +++ b/src/manager/controller/ikesa_controller.h @@ -1,10 +1,3 @@ -/** - * @file ikesa_controller.h - * - * @brief Interface of ikesa_controller_t. - * - */ - /* * Copyright (C) 2007 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup ikesa_controller ikesa_controller + * @{ @ingroup controller */ #ifndef IKESA_CONTROLLER_H_ @@ -29,7 +29,7 @@ typedef struct ikesa_controller_t ikesa_controller_t; /** - * @brief Status controller. + * Status controller. */ struct ikesa_controller_t { @@ -40,8 +40,8 @@ struct ikesa_controller_t { }; /** - * @brief Create a ikesa_controller controller instance. + * Create a ikesa_controller controller instance. */ controller_t *ikesa_controller_create(context_t *context, void *param); -#endif /* IKESA_CONTROLLER_H_ */ +#endif /* IKESA_CONTROLLER_H_ @} */ diff --git a/src/manager/database.c b/src/manager/database.c deleted file mode 100644 index a7776c81e..000000000 --- a/src/manager/database.c +++ /dev/null @@ -1,183 +0,0 @@ -/** - * @file database.c - * - * @brief Implementation of database_t. - * - */ - -/* - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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 "database.h" - -#include -#include -#include - - -typedef struct private_database_t private_database_t; - -/** - * private data of database - */ -struct private_database_t { - - /** - * public functions - */ - database_t public; - - /** - * SQLite database handle - */ - sqlite3 *db; -}; - -/** - * database enumerator implements enumerator_t - */ -typedef struct { - enumerator_t enumerator; - sqlite3_stmt *stmt; -} db_enumerator_t; - -/** - * destroy a database enumerator - */ -static void db_enumerator_destroy(db_enumerator_t* this) -{ - sqlite3_finalize(this->stmt); - free(this); -} - -/** - * create a database enumerator - */ -static enumerator_t *db_enumerator_create(bool(*enumerate)(db_enumerator_t*,void*,...), - sqlite3_stmt *stmt) -{ - db_enumerator_t *this = malloc_thing(db_enumerator_t); - this->enumerator.enumerate = (void*)enumerate; - this->enumerator.destroy = (void*)db_enumerator_destroy; - this->stmt = stmt; - return &this->enumerator; -} - -/** - * Implementation of database_t.login. - */ -static int login(private_database_t *this, char *username, char *password) -{ - sqlite3_stmt *stmt; - hasher_t *hasher; - chunk_t hash, data; - size_t username_len, password_len; - int uid = 0; - char *str; - - /* hash = SHA1( username | password ) */ - hasher = hasher_create(HASH_SHA1); - hash = chunk_alloca(hasher->get_hash_size(hasher)); - username_len = strlen(username); - password_len = strlen(password); - data = chunk_alloca(username_len + password_len); - memcpy(data.ptr, username, username_len); - memcpy(data.ptr + username_len, password, password_len); - hasher->get_hash(hasher, data, hash.ptr); - hasher->destroy(hasher); - str = chunk_to_hex(hash, FALSE); - - if (sqlite3_prepare_v2(this->db, - "SELECT oid FROM users WHERE username = ? AND password = ?;", - -1, &stmt, NULL) == SQLITE_OK) - { - if (sqlite3_bind_text(stmt, 1, username, -1, SQLITE_STATIC) == SQLITE_OK && - sqlite3_bind_text(stmt, 2, str, -1, SQLITE_STATIC) == SQLITE_OK && - sqlite3_step(stmt) == SQLITE_ROW) - { - uid = sqlite3_column_int(stmt, 0); - } - sqlite3_finalize(stmt); - } - free(str); - return uid; -} - -/** - * enumerate function for gateway enumrator - */ -static bool gateway_enumerate(db_enumerator_t* e, int *id, const char **name, - int *port, const char **address) -{ - if (sqlite3_step(e->stmt) == SQLITE_ROW) - { - *id = sqlite3_column_int(e->stmt, 0); - *name = sqlite3_column_text(e->stmt, 1); - *port = sqlite3_column_int(e->stmt, 2); - *address = sqlite3_column_text(e->stmt, 3); - return TRUE; - } - return FALSE; -} - -/** - * Implementation of database_t.create_gateway_enumerator. - */ -static enumerator_t* create_gateway_enumerator(private_database_t *this, int user) -{ - sqlite3_stmt *stmt; - - if (sqlite3_prepare_v2(this->db, - "SELECT gateways.oid AS gid, name, port, address FROM " - "gateways, user_gateway AS ug ON gid = ug.gateway WHERE ug.user = ?;", - -1, &stmt, NULL) == SQLITE_OK) - { - if (sqlite3_bind_int(stmt, 1, user) == SQLITE_OK) - { - return db_enumerator_create((void*)gateway_enumerate, stmt); - } - sqlite3_finalize(stmt); - } - return enumerator_create_empty(); -} - -/** - * Implementation of database_t.destroy - */ -static void destroy(private_database_t *this) -{ - sqlite3_close(this->db); - free(this); -} - -/* - * see header file - */ -database_t *database_create(char *dbfile) -{ - private_database_t *this = malloc_thing(private_database_t); - - this->public.login = (int(*)(database_t*, char *username, char *password))login; - this->public.create_gateway_enumerator = (enumerator_t*(*)(database_t*,int))create_gateway_enumerator; - this->public.destroy = (void(*)(database_t*))destroy; - - if (sqlite3_open(dbfile, &this->db) != SQLITE_OK) - { - destroy(this); - return NULL; - } - return &this->public; -} - diff --git a/src/manager/database.h b/src/manager/database.h deleted file mode 100644 index 228d1cb22..000000000 --- a/src/manager/database.h +++ /dev/null @@ -1,69 +0,0 @@ -/** - * @file database.h - * - * @brief Interface of database_t. - * - */ - -/* - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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 DATABASE_H_ -#define DATABASE_H_ - -#include - - -typedef struct database_t database_t; - -/** - * @brief Persistent database. - */ -struct database_t { - - /** - * @brief Try to log in using specified credentials. - * - * @param username username - * @param password plaintext password - * @return user ID if login good, 0 otherwise - */ - int (*login)(database_t *this, char *username, char *password); - - /** - * @brief Create an iterator over the gateways. - * - * enumerate() arguments: int id, char *name, int port, char *address - * If port is 0, address is a Unix socket address. - * - * @param user user Id - * @return enumerator - */ - enumerator_t* (*create_gateway_enumerator)(database_t *this, int user); - - /** - * @brief Destroy a database instance. - */ - void (*destroy)(database_t *this); -}; - -/** - * @brief Create a database instance. - * - * @param dbfile SQLite database file - */ -database_t *database_create(char *dbfile); - -#endif /* DATABASE_H_ */ diff --git a/src/manager/gateway.c b/src/manager/gateway.c index d4eb5279e..6d5f6f7d2 100644 --- a/src/manager/gateway.c +++ b/src/manager/gateway.c @@ -1,10 +1,3 @@ -/** - * @file gateway.c - * - * @brief Implementation of gateway_t. - * - */ - /* * Copyright (C) 2007 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,8 @@ * 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. + * + * $Id$ */ #include "gateway.h" @@ -29,7 +24,7 @@ #include #include -#include +#include typedef struct private_gateway_t private_gateway_t; diff --git a/src/manager/gateway.h b/src/manager/gateway.h index 81d8b9c3f..8c012d303 100644 --- a/src/manager/gateway.h +++ b/src/manager/gateway.h @@ -1,10 +1,3 @@ -/** - * @file gateway.h - * - * @brief Interface of gateway_t. - * - */ - /* * Copyright (C) 2007 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,13 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup gateway gateway + * @{ @ingroup manager */ #ifndef GATEWAY_H_ @@ -29,12 +29,12 @@ typedef struct gateway_t gateway_t; /** - * @brief A connection to a gateway. + * A connection to a gateway. */ struct gateway_t { /** - * @brief Send an XML request to the gateway. + * Send an XML request to the gateway. * * @param xml xml request string * @return allocated xml response string @@ -42,21 +42,21 @@ struct gateway_t { char* (*request)(gateway_t *this, char *xml); /** - * @brief Query the list of IKE_SAs and all its children. + * Query the list of IKE_SAs and all its children. * * @return enumerator over ikesa XML elements */ enumerator_t* (*query_ikesalist)(gateway_t *this); /** - * @brief Query the list of peer configs and its subconfigs. + * Query the list of peer configs and its subconfigs. * * @return enumerator over peerconfig XML elements */ enumerator_t* (*query_configlist)(gateway_t *this); /** - * @brief Terminate an IKE or a CHILD SA. + * Terminate an IKE or a CHILD SA. * * @param ike TRUE for IKE-, FALSE for a CHILD-SA * @param id ID of the SA to terminate @@ -65,7 +65,7 @@ struct gateway_t { enumerator_t* (*terminate)(gateway_t *this, bool ike, u_int32_t id); /** - * @brief Initiate an IKE or a CHILD SA. + * Initiate an IKE or a CHILD SA. * * @param ike TRUE for IKE-, FALSE for CHILD-SA * @param name name of the peer/child config @@ -74,13 +74,13 @@ struct gateway_t { enumerator_t* (*initiate)(gateway_t *this, bool ike, char *name); /** - * @brief Destroy a gateway instance. + * Destroy a gateway instance. */ void (*destroy)(gateway_t *this); }; /** - * @brief Create a gateway instance using a TCP connection. + * Create a gateway instance using a TCP connection. * * @param name name of the gateway * @param host gateway connection endpoint @@ -89,11 +89,11 @@ struct gateway_t { gateway_t *gateway_create_tcp(char *name, host_t *host); /** - * @brief Create a gateway instance using a UNIX socket. + * Create a gateway instance using a UNIX socket. * * @param name name of the gateway * @param */ gateway_t *gateway_create_unix(char *name); -#endif /* GATEWAY_H_ */ +#endif /* GATEWAY_H_ @} */ diff --git a/src/manager/lib/context.h b/src/manager/lib/context.h deleted file mode 100644 index 23c979b8e..000000000 --- a/src/manager/lib/context.h +++ /dev/null @@ -1,47 +0,0 @@ -/** - * @file context.h - * - * @brief Interface of context_t. - * - */ - -/* - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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 CONTEXT_H_ -#define CONTEXT_H_ - -typedef struct context_t context_t; - -/** - * @brief Constructor function for a context - */ -typedef context_t *(*context_constructor_t)(void *param); - -/** - * @brief Custom session context - * - */ -struct context_t { - - /** - * @brief Destroy the context_t. - * - * @param this calling object - */ - void (*destroy) (context_t *this); -}; - -#endif /* CONTEXT_H_ */ diff --git a/src/manager/lib/controller.h b/src/manager/lib/controller.h deleted file mode 100644 index 5b39f559c..000000000 --- a/src/manager/lib/controller.h +++ /dev/null @@ -1,84 +0,0 @@ -/** - * @file controller.h - * - * @brief Interface controller_t. - * - */ - -/* - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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 CONTROLLER_H_ -#define CONTROLLER_H_ - -#include "request.h" -#include "context.h" - -typedef struct controller_t controller_t; - -/** - * @brief Controller action handle function - * - * @param request http request - * @param response http response - */ -typedef void *(*controller_handler_t)(controller_t *this, request_t *request); - -/** - * @brief Constructor function for a controller - * - * @param context session specific context - * @param param user supplied param - */ -typedef controller_t *(*controller_constructor_t)(context_t* context, void *param); - -/** - * @brief Controller interface, to be implemented by users controllers. - * - */ -struct controller_t { - - /** - * @brief Get the name of the controller. - * - * @return name of the controller - */ - char* (*get_name)(controller_t *this); - - /** - * @brief Handle a HTTP request for that controller. - * - * Request URLs are parsed in the form - * controller_name/p1/p2/p3/p4/p5 with a maximum of 5 parameters. Each - * parameter not found in the request URL is set to NULL. - * - * @param request HTTP request - * @param p1 first parameter - * @param p2 second parameter - * @param p3 third parameter - * @param p4 forth parameter - * @param p5 fifth parameter - * @return - */ - void (*handle)(controller_t *this, request_t *request, - char *a1, char *a2, char *a3, char *a4, char *a5); - - /** - * @brief Destroy the controller instance. - */ - void (*destroy) (controller_t *this); -}; - -#endif /* CONTROLLER_H_ */ diff --git a/src/manager/lib/dispatcher.c b/src/manager/lib/dispatcher.c deleted file mode 100644 index ce53d39ea..000000000 --- a/src/manager/lib/dispatcher.c +++ /dev/null @@ -1,401 +0,0 @@ -/** - * @file dispatcher.c - * - * @brief Implementation of dispatcher_t. - * - */ - -/* - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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 "dispatcher.h" - -#include "request.h" -#include "session.h" - -#include -#include -#include -#include - -#include -#include - -typedef struct private_dispatcher_t private_dispatcher_t; - -/** - * private data of the task manager - */ -struct private_dispatcher_t { - - /** - * public functions - */ - dispatcher_t public; - - /** - * fcgi socket fd - */ - int fd; - - /** - * thread list - */ - pthread_t *threads; - - /** - * number of threads in "threads" - */ - int thread_count; - - /** - * session locking mutex - */ - pthread_mutex_t mutex; - - /** - * List of sessions - */ - linked_list_t *sessions; - - /** - * session timeout - */ - time_t timeout; - - /** - * List of controllers controller_constructor_t - */ - linked_list_t *controllers; - - /** - * constructor function to create session context (in constructor_entry_t) - */ - context_constructor_t context_constructor; - - /** - * user param to context constructor - */ - void *param; - - /** - * thread specific initialization handler - */ - void (*init)(void *param); - - /** - * argument to pass to thread intiializer - */ - void *init_param; - - /** - * thread specific deinitialization handler - */ - void (*deinit)(void *param); - - /** - * param tho thread specific deinitialization handler - */ - void *deinit_param; -}; - -typedef struct { - /** constructor function */ - controller_constructor_t constructor; - /** parameter to constructor */ - void *param; -} constructor_entry_t; - -typedef struct { - /** session instance */ - session_t *session; - /** condvar to wait for session */ - pthread_cond_t cond; - /** TRUE if session is in use */ - bool in_use; - /** last use of the session */ - time_t used; -} session_entry_t; - -/** - * create a session and instanciate controllers - */ -static session_t* load_session(private_dispatcher_t *this) -{ - iterator_t *iterator; - constructor_entry_t *entry; - session_t *session; - context_t *context = NULL; - controller_t *controller; - - if (this->context_constructor) - { - context = this->context_constructor(this->param); - } - session = session_create(context); - - iterator = this->controllers->create_iterator(this->controllers, TRUE); - while (iterator->iterate(iterator, (void**)&entry)) - { - controller = entry->constructor(context, entry->param); - session->add_controller(session, controller); - } - iterator->destroy(iterator); - - return session; -} - -/** - * create a new session entry - */ -static session_entry_t *session_entry_create(private_dispatcher_t *this) -{ - session_entry_t *entry; - - entry = malloc_thing(session_entry_t); - entry->in_use = FALSE; - pthread_cond_init(&entry->cond, NULL); - entry->session = load_session(this); - entry->used = time(NULL); - - return entry; -} - -static void session_entry_destroy(session_entry_t *entry) -{ - entry->session->destroy(entry->session); - free(entry); -} - -/** - * Implementation of dispatcher_t.add_controller. - */ -static void add_controller(private_dispatcher_t *this, - controller_constructor_t constructor, void *param) -{ - constructor_entry_t *entry = malloc_thing(constructor_entry_t); - - entry->constructor = constructor; - entry->param = param; - this->controllers->insert_last(this->controllers, entry); -} - -/** - * Actual dispatching code - */ -static void dispatch(private_dispatcher_t *this) -{ - FCGX_Request fcgi_req; - - if (FCGX_InitRequest(&fcgi_req, this->fd, 0) == 0) - { - while (TRUE) - { - request_t *request; - session_entry_t *current, *found = NULL; - iterator_t *iterator; - time_t now; - char *sid; - int accepted; - - pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); - accepted = FCGX_Accept_r(&fcgi_req); - pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); - - if (accepted != 0) - { - break; - } - - /* prepare */ - request = request_create(&fcgi_req, TRUE); - if (request == NULL) - { - continue; - } - sid = request->get_cookie(request, "SID"); - now = time(NULL); - - /* find session */ - pthread_mutex_lock(&this->mutex); - iterator = this->sessions->create_iterator(this->sessions, TRUE); - while (iterator->iterate(iterator, (void**)¤t)) - { - /* check all sessions for timeout */ - if (!current->in_use && - current->used < now - this->timeout) - { - iterator->remove(iterator); - session_entry_destroy(current); - continue; - } - if (!found && sid && - streq(current->session->get_sid(current->session), sid)) - { - found = current; - } - } - iterator->destroy(iterator); - - if (found) - { /* wait until session is unused */ - while (found->in_use) - { - pthread_cond_wait(&found->cond, &this->mutex); - } - } - else - { /* create a new session if not found */ - found = session_entry_create(this); - this->sessions->insert_first(this->sessions, found); - } - found->in_use = TRUE; - pthread_mutex_unlock(&this->mutex); - - /* start processing */ - found->session->process(found->session, request); - found->used = time(NULL); - - /* release session */ - pthread_mutex_lock(&this->mutex); - found->in_use = FALSE; - pthread_cond_signal(&found->cond); - pthread_mutex_unlock(&this->mutex); - - /* cleanup */ - request->destroy(request); - - /* - FCGX_FPrintF(fcgi_req.out, "
    "); - char **env = fcgi_req.envp; - while (*env) - { - FCGX_FPrintF(fcgi_req.out, "
  • %s
  • ", *env); - env++; - } - FCGX_FPrintF(fcgi_req.out, "
"); - */ - } - } -} - -/** - * Setup thread and start dispatching - */ -static void start_dispatching(private_dispatcher_t *this) -{ - pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); - if (this->init) - { - this->init(this->init_param); - } - if (this->deinit) - { - pthread_cleanup_push(this->deinit, this->deinit_param); - dispatch(this); - pthread_cleanup_pop(1); - } - else - { - dispatch(this); - } -} - -/** - * Implementation of dispatcher_t.run. - */ -static void run(private_dispatcher_t *this, int threads, - void(*init)(void *param), void *init_param, - void(*deinit)(void *param), void *deinit_param) -{ - this->init = init; - this->init_param = init_param; - this->deinit = deinit; - this->deinit_param = deinit_param; - this->thread_count = threads; - this->threads = malloc(sizeof(pthread_t) * threads); - while (threads) - { - if (pthread_create(&this->threads[threads - 1], - NULL, (void*)start_dispatching, this) == 0) - { - threads--; - } - } -} - -/** - * Implementation of dispatcher_t.waitsignal. - */ -static void waitsignal(private_dispatcher_t *this) -{ - sigset_t set; - int sig; - - sigemptyset(&set); - sigaddset(&set, SIGINT); - sigaddset(&set, SIGTERM); - sigaddset(&set, SIGHUP); - sigprocmask(SIG_BLOCK, &set, NULL); - sigwait(&set, &sig); -} - -/** - * Implementation of dispatcher_t.destroy - */ -static void destroy(private_dispatcher_t *this) -{ - FCGX_ShutdownPending(); - while (this->thread_count--) - { - pthread_cancel(this->threads[this->thread_count]); - pthread_join(this->threads[this->thread_count], NULL); - } - this->sessions->destroy_function(this->sessions, (void*)session_entry_destroy); - this->controllers->destroy_function(this->controllers, free); - free(this); -} - -/* - * see header file - */ -dispatcher_t *dispatcher_create(char *socket, int timeout, - context_constructor_t constructor, void *param) -{ - private_dispatcher_t *this = malloc_thing(private_dispatcher_t); - - this->public.add_controller = (void(*)(dispatcher_t*, controller_constructor_t, void*))add_controller; - this->public.run = (void(*)(dispatcher_t*, int threads,void(*)(void *),void *,void(*)(void *),void *))run; - this->public.waitsignal = (void(*)(dispatcher_t*))waitsignal; - this->public.destroy = (void(*)(dispatcher_t*))destroy; - - this->sessions = linked_list_create(); - this->controllers = linked_list_create(); - this->context_constructor = constructor; - pthread_mutex_init(&this->mutex, NULL); - this->param = param; - this->fd = 0; - this->timeout = timeout; - - FCGX_Init(); - - if (socket) - { - unlink(socket); - this->fd = FCGX_OpenSocket(socket, 10); - } - return &this->public; -} - diff --git a/src/manager/lib/dispatcher.h b/src/manager/lib/dispatcher.h deleted file mode 100644 index 274837838..000000000 --- a/src/manager/lib/dispatcher.h +++ /dev/null @@ -1,95 +0,0 @@ -/** - * @file dispatcher.h - * - * @brief Interface of dispatcher_t. - * - */ - -/* - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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 DISPATCHER_H_ -#define DISPATCHER_H_ - -#include "controller.h" - -typedef struct dispatcher_t dispatcher_t; - -/** - * @brief Dispatcher, accepts connections using multiple threads. - * - * The dispatcher creates a session for each client (using SID cookies). In - * each session, a session context is created using the context constructor. - * Each controller is instanciated in the session using the controller - * constructor added with add_controller. - */ -struct dispatcher_t { - - /** - * @brief Register a controller to the dispatcher. - * - * The first controller added serves as default controller. Client's - * get redirected to it if no other controller matches. - * - * @param constructor constructor function to the conntroller - * @param param param to pass to constructor - */ - void (*add_controller)(dispatcher_t *this, - controller_constructor_t constructor, void *param); - - /** - * @brief Start with dispatching. - * - * It may be necessary to call per-thread initialization functions. - * If init is not NULL, the handler is called right after thread - * creation (by the created thread) and the deinit function is called - * before the thread gets destroyed (again by the thread itself). - * - * @param thread number of dispatching threads - * @param init thread specific initialization function, or NULL - * @param init_param param to pass to init function - * @param deinit thread dpecific deinitialization function, or NULL - * @param deinit_param param to pass to deinit function - */ - void (*run)(dispatcher_t *this, int threads, - void(*init)(void *param), void *init_param, - void(*deinit)(void *param), void *deinit_param); - - /** - * @brief Wait for a relevant signal action. - */ - void (*waitsignal)(dispatcher_t *this); - - /** - * @brief Destroy the dispatcher_t. - */ - void (*destroy) (dispatcher_t *this); -}; - -/** - * @brief Create a dispatcher. - * - * The context constructor is invoked to create a session context for - * each session. - * - * @param socket FastCGI socket path, NULL for dynamic - * @param timeout session timeout - * @param constructor construction function for session context - * @param param parameter to supply to context constructor - */ -dispatcher_t *dispatcher_create(char *socket, int timeout, - context_constructor_t constructor, void *param); - -#endif /* DISPATCHER_H_ */ diff --git a/src/manager/lib/request.c b/src/manager/lib/request.c deleted file mode 100644 index bbaec10cc..000000000 --- a/src/manager/lib/request.c +++ /dev/null @@ -1,341 +0,0 @@ -/** - * @file request.c - * - * @brief Implementation of request_t. - * - */ - -/* - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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 "request.h" - -#include -#include -#include -#include -#include - -typedef struct private_request_t private_request_t; - -/** - * private data of the task manager - */ -struct private_request_t { - - /** - * public functions - */ - request_t public; - - /** - * FastCGI request object - */ - FCGX_Request *req; - - /** - * ClearSilver CGI Kit context - */ - CGI *cgi; - - /** - * ClearSilver HDF dataset for this request - */ - HDF *hdf; -}; - -/** - * key to a thread specific FCGX_Request, used for ClearSilver cgiwrap callbacks. - * ClearSilver cgiwrap is not threadsave, so we use a private - * context for each thread. - */ -static pthread_key_t req_key; - -/** - * length of param list in req->envp - */ -static pthread_key_t req_env_len_key; - -/** - * control variable for pthread_once - */ -pthread_once_t once = PTHREAD_ONCE_INIT; - -/** - * fcgiwrap read callback - */ -static int read_cb(void *null, char *buf, int size) -{ - FCGX_Request *req = (FCGX_Request*)pthread_getspecific(req_key); - return FCGX_GetStr(buf, size, req->in); -} - -/** - * fcgiwrap writef callback - */ -static int writef_cb(void *null, const char *format, va_list args) -{ - FCGX_Request *req = (FCGX_Request*)pthread_getspecific(req_key); - FCGX_VFPrintF(req->out, format, args); - return 0; -} -/** - * fcgiwrap write callback - */ -static int write_cb(void *null, const char *buf, int size) -{ - FCGX_Request *req = (FCGX_Request*)pthread_getspecific(req_key); - return FCGX_PutStr(buf, size, req->out); -} - -/** - * fcgiwrap getenv callback - */ -static char *getenv_cb(void *null, const char *key) -{ - char *value; - FCGX_Request *req = (FCGX_Request*)pthread_getspecific(req_key); - value = FCGX_GetParam(key, req->envp); - return value ? strdup(value) : NULL; -} - -/** - * fcgiwrap getenv callback - */ -static int putenv_cb(void *null, const char *key, const char *value) -{ - /* not supported */ - return 1; -} - -/** - * fcgiwrap iterenv callback - */ -static int iterenv_cb(void *null, int num, char **key, char **value) -{ - *key = NULL; - *value = NULL; - FCGX_Request *req = (FCGX_Request*)pthread_getspecific(req_key); - int req_env_len = (int)pthread_getspecific(req_env_len_key); - if (num < req_env_len) - { - char *eq; - - eq = strchr(req->envp[num], '='); - if (eq) - { - *key = strndup(req->envp[num], eq - req->envp[num]); - *value = strdup(eq + 1); - } - if (*key == NULL || *value == NULL) - { - free(*key); - free(*value); - return 1; - } - } - return 0; -} - -/** - * Implementation of request_t.get_cookie. - */ -static char* get_cookie(private_request_t *this, char *name) -{ - return hdf_get_valuef(this->hdf, "Cookie.%s", name); -} - -/** - * Implementation of request_t.get_path. - */ -static char* get_path(private_request_t *this) -{ - char * path = FCGX_GetParam("PATH_INFO", this->req->envp); - return path ? path : ""; -} - -/** - * Implementation of request_t.get_post_data. - */ -static char* get_query_data(private_request_t *this, char *name) -{ - return hdf_get_valuef(this->hdf, "Query.%s", name); -} - -/** - * Implementation of request_t.add_cookie. - */ -static void add_cookie(private_request_t *this, char *name, char *value) -{ - cgi_cookie_set (this->cgi, name, value, - FCGX_GetParam("SCRIPT_NAME", this->req->envp), - NULL, NULL, 0, 0); -} - -/** - * Implementation of request_t.redirect. - */ -static void redirect(private_request_t *this, char *fmt, ...) -{ - va_list args; - - FCGX_FPrintF(this->req->out, "Status: 303 See Other\n"); - FCGX_FPrintF(this->req->out, "Location: %s%s", - FCGX_GetParam("SCRIPT_NAME", this->req->envp), - *fmt == '/' ? "" : "/"); - va_start(args, fmt); - FCGX_VFPrintF(this->req->out, fmt, args); - va_end(args); - FCGX_FPrintF(this->req->out, "\n\n"); -} - -/** - * Implementation of request_t.get_base. - */ -static char* get_base(private_request_t *this) -{ - return FCGX_GetParam("SCRIPT_NAME", this->req->envp); -} - -/** - * Implementation of request_t.serve. - */ -static void serve(private_request_t *this, char *headers, chunk_t chunk) -{ - FCGX_FPrintF(this->req->out, "%s\n\n", headers); - - FCGX_PutStr(chunk.ptr, chunk.len, this->req->out); -} - -/** - * Implementation of request_t.render. - */ -static void render(private_request_t *this, char *template) -{ - NEOERR* err; - - err = cgi_display(this->cgi, template); - if (err) - { - cgi_neo_error(this->cgi, err); - nerr_log_error(err); - } - return; -} - -/** - * Implementation of request_t.set. - */ -static void set(private_request_t *this, char *key, char *value) -{ - hdf_set_value(this->hdf, key, value); -} - -/** - * Implementation of request_t.setf. - */ -static void setf(private_request_t *this, char *format, ...) -{ - va_list args; - - va_start(args, format); - hdf_set_valuevf(this->hdf, format, args); - va_end(args); -} - -/** - * Implementation of request_t.destroy - */ -static void destroy(private_request_t *this) -{ - cgi_destroy(&this->cgi); - free(this); -} - -/** - * This initialization method is guaranteed to run only once - * for all threads. - */ -static void init(void) -{ - cgiwrap_init_emu(NULL, read_cb, writef_cb, write_cb, - getenv_cb, putenv_cb, iterenv_cb); - pthread_key_create(&req_key, NULL); - pthread_key_create(&req_env_len_key, NULL); -} - -/* - * see header file - */ -request_t *request_create(FCGX_Request *request, bool debug) -{ - NEOERR* err; - private_request_t *this = malloc_thing(private_request_t); - - this->public.get_path = (char*(*)(request_t*))get_path; - this->public.get_base = (char*(*)(request_t*))get_base; - this->public.add_cookie = (void(*)(request_t*, char *name, char *value))add_cookie; - this->public.get_cookie = (char*(*)(request_t*,char*))get_cookie; - this->public.get_query_data = (char*(*)(request_t*, char *name))get_query_data; - this->public.redirect = (void(*)(request_t*, char *fmt,...))redirect; - this->public.render = (void(*)(request_t*,char*))render; - this->public.serve = (void(*)(request_t*,char*,chunk_t))serve; - this->public.set = (void(*)(request_t*, char *, char*))set; - this->public.setf = (void(*)(request_t*, char *format, ...))setf; - this->public.destroy = (void(*)(request_t*))destroy; - - pthread_once(&once, init); - - this->req = request; - pthread_setspecific(req_key, (void*)request); - - int req_env_len = 0; - while (request->envp[req_env_len] != NULL) - { - req_env_len++; - } - - pthread_setspecific(req_env_len_key, (void*)req_env_len); - - err = hdf_init(&this->hdf); - if (!err) - { - hdf_set_value(this->hdf, "base", get_base(this)); - hdf_set_value(this->hdf, "Config.NoCache", "true"); - if (!debug) - { - hdf_set_value(this->hdf, "Config.TimeFooter", "0"); - hdf_set_value(this->hdf, "Config.CompressionEnabled", "1"); - hdf_set_value(this->hdf, "Config.WhiteSpaceStrip", "2"); - } - - err = cgi_init(&this->cgi, this->hdf); - if (!err) - { - err = cgi_parse(this->cgi); - if (!err) - { - return &this->public; - } - cgi_destroy(&this->cgi); - } - } - nerr_log_error(err); - free(this); - return NULL; -} - diff --git a/src/manager/lib/request.h b/src/manager/lib/request.h deleted file mode 100644 index f78741d37..000000000 --- a/src/manager/lib/request.h +++ /dev/null @@ -1,135 +0,0 @@ -/** - * @file request.h - * - * @brief Interface of request_t. - * - */ - -/* - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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 REQUEST_H_ -#define REQUEST_H_ - -#include -#include - -typedef struct request_t request_t; - -/** - * @brief A HTTP request, encapsulates FCGX_Request. - * - */ -struct request_t { - - /** - * @brief Add a cookie to the reply (Set-Cookie header). - * - * @param name name of the cookie to set - * @param value value of the cookie - */ - void (*add_cookie)(request_t *this, char *name, char *value); - - /** - * @brief Get a cookie the client sent in the request. - * - * @param name name of the cookie - * @return cookie value, NULL if no such cookie found - */ - char* (*get_cookie)(request_t *this, char *name); - - /** - * @brief Get the request path relative to the application. - * - * @return path - */ - char* (*get_path)(request_t *this); - - /** - * @brief Get the base path of the application. - * - * @return base path - */ - char* (*get_base)(request_t *this); - - /** - * @brief Get a post/get variable included in the request. - * - * @param name name of the POST/GET variable - * @return value, NULL if not found - */ - char* (*get_query_data)(request_t *this, char *name); - - /** - * @brief Redirect the client to another location. - * - * @param fmt location format string - * @param ... variable argument for fmt - */ - void (*redirect)(request_t *this, char *fmt, ...); - - /** - * @brief Set a template value. - * - * @param key key to set - * @param value value to set key to - */ - void (*set)(request_t *this, char *key, char *value); - - /** - * @brief Set a template value using format strings. - * - * Format string is in the form "key=value", where printf like format - * substitution occurs over the whole string. - * - * @param format printf like format string - * @param ... variable argument list - */ - void (*setf)(request_t *this, char *format, ...); - - /** - * @brief Render a template. - * - * The render() function additionally sets a HDF variable "base" - * which points to the root of the web application and allows to point to - * other targets without to worry about path location. - * - * @param template clearsilver template file location - */ - void (*render)(request_t *this, char *template); - - /** - * @brief Serve a request with headers and a body. - * - * @param headers HTTP headers, \n separated - * @param chunk body to write to output - */ - void (*serve)(request_t *this, char *headers, chunk_t chunk); - - /** - * @brief Destroy the request_t. - */ - void (*destroy) (request_t *this); -}; - -/** - * @brief Create a request from the fastcgi struct. - * - * @param request the FCGI request - * @param debug no stripping, no compression, timing information - */ -request_t *request_create(FCGX_Request *request, bool debug); - -#endif /* REQUEST_H_ */ diff --git a/src/manager/lib/session.c b/src/manager/lib/session.c deleted file mode 100644 index fe260b887..000000000 --- a/src/manager/lib/session.c +++ /dev/null @@ -1,175 +0,0 @@ -/** - * @file session.c - * - * @brief Implementation of session_t. - * - */ - -/* - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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 "session.h" - -#include -#include -#include - -#include -#include - -typedef struct private_session_t private_session_t; - -/** - * private data of the task manager - */ -struct private_session_t { - - /** - * public functions - */ - session_t public; - - /** - * session ID - */ - char *sid; - - /** - * list of controller instances controller_t - */ - linked_list_t *controllers; - - /** - * user defined session context - */ - context_t *context; -}; - -/** - * Implementation of session_t.load_controller. - */ -static void add_controller(private_session_t *this, controller_t *controller) -{ - this->controllers->insert_last(this->controllers, controller); -} - -/** - * Create a session ID and a cookie - */ -static void create_sid(private_session_t *this, request_t *request) -{ - char buf[16]; - chunk_t chunk = chunk_from_buf(buf); - randomizer_t *randomizer = randomizer_create(); - - randomizer->get_pseudo_random_bytes(randomizer, sizeof(buf), buf); - this->sid = chunk_to_hex(chunk, FALSE); - request->add_cookie(request, "SID", this->sid); - randomizer->destroy(randomizer); -} - -/** - * Implementation of session_t.process. - */ -static void process(private_session_t *this, request_t *request) -{ - char *pos, *start, *param[6] = {NULL, NULL, NULL, NULL, NULL, NULL}; - iterator_t *iterator; - bool handled = FALSE; - controller_t *current; - int i = 0; - - if (this->sid == NULL) - { - create_sid(this, request); - } - - start = request->get_path(request); - if (start) - { - if (*start == '/') start++; - while ((pos = strchr(start, '/')) != NULL && i < 5) - { - param[i++] = strndup(start, pos - start); - start = pos + 1; - } - param[i] = strdup(start); - iterator = this->controllers->create_iterator(this->controllers, TRUE); - while (iterator->iterate(iterator, (void**)¤t)) - { - if (streq(current->get_name(current), param[0])) - { - current->handle(current, request, param[1], param[2], param[3], - param[4], param[5]); - handled = TRUE; - break; - } - } - iterator->destroy(iterator); - for (i = 0; i < 6; i++) - { - free(param[i]); - } - } - if (!handled) - { - if (this->controllers->get_first(this->controllers, - (void**)¤t) == SUCCESS) - { - request->redirect(request, current->get_name(current)); - } - } -} - -/** - * Implementation of session_t.get_sid. - */ -static char* get_sid(private_session_t *this) -{ - return this->sid; -} - -/** - * Implementation of session_t.destroy - */ -static void destroy(private_session_t *this) -{ - this->controllers->destroy_offset(this->controllers, offsetof(controller_t, destroy)); - if (this->context) this->context->destroy(this->context); - free(this->sid); - free(this); -} - -/* - * see header file - */ -session_t *session_create(context_t *context) -{ - private_session_t *this = malloc_thing(private_session_t); - - this->public.add_controller = (void(*)(session_t*, controller_t*))add_controller; - this->public.process = (void(*)(session_t*,request_t*))process; - this->public.get_sid = (char*(*)(session_t*))get_sid; - this->public.destroy = (void(*)(session_t*))destroy; - - this->sid = NULL; - this->controllers = linked_list_create(); - this->context = context; - - return &this->public; -} - diff --git a/src/manager/lib/session.h b/src/manager/lib/session.h deleted file mode 100644 index d18545876..000000000 --- a/src/manager/lib/session.h +++ /dev/null @@ -1,73 +0,0 @@ -/** - * @file session.h - * - * @brief Interface of session_t. - * - */ - -/* - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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 SESSION_H_ -#define SESSION_H_ - -#include "request.h" -#include "controller.h" - -typedef struct session_t session_t; - -/** - * @brief A session, identified by a session ID. - * - */ -struct session_t { - - /** - * @brief Get the session ID of the session. - * - * @return session ID - */ - char* (*get_sid)(session_t *this); - - /** - * @brief Add a controller instance to the session. - * - * @param controller controller to add - */ - void (*add_controller)(session_t *this, controller_t *controller); - - /** - * @brief Process a request in this session. - * - * @param request request to process - */ - void (*process)(session_t *this, request_t *request); - - /** - * @brief Destroy the session_t. - * - * @param this calling object - */ - void (*destroy) (session_t *this); -}; - -/** - * @brief Create a session. - * - * @param context user defined session context instance - */ -session_t *session_create(context_t *context); - -#endif /* SESSION_H_ */ diff --git a/src/manager/lib/xml.c b/src/manager/lib/xml.c deleted file mode 100644 index 008235b69..000000000 --- a/src/manager/lib/xml.c +++ /dev/null @@ -1,169 +0,0 @@ -/** - * @file xml.c - * - * @brief Implementation of xml_t. - * - */ - -/* - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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 "xml.h" - -#include -#include - - -typedef struct private_xml_t private_xml_t; - -/** - * private data of xml - */ -struct private_xml_t { - - /** - * public functions - */ - xml_t public; - - /** - * root node of this xml (part) - */ - xmlNode *node; - - /** - * document, only for root xml_t - */ - xmlDoc *doc; - - /** - * Root xml_t* - */ - private_xml_t *root; - - /** - * number of enumerator instances - */ - int enums; -}; - -/** - * child element enumerator - */ -typedef struct { - /** enumerator interface */ - enumerator_t e; - /** current child context (returned to enumerate() caller) */ - private_xml_t child; - /** currently processing node */ - xmlNode *node; -} child_enum_t; - -/** - * Implementation of xml_t.children().enumerate(). - */ -static bool child_enumerate(child_enum_t *e, private_xml_t **child, - char **name, char **value) -{ - while (e->node && e->node->type != XML_ELEMENT_NODE) - { - e->node = e->node->next; - } - if (e->node) - { - xmlNode *text; - - text = e->node->children; - *value = NULL; - - while (text && text->type != XML_TEXT_NODE) - { - text = text->next; - } - if (text) - { - *value = text->content; - } - *name = (char*)e->node->name; - *child = &e->child; - e->child.node = e->node->children; - e->node = e->node->next; - return TRUE; - } - return FALSE; -} - -/** - * Implementation of xml_t.get_attribute. - */ -static char* get_attribute(private_xml_t *this, char *name) -{ - return NULL; -} - -/** - * destroy enumerator, and complete tree if this was the last enumerator - */ -static void child_destroy(child_enum_t *this) -{ - if (--this->child.root->enums == 0) - { - xmlFreeDoc(this->child.root->doc); - free(this->child.root); - } - free(this); -} - -/** - * Implementation of xml_t.children. - */ -static enumerator_t* children(private_xml_t *this) -{ - child_enum_t *ce = malloc_thing(child_enum_t); - ce->e.enumerate = (void*)child_enumerate; - ce->e.destroy = (void*)child_destroy; - ce->node = this->node; - ce->child.public.children = (void*)children; - ce->child.public.get_attribute = (void*)get_attribute; - ce->child.node = NULL; - ce->child.doc = this->doc; - ce->child.root = this->root; - this->root->enums++; - return &ce->e; -} - -/* - * see header file - */ -xml_t *xml_create(char *xml) -{ - private_xml_t *this = malloc_thing(private_xml_t); - - this->public.get_attribute = (char*(*)(xml_t*,char*))get_attribute; - this->public.children = (enumerator_t*(*)(xml_t*))children; - - this->doc = xmlReadMemory(xml, strlen(xml), NULL, NULL, 0); - if (this->doc == NULL) - { - free(this); - return NULL; - } - this->node = xmlDocGetRootElement(this->doc); - this->root = this; - this->enums = 0; - - return &this->public; -} - diff --git a/src/manager/lib/xml.h b/src/manager/lib/xml.h deleted file mode 100644 index 738a8e1b3..000000000 --- a/src/manager/lib/xml.h +++ /dev/null @@ -1,63 +0,0 @@ -/** - * @file xml.h - * - * @brief Interface of xml_t. - * - */ - -/* - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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 XML_H_ -#define XML_H_ - -#include - -typedef struct xml_t xml_t; - -/** - * @brief Simple enumerator based XML parser. - * - * An xml_t is a single node of the XML tree, but also serves as root node - * and therefore the document. - * This object has no destructor, the tree gets destroyed when all enumerator - * instances get destroyed. - */ -struct xml_t { - - /** - * @brief Create an enumerator over all children. - * - * Enumerated values must not be manipulated or freed. - * - * @return enumerator over (xml_t* child, char *name, char *value) - */ - enumerator_t* (*children)(xml_t *this); - - /** - * @brief Get an attribute value by its name. - * - * @param name name of the attribute - * @return attribute value, NULL if not found - */ - char *(*get_attribute)(xml_t *this, char *name); -}; - -/** - * @brief Create a xml instance. - */ -xml_t *xml_create(char *xml); - -#endif /* XML_H_ */ diff --git a/src/manager/main.c b/src/manager/main.c index eb4654ced..fc1f5fc2d 100644 --- a/src/manager/main.c +++ b/src/manager/main.c @@ -1,10 +1,3 @@ -/** - * @file main.c - * - * @brief Implementation of dispatcher_t. - * - */ - /* * Copyright (C) 2007 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,13 +11,15 @@ * 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. + * + * $Id$ */ #include #include #include "manager.h" -#include "database.h" +#include "storage.h" #include "controller/auth_controller.h" #include "controller/ikesa_controller.h" #include "controller/gateway_controller.h" @@ -38,34 +33,40 @@ int main (int arc, char *argv[]) { dispatcher_t *dispatcher; - database_t *database; + storage_t *storage; char *socket = NULL; + bool debug = FALSE; #ifdef FCGI_SOCKET socket = FCGI_SOCKET; + debug = TRUE; #endif /* FCGI_SOCKET */ + + library_init(IPSECDIR "/manager.conf"); - database = database_create(DBFILE); - if (database == NULL) + storage = storage_create("sqlite://"DBFILE); + if (storage == NULL) { fprintf(stderr, "opening database '%s' failed.\n", DBFILE); return 1; } - dispatcher = dispatcher_create(socket, SESSION_TIMEOUT, - (context_constructor_t)manager_create, database); + dispatcher = dispatcher_create(socket, debug, SESSION_TIMEOUT, + (context_constructor_t)manager_create, storage); dispatcher->add_controller(dispatcher, ikesa_controller_create, NULL); dispatcher->add_controller(dispatcher, gateway_controller_create, NULL); dispatcher->add_controller(dispatcher, auth_controller_create, NULL); dispatcher->add_controller(dispatcher, control_controller_create, NULL); dispatcher->add_controller(dispatcher, config_controller_create, NULL); - dispatcher->run(dispatcher, THREADS, NULL, NULL, NULL, NULL); + dispatcher->run(dispatcher, THREADS); dispatcher->waitsignal(dispatcher); dispatcher->destroy(dispatcher); - database->destroy(database); + storage->destroy(storage); + + library_deinit(); return 0; } diff --git a/src/manager/manager.c b/src/manager/manager.c index 39c8d995a..2bf2869b5 100644 --- a/src/manager/manager.c +++ b/src/manager/manager.c @@ -1,10 +1,3 @@ -/** - * @file manager.c - * - * @brief Implementation of manager_t. - * - */ - /* * Copyright (C) 2007 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,6 +11,8 @@ * 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. + * + * $Id$ */ #include "manager.h" @@ -39,9 +34,9 @@ struct private_manager_t { manager_t public; /** - * underlying database + * underlying storage database */ - database_t *db; + storage_t *store; /** * user id, if we are logged in @@ -59,7 +54,7 @@ struct private_manager_t { */ static enumerator_t* create_gateway_enumerator(private_manager_t *this) { - return this->db->create_gateway_enumerator(this->db, this->user); + return this->store->create_gateway_enumerator(this->store, this->user); } /** @@ -77,7 +72,7 @@ static gateway_t* select_gateway(private_manager_t *this, int select_id) if (this->gateway) this->gateway->destroy(this->gateway); this->gateway = NULL; - enumerator = this->db->create_gateway_enumerator(this->db, this->user); + enumerator = this->store->create_gateway_enumerator(this->store, this->user); while (enumerator->enumerate(enumerator, &id, &name, &port, &address)) { if (select_id == id) @@ -117,7 +112,7 @@ static bool login(private_manager_t *this, char *username, char *password) { if (!this->user) { - this->user = this->db->login(this->db, username, password); + this->user = this->store->login(this->store, username, password); } return this->user != 0; } @@ -147,7 +142,7 @@ static void destroy(private_manager_t *this) /* * see header file */ -manager_t *manager_create(database_t *database) +manager_t *manager_create(storage_t *storage) { private_manager_t *this = malloc_thing(private_manager_t); @@ -159,7 +154,7 @@ manager_t *manager_create(database_t *database) this->public.context.destroy = (void(*)(context_t*))destroy; this->user = 0; - this->db = database; + this->store = storage; this->gateway = NULL; return &this->public; diff --git a/src/manager/manager.h b/src/manager/manager.h index 4235618cd..53808b794 100644 --- a/src/manager/manager.h +++ b/src/manager/manager.h @@ -1,10 +1,3 @@ -/** - * @file manager.h - * - * @brief Interface of manager_t. - * - */ - /* * Copyright (C) 2007 Martin Willi * Hochschule fuer Technik Rapperswil @@ -18,12 +11,24 @@ * 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. + * + * $Id$ + */ + +/** + * @defgroup manager manager + * + * @defgroup controller controller + * @ingroup manager + * + * @defgroup manager_i manager + * @{ @ingroup manager */ #ifndef MANAGER_H_ #define MANAGER_H_ -#include "database.h" +#include "storage.h" #include "gateway.h" #include @@ -33,7 +38,7 @@ typedef struct manager_t manager_t; /** - * @brief The manager, manages multiple gateways. + * The manager, manages multiple gateways. */ struct manager_t { @@ -43,7 +48,7 @@ struct manager_t { context_t context; /** - * @brief Create an iterator over all configured gateways. + * Create an iterator over all configured gateways. * * enumerate() arguments: int id, char *name, int port, char *address * If port is 0, address is a Unix socket address. @@ -53,7 +58,7 @@ struct manager_t { enumerator_t* (*create_gateway_enumerator)(manager_t *this); /** - * @brief Select a gateway. + * Select a gateway. * * If id is 0, the previously selected gateway is returned. If none has * been selected yet, NULL is returned. @@ -64,7 +69,7 @@ struct manager_t { gateway_t* (*select_gateway)(manager_t *this, int id); /** - * @brief Try to log in. + * Try to log in. * * @param username username * @param password cleartext password @@ -73,21 +78,21 @@ struct manager_t { bool (*login)(manager_t *this, char *username, char *password); /** - * @brief Check if user logged in. + * Check if user logged in. * * @return TRUE if logged in */ bool (*logged_in)(manager_t *this); /** - * @brief Log out. + * Log out. */ void (*logout)(manager_t *this); }; /** - * @brief Create a manager instance. + * Create a manager instance. */ -manager_t *manager_create(database_t *database); +manager_t *manager_create(storage_t *storage); -#endif /* MANAGER_H_ */ +#endif /* MANAGER_H_ @} */ diff --git a/src/manager/storage.c b/src/manager/storage.c new file mode 100644 index 000000000..87e0374a7 --- /dev/null +++ b/src/manager/storage.c @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "storage.h" + +#include +#include + + +typedef struct private_storage_t private_storage_t; + +/** + * private data of storage + */ +struct private_storage_t { + + /** + * public functions + */ + storage_t public; + + /** + * database connection + */ + database_t *db; +}; + +/** + * Implementation of storage_t.login. + */ +static int login(private_storage_t *this, char *username, char *password) +{ + hasher_t *hasher; + chunk_t hash, data; + size_t username_len, password_len; + int uid = 0; + char *str; + enumerator_t *enumerator; + + /* hash = SHA1( username | password ) */ + hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); + if (hasher == NULL) + { + return 0; + } + hash = chunk_alloca(hasher->get_hash_size(hasher)); + username_len = strlen(username); + password_len = strlen(password); + data = chunk_alloca(username_len + password_len); + memcpy(data.ptr, username, username_len); + memcpy(data.ptr + username_len, password, password_len); + hasher->get_hash(hasher, data, hash.ptr); + hasher->destroy(hasher); + str = chunk_to_hex(hash, FALSE); + + enumerator = this->db->query(this->db, + "SELECT oid FROM users WHERE username = ? AND password = ?;", + DB_TEXT, username, DB_TEXT, str, + DB_INT); + if (enumerator) + { + enumerator->enumerate(enumerator, &uid); + enumerator->destroy(enumerator); + } + free(str); + return uid; +} + +/** + * Implementation of storage_t.create_gateway_enumerator. + */ +static enumerator_t* create_gateway_enumerator(private_storage_t *this, int user) +{ + enumerator_t *enumerator; + + enumerator = this->db->query(this->db, + "SELECT gateways.oid AS gid, name, port, address FROM " + "gateways, user_gateway AS ug ON gid = ug.gateway WHERE ug.user = ?;", + DB_INT, user, + DB_INT, DB_TEXT, DB_INT, DB_TEXT); + if (!enumerator) + { + enumerator = enumerator_create_empty(); + } + return enumerator; +} + +/** + * Implementation of storage_t.destroy + */ +static void destroy(private_storage_t *this) +{ + this->db->destroy(this->db); + free(this); +} + +/* + * see header file + */ +storage_t *storage_create(char *uri) +{ + private_storage_t *this = malloc_thing(private_storage_t); + + this->public.login = (int(*)(storage_t*, char *username, char *password))login; + this->public.create_gateway_enumerator = (enumerator_t*(*)(storage_t*,int))create_gateway_enumerator; + this->public.destroy = (void(*)(storage_t*))destroy; + + this->db = lib->db->create(lib->db, uri); + if (this->db == NULL) + { + free(this); + return NULL; + } + return &this->public; +} + diff --git a/src/manager/storage.h b/src/manager/storage.h new file mode 100644 index 000000000..b7439ffd1 --- /dev/null +++ b/src/manager/storage.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +/** + * @defgroup storage storage + * @{ @ingroup manager + */ + +#ifndef STORAGE_H_ +#define STORAGE_H_ + +#include + + +typedef struct storage_t storage_t; + +/** + * Persistent database storage. + */ +struct storage_t { + + /** + * Try to log in using specified credentials. + * + * @param username username + * @param password plaintext password + * @return user ID if login good, 0 otherwise + */ + int (*login)(storage_t *this, char *username, char *password); + + /** + * Create an iterator over the gateways. + * + * enumerate() arguments: int id, char *name, int port, char *address + * If port is 0, address is a Unix socket address. + * + * @param user user Id + * @return enumerator + */ + enumerator_t* (*create_gateway_enumerator)(storage_t *this, int user); + + /** + * Destroy a storage instance. + */ + void (*destroy)(storage_t *this); +}; + +/** + * Create a storage instance. + * + * @param uri database connection URI + */ +storage_t *storage_create(char *uri); + +#endif /* STORAGE_H_ @} */ diff --git a/src/manager/xml.c b/src/manager/xml.c new file mode 100644 index 000000000..17e7752ab --- /dev/null +++ b/src/manager/xml.c @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +#include "xml.h" + +#include +#include + + +typedef struct private_xml_t private_xml_t; + +/** + * private data of xml + */ +struct private_xml_t { + + /** + * public functions + */ + xml_t public; + + /** + * root node of this xml (part) + */ + xmlNode *node; + + /** + * document, only for root xml_t + */ + xmlDoc *doc; + + /** + * Root xml_t* + */ + private_xml_t *root; + + /** + * number of enumerator instances + */ + int enums; +}; + +/** + * child element enumerator + */ +typedef struct { + /** enumerator interface */ + enumerator_t e; + /** current child context (returned to enumerate() caller) */ + private_xml_t child; + /** currently processing node */ + xmlNode *node; +} child_enum_t; + +/** + * Implementation of xml_t.children().enumerate(). + */ +static bool child_enumerate(child_enum_t *e, private_xml_t **child, + char **name, char **value) +{ + while (e->node && e->node->type != XML_ELEMENT_NODE) + { + e->node = e->node->next; + } + if (e->node) + { + xmlNode *text; + + text = e->node->children; + *value = NULL; + + while (text && text->type != XML_TEXT_NODE) + { + text = text->next; + } + if (text) + { + *value = text->content; + } + *name = (char*)e->node->name; + *child = &e->child; + e->child.node = e->node->children; + e->node = e->node->next; + return TRUE; + } + return FALSE; +} + +/** + * Implementation of xml_t.get_attribute. + */ +static char* get_attribute(private_xml_t *this, char *name) +{ + return NULL; +} + +/** + * destroy enumerator, and complete tree if this was the last enumerator + */ +static void child_destroy(child_enum_t *this) +{ + if (--this->child.root->enums == 0) + { + xmlFreeDoc(this->child.root->doc); + free(this->child.root); + } + free(this); +} + +/** + * Implementation of xml_t.children. + */ +static enumerator_t* children(private_xml_t *this) +{ + child_enum_t *ce = malloc_thing(child_enum_t); + ce->e.enumerate = (void*)child_enumerate; + ce->e.destroy = (void*)child_destroy; + ce->node = this->node; + ce->child.public.children = (void*)children; + ce->child.public.get_attribute = (void*)get_attribute; + ce->child.node = NULL; + ce->child.doc = this->doc; + ce->child.root = this->root; + this->root->enums++; + return &ce->e; +} + +/* + * see header file + */ +xml_t *xml_create(char *xml) +{ + private_xml_t *this = malloc_thing(private_xml_t); + + this->public.get_attribute = (char*(*)(xml_t*,char*))get_attribute; + this->public.children = (enumerator_t*(*)(xml_t*))children; + + this->doc = xmlReadMemory(xml, strlen(xml), NULL, NULL, 0); + if (this->doc == NULL) + { + free(this); + return NULL; + } + this->node = xmlDocGetRootElement(this->doc); + this->root = this; + this->enums = 0; + + return &this->public; +} + diff --git a/src/manager/xml.h b/src/manager/xml.h new file mode 100644 index 000000000..14458a2d0 --- /dev/null +++ b/src/manager/xml.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * $Id$ + */ + +/** + * @defgroup xml xml + * @{ @ingroup manager + */ + +#ifndef XML_H_ +#define XML_H_ + +#include + +typedef struct xml_t xml_t; + +/** + * Simple enumerator based XML parser. + * + * An xml_t is a single node of the XML tree, but also serves as root node + * and therefore the document. + * This object has no destructor, the tree gets destroyed when all enumerator + * instances get destroyed. + */ +struct xml_t { + + /** + * Create an enumerator over all children. + * + * Enumerated values must not be manipulated or freed. + * + * @return enumerator over (xml_t* child, char *name, char *value) + */ + enumerator_t* (*children)(xml_t *this); + + /** + * Get an attribute value by its name. + * + * @param name name of the attribute + * @return attribute value, NULL if not found + */ + char *(*get_attribute)(xml_t *this, char *name); +}; + +/** + * Create a xml instance. + */ +xml_t *xml_create(char *xml); + +#endif /* XML_H_ @} */ diff --git a/src/pluto/Makefile.am b/src/pluto/Makefile.am index 69902ad8f..f7125b920 100644 --- a/src/pluto/Makefile.am +++ b/src/pluto/Makefile.am @@ -123,12 +123,14 @@ if USE_NAT_TRANSPORT endif # This compile option activates dynamic URL fetching using libcurl -if USE_LIBCURL +if USE_CURL pluto_LDADD += -lcurl + AM_CFLAGS += -DLIBCURL endif # This compile option activates dynamic LDAP CRL fetching -if USE_LIBLDAP +if USE_LDAP pluto_LDADD += -lldap -llber + AM_CFLAGS += -DLIBLDAP endif diff --git a/src/scepclient/Makefile.am b/src/scepclient/Makefile.am index 3a5f9839f..d1bce886d 100644 --- a/src/scepclient/Makefile.am +++ b/src/scepclient/Makefile.am @@ -23,11 +23,6 @@ scepclient_LDADD = asn1.o ca.o crl.o certs.o constants.o defs.o fetch.o id.o \ $(LIBFREESWANDIR)/libfreeswan.a $(LIBCRYPTODIR)/libcrypto.a \ -lgmp -# This compile option activates dynamic URL fetching using libcurl -if USE_LIBCURL - scepclient_LDADD += -lcurl -endif - # This compile option activates smartcard support if USE_SMARTCARD scepclient_LDADD += -ldl diff --git a/src/starter/args.c b/src/starter/args.c index 7b4fcaabb..2520bf8df 100644 --- a/src/starter/args.c +++ b/src/starter/args.c @@ -172,7 +172,6 @@ static const token_info_t token_info[] = { ARG_ENUM, offsetof(starter_config_t, setup.nat_traversal), LST_bool }, { ARG_TIME, offsetof(starter_config_t, setup.keep_alive), NULL }, { ARG_STR, offsetof(starter_config_t, setup.virtual_private), NULL }, - { ARG_STR, offsetof(starter_config_t, setup.eapdir), NULL }, { ARG_STR, offsetof(starter_config_t, setup.pkcs11module), NULL }, { ARG_STR, offsetof(starter_config_t, setup.pkcs11initargs), NULL }, { ARG_ENUM, offsetof(starter_config_t, setup.pkcs11keepstate), LST_bool }, diff --git a/src/starter/confread.h b/src/starter/confread.h index 3f1884048..3270eab10 100644 --- a/src/starter/confread.h +++ b/src/starter/confread.h @@ -185,7 +185,6 @@ struct starter_config { bool nat_traversal; u_int keep_alive; char *virtual_private; - char *eapdir; char *pkcs11module; char *pkcs11initargs; bool pkcs11keepstate; diff --git a/src/starter/invokecharon.c b/src/starter/invokecharon.c index 3da407d50..d69b2ced2 100644 --- a/src/starter/invokecharon.c +++ b/src/starter/invokecharon.c @@ -118,11 +118,6 @@ starter_start_charon (starter_config_t *cfg, bool debug) { arg[argc++] = "--use-syslog"; } - if (cfg->setup.strictcrlpolicy) - { - arg[argc++] = "--strictcrlpolicy"; - arg[argc++] = cfg->setup.strictcrlpolicy == STRICT_IFURI ? "2":"1"; - } if (cfg->setup.cachecrls) { arg[argc++] = "--cachecrls"; @@ -133,11 +128,6 @@ starter_start_charon (starter_config_t *cfg, bool debug) arg[argc++] = "--crlcheckinterval"; arg[argc++] = buffer1; } - if (cfg->setup.eapdir) - { - arg[argc++] = "--eapdir"; - arg[argc++] = cfg->setup.eapdir; - } { /* parse debug string */ char *pos, *level, *buf_pos, type[4]; diff --git a/src/starter/keywords.h b/src/starter/keywords.h index e9fe9ec77..e1957b3d8 100644 --- a/src/starter/keywords.h +++ b/src/starter/keywords.h @@ -40,7 +40,6 @@ typedef enum { KW_NAT_TRAVERSAL, KW_KEEP_ALIVE, KW_VIRTUAL_PRIVATE, - KW_EAPDIR, KW_PKCS11MODULE, KW_PKCS11INITARGS, KW_PKCS11KEEPSTATE, diff --git a/src/starter/keywords.txt b/src/starter/keywords.txt index 1b62937bf..bcadb1770 100644 --- a/src/starter/keywords.txt +++ b/src/starter/keywords.txt @@ -49,7 +49,6 @@ nat_traversal, KW_NAT_TRAVERSAL keep_alive, KW_KEEP_ALIVE virtual_private, KW_VIRTUAL_PRIVATE eap, KW_EAP -eapdir, KW_EAPDIR mobike, KW_MOBIKE forceencaps, KW_FORCEENCAPS pkcs11module, KW_PKCS11MODULE diff --git a/src/starter/starter.c b/src/starter/starter.c index aa4095d8c..af55961e9 100644 --- a/src/starter/starter.c +++ b/src/starter/starter.c @@ -589,7 +589,7 @@ int main (int argc, char **argv) } if (starter_charon_pid()) { - starter_stroke_add_conn(conn); + starter_stroke_add_conn(cfg, conn); } if (starter_pluto_pid()) { diff --git a/src/starter/starterstroke.c b/src/starter/starterstroke.c index 67e0cadcc..0ce0937b2 100644 --- a/src/starter/starterstroke.c +++ b/src/starter/starterstroke.c @@ -32,7 +32,7 @@ #include #include -#include +#include #include "starterstroke.h" #include "confread.h" @@ -175,7 +175,7 @@ static void starter_stroke_add_end(stroke_msg_t *msg, stroke_end_t *msg_end, sta msg_end->sourceip = push_string(msg, buffer); } -int starter_stroke_add_conn(starter_conn_t *conn) +int starter_stroke_add_conn(starter_config_t *cfg, starter_conn_t *conn) { stroke_msg_t msg; @@ -232,6 +232,7 @@ int starter_stroke_add_conn(starter_conn_t *conn) } msg.add_conn.mobike = conn->policy & POLICY_MOBIKE; msg.add_conn.force_encap = conn->policy & POLICY_FORCE_ENCAP; + msg.add_conn.crl_policy = cfg->setup.strictcrlpolicy; msg.add_conn.algorithms.ike = push_string(&msg, conn->ike); msg.add_conn.algorithms.esp = push_string(&msg, conn->esp); msg.add_conn.dpd.delay = conn->dpd_delay; diff --git a/src/starter/starterstroke.h b/src/starter/starterstroke.h index 38fc18a46..8d45141ac 100644 --- a/src/starter/starterstroke.h +++ b/src/starter/starterstroke.h @@ -19,7 +19,7 @@ #include "confread.h" -extern int starter_stroke_add_conn(starter_conn_t *conn); +extern int starter_stroke_add_conn(starter_config_t *cfg, starter_conn_t *conn); extern int starter_stroke_del_conn(starter_conn_t *conn); extern int starter_stroke_route_conn(starter_conn_t *conn); extern int starter_stroke_initiate_conn(starter_conn_t *conn); diff --git a/src/stroke/Makefile.am b/src/stroke/Makefile.am index 6ea64753c..aaedfc787 100644 --- a/src/stroke/Makefile.am +++ b/src/stroke/Makefile.am @@ -1,9 +1,10 @@ ipsec_PROGRAMS = stroke -stroke_SOURCES = stroke.c stroke.h stroke_keywords.c stroke_keywords.h +stroke_SOURCES = stroke.c stroke_msg.h stroke_keywords.c stroke_keywords.h INCLUDES = -I$(top_srcdir)/src/libstrongswan EXTRA_DIST = stroke_keywords.txt MAINTAINERCLEANFILES = stroke_keywords.c +AM_CFLAGS = -DIPSEC_PIDDIR=\"${piddir}\" stroke_keywords.c: stroke_keywords.txt stroke_keywords.h $(GPERF) -C -G -t < stroke_keywords.txt > stroke_keywords.c diff --git a/src/stroke/stroke.c b/src/stroke/stroke.c index 3365add54..6b2e33d1f 100644 --- a/src/stroke/stroke.c +++ b/src/stroke/stroke.c @@ -28,7 +28,7 @@ #include #include -#include "stroke.h" +#include "stroke_msg.h" #include "stroke_keywords.h" struct stroke_token { diff --git a/src/stroke/stroke.h b/src/stroke/stroke.h deleted file mode 100644 index 7ccddfb3e..000000000 --- a/src/stroke/stroke.h +++ /dev/null @@ -1,249 +0,0 @@ -/** - * @file stroke.h - * - * @brief Definition of stroke_msg_t. - * - */ - -/* - * Copyright (C) 2006 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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. - * - * RCSID $Id$ - */ - -#ifndef STROKE_H_ -#define STROKE_H_ - -#include - -/** - * Socket which is used to communicate between charon and stroke - */ -#define STROKE_SOCKET "/var/run/charon.ctl" - -#define STROKE_BUF_LEN 2048 - -typedef enum list_flag_t list_flag_t; - -/** - * Definition of the LIST flags, used for - * the various stroke list* commands. - */ -enum list_flag_t { - /** don't list anything */ - LIST_NONE = 0x0000, - /** list all host/user certs */ - LIST_CERTS = 0x0001, - /** list all ca certs */ - LIST_CACERTS = 0x0002, - /** list all ocsp signer certs */ - LIST_OCSPCERTS = 0x0004, - /** list all aa certs */ - LIST_AACERTS = 0x0008, - /** list all attribute certs */ - LIST_ACERTS = 0x0010, - /** list all access control groups */ - LIST_GROUPS = 0x0020, - /** list all ca information records */ - LIST_CAINFOS = 0x0040, - /** list all crls */ - LIST_CRLS = 0x0080, - /** list all ocsp cache entries */ - LIST_OCSP = 0x0100, - /** all list options */ - LIST_ALL = 0x01FF, -}; - -typedef enum reread_flag_t reread_flag_t; - -/** - * Definition of the REREAD flags, used for - * the various stroke reread* commands. - */ -enum reread_flag_t { - /** don't reread anything */ - REREAD_NONE = 0x0000, - /** reread all secret keys */ - REREAD_SECRETS = 0x0001, - /** reread all ca certs */ - REREAD_CACERTS = 0x0002, - /** reread all ocsp signer certs */ - REREAD_OCSPCERTS = 0x0004, - /** reread all aa certs */ - REREAD_AACERTS = 0x0008, - /** reread all attribute certs */ - REREAD_ACERTS = 0x0010, - /** reread all crls */ - REREAD_CRLS = 0x0020, - /** all reread options */ - REREAD_ALL = 0x003F, -}; - -typedef enum purge_flag_t purge_flag_t; - -/** - * Definition of the PURGE flags, currently used for - * the stroke purgeocsp command. - */ -enum purge_flag_t { - /** don't purge anything */ - PURGE_NONE = 0x0000, - /** purge ocsp cache entries */ - PURGE_OCSP = 0x0001, -}; - -typedef struct stroke_end_t stroke_end_t; - -/** - * definition of a peer in a stroke message - */ -struct stroke_end_t { - char *id; - char *cert; - char *ca; - char *groups; - char *updown; - char *address; - char *sourceip; - u_int8_t virtual_ip; - char *subnet; - int subnet_mask; - int sendcert; - int hostaccess; - int tohost; - u_int8_t protocol; - u_int16_t port; -}; - -typedef struct stroke_msg_t stroke_msg_t; - -/** - * @brief A stroke message sent over the unix socket. - */ -struct stroke_msg_t { - /* length of this message with all strings */ - u_int16_t length; - - /* type of the message */ - enum { - /* initiate a connection */ - STR_INITIATE, - /* install SPD entries for a policy */ - STR_ROUTE, - /* uninstall SPD entries for a policy */ - STR_UNROUTE, - /* add a connection */ - STR_ADD_CONN, - /* delete a connection */ - STR_DEL_CONN, - /* terminate connection */ - STR_TERMINATE, - /* show connection status */ - STR_STATUS, - /* show verbose connection status */ - STR_STATUS_ALL, - /* add a ca information record */ - STR_ADD_CA, - /* delete ca information record */ - STR_DEL_CA, - /* set a log type to log/not log */ - STR_LOGLEVEL, - /* list various objects */ - STR_LIST, - /* reread various objects */ - STR_REREAD, - /* purge various objects */ - STR_PURGE - /* more to come */ - } type; - - /* verbosity of output returned from charon (-from -1=silent to 4=private)*/ - int output_verbosity; - - union { - /* data for STR_INITIATE, STR_ROUTE, STR_UP, STR_DOWN, ... */ - struct { - char *name; - } initiate, route, unroute, terminate, status, del_conn, del_ca; - - /* data for STR_ADD_CONN */ - struct { - char *name; - int ikev2; - int auth_method; - u_int32_t eap_type; - u_int32_t eap_vendor; - int mode; - int mobike; - int force_encap; - struct { - char *ike; - char *esp; - } algorithms; - struct { - int reauth; - time_t ipsec_lifetime; - time_t ike_lifetime; - time_t margin; - unsigned long tries; - unsigned long fuzz; - } rekey; - struct { - time_t delay; - int action; - } dpd; - struct { - int mediation; - char *mediated_by; - char *peerid; - } p2p; - stroke_end_t me, other; - } add_conn; - - /* data for STR_ADD_CA */ - struct { - char *name; - char *cacert; - char *crluri; - char *crluri2; - char *ocspuri; - char *ocspuri2; - } add_ca; - - /* data for STR_LOGLEVEL */ - struct { - char *type; - int level; - } loglevel; - - /* data for STR_LIST */ - struct { - list_flag_t flags; - int utc; - } list; - - /* data for STR_REREAD */ - struct { - reread_flag_t flags; - } reread; - - /* data for STR_PURGE */ - struct { - purge_flag_t flags; - } purge; - }; - char buffer[STROKE_BUF_LEN]; -}; - -#endif /* STROKE_H_ */ diff --git a/src/stroke/stroke_msg.h b/src/stroke/stroke_msg.h new file mode 100644 index 000000000..1af3c6ec7 --- /dev/null +++ b/src/stroke/stroke_msg.h @@ -0,0 +1,260 @@ +/** + * @file stroke_msg.h + * + * @brief Definition of stroke_msg_t. + * + */ + +/* + * Copyright (C) 2006 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + * + * RCSID $Id$ + */ + +#ifndef STROKE_MSG_H_ +#define STROKE_MSG_H_ + +#include + +/** + * Socket which is used to communicate between charon and stroke + */ +#define STROKE_SOCKET IPSEC_PIDDIR "/charon.ctl" + +#define STROKE_BUF_LEN 2048 + +typedef enum list_flag_t list_flag_t; + +/** + * Definition of the LIST flags, used for + * the various stroke list* commands. + */ +enum list_flag_t { + /** don't list anything */ + LIST_NONE = 0x0000, + /** list all host/user certs */ + LIST_CERTS = 0x0001, + /** list all ca certs */ + LIST_CACERTS = 0x0002, + /** list all ocsp signer certs */ + LIST_OCSPCERTS = 0x0004, + /** list all aa certs */ + LIST_AACERTS = 0x0008, + /** list all attribute certs */ + LIST_ACERTS = 0x0010, + /** list all access control groups */ + LIST_GROUPS = 0x0020, + /** list all ca information records */ + LIST_CAINFOS = 0x0040, + /** list all crls */ + LIST_CRLS = 0x0080, + /** list all ocsp cache entries */ + LIST_OCSP = 0x0100, + /** all list options */ + LIST_ALL = 0x01FF, +}; + +typedef enum reread_flag_t reread_flag_t; + +/** + * Definition of the REREAD flags, used for + * the various stroke reread* commands. + */ +enum reread_flag_t { + /** don't reread anything */ + REREAD_NONE = 0x0000, + /** reread all secret keys */ + REREAD_SECRETS = 0x0001, + /** reread all ca certs */ + REREAD_CACERTS = 0x0002, + /** reread all ocsp signer certs */ + REREAD_OCSPCERTS = 0x0004, + /** reread all aa certs */ + REREAD_AACERTS = 0x0008, + /** reread all attribute certs */ + REREAD_ACERTS = 0x0010, + /** reread all crls */ + REREAD_CRLS = 0x0020, + /** all reread options */ + REREAD_ALL = 0x003F, +}; + +typedef enum purge_flag_t purge_flag_t; + +/** + * Definition of the PURGE flags, currently used for + * the stroke purgeocsp command. + */ +enum purge_flag_t { + /** don't purge anything */ + PURGE_NONE = 0x0000, + /** purge ocsp cache entries */ + PURGE_OCSP = 0x0001, +}; + +/** + * CRL certificate validation policy + */ +typedef enum { + CRL_STRICT_NO, + CRL_STRICT_YES, + CRL_STRICT_IFURI, +} crl_policy_t; + + +typedef struct stroke_end_t stroke_end_t; + +/** + * definition of a peer in a stroke message + */ +struct stroke_end_t { + char *id; + char *cert; + char *ca; + char *groups; + char *updown; + char *address; + char *sourceip; + u_int8_t virtual_ip; + char *subnet; + int subnet_mask; + int sendcert; + int hostaccess; + int tohost; + u_int8_t protocol; + u_int16_t port; +}; + +typedef struct stroke_msg_t stroke_msg_t; + +/** + * @brief A stroke message sent over the unix socket. + */ +struct stroke_msg_t { + /* length of this message with all strings */ + u_int16_t length; + + /* type of the message */ + enum { + /* initiate a connection */ + STR_INITIATE, + /* install SPD entries for a policy */ + STR_ROUTE, + /* uninstall SPD entries for a policy */ + STR_UNROUTE, + /* add a connection */ + STR_ADD_CONN, + /* delete a connection */ + STR_DEL_CONN, + /* terminate connection */ + STR_TERMINATE, + /* show connection status */ + STR_STATUS, + /* show verbose connection status */ + STR_STATUS_ALL, + /* add a ca information record */ + STR_ADD_CA, + /* delete ca information record */ + STR_DEL_CA, + /* set a log type to log/not log */ + STR_LOGLEVEL, + /* list various objects */ + STR_LIST, + /* reread various objects */ + STR_REREAD, + /* purge various objects */ + STR_PURGE + /* more to come */ + } type; + + /* verbosity of output returned from charon (-from -1=silent to 4=private)*/ + int output_verbosity; + + union { + /* data for STR_INITIATE, STR_ROUTE, STR_UP, STR_DOWN, ... */ + struct { + char *name; + } initiate, route, unroute, terminate, status, del_conn, del_ca; + + /* data for STR_ADD_CONN */ + struct { + char *name; + int ikev2; + int auth_method; + u_int32_t eap_type; + u_int32_t eap_vendor; + int mode; + int mobike; + int force_encap; + crl_policy_t crl_policy; + struct { + char *ike; + char *esp; + } algorithms; + struct { + int reauth; + time_t ipsec_lifetime; + time_t ike_lifetime; + time_t margin; + unsigned long tries; + unsigned long fuzz; + } rekey; + struct { + time_t delay; + int action; + } dpd; + struct { + int mediation; + char *mediated_by; + char *peerid; + } p2p; + stroke_end_t me, other; + } add_conn; + + /* data for STR_ADD_CA */ + struct { + char *name; + char *cacert; + char *crluri; + char *crluri2; + char *ocspuri; + char *ocspuri2; + } add_ca; + + /* data for STR_LOGLEVEL */ + struct { + char *type; + int level; + } loglevel; + + /* data for STR_LIST */ + struct { + list_flag_t flags; + int utc; + } list; + + /* data for STR_REREAD */ + struct { + reread_flag_t flags; + } reread; + + /* data for STR_PURGE */ + struct { + purge_flag_t flags; + } purge; + }; + char buffer[STROKE_BUF_LEN]; +}; + +#endif /* STROKE_MSG_H_ */ -- cgit v1.2.3